TL;DR
- 本文解決:想固定 AI 生成角色形象、不想自架 GPU、想找一條最省事的路徑
- 推薦給:插畫家、創作者、IG 短影片帳號經營者、想做角色 IP 的人
- 讀完你會知道:如何用 15 張截圖在 fal.ai 訓練出一顆可重複生成同一角色的 LoRA、實際花費 $9、實際時間 131 分鐘
---
📌 目錄
---
這篇在講什麼
我用桌面上 15 張隨手截的角色圖(白髮黃眼、黃星圍巾的女孩),在 fal.ai 上訓練了一顆 Wan 2.2 角色 LoRA。整個流程從零開始走完,含資料整理、上傳、排隊、訓練,總共花了 131 分鐘 跟 $9 美金,最後拿到兩顆 146MB 的 .safetensors 永久檔案,之後生圖、生影片只要寫 prompt 帶上 ohwx_character 觸發詞,角色就會穩定出現。
這篇不是介紹文,是「你照著做也能跑出來」的實作教學。包含資料怎麼放、caption 怎麼寫、踩過哪幾個坑、為什麼排隊那麼久、總共付了多少錢。
下面這張就是訓練資料的其中一張,14 張類似畫風的同一角色:
---
為什麼需要 LoRA
如果你只是要「同一個角色,不同姿勢、不同場景、不同表情」反覆出現,現有方案其實都不太行。我列三個常見做法跟它們各自卡在哪:
方案 A:純 prompt 描述
做法:在 prompt 裡寫「白髮、黃眼、黃星圍巾、白色外套」。
痛點:換一次 seed 角色就變人。長度、髮色 OK,但臉型、眼距、嘴型每次都不一樣。觀眾一眼看出「這不是同一個角色」。
方案 B:reference image i2v
做法:丟一張角色圖當 reference,叫模型保持。
痛點:模型只記住「表面紋理」。角色一轉身、一蹲下、一遮臉,就崩。適合「角色靜止、鏡頭動」的場景,不適合「角色動」。
方案 C:自架 DreamBooth / Kohya
做法:自己租 A100、裝 Python 環境、跑訓練腳本。
痛點:要會 Linux、會 CUDA、要 debug 環境衝突,第一次跑通至少 3 天。電費 + GPU 租金加起來不見得便宜。
LoRA on SaaS 的解法
把訓練這步丟給 fal.ai,自己只負責:
.safetensors 檔案之後生任何圖、任何影片,都把這顆 LoRA 掛上去 + prompt 帶觸發詞,角色形象就鎖死。第一次成本約 $9,之後生圖 / 影片只算推理費用,不用再付訓練錢。
---
LoRA 是什麼 + Wan 2.2 雙 transformer 架構
LoRA(Low-Rank Adaptation) 是一種「微調但不動原模型」的技術。原始 Wan 2.2 模型有 14B 參數(約 28GB),LoRA 不去動它,而是在它上面加一層「補丁」(你訓練出來的 .safetensors,只有幾百 MB),讓模型針對你的角色做出反應。
為什麼是兩顆 .safetensors?
Wan 2.2 跟 Wan 2.1 最大的差別是改成 雙 transformer 架構:
┌─── high noise transformer ── 你的 high LoRA
輸入 ──→ ┤
└─── low noise transformer ── 你的 low LoRA
- High noise transformer:負責早期 denoising 階段(粗略構圖、姿勢)
- Low noise transformer:負責後期 denoising 階段(細節、紋理、臉部)
---
fal.ai vs Replicate vs RunPod vs 自架
選平台時我比較了 4 個選項。實際使用後對照如下:
| 維度 | fal.ai | Replicate | RunPod | 自架 (A100) |
|---|---|---|---|---|
| 訓練 LoRA | ✓(一條龍) | ✓ | △(要自己拼) | ✓(最自由) |
| Wan 2.2 支援 | ✓ | △ | ✓ | ✓ |
| 不用碰 Python 環境 | ✓ | ✓ | ✗ | ✗ |
| 拿到 .safetensors | ✓ | ✓ | ✓ | ✓ |
| 訓練 2000 steps 成本 | $9 | ~$10-15 | $5-8(要自己跑) | $20+ 月租 |
| 訓練 2000 steps 時間 | 131 分鐘 | 60-90 分 | 看 GPU 等待 | 30-60 分 |
| 第一次跑通難度 | 低 | 低 | 中 | 高 |
---
從 0 開始的安裝步驟
前置需求
| 項目 | 用途 | 怎麼裝 |
|---|---|---|
| macOS(或 Linux) | 跑 prepare 腳本 | — |
| Python 3.10+ | 跑 training script | brew install python@3.11 |
fal-client Python 套件 | 呼叫 fal.ai API | pip install fal-client |
| Real-ESRGAN ncnn vulkan | 把截圖放大到 LoRA 友善尺寸 | 下面教 |
| FAL_KEY | fal.ai API 金鑰 | 去 https://fal.ai/dashboard/keys 申請 |
| 餘額 $10 | 訓練 + 試生幾張圖 | https://fal.ai/dashboard/billing |
安裝 Real-ESRGAN(一次性)
mkdir -p ~/tools/realesrgan && cd ~/tools/realesrgan
curl -fsSL -o r.zip 'https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesrgan-ncnn-vulkan-20220424-macos.zip'
unzip r.zip
chmod +x realesrgan-ncnn-vulkan
xattr -d com.apple.quarantine realesrgan-ncnn-vulkan # macOS 解隔離
設定 FAL_KEY
echo 'export FAL_KEY="你的key"' >> ~/.zshrc
source ~/.zshrc
⚠️ 千萬不要把 key commit 到 git,建議放.zshrc或.envrc,不要寫死在腳本裡。
---
資料準備細節
為什麼是 15 張,不是更多
| 張數 | 結果 |
|---|---|
| < 10 | 容易 overfit,生出來表情僵硬 |
| 15-20 | 甜蜜點,臉特徵記住、姿勢不僵 |
| > 30 | 訓練變慢、邊際效益遞減 |
為什麼要先用 Real-ESRGAN 放大
桌面截圖通常 800-1200 px,但 Wan 2.2 LoRA 訓練的 resolution 設定是 1024。用 anime 專用模型 realesrgan-x4plus-anime 4x 放大,把線條補回來,避免訓練吃進模糊資料。
caption .txt 怎麼寫(最重要)
每張 01.png 旁邊放一個 01.txt,內容是這張圖的描述。規則:
| 該寫的 | 不該寫的 |
|---|---|
| 表情(smiling, smirk) | 髮色(白髮) |
| 姿勢(half body, side view) | 服裝特徵(黃星圍巾) |
| 構圖(close-up, full body) | 眼睛顏色(黃眼) |
範例 caption:
ohwx_character, smiling, upper body, looking at viewer
ohwx_character 是觸發詞,所有 caption 開頭都要有這個,之後生成時用它呼叫角色。
---
實際下的指令
Step 1:自動整理資料(一行)
我寫了個 bash 腳本 prepare_lora.sh,做四件事:抓桌面最新 N 張 png、複製重命名、Real-ESRGAN 4x、產生 caption .txt、打包成 zip。
./prepare_lora.sh 15 ohwx_character
跑完會在 ~/Desktop/character_lora/character.zip 產生 19MB 的訓練資料包。
Step 2:啟動訓練
export FAL_KEY="..."
python3 train_lora.py \
--zip ~/Desktop/character_lora/character.zip \
--trigger ohwx_character \
--steps 2000 \
--learning-rate 0.0007
Step 3:訓練 script 核心邏輯
train_lora.py 主要就是兩段:上傳 zip、subscribe API。重點是這段:
import fal_client
training_data_url = fal_client.upload_file("character.zip")
result = fal_client.subscribe(
"fal-ai/wan-22-image-trainer",
arguments={
"training_data_url": training_data_url,
"trigger_phrase": "ohwx_character",
"steps": 2000,
"learning_rate": 0.0007,
"is_style": False, # character mode (face detection on)
"include_synthetic_captions": False, # 用我們自己的 .txt
},
with_logs=True,
)
# 拿到兩顆 .safetensors URL
low_url = result["diffusers_lora_file"]["url"]
high_url = result["high_noise_lora"]["url"]
Step 4:之後怎麼用
拿到 LoRA 後,用 i2v endpoint 生影片時這樣帶:
fal_client.subscribe(
"fal-ai/wan/v2.2-a14b/image-to-video/lora",
arguments={
"image_url": "https://你的reference圖.png",
"prompt": "ohwx_character walking in cyberpunk street",
"num_frames": 161,
"frames_per_second": 16,
"resolution": "720p",
"loras": [
{"path": high_url, "scale": 0.9, "transformer": "high"},
{"path": low_url, "scale": 0.9, "transformer": "low"},
],
},
)
scale 設 0.9 是甜蜜點,太低不像、太高僵硬。
---
踩到的 4 個坑
⚠️ 坑 1:wan-22-trainer 跟 wan-22-image-trainer 不一樣
第一次我用 fal-ai/wan-22-trainer/i2v-a14b,回 404。後來才發現 fal.ai 上有兩個 Wan 2.2 trainer:
| Endpoint | 吃的資料 | 用途 |
|---|---|---|
fal-ai/wan-22-trainer/i2v-a14b | 影片 dataset | 訓練動作風格 |
fal-ai/wan-22-image-trainer | 靜態圖片 | 訓練角色 / 畫風 ✅ |
⚠️ 坑 2:bash 全形括號吃變數
prepare_lora.sh 一開始有這行:
info "用模型($ESRGAN_MODEL_NAME)"
執行報 $ESRGAN_MODEL_NAME: unbound variable。原因是全形 ) 的 UTF-8 byte 跟變數名解析衝突。修法:bash 字串內全形括號全部換半形,或在變數加 ${VAR} 強制邊界。
⚠️ 坑 3:zsh 跟 bash 陣列起始 index 不一樣
腳本裡用 ${ARRAY[0]} 取第一個元素,在 bash 是「第一個」,在 zsh 是「空字串」(因為 zsh 從 1 開始)。如果你用 macOS 預設 shell(zsh),記得在腳本開頭加 #!/usr/bin/env bash,或顯式 bash -c '...'。
⚠️ 坑 4:排隊 130 分鐘的真相
文件說「60-90 分鐘」,我實際跑了 131 分鐘。其中前 ~120 分鐘都沒有 log 輸出,只有「queued」。原因是:
- 訓練 GPU 在排隊系統裡優先序低於 inference(推理是即時計費,訓練是 batch)
- 美西早晨 / 中午是高峰期,等待時間更長
- 一旦輪到,實際訓練只花 ~10 分鐘
---
時間 / 成本拆解
| 階段 | 時間 | 成本 |
|---|---|---|
| 撿截圖 + Real-ESRGAN 放大 + caption | 5 分鐘 | $0 |
| 上傳 zip 到 fal.ai | 10 秒 | $0 |
| 排隊 + 訓練(2000 steps) | 131 分鐘 | $9.00 |
| 下載 .safetensors 本機備份 | 30 秒 | $0 |
| 試生 1 張角色圖(驗證效果) | 20 秒 | ~$0.05 |
| 合計 | 約 2.5 小時 | 約 $9.05 |
之後生圖片:每張幾分錢。
也就是說 第一次的 $9 是固定成本,之後角色「終身免費復活」(只要 fal.ai 不收掉這條 URL,或你保留本機 .safetensors)。
---
心法
.gitignore。---
🔗 延伸資源
- fal.ai Wan 2.2 Image Trainer 官方文件
- fal.ai Wan 2.2 i2v + LoRA endpoint
- Real-ESRGAN GitHub repo
- Wan 2.2 模型 paper(arXiv)
- LoRA 原始論文(Hu et al., 2021)
我輩修行之人,以聖的標準要求自己,以凡的眼光理解別人。