1. GAN 基础概念:生成对抗网络原理与架构
生成对抗网络,说白了就是让两个网络互相“对着干”。一个负责生成,一个负责鉴别。我记得第一次接触这个概念是在 2018 年,当时就觉得——这思路太妙了。造假币的和验钞的不断博弈,最后假币能乱真,验钞的也火眼金睛。你想想看,这不就是最好的学习机制吗?
在药物设计里,我们把“造假币”换成“生成化合物分子”,“验钞”换成“判别分子是否真实”。两个网络在对抗中共同进化,最后生成器能产出高度逼真的新分子。这就是 GAN 的核心魅力。
1.1 生成器:从随机噪声到分子结构
生成器 G 的任务很简单——输入一段随机噪声,输出一个化合物表示。这个表示可以是分子指纹、SMILES 字符串,也可以是 3D 构象的坐标矩阵。你给它一堆随机数,它还你一个看起来像模像样的分子。
我刚开始做生成模型时,总觉得这步像是“无中生有”,不太靠谱。后来才明白,随机噪声只是种子,真正的能力藏在生成器的网络参数里。它通过学习真实化合物的分布,把噪声映射到分子空间。
- 输入:高斯或均匀分布的随机向量(latent vector)
- 输出:固定长度的分子表示(如 128 维指纹或 SMILES 序列)
- 网络结构:常用反卷积层(图像)或 GRU/LSTM(序列),在分子领域多用 MLP + 残差连接
1.2 判别器:真假鉴定师
判别器 D 是个二分类器。它吃进去一个化合物表示,吐出来一个 0 到 1 之间的分数——越接近 1 表示越像真实分子,越接近 0 表示怀疑是生成的。
这里的“真实分子”来自训练集(比如 ChEMBL 或 ZINC 数据库),而“假分子”来自生成器。判别器的目标很简单:尽可能准确地把两者分开。
| 角色 | 生成器 (G) | 判别器 (D) |
|---|---|---|
| 核心目标 | 生成以假乱真的化合物 | 准确区分真伪分子 |
| 输入 | 随机噪声向量 | 化合物表示(真实或生成) |
| 输出 | 分子结构数据 | 真伪概率 (0~1) |
| 训练方向 | 最大化判别器的犯错率 | 最小化分类错误 |
| 类比 | 造假币者 | 验钞警察 |
我在调判别器的时候踩过一个坑:判别器收敛得太快,导致生成器梯度消失,学不动了。后来用了标签平滑(label smoothing)和梯度惩罚,才稳住局面。
1.3 对抗训练:两个网络的博弈
训练 GAN 不是单纯地最小化一个损失,而是让两个网络玩一场 极小极大博弈。生成器想让判别器把假样本判成真的,判别器则拼命不犯错。两者交替更新,像在走钢丝。
训练循环的伪代码大致长这样:
for epoch in range(num_epochs):
# ---- 训练判别器 ----
real_data = sample_real_compounds(batch_size)
z = sample_noise(batch_size, latent_dim)
fake_data = generator(z).detach()
d_real = discriminator(real_data)
d_fake = discriminator(fake_data)
d_loss = -(log(d_real) + log(1 - d_fake)).mean()
d_optimizer.zero_grad()
d_loss.backward()
d_optimizer.step()
# ---- 训练生成器 ----
z = sample_noise(batch_size, latent_dim)
fake_data = generator(z)
g_loss = -log(discriminator(fake_data)).mean()
g_optimizer.zero_grad()
g_loss.backward()
g_optimizer.step()
注意判别器训练时用了 .detach(),确保梯度不会回流到生成器。生成器训练时则把判别器当固定评估器,只更新自己的参数。这种交替机制是 GAN 的精髓。
1.4 训练中的挑战与应对
GAN 出了名的难训。我自己的经验是,生成器和判别器的平衡非常微妙。判别器太强,生成器梯度消失;生成器太强,判别器崩溃,整个训练失去方向。
常见的几个问题: