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・機械学習などに活用してください。










