今年も残り10日ちょっとですね。
今日はRaspberry Pi Advent Calendar 2023の18日目の記事です。 先日のPython東海で話した内容をまとめただけの記事です…

はじめに

いつもとちょっと毛色が違って、Maker Faireとかに展示物を作る時にどうやってるかを雑にまとめた内容です。
先日のMFTで先行販売されていた雑に作るを読んで、どう考えて何やってるかをまとめてみるのも面白いかなーと。

展示物を作る動機

「展示があるから」これ以外にないです!
先日のMaker FaireはRaspberryPi Japanese Users Groupでの出展だったので、RasPiを使ったなにか新しい展示物作りたいわねーと思って作りました。
コロナ前はわりかし色々作ってたので展示物困らなかったのですが、最近は新しくなにか作ってなかっったのでまずは何か1個新しいものを作ろうと。
ちなみに、よく「何作ればいいかわかりません」って話聞きますが、出展すれば嫌でも作る必要でてきますよっと。

ネタだし

雑思考

  • RasPi4を使いたい
    • 性能よいし(※ RasPi5発表前)
  • 流行り物なにか取り入れたいなー
    • AIとか?
    • でもクラウド利用はNGだなー(※ 会場はNWがだいたい死ぬ)
  • 見た目でわかりやすいのがいいなー
  • でもめんどくさいのやだなー

環境的な変化

Pimoroniでセールがされていて、電子ペーパー(inky-impression)がお安く買える状況に。
これは買うしかない!ととりあえずポチーっと脳死で購入しました。

合体

雑思考とセールで買った電子ペーパーを組み合わせると「画像生成AIで電子ペーパーに画像表示させればいいのでは?」となったのでなんとなーく作りたいもののイメージが固まりました。

やり方調査と結果

先人がいないか

たぶん同じような考えをする人はいると思うのでやってる人がいないか調べてみる。
と、全く同じ感じでいい感じにまとめている人がいたので参考にする。
参考としたのはこちら「raspberry pi 4でStable Diffusionを動かしてみる(画像自動生成&更新フォトフレームの作成)」 だいたい、考え方はこのままいけると思うので、diffusersってのを使えばStable DiffusionがRasPiで動くと理解。

Stable Diffusionって?

  • 「ステーブルディフュージョン」と読む
  • ディープラーニングのtext-to-imageモデル
  • ミュンヘン大学、Stability AI社、Runway社が共同で公開
  • コードが公開されている
  • 著作権的にはちょっと課題も抱えているみたい

diffusersって?

  • 「ディフューザーズ」と読む
  • 色々なdiffusersモデルを共通なインターフェイスで利用できるパッケージ
  • モデルIDを切り替えれば簡単にモデル変更が可能
  • ???モデル???
    → 正直、正確な説明できるほど勉強できていない
  • 生成エンジン的なイメージでいじっている
  • メモ的に「Software Design 2023年6月号」から連載されている「【新連載】Stable Diffusionで学ぶ画像生成AIのしくみ」でちょっと理解は進んだ気がする。

作ってみる

ここからインストールとかの話。

前提条件

  • RaspberryPi 4B 8GBモデルを使用
  • USB-SSDブートにしてSDカードは利用しない
  • OSはbullseye
    ※ bookwormではないです
  • 2023/9月頃に実施した手順です
  • 先程の参考ページ等と実施手順を変えています(不要な手順があったため)

RasPiへのdiffusersのインストール手順

環境

$  lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description:    Debian GNU/Linux 11 (bullseye)
Release:        11
Codename:       bullseye

手順

ぐぐってでてくるちょっと前の手順だとpytoachのインストールでエラーがでるので誰かがmakeしたのを使うとあったりしますが、10月時点では普通にインストールできます。 メモリが足りないのでSWAPのサイズ変更が必要です。
なので、SDカードでは使わずUSB-SSDbootで使いましょう。

環境確認

$ uname -a
Linux pi4 6.1.21-v8+ #1642 SMP PREEMPT Mon Apr  3 17:24:16 BST 2023 aarch64 GNU/Linux 

アップデート

このあたりはお約束的な

$ sudo apt update
$ sudo apt upgrade

必要パッケージインストール

$ sudo apt install -y python3-pip libjpeg-dev libopenblas-dev libopenmpi-dev libomp-dev

pythonパッケージインストール

$ pip3 install setuptools==58.3.0
$ sudo pip3 install Cython
$ sudo pip3 install torch
$ sudo pip3 install transformers
$ sudo pip3 install diffusers
$ sudo pip3 install accelerate
$ sudo pip3 install scipy

動作確認(エラーがなければOK)

$ python3
>>> import torch

SWAPサイズ変更

$ diff -u /etc/dphys-swapfile{.orig,}
--- /etc/dphys-swapfile.orig    2023-05-03 11:55:51.329630118 +0900
+++ /etc/dphys-swapfile 2023-09-16 17:49:43.165817087 +0900
@@ -13,7 +13,8 @@

 # set size to absolute value, leaving empty (default) then uses computed value
 #   you most likely don't want this, unless you have an special disk situation
-CONF_SWAPSIZE=100
+#CONF_SWAPSIZE=100
+CONF_SWAPSIZE=4096

 # set size to computed value, this times RAM size, dynamically adapts,
 #   guarantees that there is enough swap without wasting disk space on excess
@@ -24,3 +25,4 @@
 #   this is/was a (outdated?) 32bit kernel limit (in MBytes), do not overrun it
 #   but is also sensible on 64bit to prevent filling /var or even / partition
 #CONF_MAXSWAP=2048
+CONF_MAXSWAP=4096

再起動

$ sudo shutdown -r now

SWAPサイズ確認

$ swapon -s

使い方

整理しきれてないですが、全体のコードはgithubにあります。
今回は画像サイズをInky pHatの解像度に合わせて、step数を減らすことで1時間程度で生成されるようにしていますが、step数を増やすことで画像のクオリティを上げることができすます。その代わり時間はかかります。 このあたりはどう使うかで変わると思うので修正してみてください。

以下、使い方コードの説明です。


from diffusers import StableDiffusionPipeline, EulerDiscreteScheduler

# モデル名指定
model_id = "stabilityai/stable-diffusion-2"
scheduler = EulerDiscreteScheduler.from_pretrained(model_id, subfolder="scheduler")

# パイプラインの作成
pipe = StableDiffusionPipeline.from_pretrained(model_id, scheduler=scheduler, low_cpu_mem_usage=True)

# CPUのみ使用の指定(RasPiのGPUは使えなさそう)
pipe = pipe.to(cpu")

# CPUのみ使用の指定(RasPiのGPUは使えなさそう)
image = pipe(prompt, num_inference_steps=steps, height=448, width=640).images[0]

# 生成したい画像の設営
prompt = "space cat"

# ステップ数。この環境だと50くらいで1時間ちょいくらい
steps = 50

# 画像の生成
# prompt:生成したい画像
# num_inference_steps:ステップ数。RasPiだと50stepで1時間程度(歩留まりはお察し)
# height,widthで画像サイズ指定
# ※ モデルによって変わるのでモデルの手順を確認
image = pipe(prompt, num_inference_steps=steps, height=448, width=640).images[0]

# 生成した画像を保存
image.save(os.path.join(image_dir, file_name))

生成された画像

ねこ1

ねこ2

戦車

他のモデルとか

ここで探そう。使い方はモデル事に差異があるので確認必要です。
https://huggingface.co/models?other=stable-diffusion

展示形態

もっときれいにまとめたかったけどいつもの雑思考で100均のスマホスタンドで引っ掛ける形に。
ほんとは額縁的なのをつけたかったけど…

展示の形を考えると冷却不足となったので気合FANで冷却した。

当日の展示はこんな形に。実に地味。

まとめとか反省とか

  • 初回起動時はモデル確認のためかインターネット接続が必要
    • MFT2日目は朝から回線が死んでいたので動かず…
  • いい感じのプロンプトまでは考えられず
    • 今回は適当なワードをランダムに組み合わせた程度…
  • 表示と生成をうまく組み合わせられなかった
    • InkyImpressionがsignalを使っていて理解しきれず
  • MFTの会場では気づかれない、地味すぎた。
    • 説明資料が必要だった
    • 出展でPOP大事。ちゃんと作ろう…
    • 毎回思って手が回らない…
  • 説明して気づかれると「できるの!?」といった反応が多かった
  • RasPi5の性能がいい感じにあがってるので入手したら移植&試したい
  • みんなも雑にRasPi工作をしよう!!