写在前面
本文为Pytorch自学实战项目其2和1的后续。1 https://blog.csdn.net/weixin_46479223/article/details/133316914中建立了简单的全连接网络学习yawrate,2https://blog.csdn.net/weixin_46479223/article/details/134054330中将数据集和模型改为rnn的形式,使用历史信息。都做了对应的训练和验证。
本节是针对rnn网络来调节超参数以及优化网络结构来获取更好的学习估计结果。
更新
- 12月13日:当前效果总结推理模型效果以及两个大问题修改:BN换LN;特征选取不当
- 12月10日:修改一个错误,改BN层为LN层
1129: 第一次初稿
1130:修改了第一次出现的bug(BN层维度问题),下一次更新超参数调整
12月7日: 关于超参数的调整(Tensoroard可视化和Hyperopt的使用)新开了3.1,更新在https://blog.csdn.net/weixin_46479223/article/details/134792680中
12月8日:新开了3.2 把3.1的做法运用到本模型实际调参中
Outline
- 增加模型复杂度,移动到GPU
- 超参数调整方法,超参数相关笔记
- hyperopt && tensorboard&&加入 Earlystop Flag可视化
- tensorRT
使用GPU
之前一直在cpu上搞,为了学习BEV,618整了块显卡,现在使用显卡训练。显卡驱动安装,cuda按照,pytorch安装均可见https://blog.csdn.net/h904798869/article/details/131719404
分别验证cuda工具包版本,显卡驱动情况(注意这显示的是可使用的最高版本的cuda而不是你安装好的),和torch版本。conda是因为我在使用anaconda虚拟环境
nvcc-V
nvidia-smi
conda list | grep torch
使用
import torch
print('CUDA 可用:', torch.cuda.is_available())
if torch.cuda.is_available():
print('可用的 CUDA 设备数:', torch.cuda.device_count())
print('当前 CUDA 设备索引:', torch.cuda.current_device())
print('当前 CUDA 设备名称:', torch.cuda.get_device_name(torch.cuda.current_device()))
else:
print('CUDA 不可用')
print(torch.__version__, torch.cuda.is_available())
# Pytorch 实际使用的运行时的 cuda 目录
import torch.utils.cpp_extension
print(torch.utils.cpp_extension.CUDA_HOME)
我这段代码也可以作出如下验证
开始调整超参数
首先这里,根据书《深度学习入门》的第6章开始一节一节尝试优化方法
同时 这篇文章里表达的很好,调参数主要是过拟合和找最优之间的对抗
参数的更新&& 权重初始值
其实在1、2节中已经尝试过,具体不同梯度下降的处理方式按照上图中的目录可以自行搜索。
- 1中 https://blog.csdn.net/weixin_46479223/article/details/133316914使用了均方差损失函数 使用了SGD随机梯度下降 和动态学习率 (StepLR(optimizer, step_size=100, gamma=0.9) # 设置学习率每x个 epoch 减小为原来的0.9)加入权重初始化代码(使用xavier_uniform_)
- 2中 https://blog.csdn.net/weixin_46479223/article/details/134054330使用了Adam参数更新方法。初始化调整为normal_,其他特性和1中一样
以下为本次对RNN网络结构的更新后的结构,具体修改解释见代码后的文章
成功跑起来版20231130 修改了batch的变形方法,我在对BN层用法的研究记录在了https://blog.csdn.net/weixin_46479223/article/details/134721806中
class MyRNN(nn.Module):
def __init__(self):
super().__init__()
self.linear_in = nn.Linear(9,32)
self.relu = nn.ReLU()
self.linear_32=nn.Linear(32,32)
self.rnn = nn.RNN(input_size=32, hidden_size=32, num_layers=1, batch_first=True)
self.linear_out=nn.Linear(32,7)
# 创建 Batch Normalization 层
self.batch_norm_layer = nn.BatchNorm1d(num_features=32)
self.dropout = nn.Dropout(p=0.5) # 添加 Dropout 层,丢弃率0.5
for name, param in self.named_parameters():
if 'weight' in name:
nn.init.normal_(param, mean=0.0, std=0.01)
elif 'bias' in name:
nn.init.constant_(param, 0)
def forward(self, x,hidden_prev):
batch_size,sequence_length,num_features=x.shape
temp1=self.linear_in(x)# temp1 (16,5,32)
#temp1 = temp1.unsqueeze(2) # 增加一个维度,变成 (batch_size, sequence_length, 1, input_size)
temp1 = temp1.view(-1, 32) # 将形状从 (batch_size, sequence_length, num_features) 改为 (batch_size*sequence_length, num_features)
temp11 = self.batch_norm_layer(temp1)
temp11 = temp11.view(batch_size,sequence_length, 32) # 再次变换形状回到原来的状态
#temp1 = temp11.squeeze(2) # 移除添加的维度
temp2=self.relu (temp11)
temp3=self.linear_32(temp2)# temp3 (16,5,32)
out, hidden_prev = self.rnn(temp3,hidden_prev)# out (16,5,32) #hidden(1,16,32)
# Get output from the last time step
last_output = out[:, -1, :]#last_output(16,32)
last_output = last_output.unsqueeze(1)# let (16,32)to(16,1,32)
# Feed into linear layer and apply activation
temp4 = self.linear_32(last_output)#temp4 (16,1,32)
#temp4 = temp4.unsqueeze(2)
temp4 = temp4.view(-1, 32)
temp41 = self.batch_norm_layer(temp4)
temp4 = temp41.view(batch_size,1, 32)
#temp4 = temp41.squeeze(2)
temp5 = self.relu(temp41)#temp5(16,1,32)
# 应用 Dropout 层
temp5 = self.dropout(temp5)
output =self.linear_out(temp5)#output(16,1,7)
return output,hidden_prev
batch normalization &&增加网络结构复杂度
这里我对2中的RNN 类作出两处修改
- 加入对数据分布进行正规化的层batch_norm_layer
- 增加全连接网络层数让网络学习到更复杂的结果。
关于细节这篇文章讲的很好,以及有关于数据特征的缩放处理
BatchNormalization
特征缩放
以下附上书中的解释,我理解这个还是对同一个特征 在批次维度上正规化,而不是同一个样本不同特征之间的样本标准化
同时,这个层带有可学习参数,要注意使用model.train() 和eval()改变其学习计算的方式。
扩展 gpt对batch normalization的解释
(更多可以见https://blog.csdn.net/weixin_46479223/article/details/132784268)
Batch Normalization(批归一化)是一种用于加速深度神经网络训练过程、提高模型性能的技术。它在神经网络的每一层对输入进行归一化,使得每个特征的均值接近0,标准差接近1。这一操作通常在激活函数之前进行。
以下是Batch Normalization的一些关键思想和操作步骤:
思想:
在神经网络中,每一层的输入分布可能会随着训练的进行而发生变化,这被称为“Internal Covariate Shift”问题。Batch Normalization的目标是通过标准化输入,减少这种分布变化,从而加速训练。
操作步骤:
对于每个mini-batch(一小批样本),计算该批次中每个特征的均值和标准差。 # 我这里目前是16一批
使用批次的均值和标准差对批次中的每个样本进行归一化,得到零均值和单位方差的样本。# 归一、L1、L2正则、标准化是不同的概念,归一还有批和层归一的区别
引入可学习的参数(缩放和平移)进行线性变换,使得网络可以恢复其表达能力。
在激活函数之前应用上述操作,确保输出的每个特征都被标准化。
Batch Normalization的优势包括:
加速收敛: 由于输入被标准化,神经网络更容易学到适当的权重,因此收敛速度更快。
降低对权重初始化的敏感性: Batch Normalization减少了对权重初始化的依赖,允许使用更大的学习率。
正则化效果: 类似于Dropout,Batch Normalization在一定程度上有正则化效果,可以减轻过拟合问题。
在实际应用中,Batch Normalization已经成为深度学习中的标配技术,被广泛应用于各种类型的神经网络。
正则化
在我2的结果中,发现已经出现了训练集准确度大于测试集合的效果,即过拟合。
书中提到权值衰减、L1 L2 范式(针对输出,BN是),但我这里不展开,可以根据书中提纲自行开展搜索,我这里使用dropout。
#init
self.dropout = nn.Dropout(p=0.5)
#forward
temp5 = self.dropout(temp5)
扩展 gpt总结应对过拟合的方式
更多的数据: 提供更多的训练数据是减轻过拟合的有效方法。更多的数据有助于模型学到更一般的模式,从而提高在未见过的数据上的泛化能力。
数据增强: 对训练数据进行增强,通过对图像进行随机旋转、翻转、缩放等操作,可以生成更多样本,有助于模型更好地学习数据的不变性。
简化模型: 减少模型的复杂度,可以通过减少网络的层数、每层的神经元数目等方式来降低模型的容量,从而减少过拟合的风险。
正则化:
L1和L2正则化: 在损失函数中加入L1或L2正则化项,限制权重的大小,防止模型学习过于复杂的特征。
Dropout: 在训练过程中随机丢弃一部分神经元,防止神经元之间建立过于强烈的依赖关系,有助于泛化。
交叉验证: 使用交叉验证来评估模型的性能,确保模型在不同的数据划分上都有良好的表现,而不是只依赖于单一的训练-验证划分。
集成方法: 使用集成学习方法,如bagging和boosting,可以降低过拟合的风险。
早停: 监控模型在验证集上的性能,当性能不再提升时停止训练,以防止过拟合。
特征选择: 仔细选择与任务相关的特征,避免使用过多无关或冗余的特征。
对抗训练: 引入对抗样本训练,使模型对输入的微小扰动具有更好的鲁棒性。
注意力机制: 使用注意力机制帮助模型集中注意力于关键的部分,减少对噪声的过度关注。
超参数的调整作为本文下一次大更新
附上 GPT 所回答的超参数的调整项总结
学习率(Learning Rate):
影响: 学习率决定了权重更新的步长,过大的学习率可能导致不稳定的训练,而过小的学习率可能导致训练速度过慢。
调整方法: 使用学习率调度(learning rate schedule)、自适应学习率算法(如Adam、Adagrad)或者手动调整学习率。
权重衰减(Weight Decay):
影响: 控制正则化项的大小,有助于防止过拟合。
调整方法: 尝试不同的权重衰减系数,通常通过交叉验证或验证集的性能来选择最佳值。
批量大小(Batch Size):
影响: 影响训练的速度和稳定性,较大的批量大小通常会提高训练速度,但也可能导致内存不足。
调整方法: 通常通过实验来选择适当的批量大小,可以尝试不同的批量大小并监视性能。
迭代次数(Epochs):
影响: 控制整个训练数据集被遍历的次数。
调整方法: 通过观察模型在验证集上的性能,选择适当的迭代次数,过多的迭代可能导致过拟合。
隐藏层神经元数量和层数:
影响: 影响模型的容量和复杂性。
调整方法: 通过交叉验证或验证集性能选择合适的神经元数量和层数。
激活函数(Activation Function):
影响: 不同的激活函数对梯度传播和模型的表达能力有影响。
调整方法: 选择适合任务的激活函数,ReLU是常用的激活函数,但在某些情况下,tanh或sigmoid也可能更合适。
初始化方法(Weight Initialization):
影响: 初始权重的选择可能影响模型的训练速度和性能。
调整方法: 使用合适的初始化方法,如Xavier/Glorot初始化,或者使用预训练模型的权重。
优化器(Optimizer):
影响: 不同的优化算法可能导致不同的训练速度和性能。
调整方法: 尝试不同的优化算法,如Adam、SGD等,并调整其超参数。
Dropout率:
影响: Dropout可以减少过拟合。
调整方法: 尝试不同的Dropout率,通常在0.2到0.5之间,通过验证集性能选择最佳值。
学习率衰减和调度:
影响: 在训练的不同阶段使用不同的学习率,有助于稳定训练。
调整方法: 使用学习率衰减策略,如按指数衰减、按阶梯衰减等。
梯度裁剪(Gradient Clipping):
影响: 防止梯度爆炸问题。
调整方法: 设置梯度裁剪的阈值,通常在1.0附近,以确保梯度的大小在可控范围内。