深度学习基础回顾:神经网络、激活函数、损失函数、优化器

说实话,很多同学一上来就追着分布式训练跑,结果连单卡模型都调不稳。我记得当年做分子生成项目时,模型死活不收敛,折腾了两天,最后发现是激活函数选错了——这玩意儿看着不起眼,坑起来真要命。

所以这一章,咱们把老本行踏实捋一遍。重点不是堆公式,是我踩过的雷和实战中用得顺手的招式。

神经网络:从单层到深度

神经网络本质就是个多层复合函数。输入是分子描述符、原子坐标、键长这些特征,经过一层层线性变换+非线性激活,最后输出分子的属性或生成新的分子。

一个全连接层的基本操作:

z = W * x + b
a = activation(z)

我自己的习惯是,写代码前先把维度算清楚,画个表格贴显示器上。尤其是分布式场景里,各卡的输入张量切分方式一乱,整个loss直接飞掉。

层类型输入形状输出形状参数量
全连接(batch, 128)(batch, 256)128×256 + 256
卷积1D(batch, 50, 32)(batch, 48, 64)kernel_size×32×64 + 64
图卷积节点特征 (N, F)(N, F')邻接矩阵相关

你想想看,如果batch size是1024,张量在GPU间切分时,每个rank只拿到256条样本,但是全连接层的权重矩阵在所有卡上是一样的。这就是分布式训练的基础——数据并行。我个人建议先用单卡把小模型跑通,再拆成多卡,否则问题定位会非常痛苦。

激活函数:非线性是关键

没有激活函数,多少层都等于一层线性变换。分子生成里常用的就那几个,但选错一个,梯度就炸了。

  • ReLU:最简单,梯度1或0。缺点是死神经元——我一台卡上曾经80%的ReLU单元全死了,loss死活降不下去,排查半天才发现初始化有问题。
  • Leaky ReLU / PReLU:给负数一点小斜率,避免死亡。我个人习惯在分子编码器里用Leaky ReLU,斜率0.01就够。
  • GELU:Transformer和扩散模型标配。分子生成里的注意力模块,我推荐用GELU,效果确实比ReLU稳一截。
  • Sigmoid / Tanh:输出范围有限,常用于门控或分子二分类任务。但小心梯度饱和——我曾在一个深度生成网络上用了Tanh,结果深层梯度几乎为零,白训三天。

我的避坑指南:遇到loss震荡或梯度消失,先检查激活函数的选择。如果网络超过20层,尽量用GELU或Swish,ReLU配上batch norm也能救,但别省。

# 我在分子生成项目中常用的激活函数配置
import torch.nn as nn

class MolEncoder(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(256, 512)
        self.act = nn.GELU()
        self.fc2 = nn.Linear(512, 256)

    def forward(self, x):
        x = self.act(self.fc1(x))
        x = self.fc2(x)
        return x

损失函数:分子生成场景怎么选

损失函数直接决定了模型学什么方向。分子生成不是单纯的分类或回归,往往要组合多个loss。

任务类型常用损失原因
分子性质预测MSE / MAE数值回归,简单直接
分子图生成交叉熵 + 重建损失离散原子类型、键型
分子构象生成扩散噪声损失 (L2 on epsilon)符合高斯扩散假设
分子对接评分对比损失 (InfoNCE)区分正负分子对

我记得一个很典型的坑:做分子变分自编码器时,KL散度项权重调太大,模型直接坍缩到先验分布,生成出来的分子全是甲烷。你想想看,调了两周,结果每张卡都给同一坨东西。后来我把KL权重从1.0降到0.001,配合beta-VAE的渐进式增加,才算稳住。

注意:多卡训练时,各个rank的loss计算必须同步。如果你在每张卡上单独算loss然后平均,别忘了把loss scale也对齐。我遇到过batch size变大导致loss变小,但其实模型根本没学好的情况——因为lr没跟着调。

优化器:SGD、Adam、LAMB怎么选

优化器这东西,说白了就是下山的路怎么走。单卡时我无脑AdamW,但多卡分布式下,AdamW的通信量其实不小——它要同步一阶动量和二阶动量。

  • SGD + Momentum:经典,但收敛慢。现在大规模分子预训练很少用了。
  • Adam / AdamW:自适应学习率,效果好,我90%的项目用这个。不过注意,weight decay在AdamW里要同时作用在梯度上,别用成Adam。
  • LAMB:专门为大规模分布式训练设计的,能支持几万的batch size。我用它训过分子构象模型,单卡batch 32,32卡batch 1024,收敛速度和单卡几乎一致。夸张吧?
  • Adafactor:内存省一半,适合分子大模型。如果你的显存快满了,可以试试。
# 我常用的分布式优化器配置示例
from torch.optim import AdamW
from torch.optim.lr_scheduler import CosineAnnealingLR

optimizer = AdamW(model.parameters(), lr=1e-4, weight_decay=1e-2)
scheduler = CosineAnnealingLR(optimizer, T_max=100)

# 分布式场景下,最好用DistributedSampler + 按global_batch调整lr
lr = base_lr * (global_batch_size / 256)

核心原则:优化器选定了就别经常换。我自己的经验是,先把AdamW跑一个基准,再试试LAMB看能不能加速。不要一开始就搞花活,容易翻车。

本章知识图谱

深度学习基础回顾 · 知识结构 深度学习基础 神经网络结构 激活函数 损失函数 优化器 全连接/卷积/图 分子编码器结构 MSE / 交叉熵 KL散度 / 对比 ReLU / GELU Leaky / Swish AdamW LAMB 这四个部分在分布式训练中都需要重新检查:通信量、初始化、同步方式

小结

深度学习基础这部分,说白了就是搭积木。神经网络是骨架,激活函数给非线性,损失函数定方向,优化器让模型真正动起来。我这两年带项目发现,70%的训练崩溃都出在这四个基础模块的搭配上——选对了就顺,选错了就卡。

下一阶段咱们就要把这些基础模块扔到多卡环境里跑,到时候我会给你讲分布式数据并行、梯度同步、batch size和lr的联动策略。嗯,先把这章消化了,后面上多卡才不慌。