AI画像生成・加工から最適化配信までさくらのサービスで実現してみた

はじめに
今日話題に事欠かない画像生成AI。Text-to-Imageモデルを使えば、利用者の入力内容に応じた画像を生成してくれます。
最初期は遊び程度の品質でしか出力できませんでしたが、令和8年現在では、職業作品とほとんど区別できない水準の画像を出力しているケースも出てきています。
さくらインターネットでは「高火力シリーズ」と呼ばれるGPU基盤を提供しており、この基板上でも画像生成を実現することが可能です。
今回は、AI画像生成から、保存、最適化、配信までを、さくらインターネットのサービスで一気通貫で構成してみました。実現イメージは以下の通りです。
- 高火力 DOKでWeb向けAI画像生成を実行します。
- 成果物をオブジェクトストレージに格納します。
- ImageFlux 画像変換・配信エンジン(以下、ImageFlux)で最適化・配信をを行います。
以上です。それでは各手順の詳細をお伝えしていきます。
高火力 DOKでの画像生成からオブジェクトストレージ格納まで
さくらのナレッジにある以下の2コラムを参考に実現しました。
今回の記事では、今年1月に出たばかりの画像生成AIモデル、FLUX.2-klein-4bを高火力 DOKに載せ、画像生成をしています。
【生成AIに触れてみよう】 高火力 DOKことはじめ #1 〜Dockerイメージ作成環境の構築〜
【生成AIに触れてみよう】 高火力 DOKことはじめ #2 ~SDXL(Stable Diffusion XL)による画像の生成~
記事の通りに実行しても良いのですが、AIモデルの変更と、Web向けの画像生成に向けて、ソースを再作成しています。
- 実行環境とパラメータをFLUX.2-klein-4b向けに変更する。
- SEO向けに、ファイル名をランダムな文字列でなく、その内容に適したものにする。
- 複数種類の画像生成タスクを一気に実行できるようにする。
Dockerイメージ構築用ファイル
ソースは以下の通りです。
- Dockerfile:Dockerイメージの設計図。AIモデルも格納します。
- docker-entrypoint.sh:画像生成をする際のエントリーポイントとなるシェルスクリプト。
- docker-entrypoint-img2img.sh:画像編集をする際のエントリーポイントとなるシェルスクリプト。
- runner.py:画像生成をする際のPythonスクリプト。
- runner_img2img.py:画像編集をする際のPythonスクリプト。
【ソースのリンクはこちら】
FLUX.2-klein-4bモデルのダウンロードには、AIモデル共有サイトHugging Faceのアカウント登録とアクセストークン発行が必要になります。
アクセストークンを発行したら、Docker buildコマンドにそれを反映します(今回は個人閉域利用を想定して直接トークンを貼り付けていますが、本来はセキュアな内容はシークレットsecretsという仕組みで渡すのが一般的です)。
その後のlogin、pushは前記事と同じ要領で実行します。
sudo docker login -t <作成したレジストリのホスト名>.sakuracr.jp
-u <作成したユーザー> -p <作成したユーザーのパスワード>
sudo docker build --build-arg access_token=アクセストークン -t <作成したレジストリのホスト名>/flux.2-klein-4b:latest .
sudo docker image push <作成したレジストリのホスト名>.sakuracr.jp/flux.2-klein-4b:latest
複数種類の画像生成タスク登録
Webでは膨大な数の画像を扱うため、高火力 DOKのダッシュボードで1つ1つタスクを作っていては、現実的な工数に収まりません。
そこで以下のようなcsvを読み込み、各行の値を二次元配列化して高火力 DOKに登録、一気に複数の枚数を出力できるようにしています。担当者は、ファイル名称、プロンプトにのみ集中します。
| prefix | prompt |
|---|---|
| "ファイル名1" | "プロンプト" |
| "ファイル名2" | "プロンプト" |
高火力 DOKのAPI仕様はこちら。
https://secure.sakura.ad.jp/cloud/zone/is1a/api/managed-container/1.0/tasks/
宛てにPOSTメソッドを呼べばよいことがわかります。
APIを呼び出すためのAPIキーをさくらのクラウドホームから出力し、
PowerShellからAPIを呼び出します。
以下のようなコードを記述しました。
PowerShellで呼び出す際の第一引数に、csvのパスを入れれば実行できます。設定値は上記でご紹介している記事に基づいて設定してください。
(MacやLinuxをお使いの方は上記と同様の動作をするシェルスクリプトを書いて実行してください)
# =====初期設定値=====
$ACCESSTOKEN = "アクセストークンに置換"
$ACCESSTOKENSECRET = "アクセストークンシークレットに置換"
$URI = "https://secure.sakura.ad.jp/cloud/zone/is1a/api/managed-container/1.0/tasks/"
# =====タスク向け設定値=====
$IMAGENAME = "イメージ名に置換"
$REGISTRYID = "レジストリ―認証情報に置換"
$OBJST_ENDPOINT = "https://s3.isk01.sakurastorage.jp"
$OBJST_TOKEN = "アクセスキーIDに置換"
$OBJST_SECRET = "シークレットアクセスキーに置換"
$OBJST_BUCKET = "バケット名に置換"
# =====AI向け設定値=====
$steps = 4
$num_images = 2
$batch = 2
# 入力データの処理
# csvパス、ファイルの検証
if ($Args.Count -lt 1 -or [string]::IsNullOrWhiteSpace($Args[0])) {
throw "csvファイルのパスを指定してください。"
}
$CsvPath = $Args[0]
if (-not (Test-Path -LiteralPath $CsvPath)) {
throw "指定されたcsvファイルが見つかりません: $CsvPath"
}
# csvの読み込み
$CsvFile = Get-Item -LiteralPath $CsvPath # ファイル情報を取得
$rows = Import-Csv -LiteralPath $CsvPath
$promptList = @()
# 二次元配列化
foreach ($r in $rows) {
# [prefix, prompt] の形式で配列に追加
$promptList += ,@($r.prefix, $r.prompt)
}
$promptJsonString = ConvertTo-Json @($promptList) -Compress
# Basic認証ヘッダ作成
$pair = "$ACCESSTOKEN`:$ACCESSTOKENSECRET"
$bytes = [System.Text.Encoding]::ASCII.GetBytes($pair)
$encoded = [Convert]::ToBase64String($bytes)
$headers = @{
"Authorization" = "Basic $encoded"
"Content-Type" = "application/json"
"Accept" = "application/json"
}
# csvの各行を読み込み、高火力 DOKのタスク登録を行う。
# 送信するJSONボディ =====
$bodyObject = @{
name = $CsvFile.BaseName + "Task"
containers = @(
@{
image = $IMAGENAME
registry = $REGISTRYID
command = @()
entrypoint = @()
environment = @{
OBJST_ENDPOINT = $OBJST_ENDPOINT
OBJST_TOKEN = $OBJST_TOKEN
OBJST_SECRET = $OBJST_SECRET
OBJST_BUCKET = $OBJST_BUCKET
PROMPT = $promptJsonString
STEPS = $steps
NUM_IMAGES = $num_images
BATCH = $batch
}
plan = "v100-32gb"
}
)
tags = @()
execution_time_limit_sec = $null
}
# JSON化(ネストが深いのでDepthを上げる)
$bodyJson = $bodyObject | ConvertTo-Json -Depth 20
# ===== POSTリクエスト =====
$response = Invoke-RestMethod `
-Method Post `
-Uri $URI `
-Headers $headers `
-Body $bodyJson
# ===== タスクURLの表示 =====
$taskURL = "タスクを登録しました:https://secure.sakura.ad.jp/koukaryoku-container/tasks/detail/" + $response.id
$taskURL
いざ出力
ここまで準備ができたら、いよいよ画像出力を行います。
今回はImageFluxにちなみ、デザイナー、Webエンジニアおよびその両方の従業員が働いているイメージイラストを出力させてみます。
"prefix","prompt"
"Designer_ImageFlux","A detailed illustration of a professional web design team working together in a modern office. Team members are focused on UI/UX design, creating wireframes, visual layouts, and design systems."
"WebEngineer_ImageFlux","A detailed illustration of a professional web development team working in a modern tech environment. Team members are writing code, reviewing pull requests, and discussing system architecture."
"Designer_WebEngineer_ImageFlux","A detailed illustration showing a web design team and a web development team collaborating on the same project. Designers and developers are gathered around a shared workspace, exchanging ideas and aligning on requirements. UI mockups and code interfaces are visible side by side on shared screens."
PowerShellターミナルを起動し、スクリプトのパス、csvのパスを記述し、Enterキーを押します。無事タスクが登録できました。
高火力 DOKのページを見ると、たしかにタスクが登録されています。
実行完了画面。今回は3種類の写真を4枚ずつ、計12枚出力しました。
オブジェクトストレージに、生成済みの画像が格納されていることも確認できました。
続けて、これらの画像を最適化・配信していきます。
ImageFluxオリジン登録から配信まで
オリジン登録
ImageFluxドキュメントにならい、まずはオリジンを設定していきます。
これにより、高火力 DOKによって生成された画像を持っている、オブジェクトストレージとImageFluxを繋ぎます。
Access Key ID、SecretAccessKey、Bucketには、高火力 DOKやPowerShellで入力したオブジェクトストレージの値を入力します。
End Point、Regionはオブジェクトストレージのサイト画面で確認できます。
下セクションの値は既定値のままで問題ありません。
プレビュー
オリジンを追加したら、ファイルをプレビューしてみます。
ImageFluxコンソールにログインし、上メニューの「プレビュー」をクリックします。
プレビュー画面が出たら、「変換元画像」欄で追加したオリジンを選択し、さらに生成された画像の名前を入力、「画像をロード」を押下します。
画像が表示されました。
このまま使っても良いのですが、サムネイルや記事中の画像向けにはやや大き過ぎるサイズです。これから軽量化、最適化を施していきます。
リサイズ・変換
リサイズ
まず、1024pxの画像を320pxまで縮小してみます。
変換
pngファイルはサイズが大きいため、軽量な次世代フォーマットのWebPに変換します。
最適化
再度、「画像をロード」を押下すると、軽量化した画像が表示されます。
画像下部のURLを使うことで、このまま配信することが可能です。
ファイルサイズは1,763 KBから22 KBまで削減できていました。
おまけ
FLUX.2-klein-4bは、画像生成だけでなく、画像を編集する機能も持っています。
今回のソースでは、editImage.ps1の第一引数に以下のような形式のcsvを読ませることで、画像編集にも対応できるようにしています。
| filename | prompt | suffix |
|---|---|---|
| "ファイル名1" | "プロンプト" | "編集後のファイル名に付ける接尾辞" |
| "ファイル名2" | "プロンプト" | "編集後のファイル名に付ける接尾辞" |
試しに、今回生成した画像「WebEngineer_1.png」を、プロンプト「make it more dark and moody with dramatic lighting」を適用することで、「暗めで、ドラマチックな雰囲気に」加工してみます。
画像編集はより大きなリソースを必要とするため、H100で実行してみました。GPUを適宜選べるのも高火力 DOKの魅力です。
生成された画像は……
たぶん、納期ギリギリなんでしょうね(汗)
まとめ
今回は、さくらインターネットが提供しているサービスを連携させて、AI画像生成->保存->最適化→配信まで一気通貫で実現できる仕組みを構築してみました。
画像変換、画像CDNサービスはいくつかありますが、パブリッククラウド事業者が提供する画像CDNというImageFluxならではの潜在価値を、少しでも感じていただけたら幸いです。