実験日: 2026-08-24
環境: RTX 5070 Ti 16GB / WSL2 / PyTorch 2.13.0+cu130 / Diffusers 0.40.0
生成AIを理解するには、promptをweb serviceへ入力するだけでなく、modelをlocal GPUへloadし、seed、denoising step、VRAM、latencyを測ると仕組みが見えます。
stepを増やせば必ず画像が良くなるとは限りません。待ち時間との釣り合いも確認します。
公開modelstabilityai/sd-turboをこのPCへdownloadし、512×512、FP16、guidance scale 0、seed 42で1・2・4・8 stepを実行しました。warmup後5回の中央値は0.092、0.117、0.166、0.254秒。PyTorch peak allocatedは全条件約3,120 MiBでした。
同じ4 step・seed 42を再実行するとpixel SHA-256が完全一致し、seed 43では別画像になりました。ただし同じseedの再現性はsoftware、driver、hardwareを変えてまで保証する結果ではありません。
1・2・4・8 stepの結果
| steps | 中央値 | 5回範囲 | peak allocated |
|---|---|---|---|
| 1 | 0.092秒 | 0.088~0.096秒 | 3,120.5 MiB |
| 2 | 0.117秒 | 0.112~0.117秒 | 3,120.5 MiB |
| 4 | 0.166秒 | 0.155~0.188秒 | 3,120.5 MiB |
| 8 | 0.254秒 | 0.249~0.257秒 | 3,120.5 MiB |

4 stepの生成結果です。

画像を目視すると、stepを増やすほど単調に品質が上がるとは言えません。SD-Turboは少step向けにdistillされたmodelで、8 stepは「高品質設定」と同義ではありません。
実際にdownloadしたもの
Python packageをWSL venvへ入れました。
source /opt/ai-lab/venv/bin/activate
pip install diffusers transformers accelerate safetensors sentencepiece
実行versionです。
diffusers 0.40.0
transformers 5.15.1
accelerate 1.14.0
safetensors 0.8.0
torch 2.13.0+cu130
modelはDiffusersがstabilityai/sd-turboから取得し、Hugging Face cacheへ保存しました。初回は12 fileの取得に約31秒、pipeline loadを含むscript上のload時間は33.9秒でした。
2回目はcacheから読み、load時間2.63秒です。画像1枚の0.1~0.3秒だけを見ても、初回downloadとmodel loadを含むuser experienceは説明できません。
pipelineをGPUへ載せる
pipe = AutoPipelineForText2Image.from_pretrained(
"stabilityai/sd-turbo",
torch_dtype=torch.float16,
variant="fp16",
)
pipe = pipe.to("cuda")
FP16を使うとFP32よりweight memoryを減らせます。今回のtorch_dtype引数には将来dtypeへ変更するdeprecation warningが出ました。warningを記録し、versionを固定しています。
DiffusersのAutoPipelineはmodel configから適切なtext-to-image pipelineを選びます。この実行ではStableDiffusionPipelineが構成されました。
promptを固定する
全条件で同じ英語promptを使いました。
A small university AI laboratory desk,
a black GPU workstation beside notebooks with neural network diagrams,
warm morning light, realistic editorial photograph,
no text, no logo
比較中にpromptを変えると、step差とprompt差を分離できません。negative promptは使っていません。
no text, no logoと書いても完全な保証にはなりません。実際の比較画像にはmonitor上に文字のような模様があります。生成modelはinstructionを論理constraintとして実行するわけではありません。
guidance scaleを0にする
生成callです。
image = pipe(
prompt,
num_inference_steps=4,
guidance_scale=0.0,
height=512,
width=512,
generator=generator,
).images[0]
SD-Turboのmodel cardは1~4 stepの高速生成とguidance_scale=0.0を例示しています。普通のStable Diffusionでよく見る7.5をそのまま使わず、model固有の推奨条件へ合わせました。
model familyが違えば適切なscheduler、step、guidanceも変わります。「Stable Diffusionの設定」を一括りにできません。
seedはCUDA Generatorへ渡す
generator = torch.Generator(device="cuda").manual_seed(42)
diffusion modelはrandom noiseから生成を始めます。seedを固定すると初期noiseを固定でき、step数だけを変える比較がしやすくなります。
global torch.manual_seedだけに頼らず、生成call専用Generatorを作りました。各測定replicateでもseed 42から作り直しています。
warmupを測定から外す
最初のdiagnostic runでは1 stepが0.790秒、2 stepが0.127秒でした。1 stepの方が大幅に遅いのは不自然です。
原因は最初のcallにCUDA initializationやkernel setupが含まれたためです。そこでseed 999で1回warmupし、その後各stepを5回測り直しました。
pipe(prompt, num_inference_steps=1, generator=warmup_generator)
for _ in range(5):
torch.cuda.synchronize()
started = time.perf_counter()
image = pipe(...)
torch.cuda.synchronize()
samples.append(time.perf_counter() - started)
この修正で1 step中央値は0.092秒になりました。GPU benchmarkではwarmupとsynchronize()が不可欠です。CUDA operationは非同期なので、同期せずCPU clockだけ測ると処理完了前にtimerが止まります。
step数と時間はほぼ増える
1 step 0.092 s
2 steps 0.117 s
4 steps 0.166 s
8 steps 0.254 s
1→8 stepでUNet evaluation回数は8倍ですが、end-to-end時間は2.76倍でした。text encoding、VAE decode、Python callなどstep数に依存しない固定costがあるためです。
画像/秒へ単純換算すると次です。
1 step 約10.84 images/s
2 steps 約 8.56 images/s
4 steps 約 6.04 images/s
8 steps 約 3.93 images/s
これはbatch 1、512×512、同じpipelineをload済みのthroughputです。model load、PNG保存、web deliveryは含みません。
peak memoryがstep数で変わらなかった理由
全条件のtorch.cuda.max_memory_allocated()は約3,120.5 MiBでした。
denoising stepを増やしても、同じshapeのlatentとmodel weightを順番に再利用します。計算回数は増えても、同時に保持するtensorの最大構成が同じならpeakは増えません。
一方、resolutionやbatchを増やすとactivation tensorが大きくなり、peak memoryは増えます。step数は主にtime、resolutionとbatchはtimeとmemoryの両方へ効く、という違いです。
この3,120 MiBはPyTorch allocatorのallocated peakです。driver contextや他processを含むnvidia-smi値とは一致しません。
1・2・4・8 stepを目視比較する
全画像は同じseed 42ですが、scheduler trajectoryがstep数で変わるため別pixelになります。
1 stepでもdesk、monitor、rackらしい構図は出ています。2~4 stepではobjectの輪郭や配置が変わり、8 stepでは色の強いmonitorや本が増えました。
ただし「8 stepが最高」と客観評価していません。prompt adherence、美観、artifactは人によって判断が変わります。1 prompt×1 seedだけではquality benchmarkになりません。
定量化するなら次が必要です。
- 複数prompt category
- 各prompt複数seed
- human preference blind test
- CLIPなどのtext-image alignment
- artifactや文字崩れのannotation
- generation失敗率
この記事の画像は、実行条件差を人間が確認するqualitative evidenceです。
同じseedはpixel単位で一致した
4 step、seed 42を同じprocessで再実行しました。PIL imageのpixel byte列へSHA-256を計算します。
hashlib.sha256(image.tobytes()).hexdigest()
2回とも次のhashでした。
deb671cd10d3abd2a64944305de5011efbec9ba74efefd161c2eb704f2f62d9e
pixel単位で完全一致です。PNG file sizeも両方409,308 bytesでした。
seed 43は別hashになりました。
30959d7387faa9fcc42bb055a8f59702a0bac98b742983c17a2769078f3ca058
ただしPyTorch、Diffusers、CUDA、scheduler、GPU architectureを変えると、同じseedでも同一pixelにならない可能性があります。seedは実験条件の一部であり、普遍的な画像IDではありません。
safety checker warningをどう扱ったか
pipeline load時、safety checkerが無効であるというwarningが出ました。公開serviceでunfiltered resultをそのまま配信しないようDiffusersが注意しています。
今回は自分のoffline experimentで、promptは研究室の机です。生成6枚を保存後に目視確認し、公開する比較gridと4-step画像に不適切内容や実在人物の描写がないことを確認しました。
不特定userのpromptを受けるserviceなら、content policy、input/output filter、rate limit、audit log、人間review、model license確認が必要です。
download元とlicenseを記録する
localで動くことと、自由に再配布できることは同じではありません。model cardとlicenseを確認し、model IDを結果JSONへ保存しました。
{
"model": "stabilityai/sd-turbo",
"dtype": "float16",
"resolution": [512, 512],
"guidance_scale": 0.0
}
研究成果へ画像を使う場合は、model licenseだけでなくdataset由来のrisk、生成物の扱い、所属機関のruleも確認します。
再現手順
source /opt/ai-lab/venv/bin/activate
cd /mnt/c/Users/user/Documents/Codex/2026-08-24/ko/work/ai_lab
python -u experiment_local_image_generation.py
artifactです。
work/ai_lab/experiment_local_image_generation.py
work/ai_lab/results/local_image_generation.json
work/ai_lab/generated_images/sd_turbo_steps1_seed42.png
work/ai_lab/generated_images/sd_turbo_steps2_seed42.png
work/ai_lab/generated_images/sd_turbo_steps4_seed42.png
work/ai_lab/generated_images/sd_turbo_steps8_seed42.png
work/ai_lab/generated_images/sd_turbo_steps4_seed42_repeat.png
work/ai_lab/generated_images/sd_turbo_steps4_seed43_different_seed.png
work/figures/sd-turbo-local-steps.png
JSONにはload時間、prompt、version、GPU、各5回のraw秒、median、peak allocated、pixel hash、PNG sizeを保存しています。
結論
RTX 5070 Ti 16GBとWSL2でSD-Turboをlocal実行し、512×512画像をwarm状態で約0.09~0.25秒で生成できました。peak PyTorch allocationは約3.05 GiBで、16GB VRAMには余裕があります。
しかし速さだけが結果ではありません。初回downloadは31秒、pipeline loadはcache後でも2.63秒かかります。1 stepの最初の測定はwarmup不足で0.79秒となり、測定設計を直す必要がありました。
同じseed・条件ではpixel一致を確認できましたが、step数を増やしても品質が単調に上がる保証はありません。local画像生成も、model ID、prompt、seed、scheduler条件、warmup、raw timing、目視確認を揃えると、再現可能なexperimentになります。
