Nosana: アクセスしやすいGPUでStable Diffusionモデルを実行する

Stable Diffusionは、テキストの説明から詳細な画像を生成する(text-to-image)、テキストに基づいて既存の画像を変更する(image-to-image)、さらに多くのことを行うことができる強力なオープンソースのディープラーニングモデルです。画像を低次元の潜在空間にエンコードし、ノイズを加え、次にテキストプロンプトに導かれてそのノイズを予測・除去するモデルを使用する潜在拡散モデルの一種です。

このノートブックでは、基本的な概念をカバーし、すぐに始められるように明快で簡潔なコードを提供します。以下を探索します。

  1. セットアップ: ライブラリのインストールとAPIキーの読み込み。
  2. テキストから画像(txt2img): テキストプロンプトだけで画像を作成。
  3. 画像から画像(img2img): テキストプロンプトで既存の画像を変更。
  4. Depth-to-Image: 画像の深度マップを使って生成を行う、より高度なテクニック。

始めましょう!

1. セットアップ

画像生成のようなGPUを大量に使うワークロードでは、Nosanaを使ってJupyter Notebook環境を簡単に作成できます。

Nosanaダッシュボードにアクセスし、Pytorch Jupyter Notebookテンプレートを選択するだけです:

docker.io/nosana/pytorch-jupyter:2.0.0

これにより、GPUサポート付きのJupyter Notebook環境が起動し、Stable Diffusionや他のディープラーニングモデルの実行に最適です。 ヒント: Jupyter Notebook UIをローカルまたはVS Codeで実行したい場合は、Nosana Base URLをノートブックのKernel URLとしてコピー&ペーストするだけです。これにより、好みのローカル環境で作業しながら、NosanaのリモートGPUリソースを使用できます。 次に、必要なPythonライブラリをインストールします。diffusersはHugging Faceから提供される拡散モデル用の中核ライブラリです。transformersはテキスト処理コンポーネントに、accelerateは処理を高速化するのに必要です。python-dotenvを使えばAPIキーを安全に管理できます。 また、このノートブックと同じディレクトリに.envファイルを作成する必要があります。このファイルには、事前学習済みモデルのダウンロードに必要なHugging Face APIトークンが保存されます。.envファイルに以下の行を追加してください:

HUGGINGFACE_ACCESS_TOKEN='your_api_key_here'
%pip install diffusers transformers accelerate python-dotenv Pillow -q
Note: you may need to restart the kernel to use updated packages.
# Install ipywidgets for tqdm progress bars in Jupyter
%pip install ipywidgets --upgrade -q
Note: you may need to restart the kernel to use updated packages.
import torch
from diffusers import AutoPipelineForText2Image, AutoPipelineForImage2Image, StableDiffusionDepth2ImgPipeline
from PIL import Image
import requests
from dotenv import load_dotenv
import os

# Create an .env file and echo your token into the file
load_dotenv()
api_key = os.getenv("HUGGINGFACE_ACCESS_TOKEN")

# Check for GPU availability
device = "cuda" if torch.cuda.is_available() else "cpu"
torch_dtype = torch.float16 if torch.cuda.is_available() else torch.float32

print(f"Using device: {device}")
Using device: cpu

2. テキストから画像(txt2img)

これはStable Diffusionで最も一般的な使い方です。テキストの説明から画像を作成します。プロセスでは、プロンプト(見たいもの)と、オプションでネガティブプロンプト(避けたいもの)を提供します。 主なパラメータ:

  • prompt: 望む画像を表す文字列。
  • negative_prompt: 画像に含めたくない用語の文字列。
  • num_inference_steps: ノイズ除去ステップの数。ステップ数が多いほど品質が高くなる可能性がありますが、時間もかかります。25〜50の間がバランスが良いです。
  • guidance_scale: プロンプトへの従順度。高い値ほど厳密に従います。通常、7.5前後がうまく機能します。
import time
from huggingface_hub import login
from diffusers import AutoPipelineForText2Image
import torch
from IPython.display import display

# Authenticate with Hugging Face Hub
login(token=api_key)

# # Load the text-to-image pipeline with authentication
# txt2img_pipe = AutoPipelineForText2Image.from_pretrained(
#     "stable-diffusion-v1-5/stable-diffusion-v1-5", 
#     torch_dtype=torch.float32,   # assuming you're using GPU
#     use_safetensors=True,
#     token=api_key
# ).to("cuda")   

# Load the text-to-image pipeline with authentication
txt2img_pipe = AutoPipelineForText2Image.from_pretrained(
    "stable-diffusion-v1-5/stable-diffusion-v1-5", 
    torch_dtype=torch.float32,   # CPU must use float32
    use_safetensors=True,
    token=api_key
).to("cpu") # change to cpu or mps

# Define the prompt
prompt = "A cinematic shot of a cat in a library, wearing a monocle, detailed, 8k"
negative_prompt = "blurry, low quality, deformed, ugly"

# Measure time
start_time = time.time()

image = txt2img_pipe(
    prompt=prompt, 
    negative_prompt=negative_prompt, 
    num_inference_steps=30, 
    guidance_scale=7.5
).images[0]

end_time = time.time()
elapsed_time = end_time - start_time

print(f"Image generated in {elapsed_time:.2f} seconds")

# ✅ Display inline in Jupyter
display(image)
Loading pipeline components...:   0%|          | 0/7 [00:00<?, ?it/s]
  0%|          | 0/30 [00:00<?, ?it/s]
Image generated in 178.60 seconds

3. 画像から画像(img2img)

Image-to-imageでは、初期画像とプロンプトを提供して画像の変換をガイドします。これは、画像の全体的な構成を保ちながらスタイルを変えたり、内容を変更したりするのに最適です。 新しい主なパラメータは:

  • strength: 0.0から1.0の間の値で、元の画像がどれだけ変更されるかを制御します。低い値ほど元の画像が多く残り、高い値ほどモデルに創造的自由が与えられます。
# Load the image-to-image pipeline
img2img_pipe = AutoPipelineForImage2Image.from_pretrained(
    "stable-diffusion-v1-5/stable-diffusion-v1-5", 
    torch_dtype=torch_dtype, 
    use_safetensors=True
).to(device)

# Load an initial image from a URL
url = "https://upload.wikimedia.org/wikipedia/commons/thumb/e/ea/Van_Gogh_-_Starry_Night_-_Google_Art_Project.jpg/1280px-Van_Gogh_-_Starry_Night_-_Google_Art_Project.jpg"
init_image = Image.open(requests.get(url, stream=True).raw).resize((768, 600))

prompt = "A futuristic cityscape at night, high-tech, neon lights, in the style of Blade Runner"

# Generate the new image
image = img2img_pipe(
    prompt=prompt,
    image=init_image,
    strength=0.75,
    guidance_scale=7.5
).images[0]

# Display the transformed image
image

4. Depth-to-Image

Depth-to-imageは、初期画像の深度情報を使って新しい画像を生成する高度なテクニックです。これは、元のシーンの3D構造と構成を維持しながら、内部のスタイルや物体を完全に変更するのに非常に強力です。

モデルはまず入力画像から深度マップを推定し、それとプロンプトを使って生成プロセスをガイドします。

# Load the depth-to-image pipeline
depth_pipe = StableDiffusionDepth2ImgPipeline.from_pretrained(
    "stabilityai/stable-diffusion-2-depth",
    torch_dtype=torch_dtype,
).to(device)

# Use the same initial image
url = "https://upload.wikimedia.org/wikipedia/commons/thumb/e/ea/Van_Gogh_-_Starry_Night_-_Google_Art_Project.jpg/1280px-Van_Gogh_-_Starry_Night_-_Google_Art_Project.jpg"
init_image = Image.open(requests.get(url, stream=True).raw).resize((768, 600))

prompt = "Two majestic wolves howling at the moon, fantasy art, detailed"

# Generate the new image using depth information
image = depth_pipe(
    prompt=prompt, 
    image=init_image, 
    strength=0.7
).images[0]

# Display the result
image

まとめ

おめでとうございます!3つの異なるテクニックを使ってStable Diffusionで画像を生成できました。

基本をカバーしましたが、探索できる世界は広大です。

  • プロンプトエンジニアリング: 高度に詳細なプロンプト、アーティスト名、スタイルを試す。
  • 異なるモデル: Hugging Face Hubには、特定のスタイル(例: アニメ、フォトリアリズム)用に数千ものカスタム学習済みモデルがあります。
  • スケジューラ: diffusersライブラリでは、画像生成の速度と品質に影響を与えるさまざまなスケジューラに切り替えることができます。
  • GPUリソース: Nosanaを使えば、Stable Diffusionや他のディープラーニングワークロードを実行するための強力なGPUリソースに簡単にアクセスできます。クラウド上でも、ローカルノートブックをリモートカーネルに接続することでも可能です。

Happy diffusing! 🎉