2. 深度学习基础:神经网络原理、激活函数、损失函数、优化器
说实话,刚接触深度学习那会儿,我也觉得这东西挺玄乎的。什么神经元、反向传播,听起来像生物课。但干我们ADMET这行的,说白了就是把模型调明白,让分子性质预测得准。所以我习惯把深度学习拆成四个块来理解:网络怎么搭、激活怎么选、损失怎么算、优化怎么跑。一个一个吃透,后面调批次校正才不会懵。
2.1 神经网络原理:从感知机到多层结构
先看个最简单的场景。你要判断一个化合物是不是有毒性,只看分子量肯定不够。但如果你把十几个分子描述符拼起来,扔进一个线性模型,它学不动非线性关系。这时候就需要神经网络的“层”来帮忙。
一个神经元干的事很简单:输入乘权重,加偏置,过激活函数。
z = w1*x1 + w2*x2 + ... + wn*xn + b
a = activation(z)
单个神经元就是逻辑回归。但一旦堆成多层,它的表达能力就上来了。我刚开始做毒性预测时,用了个三层网络,效果确实比XGBoost好一截。但也不是越深越好,我试过七层,反而过拟合严重,训练集跑得很好,验证集直接崩。这就是ADMET场景里常见的坑——数据量小,网络一深就容易出事。
下面这张图把神经网络的核心流程串起来了。你可以看到数据从输入一路流到输出,中间经过隐藏层,再通过损失函数和优化器完成闭环。
2.2 激活函数:非线性瓶颈
如果网络全是线性变换,那堆多少层都没用。激活函数就是用来打破线性的。常见的就那几种,各有各的脾气。
| 激活函数 | 公式 | 优点 | 缺点 |
|---|---|---|---|
| Sigmoid | σ(z) = 1 / (1 + e-z) | 输出在0~1,适合二分类 | 梯度饱和,容易消失 |
| Tanh | tanh(z) = (ez - e-z) / (ez + e-z) | 零中心,比Sigmoid好点 | 还是梯度饱和 |
| ReLU | f(z) = max(0, z) | 计算快,梯度不饱和 | 神经元可能"死掉" |
| Leaky ReLU | f(z) = max(αz, z) | 解决ReLU死亡问题 | α需要调 |
我自己的经验是:隐藏层无脑用ReLU。我在做批次校正时试过Tanh,训练慢了一倍,效果还没ReLU好。但注意,输出层要根据任务选——二分类用Sigmoid,多分类用Softmax,回归任务就别用激活了,直接线性输出。
2.3 损失函数:告诉模型错在哪
损失函数就是模型犯错的代价。选对了,模型知道往哪优化;选错了,训练半天也是白费功夫。
ADMET场景里最常用的两个损失函数:
- 均方误差(MSE):适合回归任务,比如预测logP、溶解度。公式很简单:
L = (y - ŷ)²,误差大惩罚重。 - 交叉熵损失(Cross-Entropy):适合分类任务,比如预测毒性、致癌性。二分类用BCE(Binary Cross-Entropy),多分类用Categorical Cross-Entropy。
你可能会问,什么时候用MAE(平均绝对误差)而不是MSE?我自己的习惯是:如果数据里有明显离群点,MAE更鲁棒,因为MSE会把离群点的误差平方放大。我拿过一个logP数据集,里面有几个合成出错导致的离群值,用MSE训练那叫一个惨,后来换了MAE才稳住。
# PyTorch 里常见的损失函数用法
import torch.nn as nn
# 回归任务
mse_loss = nn.MSELoss()
mae_loss = nn.L1Loss()
# 二分类
bce_loss = nn.BCEWithLogitsLoss() # 自带Sigmoid,更稳定
# 多分类
ce_loss = nn.CrossEntropyLoss() # 自带Softmax
2.4 优化器:梯度下降的进化史
损失函数告诉我们错在哪,优化器负责怎么修正权重。以前只有SGD(随机梯度下降),但它太慢了,而且容易卡在鞍点。现在主流的是Adam,自适应学习率,基本开箱即用。
| 优化器 | 特点 | 适用场景 |
|---|---|---|
| SGD | 简单,学习率固定 | 数据足够大、训练时间充裕 |
| SGD + Momentum | 加速收敛,缓解震荡 | 比SGD稳,调参经验多 |
| Adam | 自适应学习率,动量+RMSProp结合 | 大部分场景首选 |
| AdamW | Adam + 权重衰减解耦 | 需要正则化时 |
我个人的习惯是:新项目默认用Adam,学习率从0.001开始。跑几个epoch看看loss曲线,如果震荡厉害就降到0.0005,如果太慢就提到0.003。但注意,Adam不是万能的。有一次我做一个图像相关的回归任务,Adam在验证集上一直震荡,换成SGD+Momentum反而稳定了。所以,最终你还是要看数据说话。
# 常用优化器配置
import torch.optim as optim
optimizer = optim.Adam(
model.parameters(),
lr=0.001,
betas=(0.9, 0.999),
weight_decay=1e-5 # 加一点正则化
)
# 如果你需要学习率衰减
scheduler = optim.lr_scheduler.ReduceLROnPlateau(
optimizer,
mode='min',
factor=0.5,
patience=5
)
2.5 知识结构一览
把这一章的内容拉一个表格,方便你记笔记:
| 模块 | 核心要素 | 常用选择 | 常见陷阱 |
|---|---|---|---|
| 神经网络 | 层数、宽度、连接方式 | 2~3个隐藏层,64~128个神经元 | 层数太深=过拟合 |
| 激活函数 | 非线性变换 | 隐藏层用ReLU,输出层看任务 | 输出层用错激活 |
| 损失函数 | 衡量预测误差 | MSE(回归)、BCE(二分类) | 离群点用MSE被放大 |
| 优化器 | 更新权重的策略 | Adam(默认),AdamW(正则) | 学习率设太大loss震荡 |
这一块是深度学习最核心的基础。后面讲批次校正的时候,你会发现所有技巧都绕不开这些概念:网络结构决定容量,激活函数决定非线性表达能力,损失函数定义优化方向,优化器控制收敛效率。把这几样东西吃透,调起参来才能有方向。