Mở đầu: 170 mẫu dồn về 1 phía, phía kia trống trơn — mode collapse thật
Train $1$ GAN nhỏ để bắt chước phân bố $2$ nhóm điểm tách biệt (mean $-2$ và $+2$) — nếu Discriminator học nhanh hơn Generator quá nhiều ($5$ bước cập nhật D cho mỗi $1$ bước G), verify bằng số thật: trong $200$ mẫu Generator sinh ra, $170$ mẫu dồn hết về nhóm $-2$, đúng $0$ mẫu rơi vào nhóm $+2$. Generator đã tìm ra $1$ "chiêu" duy nhất đánh lừa được Discriminator và LẶP LẠI mãi nó — bỏ hẳn nửa kia của phân bố mục tiêu. Đây gọi là mode collapse, cạm bẫy nổi tiếng nhất khiến GAN khét tiếng khó train.
Cùng bài toán sinh mẫu, diffusion đi hướng khác hẳn: không đối kháng, chỉ có $1$ hàm hồi quy đơn thuần. Bài này verify diffusion không chỉ train ổn định hơn (không có bên nào "phá" bên nào) mà còn thực sự SINH ĐƯỢC mẫu giống dữ liệu gốc — điểm sinh ra từ nhiễu thuần gần hình xoắn ốc mục tiêu hơn $5{,}8$ lần so với điểm nhiễu ngẫu nhiên chưa qua xử lý gì.
1. Bài toán sinh: học cả phân bố, không chỉ học ánh xạ
Toàn bộ $14$ bài trước (trừ Bài 4) học discriminative: cho input $x$, dự đoán nhãn/giá trị $y$ — một ánh xạ $x\to y$. Mô hình generative học điều khác hẳn: phân bố xác suất $p(x)$ của chính dữ liệu, để sau đó LẤY MẪU MỚI từ phân bố đó — sinh ra ảnh/nhạc/văn bản chưa từng tồn tại nhưng "giống thật".
| Discriminative (Bài 1–3, 6, 10, 11) | Generative (bài này) | |
|---|---|---|
| Học gì | Ánh xạ $p(y \mid x)$ — input $\to$ nhãn | Phân bố $p(x)$ — chính dữ liệu |
| Dùng để làm gì | Phân loại, hồi quy, phát hiện | Sinh mẫu MỚI (ảnh, nhạc, văn bản, video) |
| Ví dụ đã học | MLP MNIST (Bài 10), CNN (Bài 11) | GAN, Diffusion (bài này) |
Đây là "nửa còn lại" của AI hiện đại — cùng nền tảng toán học (gradient descent, backprop, MLP) nhưng nhắm tới mục tiêu hoàn toàn khác: không phải "đoán đúng", mà "tạo ra cái mới hợp lý".
2. GAN: trò chơi minimax Generator vs Discriminator
$2$ mạng đấu nhau: Generator ($G$) nhận nhiễu ngẫu nhiên $z$, cố tạo ra mẫu giả trông như thật; Discriminator ($D$) nhận $1$ mẫu (thật hoặc giả), cố đoán đúng nó từ đâu ra. $G$ học từ chính việc "đánh lừa" $D$ — không có nhãn thật nào cho $G$ ngoài tín hiệu phản hồi từ $D$. Công thức trò chơi đối kháng (minimax):
$$\min_G \max_D \; \mathbb{E}_{x\sim p_{data}}[\log D(x)] + \mathbb{E}_{z\sim p_z}[\log(1-D(G(z)))]$$
$D$ muốn tối đa hoá: đoán đúng mẫu thật là thật ($D(x)\to1$) VÀ đoán đúng mẫu giả là giả ($D(G(z))\to0$).
$G$ muốn tối thiểu hoá đúng vế thứ $2$ — nói cách khác, muốn $D(G(z))\to1$ (lừa được $D$ tin mẫu giả là
thật). Cài đặt dùng đúng sigmoidCrossEntropy() đã có từ
Bài 12 cho cả $2$ mạng — $D$ là bài toán phân loại nhị phân thông
thường, $G$ tối ưu hoá gián tiếp qua gradient CHẢY NGƯỢC từ $D$.
Mode collapse (verified ở đầu bài): nếu $D$ học NHANH HƠN $G$ quá nhiều, $G$ không có đủ "thời gian" khám phá toàn bộ phân bố mục tiêu — nó tìm ra $1$ điểm mù của $D$ và bám chặt lấy đó, in ra gần như CÙNG $1$ mẫu (hoặc $1$ cụm rất hẹp) mãi mãi, bỏ hẳn phần còn lại của dữ liệu thật. Verify: $170/200$ mẫu dồn về nhóm $-2$, nhóm $+2$ hoàn toàn trống.
Mất cân bằng huấn luyện: $D$ quá mạnh làm $G$ không nhận được gradient hữu ích (loss bão hoà — nối cạm bẫy scale ở Bài 14); $D$ quá yếu thì $G$ "lừa" được mà không thực sự học được gì có ích, vì tín hiệu phản hồi từ $D$ không đáng tin. Verify bằng số ở cấu hình CÂN BẰNG ($1$ bước $D$/$1$ bước $G$, $80$ epoch): tương quan giữa loss $D$ và loss $G$ qua từng epoch là $-0{,}307$ — âm rõ rệt, đúng đặc trưng đối kháng: khi $D$ "khá hơn" (loss giảm), $G$ ngay lập tức "tệ đi" (loss tăng) và ngược lại, $2$ mạng liên tục giằng co thay vì cùng hội tụ êm ả như $1$ bài toán hồi quy thông thường.
- $D(G(z))=0{,}5$ (D chưa phân biệt được): cả 2 công thức cho gradient $-2{,}0$ — giống nhau.
- $D(G(z))=0{,}1$ ($D$ khá chắc mẫu là giả): gốc $\approx -1{,}11$ (gần như bão hoà) so với non-saturating $-10{,}0$ (mạnh gấp $9$ lần).
- $D(G(z))=0{,}01$ ($D$ RẤT chắc mẫu là giả — đúng lúc $G$ cần sửa gấp nhất): gốc chỉ còn $\approx -1{,}01$ — gần như PHẲNG, trong khi non-saturating vọt lên $-100{,}0$.
3. Diffusion: thêm nhiễu dần, rồi học khử nhiễu ngược
Ý tưởng hoàn toàn khác GAN: quá trình tiến (forward) thêm nhiễu Gauss nhỏ liên tiếp qua $T$ bước cho tới khi dữ liệu biến thành nhiễu thuần $\mathcal{N}(0,1)$ — đây là công thức CỐ ĐỊNH, không học gì cả:
$$x_t = \sqrt{\bar\alpha_t}\,x_0 + \sqrt{1-\bar\alpha_t}\,\epsilon \qquad \epsilon\sim\mathcal{N}(0,1)$$
$\bar\alpha_t$ giảm dần từ gần $1$ (bước $0$, gần như chưa nhiễu) về gần $0$ (bước $T$, nhiễu thuần) — verify với lịch trình $T=50$ bước dùng trong demo: $\bar\alpha_0=0{,}9999$, $\bar\alpha_{49}=0{,}0046$. Quá trình ngược (reverse) là phần DUY NHẤT cần học: $1$ mạng $\epsilon_\theta(x_t, t)$ nhận điểm nhiễu $x_t$ VÀ bước thời gian $t$, dự đoán ĐÚNG lượng nhiễu $\epsilon$ đã cộng vào — huấn luyện bằng MSE đơn giản giữa nhiễu dự đoán và nhiễu thật, không có đối kháng nào cả.
Đây chính là lý do diffusion train ổn định hơn GAN hẳn: chỉ $1$ mạng, $1$ loss hồi quy trơn tru, giảm đều qua epoch (verify: từ $\approx2{,}56$ epoch đầu xuống ổn định quanh $0{,}4$–$0{,}5$) — không có "đối thủ" nào để giằng co, không tương quan âm kiểu Mục 2.
GAN sinh mẫu chỉ cần $1$ lượt forward qua $G$ — tức thì. Diffusion cần lặp lại quá trình ngược ĐỦ $T$ bước (demo dùng $T=50$; ảnh thật thường cần hàng chục tới hàng trăm bước) — mỗi bước là $1$ lượt forward qua mạng denoiser. Chất lượng/ổn định đổi lấy tốc độ — sự đánh đổi kinh điển trong toàn bộ học máy sinh.
4. Vì sao diffusion soán ngôi — và GAN còn đất sống ở đâu
Từ khoảng $2020$ (Ho et al. — DDPM), diffusion vượt GAN trên hầu hết benchmark ảnh: chất lượng cao hơn, đa dạng hơn (không mode collapse), và train ổn định hơn hẳn (verified Mục 2-3). Đây là kỹ thuật đứng sau Stable Diffusion, DALL-E 2/3, Midjourney.
GAN vẫn còn đất sống ở nơi cần tốc độ sinh tức thì (real-time — game, video call) và siêu phân giải ảnh (super-resolution) — chính vì GAN chỉ cần $1$ lượt forward, không phải đánh đổi hàng chục bước như diffusion.
Sinh có điều kiện (conditional generation): thay vì sinh ngẫu nhiên, "mớm" thêm thông tin (nhãn lớp, hoặc — như Stable Diffusion — embedding của $1$ câu mô tả văn bản) vào mạng denoiser ở mỗi bước, hướng quá trình sinh theo đúng ý muốn. Đây chỉ là cửa sổ khái niệm — cơ chế embedding văn bản đầy đủ (text-to-image) vượt phạm vi bài; tài liệu tham khảo cuối bài dẫn đường đọc tiếp.
5. Thực hành: diffusion 2D và mode collapse GAN 1D
Train denoiser MLP nhỏ trên hình xoắn ốc, rồi bấm từng bước khử nhiễu xem hình "mọc" ra từ đám nhiễu thuần:
Hình xoắn ốc mục tiêu (300 điểm)
Nhiễu thuần (bước T)
Minh hoạ phụ hoạ — GAN 1D: chọn cấu hình huấn luyện, xem mode collapse xảy ra trực tiếp:
Chấm xanh lá = mẫu thật ($2$ nhóm quanh $-2$ và $+2$); chấm đỏ = mẫu Generator sinh ra. Cấu hình "D quá mạnh": mọi chấm đỏ dồn về $1$ phía. Cấu hình cân bằng: chấm đỏ trải rộng, chưa ổn định hẳn (đúng bản chất khó train của GAN — không phải lỗi cấu hình).
Đối chiếu công nghiệp: vòng train diffusion tối giản (PyTorch, ~$40$ dòng) đúng 1-1 với Mục 3, 5:
# Doi chieu 1-1 voi Muc 3 - cai dat: pytorch.org/get-started/locally
import torch, torch.nn as nn
T = 50
betas = torch.linspace(1e-4, 0.2, T)
alphas = 1 - betas
alpha_bars = torch.cumprod(alphas, dim=0)
denoiser = nn.Sequential(nn.Linear(3, 64), nn.ReLU(), nn.Linear(64, 64), nn.ReLU(), nn.Linear(64, 2))
optimizer = torch.optim.Adam(denoiser.parameters(), lr=1e-3)
for epoch in range(60):
for x0 in data_batches: # x0: (batch, 2) - diem that
t = torch.randint(0, T, (x0.shape[0],))
eps = torch.randn_like(x0)
ab = alpha_bars[t].unsqueeze(-1)
xt = ab.sqrt() * x0 + (1 - ab).sqrt() * eps # forward - KHONG hoc, cong thuc co dinh
pred_eps = denoiser(torch.cat([xt, t.unsqueeze(-1) / T], dim=-1))
loss = ((pred_eps - eps) ** 2).mean() # MSE thuan - KHONG doi khang
optimizer.zero_grad(); loss.backward(); optimizer.step()
# Sinh mau: bat dau x ~ N(0,1), lap nguoc t=T-1..0 dung cong thuc reverse Muc 3
Tóm lược
- ✅ Học sinh (generative) học phân bố $p(x)$ để lấy mẫu mới, khác hẳn học discriminative ($x\to y$) của $14$ bài trước — nền tảng sinh ảnh/nhạc/video.
- ✅ GAN = trò chơi minimax $G$ vs $D$; verified mode collapse thật ($D$ quá mạnh: $170/200$ mẫu dồn $1$ phía, phía kia trống trơn) và dao động đối kháng (tương quan loss $D$/$G=-0{,}307$, đúng đặc trưng "bên này thắng, bên kia thua").
- ✅ Diffusion = thêm nhiễu tiến (công thức cố định) + học khử nhiễu ngược (MSE đơn thuần, không đối kháng) — train ổn định hơn GAN hẳn, đổi lại sinh chậm (cần đủ $T$ bước, không phải $1$ lượt forward).
- ✅ Verified: mẫu sinh bằng diffusion từ nhiễu thuần gần hình xoắn ốc gốc hơn $5{,}8$ lần so với điểm nhiễu ngẫu nhiên chưa xử lý — quá trình ngược thực sự "học" được cấu trúc dữ liệu.
- ✅ Diffusion soán ngôi nhờ chất lượng+đa dạng+ổn định (Stable Diffusion, DALL-E); GAN còn đất sống ở real-time/siêu phân giải nhờ sinh tức thì.
Tải file code thực hành minh họa bài học
File JavaScript train GAN 1D (mode collapse + dao động đối kháng) và diffusion 2D (hình xoắn ốc), verify
bằng số đo được (chạy node gan_diffusion_demo.js, mất khoảng $1{,}5$ giây):
Bình luận