深度学习-神经网络(下篇)
五、损失函数
作用:衡量模型预测结果与真实值之间的差异,是指导网络参数优化的核心指标。
1. 分类任务损失函数
多分类交叉熵损失 (Cross Entropy Loss)
公式:
L = -Σ y_true * log(y_pred)
y_true
:真实标签的概率分布(通常为one-hot编码)。y_pred
:经过Softmax激活后的预测概率分布。
特点:最小化该损失等价于最大化真实类别的预测概率的对数。
PyTorch实现:
nn.CrossEntropyLoss
(该函数已内置Softmax,输入为网络的原始logits输出,无需手动激活)。criterion = nn.CrossEntropyLoss() loss = criterion(y_pred_logits, y_true_labels) # y_true_labels是整数索引,非one-hot
二分类交叉熵损失 (Binary Cross Entropy Loss)
公式:
L = -[y_true * log(y_pred) + (1 - y_true) * log(1 - y_pred)]
特点:用于二分类问题,输出层使用Sigmoid激活函数。
PyTorch实现:
nn.BCELoss
(输入需为经过Sigmoid后的概率值)。criterion = nn.BCELoss() loss = criterion(y_pred_probs, y_true_labels)
2. 回归任务损失函数
L1损失 (MAE - Mean Absolute Error)
公式:
L = Σ |y_pred - y_true|
特点:对离群点鲁棒,但梯度在零点不平滑,收敛速度可能较慢。
PyTorch实现:
nn.L1Loss
L2损失 (MSE - Mean Squared Error)
公式:
L = Σ (y_pred - y_true)²
特点:计算梯度稳定,但对离群点敏感,易导致梯度爆炸。
PyTorch实现:
nn.MSELoss
Smooth L1损失
公式:在
|x| < 1
时使用平方项(平滑),否则使用绝对值项(稳定)。特点:结合了L1和L2的优点,在零点附近平滑,对离群点不敏感。
PyTorch实现:
nn.SmoothL1Loss
六、网络优化方法
1. 核心概念
梯度下降:核心思想是沿损失函数梯度反方向更新参数,以最小化损失。
W_new = W_old - η * ∇L
(η为学习率)Epoch:使用训练集全部数据进行一次完整训练的次数。
Batch:每次参数更新所使用的小批量样本数。
Iteration:完成一个Batch的训练所需的一次参数更新过程。
关系:
Iteration次数 = (总样本数 / Batch Size) * Epoch数
2. 梯度下降优化算法
动量法 (Momentum)
思想:不仅考虑当前梯度,还引入之前梯度的指数加权平均(惯性) 作为当前更新方向。
公式:
v_t = β * v_{t-1} + (1-β) * ∇L
,W_new = W_old - η * v_t
优点:有助于加速收敛并抑制震荡,有助于跳出局部最小或平坦区。
PyTorch实现:在
torch.optim.SGD
中设置momentum=0.9
。
AdaGrad
思想:为不同参数自适应地调整学习率。累计历史梯度平方和,梯度大的参数学习率减小更快。
缺点:学习率会单调下降至过小,可能导致训练提前终止。
RMSProp
思想:对AdaGrad的改进,使用指数加权移动平均替代累计和,解决学习率过早衰减问题。
PyTorch实现:
torch.optim.RMSprop
Adam (Adaptive Moment Estimation)
思想:结合了Momentum和RMSProp的优点。同时计算梯度的一阶矩(均值)和二阶矩(未中心化的方差)的指数移动平均,并进行偏差校正。
优点:通常收敛快,效果好,是目前最常用的优化算法。
PyTorch实现:
torch.optim.Adam
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3, betas=(0.9, 0.999))
3. 学习率衰减策略
固定学习率可能难以收敛至最优解,动态调整学习率有助于提升性能。
等间隔衰减 (StepLR)
lr = lr * gamma
,每训练step_size
个Epoch衰减一次。torch.optim.lr_scheduler.StepLR(optimizer, step_size=50, gamma=0.5)
指定间隔衰减 (MultiStepLR)
在指定的Epoch点(如
[50, 125, 160]
)进行衰减。torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=[50,125,160], gamma=0.5)
指数衰减 (ExponentialLR)
lr = lr * gamma^epoch
,每个Epoch都按指数规律衰减。torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.95)
七、正则化方法
作用:防止模型过拟合,提高泛化能力。
1. Dropout(随机失活)
原理:在训练阶段,以概率
p
随机将神经元的输出置零, temporarily removing it from the network。未被失活的神经元按1/(1-p)
缩放。效果:每次迭代都在训练一个不同的“子网络”,避免了神经元间的复杂共适应关系,是一种模型平均的近似。
注意:在测试阶段,Dropout不生效,所有神经元都参与计算。
PyTorch实现:
torch.nn.Dropout(p=0.4)
2. 批量归一化 (Batch Normalization, BN层)
原理:对一个Mini-batch的数据在每一层输入进行标准化(减均值、除以标准差),然后进行缩放和平移重构。
y = γ * ((x - μ) / σ) + β
μ, σ
为当前batch的均值和标准差。γ, β
为可学习的参数。
作用:
内部协变量偏移:缓解网络层输入分布随参数变化而剧烈变化的问题。
允许使用更大的学习率,加速训练。
具有一定的正则化效果,可部分替代Dropout。
通常使用位置:卷积层或全连接层之后,激活函数之前。
八、案例-价格分类案例实战
1. 需求与流程分析
任务:根据手机性能数据(RAM等20个特征)预测其价格所属的类别(0,1,2,3共4类)。
流程:
数据准备:读取、划分、转换为TensorDataset和DataLoader。
模型构建:搭建全连接神经网络。
模型训练:定义损失函数、优化器,编写训练循环。
模型评估:在测试集上评估准确率。
调优:调整网络结构、超参数等以提升性能。
2. 核心代码摘要
# 1. 构建模型
class PhonePriceModel(nn.Module):def __init__(self, input_dim, output_dim):super().__init__()self.linear1 = nn.Linear(input_dim, 128)self.linear2 = nn.Linear(128, 256)self.linear3 = nn.Linear(256, output_dim) # output_dim=4self.relu = nn.ReLU()def forward(self, x):x = self.relu(self.linear1(x))x = self.relu(self.linear2(x))x = self.linear3(x) # 输出层不接激活,CrossEntropyLoss自带return x# 2. 训练准备
model = PhonePriceModel(input_dim=20, output_dim=4)
criterion = nn.CrossEntropyLoss() # 交叉熵损失
optimizer = torch.optim.Adam(model.parameters(), lr=1e-4) # 使用Adam优化器
# scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=30, gamma=0.1) # 可选的学习率调度# 3. 训练循环 (核心步骤)
for epoch in range(num_epochs):for batch_x, batch_y in train_dataloader: # 遍历数据optimizer.zero_grad() # 梯度清零output = model(batch_x) # 前向传播loss = criterion(output, batch_y) # 计算损失loss.backward() # 反向传播optimizer.step() # 参数更新# scheduler.step() # 更新学习率# 4. 评估
model.eval() # 设置模型为评估模式(影响Dropout、BN等层)
with torch.no_grad(): # 不计算梯度,加速推理for batch_x, batch_y in test_dataloader:output = model(batch_x)predicted = torch.argmax(output, dim=1) # 取概率最大的类别作为预测结果total_correct += (predicted == batch_y).sum().item()
accuracy = total_correct / len(test_dataset)
print(f'Test Accuracy: {accuracy:.4f}')
3. 模型调优思路
初始准确率不高(~54.75%),可从以下方面优化:
数据层面:进行数据标准化/归一化。
模型结构:增加网络深度或宽度,添加Dropout层或BN层。
优化器:尝试不同的优化器(如AdamW),调整学习率(
lr
)。学习率调度:使用学习率衰减策略。
训练轮次:增加Epoch,并观察验证集损失防止过拟合。
超参数调优:系统调整Batch Size、Dropout率等。
总结:神经网络是一个强大的工具,但其效果依赖于对数据、模型、损失函数、优化器和正则化技术的综合理解和恰当运用。通过理论学习和大量实践,才能熟练掌握如何构建和优化神经网络模型以解决实际问题。