在机器学习模型训练过程中,准确率(acc)曲线的波动和增长模式受多种因素影响。
在机器学习模型训练过程中,准确率(acc)曲线的波动和增长模式受多种因素影响。
1. 准确率波动(增减交替)的原因
学习率过高
- 现象:参数更新步长过大,导致模型在最优解附近震荡,无法稳定收敛。
- 解决方案:降低学习率或使用学习率调度器动态调整。
数据分布不均
- 现象:训练数据中正负样本的随机性可能导致批次间分布波动,影响梯度方向。
- 解决方案:增加批次大小或使用更稳定的优化器(如 RMSprop、Adam)。
模型容量不足
- 现象:简单的线性模型可能无法完全捕捉复杂模式,导致训练不稳定。
- 解决方案:增加模型复杂度(如添加隐藏层)或引入非线性激活函数。
2. 先快速提升后缓慢增长的原因
梯度消失 / 爆炸
- 现象:Sigmoid 激活函数在输入值较大或较小时梯度趋近于 0,导致训练后期更新缓慢。
- 解决方案:改用 ReLU 等更适合深度网络的激活函数。
优化算法特性
- 现象:Adam 等自适应优化器在初期快速收敛,但后期可能因学习率衰减而停滞。
- 解决方案:尝试 SGD + 动量或调整优化器参数(如
betas)。
过拟合
- 现象:模型在训练集上表现越来越好,但泛化能力下降。
- 解决方案:添加正则化(如 L2 正则化、Dropout)或提前停止训练。
3. 优化建议
以下是优化代码的具体实现:
python
运行
import torch
import torch.nn as nn
import numpy as np
from matplotlib import pyplot as plt
from torch.optim.lr_scheduler import StepLR
class ImprovedModel(nn.Module):
def __init__(self, input_size):
super(ImprovedModel, self).__init__()
# 增加模型复杂度,使用多层网络
self.layer1 = nn.Linear(input_size, 10)
self.layer2 = nn.Linear(10, 1)
self.activation = nn.ReLU() # 改用ReLU激活函数
self.output_act = nn.Sigmoid() # 输出层用Sigmoid保持二分类特性
self.loss = nn.BCELoss() # 改用更适合二分类的交叉熵损失
def forward(self, x, y=None):
x = self.activation(self.layer1(x))
y_pred = self.output_act(self.layer2(x))
if y is not None:
return self.loss(y_pred, y)
else:
return y_pred
def main():
# 配置参数
epoch_num = 100
batch_size = 64 # 增大批次大小提高稳定性
train_sample = 4000
input_size = 5
learning_rate = 0.005 # 适当提高初始学习率
# 建立改进模型
model = ImprovedModel(input_size)
optim = torch.optim.Adam(model.parameters(), lr=learning_rate, weight_decay=1e-5) # 添加L2正则化
scheduler = StepLR(optim, step_size=20, gamma=0.5) # 学习率调度器,每20轮衰减一半
log = []
train_x, train_y = build_dataset(train_sample)
for epoch in range(epoch_num):
model.train()
watch_loss = []
for batch_index in range(train_sample // batch_size):
x = train_x[batch_index * batch_size : (batch_index + 1) * batch_size]
y = train_y[batch_index * batch_size : (batch_index + 1) * batch_size]
loss = model(x, y)
loss.backward()
optim.step()
optim.zero_grad()
watch_loss.append(loss.item())
print("=========\n第%d轮平均loss:%f" % (epoch + 1, np.mean(watch_loss)))
acc = evaluate(model)
log.append([acc, float(np.mean(watch_loss))]
