1.1 检验模型参数的更新幅度
optimizer.zero_grad()
model_output, pooler_output = model(input_data)
Before = list(model.parameters())[0].clone() # 获取更新前模型的第0层权重
loss = criterion(model_output, label)
loss.backward()
# nn.utils.clip_grad_norm_(model.parameters(), max_norm=20, norm_type=2) # 梯度截断
optimizer.step()
# 检验模型的学习情况
After = list(model.parameters())[0].clone() # 获取更新后模型的第0层权重
predicted_label = torch.argmax(model_output, -1)
acc = accuracy_score(label.float().cpu(), predicted_label.view(-1).float().cpu())
print(loss,acc) # 打印mini-batch的损失值以及准确率
print('模型的第0层更新幅度:',torch.sum(After-Before))
如果:模型更新幅度非常小,其绝对值<0.01, 很可能是梯度消失了; 如果绝对值>1000,很可能是梯度爆炸;
具体阈值需要自行去调节,只是提供了一种思路
1.2 解决
(1)梯度爆炸
梯度爆炸常见原因:使用了深层网络、参数初始化过大,解决方案:
1)更换优化器
2)学习率调低
3)梯度截断
4)使用正则化
(2)梯度消失
梯度消失很有可能是:深层网络、使用了sigmoid激活函数,解决方案:
1)使用Batch Norm 批标准化
BN将网络中每一层的输出标准化为正态分布,并使用缩放和平移参数对标准化之后的数据分布进行调整,可以将集中在梯度饱和区的原始输出拉向线性变化区,增大梯度值,缓解梯度消失问题,并加快网络的学习速度。
2)选用Relu()激活函数
3)使用残差网络ResNet
使用ResNet可以轻松搭建几百层、上千层的网络,而不用担心梯度消失问题.