CNN模型如下:
self.model1 = nn.Sequential(
nn.Conv1d(in_channels=6, out_channels=8, kernel_size=3, stride=1, padding=1),
nn.Tanh(),
# nn.MaxPool1d(2), # torch.Size([128, 16, 5])
nn.Conv1d(in_channels=8, out_channels=16, kernel_size=3, stride=1, padding=1),
nn.Tanh(),
# nn.MaxPool1d(2), # torch.Size([128, 32, 1])
nn.Flatten(), # torch.Size([128, 32])
)
LSTM模型如下
self.lstm = nn.LSTM(
input_size=16,
hidden_size=32, # RNN隐藏神经元个数
num_layers=2, # RNN隐藏层个数
batch_first=True
)
self.out = nn.Linear(32, 1)
训练时主要要关注的参数是卷积网络层数,卷积网络输入数据维数,输出数据维数,LSTM层相关参数。
其中损失函数选择了cnn和lstm模型最常用的Tanh(双曲正切函数),
起初遇到了模型未收敛的问题,如下所示
模型未收敛的主要原因如下:
学习率设置不合理,优化算法设置不合理,出现了过拟合问题,训练批次设置问题等等。
对于学习率的设置通常可以有如下几个策略
1、使用固定学习率
即根据在测试集上的结果来固定的选择学习率。
但是这样就会出现一些较为明显的缺陷,首先就是可能会出现收敛速度慢,过拟合等现象。
比如当前模型lr设定为0.00005,训练轮次设置为1000时,在测试集上的效果会很好,如下所示
然而当训练轮次降低到100的时候,模型精度就会显著下降,也就是模型未收敛
2、学习率衰减策略,固定多少个epoch后降低一定比例的学习率
使用这种方法可以实现在收敛速度快的情况下也能在测试集上有着很好的表现
但是模型经过多次测试发现其在测试集上的准确率并不稳定,可能会出现下面情况
对于模型不稳定的情况经过了解可能是模型过拟合的问题,于是尝试采用早停技术
import numpy as np
import torch
class EarlyStopping:
def __init__(self, patience=7, verbose=False, delta=0.001, path='checkpoint.pth'):
"""
Args:
patience (int): How long to wait after last time validation loss improved.
verbose (bool): If True, prints a message for each validation loss improvement.
delta (float): Minimum change in the monitored quantity to qualify as an improvement.
path (str): Path for the checkpoint to be saved to.
"""
self.patience = patience
self.verbose = verbose
self.counter = 0
self.best_score = None
self.early_stop = False
self.val_loss_min = np.Inf
self.delta = delta
self.path = path
def __call__(self, val_loss, model):
score = -val_loss # 使用负值,因为我们希望损失值越低越好
if self.best_score is None:
self.best_score = score
self.save_checkpoint(val_loss, model)
elif score < self.best_score - self.delta:
self.counter += 1
print(f'EarlyStopping counter: {self.counter} out of {self.patience}')
if self.counter >= self.patience:
self.early_stop = True
else:
self.counter = 0
self.best_score = score
self.save_checkpoint(val_loss, model)
def save_checkpoint(self, val_loss, model):
'''Saves model when validation loss decrease.'''
if self.verbose:
print(f'Validation loss decreased ({self.val_loss_min:.6f} --> {val_loss:.6f}). Saving model ...')
torch.save({
'epoch': epoch,
'model_state_dict': model.state_dict(),
'val_loss': val_loss,
}, self.path)
self.val_loss_min = val_loss
# 假设你已经有了训练循环的其它部分,你可以在验证步骤后调用早停对象
early_stopping = EarlyStopping(patience=7, verbose=True)
for epoch in range(num_epochs):
# ... 训练循环 ...
val_loss = ... # 计算验证损失
early_stopping(val_loss, model)
if early_stopping.early_stop:
print("Early stopping")
break
# 如果模型因为早停而提前结束训练,可以加载保存的最佳模型
if early_stopping.early_stop:
model = torch.load(early_stopping.path)
结果有了较大的改善,并且模型较为稳定,收敛速度快,但是仍有小概率出现准确率低的情况
3、周期性学习率
CosineAnnealingLR 是PyTorch自带的一种学习率调度器,它使用余弦退火策略来调整学习率。在每个训练周期(epoch)中,学习率会根据余弦函数进行周期性变化。
可以看到当前周期性学习率取得的效果并不是很优秀
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=epochs, eta_min=min_lr)
并且随着训练轮次的提高有着准确率降低的趋势,这时就需要采用一些策略来防止过拟合,如采用修改Dropout比率来实现
self.lstm = nn.LSTM(
input_size=16,
hidden_size=32, # RNN隐藏神经元个数
num_layers=2, # RNN隐藏层个数
batch_first=True,
dropout=0.1
)
再次运行模型可以发现模型也得到了一定的改善
综上考虑针对cnn-lstm模型,最稳定并且正确率最高的模型是采用如1所示的固定学习率,如果想要快速收敛并且较为稳定的模型可采用2中学习率衰减策略并且采用早停技术进行实现。
除了对学习率和学习轮次的优化也可以从模型自身来改动,在训练的过程中也有可能会出现过拟合的问题。例如当训练轮次为100的时候效果较好,当时当挑高训练轮次到1000时,效果却变差了,这就是所谓的过拟合。对于此类过拟合也可以通过设置模型参数drop来丢弃部分神经元输出。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。