DOKはコンテナー型のGPUサービスで、NVIDIA V100やH100を実行時間課金で利用できるサービスです。
今回はこのDOKを使って、Animagine XL 4.0を試してみました。
注意
この画像生成で作られる画像は、アニメのキャラクターを学習利用しており、固有名詞を使って絵柄が指定できます。そういった画像は著作権上、問題になる可能性が高いので利用時には注意してください。
参考
cagliostrolab/animagine-xl-4.0 · Hugging Faceにある利用例をベースに進めます。
とりあえず試す
コンテナレジストリにプッシュ済みのイメージを使って実行してみたい方は、DOKにて新しいタスクを作成し、以下の情報を入力してください。
項目 | 設定 |
---|---|
イメージ | dok-handson.sakuracr.jp/animagine |
環境変数 | PROMPT = 1girl, yellow long hair, dancing, cosplay, looking at viewer, smile, outdoors, night, v, masterpiece, high score, great score, absurdres NEGATIVE = lowres, bad anatomy, bad hands, text, error, missing finger, extra digits, fewer digits, cropped, worst quality, low quality, low score, bad score, average score, signature, watermark, username, blurry WIDTH = 1024 HEIGHT = 1024 |
PROMPTは生成する画像の指示内容です。NEGATIVEは、生成対象外にする情報、WIDTHとHEIGHTは画像のサイズです。
コンテナイメージの作成と登録
上記タスクで利用したDockerイメージを作成する手順は以下の通りです。完成版はgoofmint/dok-animagineにありますので、実装時の参考にしてください。
Dockerfile の作成
cagliostrolab/animagine-xl-4.0 · Hugging Faceの内容に沿って、Dockerfileを作成します。
ベースイメージ
ベースは FROM nvidia/cuda:12.5.1-runtime-ubuntu22.04
です。
FROM nvidia/cuda:12.5.1-runtime-ubuntu22.04
ライブラリのインストール
Pythonと、必要なライブラリをインストールします。
RUN apt-get update && \
apt-get install -y \
git \
python3 \
python3-pip \
&& \
mkdir /app /opt/artifact && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt .
# 依存ライブラリのインストール
RUN pip install -r requirements.txt
requirements.txt
の内容は以下の通りです。公式サイトにあるものと、CLIのパラメーターのパーサー、そしてオブジェクトストレージ用ライブラリを追加しています。
diffusers
transformers
accelerate
safetensors
boto3
argparse
後は 後述する runner.py
と、 docker-entrypoint.sh
をコピーします。
COPY runner.py .
# Dockerコンテナー起動時に実行するスクリプト(後で作成)
COPY docker-entrypoint.sh /
# 実行権限を付与
RUN chmod +x /docker-entrypoint.sh /
WORKDIR /
# Dockerコンテナー起動時に実行するスクリプトを指定して実行
CMD ["/bin/bash", "/docker-entrypoint.sh"]
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 \
python3 \
python3-pip \
&& \
mkdir /app /opt/artifact && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt .
# 依存ライブラリのインストール
RUN pip install -r requirements.txt
COPY runner.py .
# 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コンテナー起動時に実行するスクリプトです。ここでは環境変数をチェックして、 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 "${PROMPT:-}" ]; then
echo "Environment variable PROMPT is not set" >&2
exit 1
fi
# 画像生成用プロンプト(ネガティブ)
if [ -z "${NEGATIVE:-}" ]; then
echo "Environment variable NEGATIVE is not set" >&2
exit 1
fi
# 画像の幅
if [ -z "${WIDTH:-}" ]; then
WIDTH=800
exit 1
fi
# 画像の高さ
if [ -z "${HEIGHT:-}" ]; then
HEIGHT=600
exit 1
fi
# S3_はすべてboto3用の環境変数です
pushd /app
python3 runner.py \
--id="${SAKURA_TASK_ID}" \
--output="${SAKURA_ARTIFACT_DIR}" \
--prompt="${PROMPT}" \
--negative="${NEGATIVE}" \
--width="${WIDTH}" \
--height="${HEIGHT}" \
--s3-bucket="${S3_BUCKET:-}" \
--s3-endpoint="${S3_ENDPOINT:-}" \
--s3-secret="${S3_SECRET:-}" \
--s3-token="${S3_TOKEN:-}"
popd
runner.py の作成
runner.py は実際に処理を行うスクリプトです。まず必要なライブラリをインポートします。
import torch
from diffusers import StableDiffusionXLPipeline
import argparse
import boto3
パラメータの取得
docker-entrypoint.sh
から渡されたパラメータを取得します。
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument(
'--output',
default='/opt/artifact',
help='出力先ディレクトリを指定します。',
)
arg_parser.add_argument(
'--prompt',
default='',
help='プロンプト',
)
arg_parser.add_argument(
'--negative',
default='',
help='プロンプト(ネガティブ)',
)
arg_parser.add_argument(
'--width',
default=800,
help='画像幅',
)
arg_parser.add_argument(
'--height',
default=600,
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()
オブジェクトストレージ用のオブジェクトを準備
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)
Animagine XL 4.0の実行
公式サイトのドキュメントに沿って、実行部分を記述します。生成された画像を /opt/artifact
(環境変数で --output
にて受け取ったパス) に保存します。こうすると、実行後にDOKの管理画面でダウンロードできます。
pipe = StableDiffusionXLPipeline.from_pretrained(
"cagliostrolab/animagine-xl-4.0",
torch_dtype=torch.float16,
use_safetensors=True,
custom_pipeline="lpw_stable_diffusion_xl",
add_watermarker=False
)
pipe.to('cuda')
print(args)
image = pipe(
args.prompt,
negative_prompt=args.negative,
width=int(args.width),
height=int(args.height),
guidance_scale=6,
num_inference_steps=25
).images[0]
save_path = f'{args.output}/{args.id}.png'
image.save(save_path)
オブジェクトストレージに保存
もし s3
があれば、生成した画像をオブジェクトストレージに保存します。
if s3 is not None:
s3.upload_file(
Filename=save_path,
Bucket=args.s3_bucket,
Key=os.path.basename(save_path))
全体の処理
runner.py
の全体の処理は以下の通りです。
import torch
from diffusers import StableDiffusionXLPipeline
import argparse
import boto3
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument(
'--output',
default='/opt/artifact',
help='出力先ディレクトリを指定します。',
)
arg_parser.add_argument(
'--prompt',
default='',
help='プロンプト',
)
arg_parser.add_argument(
'--negative',
default='',
help='プロンプト(ネガティブ)',
)
arg_parser.add_argument(
'--width',
default=800,
help='画像幅',
)
arg_parser.add_argument(
'--height',
default=600,
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()
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)
pipe = StableDiffusionXLPipeline.from_pretrained(
"cagliostrolab/animagine-xl-4.0",
torch_dtype=torch.float16,
use_safetensors=True,
custom_pipeline="lpw_stable_diffusion_xl",
add_watermarker=False
)
pipe.to('cuda')
print(args)
image = pipe(
args.prompt,
negative_prompt=args.negative,
width=int(args.width),
height=int(args.height),
guidance_scale=6,
num_inference_steps=25
).images[0]
save_path = f'{args.output}/{args.id}.png'
image.save(save_path)
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機能で、コンテナレジストリを提供しています。さくらのクラウドにログインしたら さくらのクラウド
を選択します。
左側のメニューの LAB
の中にある コンテナレジストリ
を選択します。
追加
を押して、コンテナレジストリを作成します。最低限、以下の入力が必要です。
項目 | 設定 |
---|---|
名前 | 分かりやすい、任意の名前を入力してください |
コンテナレジストリ名 | ドメイン名に使われます。以下では、 EXAMPLE.sakuracr.jp として説明します |
公開設定 | Pullのみとします |
ユーザーの作成
コンテナレジストリを作成したら、作成したコンテナレジストリを一覧でダブルクリックします。
詳細表示にて、ユーザータブをクリックします。
追加ボタンを押し、ユーザーを作成します。 YOUR_USER_NAME
と PASSWORD
は任意のものを指定してください。
項目 | 設定 |
---|---|
ユーザー名 | YOUR_USER_NAME |
パスワード | YOUR_PASSWORD |
ユーザ権限設定 | All |
Dockerイメージのビルド
DockerイメージはLinuxで行います。今回はUbuntu 24.04を使っています。Dockerが使える環境であれば、Windows + WSL2でも問題ありません。macOSの場合、アーキテクチャが異なるので動かせないかも知れません(未検証です)。
EXAMPLE.sakuracr.jp
の部分は、作成したコンテナレジストリのドメイン名に置き換えてください。また、 animagine
は任意の名前で大丈夫です(以下はその名称で読み替えてください)。
sudo docker build -t EXAMPLE.sakuracr.jp/animagine:latest .
コンテナレジストリへのログイン
作成したコンテナレジストリにログインします。ログインIDとパスワードが求められるので、作成したものを入力してください。
sudo docker login EXAMPLE.sakuracr.jp
イメージのプッシュ
作成したイメージをコンテナレジストリにプッシュします。イメージサイズが大きいので、数十分かかります。
sudo docker push EXAMPLE.sakuracr.jp/animagine:latest
タスクを作成する
後は最初と同じようにDOKでタスクを作成、実行します。
項目 | 設定 |
---|---|
イメージ | dok-handson.sakuracr.jp/animagine |
環境変数 | PROMPT = 1girl, yellow long hair, dancing, cosplay, looking at viewer, smile, outdoors, night, v, masterpiece, high score, great score, absurdres NEGATIVE = lowres, bad anatomy, bad hands, text, error, missing finger, extra digits, fewer digits, cropped, worst quality, low quality, low score, bad score, average score, signature, watermark, username, blurry WIDTH = 1024 HEIGHT = 1024 |
実行が完了し、画像が生成できていれば成功です。
まとめ
今回はAnimagine XL 4.0を使って、DOK上で画像生成を行いました。まずは実行できるのみ、次にDockerイメージの作成と段階的に進められるようにしています。画像生成のように、処理に時間がかかるものを利用する際にDOKは便利です。
DOKはタスクを多数立ち上げて、後は結果を待つのみと言った使い方ができます。ぜひAI・機械学習に活用してください。