pytorch 实现学习率设置 观察数据具体调整

摘要

学习率的设置也是训练好模型的关键点之一,所以需要掌握常用的学习率的设置,一种是使用自带函数,另一种是自己设置每个阶段的学习率作为调整,

模型保存方式

在学习率调整的时候你是没有办法直接感觉多少epoch能训练出来,所以保存模型的时候最好是可以继续训练的形式,例如我在训练102分类的时候acc达到93的时候基本很难再增进了这时候就要在考虑一下学习率的设置,开始的时候全程0.001,所以这时候将学习率改为0.0001会有更好的效果。所以保存可以中断训练继续的保存很重要

net = resnet50.Resnet().cuda()
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(net.parameters(),lr=0.001)
checkpoint = torch.load(PATH)
net.load_state_dict(checkpoint['model_state_dict'])
optimizer.load_state_dict(checkpoint['optimizer_state_dict'])
epoch = checkpoint['epoch']
loss = checkpoint['loss']

#这部分是加载,只有训练一次之后才有的模型可以这样加载,对应保存部分


  torch.save({'epoch':epoch,
                    'model_state_dict': net.state_dict(),
                       'optimizer_state_dict': optimizer.state_dict(),
                    'loss': loss
        },PATH)
 #这部分代码写在每个训练当中进行保存,

自带函数调整

import torch
import torch.optim as optim
from torch.optim import lr_scheduler
from torchvision.models import AlexNet
import matplotlib.pyplot as plt

model = AlexNet(num_classes=2)
optimizer = optim.SGD(params=model.parameters(), lr=0.05)

# lr_scheduler.StepLR()
# Assuming optimizer uses lr = 0.05 for all groups
# lr = 0.05     if epoch < 30
# lr = 0.005    if 30 <= epoch < 60
# lr = 0.0005   if 60 <= epoch < 90

scheduler = lr_scheduler.StepLR(optimizer, step_size=30, gamma=0.1)
plt.figure()
x = list(range(100))
y = []
for epoch in range(100):
    scheduler.step()
    lr = scheduler.get_lr()
    print(epoch, scheduler.get_lr()[0])
    y.append(scheduler.get_lr()[0])

plt.plot(x, y)
plt.show()

在这里插入图片描述
函数的重点使用注意二个点就可以,step_size的设置就是每个多少个epoch变动一次,变动的大小幅度是乘gamma。在使用自带的学习率规则调整只需要在训练的批次当中加上lrScheduler.step()进行调成即可,具体如下

lrScheduler = optim.lr_scheduler.StepLR(optimizer, step_size=1, gamma=0.95)
 for epoch in range(pre_epoch, EPOCH):
 	for i, data in enumerate(trainloader):
	...
    lrScheduler.step()
    ...	
 	

自定义学习率

train_cfg = dict(
    warmup=5,
    lr=[0.004, 0.002, 0.0004, 0.00004, 0.000004],
    step_lr=dict(
        COCO=[90, 110, 130, 150, 160],
    ),
)


def adjust_learning_rate(optimizer, epoch, train_cfg):
    global lr

    # 在warmup 训练期间,学习率先行增大到初始学习率lr[0] = 0.04
    if epoch <= train_cfg.warmup:
        lr = 0.004*epoch*2

    # 在warmup 之后,学习率按照设置的lr进行衰减,也可以自行设置指数衰减的形式
    else:
        for i in range(len(train_cfg.step_lr.COCO)):
            if train_cfg.step_lr.COCO[i] >= epoch:
                lr = train_cfg.lr[i]
                break
        # lr = train_cfg.init_lr * (gamma ** (step_index))
    for param_group in optimizer.param_groups:
        param_group['lr'] = lr

在训练模型中一个比较好的点就是学习率预热,先从小的学习率开始慢慢增大,训练数据更加平稳,具体使用如下

optimizer = optim.Adam(net.parameters(),lr=0.004)

 for epoch in range(pre_epoch, EPOCH):
 	for i, data in enumerate(trainloader):
	...
     adjust_learning_rate(optimizer,epoch,train_cfg)
    ...	
 	

总结

学习率的变化最好是结合训练情况及时调整,整体流程就是开始学习率预热,中间调整lr最大为0.05左右,到acc提升到末尾的时候,可以将lr在设置到0.00005左右的大小。

其他重要细节点

在训练的时候有几个比较重要的点,就是训练集分为训练集和验证集的时候,最好是保持数据的类别比例分开,将训练集和验证集分为9:1的比例比较协调,在其中要保证每个类别的比例基本没有太大变化。比如猫狗比例3:7,那么验证集的提取比例也应为3:7。
预训练权重也是可以极大的加快训练速度,大部分数据集都可以使用预训练权重。使用预训练权重有个最要要的细节是transform.normalize的使用

针对预训练权重初始化训练

大部分的网络预训练都是在1000分类的图像训练,所以transforms.Normalize的设置是不同的,这种归一化可以使得数据更加稳定,训练的效果更好,使得自己的数据集均值和标准差符合imagenet的分布,是预训练权重效果完全展现,所以,只要使用了预训练权重就要设置transforms.Normalize

if 'coco' in args.dataset:
  mean_vals = [0.471, 0.448, 0.408]
  std_vals = [0.234, 0.239, 0.242]
elif 'imagenet' in args.dataset:
  mean_vals = [0.485, 0.456, 0.406]
  std_vals = [0.229, 0.224, 0.225]
  

对不同的预训练过的模型设置值,在没有预训练权重的时候需要自己去计算mean和std的值,代码如下

import torchvision.transforms as transforms
import torch.nn as nn
import numpy as np
import pandas as pd
import torch.optim as optim
from torch.utils.data.sampler import SubsetRandomSampler
from efficientnet_pytorch import EfficientNet
from PIL import Image
from tqdm import tqdm
import torch.nn.functional as F
import torch
import random
from torch.autograd import Variable
from torch.utils.data import Dataset, DataLoader
train_df = pd.read_csv('./54_data/train.csv')
train_df['filename'] = train_df['filename'].apply(lambda x: './54_data/train/{0}'.format(x))
class MyDataset(Dataset):
    def __init__(self, df, transform):
        self.df = df
        self.transform = transform

    def __getitem__(self, index):
        img = Image.open(self.df['filename'].iloc[index]).convert('RGB')
        img = self.transform(img)
        return img, torch.from_numpy(np.array(self.df['label'].iloc[index]))

    def __len__(self):
        return len(self.df)
train_transform = transforms.Compose([
    transforms.Resize([224, 224]),
    transforms.ToTensor(),
])
train_data = MyDataset(train_df, train_transform)
dataloader = DataLoader(train_data, batch_size=10, shuffle=True)
mean = torch.zeros(3)
std = torch.zeros(3)
print('==> Computing mean and std..')
for inputs, targets in dataloader:
    for i in range(3):
        # print(inputs)
        mean[i] += inputs[:, i, :, :].mean()
        std[i] += inputs[:, i, :, :].std()
mean.div_(len(dataloader))

std.div_(len(dataloader))
print(mean)
print(std)

计算出来之后再去设置自己的mean和std的值,具体如下

   tf = transforms.Compose([
            lambda x: Image.open(x).convert('RGB'),  # string path= > image data
            transforms.Resize((int(self.resize * 1.25), int(self.resize * 1.25))),
            transforms.RandomRotation(15),
            transforms.CenterCrop(self.resize),
            transforms.ToTensor(),
            transforms.Normalize(mean=[0.436424, 0.433079, 0.330037],
                                 std=[0.252266, 0.247213, 0.250690])
        ])

效果图

在这里插入图片描述
这是102类别的分类,数据集5735张用efficientnet-b0的效果,用上归一化效果和速度方面直接暴涨,测试集基本也在96-97左右,基本已经达到最大训练效果了。

原创文章 25 获赞 35 访问量 5189

猜你喜欢

转载自blog.csdn.net/cp1314971/article/details/105654684