Stable Diffusionを使って画像を生成する
今回は、Google Colab上でStable Diffusionを実行できる環境を作り、画像の生成をする。
環境構築
必要なライブラリをインストールする。
!pip install diffusers transformers accelerate ftfy pillow scipy
!pip install --upgrade torch torchvision torchaudio peft --index-url https://download.pytorch.org/whl/cu118簡単な画像を生成する
ライブラリのインポートやモデルのロードを行う。 StableDiffusionPipeline.from_pretrained() を呼び出した時、モデルがまだダウンロードされていなければ、モデルのダウンロードも行われる。
import os
import torch
from diffusers import StableDiffusionPipeline
os.environ["TOKENIZERS_PARALLELISM"] = "true"
pipe = StableDiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5")
pipe = pipe.to("cuda")プロンプトを渡し、画像を生成する。
prompt = "かわいい猫"
image = pipe(prompt).images[0]生成した画像を表示する。
display(image)diffusersをソースコードからインストールする
今度は、diffusersをソースコードからインストールしてみよう。
まずは、リポジトリを取得する。
git clone --depth 1 [email protected]:huggingface/diffusers.gitリポジトリの最上位ディレクトリに移動する。
cd ./diffusersインストールする。今回はエディタブルインストールする。
python3 -m pip install --no-build-isolation -v -e .インストールに成功すると、最後に以下のような出力が表示される。
Successfully installed diffusers-0.37.0.dev0 importlib_metadata-8.7.1 regex-2026.1.15 safetensors-0.7.0 zipp-3.23.0
インストールできている事を確認する。
python3 -c 'import diffusers; print(diffusers.__version__)'0.37.0.dev0
出来ていそうだ。
DDPMを使う
DDPM を使用してみる。これはGoogleが配布しているモデルで、とても軽量なモデルであるため、モデル自体の品質が重要でない場合の動作確認には向いている。
Pythonインタプリタでコードを実行し、モデルのロードから推論までを見ていく。まずはモデルをロードする。この時、ローカルのキャッシュにモデルが無ければダウンロードも行われる。
import torch
from diffusers.pipelines.ddpm.pipeline_ddpm import DDPMPipeline
pipeline = DDPMPipeline.from_pretrained("google/ddpm-cat-256", torch_dtype=torch.float16).to("mps")このパイプラインを使って推論を実行し、画像を生成する。シンプルなDDPMの実装の場合、推論ステップは1000回ほど必要になるしい。
generator = torch.Generator(device="cpu") # ここはあえてcpuを指定する(理由は後述)
result = pipeline(batch_size=1, generator=generator, num_inference_steps=10,) # 推論推論の結果が返ったら、その画像を表示して確認しよう。
result.images[0].show() # 画像を表示RuntimeError: Placeholder storage has not been allocated on MPS device! が発生した場合はdeviceが食い違っている
先程のコードの中の torch.Generator() は、deviceに"cpu"を指定しているが、"mps"を指定してしまうと RuntimeError が発生した。
RuntimeError: Placeholder storage has not been allocated on MPS device!
ソースコードを辿っていくと、 diffusers/src/diffusers/pipelines/ddpm/pipeline_ddpm.py で定義されているDDPMPipelineの以下のコードで、問題が発生していた。
if self.device.type == "mps":
# randn does not work reproducibly on mps
image = randn_tensor(image_shape, generator=generator, dtype=self.unet.dtype)
image = image.to(self.device)
else:
image = randn_tensor(image_shape, generator=generator, device=self.device, dtype=self.unet.dtype)
self.device.type は "mps" であるため、最初の if のブロックに入のだが、何やらあやしげなコメント「randn does not work reproducibly on mps」がある。どうやら mps では randn の再現性や挙動が環境依存になることがあるらしい。そのため、乱数テンソルを一時的にcpuで生成してからmpsに移動させているようだ。 randn_tensor() の呼び出しに device を指定していないため、デフォルト値の cpu が使われるようになっていた。generatorのdeviceはmpsを指定していると、この部分で食い違いが発生し、最終的に randn_tensor() 内の以下の処理でエラーするようになっていた。
latents = torch.randn(shape, generator=generator, device=rand_device, dtype=dtype, layout=layout).to(device)
僕の環境では、 randn_tensor() 呼出しの時にdeviceも渡すように修正してみたのだが、その場合でもエラーは発生しなかった。ただ、エラーが発生していないだけで、意図した挙動をさせられていない可能性はある。そのため、Generatorのdeviceにはcpuを指定する事で、エラーを回避した。
Stable Diffusion Web UIを使う
git clone --depth 1 [email protected]:AUTOMATIC1111/stable-diffusion-webui.gitcd stable-diffusion-webuipython3 -m pip install --no-build-isolation -v -e .#+end_src
* memo :noexport:
#+begin_src python
import os
import torch
from diffusers.pipelines.ddpm.pipeline_ddpm import DDPMPipeline
from src.utils import ExperimentalContext, options
def inference(pipeline, context: ExperimentalContext, batch_size, num_inference_steps=1000):
# 推論
images = pipeline(
batch_size=batch_size,
generator=context.generator,
num_inference_steps=num_inference_steps,
).images
# 画像の保存
for i, image in enumerate(images):
context.save_image(image, 'uncond', f'i{i}_n{num_inference_steps}')
@options
def main(seed, device):
batch_size = 1
# モデルの読み込み
pipeline = DDPMPipeline.from_pretrained('google/ddpm-cat-256', torch_No changes detected in the diff output.dtype=torch.float16).to(device)
context = ExperimentalContext(seed=seed, device=device, root_dir=os.path.join('out', 'ddpm_cat'))
inference(pipeline=pipeline, context=context, batch_size=batch_size, num_inference_steps=1000)
if __name__ == '__main__':
main()- https://huggingface.co/google/ddpm-cat-256
- https://zenn.dev/tf63/articles/diffusers-apple-tf63-20241126
RuntimeError: Failed to import transformers.models.clip.modeling_clip because of the following error (look up to see its traceback):
No module named 'torch._C._distributed_c10d'; 'torch._C' is not a package