Skip to content

CMU 10-423 HW2:在 AFHQ 貓圖上從零實作 DDPM——題目結構、要改的檔案與算力

2026年9月30日1 分鐘
TL;DRCMU 10-423 Spring 2026 的 HW2 總分 60:書面題考 CNN(8 分)、encoder-only Transformer(4 分)、GAN(5 分)、VAE(6 分)與擴散模型(14 分),程式題(21 分)要你在 AFHQ 貓圖上從零實作 DDPM,填完 diffusion.py 與 unet.py 的 TODO,再用 W&B 交出損失曲線、FID 曲線與正反向擴散圖。最長的一個實驗是在 Colab T4 上訓練 10,000 步,官方估計約 2 小時。

🌏 English version

本文依據 CMU 10-423/623/723 Generative AI Spring 2026 版。 這是 CMU 10-423 導讀系列第 9 篇,也是影像單元的收尾。前面四篇講了 CNN 與 ViT、GAN、擴散模型 與 變分推論和 VAE,這一篇看作業怎麼把它們全部考一遍,再要你親手寫出一個會畫貓的 DDPM。

用到的官方材料:Coursework 頁上的 hw2.zip(32 MB,內含 27 頁的 hw2.pdf、起始碼、資料與 LaTeX 模板)、HW2 Overleaf 唯讀模板、2 月 13 日的 HW2 recitation 投影片(Google Drive 上的 PowerPoint,公開),以及課綱的作業規則。事實皆於 2026-09-30 打開官方材料核對。本文只寫題目結構與設定,不附任何解答。

基本資料

項目內容
名稱Homework 2: Generative Models of Images(Coursework 頁標為「Image Generation」)
範圍L5–L8(講次表在 2 月 9 日寫「HW2 out (L5-L8)」)
發下2026-02-09
截止2026-02-21 晚上 11:59(Slot A,L10 投影片的 Reminders)
Slot B講次表暫定 3 月 1 日;回饋暫定 2 月 26 日
繳交Gradescope:書面 PDF 一份、程式只交 diffusion.py
總分60

配分表(hw2.pdf 第 2 頁):

大題分數
LaTeX Template Alignment0
Convolutional Neural Networks8
Encoder-only Transformers4
Generative Adversarial Network (GAN)5
Variational Autoencoders6
Understanding Diffusion Models14
Programming: Diffusion Models21
Code Upload0
Collaboration Questions2

書面答案要照模板作答,沒對齊模板會被扣該份作業 2% 的分數,hw2.pdf 給的理由是批改有用到 AI 輔助的評分器。課綱的 Slot A/B 規則也適用:Slot A 只能交純人工作答,拿到回饋後三天內可以在 Slot B 用 AI 輔助修正答錯的題目,每題取兩次較高分。完整規則寫在系列總覽。

書面題在考什麼

五個書面大題幾乎一講一題,順序跟 L5–L8 一致。

CNN(8 分)。 先給一個單通道輸出的卷積定義,要你算出左右上下各需要幾行、幾列「幻覺像素」(hallucinated pixels),只能用 floor 函式表示;再把公式改寫成先補零、只索引合法位置的版本。最後兩小題是 U-Net 的觀念題:skip connection 的作用,以及特徵圖解析度在 encoder 與 decoder 裡怎麼變。這兩題是為程式題鋪路,因為 DDPM 的去噪網路就是 U-Net。

Encoder-only Transformer(4 分)。 畫出 decoder-only Transformer 所定義序列分佈的有向圖模型,再比較 encoder-only 模型接上逐字詞性分類頭之後,能表達哪一類序列分佈、各自適合什麼應用。對應 L5 的 BERT 段落。

GAN(5 分)。 情境是題目裡的角色 Lora the Llama 想替灰階的羊駝照片做 inpainting。題目給一段訓練虛擬碼,要你補上三個空格:模型輸出怎麼只替換被遮住的像素、只看遮罩區域的平方誤差,以及 GAN 形式的目標函數;最後問只用平方誤差訓練有什麼缺點。

VAE(6 分)。 第一小題給一個一維的線性高斯 encoder/decoder,問「把取樣當黑盒子」與「用 reparameterization trick」兩種計算圖下,哪些參數收得到重建項的梯度。第二小題把 VAE 用在影片上,要你寫出一個 batch 的完整損失(MSE 重建項加上乘了 β 的 KL 項)。第三小題是 β-VAE 的單選:β 從 0 慢慢調大時,潛在表示與重建品質怎麼變。

Understanding Diffusion Models(14 分)。 全份作業最重的書面題,分兩段:

  • ELBO Surgery(6.1–6.2):6.1 占 5 分,要你從 ELBO 出發,證明它可以拆成重建項、一串 L_t 項與一個跟 θ 無關的常數。題目附了六條提示,還加註「證明很可怕」,期待的答案以方程式為主。6.2 問 L_t 對反向過程的作用,以及它何時最大。
  • Image Diffusion(6.3–6.5):給定每一步的前向分佈,先描述怎麼一步步取樣到第 τ 步、時間複雜度是多少;再用 reparameterization trick 推出可以直接從 x₀ 跳到 x_t 的封閉形式;最後說明用這個形式取樣的做法與複雜度。

6.4 推出來的那條式子就是程式題 q_sample 要實作的東西,所以建議先寫完第 6 題再動程式。ELBO 的推導背景在第 8 篇。

程式題:從零實作 DDPM

資料

hw2.pdf 寫的資料集是 Animal Faces-HQ(AFHQ),「15,000 張 36×36 的圖片」,分貓、狗、野生動物三類,作業只用貓圖以降低計算量;handout 也事先說明,因為只用了原資料集的子集,生成品質可能不如預期。我實際解開 zip 數了一次:data/train/ 底下 cat 5,153 張、dog 4,739 張、wild 4,738 張,data/val/ 三類各 500 張,每張確實是 36×36。模型預設的 image_size 是 32。

資料就在 zip 裡,不用另外下載。Kaggle 版 notebook 另外提供一個已上傳的 Kaggle 資料集,2026-09-30 仍可打開。

檔案與要改的地方

檔案作用
diffusion.pyDiffusion 類別:前向過程、反向過程與排程,要改
unet.py去噪用的 U-Net,要改(只有 forward)
trainer.py訓練迴圈、取樣、FID、W&B 紀錄
utils.pytrain_diffusion、visualize_diffusion 兩個入口與 W&B 初始化
main.py在本機或 AWS 上跑的命令列入口
run_in_colab.ipynb/run_in_kaggle.ipynb雲端 notebook
test_diffusion.py、data.pt單元測試與測試用的固定張量
requirements.txt依賴清單

hw2.pdf 說只需要改 diffusion.py 和 unet.py,要改的地方都標了 TODO。實際打開檔案:

  • diffusion.py 有 7 個 TODO:__init__ 裡的預先計算係數,加上 q_sample、p_losses、forward、p_sample、p_sample_loop、sample 六個函式。recitation 投影片把它們分成訓練(forward、p_losses、q_sample)與取樣(sample、p_sample_loop、p_sample)兩組。
  • 噪音排程已經寫好:cosine_schedule 實作 Nichol & Dhariwal(2021)的 cosine 排程,s = 0.008。
  • unet.py 的 TODO 集中在 Unet.forward:下採樣路徑每一層跑兩個殘差區塊與 attention、存下 skip 特徵,接 bottleneck,再在上採樣路徑把 skip 特徵串接回來。網路的各個元件(ResnetBlock、LinearAttention、SinusoidalPosEmb 等)都已經給好。

hw2.pdf 規定的訓練細節:p_losses 用 L1 損失比較真實雜訊與預測雜訊;取樣演算法會先由預測雜訊估出 x̂₀、把它 clamp 到 [−1, 1],再用後驗平均與變異數往前走一步。trainer.py 用 Adam。

有一處要注意:Code Upload 題與測試檔都寫明只上傳 diffusion.py,但 unet.py 也有 TODO,第 8 個測試也在測 U-Net 的 forward。Gradescope 實際怎麼處理 unet.py,校外看不到。

預設超參數

參數預設值
time_steps(T)50
batch_size32
image_size32
unet_dim16
unet_dim_mults[1, 2, 4, 8]
learning_rate1e-3
data_classcat
dataloader_workers16

hw2.pdf 說表 4 的這些值在本作業中不需要改;實驗之間要調的只有 train_steps、save_and_sample_every 和 fid。

單元測試

test_diffusion.py 有 8 個測試,全部強制在 CPU 上跑(註解說 GPU 可能產生些微不同的輸出)。T01(檢查上傳檔案)與 T02(noise_like)權重為 0,T03–T08 各 1 分,分別測 p_sample、p_losses、p_sample_loop、sample、q_sample 與 U-Net forward。

我在 2026-09-30 用 macOS、Python 3.12、PyTorch 2.14.0(CPU)跑未修改的起始碼:8 個測試約 5 秒跑完,T01、T02 通過,其餘 4 個 FAIL、2 個 ERROR,這是 TODO 還沒填的預期結果。要注意 diffusion.py 開頭就 import wandb,所以連跑測試都要先裝 wandb。我只裝了 torch、einops、tqdm、wandb,沒有照 requirements.txt 的版本釘選。

五個實驗題

程式題的 21 分全部來自實驗結果,圖都從 W&B 取:

題號內容建議參數官方估計(Colab T4)分數
7.11,000 步的訓練損失曲線;此時應該生成出模糊的貓train_steps=1000、save_and_sample_every=100、fid=False5–10 分鐘4
7.2每 100 步算一次 FID,畫 1,000 步內的 FID 曲線同上,fid=True15–60 分鐘4
7.3完整訓練 10,000 步,貼出最後一批生成圖train_steps=10000、save_and_sample_every=1000、fid=False約 2 小時5
7.4用 10,000 步的模型畫前向過程:0%、25%、50%、75%、99%呼叫 visualize_diffusion—4
7.5把前向過程最後一步的雜訊餵回去,畫反向過程的同樣五個時間點同上—4

FID 用 clean-fid 的 compute_fid 計算。hw2.pdf 的描述是和「縮放過的訓練圖」比較;trainer.py 的寫法是把 data_path 裡的 train 換成 val 當參考資料夾,只有那個資料夾是空的時候才把訓練集的貓圖縮放後放進去。zip 已經附了非空的 data/val/,照預設路徑跑時實際比對的是哪一組圖,我沒有跑 FID 驗證。

環境與算力:今天還跑得動嗎

hw2.pdf 列了三種跑法:本機或 AWS 用 main.py,雲端用 Colab 或 Kaggle 的 notebook,開 GPU 的詳細步驟則要回去看 HW1 的 handout。兩份 notebook 的用法相同:先裝 requirements.txt,把整份 diffusion.py 貼進指定的 cell,填好 train_steps、save_and_sample_every、fid 三個參數,再呼叫 train_diffusion 與 visualize_diffusion。

算力要抓寬一點:

  • recitation 投影片說這是整門課訓練時間最長的一份作業,要跑的實驗在 Colab T4 上合計 2–3 小時,而且除錯時多半會重跑。它的建議是提早開始、先用少量步數測試程式。
  • 同一份投影片有一頁寫「Colab Pro is FREE for students」。這是對修課學生說的,校外讀者能不能適用,我沒有查證。
  • requirements.txt 要求 Python 3.9 以上、3.13 以下,並釘選 clean-fid 0.1.35、einops 0.8.1、pillow 11.3.0、tqdm 4.67.1、wandb 0.21.3;torch 與 torchvision 沒有釘版本。
  • utils.py 在訓練與視覺化開始前都會呼叫 wandb.login(),所以需要一個 Weights & Biases 帳號。紀錄會寫到名為 DDPM_AFHQ 的 project。

跟 HW1 相比,HW2 一樣不需要下載外部權重,資料也在 zip 裡;多出來的門檻是 W&B 帳號和較長的 GPU 時間。

Recitation 投影片可以補什麼

2 月 13 日的 recitation 投影片共 75 頁,分三段:

  • 起始碼導覽:逐一說明每個檔案的用途,把實作拆成四塊:U-Net 的 forward、噪音排程(已完成)、訓練演算法、取樣演算法。後兩塊就是 diffusion.py 的六個函式。
  • 書面題複習:用「會加噪也會去噪」的比喻講擴散模型,強調「去噪不是還原圖片,而是生成圖片」;介紹 FID 怎麼用 Inception-v3 抽特徵、分數越低越接近目標分佈;ELBO 則用「要寫得準確、又要衝點閱率的犯罪現場記者」比喻重建誤差與 KL 項,再用 Jensen 不等式一步步推導,最後講 reparameterization trick。
  • 好用的函式:為什麼要用 noise_like 而不是直接呼叫 torch.randn(投影片的答案是讓每份繳交的隨機性一致)、gather_timestep_coeff 怎麼從預先算好的係數表取出需要的時間步,以及 torch.cumprod、torch.clamp、torch.full 的小測驗。torch.clamp 那題特地示範把 numpy 陣列傳進去會丟 TypeError。

這份投影片放在 Google Drive 上,是 PowerPoint 檔而不是原生的 Google Slides,2026-09-30 可以直接匯出下載。

這份作業跟考試的關係

講次表把「Programming Test HW1/HW2」排在 2 月 25 日課堂上,範圍是 HW1 與 HW2 的程式部分,閉書。這場測驗校外拿不到,但它說明了課程期待你真的理解自己寫的 q_sample 與 p_sample,而不只是讓測試通過。練習考卷裡對應 HW2 範圍的是 ViT(14 分)、GAN(9 分)、VAE(8 分)與 Diffusion Models(8 分)四題。

怎麼做:今晚下載 hw2.zip,裝好 torch、einops、tqdm、wandb,跑一次 python test_diffusion.py,確認看到 T01、T02 通過、其餘失敗。接著先寫書面題 6.4,把 q(x_t | x₀) 的形式推出來,再打開 diffusion.py 填 __init__ 和 q_sample,讓 T07 變綠。

這一篇可以確認與不能確認的

可以確認:hw2.zip 裡的 PDF、起始碼、資料與測試,recitation 投影片,課綱的 Slot A/B 規則,講次表的日期,以及本機跑單元測試的結果。不能確認:Gradescope 的自動評分與人工批改標準、unet.py 在 Gradescope 上怎麼被評分、講次表暫定的 Slot B 日期(3 月 1 日)當學期是否照表執行、FID 實際使用的參考圖、在 Colab T4 上的實際訓練時間(我沒有在 GPU 上跑),以及官方解答。

延伸閱讀:想從 ODE/SDE 的角度重新理解擴散模型與 flow matching,可以看 MIT 6.S184 導讀;它的 Lab 3 也有另一份從零訓練生成模型的作業可以對照。

系列導覽:上一篇 L8–L9:變分推論、VAE 與擴散模型的 ELBO|下一篇 L10–L11:參數高效微調與 in-context learning|系列總覽

參考資料