DOKはコンテナー型のGPUサービスで、NVIDIA V100とかH100を実行時間課金で利用できるサービスです。
コンテナー型GPUクラウドサービス 高火力 DOK(ドック) | さくらインターネット
今回はこのDOKで、VALL-E X(音声読み上げAI) を試してみました。
実行までのステップ
- さくらのクラウドのアカウントの用意(必須)
- Dockerイメージのビルド環境(Linuxなど)を用意
- Dockerイメージのビルド
- DOKにイメージをアップロード
- DOKでコンテナーを起動・実行
1. さくらのクラウドのアカウントの用意
DOKはさくらのクラウドに紐付いたサービスなので、さくらのクラウドのアカウント必須です。
コンテナレジストリの作成
さくらのクラウドにログインしたら さくらのクラウド
を選択します。
左側のメニューの LAB
の中にある コンテナレジストリ
を選択します。
追加
を押して、コンテナレジストリを作成します。最低限、以下の入力が必要です。
項目 | 設定 |
---|---|
名前 | 分かりやすい、任意の名前を入力してください |
コンテナレジストリ名 | ドメイン名に使われます。 EXAMPLE.sakuracr.jp というコンテナレジストリになります |
公開設定 | 非公開で良いかと思います |
ユーザーの作成
コンテナレジストリにアクセスできるユーザーを作成します。作成したコンテナレジストリをダブルクリックして、詳細を表示します。
ユーザー
タブを選択して、追加
を押します。
IDとパスワードを設定して、権限は All
にして作成してください。
2. Dockerイメージのビルド環境(Linuxなど)を用意
WindowsのWSL2でできるかは分かりませんが、少なくともmacOS(M1など)ではDockerイメージをビルドできなかったので、別途用意が必要です。これは適当なVPSサーバーや自宅サーバ、さくらのクラウドでインスタンスを立ち上げるでもOKです。
以下はスペックの例です。
- コア
2 - メモリ
4GB - OS
Ubuntu Server 22.04.4 LTS 64bit - ディスク
100GB
3. Dockerイメージのビルド
作業フォルダを作成します。
mkdir VALL-E-X
cd VALL-E-X
後はこの VALL-E-X
ディレクトリの中で処理を書いていきます。
Dockerfileの作成
Dockerfileを作成します。内容は以下の通りです。
FROM nvidia/cuda:12.5.1-runtime-ubuntu22.04
ENV DEBIAN_FRONTEND=noninteractive
# 必要なパッケージのインストール
# /appはアプリのディレクトリ、/opt/artifactはアウトプット先のディレクトリ
RUN apt-get update && \
apt-get install -y \
git \
git-lfs \
python3 \
python3-pip \
&& \
mkdir /app /opt/artifact && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# VALL-E Xのリポジトリをクローン
RUN git clone https://github.com/Plachtaa/VALL-E-X.git /app
WORKDIR /app
# git-lfsのインストール
RUN git lfs install --skip-smudge
# 依存ライブラリのインストール
RUN pip install -r requirements.txt
# 出力データをオブジェクトストレージにアップロードするためのライブラリ
RUN pip install boto3
RUN pip cache purge
# 実行スクリプト(後で作成)
COPY runner.py /app/
# Dockerコンテナー起動時に実行するスクリプト(後で作成)
COPY docker-entrypoint.sh /
# 実行権限を付与
RUN chmod +x /docker-entrypoint.sh /
WORKDIR /
# Dockerコンテナー起動時に実行するスクリプトを指定して実行
CMD ["/bin/bash", "/docker-entrypoint.sh"]
docker-entrypoint.shの作成
docker-entrypoint.shは、Dockerコンテナー起動時に実行するスクリプトです。内容は以下の通りです。
#!/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 TEXT is not set" >&2
exit 1
fi
# S3_はすべてboto3用の環境変数です
pushd /app
python3 runner.py \
--id="${SAKURA_TASK_ID}" \
--output="${SAKURA_ARTIFACT_DIR}" \
--text="${TEXT}" \
--s3-bucket="${S3_BUCKET:-}" \
--s3-endpoint="${S3_ENDPOINT:-}" \
--s3-secret="${S3_SECRET:-}" \
--s3-token="${S3_TOKEN:-}"
popd
runner.pyの作成
runner.pyは実際に実行するスクリプトです。内容は以下の通りです。
ライブラリの読み込み
最初にライブラリを読み込みます。
from utils.generation import SAMPLE_RATE, generate_audio, preload_models
from scipy.io.wavfile import write as write_wav
import argparse
引数のパース
実行時に渡される引数をパースします。
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument(
'--output',
default='/opt/artifact',
help='出力先ディレクトリを指定します。',
)
arg_parser.add_argument(
'--text',
default='Hello from Dok',
help='読み上げるテキストを指定します。',
)
arg_parser.add_argument(
'--id',
default='',
help='タスクIDを指定します。',
)
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()
モデルの読み込み
必要なモデルをダウンロードして読み込みます。
preload_models()
テキストから音声の生成
テキストから音声データを生成します。
audio_array = generate_audio(args.text)
音声データの保存
音声データを保存します。 /opt/artifact
ディレクトリに output-{args.id}.wav
という名前で保存します。
file = f'{args.output}/output-{args.id}.wav'
write_wav(file, SAMPLE_RATE, audio_array)
オブジェクトストレージへのアップロード
もし、S3_ではじまる環境変数が設定されていれば、boto3を使って出力内容をアップロードします。
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,
)
# ファイルアップロード
s3.upload_file(
Filename=file,
Bucket=args.s3_bucket,
Key=os.path.basename(file),
)
全体のコード
runner.py
の全体のコードは以下の通りです。
from utils.generation import SAMPLE_RATE, generate_audio, preload_models
from scipy.io.wavfile import write as write_wav
import argparse
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument(
'--output',
default='/opt/artifact',
help='出力先ディレクトリを指定します。',
)
arg_parser.add_argument(
'--text',
default='Hello from Dok',
help='読み上げるテキストを指定します。',
)
arg_parser.add_argument(
'--id',
default='',
help='タスクIDを指定します。',
)
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()
preload_models()
audio_array = generate_audio(args.text)
file = f'{args.output}/output-{args.id}.wav'
write_wav(file, SAMPLE_RATE, audio_array)
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,
)
# ファイルアップロード
s3.upload_file(
Filename=file,
Bucket=args.s3_bucket,
Key=os.path.basename(file),
)
Dockerイメージのビルド
Dockerイメージをビルドします。この時、コンテナレジストリのドメイン名を使ってイメージ名を作成してください。
EXAMPLE.sakuracr.jp
の場合、 EXAMPLE.sakuracr.jp/VALL-E-X
といった名前になります。 VALL-E-X
は適当に分かりやすいものを付けます。
$ sudo docker build -t EXAMPLE.sakuracr.jp/VALL-E-X .
実際の動作を確認する際には、docker run
でコンテナーを起動して動作確認をしてください。出力ファイルを確認する際には、適当なディレクトリを /opt/artifact
にマウントしてください。
$ sudo docker run -e TEXT=hello \
-e SAKURA_TASK_ID=001 \
-e SAKURA_ARTIFACT_DIR=/opt/artifact \
-v /path/to/data/:/opt/artifact \
-t EXAMPLE.sakuracr.jp/VALL-E-X
これで、/path/to/data/
に output-001.wav
というファイルが作成されているはずです。
4. DOKにイメージをアップロード
作成したDockerイメージをDOKにアップロードします。まずコンテナレジストリにログインします。コンテナレジストリのドメイン、ユーザー名、パスワードを入力してください。
$ sudo docker login EXAMPLE.sakuracr.jp
Username:
Password:
ログインしたら、イメージをプッシュします。
$ sudo docker image push EXAMPLE.sakuracr.jp/VALL-E-X
これでプッシュが終われば、準備は完了です。
5. DOKでコンテナーを起動・実行
レジストリーの登録
DOKのダッシュボードで、 レジストリー
を選択して、 新規登録
を押します。
以下のように入力してください。入力したら、 登録
を押します。
項目 | 設定 |
---|---|
ホスト名 | 例)EXAMPLE.sakuracr.jp |
ユーザー名 | コンテナレジストリで登録したもの |
パスワード | コンテナレジストリで登録したもの |
パスワード(確認用) | コンテナレジストリで登録したもの |
タスクの作成
DOKのダッシュボードで、 タスク
を選択して、 新規作成
を押します。
以下のように入力してください。入力したら、 作成
を押します。 :latest
をつけて、レジストリの最新イメージを指定しています。
項目 | 設定 |
---|---|
イメージ | EXAMPLE.sakuracr.jp/VALL-E-X:latest |
レジストリー | 登録したレジストリー |
コマンド | 何もなし |
エントリーポイント | 何もなし |
環境変数 | 後述 |
プラン | v100-32gbまたはh100-80gb |
環境変数は、以下のように設定してください。
項目 | 設定 |
---|---|
TEXT | 読み上げるテキストを指定します |
TEXTは英語や日本語、中国語が指定できます(自動判別)。
タスクを作成するとキューに入り、順番に処理されます。
結果の確認
結果はタスクの画面で確認できます。完了していれば、 アーティファクト
にて、出力ファイルをダウンロードできます。なお、ファイルはtar.gz形式で圧縮されています。
おまけ(オブジェクトストレージを使う)
アーティファクトの保存期限は72時間なので、データを永続的に残しておきたい場合はオブジェクトストレージへの保存をお勧めします。
オブジェクトストレージの作成
さくらのクラウドのダッシュボードで、 オブジェクトストレージ
を選択します。
バケットとアクセスキーを作成します。シークレットアクセスキーも生成されるので、保存しておいてください。
情報としては、以下が手に入ります(例)。
- S3エンドポイント
s3.isk01.sakurastorage.jp - バケット名
自分で決めたもの - アクセスキー
自動生成されたもの - シークレットアクセスキー
自動生成されたもの
そして、これらの情報をDOKのタスク実行時の環境変数に設定してください。
項目 | 設定 |
---|---|
S3_ENDPOINT | S3エンドポイント |
S3_BUCKET | バケット名 |
S3_TOKEN | アクセスキー |
S3_SECRET | シークレットアクセスキー |
これでDOKのタスクを実行すると、結果ファイルがオブジェクトストレージにアップロードされます。ファイルアップロードの場合は、圧縮されていない状態で取得できます。
まとめ
今回は、DOKでVALL-E X(音声読み上げAI)を試してみました。Dockerイメージを作成する必要があるので、Dockerの知識とDockerイメージを作成できる環境を用意する必要があるので注意してください。
Dockerイメージさえできてしまえば、後は環境変数を指定して実行すれば良いだけなので簡単です。ぜひAI・機械学習などに活用してください。