2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

DOK × OpenVoiceで音声クローンを試す

Last updated at Posted at 2025-02-03

DOKはコンテナー型のGPUサービスで、NVIDIA V100やH100を実行時間課金で利用できるサービスです。

コンテナー型GPUクラウドサービス 高火力 DOK(ドック) | さくらインターネット

今回はこのDOKを使って、OpenVoiceにて自分の声を使った音声クローンを行ってみます。

結果

結果の音声です。日本語はもちろん、英語(インド風、オーストラリア風など)も生成できます。

参考

myshell-ai/OpenVoiceにあるUSAGE.mdを参考に、v2で行っています。

とりあえず試す

学習済みのデータを使って実行してみたい方は、DOKにて新しいタスクを作成し、以下の情報を入力してください。

項目 設定
イメージ dok-handson.sakuracr.jp/openvoice
環境変数 TEXT = "Now, here is today's news. It was a nice day today."
LANG = EN

TEXTは読み上げる文章です。LANGは言語を指定します。ENは英語、JAは日本語です。この場合はリファレンスの音声は指定していないので、デフォルトのexample_reference.mp3が利用されます。

自分の声など、特定の音声を指定してクローンを作りたい場合には、参考にする音声のMP3ファイルをどこかにアップロードし、そのURLを REFERENCE という環境変数で指定してください。
その音声は、長い方が良いようです。3分程度、適当な文章(なるべくさまざまな単語が含まれるもの)を読み、MP3ファイルにしてください

なお、プランはv100-32gbで大丈夫そうです。試してみた限りですが、v100-32gbで2分、h100-80gbで1分10秒でした(リファレンスあり)。なお、Dockerコンテナのダウンロードや初期化には時間がかかります(10分弱)。

コンテナイメージの作成と登録

上記タスクで利用したDockerイメージを作成する手順は以下の通りです。完成版はgoofmint/dok-openvoiceにありますので、実装時の参考にしてください。

ベースになるリポジトリ

ベースはmyshell-ai/OpenVoice: Instant voice cloning by MIT and MyShell. Audio foundation model.を利用します。

git clone https://github.com/myshell-ai/OpenVoice.git
cd OpenVoice

この中に必要なファイルを作成していきます。

checkpoint のダウンロードと解凍

checkpointをダウンロードし、 checkpoints_v2 ディレクトリに解凍します。

wget https://myshell-public-repo-host.s3.amazonaws.com/openvoice/checkpoints_v2_0417.zip
unzip checkpoints_v2_0417.zip

Dockerfile の作成

ここからはDockerfileの中で行っていきます。

ベースイメージ

ベースは FROM continuumio/miniconda3 です。

FROM continuumio/miniconda3

conda の設定

condaの設定を行います。

RUN conda create -n openvoice python==3.9
SHELL ["conda", "run", "-n", "openvoice", "/bin/bash", "-c"]

必要なライブラリのインストール

OpenVoiceはffmpegを使っているので、それをインストールします。 /opt/artifact はDOKのアウトプット先のディレクトリです。

RUN apt-get update && \
    apt-get install -y ffmpeg && \
    mkdir /app /opt/artifact

必要なPythonライブラリのインストール

OpenVoiceのリポジトリのファイルをすべてコピーします。そして、OpenVoice用にMeloTTSをインストールします。argparseやboto3はCLI実行用にインストールします。

WORKDIR /app
COPY . .
RUN pip install -e . && \
  pip install argparse && \
  pip install boto3 && \
  pip install git+https://github.com/myshell-ai/MeloTTS.git && \
  python -m unidic download

docker-entrypoint.sh の準備

Docker実行の際に呼び出す docker-entrypoint.sh (内容は後述)を準備します。

RUN chmod +x /app/docker-entrypoint.sh

# Dockerコンテナー起動時に実行するスクリプトを指定して実行
CMD ["/bin/bash", "/app/docker-entrypoint.sh"]

Dockerfile全体

Dockerfileの全体は以下の通りです。

FROM continuumio/miniconda3

RUN conda create -n openvoice python==3.9
SHELL ["conda", "run", "-n", "openvoice", "/bin/bash", "-c"]
RUN apt-get update && \
    apt-get install -y ffmpeg && \
    mkdir /app /opt/artifact

WORKDIR /app
COPY . .
RUN pip install -e . && \
  pip install argparse && \
  pip install boto3 && \
  pip install git+https://github.com/myshell-ai/MeloTTS.git && \
  python -m unidic download

RUN chmod +x /app/docker-entrypoint.sh

# Dockerコンテナー起動時に実行するスクリプトを指定して実行
CMD ["/bin/bash", "/app/docker-entrypoint.sh"]

docker-entrypoint.sh の作成

docker-entrypoint.sh はDockerコンテナー起動時に実行するスクリプトです。ここでは環境変数をチェックして、 runner.py を呼び出します。以下の内容で作成します。

#!/bin/bash

set -ue
shopt -s nullglob

export TZ=${TZ:-Asia/Tokyo}

# アウトプット先ディレクトリ(自動付与) /opt/artifact固定です
if [ -z "${SAKURA_ARTIFACT_DIR:-}" ]; then
  echo "Environment variable SAKURA_ARTIFACT_DIR is not set" >&2
  exit 1
fi

# DOKのタスクID(自動付与)
if [ -z "${SAKURA_TASK_ID:-}" ]; then
  echo "Environment variable SAKURA_TASK_ID is not set" >&2
  exit 1
fi

# 読み上げるテキスト(環境変数で指定)
if [ -z "${TEXT:-}" ]; then
  echo "Environment variable PROMPT is not set" >&2
  exit 1
fi

# 言語
if [ -z "${LANG:-}" ]; then
  echo "Environment variable LANG is not set" >&2
  exit 1
fi

# リファレンスの音声(オプション)
if [ -z "${REFERENCE:-}" ]; then
    REFERENCE="resources/example_reference.mp3"
else
    wget $REFERENCE -O /tmp/reference.mp3
    REFERENCE="/tmp/reference.mp3"
fi

# S3_はすべてboto3用の環境変数です
cd /app
conda run -n openvoice python3 runner.py \
	  --id="${SAKURA_TASK_ID}" \
	  --output="${SAKURA_ARTIFACT_DIR}" \
	  --text="${TEXT}" \
	  --lang="${LANG}" \
	  --reference="${REFERENCE}" \
	  --s3-bucket="${S3_BUCKET:-}" \
	  --s3-endpoint="${S3_ENDPOINT:-}" \
	  --s3-secret="${S3_SECRET:-}" \
	  --s3-token="${S3_TOKEN:-}"

runner.py の作成

runner.py は実際に処理を行うスクリプトです。まず必要なライブラリをインポートします。

import os
import torch
from openvoice import se_extractor
from openvoice.api import ToneColorConverter
from melo.api import TTS
import argparse
import nltk
import boto3

nltk.download('averaged_perceptron_tagger_eng')

パラメータの取得

docker-entrypoint.sh から渡されたパラメータを取得します。

arg_parser = argparse.ArgumentParser()

arg_parser.add_argument(
    '--output',
    default='/opt/artifact',
    help='出力先ディレクトリを指定します。',
)
arg_parser.add_argument(
    '--text',
    default='',
    help='読み上げる文章',
)
arg_parser.add_argument(
    '--id',
    default='',
    help='タスクIDを指定します。',
)
arg_parser.add_argument(
    '--lang',
    default='JP',
    help='読み上げる言語を指定',
)
arg_parser.add_argument(
    '--reference',
    default='resources/example_reference.mp3',
    help='リファレンスの音声',
)

arg_parser.add_argument('--s3-bucket', help='S3のバケットを指定します。')
arg_parser.add_argument('--s3-endpoint', help='S3互換エンドポイントのURLを指定します。')
arg_parser.add_argument('--s3-secret', help='S3のシークレットアクセスキーを指定します。')
arg_parser.add_argument('--s3-token', help='S3のアクセスキーIDを指定します。')

args = arg_parser.parse_args()

オブジェクトストレージ用のオブジェクトを準備

S3_ではじまる環境変数があれば、それを使ってS3オブジェクトを作成します。

s3 = None
if args.s3_token and args.s3_secret and args.s3_bucket:
    # S3クライアントの作成
    s3 = boto3.client(
        's3',
        endpoint_url=args.s3_endpoint if args.s3_endpoint else None,
        aws_access_key_id=args.s3_token,
        aws_secret_access_key=args.s3_secret)

OpenVoiceの設定

OpenVoice/demo_part3.ipynb at main · myshell-ai/OpenVoiceの内容に沿って、OpenVoiceを準備します。

ckpt_converter = 'checkpoints_v2/converter'
device = "cuda:0" if torch.cuda.is_available() else "cpu"
output_dir = args.output

tone_color_converter = ToneColorConverter(f'{ckpt_converter}/config.json', device=device)
tone_color_converter.load_ckpt(f'{ckpt_converter}/checkpoint.pth')

os.makedirs(output_dir, exist_ok=True)

reference_speaker = args.reference
target_se, audio_name = se_extractor.get_se(reference_speaker, tone_color_converter, vad=True)

from melo.api import TTS

src_path = f'{output_dir}/tmp.wav'

speed = 1.0

model = TTS(language=args.lang, device=device)
speaker_ids = model.hps.data.spk2id

音声の生成とアップロード

音声を生成し、アップロードします。たとえば EN を指定した場合、インド風英語やオーストラリア風英語など複数のキーが speaker_ids に入ってきます。

for speaker_key in speaker_ids.keys():
    speaker_id = speaker_ids[speaker_key]
    speaker_key = speaker_key.lower().replace('_', '-')
    source_se = torch.load(f'checkpoints_v2/base_speakers/ses/{speaker_key}.pth', map_location=device)
    model.tts_to_file(args.text, speaker_id, src_path, speed=speed)
    save_path = f'{args.output}/{args.id}_{speaker_key}.wav'
    # Run the tone color converter
    encode_message = "@MyShell"
    tone_color_converter.convert(
        audio_src_path=src_path, 
        src_se=source_se, 
        tgt_se=target_se, 
        output_path=save_path,
        message=encode_message)
    # オブジェクトストレージにアップロード
    if s3 is not None:
        s3.upload_file(
            Filename=save_path,
            Bucket=args.s3_bucket,
            Key=os.path.basename(save_path))

全体の処理

runner.py の全体の処理は以下の通りです。

import os
import torch
from openvoice import se_extractor
from openvoice.api import ToneColorConverter
from melo.api import TTS
import argparse
import nltk
import boto3

nltk.download('averaged_perceptron_tagger_eng')

arg_parser = argparse.ArgumentParser()

arg_parser.add_argument(
    '--output',
    default='/opt/artifact',
    help='出力先ディレクトリを指定します。',
)
arg_parser.add_argument(
    '--text',
    default='',
    help='読み上げる文章',
)
arg_parser.add_argument(
    '--id',
    default='',
    help='タスクIDを指定します。',
)
arg_parser.add_argument(
    '--lang',
    default='JP',
    help='読み上げる言語を指定',
)
arg_parser.add_argument(
    '--reference',
    default='resources/example_reference.mp3',
    help='リファレンスの音声',
)

arg_parser.add_argument('--s3-bucket', help='S3のバケットを指定します。')
arg_parser.add_argument('--s3-endpoint', help='S3互換エンドポイントのURLを指定します。')
arg_parser.add_argument('--s3-secret', help='S3のシークレットアクセスキーを指定します。')
arg_parser.add_argument('--s3-token', help='S3のアクセスキーIDを指定します。')

args = arg_parser.parse_args()

s3 = None
if args.s3_token and args.s3_secret and args.s3_bucket:
    # S3クライアントの作成
    s3 = boto3.client(
        's3',
        endpoint_url=args.s3_endpoint if args.s3_endpoint else None,
        aws_access_key_id=args.s3_token,
        aws_secret_access_key=args.s3_secret)

ckpt_converter = 'checkpoints_v2/converter'
device = "cuda:0" if torch.cuda.is_available() else "cpu"
output_dir = args.output

tone_color_converter = ToneColorConverter(f'{ckpt_converter}/config.json', device=device)
tone_color_converter.load_ckpt(f'{ckpt_converter}/checkpoint.pth')

os.makedirs(output_dir, exist_ok=True)

reference_speaker = args.reference
target_se, audio_name = se_extractor.get_se(reference_speaker, tone_color_converter, vad=True)


src_path = f'{output_dir}/tmp.wav'

speed = 1.0

model = TTS(language=args.lang, device=device)
speaker_ids = model.hps.data.spk2id

for speaker_key in speaker_ids.keys():
    speaker_id = speaker_ids[speaker_key]
    speaker_key = speaker_key.lower().replace('_', '-')
    source_se = torch.load(f'checkpoints_v2/base_speakers/ses/{speaker_key}.pth', map_location=device)
    model.tts_to_file(args.text, speaker_id, src_path, speed=speed)
    save_path = f'{args.output}/{args.id}_{speaker_key}.wav'
    # Run the tone color converter
    encode_message = "@MyShell"
    tone_color_converter.convert(
        audio_src_path=src_path, 
        src_se=source_se, 
        tgt_se=target_se, 
        output_path=save_path,
        message=encode_message)
    if s3 is not None:
        s3.upload_file(
            Filename=save_path,
            Bucket=args.s3_bucket,
            Key=os.path.basename(save_path))

Dockerイメージのビルド

上記の内容で、Dockerイメージをビルドします。Linux環境などで行います。

コンテナレジストリの用意

Dockerイメージを登録するコンテナレジストリを作成します。さくらのクラウドではLAB機能で、コンテナレジストリを提供しています。さくらのクラウドにログインしたら さくらのクラウド を選択します。

image.png

左側のメニューの LAB の中にある コンテナレジストリ を選択します。

image.png

追加 を押して、コンテナレジストリを作成します。最低限、以下の入力が必要です。

項目 設定
名前 分かりやすい、任意の名前を入力してください
コンテナレジストリ名 ドメイン名に使われます。以下では、 EXAMPLE.sakuracr.jp として説明します
公開設定 Pullのみとします

ユーザーの作成

コンテナレジストリを作成したら、作成したコンテナレジストリを一覧でダブルクリックします。

image.png

詳細表示にて、ユーザータブをクリックします。

image.png

追加ボタンを押し、ユーザーを作成します。 YOUR_USER_NAMEPASSWORD は任意のものを指定してください。

項目 設定
ユーザー名 YOUR_USER_NAME
パスワード YOUR_PASSWORD
ユーザ権限設定 All

Dockerイメージのビルド

DockerイメージはLinuxで行います。今回はUbuntu 24.04を使っています。Dockerが使える環境であれば、Windows + WSL2でも問題ありません。macOSの場合、アーキテクチャが異なるので動かせないかも知れません(未検証です)。

EXAMPLE.sakuracr.jp の部分は、作成したコンテナレジストリのドメイン名に置き換えてください。また、 openvoice は任意の名前で大丈夫です(以下はその名称で読み替えてください)。

sudo docker build -t EXAMPLE.sakuracr.jp/openvoice:latest .

コンテナレジストリへのログイン

作成したコンテナレジストリにログインします。ログインIDとパスワードが求められるので、作成したものを入力してください。

sudo docker login EXAMPLE.sakuracr.jp

イメージのプッシュ

作成したイメージをコンテナレジストリにプッシュします。イメージサイズが大きいので、数十分かかります。

sudo docker push EXAMPLE.sakuracr.jp/openvoice:latest

タスクを作成する

後は最初と同じようにDOKでタスクを作成、実行します。

項目 設定
イメージ dok-handson.sakuracr.jp/openvoice
環境変数 TEXT = "Now, here is today's news. It was a nice day today."
LANG = EN

FireShot Capture 393 - 高火力 DOK - タスク › 新規作成 - secure.sakura.ad.jp.jpg

音声クローンを行う際には、リファレンスの音声が必要です。ボイスレコーダーのようなアプリで自分の声を録音(2〜3分程度)し、それを任意の場所にアップロードします。たとえばさくらのオブジェクトストレージを使った場合、以下のようなURLになります(パブリックリードを指定します)。

https://s3.isk01.sakurastorage.jp/YOUR_BACKET_NAME/YOUR_REFERENCE.mp3

まとめ

今回はOpenVoiceを使って、DOK上で音声クローンを行ってみました。まずは実行できるのみ、次にDockerイメージの作成と段階的に進められるようにしています。ぜひ、試してみてください。

DOKはタスクを多数立ち上げて、後は結果を待つのみと言った使い方ができます。ぜひAI・機械学習に活用してください。

コンテナー型GPUクラウドサービス 高火力 DOK(ドック) | さくらインターネット

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?