- 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
- 🍦 参考文章:Pytorch实战 | 第P5周:运动鞋识别
- 🍖 原作者:K同学啊|接辅导、项目定制
🍺要求:
- 了解如何设置动态学习率(重点)
- 调整代码使测试集accuracy到达84%。
🍻拔高(可选):
- 保存训练过程中的最佳模型权重
- 调整代码使测试集accuracy到达86%。
🏡 我的环境:
● 语言环境:Python3.8
● 编译器:Pycharm
● 深度学习环境:Pytorch 1.10
● 显卡: RTX 3060
前言:
项目整体框架和之前一样,只是数据集改成了运动鞋。
1.实验记录
1.1 显示图片信息
#%%
import matplotlib.pyplot as plt
# 指定图片大小,图像大小为20宽、5高的绘图(单位为英寸inch)
plt.figure(figsize=(80, 20))
for i, imgs in enumerate(X[:20]):
# 维度缩减X
npimg = imgs.numpy().transpose((1, 2, 0))
# 将整个figure分成2行10列,绘制第i+1个子图。
plt.subplot(2, 10, i+1)
plt.imshow(npimg, cmap=plt.cm.binary)
plt.axis('off')
1.2 模型结构
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.conv1=nn.Sequential(
nn.Conv2d(3, 12, kernel_size=5, padding=0), # 12*220*220
nn.BatchNorm2d(12),
nn.ReLU())
self.conv2=nn.Sequential(
nn.Conv2d(12, 12, kernel_size=5, padding=0), # 12*216*216
nn.BatchNorm2d(12),
nn.ReLU())
self.pool3=nn.Sequential(
nn.MaxPool2d(2)) # 12*108*108
self.conv4=nn.Sequential(
nn.Conv2d(12, 24, kernel_size=5, padding=0), # 24*104*104
nn.BatchNorm2d(24),
nn.ReLU())
self.conv5=nn.Sequential(
nn.Conv2d(24, 24, kernel_size=5, padding=0), # 24*100*100
nn.BatchNorm2d(24),
nn.ReLU())
self.pool6=nn.Sequential(
nn.MaxPool2d(2)) # 24*50*50
self.dropout = nn.Sequential(
nn.Dropout(0.2))
self.fc=nn.Sequential(
nn.Linear(24*50*50, len(classeNames)))
def forward(self, x):
batch_size = x.size(0)
x = self.conv1(x) # 卷积-BN-激活
x = self.conv2(x) # 卷积-BN-激活
x = self.pool3(x) # 池化
x = self.conv4(x) # 卷积-BN-激活
x = self.conv5(x) # 卷积-BN-激活
x = self.pool6(x) # 池化
x = self.dropout(x)
x = x.view(batch_size, -1) # flatten 变成全连接网络需要的输入 (batch, 24*50*50) ==> (batch, -1), -1 此处自动算出的是24*50*50
x = self.fc(x)
return x
1.3 动态学习率
学习率是我们日常调参经常都会用到的参数,手动调整学习率的话费时费力。pytorch为我们封装好了动态学习率调整的方法,其方法在torch.optim.lr_scheduler库中。具体使用方法可以参考官方文档.
下面是代码示例:
>>> optimizer = torch.optim.Adam(...) #选择一种优化器
>>> scheduler = torch.optim.lr_scheduler.... # 选择一种动态调整学习率的方法,可以是下面几种之一
>>> for epoch in range(100):
>>> train(...)
>>> validate(...)
>>> optimizer.step()
>>> scheduler.step() # 需要在优化器参数更新之后再动态调整学习率
1.基于epoch数值:
LambdaLR(optimizer,lr_lambda):将每一个参数组的学习率调整为初始化学习率lr的给定函数倍, fine-tune用
StepLR(optimizer,step_size,gamma):每隔step_size个epoch就对每一参数组的学习率按gamma参数进行一次衰减,比如设置step_size=30,gamma=0.1,lr=0.5,那么
lr = 0.05 if epoch < 30
lr = 0.005 if 30 <= epoch < 60
lr = 0.0005 if 60 <= epoch < 90
…
ExponetialLR(optimizer,gamma):每个epoch都对当前学习率根据gamma作一个动态调整,相当于做以gamma为底,epoch为幂次的指数运算.
MultiStepLR(optimizer,milestones):当epoch的数目增加到一个里程碑(milestones)时,对学习率基于gamma做一个动态调整,其中milestones是一个关于epoch数值的list,表示在达到哪个epoch范围内开始变化
2.其他方法:**
ReduceLROnPlateau(optimizer,mode,last_epoch):基于验证指标的调整法。当指标停止改善时,降低学习率,通常将学习率降低2-10倍。mode=min,代表当度量指标停止下降时,开始减小学习率;当选择max时,代表当度量指标停止上升时,开始减小学习率。
CyclicLR(optimizer,base_lr,max_lr):根据周期性学习率策略(CLR)确定每个参数组的学习率,该策略以恒定的频率在base_lr和max_lr之间循环学习率,base_lr和max_lr之间的距离可以在每次迭代或每个周期的基础上进行缩放。
1.4 训练结果
1.5 指定图片预测
from PIL import Image
classes = list(train_dataset.class_to_idx)
def predict_one_image(image_path, model, transform, classes):
test_img = Image.open(image_path).convert('RGB')
# plt.imshow(test_img) # 展示预测的图片
test_img = transform(test_img)
img = test_img.to(device).unsqueeze(0)
model.eval()
output = model(img)
_,pred = torch.max(output,1)
pred_class = classes[pred]
print(f'预测结果是:{pred_class}')
# 预测训练集中的某张照片
predict_one_image(image_path='./data/5-data/test/adidas/1.jpg',
model=model,
transform=train_transforms,
classes=classes)
2. 模型改进
2.1 改进
学习率设置为 每 10 个epoch衰减到原来的 0.98
#
lr = start_lr * (0.98** (epoch // 10))
使用Adam优化器
optimizer = torch.optim.Adam(model.parameters(), lr=learn_rate)
2.2 调试结果
2.3 保存模型权重和参数
模型保存
模型的本质是一堆用某种结构存储起来的参数,保存有两种方式。一种是直接将模型整个保存下来,然后再加载模型,这样比较消耗内存。另一种则是保存模型的参数,比如weights和bias.本文采用第二种办法。
PATH = './model.pth' # 保存的参数文件名
torch.save(model.state_dict(), PATH)
model.load_state_dict(torch.load(PATH, map_location=device))
2.4 总结
本此详细学习了动态学习率的相关知识,通常采用基于epoch数值的方法。此外,还学习了保存模型和加载模型的方法。