0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

即戦力化 ディープラーニング実習(第七週)

Posted at

【第7週】画像の生成と変換

講義目録:即戦力化 ディープラーニング実習

はじめに

これまでの実習では、主に テキスト(txt2txt) 系タスクを扱い、
「生成 → 評価 → プロンプト改善」という一連の流れを体験してきました。
第7週では舞台を 画像分野 に移し、
1 行のコード変更で動かせる Stable Diffusion 系モデルを用いて

  • text-to-image:文章 → 画像をゼロから生成
  • image-to-image:既存画像を別スタイルに変換

を一気に体験します。

体験する内容は、次のgoogle colabで確認できます。

Google Colabへのリンク

1. 実習の目的

  • 画像生成(text-to-image)の基本操作を習得する

  • 画像変換(image-to-image / style-transfer)の代表的手法を比較する

    1. Img2Img : 画像を丸ごと別の画風へ変換する
    2. Instruct-Pix2Pix : 自然言語の指示文で部分編集を行う
    • Img2Imgと Pix2Pixの違いを理解する
    1. ControlNet (Canny) : 線画に着色する

2. CNN とは

今週から畳み込みニューラルネットワーク(Convolutional Neural Network; CNN) を用いた実習が始まります。

CNNは、画像のような “空間的に隣接するピクセル同士の関連” を捉えるのが得意なネットワークです。
畳み込み層は 小さなフィルタ(カーネル)を画像全体に滑らせる ことで、エッジ・テクスチャ・形状といった局所パターンを抽出します。

それを多層化(深層化)して、頑張って計算してくれるのがCNNです。

CNNの詳しい説明は、webでも書籍であちこちに存在しますので、ここでは詳しく説明しないことにします。

RNN とのちがい

先週まで扱った RNN(再帰型ネットワーク) は「時系列」や「文の単語列」のような 一次元の“順序依存” をモデリングするのに特化しています。RNN は「時間的文脈」, CNN は「空間的文脈」 を捉えるアーキテクチャだという点が最大の違いです。

3-1 共通の準備

最初に、共通のライブラリをpipでinstallします。

google colab で動かそうとすると、いろいろと面倒でした。
まずは、深く考えず、お試し実行を優先することにしましょう。

!pip uninstall -y diffusers transformers huggingface_hub peft sentence-transformers -q || true

# 衝突しない組み合わせをクリーンインストール
!pip install -q --no-cache-dir \
  "huggingface_hub==0.24.1" \
  "transformers==4.25.1" \
  "diffusers==0.26.3" \
  accelerate safetensors xformers

Google Colab上で実習する場合、上記セルを実行後、
「ランタイム ▸ 再起動」 を行ってください。そうしないと、いろいろとエラーがでてきます。

Colab ノートブック例
セルの配置やランタイム再起動の手順が不安な場合は、
▶︎ 画像生成と変換の Colab サンプル を使ってください。

3-2 画像生成(text-to-image)

Stable Diffusion v1-5 を使い、テキストから 512×512 px の画像をゼロから生成しましょう。


3-2-1 パイプラインのロード

from diffusers import StableDiffusionPipeline
import torch, datetime

pipe = StableDiffusionPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    torch_dtype=torch.float16,
).to("cuda")

初回は 4.3 GB の重みをダウンロードするため 1〜2 分かかります。

3-2-2 生成してみる

prompt = "A majestic tiger standing on a cliff at sunset, ultra-realistic, 8K"
#夕暮れの崖の上に立つ雄大な虎、超リアル、8K
image  = pipe(prompt, num_inference_steps=30, guidance_scale=7.5).images[0]
display(image)

ダウンロード.png

私の場合、きちんとトラが生成されました。みなさんは、いかがだったでしょうか。

なお、トラのimageは、後続の実習で再利用します。

では、prompt を変更し、みなさんも試してみてください。

えっ、日本語のプロンプトも試してみたいですって?

どうぞどうぞ。ぜひお試しあれ。

3-2-2 日本語プロンプトのお試し。

では早速、試してみましょう。
日本語と英語、それぞれ同じ内容のプロンプトを準備しました。

言語 プロンプト
英語 A black cat meows next to a hydrangea flower.
日本語 黒猫がアジサイの花の横でにゃーんと鳴いている。

では実行してみましょう。

prompt_en = "A black cat meows next to a hydrangea flower."
prompt_jp = "黒猫がアジサイの花の横でにゃーんと鳴いている。"

image_en = pipe(prompt_en, num_inference_steps=30, guidance_scale=7.5).images[0]
image_en.save("cat_en.png")
display(image_en)

image_jp = pipe(prompt_jp, num_inference_steps=30, guidance_scale=7.5).images[0]
image_jp.save("cat_jp.png")
display(image_jp)

英語で生成:
image.png

日本語で生成:
image.png

おお?猫に羽が生えている!! 

どうやらこのモデルは日本語が苦手なようですね。

私が試したところ、指示を日本語で与えたら、背中に羽の生えた猫?鳥?みたいなへんてこな画像が生成されました。

みなさんも、同じような状況だったのではないでしょうか。

その理由ですが、今回用いたモデルが日本語を苦手としているからなのです。ではどうすればいい?

日本語のプロンプトを英語に翻訳してあげればいいのです。

ではその翻訳は誰がするのかって?

そりゃもちろん、深層学習のモデルに行ってもらえばいいのです。

即戦力化 ディープラーニング実習の「第3週 翻訳と要約」で学んだ成果をここで生かす時が来ましたよ。

3-3 画像変換(image-to-image / style-transfer)

ここからは、先ほど生成した 虎の画像init_image として使い、
3 種類の変換手法(Img2Img / Instruct-Pix2Pix / ControlNet)を比較します。


3-3-1 共通コード

では最初に、3種類の変換手法に共通する部分です。

# 先ほど生成したトラの image を実習用のイメージに転用します
init_image = image.convert("RGB").resize((512, 512))

# 共通セットアップ
from diffusers import (
    StableDiffusionImg2ImgPipeline,
    StableDiffusionInstructPix2PixPipeline,
    ControlNetModel,
    StableDiffusionControlNetPipeline,
)
from diffusers.utils import load_image
import torch, requests, io, PIL.Image as Image

device = "cuda"          # GPU 
dtype  = torch.float16   # VRAM 節約

ポイント

  • init_image512×512 px・RGB に統一すると Stable Diffusion 1.5 系で最も安定します。
  • 以降の各パイプラインはすべて devicedtype を共通化し、メモリ効率を最大化します。

この準備ができたら、次節以降で

  1. Img2Img(画風変換)
  2. Instruct-Pix2Pix(指示文による部分編集)
  3. ControlNet (Canny)(線画固定+着彩)

を順に実行していきます。

3-3-2 Img2Img ─ 画風を「水彩画」へ変換

では、img2Img から始めましょう。先ほどのトラの絵を水彩画風に変換します。

pipe_img2img = StableDiffusionImg2ImgPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    torch_dtype=dtype,
).to(device)

prompt      = "A watercolor painting of the same scene, A majestic tiger standing on a cliff at sunset, ultra-realistic, 8K" 
#同じシーンを描いた水彩画, そのあとに、生成に利用したプロンプトをコピペしています

strength    = 0.75   # 0=original維持, 1=完全生成
guidance    = 7.5

image_out = pipe_img2img(
    prompt           = prompt,
    image            = init_image,
    strength         = strength,
    guidance_scale   = guidance,
    num_inference_steps = 30,
).images[0]

image_out

image.png

背景が良くなりましたが、しっぽが2本になりました。

まぁ、これなら良いほうでしょうか。

運が良ければなんとか原型をとどめているかと思います。

3-3-3 Instruct-Pix2Pix ─ 指示文で「夜景+星空」に編集

次は違う仕組みを使って、背景を編集してみます。

pipe_p2p = StableDiffusionInstructPix2PixPipeline.from_pretrained(
    "timbrooks/instruct-pix2pix",
    torch_dtype=dtype,
    safety_checker=None,    # NSFW フィルタ不要なら外しても
).to(device)
pipe_p2p.enable_attention_slicing()

instruction = "Make it a night scene with a starry sky"
#星空のある夜景にする
image_edit  = pipe_p2p(
    prompt            = instruction,
    image             = init_image,
    num_inference_steps = 30,
    guidance_scale      = 7.5,
    image_guidance_scale= 1.5,   # 入力画像をどれだけ信頼するか
).images[0]

image_edit

image.png

プロンプト通り、夜の景色になりましたね。

皆さんもいろいろ試してみてください。

3-3-4 Img2Img2 とpix2pix の違い

子の実習では、最初にimg2img で水彩画に、続いてInstruct-Pix2Pix(pix2pix)で夜景に変換しました。

似たような変換ですが、手法としては何が違うのでしょうか?

Img2Img は「元画像にノイズを混ぜてから prompt に従って描き直す」方式で、絵全体を新しいスタイルにリライトするのが得意です。

一方、 Instruct-Pix2Pix は「元画像・編集後画像・自然言語指示」のペアで追加学習されており、instruction を受けて 必要な部分だけを改変 するよう振る舞います。

3-3-4 ControlNet (Canny) ─ 線画を固定してアニメ調に着彩

続いて3番目の画風変換です。

線画に色を塗ってみましょう。

とはいえ最初の画像は普通のカラー画像のトラさんです。
そこで、

  1. エッジ抽出により線画を生成し、
  2. 続いて色を塗る
    という二段階の操作を行います。
# 1. ControlNet 重み(Canny)ロード
controlnet = ControlNetModel.from_pretrained(
    "lllyasviel/sd-controlnet-canny",
    torch_dtype=dtype,
)

pipe_canny = StableDiffusionControlNetPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    controlnet=controlnet,
    torch_dtype=dtype,
).to(device)
pipe_canny.enable_xformers_memory_efficient_attention()

# 2. Canny エッジを抽出
import cv2, numpy as np
np_img = np.array(init_image)
edges  = cv2.Canny(np_img, 100, 200)
edge_img = Image.fromarray(edges).convert("RGB").resize((512, 512))
display(edge_img)

# 3. 生成
prompt = "A vibrant anime style illustration"
#躍動感あふれるアニメ風イラスト
image_cn = pipe_canny(
    prompt           = prompt,
    image            = edge_img,
    num_inference_steps = 30,
    guidance_scale   = 9.0,
    controlnet_conditioning_scale = 1.0,
).images[0]

display(image_cn)

線画

image.png

おおって、なんか線画ってかっこよさげですね。
それなのに...

着色

image.png

色を塗ると、なんか幻滅。でも、色が塗れたのでよしとしましょう。
最初なら、こんなもんです。

こちらもプロンプトを変更して、どう変わるかを試してみてくださいね。

これで Img2Img → Pix2Pix → ControlNet の 3 手法を一通り体験できました。

🔚 第7週のまとめ

今週は、画像生成(text-to-image)と画像変換(image-to-image / style-transfer) を実習しました。

特に、image-to-image では3手法にチャレンジしました。

  • Img2Img
  • Instruct-Pix2Pix
  • ControlNet

✅ 今週のポイント

  • CNN とは何か、畳み込み層が “空間的文脈” を捉える原理と、RNN の “時間的文脈” との対比を学びました。
  • Stable Diffusion v1-5 で 512×512px の画像を生成し、prompt / guidance_scale / seed の3パラメータ調整を体験しました。
  • Img2Imgstrength を変えながら「画風(水彩画)変換」の自由度を検証しました。
  • Instruct-Pix2Pix で “Make it a night scene with a starry sky” のような自然言語指示により、局所編集を実行しました。
  • ControlNet (Canny) で線画に色を塗ってみました。

🔭 次回予告:「第8週 画像の特徴抽出」

次回は 「画像の特徴抽出 ― 画像からキーワードや特徴ベクトルを得る」 をテーマに進めます

  • Vision Transformer / CLIP などの 事前学習モデルを転用し、
  • 画像を入力すると 埋め込みベクトル(feature vector)自動キーワード(タグ) を取得。
  • 得られた特徴を使って 画像検索・クラスタリング・類似度計算 を体験します。
  • さらに、今週生成した画像をベンチマークに用い、
    「生成画像は検索システムでどのように表現されるか」 を実験的に確認します。

「生成→特徴抽出→検索」というワークフローは、
実サービスの“画像検索エンジン”や“レコメンドシステム”にも直結する重要ステップです。
どうぞお楽しみに!

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?