這篇文章記錄嘗試在Android手機跑Stable Diffusion,用於AI繪圖的過程,免Root。
Why? 因為你值得,寶礦力水得。
看到Github有人用8GB的樹莓派4跑Stable Diffusion。同為ARM架構的裝置,那照理說高階手機應該也可以如法炮製。
1. 系統資訊#
- 手機:Sony Xperia 5 II (Android 13)
- CPU:高通Snapdragon 865 (Adreno 650)
- RAM: 8GB
- 準備30GB以上的空間,還有很快的4G網路。
2. 設定Linux環境#
安裝 Termux
安裝 proot Debian環境,只要下載步驟1的最小系統,使用root帳號,不用裝桌面環境。
登入Proot Debian
proot-distro login debian --shared-tmp
- 安裝git, vim, Python, Pip
apt update
apt install git git-lfs vim python3 python3-pip
- 如果有需要可以安裝 Anaconda。
3. 安裝Stable Diffusion#
我下載的是最接近原始的版本,沒有圖形界面,要自己寫Pyhton程式呼叫Stable Diffusion算圖。
- 從runwayml的儲存庫下載全部模型,約30GB
git clone https://huggingface.co/runwayml/stable-diffusion-v1-5
cd stable-diffusion-v1-5
git lfs pull
- 接著安裝Python依賴套件
pip install --upgrade diffusers transformers accelerate ftfy xformers
4. 撰寫Stable Diffusion算圖程式#
用預設的512x512像素下去算Termux會直接崩掉,恐怕需要16GB RAM的電競手機才負荷得了。我的8GB RAM手機最多試到320x320就是極限了(圖片長寬需為2的N次方)。
至開發人員選項,禁止一切程式背景運作,以將資源集中給Termux。另外啟用充電時螢幕不休眠的選項。
Android預設會殺死佔用過多CPU的行程,參見 此篇於電腦安裝ADB工具,並執行以下指令,將
max_phantom_processes
的值設高一些。
adb shell "/system/bin/device_config set_sync_disabled_for_tests persistent; /system/bin/device_config put activity_manager max_phantom_processes 2147483647"
- 回到Termux,進入stable-diffusion-v1-5的上層目錄,新增
app.py
cd ~
vim app.py
- 填入以下內容。
from diffusers import StableDiffusionPipeline, EulerDiscreteScheduler
# 使用本機模型
model_id = "./stable-diffusion-v1-5"
# 使用Euler採樣
scheduler = EulerDiscreteScheduler.from_pretrained(model_id, subfolder="scheduler")
# 啟用低RAM佔用,長寬320像素,步數50
pipe = StableDiffusionPipeline.from_pretrained(model_id, scheduler=scheduler, low_cpu_mem_usage=True, height=320, width=320, num_inference_steps=50)
# 規避NSFW偵測
pipe.safety_checker = lambda images, clip_input: (images, False)
# 算圖提示詞
prompt = "A victorian woman stands on grass field."
# 開始算圖,先測試使用CPU
image = pipe(prompt).images[0]
# 存檔
image.save("result.png")
- 開始算圖
python app.py
用CPU算大約需要30分鐘。
算圖時RAM幾乎是吃滿的狀態,Termux可能會隨時崩潰,不行的話就嘗試降低圖片長寬。
算好後,要取出proot裡的圖檔,將其移動至手機內部儲存空間。
mv result.png /sdcard
- 成品像這樣。算圖下限是256x256像素,在那之下的圖片基本不能看。
5. 使用Aderno GPU算圖#
藉由實驗性的virglrenderer專案,就能讓Stable Diffusion吃到Vulkan,進而使用手機GPU加速算圖。
- 在Termux中編譯 virglrenderer,執行virgl伺服器。
MESA_NO_ERROR=1 MESA_GL_VERSION_OVERRIDE=4.0 GALLIUM_DRIVER=zink virgl_test_server --use-egl-surfaceless
- 登入Proot,在執行算圖程式前加上
GALIIUM_DRIVER=virpipe
讓其使用GPU,程式碼不用改。
GALLIUM_DRIVER=virpipe python app.py
GPU加速大約能降低一點點算圖時間。
算出來的結果差距不大。
6. 在chroot裡跑Stable Diffusion#
如果手機RAM不足,何不用SWAP就好了?
仿造上面的步驟安裝Python和Stable Diffusion,或者直接從proot-distro複製檔案 (路徑為
/data/data/com.termux/files/usr/var/lib/proot-distro/installed-rootfs/ubuntu/root
)。建立8GB的SWAP檔案,這樣手機就有8+4+8=20GB的RAM了。如果不做此步驟,chroot硬算下去手機會直接重開機。
dd if=/dev/zero of=/swapfile bs=1M count=8192 status=progress
chmod 0600 /swapfile
mkswap /swapfile
swapon /swapfile
試著將圖片大小調整為標準的512x512像素,嘿,可以運算了。RAM吃多兇可想而知,所以得用ADB Shell或SSH進入chroot防止Termux崩掉。
算一小時後的成品。好像在說:你為什麼要花這麼多時間幹這種事情