1. GAN 基础概念:生成对抗网络原理与架构

生成对抗网络,说白了就是让两个网络互相“对着干”。一个负责生成,一个负责鉴别。我记得第一次接触这个概念是在 2018 年,当时就觉得——这思路太妙了。造假币的和验钞的不断博弈,最后假币能乱真,验钞的也火眼金睛。你想想看,这不就是最好的学习机制吗?

在药物设计里,我们把“造假币”换成“生成化合物分子”,“验钞”换成“判别分子是否真实”。两个网络在对抗中共同进化,最后生成器能产出高度逼真的新分子。这就是 GAN 的核心魅力。

1.1 生成器:从随机噪声到分子结构

生成器 G 的任务很简单——输入一段随机噪声,输出一个化合物表示。这个表示可以是分子指纹、SMILES 字符串,也可以是 3D 构象的坐标矩阵。你给它一堆随机数,它还你一个看起来像模像样的分子。

我刚开始做生成模型时,总觉得这步像是“无中生有”,不太靠谱。后来才明白,随机噪声只是种子,真正的能力藏在生成器的网络参数里。它通过学习真实化合物的分布,把噪声映射到分子空间。

  • 输入:高斯或均匀分布的随机向量(latent vector)
  • 输出:固定长度的分子表示(如 128 维指纹或 SMILES 序列)
  • 网络结构:常用反卷积层(图像)或 GRU/LSTM(序列),在分子领域多用 MLP + 残差连接
小建议:latent dimension 一般取 64–256。太小了生成多样性不够,太大了训练容易发散。我个人习惯从 128 开始调。

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 的精髓。

避坑提醒:我曾经因为判别器更新次数没调好,导致生成器直接“摆烂”——输出千篇一律的分子。这就是典型的模式崩溃(mode collapse)。后来我改成每更新 1 次生成器就更新 2–3 次判别器,情况才好转。
GAN 基本架构与对抗训练流程 随机噪声 (z) 生成器 (G) 生成样本 G(z) 真实样本 (x) 判别器 (D) 真/假? 损失反馈 生成器骗判别器 判别器防欺骗 对抗中共同进步

1.4 训练中的挑战与应对

GAN 出了名的难训。我自己的经验是,生成器和判别器的平衡非常微妙。判别器太强,生成器梯度消失;生成器太强,判别器崩溃,整个训练失去方向。

常见的几个问题: