本地 AI 短劇生成完全失敗實錄:30 天 17 版 5060 Ti 16GB 血淚教科書

寫給:手裡握著 5060 Ti / 3090 / 4070 / 4080,想用 ComfyUI 拼出「五十歲女主逆襲」那種 AI 短劇的工程師、創業者,以及任何被「本地全免費」感動過的人。

不寫給:想看「成功 case 抄一抄就跑通」的人。整篇沒有 happy path,沒有一鍵腳本。有的只是 30 天 17 版 pipeline 全部走過、v17 第四版按下 ctrl+c 認輸的那種真實。

跳過序章直接看程式碼 → 第 6 章(v13 MuseTalk patch)。看雲端比較 → 第 10 章。看硬體上限 → 第 2 章。


第 1 章 序章

摘要:在你按下「ComfyUI 安裝」之前,先確認你不是在重複我們的 30 天。

1.1 這 30 天是怎麼開始的

起點是 YouTube《五十岁,我的人生刚刚开火》(ID tGbbu3axuBE):50 歲女主被外遇離婚、創業反殺,30 集 × 5 分鐘 AI 連續劇,YouTube 廣告 + 抗老精華液帶貨在簡中圈風生水起。

我看完立項,13 角色設好 LoRA trigger,PC 5060 Ti 16GB 改全天候 ComfyUI。30 天後成績單:17 版 pipeline / 1 個 ep1(17.7 分鐘 / 450 sub-shot / 21 hr 連跑)/ 7 個用戶批評 / 3 個無解問題 / 0 集能上線。

文章要說:消費級 16GB VRAM 跑產業級短劇生成是物理有上限的路,上限不在「明年新顯卡」,在「現在這代 diffusion 架構本身」。

1.2 我做這篇文章的成本

投入 數量
開發天數 / Pipeline 版本 30 天 / 17 版
GPU 全速時數 / WSL OOM 350+ hr / 80+ 次
Flux LoRA / Wan22 / MuseTalk 運算量 13 角色 × 100 step 30 hr / 620 clip / 240 shot
電費(30 天) NT$650

重來一次,前 25 天我會跳過,直接走「雲端 API + ComfyUI 本地補刀」混合路線。

1.3 / 1.4 誰該讀 / 誰不該讀

該讀:消費卡跑 AI 短劇創作者 / $0 預算研究 AI 影片可行性的工程師 / 已買 4070-5060 Ti 想理性確認的人。 不該讀:期待「跑通腳本」的人;不會 Python / SSH / ffmpeg 的人;預算 > NT$10,000/月想外包雲端的人。

1.5 文章結構

10 章按時間軸 + 技術主題排序。每章格式:踩坑 → 分析 → 教訓。沒有藏拙,這是 30 天結束時的最終狀態。

1.6 一個前情提要

我不是 ComfyUI 新手 —— Flux LoRA 訓過 13 個、Wan2.1 跑過上百 clip、workflow JSON 能徒手寫。這篇是一個有經驗的人被 16GB VRAM + diffusion 架構天花板雙重壓制 30 天的紀錄。

教訓 1.1:「本地全免費」裡「全」跟「免費」都是假的,只有「本地」是真的。 教訓 1.2:30 天失敗成本 ≈ 雲端 API 兩年訂閱費。


第 2 章 硬體真相:5060 Ti 16GB 真實能力地圖

摘要:先講清楚 16GB VRAM 在 2026 年的 diffusion 世界裡,能做什麼、不能做什麼。後面所有失敗都是這張地圖的子集。

2.1 硬體規格全表

元件 規格
GPU RTX 5060 Ti 16GB GDDR7(Blackwell sm_120, CUDA 12.8 / driver 13.2)
CPU AMD Ryzen 9, 32 core / 64 thread
RAM 128GB DDR5(WSL2 配 112GB,host 留 16GB)
儲存 2TB NVMe Gen4,ComfyUI 走 native ext4 /home/user/ComfyUI/(不走 9P /mnt/c/)
OS Windows 11 + WSL2 Ubuntu 22.04
Orchestrator Mac M4 16GB(純 SSH 控制)
網路 Mac → SSH key auth → PC 192.168.0.15 → WSL 172.27.230.199
Port ComfyUI 8188(8189 被 iphlpsvc portproxy 占,不能動)+ Mac SSH tunnel 28189

兩個踩過的 anchor:

  1. ComfyUI 必走 native ext4:9P 對 200+ 小檔 random read 超慢,Flux + LoRA 載入 8 秒爆到 90 秒。ComfyUI/ 搬到 /home/user/ComfyUI/,models/ symlink 回 /mnt/c/...,174GB 模型不用搬。
  2. port 8189 不能動:iphlpsvc portproxy 占了 8189,殺了整個 LAN 失聯。

2.2 16GB VRAM 是多大?

ASCII 圖是 5060 Ti 16GB 跑 Flux fp8 + MuseTalk 同時時的 VRAM 分配(v14 量產時 nvidia-smi 實測):

RTX 5060 Ti 16GB VRAM 分配地圖(v14 量產 talking head shot)

 0 GB ┌───────────────────────────────────────┐
      │ CUDA context + driver overhead        │ 0.8 GB
 1 GB ├───────────────────────────────────────┤
      │ ComfyUI Python runtime                │ 1.2 GB
 2 GB ├───────────────────────────────────────┤
      │ Flux UNet fp8_e4m3fn (12B params)     │ ~7.5 GB
      │  ├── T5 XXL fp8 encoder               │
      │  ├── CLIP L                           │
      │  └── VAE                              │
 9 GB ├───────────────────────────────────────┤
      │ LoRA (rank 4 fp16, ~38 MB)            │ 0.1 GB
      ├───────────────────────────────────────┤
      │ KSampler latent buffer (832×1216)     │ 1.4 GB
10 GB ├───────────────────────────────────────┤
      │ MuseTalk V1.5 unet 256² + audio enc   │ 2.8 GB
13 GB ├───────────────────────────────────────┤
      │ face_alignment dlib 68pt              │ 0.4 GB
      │ Wav2Lip checkpoint (idle)             │ 0.3 GB
14 GB ├───────────────────────────────────────┤
      │ ✦ FREE 安全餘量 (KV cache 跳動)        │ ~2.0 GB
16 GB └───────────────────────────────────────┘

關鍵:Flux fp8 占 7.5 GB(12B 最節儉組合);MuseTalk 256² 占 2.8 GB,升 512² 吃 8 GB+ → 永遠卡 256² 嘴部模糊;動態餘量只剩 2 GB,KV cache 在長序列 inference 吃滿,batch_size 永遠 1。

2.3 能跑 / 不能跑清單(30 天實測)

模型 / 任務 5060 Ti 16GB 結果 備註
Flux dev fp8 single-file ✅ 能跑,832×1216 一張約 38 秒 anchor 圖主力
Flux dev fp16 ❌ OOM 17.5 GB 載不進來
Flux LoRA rank 4 訓練 ✅ 能跑,cache miss 197s/step → cache hit 70s/step 13 角色 100 step 共 30 hr
Flux LoRA rank 16 訓練 ⚠️ 邊緣,30% 機率 OOM 不建議
Wan22 ti2v 5B fp16 ✅ 能跑,81 幀 720×1280 約 7 分鐘 上限 81 幀 = 3.375 sec @ 24fps
Wan22 i2v 14B GGUF Q4_K_M ❌ OOM(VAE decode 階段) 第一次就死
Wan22 i2v 14B fp16 ❌ 想都不要想 模型本身就 28 GB
LTX-Video 2B distilled fp8 ✅ 能跑,10 sec 約 4 分鐘 i2v 鎖首幀差,棄
MuseTalk V1.5 256² ✅ 能跑,10 sec 約 90 秒 v13 patch 才跑得通
MuseTalk V1.5 512² ❌ OOM 需要 24GB
LatentSync 1.5 ✅ 能跑,10 sec 約 110 秒 face-on 純特寫 OK,複雜畫面嘴融化
Wav2Lip 96² + GFPGAN v1.4 restore ✅ 能跑,10 sec 約 70 秒 最穩 baseline
LivePortrait KJ ✅ 能跑,但 idle talking head 才行 強表情失敗
PuLID-Flux ❌ wrapper 跟最新 ComfyUI transformer_options KeyError 棄
NoobAI XL Vpred 1.0 7.1GB(動漫 SDXL) ✅ 能跑,1024² 約 25 秒 v16 動漫轉向用
IPAdapter Plus SDXL ViT-H ✅ 能跑,weight 0.95 上限 1.5+ 開始 ghosting
ReActor face swap ✅ 能跑 第 30 幀後仍會漂移
GFPGAN v1.4 face restore(only_center_face) ✅ 能跑,加在後製 v6 過關關鍵
YOLOv5l head detection ✅ 能跑 比 OpenCV haar 穩 5 倍
RIFE 補幀 24→48 fps ✅ 能跑 加 smooth 用
Ollama qwen3:14b(劇本生成) ✅ 全 GPU 載入,40 tok/s 主力
Ollama gemma2:27b ⚠️ CPU offload,18 tok/s,JSON 不穩 fallback only

2.4 5060 Ti 16GB 真正的瓶頸在哪

把 30 天的所有失敗歸納成一句話:

16GB VRAM 同時跑得動「圖生成 + 影片生成 + 對嘴 + 後處理」四件事的任意三件,但永遠不能同時跑四件。

打臉案例:

  1. Wan22 14B i2v + 鎖首幀:14B fp16 是 28GB,GGUF Q4_K_M 10GB 也不夠(KV cache + VAE decode 吃爆剩下的 6GB)
  2. MuseTalk 512²:要先 unload Flux 才能 load 512²,pipeline 變串列,量產速度砍半
  3. 同時跑兩個 character LoRA:LoRA 在 attention 層互相污染,雙人合照失敗率 100%

2.5 第二章的兩個結論

結論一:16GB 卡只能跑「影片生成」或「對嘴」其中一件當主任務,另一件用更小 fallback。

結論二:追《五十岁》品質的技術現實:至少 24GB VRAM(RTX 4090/5090)+ Wan22 14B + MuseTalk 512²。這是物理問題,不是調參。

教訓 2.1:先量你的 VRAM 再選 pipeline。 教訓 2.2:「16GB」spec 扣掉 CUDA context + Python runtime + KV cache,實際可用 12-13 GB。


第 3 章 v1.7 - v8:早期 baseline 與 Wav2Lip 路線

摘要:從 GGUF 量化想擠進 16GB VRAM、到 Wav2Lip 96² baseline 過關、到 MuseTalk mmcv build hell 三連敗,第一週踩出來的早期經驗。

3.1 v1.7(5/22):GGUF 量化 Wan22 14B i2v 的死亡幻想

第一個版本是 v1.7(前面 v1.0-v1.6 是劇本 + LoRA 訓練的子版本,影片生成從 v1.7 開始計)。

我的初始想法很單純:

  • 跑 Wan22 i2v 14B 比 5B 多了「鎖首幀 + 連貫 motion」這兩個對短劇至關重要的能力
  • 14B fp16 = 28GB 載不進 16GB
  • 用 GGUF Q4_K_M 量化(10GB)+ ComfyUI-GGUF custom node 應該能擠進來

於是我 git clone 了 city96/ComfyUI-GGUF,下載 Wan22-I2V-14B-GGUF 的 Q4_K_M 檔(10GB),按照 README 接上 workflow,按下 queue。

# v1.7 啟動指令(已棄)
ssh user@192.168.0.15 'wsl -d Ubuntu -- bash -c "cd /home/user/ComfyUI && python main.py --listen 0.0.0.0 --port 8188"'
# Mac 端
curl -X POST http://127.0.0.1:28189/prompt -d @v1_7_test.json

結果:第一個 inference step 都還沒完成,VAE decode 階段直接 OOM。

我去看了一下 nvidia-smi:

+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|    0   N/A  N/A     12847      C   python                          15.7 GiB |
+-----------------------------------------------------------------------------+

OOM 不是 model 沒載完,是 model 載完了,VAE decode 要把 latent 還原成 720×1280 視訊張量時撐不住。GGUF 量化只省 model weight,但 KV cache + VAE decode 階段的 fp16 buffer 不會被量化,這是 GGUF 路線在影片任務上的硬傷。

踩坑 → 分析 → 教訓:

  • 踩坑:以為 GGUF 量化能 = 量化後一切。
  • 分析:GGUF 只量化 weights,inference 中間態(latent buffer / KV cache / VAE intermediate)還是 fp16,影片任務的 VAE decode 是吃 buffer 的重災區。
  • 教訓 3.1:消費卡跑 14B i2v 在 2026 年 6 月是夢,要嘛 24GB 顯卡,要嘛回 5B。

3.2 v3 base 18 shot:黑底霓虹垃圾 sample

繞回 5B 之前,我先用 Wan22 5B 量產一批「Wedding Veil 婚禮短劇」18 shot 當對嘴 input。結果大半是這樣:

v4 sniper 翻車現場 — 第 30 幀後臉部漂移

「黑底霓虹 + motion graphics + 角色五官漂移」三件套同時發作。前 10 幀正常,第 15 幀開始扭曲,第 30 幀後完全不是同一個人。Wan22 5B 第 30 幀後人臉漂移這條根因 30 天裡沒解掉。

3.3 v4 - v6(5/27):Sniper Shot06 三代迭代

整批 v3 不能用,我挑一個 shot(女主換新娘服的 close-up,叫 shot06)做 sniper,用所有可能的後處理硬把它修到能用。

v4:Flux + ReActor face swap

v4 Flux anchor 圖(face swap 前)

ReActor 第 1 幀完美,第 30 幀以後五官跑掉。ReActor frame-by-frame swap,沒 temporal consistency,每幀 landmark 微抖放大成跨幀漂移。

v5:加 PoseControlNet body lock

v5 PoseControlNet 結果

身體穩了,臉部一樣漂。ControlNet 只 condition pose 不 condition face。face 跟 body 一致性是兩個獨立問題。

v6:加 GFPGAN v1.4 only_center_face + YOLOv5l + Canny head bbox(真正過關)

v6 Flux anchor + GFPGAN restore 後的 keyframe(shot06 過關版)

最後 v6 過關的組合是:

# v6 sniper 後處理 pipeline(簡化版)
def v6_post_process(frame_dir, output_path):
    frames = sorted(Path(frame_dir).glob("*.png"))
    for f in frames:
        # 1. YOLOv5l 偵測 head bbox(比 OpenCV haar 穩 5 倍)
        bbox = yolov5l_head_detect(f)
        # 2. Canny edge 找臉部邊緣,給 GFPGAN feather 用
        head_mask = canny_head_mask(f, bbox)
        # 3. GFPGAN v1.4 only_center_face restore
        restored_face = gfpgan_restore(
            f, only_center_face=True, bg_upsampler=None, weight=0.5,
        )
        # 4. paste back with 30px Gaussian feather
        composited = paste_back_feather(f, restored_face, head_mask, feather=30)
        cv2.imwrite(str(output_path / f.name), composited)

v6 GFPGAN 修復後

shot06 終於穩了。但代價是 v6 pipeline 跑一個 4 秒 shot 要 6 分鐘,整集 32 shot = 3.2 小時,已經接近量產的邊緣。

v4-v6 三代的教訓矩陣

版本 加什麼 解決什麼 沒解決什麼
v4 ReActor 第 1 幀像 第 30 幀漂
v5 + PoseControlNet body 穩 face 仍漂
v6 + GFPGAN only_center_face face 穩 速度慢 6 min / shot

教訓 3.2:face 復原優先順序是 GFPGAN > CodeFormer > RestoreFormer(v6 我們三個都測過)。YOLOv5l 比 OpenCV haar 穩 5 倍,這是給後製做 head detection 的人記下來。

教訓 3.3:不要在 base model 階段試圖解 temporal consistency,後處理 GFPGAN + paste back feather 比改 Wan22 內參數有效十倍。

3.4 v7 LivePortrait:強表情的物理盲區

Flux 靜態 base + LP 注入表情。理論上對 idle talking head 處理很好。實測:✅ idle 微笑、輕點頭、眨眼完美;❌ 怒吼嘴糊 / 咬牙上下牙不開 / 側臉 > 15 度歪掉。五版全失敗。

短劇恰好「強表情」為主,LP 第 7 天就被砍。教訓 3.4:每個模型都有設計初衷決定的物理盲區。

3.5 v8 Wav2Lip baseline + MuseTalk mmcv build hell

v8 是 Wav2Lip 96² + paste back baseline,2020 年老模型勝在穩、輕、不挑硬體:

def wav2lip_pipeline(base_mp4, audio_wav, output_mp4):
    face_stream = crop_face_stream(base_mp4, target_size=(96, 96))
    synced_96 = wav2lip_inference(face_stream, audio_wav, "wav2lip_gan.pth")
    composited = paste_back_with_feather(base_mp4, synced_96, feather_radius=30)
    mux_audio(composited, audio_wav, output_mp4)

shot06 男主 + shot07 新娘 smoke test 完美。但 v3 base 18 shot 一半黑底霓虹垃圾,Wav2Lip 救不了「base 本身不能看」。

並行嘗試 MuseTalk 作為更高品質方案,撞上 mmcv 的牆。

MuseTalk 的 mmcv 編譯地獄

MuseTalk V1.0 依賴 mmcv-full 1.7.x,CUDA 12.8 + Blackwell sm_120 上要從原始碼編譯:

# 三連敗
pip install mmcv-full==1.7.0          # 找不到 cu128/sm_120 wheel
mim install mmcv-full==1.7.0          # 一樣
git clone .../mmcv -b 1.x && MMCV_WITH_OPS=1 pip install -e . -v
# → cannot find -lcudart_static → fix LIBRARY_PATH
# → sm_120 not supported → fix TORCH_CUDA_ARCH_LIST
# → 90 分鐘編譯後 ImportError: undefined symbol _ZN3c104impl...

8.7GB checkpoints 靜靜躺在 PC,但 mmcv 載不起來。MuseTalk mmcv build hell:永遠走 Wav2Lip。這個結論到 v13 才被推翻(用 face_alignment 取代 dwpose)。

v8 MuseTalk 嘴部模糊(v13 過關前的失敗 sample)

v8 的結算

  • ✅ Wav2Lip baseline 跑通,shot06/shot07 過關
  • ❌ MuseTalk 因 mmcv 編譯失敗,整條棄
  • ❌ v3 base 18 shot 大半垃圾,要重煉

教訓 3.5:當你發現一個 lib 要從原始碼編譯,而且是 CUDA C++ kernel,先確認有沒有同功能的純 PyTorch 替代品。mmcv 後來證明根本不必要,但我為它燒了 6 個小時編譯。

3.6 第三章的小結

第一週收穫:(1) GGUF 救不了 14B i2v;(2) Wan22 5B 81 幀 = 3.375 秒架構上限;(3) face swap + face restore 是兩件事;(4) LivePortrait 強表情盲區;(5) Wav2Lip 96² 是天花板;(6) MuseTalk mmcv 地獄要繞。

到這裡我以為「baseline 跑通,下面就是迭代品質」。事實證明我錯了,後面 23 天都在這個錯誤判斷的延伸線上。


第 4 章 v9 - v10:LivePortrait 與 LatentSync 進化

摘要:v9.1 用 GFPGAN restore 把 Wav2Lip 拉到能看,v10 拼 LatentSync 1.5 結果發現只能做純臉特寫。第二週的核心收穫是「沒有銀彈,只有適用場景」。

4.1 v9.1 大女主獨白工廠

v8 的 18 shot 重煉後,挑 8 個 close-up shot 做 v9.1 sniper:

# v9.1 corruption filter + auto rerun + GFPGAN 局部修復層
def v9_1_pipeline(base_mp4, audio_wav, output_mp4, max_retry=3):
    for attempt in range(max_retry):
        synced = wav2lip_inference(base_mp4, audio_wav)
        if not is_mouth_corrupted(synced, threshold=0.85):
            break  # SSIM 對比嘴部,差異過大就 rerun
        log.warning(f"[v9.1] attempt {attempt+1} corrupted, rerun")
    restored = gfpgan_restore_video(synced, weight=0.5)
    composited = paste_back_feather(base_mp4, restored, feather=30)
    mux_audio(composited, audio_wav, output_mp4)

關鍵三招:corruption filter + auto rerun + GFPGAN only_center_face restore。8 個 shot 全綠,shot06 比較 v9.1 vs v10 LatentSync,v9.1 反而更穩。第一次意識到「最新模型 ≠ 最好結果」。

4.2 v10 LatentSync 1.5:本地對嘴的當代冠軍

3 個 agent 平行做 web research「2026 本地能跑、繁中支援、消費卡可裝對嘴模型」,共識指向 LatentSync 1.5(Apache-2.0、8GB VRAM、Whisper 中文、Blackwell sm_120 原生 wheel):

pip install latentsync==1.5.0
huggingface-cli download ByteDance/LatentSync-1.5 \
  --local-dir /home/user/ComfyUI/models/latentsync

bride solo shot05/06/07 三個 face-on 特寫效果震撼:

v10 LatentSync face-on 特寫成功 sample

對嘴精準度比 Wav2Lip 96² 高一檔,嘴形跟 audio waveform 逐幀對齊。我當時想:「對嘴問題解決了。」

4.3 LatentSync 的盲區:複雜畫面嘴部融化

把 LatentSync 餵給 shot04(女主梳妝台 + 手 + 首飾盒 + 臉的構圖)。嘴部完全融化 —— 不是對不準,是真的物理融化:嘴位置長出 third lip、皮膚紋理跟首飾盒紋理混在一起。

5 次跑 5 個 seed 全部一樣。4 個 agent 拆 root cause 結論:

LatentSync 1.5 的 face detection 在「臉 + 手 + 物」三元素同框時會誤判,把手或物的紋理當成臉的延伸,latent 階段把整個誤判區域當「嘴」生成。

模型架構級限制,沒辦法 fine-tune。LatentSync 只能用在 face-on 純特寫。

4.4 v9.1 vs v10 vs v12B2 對嘴技術 PK 矩陣

5/29 對三個對嘴方案 head-to-head 比較(30 test shot 評分):

shot 類型 Wav2Lip 96² (v8) LatentSync 1.5 (v10) Wav2Lip+GFPGAN (v9.1)
純臉特寫 (10) 7.5 9.5 8.5
talking head (10) 7 6 8
手+物+臉 (5) 6 2 7
側臉 30° (3) 5 3 6
強表情 (2) 4 3 5

LatentSync 只贏純臉特寫;Wav2Lip+GFPGAN 在 4/5 場景拿最高。沒有銀彈是第二週最大教訓。這張表後來成為 v12 5 版失敗時的關鍵診斷工具。

4.5 第四章的小結

第二週核心收穫:(1) 沒有銀彈,每個對嘴模型都有適用場景;(2) 舊模型不過時,Wav2Lip 2020 加 GFPGAN 擊敗 2025 LatentSync;(3) community consensus ≠ your use case。

教訓 4.1:看到「state of the art」先問三問:demo 是不是純臉特寫;evaluation set 跟你 use case 像不像;limitations 段寫了什麼(這段是金礦)。

教訓 4.2:保留舊版本當 fallback,v14 量產時 talking_head dispatcher 就是 MuseTalk 為主 + v9.1 GFPGAN 為 fallback。


第 5 章 v11 - v12:PuLID-Flux 與 Wan22 五版失敗

摘要:v11 試 PuLID 取代 LoRA 失敗,v12 用 Wan22 5B + LatentSync 連續五版全部翻車,那一晚我寫了 handoff 文件準備認輸。

5.1 v11 PuLID-Flux:取代 LoRA 的美夢

13 LoRA 訓練花 30 小時(cache miss 197s/step → cache hit 70s/step 3x 差距)。痛點:(1) 每加角色重訓一次;(2) 多 LoRA 在 attention 互相污染,雙人合照 100% 失敗。

PuLID-Flux 承諾:不用訓 LoRA、給 reference image 就能 condition、多角色解雙人合照、ID 一致性更穩(cross-attention 而非 weight 改寫)。

裝 cubiq/ComfyUI_PuLID_Flux,第一個 KSampler 直接報錯:

KeyError: 'transformer_options'
  File ".../ComfyUI_PuLID_Flux/pulid_flux.py", line 184, in patch_attention
    options = model_options['transformer_options']

PuLID-Flux wrapper 跟最新 ComfyUI transformer_options API 不兼容,作者 4 個月沒更新。三個 workaround:(1) 降 ComfyUI 版本(半小時後放棄,Wan22 需要新版);(2) fork PuLID 手動 patch(patch 完效果跟 LoRA 差不多);(3) InstantID 不支援 Flux 棄。

13 LoRA 已訓完,PuLID 沒解雙人合照(attention 仍干擾),當天棄。

教訓 5.1:用 X 取代 Y 先問「X 真的解決 Y 的痛點嗎?」PuLID 沒解雙人合照,只是把「訓 LoRA」換「跑 inference」。 教訓 5.2:custom node 作者 4 個月沒更新 = 高風險,半年內必 break。

5.2 v12 五版全失敗:Wan22 + LatentSync 的完美風暴

5/28 晚是 30 天最痛的一晚。計畫 Wan22 5B i2v + LatentSync 對嘴量產 ep1 talking head。

v12 A:Wan22 5B i2v 鎖首幀直接失敗

5060 Ti 上沒有可用的「i2v 鎖首幀」node:

  • WanImageToVideoLatent:32GB VRAM 才能 forward,OOM
  • WanFunControlToVideo:可 forward,但首幀只是 ref_image 風格參考,不是鎖第 1 幀
  • IPAdapter + Wan22:IPAdapter 不支援 Wan22 video latent
  • 手動 latent 注入第 1 幀:跑通了但第 5 幀漂走

Anchor + Wan22 構圖完全脫鉤,Flux 跟 Wan22 是兩個故事。

v12 B:LatentSync 對複雜畫面嘴部融化

改 Plan B「Flux anchor → ffmpeg loop static base → LatentSync」。shot01 梳妝台「手 + 首飾盒 + 臉」鏡頭,LatentSync 又融化。Production 場景的第一次驗證。

v12 B2:復活 v9.1 Wav2Lip + GFPGAN restore

砍 LatentSync 砍 i2v,改 v9.1 路線:

# v12 B2 復活 v9.1 路線(核心 7 stage)
def v12_b2_pipeline(shot_spec, output_mp4):
    # 1. Flux + LoRA → anchor 720×1280 png
    anchor_png = flux_with_lora(
        prompt=shot_spec.prompt,
        lora=shot_spec.character_lora,
        seed=shot_spec.seed,
    )
    # 2. ffmpeg Ken Burns zoom → 靜態 base mp4 (4s @ 24fps = 96 frame)
    base_mp4 = ffmpeg_ken_burns(anchor_png, duration=4.0, zoom=1.05)
    # 3. Edge TTS → audio.wav
    audio_wav = edge_tts(shot_spec.dialogue, voice=shot_spec.voice)
    # 4. InsightFace 偵測 face bbox track
    face_bbox = insightface_detect(base_mp4, gender="female")
    # 5. crop face stream → 96×96
    face_stream = crop_face_stream(base_mp4, face_bbox, size=96)
    # 6. Wav2Lip → synced 96×96
    synced_96 = wav2lip(face_stream, audio_wav)
    # 7. GFPGAN v1.4 restore (only_center_face) → synced_hq
    synced_hq = gfpgan_restore_video(synced_96, weight=0.5)
    # 8. paste back with 30px Gaussian feather
    composited = paste_back_feather(base_mp4, synced_hq, feather=30)
    # 9. mux audio
    mux_audio(composited, audio_wav, output_mp4)

跑通了,shot01 出來能看,但整條 pipeline 跑一個 shot 要 6 分鐘。32 shot × 6 min = 3.2 hr,量產 30 集需要 96 hr GPU 連跑。

v12 B3 / B4

B3:F5-TTS voice clone 整合,5 次跑 4 次像、1 次崩,沒法量產。 B4:完全放棄 i2v,全部「Flux anchor + ffmpeg Ken Burns + Wav2Lip」,出來「PPT + 對嘴」,質感倒退到 2018 vTuber。

那晚的 handoff 文件

5/28 23:50 寫了 anchor-drama-handoff-20260521-v12-failed.md,預設隔天放棄 drama factory:

v12 五版全失敗結論:5060 Ti 16GB 跑不出「動 + 對嘴 + 一致性」三件套同時成立的 talking head。

隔天早上沒放棄,因為看到 MuseTalk V1.5 issue 提到 face_alignment 可繞 mmcv。這條線索把我拉進 v13。

5.3 v12 的最終 17.7 min 樣品

B2 路線最後硬跑出一個完整 ep1(17.7 分鐘)作為 baseline:

v12 ep1 真人 drama baseline frame

5.4 第五章的小結

第二週末核心收穫:(1) 5060 Ti 跑 Wan22 5B 沒有可用 i2v 鎖首幀 node;(2) LatentSync 對「臉 + 手 + 物」場景必死;(3) PuLID-Flux 跟最新 ComfyUI API 斷層;(4) F5-TTS 中文 voice clone 5 次 4 次像 1 次崩,沒法量產。

教訓 5.3:當某個版本「全部失敗」,不要急著推翻架構。寫 handoff 睡一覺,第二天常會發現失敗的是子路線不是方向。v12 → v13 就是這樣翻過來的。

教訓 5.4:保留「最爛但能跑」的 baseline。v12 B4 純靜態 PPT 對嘴雖爛,但是「下限保底版」。


第 6 章 v13 突破:MuseTalk V1.5 face_alignment 68 patch

摘要:30 天裡最重要的一個技術突破。三個 patch 把 MuseTalk V1.5 在 5060 Ti Blackwell sm_120 上跑通 256²,把對嘴品質從 Wav2Lip 96² 拉到完全不同的檔次。但這個突破也是後面 v14 量產翻車的種子。

6.1 5/29 早上的線索

前一晚 v12 handoff 寫完去睡。早上在 MuseTalk repo issue 看到一則:

When using face_alignment library instead of dwpose for landmark detection, MuseTalk runs without mmcv. Tested on RTX 4090.

立刻 pip install face-alignment==1.4.1,30 秒裝完。比起 mmcv 6 小時編譯地獄,這條線索像免費禮物。但事情沒這麼簡單。

6.2 三個關鍵 patch

MuseTalk V1.5 在 5060 Ti Blackwell sm_120 跑通 256² 需要 3 個 patch:

Patch 1:preprocessing.py 用 face_alignment.fa.get_landmarks() 取代 dwpose

MuseTalk 原本用 mmcv dwpose 做 68 點 face landmark(dlib 格式),改用 face_alignment lib(同 68 點 dlib 格式):

# musetalk/utils/preprocessing.py(patch 後)
import face_alignment

class FaceAlignmentLandmarkExtractor:
    def __init__(self, device='cuda'):
        # 關鍵:必須用 standalone face_alignment lib(不是 face_detection.FaceAlignment)
        self.fa = face_alignment.FaceAlignment(
            face_alignment.LandmarksType.TWO_D,
            device=device,
            flip_input=False,
            face_detector='sfd',
        )

    def get_landmarks(self, frame_bgr):
        # face_alignment 期待 RGB
        frame_rgb = cv2.cvtColor(frame_bgr, cv2.COLOR_BGR2RGB)
        # 輸出 68×2 numpy array(dlib 格式:jaw 0-16, brow 17-26, nose 27-35, eyes 36-47, mouth 48-67)
        landmarks_list = self.fa.get_landmarks(frame_rgb)
        if landmarks_list is None or len(landmarks_list) == 0:
            return None
        return landmarks_list[0]  # 取第一張臉

關鍵細節:face_alignment.FaceAlignment 是 standalone lib,不是 face_detection.FaceAlignment(那是 face_detection 套件內部類別,名字像但完全不同)。我踩了一小時。

Patch 2:7 個 file 加 weights_only=False

PyTorch 2.6+ torch.load() 預設 weights_only=True,對 MuseTalk 舊 checkpoint 是 breaking change。搜尋整個 musetalk/ 目錄 7 個檔案(vae.py / unet.py / audio_encoder.py / audio_processor.py / preprocessing.py / inference.py / realtime/runner.py)所有 torch.load() 加 weights_only=False。

Patch 3:V1.5 config path

model:
  unet_config: ./models/musetalkV15/musetalk.json
  unet_model_path: ./models/musetalkV15/unet.pth
  vae_type: sd-vae-ft-mse
  whisper_model_path: ./models/whisper
inference:
  bbox_shift: 0  # 關鍵:V1.5 必須 0,不能 V1.0 ±5
  fps: 25

6.3 三個地雷

跑通後連踩三個地雷,每個浪費 1-2 小時:

地雷 1:mediapipe FaceMesh 索引不對應 dlib 68 點。想偷懶用 mediapipe(更快),結果嘴部完全不動。mediapipe 是 478 點,索引完全不對應。MuseTalk 用 dlib mouth 索引(48-67)做 latent injection,餵 mediapipe 等於餵錯位置 → 在「鼻子的地方」生嘴形。必走 face_alignment lib。

地雷 2:bbox_shift V1.5 必須 0。V1.0 預設 ±5,V1.5 必須 0。用 V1.0 預設跑,嘴的位置在鼻孔下方 5 pixel。DEFAULT_BBOX_SHIFT = 0。

地雷 3:yaml 路徑相對位置。MuseTalk 預設從 musetalk/ 目錄跑,yaml 的 video_path 是 ../ComfyUI/,從 custom_nodes 跑要改 ../../ComfyUI/。最後 hardcode 絕對路徑避免坑。

6.4 跑通後的 range 驗證

ssh user@192.168.0.15 'wsl -d Ubuntu -- bash -c "
cd /home/user/ComfyUI/custom_nodes/MuseTalk &&
python -m scripts.inference --inference_config configs/inference/test.yaml \
  --result_dir /home/user/drama-factory/data/control/v13_smoke"'

# log
[18:22:14] face_alignment landmarks: 68 points detected
[18:22:15] bbox_shift range: [-0~0] ✓
[18:23:42] frame 250/250 inference complete

shot06 對嘴完美、range [-0~0] 完美、Whisper 中文對齊精準。v13 突破是 30 天裡少數讓我覺得「對,這條路可以」的時刻。

6.5 v13 patch 流程速覽

clone MuseTalk V1.5 → 試 mmcv(6 小時編譯地獄棄)
  → pip install face-alignment(30 秒)
  → Patch 1: preprocessing.py 用 fa.get_landmarks() 取代 dwpose
  → Patch 2: 7 個 file 加 torch.load(weights_only=False)
  → Patch 3: configs/v1.5.yaml bbox_shift: 0
  → smoke ✓ 68 landmarks ✓ range [-0~0] ✓ VRAM 2.8 GB

6.6 v13 的代價

v13 成功讓我做出致命判斷:MuseTalk 跑通 = 對嘴問題解決 = 可以量產。事實是 256² 上限導致 v14 量產 17.7 min ep1 後用戶第一個批評就是「嘴模糊」。升 512² 要 24GB VRAM,30 天沒解掉。

6.7 第六章的小結

核心收穫:(1) face_alignment lib 是消費卡 MuseTalk 救星,30 秒安裝取代 6 小時 mmcv;(2) mediapipe FaceMesh ≠ dlib 68 點,硬塞會崩;(3) bbox_shift V1.5 必須 0;(4) 跑通 ≠ 可量產,256² 上限決定「嘴模糊」是物理事實。

教訓 6.1:「works on 4090」的 patch 在 5060 Ti 上常常只能跑更小解析度。教訓 6.2:替代品 patch 必做嚴格 output format 驗證,「68 points」字面相同座標系可能完全不同。


第 7 章 v14 量產翻車:450 shot 21 hr 用戶 7 個批評

摘要:v13 突破帶來的虛假信心讓我們直接進入量產,21 小時跑完一個 17.7 分鐘的 ep1,交付當天被批 7 項,每一項都是物理性無解。沒做 smoke test 是這 30 天最大的單一錯誤。

7.1 v14 的雄心壯志

v13 跑通隔天(5/30)做了 v14 量產 SOP。核心是 4 type sniper dispatcher:

v14 量產 dispatcher 流程

   ┌───────────────────────┐
   │ shot_spec from script │
   │  (JSON, 450 sub-shot)  │
   └──────────┬────────────┘
              │
              ▼
   ┌──────────────────────┐
   │ shot_type router      │
   └──────────┬───────────┘
              │
     ┌────────┼────────────┬─────────────┐
     │        │            │             │
     ▼        ▼            ▼             ▼
  ┌──────┐ ┌──────┐ ┌─────────────┐ ┌──────────┐
  │ cut  │ │static│ │  talking    │ │  action  │
  │ away │ │ pose │ │  head       │ │          │
  ├──────┤ ├──────┤ ├─────────────┤ ├──────────┤
  │Flux  │ │Flux+ │ │Flux + LoRA  │ │Flux+LoRA │
  │+ loop│ │LoRA+ │ │+ Edge TTS   │ │+ Wan22 5B│
  │      │ │Ken   │ │+ MuseTalk   │ │ti2v 81fr │
  │~1 min│ │Burns │ │+ 字幕       │ │+ 字幕    │
  │      │ │~1.5  │ │~3 min       │ │~7 min    │
  │      │ │  min │ │             │ │          │
  └──────┘ └──────┘ └─────────────┘ └──────────┘

episode_v14_runner.py 完整的 dispatcher 片段(這是真實程式碼):

# episode_v14_runner.py 真實片段
"""episode_v14_runner — 漫剧 v14 統一 dispatcher,按 shot_type 路由 4 種 pipeline

shot_type:
  cutaway      → Flux 1 圖 + ffmpeg loop (2-3 sec, 無對白)        ~1 min
  static_pose  → Flux + LoRA + ffmpeg Ken Burns zoom (2-3 sec)    ~1.5 min
  talking_head → Flux + LoRA + Edge TTS + MuseTalk + 字幕         ~3 min
  action       → Flux + LoRA + Wan22 5B ti2v + 字幕                ~7 min

每 shot 獨立 mp4,concat 由 batch script 處理。
"""

EPISODE = "v14_ep1"
RESOLUTION = (720, 1280)
FPS = 24

# 角色 ID → LoRA 檔名 + trigger
CHAR_LORA = {
    "female_lead": ("soxw_zh50_v1_100step_rank4_fp16-step00100.safetensors", "soxw_zh50"),
    "male_lead":   ("fujx_zh48_v1_100step_rank4_fp16-step00100.safetensors", "fujx_zh48"),
    "antagonist_ex_husband": ("chenjh_zh53_v1_100step_rank4_fp16-step00100.safetensors", "chenjh_zh53"),
    "daughter":    ("chenyl_zh23_v1_100step_rank4_fp16-step00100.safetensors", "chenyl_zh23"),
    "antagonist_secretary": ("linyq_zh28_v1_100step_rank4_fp16-step00100.safetensors", "linyq_zh28"),
    "assistant":   ("lim_zh35_v1_100step_rank4_fp16-step00100.safetensors", "lim_zh35"),
}
CHAR_VOICE = {
    "female_lead": "zh-CN-XiaoxiaoNeural",
    "male_lead":   "zh-CN-YunjianNeural",
    "antagonist_ex_husband": "zh-CN-YunyangNeural",
    "daughter":    "zh-CN-XiaoyiNeural",
    "antagonist_secretary": "zh-CN-XiaomengNeural",
    "assistant":   "zh-CN-YunxiNeural",
}

# Wan22 5B 配置
WAN_UNET = "wan2.2_ti2v_5B_fp16.safetensors"
WAN_CLIP = "umt5_xxl_fp8_e4m3fn_scaled.safetensors"
WAN_VAE  = "wan2.2_vae.safetensors"
WAN_FRAMES = 81  # 3.4 sec @ 24fps

7.2 5/31 - 6/1 的 21 小時連跑

5/31 18:00 啟動,6/1 15:00 跑完。Mac keeper 保活 ssh:

nohup bash -c 'echo "sleep 108000" | ssh -o ServerAliveInterval=15 \
  user@192.168.0.15 "wsl -d Ubuntu -- bash"' > /tmp/wsl_keeper.log 2>&1 &

成果:450 sub-shot / 17.7 min / 720×1280 / ep1_FULL.mp4 280 MB。平均 168 sec/sub-shot。我跟自己說「30 天磨一劍」,上傳給用戶。

7.3 用戶 7 項批評

15 分鐘後用戶回我七條,每條都對:

# 批評 根因 解法
1 嘴模糊 MuseTalk 256² 上限,paste back 到 720×1280 上採樣 2.8x 升 512² 需 24GB VRAM,無解
2 配音單調 Edge TTS 免費版不支援 <mstts:express-as> 上 Azure Premium(NT$0.05/字)/ ElevenLabs
3 沒 BGM v14 dispatcher 根本沒寫 BGM 邏輯 v15 加(執行 bug)
4 角色不一致 每 shot 獨立 Flux inference,seed 不同 → 五官微漂 seed 鎖角色 ID hash + IPAdapter ref
5 沒多角色 script 全女主獨白,cutaway 全 talking head script writing 問題
6 運鏡失敗 cutaway 是 ffmpeg loop,static_pose 是 Ken Burns,無推拉 pan whip v15 加 camera-aware vf
7 角色沒動作 cutaway loop 不會讓人物動,只有嘴動 全改 action type 量產時間 21 → 100+ hr 不現實

7.4 為什麼沒做 smoke test

整個 v14 最關鍵問題:為什麼 21 hr 量產之前不先 30 sec smoke test?

心路歷程:(1) v13 MuseTalk 跑通讓我以為對嘴問題解決;(2) dispatcher 4 type 都單獨 sniper 測過;(3) 「個別 OK → 組合一定 OK」的盲信;(4) 沒考慮「個別 30 sec」跟「連續 17 min」是兩種體驗;(5) 沒考慮執行細節(BGM 忘加、運鏡沒寫)會在量產時被放大。

根本錯誤:把「技術可行性驗證」當成「成品驗證」。技術可行性證明「能跑」,成品驗證證明「能看」,兩件事。

7.5 v14 翻車的 bug 大全

除了用戶 7 項,內部還有:MuseTalk alpha 接縫(v15 feather 60px)、Edge TTS 偶發中斷(retry+cache)、Wan22 30 幀後人臉漂(無解)、concat audio offset 1 frame、ttc 字型 ffmpeg 偶發崩、中文標點渲染怪、Ken Burns 中心點全相同。

7.6 第七章的小結

v14 是量產時間最長、回饋最痛的版本。核心收穫:(1) 21 hr 量產 = 沒中途 sanity check 的代價;(2) 個別 sniper 過 ≠ 整集量產過,累積感受是另一維度;(3) 技術可行性 ≠ 成品可看性,兩種驗證需要兩種人;(4) MuseTalk 256² 上限再多後處理救不了;(5) Edge TTS 免費版不能做產業配音。

教訓 7.1:量產前必跑 30 秒 smoke test(dispatcher 所有 type 各 1 shot concat),用戶簽核才動 21 hr。 教訓 7.2:寫 dispatcher 時,BGM / 運鏡 / 字幕 / 角色一致性列在 checklist 最上面,否則量產一定忘。 教訓 7.3:「跑通 ≠ 可量產 ≠ 可上線」,每個 ≠ 號吃掉 1 週時間。


第 8 章 v15 - v16:SSML 情感 TTS 與 50 角色動漫轉向

摘要:v15 試圖修 v14 七大缺陷,剛跑通 smoke 用戶就轉向動漫。v16 NoobAI XL Vpred SDXL + IPAdapter Plus 50 角色全套,IPAdapter 兩個 bug 修完跑 460-shot batch 一樣翻車。

8.1 v15 修 7 缺陷

6/1 - 6/3 系統性修 v14 七大缺陷:

8.1.1 SSML 22 emotion 映射

Edge TTS 雖不支援 <mstts:express-as>,但可用 <prosody rate pitch volume> 三維度組合模擬 emotion。22 種 emotion 映射表:

# v15 SSML emotion map(22 種 emotion)
EMOTION_PROSODY = {
    "neutral":       {"rate": "0%",   "pitch": "+0Hz", "volume": "+0%"},
    "happy":         {"rate": "+10%", "pitch": "+10Hz","volume": "+5%"},
    "sad":           {"rate": "-15%", "pitch": "-10Hz","volume": "-5%"},
    "angry":         {"rate": "+5%",  "pitch": "+15Hz","volume": "+15%"},
    "fear":          {"rate": "+15%", "pitch": "+5Hz", "volume": "-10%"},
    "surprise":      {"rate": "+20%", "pitch": "+20Hz","volume": "+10%"},
    "disgust":       {"rate": "-5%",  "pitch": "-5Hz", "volume": "+0%"},
    "shocked":       {"rate": "-10%", "pitch": "+10Hz","volume": "+15%"},
    "devastated":    {"rate": "-20%", "pitch": "-15Hz","volume": "-10%"},
    "determined":    {"rate": "-5%",  "pitch": "+5Hz", "volume": "+10%"},
    "tender":        {"rate": "-10%", "pitch": "-5Hz", "volume": "-5%"},
    "sarcastic":     {"rate": "-5%",  "pitch": "-10Hz","volume": "+0%"},
    "whispering":    {"rate": "-15%", "pitch": "-5Hz", "volume": "-20%"},
    "shouting":      {"rate": "+5%",  "pitch": "+20Hz","volume": "+20%"},
    "crying":        {"rate": "-15%", "pitch": "-15Hz","volume": "-10%"},
    "laughing":      {"rate": "+10%", "pitch": "+15Hz","volume": "+10%"},
    "narration":     {"rate": "-5%",  "pitch": "+0Hz", "volume": "+5%"},
    "monologue":     {"rate": "-10%", "pitch": "+0Hz", "volume": "+0%"},
    "exclamation":   {"rate": "+5%",  "pitch": "+15Hz","volume": "+15%"},
    "question":      {"rate": "+0%",  "pitch": "+10Hz","volume": "+5%"},
    "intimate":      {"rate": "-15%", "pitch": "-5Hz", "volume": "-10%"},
    "dramatic":      {"rate": "-10%", "pitch": "+5Hz", "volume": "+10%"},
}

def build_ssml(text, voice, emotion="neutral"):
    p = EMOTION_PROSODY.get(emotion, EMOTION_PROSODY["neutral"])
    return f"""<speak xmlns="http://www.w3.org/2001/10/synthesis"
                       xmlns:mstts="http://www.w3.org/2001/mstts"
                       version="1.0" xml:lang="zh-CN">
  <voice name="{voice}">
    <prosody rate="{p['rate']}" pitch="{p['pitch']}" volume="{p['volume']}">
      {text}
    </prosody>
  </voice>
</speak>"""

22 種 emotion 確實有差別,但 Edge TTS rate ±20% 上限,「shouting」跟「crying」prosody 不同,聽起來還是「同一個人不同節奏」,沒有真正情感層次。

8.1.2 Camera-aware ffmpeg vf(運鏡)

v15 加 7 種 ffmpeg vf 運鏡:

# v15 camera-aware ffmpeg vf 運鏡映射
CAMERA_VF = {
    "push_in":     "zoompan=z='min(zoom+0.0015,1.5)':d=125:s=720x1280:fps=24",
    "pull_back":   "zoompan=z='if(eq(on,0),1.5,max(zoom-0.0015,1.0))':d=125:s=720x1280:fps=24",
    "whip_pan":    "crop=720:1280:'min(t*200,iw-720)':0,scale=720:1280",
    "pan_left":    "crop=720:1280:'iw-720-t*30':0,scale=720:1280",
    "pan_right":   "crop=720:1280:'t*30':0,scale=720:1280",
    "low_angle":   "perspective=x0=0:y0=H*0.1:x1=W:y1=H*0.1:x2=0:y2=H:x3=W:y3=H",
    "over_shoulder": "crop=720:1280:'iw*0.2':'ih*0.1',scale=720:1280",
}

def apply_camera(input_mp4, output_mp4, camera_type):
    vf = CAMERA_VF.get(camera_type, "null")
    subprocess.run([
        FFMPEG, "-y", "-i", str(input_mp4),
        "-vf", vf, "-c:v", "libx264", "-preset", "medium", "-crf", "18",
        str(output_mp4),
    ], check=True)

有運鏡感了,特別是 push_in / pan_left 對「女主決心離婚」很好用。但 ffmpeg zoompan 是固定中心點推拉,沒有 cinematic「motivated motion」感。

8.1.3 BGM mixing(-22 to -28 dB)+ ducking

# v15 BGM ducking 公式(ffmpeg sidechain)
ffmpeg -y -i dialogue.wav -i bgm.mp3 -filter_complex "
  [1:a]volume=-25dB,acompressor=threshold=-21dB:ratio=8[bgm_c];
  [0:a][bgm_c]sidechaincompress=threshold=0.05:ratio=20:attack=20:release=250[bgm_d];
  [0:a][bgm_d]amix=inputs=2:duration=first" -c:a aac -b:a 192k out.aac

對白時 BGM 自動降,沒對白時浮回來。

8.1.4 雙層 unsharp + 同源 seed

  • 雙層 unsharp:5×5 luma 0.5 + 3×3 chroma 0.3,perceived sharpness +20%
  • 同源 seed:hash(character_id) % 2^32,同角色所有 shot 鎖住五官

8.1.5 v15 結算:smoke only

sub0001(女主獨白 4 秒)smoke 全綠:SSML / 運鏡 / BGM / unsharp 都 OK。但用戶看完直接說:

「真人短劇我看夠了,轉動漫吧。動漫不用對嘴、不用 LoRA、不用 Edge TTS,純無對話漫剧就好。」

v15 在 smoke only 階段擱置,v16 直接轉向動漫。

8.2 v16 動漫轉向:NoobAI XL Vpred + IPAdapter Plus

v16 spec:NoobAI XL Vpred 1.0(7.1 GB SDXL v-prediction)+ 832×1216 + IPAdapter Plus ViT-H ref + 50 角色(f01-f28 女 / m01-m18 男 / x01-x04 special)+ 無對嘴 + 無 LoRA。

50 角色命名(節錄):

female_characters:
  f01: { name: "林夏", age: 22, type: "elegant" }
  f02: { name: "蘇妮", age: 24, type: "sexy" }
  f03: { name: "沐雪", age: 28, type: "villain" }
  # ... f04-f28
male_characters:
  m01: { name: "沈逸", age: 28, type: "ceo" }
  m02: { name: "顧寒", age: 32, type: "villain" }
  # ... m03-m18
special_characters:
  x01: { name: "陳阿姨", age: 50, type: "aunt" }
  x03: { name: "Boss 女王", age: 45, type: "villain_lady" }
  # ... x02, x04

四張角色 ref 圖(IPAdapter 條件源):

v16 動漫女主 林夏 elegant

v16 動漫反派女 沐雪 villain

v16 動漫女角 蘇妮 sexy

v16 動漫 CEO 沈逸

8.3 IPAdapter 2 個 bug

v16 第一個 batch 撞兩個 bug:

Bug 1:IPAdapter 缺 weight_type → HTTP 400

wf["12"] = {"class_type": "IPAdapter", "inputs": {
    "model": ["11", 0], "ipadapter": ["11", 1], "image": ["10", 0],
    "weight": 0.7, "start_at": 0.0, "end_at": 0.95,
    "weight_type": "standard"}}  # ← 缺這個就 400

Bug 2:ClipVision model not found

cd /home/user/ComfyUI/models/clip_vision/
cp clip_vision_h.safetensors CLIP-ViT-H-14-laion2B-s32B-b79K.safetensors

8.4 v16 460-shot batch 翻車

兩個 bug 修完跑 460-shot 動漫 batch(5 集 × 92 shot/集)8 hr 結果:

  • ✅ IPAdapter ref 鎖臉一致性比 v14 LoRA 好
  • ❌ IPAdapter weight 0.7 像度 60%,0.95 像度 85% 開始 ghosting,1.5+ 雙臉重疊
  • ❌ 服裝不鎖(沈逸 CEO shot01 黑西裝 / shot02 藍襯衫 / shot03 灰風衣)
  • ❌ 場景一致性差(每 shot 獨立 SDXL inference 背景風格漂)

最致命「服裝不鎖」—— 觀眾看 5 分鐘就跳出。「無對嘴漫剧」表面簡化問題,實際暴露 IPAdapter 在跨 shot 服裝一致性的物理盲區。

8.5 v16 vs v14 對比

維度 v14 真人 talking v16 動漫 silent
臉一致性 70%(LoRA + 每 shot 漂) 85%(IPAdapter)
服裝一致性 75%(LoRA 學服裝) 50%(不鎖服裝)
對嘴 / 配音 256² 模糊 / 單調 N/A / 純旁白
量產速度 / 集成本 168 sec/shot / 21 hr 17min 60 sec/shot / 8 hr 5min
整體可看性 6/10 5/10

v16 量產更快但可看性下降。「動漫風格」對 prompt + reference 容錯度更低,一個 frame 不對整集掉 line。

8.6 第八章的小結

核心收穫:(1) 修 7 缺陷代價 3 天,用戶可能下一秒轉方向;(2) SSML 22 emotion 在 Edge TTS 只是「假裝有層次」;(3) 「無對嘴」表面簡化實際引入服裝一致性問題;(4) IPAdapter 鎖臉強鎖服裝弱。

教訓 8.1:spec 變動敏感階段先做 modular dispatcher,monolithic pipeline 一變就全砍重寫。 教訓 8.2:「跨 shot 一致性」需要「臉 + 髮 + 服裝」三件套,2026/6 沒有單一技術完整解決。


第 9 章 v17 10 秒 demo 四連戰:認輸的那一刻

摘要:v14 翻車後我們縮回去做 10 秒 demo 驗證可行性。v17 從愛情劇到武俠,連續四版迭代,每版都修舊問題引入新問題,最後第四版交付時用戶說「武打太慢、臉扭曲、配音慢」,我承認 5060 Ti 16GB 已是天花板,30 天結束。

9.1 為什麼縮回 10 秒 demo

v14 量產 17.7 min 被批 7 項、v16 460-shot batch 翻車,「先量產再說」代價太大。v17 鐵律:每版只 10 秒 demo(3 shot × 3.4 sec)→ 用戶簽核 → 才放大。

9.2 v17 v1:愛情劇(沈逸 + 林夏 office 10 秒)

3 shot(pull back / push in two-shot / close-up reaction),MuseTalk V1.5 對嘴 + 22 emotion SSML。✅ IPAdapter 鎖臉 + Wan22 push in 有 cinematic 感;❌ 嘴模糊(256² 老問題)+ 嘴形精準度低(office 背景有椅子 + 桌面,MuseTalk 在這場景也開始抖)。

我自評 65 分,用戶沒簽核,叫換武俠題材試試。

9.3 v17 v2:武俠拔劍 10 秒

3 shot(aerial / combat / reveal),紅衣 hero solo + Edge TTS 雲健旁白。用戶批 4 點:

  1. SFX 太弱:劍擊聲、馬蹄聲、風聲沒加
  2. 旁白不夠大聲:+15% 仍被 BGM 蓋過
  3. 台詞爛:「風起雲湧,江湖再現」國中作文等級
  4. 鏡頭近、動作慢:3 shot 都 close to mid,Wan22 motion 偏慢

查 motion_prompt 發現我自己寫的全是「slow cinematic / ultra-slow majestic」,自己把節奏放慢。

9.4 v17 v3:v2 修 → 引入 3 個新 bug

v3 修 v2 4 點(motion_prompt 改快 / 旁白 +25% + SFX / 台詞重寫 / 鏡頭層次),結果撞到 3 個新 bug:

Bug 1:前幾秒白屏

# v3 fade transition(錯誤版)
fade_filter = "fade=t=in:st=3.35:d=0.1:color=white:alpha=0"

alpha=0 在 ffmpeg fade 是「淡入起點 alpha=0」意思是「前面全幀填充色」,不是「沒有 alpha 效果」。前 3.35 秒全幀白溢出。文件沒讀清楚的代價。

Bug 2:Wan22 cfg 8.0 timeout 1800s

cfg 6.0 推到 8.0 想「motion 強一點」,ComfyUI step 18/20 直接 hang,1800s timeout 也沒 return。root cause:Wan22 5B cfg > 7.5 時 KV cache 在某 attention layer 累積到 OOM 但不報錯,整個 inference loop hang。改回 cfg 6.5 穩定。

Bug 3:ComfyUI VRAM zombie 15.8 GB at 0% util

inference 結束但 ComfyUI 進程持有 15.8 GB VRAM、GPU util 0%、Python interpreter alive。custom node crash 後 python 沒 unload model:

# VRAM zombie 急救三連
ssh user@192.168.0.15 'wsl -d Ubuntu -- bash -c "
  pkill -9 -f \"python main.py\"; sleep 2
  fuser -k /dev/nvidia*; sleep 2
  nvidia-smi --gpu-reset || true"'

9.5 v17 v4:最後一搏

v4 調整:字幕 FontSize 32→26、MarginV 80→50;HERO_LOCK weight 1.3→1.5;IPAdapter weight 0.7→0.95;Wan22 cfg 6.5(v3 教訓)。

真實程式碼片段(武俠 hero lock):

# v17_wuxia_v4.py 真實 HERO_LOCK 配置
HERO_LOCK = (
    "(same handsome wuxia warrior:1.5), "
    "(same long black hair tied with red ribbon:1.4), "
    "(same crimson red silk robe with gold dragon embroidery:1.5), "
    "(same young 25 years old strong man), "
    "(same sharp piercing eyes:1.2), "
    "(holding same jade-hilted sword:1.4), "
    "masculine warrior, Asian male, dark hair, red clothing"
)

# 鎖角色串:3 個 motion 都重複
CONSISTENCY_LOCK = (
    "same character, same red robe, same long black hair, "
    "same red ribbon, same jade sword, consistent appearance throughout"
)

NEG_SDXL = (
    "worst quality, low quality, lowres, blurry, jpeg artifacts, "
    "bad anatomy, bad hands, missing fingers, "
    "modern clothing, suit, tie, t-shirt, jeans, glasses, "
    "watermark, signature, text, ugly, deformed, "
    "asymmetrical face, ugly face, plain face, "
    "(close-up:1.3), (portrait:1.3), face only, head only, "
    "talking, dialogue, speaking, "
    "different clothing, color change, hairstyle change, "
    "flat shading, line art"
)

NEG_WAN = (
    "text, watermark, blurry, deformed, frozen, static, "
    "close-up portrait, talking head, "
    "character change, color shift, clothing change, hair change"
)

跑出來:

v17 武俠 v4 戰鬥 shot

技術指標:

  • ✅ 前 3.35 秒不再白屏
  • ✅ Wan22 cfg 6.5 穩定 inference
  • ✅ ComfyUI 無 VRAM zombie
  • ✅ 字幕位置 OK
  • ✅ HERO_LOCK 1.5 角色一致性提升

9.6 用戶最終 3 個批評(無解)

v4 交付,用戶回三條無解物理盲區:

  1. 武打太慢:Wan22 5B prompt-driven motion,「fast」實際還是 diffusion 平均速度。需 14B 才解,5060 Ti 跑不動
  2. 臉扭曲:Wan22 5B 第 30 幀後人臉漂移,需 14B 才解
  3. 配音慢:Edge TTS rate +20% 是天花板,再快卡頓變慢動作,需付費 SSML API(Azure / ElevenLabs)

我對著這三條看了 30 分鐘,打開 CLAUDE.md 寫下:

honest admit:5060 Ti 16GB 已天花板。30 天 17 版證明本地消費卡跑不動產業級短劇生成。下一步:認輸轉雲端 / 寫教科書。

然後我寫了這篇文章。

9.7 v17 四連戰時間消耗

v1 愛情劇 4 hr → 嘴模糊;v2 武俠 5 hr → 4 缺陷;v3 修 v2 8 hr → 引入 3 bug;v4 修 v3 6 hr → 認輸。合計 23 hr / 4 個 demo / 0 過關。

9.8 為什麼 v17 在 10 秒 demo 階段就認輸

v14 教訓是「不要先量產」,v17 嚴格遵守「先 10 秒 demo」,但 v17 v4 仍失敗 —— 不是流程問題,是無論怎麼 demo,10 秒裡仍會曝露「嘴模糊 / 臉漂 / 配音慢」三個物理盲區。

  • v14 失敗 = 流程問題(沒 smoke test)→ 可修
  • v17 失敗 = 物理問題(硬體 + 模型上限)→ 改不了,除非換硬體(24GB+)或換 pipeline(雲端)

9.9 第九章的小結

核心收穫:(1) 10 秒 demo smoke test 是對的,但不能 cure 物理盲區;(2) prompt engineering 救不了 motion speed,Wan22 5B 的動作速度是 model bias;(3) 每次「修」會「引入新 bug」,pipeline 複雜度導致「修一處壞兩處」;(4) 白屏 / cfg hang / VRAM zombie 是 ComfyUI 量產隱性炸彈。

教訓 9.1:根因是「物理盲區 + 硬體限制」就停止迭代,直接寫認輸文件轉路線。每多迭代一版是 4-8 小時。 教訓 9.2:ffmpeg filter 第一次用先讀官方文件,「alpha=0」這種字面意思跟行為不同的坑滿地都是。 教訓 9.3:ComfyUI VRAM zombie 真實存在,量產每 batch 後加 pkill + fuser -k + restart,否則 50 shot 後 GPU 卡死。


第 10 章 終章:本地 vs 雲端的最終決勝

摘要:把 30 天的真實成本算給你看。一張對照表 + 雲端 vs 本地時序圖 + 給後來者的 10 條建議。看完這章你會理解為什麼 2026 年 6 月的「本地全免費」是工程師最大的自我欺騙。

10.1 本地 vs 雲端 真實成本對照

下面這張表是 30 天結束時我們對所有可用方案做的硬比較:

維度 本地 5060 Ti 16GB Dreamina Kling 1.6 Runway Gen-3
一次性硬體成本 NT$15,000 0 0 0
每月電費(30 天 GPU 全速) NT$650 0 0 0
每 clip 成本(10 秒) "免費" 免費(225 點 / 天) NT$10 $1
影片品質(10 分滿分) 60 分 90 分 95 分 98 分
角色一致性 差(face drift) 好(內建 character ref) 極好(character lock) 極好
中文配音 Edge TTS 免費版單調 內建情感配音 內建情感配音 需另接 ElevenLabs
對嘴 MuseTalk 256² 模糊 內建 內建 需另接
30 集成本(30 × 5 min ≈ 90 個 10s clip / 集 × 30 = 2700 clip) "免費" + 1 個月血淚 免費(225 點 / 天 = 11 個 clip / 天 → 246 天) NT$27,000 $2,700
上手時間 30+ 天 30 分鐘 30 分鐘 1 小時
1 集量產時間(90 clip) 21+ hr 8 hr(手動)/ 2 hr(API) 2 hr 1 hr
API 可程式化 完全 部分 完全 完全

10.2 30 集真實成本拆解

以 30 集 × 5 分鐘短劇為例:

本地 vs 雲端 30 集成本時序圖

本地路線(5060 Ti 16GB):
  Day 1-30  │ 17 版開發 + 0 集上線
  Day 31-56 │ 假設能繼續,每集量產 21 hr × 30 ≈ 26 天 GPU 連跑
  ─────────│
  電費 NT$823 + 硬體攤提 NT$780 + 人力 56×8×NT$1000 = NT$449,603
  最終結果:0 集上線(30 天結束時連 1 集 demo 都沒過用戶簽核)

雲端路線(Kling 1.6):
  Day 1     │ 註冊 + 看 demo
  Day 2-5   │ 30 集劇本 + 主視覺
  Day 6-15  │ API 串接 + batch 腳本
  Day 16-30 │ 30 集 × 90 clip × NT$10 = NT$27,000 直接量產
  ─────────│
  API NT$27,000 + 人力 30×8×NT$1000 = NT$267,000
  最終結果:30 集全上線

雲端少花 NT$182,603,而且真的有成品。

10.3 雲端 API 不是 cheating

工程師心結「用雲端 = 放棄」是不理性的:

  1. 時間值錢:時薪 NT$500,30 天 × 8 hr = NT$120,000。雲端 NT$27,000 跑 30 集,等於用 NT$27,000 換 NT$120,000
  2. 本地不是 0 成本:5060 Ti 350W × 24 hr × 30 天 ≈ NT$882 電費 + 硬體攤提
  3. 品質差距是 cliff 不是 gradient:本地 60 分 vs 雲端 95 分,觀眾不會給三星,他們直接滑掉。沒觀眾 = 沒變現 = 商業模型崩

10.4 雲端 API 短評

  • Dreamina(字節跳動):每天免費 225 點 ≈ 11 個 10 秒 clip,中文 prompt 對齊度第一,付費約 NT$300/月起;適用個人試水溫
  • Kling 1.6(快手):影片品質、motion、角色一致性頂尖,每 clip 約 NT$10;商用首選,API 完整公開
  • Runway Gen-3:英文 cinematic 感最強,每 clip US$1;中文支援差,需另接中文配音
  • Pika 2.0:UI 友善、月費制,解析度上限 1280×720;適合社群短影片
  • Hailuo(MiniMax):中文 + 角色一致性內建不錯,API 還不太穩定(2026/6 狀態)

10.5 「本地仍然有意義」的三個場景

本地在以下場景仍有意義:(1) LoRA 訓練 / fine-tune(雲端不提供);(2) 批量後處理(RIFE 補幀 / RealESRGAN 超解析度 / GFPGAN 修臉);(3) prompt research / 風格實驗(零邊際成本)。

本地的正確定位是「實驗室 + 後製站」,不是「量產車間」。

10.6 給後來者的 10 條建議

10 條血淚建議,每條都能省你至少 3 天:

  1. 先量你的 VRAM,再選 pipeline:16GB vs 24GB 在 2026/6 是兩個物種。第二章那張「能跑 / 不能跑」清單先抄
  2. 本地 + 雲端混合,不要二選一:本地跑 LoRA + 後處理,雲端跑 i2v + 對嘴。月成本 NT$5,000-15,000,品質 90 分
  3. 量產前必須 30 秒 smoke test 給用戶簽:dispatcher 所有 type 各 1 shot concat 成 30 秒,用戶簽核才動量產。v14 血淚教訓
  4. 保留所有「過時」版本:v8 / v9.1 / v12B2 都被「過時」過,但仍是某些場景最佳。dispatcher 留 fallback
  5. technical selection 別信「state of the art」:LatentSync 在 3 agent 共識下被推,實測輸 2020 年 Wav2Lip。讀 limitations、讀 demo 場景、讀 issue 最近 3 個月
  6. custom node 4 個月沒更新就視同 deprecated:PuLID-Flux 是案例
  7. WSL2 vmIdleTimeout 必須設 -1:搭配 Mac SSH keeper(nohup ssh sleep 3600),否則 28 秒 idle terminate
  8. Edge TTS 免費版不能做產業級配音:上 Azure Premium(NT$0.05/字)或 ElevenLabs($5/月起)
  9. ComfyUI 量產必須有 health check + watchdog:每 N batch 自動 pkill + fuser -k + restart,否則 50 shot 後 GPU 卡死
  10. 先承認本地有天花板,再決定戰術:「30 集上 YouTube 商用」在 5060 Ti 16GB 是死路。承認能省你 30 天

10.7 30 天的最終結論

10 條:(1) 本地天花板真實存在;(2) 沒有單一銀彈,pipeline 必須 modular;(3) face_alignment 68 vs mediapipe 是地雷,MuseTalk 必走 dlib;(4) WSL vmIdleTimeout=-1 是 PC 長任務命脈;(5) Edge TTS 免費版 SSML 限縮,商業必上 Azure Premium / ElevenLabs;(6) 量產前必 smoke test 10 秒;(7) 品質基準是文章先決;(8) 雲端 API 不是 cheating,算對成本後常更便宜;(9) 失敗版本要保留當 fallback;(10) 手動驗證 > agent 報「完成」。

10.8 給看到這裡的讀者

如果只能從這篇拿走一件事:「本地全免費」是 2026 年 AI 影片生成圈最大的工程師自我欺騙。免費的是 GPU 算力,貴的是你的 30 天時間。

不管選哪條路,請至少做到「smoke test 先給用戶簽」這一件事。30 天結束。Drama Factory 專案封存。


附錄 A:30 天時間軸總表

日期 版本 結果
5/17 立項 看《五十岁》後本地複製
5/18 Phase 0 LoRA Flux LoRA 13 角色 30 hr 連跑
5/22 v1.7 GGUF Wan22 14B OOM 棄
5/24-25 v8 Wav2Lip baseline shot06 OK,多半垃圾
5/26 LTX 中介 i2v 鎖首幀差
5/27 v4-v6 sniper v6 GFPGAN 過關
5/27 v8 MuseTalk mmcv 棄走 Wav2Lip
5/28 早 v9.1 GFPGAN / v10 LatentSync v9.1 較穩
5/28 晚 v11 PuLID + v12 五版 全敗,寫 handoff
5/29 v13 MuseTalk face_alignment 68 patch 跑通 256²
5/31-6/1 v14 量產 450 shot 21 hr 17.7 min mp4,被批 7 項
6/1-6/3 v15 修 7 缺陷 smoke only
6/3 v16 動漫 460-shot 翻車
6/3-6/4 v17 10 秒 4 連版 v4 仍 3 物理盲區
6/4 認輸封存 寫教科書

附錄 B:30 天踩過的 10 個坑(速查)

# 坑 修法
1 WSL idle terminate(每 28 秒殺一切) .wslconfig 設 vmIdleTimeout=-1 + Mac 端 keeper
2 Ollama 長輸出 >10K tokens 斷線 拆 patch 短段,gemma family CPU offload 不穩
3 Qwen3 + format=json + thinking 衝突 /no_think + 拿掉 format=json + regex parse
4 Python .format() 對 JSON 範例 prompt 炸 統一用 .replace()
5 ComfyUI-FluxTrainer 5 連坑 numpy + transformers + cp950 + detach + caption_dropout
6 5060 Ti Flux LoRA cache miss 197s/step 預熱 cache,第二角色起 70s/step(3x 差距)
7 Windows cp950 console 殺 ComfyUI training chcp 65001 + PYTHONIOENCODING=utf-8 寫進 .bat
8 HF BFL Flux 全 gated 走 ComfyUI portable fp8 single-file 避開
9 duix.avatar 3 container 偷 6.5 GB GPU restart=no + stop 永久關
10 Port 8188 portproxy 占用 8189 不動 portproxy,用 8188 + SSH tunnel 28189

附錄 C:軟體棧速查表

工具 用途 狀態
ComfyUI v0.21.1 portable GPU pipeline 主機 ✅
Wan22 5B ti2v fp16 i2v 影片生成 ✅ 但 81 幀上限
Flux fp8 single-file anchor 圖生成 ✅
MuseTalk V1.5 對嘴 256² ✅ v13 patch
LatentSync 1.5 對嘴複雜 face-on only ⚠️
Wav2Lip 96² + GFPGAN v1.4 對嘴 backup ✅
LivePortrait KJ 表情注入 ❌ extreme 表情 fail
NoobAI XL Vpred 1.0 7.1 GB 動漫 base ✅ v16
IPAdapter Plus SDXL ViT-H 角色 reference ✅
Edge TTS(Xiaoxiao / Yunjian) 旁白 ⚠️ SSML 受限
F5-TTS / GPT-SoVITS voice clone 收完待煉
ReActor face swap ✅
RIFE 補幀 24→48 fps ✅
ffmpeg vf zoompan / scale / crop 運鏡 ✅ v15 加
Ollama qwen3:14b 劇本生成 ✅ 主力 40 tps
Ollama gemma2:27b 劇本 fallback ⚠️ CPU offload 18 tps JSON 不穩

附錄 D:本地 vs 雲端速查決策

  • 商用變現 + 時薪 > NT$500 → 雲端 Kling + ElevenLabs
  • 商用變現 + 純練手 → Dreamina 免費每天 11 clip
  • 學技術 / 寫文章 → 本地,這篇是你的指南

預算對照: - 純本地:NT$650/月電費 + 30 天時間(產出爛) - 純雲端:NT$27,000/30 集(Kling)/ NT$87,000(Runway) - 混合(推薦):NT$5,000-15,000/月(本地 LoRA + 雲端 i2v)

承認失敗比繼續迭代更勇敢。如果你正在重複我們的某一步,希望這篇文章能讓你提早一週認輸。

完。


本系列其他兩篇

這篇是 A 版(30 天血淚教科書,敘事風)。同系列另有兩個視角:

三篇用同一份 30 天血淚數據,但給不同類型讀者。建議閱讀順序:B(決定要不要做)→ A(理解失敗本質)→ C(真要做的執行指南)。