金融投资公司网站建设论文,做我女朋友的表白句的网站,深圳百度竞价托管公司,wordpress 什么值得买 主题1 数据增强
在目前分类效果最好的EficientNet系列模型中#xff0c;EfficientNet-B7版本的模型就是使用随机数据增强方法训练而成的。
RandAugment方法也是目前主流的数据增强方法#xff0c;用RandAugment方法进行训练#xff0c;会使模型的精度得到提升。 2 RandAugment… 1 数据增强
在目前分类效果最好的EficientNet系列模型中EfficientNet-B7版本的模型就是使用随机数据增强方法训练而成的。
RandAugment方法也是目前主流的数据增强方法用RandAugment方法进行训练会使模型的精度得到提升。 2 RandAugment
2.1 RandAugment方法简介
RandAugment方法是一种新的数据增强方法它比自动数据增强AutOAugment方法更简单、更好用。它可以在原有的训练框架中直接对AutoAugment方法进行替换。
2.1.1 Tip
AuoAugment方法包含30多个参数可以对图片数据进行各种变换参见arXiv网站上编号为1805.09501的论文)。
2.2 RandAugment方法的构成
RandAugment方法是在AutoAugment方法的基础之上将30多个参数进行策略级的优化管理使这30多个参数被简化成两个参数图片的N次变换和每次变换的强度M。其中每次变换的强度M取值为010只取整数)表示使原有图片增强失真的大小。
RandAugment方法以结果为导向使数据增强过程更加面向用。在减少AutoAugment的运算消耗的同时又使增强的效果变得可控。详细内容可以参考相关论文(参见arXⅳ网站上编号为1909.13719的论文)。
2.2 代码获取
https://github.com/heartInsert/randaugment
# 只有一个代码文件Rand_Augmentpy将其下载后直接引入代码即可使用。 3 本节案例带有数据增强的识别
3.1 案例简介
使用迁移学习对预训练模型进行微调的基础上实现数据增强让其学习鸟类数据集实现对多种鸟类进行识别。
3.2 代码实现load_data函数加载图片名称与标签的加载----Transfer_bird2_Augmentation.py第1部分
import glob
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt #plt 用于显示图片
import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim import lr_scheduler
from torch.utils.data import Dataset,DataLoader
import torchvision
import torchvision.models as model
from torchvision.transforms import ToPILImage
import torchvision.transforms as transforms
import os
os.environ[KMP_DUPLICATE_LIB_OK] True# 1.1 实现load_data函数加载图片名称与标签的加载并使用torch.utils.data接口将其封装成程序可用的数据集类OwnDataset。
def load_dir(directory,labstart0): # 获取所有directory中的所有图与标签# 返回path指定的文件夹所包含的文件或文件名的名称列表strlabels os.listdir(directory)# 对标签进行排序以便训练和验证按照相同的顺序进行:在不同的操作系统中加载文件夹的顺序可能不同。目录不同的情况会导致在不同的操作系统中模型的标签出现串位的现象。所以需要对文件夹进行排序保证其顺序的一致性。strlabels.sort()# 创建文件标签列表file_labels []for i,label in enumerate(strlabels):print(label)jpg_names glob.glob(os.path.join(directory,label,*.jpg))print(jpg_names)# 加入列表file_labels.extend(zip(jpg_names, [i labstart] * len(jpg_names)))return file_labels,strlabelsdef load_data(dataset_path): # 定义函数load_data函数完成对数据集中图片文件名称和标签的加载。# 该函数可以实现两层文件夹的嵌套结构。其中外层结构使用load_data函数进行遍历内层结构使用load_dir函进行遍历。sub_dir sorted(os.listdir(dataset_path)) # 跳过子文件夹:在不同的操作系统中加载文件夹的顺序可能不同。目录不同的情况会导致在不同的操作系统中模型的标签出现串位的现象。所以需要对文件夹进行排序保证其顺序的一致性。start 1 # 第0类是nonetfile_lables,tstrlabels [],[none] # 在制作标签时人为地在前面添加了一个序号为0的none类。这是一个训练图文类模型的技巧为了区分模型输出值是0和预测值是0这两种情况。for i in sub_dir:directory os.path.join(dataset_path,i)if os.path.isdir(directory) False: # 只处理文件夹中的数据print(directory)continuefile_labels,strlables load_dir(directory,labstartstart)tfile_lables.extend(file_labels)tstrlabels.extend(strlables)start len(strlables)# 将数据路径与标签解压缩,把数据路径和标签解压缩出来filenames,labels zip(*tfile_lables)return filenames, labels, tstrlabels
3.3 代码实现自定义数据集类OwnDataset----Transfer_bird2_Augmentation.py第2部分
# 1.2 实现自定义数据集OwnDataset
def default_loader(path) : # 定义函数加载图片return Image.open(path).convert(RGB)class OwnDataset(Dataset): # 复用性较强可根据自己的数据集略加修改使用# 在PyTorch中提供了一个torch.utis.data接口可以用来对数据集进行封装。在实现时只需要继承torch.utis.data.Dataset类并重载其__gettem__方法。# 在使用时框架会向__gettem__方法传入索引index在__gettem__方法内部根据指定index加载数据并返回。def __init__(self,img_dir,labels,indexlistNone,transformtransforms.ToTensor(),loaderdefault_loader,cacheTrue): # 初始化self.labels labels # 存放标签self.img_dir img_dir # 样本图片文件名self.transform transform # 预处理方法self.loader loader # 加载方法self.cache cache # 缓存标志if indexlist is None: # 要加载的数据序列self.indexlist list(range(len(self.img_dir)))else:self.indexlist indexlistself.data [None] * len(self.indexlist) # 存放样本图片def __getitem__(self, idx): # 加载指定索引数据if self.data[idx] is None: # 第一次加载data self.loader(self.img_dir[self.indexlist[idx]])if self.transform:data self.transform(data)else:data self.data[idx]if self.cache: # 保存到缓存里self.data[idx] datareturn data,self.labels[self.indexlist[idx]]def __len__(self): # 计算数据集长度return len(self.indexlist)
3.4 代码实战测试数据集----Transfer_bird2_Augmentation.py第3部分【数据增强模块】
# 1.3 测试数据集在完成数据集的制作之后编写代码对其进行测试。
# 数据增强模块
from Rand_Augment import Rand_Augment
data_transform { #定义数据的预处理方法train:transforms.Compose([Rand_Augment(), # 数据增强的方法带入 仅此一处修改transforms.RandomResizedCrop(224),transforms.RandomHorizontalFlip(),transforms.ToTensor(),transforms.Normalize([0.485,0.456,0.406],[0.229,0.224,0.225])]),val:transforms.Compose([transforms.Resize(256),transforms.CenterCrop(224),transforms.ToTensor(),transforms.Normalize([0.485,0.456,0.406],[0.229,0.224,0.225])]),
}
def Reduction_img(tensor,mean,std): #还原图片实现了图片归一化的逆操作显示数据集中的原始图片。dtype tensor.dtypemean torch.as_tensor(mean,dtypedtype,devicetensor.device)std torch.as_tensor(std,dtypedtype,devicetensor.device)tensor.mul_(std[:,None,None]).add_(mean[:,None,None]) # 还原操作dataset_path r./data/cub200/ # 加载数据集路径
filenames,labels,classes load_data(dataset_path) # 调用load_data函数对数据集中图片文件名称和标签进行加载其返回对象classes中包含全部的类名。
# 打乱数据顺序
# 110-115行对数据文件列表的序号进行乱序划分分为测试数据集和训练数集两个索引列表。该索引列表会传入OwnDataset类做成指定的数据集。
np.random.seed(0)
label_shuffle_index np.random.permutation(len(labels))
label_train_num (len(labels)//10) * 8 # 划分训练数据集和测试数据集
train_list label_shuffle_index[0:label_train_num]
test_list label_shuffle_index[label_train_num:] # 没带train_dataset OwnDataset(filenames,labels,train_list,data_transform[train])# 实例化训练数据集
val_dataset OwnDataset(filenames,labels,test_list,data_transform[val]) # 实例化测试数据集
# 实例化批次数据集OwnDataset类所定义的数据集其使用方法与PyTorch中的内置数据集的使用方法完全一致配合DataLoader接口即可生成可以进行训练或测试的批次数据。具体代码如下。
train_loader DataLoader(datasettrain_dataset,batch_size32,shuffleTrue)
val_loader DataLoader(datasetval_dataset,batch_size32,shuffleTrue)sample iter(train_loader) # 获取一批次数据进行测试
images,labels sample.next()
print(样本形状,np.shape(images))
print(标签个数,len(classes))
mulimgs torchvision.utils.make_grid(images[:10],nrow10) # 拼接多张图片
Reduction_img(mulimgs,[0.485,0.456,0.406],[0.229,0.224,0.225])
_img ToPILImage()(mulimgs) # 将张量转化为图片
plt.axis(off)
plt.imshow(_img) # 显示
plt.show()
print(,.join(%5s % classes[labels[j]] for j in range(len(images[:10]))))输出 样本形状 torch.Size([32, 3, 224, 224]) 标签个数 6 输出数据集中的10个图片 3.5 代码实战获取并改造ResNet模型----Transfer_bird2_Augmentation.py第4部分
# 1.4 获取并改造ResNet模型获取ResNet模型并加载预训练模型的权重。将其最后一层输出层去掉换成一个全新的全连接层该全连接层的输出节点数与本例分类数相同。
# 指定设备
device torch.device(cuda:0 if torch.cuda.is_available() else cpu)
print(device)
# get_ResNet函数获取预训练模型可指定pretrainedTrue来实现自动下载预训练模型也可指定loadfile来从本地路径加载预训练模型。
def get_ResNet(classes,pretrainedTrue,loadfileNone):ResNet model.resnet101(pretrained) # 自动下载官方的预训练模型if loadfile ! None:ResNet.load_state_dict(torch.load(loadfile)) # 加载本地模型# 将所有的参数层进行冻结设置模型仅最后一层可以进行训练使模型只针对最后一层进行微调。for param in ResNet.parameters():param.requires_grad False# 输出全连接层的信息print(ResNet.fc)x ResNet.fc.in_features # 获取全连接层的输入ResNet.fc nn.Linear(x,len(classes)) # 定义一个新的全连接层print(ResNet.fc) # 最后输出新的模型return ResNet
ResNet get_ResNet(classes) # 实例化模型
ResNet.to(devicedevice)
3.6 代码实战定义损失函数、训练函数及测试函数对模型的最后一层进行微调----Transfer_bird2_Augmentation.py第5部分
# 1.5 定义损失函数、训练函数及测试函数对模型的最后一层进行微调。
criterion nn.CrossEntropyLoss()
# 指定新加的全连接层的学习率
optimizer torch.optim.Adam([{params:ResNet.fc.parameters()}],lr0.01)
def train(model,device,train_loader,epoch,optimizer): # 定义训练函数model.train()allloss []for batch_idx,data in enumerate(train_loader):x,y datax x.to(device)y y.to(device)optimizer.zero_grad()y_hat model(x)loss criterion(y_hat,y)loss.backward()allloss.append(loss.item())optimizer.step()print(Train Epoch:{}\t Loss:{:.6f}.format(epoch,np.mean(allloss))) # 输出训练结果def test(model,device,val_loader): # 定义测试函数model.eval()test_loss []correct []with torch.no_grad(): # 使模型在运行时不进行梯度跟踪可以减少模型运行时对内存的占用。for i,data in enumerate(val_loader):x, y datax x.to(device)y y.to(device)y_hat model(x)test_loss.append(criterion(y_hat,y).item()) # 收集损失函数pred y_hat.max(1,keepdimTrue)[1] # 获取预测结果correct.append(pred.eq(y.view_as(pred)).sum().item()/pred.shape[0]) # 收集精确度print(\nTest:Average loss:{:,.4f},Accuracy:({:,.0f}%)\n.format(np.mean(test_loss),np.mean(correct)*100)) # 输出测试结果# 迁移学习的两个步骤如下
if __name__ __main__:
# 迁移学习步骤①固定预训练模型的特征提取部分只对最后一层进行训练使其快速收敛。firstmodepth ./data/cub200/firstmodepth_1.pth # 定义模型文件的地址if os.path.exists(firstmodepth) False:print(—————————固定预训练模型的特征提取部分只对最后一层进行训练使其快速收敛—————————)for epoch in range(1,2): # 迭代两次train(ResNet,device,train_loader,epoch,optimizer)test(ResNet,device,val_loader)# 保存模型torch.save(ResNet.state_dict(),firstmodepth)
3.7 代码实战使用退化学习率对模型进行全局微调----Transfer_bird2_Augmentation.py第6部分
# 1.6 使用退化学习率对模型进行全局微调
#迁移学习步骤②使用较小的学习率对全部模型进行训练并对每层的权重进行细微的调节即将模型的每层权重都设为可训练并定义带有退化学习率的优化器。1.6部分secondmodepth ./data/cub200/firstmodepth_2.pthoptimizer2 optim.SGD(ResNet.parameters(),lr0.001,momentum0.9) # 第198行代码定义带有退化学习率的SGD优化器。该优化器常用来对模型进行手动微调。有实验表明使用经过手动调节的SGD优化器在训练模型的后期效果优于Adam优化器。exp_lr_scheduler lr_scheduler.StepLR(optimizer2,step_size2,gamma0.9) # 由于退化学习率会在训练过程中不断地变小为了防止学习率过小最终无法进行权重需要对其设置最小值。当学习率低于该值时停止对退化学习率的操作。for param in ResNet.parameters(): # 所有参数设计为可训练param.requires_grad Trueif os.path.exists(secondmodepth):ResNet.load_state_dict(torch.load(secondmodepth)) # 加载本地模型else:ResNet.load_state_dict(torch.load(firstmodepth)) # 加载本地模型print(____使用较小的学习率对全部模型进行训练定义带有退化学习率的优化器______)for epoch in range(1,100):train(ResNet,device,train_loader,epoch,optimizer2)if optimizer2.state_dict()[param_groups][0][lr] 0.00001:exp_lr_scheduler.step()print(___lr:,optimizer2.state_dict()[param_groups][0][lr])test(ResNet,device,val_loader)# 保存模型torch.save(ResNet.state_dict(),secondmodepth) 4 代码总览Transfer_bird2_Augmentation.py
import glob
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt #plt 用于显示图片
import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim import lr_scheduler
from torch.utils.data import Dataset,DataLoader
import torchvision
import torchvision.models as model
from torchvision.transforms import ToPILImage
import torchvision.transforms as transforms
import os
os.environ[KMP_DUPLICATE_LIB_OK] True# 1.1 实现load_data函数加载图片名称与标签的加载并使用torch.utils.data接口将其封装成程序可用的数据集类OwnDataset。
def load_dir(directory,labstart0): # 获取所有directory中的所有图与标签# 返回path指定的文件夹所包含的文件或文件名的名称列表strlabels os.listdir(directory)# 对标签进行排序以便训练和验证按照相同的顺序进行:在不同的操作系统中加载文件夹的顺序可能不同。目录不同的情况会导致在不同的操作系统中模型的标签出现串位的现象。所以需要对文件夹进行排序保证其顺序的一致性。strlabels.sort()# 创建文件标签列表file_labels []for i,label in enumerate(strlabels):print(label)jpg_names glob.glob(os.path.join(directory,label,*.jpg))print(jpg_names)# 加入列表file_labels.extend(zip(jpg_names, [i labstart] * len(jpg_names)))return file_labels,strlabelsdef load_data(dataset_path): # 定义函数load_data函数完成对数据集中图片文件名称和标签的加载。# 该函数可以实现两层文件夹的嵌套结构。其中外层结构使用load_data函数进行遍历内层结构使用load_dir函进行遍历。sub_dir sorted(os.listdir(dataset_path)) # 跳过子文件夹:在不同的操作系统中加载文件夹的顺序可能不同。目录不同的情况会导致在不同的操作系统中模型的标签出现串位的现象。所以需要对文件夹进行排序保证其顺序的一致性。start 1 # 第0类是nonetfile_lables,tstrlabels [],[none] # 在制作标签时人为地在前面添加了一个序号为0的none类。这是一个训练图文类模型的技巧为了区分模型输出值是0和预测值是0这两种情况。for i in sub_dir:directory os.path.join(dataset_path,i)if os.path.isdir(directory) False: # 只处理文件夹中的数据print(directory)continuefile_labels,strlables load_dir(directory,labstartstart)tfile_lables.extend(file_labels)tstrlabels.extend(strlables)start len(strlables)# 将数据路径与标签解压缩,把数据路径和标签解压缩出来filenames,labels zip(*tfile_lables)return filenames, labels, tstrlabels# 1.2 实现自定义数据集OwnDataset
def default_loader(path) : # 定义函数加载图片return Image.open(path).convert(RGB)class OwnDataset(Dataset): # 复用性较强可根据自己的数据集略加修改使用# 在PyTorch中提供了一个torch.utis.data接口可以用来对数据集进行封装。在实现时只需要继承torch.utis.data.Dataset类并重载其__gettem__方法。# 在使用时框架会向__gettem__方法传入索引index在__gettem__方法内部根据指定index加载数据并返回。def __init__(self,img_dir,labels,indexlistNone,transformtransforms.ToTensor(),loaderdefault_loader,cacheTrue): # 初始化self.labels labels # 存放标签self.img_dir img_dir # 样本图片文件名self.transform transform # 预处理方法self.loader loader # 加载方法self.cache cache # 缓存标志if indexlist is None: # 要加载的数据序列self.indexlist list(range(len(self.img_dir)))else:self.indexlist indexlistself.data [None] * len(self.indexlist) # 存放样本图片def __getitem__(self, idx): # 加载指定索引数据if self.data[idx] is None: # 第一次加载data self.loader(self.img_dir[self.indexlist[idx]])if self.transform:data self.transform(data)else:data self.data[idx]if self.cache: # 保存到缓存里self.data[idx] datareturn data,self.labels[self.indexlist[idx]]def __len__(self): # 计算数据集长度return len(self.indexlist)# 1.3 测试数据集在完成数据集的制作之后编写代码对其进行测试。
# 数据增强模块
from Rand_Augment import Rand_Augment
data_transform { #定义数据的预处理方法train:transforms.Compose([Rand_Augment(), # 数据增强的方法带入 仅此一处修改transforms.RandomResizedCrop(224),transforms.RandomHorizontalFlip(),transforms.ToTensor(),transforms.Normalize([0.485,0.456,0.406],[0.229,0.224,0.225])]),val:transforms.Compose([transforms.Resize(256),transforms.CenterCrop(224),transforms.ToTensor(),transforms.Normalize([0.485,0.456,0.406],[0.229,0.224,0.225])]),
}
def Reduction_img(tensor,mean,std): #还原图片实现了图片归一化的逆操作显示数据集中的原始图片。dtype tensor.dtypemean torch.as_tensor(mean,dtypedtype,devicetensor.device)std torch.as_tensor(std,dtypedtype,devicetensor.device)tensor.mul_(std[:,None,None]).add_(mean[:,None,None]) # 还原操作dataset_path r./data/cub200/ # 加载数据集路径
filenames,labels,classes load_data(dataset_path) # 调用load_data函数对数据集中图片文件名称和标签进行加载其返回对象classes中包含全部的类名。
# 打乱数据顺序
# 110-115行对数据文件列表的序号进行乱序划分分为测试数据集和训练数集两个索引列表。该索引列表会传入OwnDataset类做成指定的数据集。
np.random.seed(0)
label_shuffle_index np.random.permutation(len(labels))
label_train_num (len(labels)//10) * 8 # 划分训练数据集和测试数据集
train_list label_shuffle_index[0:label_train_num]
test_list label_shuffle_index[label_train_num:] # 没带train_dataset OwnDataset(filenames,labels,train_list,data_transform[train])# 实例化训练数据集
val_dataset OwnDataset(filenames,labels,test_list,data_transform[val]) # 实例化测试数据集
# 实例化批次数据集OwnDataset类所定义的数据集其使用方法与PyTorch中的内置数据集的使用方法完全一致配合DataLoader接口即可生成可以进行训练或测试的批次数据。具体代码如下。
train_loader DataLoader(datasettrain_dataset,batch_size32,shuffleTrue)
val_loader DataLoader(datasetval_dataset,batch_size32,shuffleTrue)sample iter(train_loader) # 获取一批次数据进行测试
images,labels sample.next()
print(样本形状,np.shape(images))
print(标签个数,len(classes))
mulimgs torchvision.utils.make_grid(images[:10],nrow10) # 拼接多张图片
Reduction_img(mulimgs,[0.485,0.456,0.406],[0.229,0.224,0.225])
_img ToPILImage()(mulimgs) # 将张量转化为图片
plt.axis(off)
plt.imshow(_img) # 显示
plt.show()
print(,.join(%5s % classes[labels[j]] for j in range(len(images[:10]))))# 1.4 获取并改造ResNet模型获取ResNet模型并加载预训练模型的权重。将其最后一层输出层去掉换成一个全新的全连接层该全连接层的输出节点数与本例分类数相同。
# 指定设备
device torch.device(cuda:0 if torch.cuda.is_available() else cpu)
print(device)
# get_ResNet函数获取预训练模型可指定pretrainedTrue来实现自动下载预训练模型也可指定loadfile来从本地路径加载预训练模型。
def get_ResNet(classes,pretrainedTrue,loadfileNone):ResNet model.resnet101(pretrained) # 自动下载官方的预训练模型if loadfile ! None:ResNet.load_state_dict(torch.load(loadfile)) # 加载本地模型# 将所有的参数层进行冻结设置模型仅最后一层可以进行训练使模型只针对最后一层进行微调。for param in ResNet.parameters():param.requires_grad False# 输出全连接层的信息print(ResNet.fc)x ResNet.fc.in_features # 获取全连接层的输入ResNet.fc nn.Linear(x,len(classes)) # 定义一个新的全连接层print(ResNet.fc) # 最后输出新的模型return ResNet
ResNet get_ResNet(classes) # 实例化模型
ResNet.to(devicedevice)# 1.5 定义损失函数、训练函数及测试函数对模型的最后一层进行微调。
criterion nn.CrossEntropyLoss()
# 指定新加的全连接层的学习率
optimizer torch.optim.Adam([{params:ResNet.fc.parameters()}],lr0.01)
def train(model,device,train_loader,epoch,optimizer): # 定义训练函数model.train()allloss []for batch_idx,data in enumerate(train_loader):x,y datax x.to(device)y y.to(device)optimizer.zero_grad()y_hat model(x)loss criterion(y_hat,y)loss.backward()allloss.append(loss.item())optimizer.step()print(Train Epoch:{}\t Loss:{:.6f}.format(epoch,np.mean(allloss))) # 输出训练结果def test(model,device,val_loader): # 定义测试函数model.eval()test_loss []correct []with torch.no_grad(): # 使模型在运行时不进行梯度跟踪可以减少模型运行时对内存的占用。for i,data in enumerate(val_loader):x, y datax x.to(device)y y.to(device)y_hat model(x)test_loss.append(criterion(y_hat,y).item()) # 收集损失函数pred y_hat.max(1,keepdimTrue)[1] # 获取预测结果correct.append(pred.eq(y.view_as(pred)).sum().item()/pred.shape[0]) # 收集精确度print(\nTest:Average loss:{:,.4f},Accuracy:({:,.0f}%)\n.format(np.mean(test_loss),np.mean(correct)*100)) # 输出测试结果# 迁移学习的两个步骤如下
if __name__ __main__:
# 迁移学习步骤①固定预训练模型的特征提取部分只对最后一层进行训练使其快速收敛。firstmodepth ./data/cub200/firstmodepth_1.pth # 定义模型文件的地址if os.path.exists(firstmodepth) False:print(—————————固定预训练模型的特征提取部分只对最后一层进行训练使其快速收敛—————————)for epoch in range(1,2): # 迭代两次train(ResNet,device,train_loader,epoch,optimizer)test(ResNet,device,val_loader)# 保存模型torch.save(ResNet.state_dict(),firstmodepth)
# 1.6 使用退化学习率对模型进行全局微调
#迁移学习步骤②使用较小的学习率对全部模型进行训练并对每层的权重进行细微的调节即将模型的每层权重都设为可训练并定义带有退化学习率的优化器。1.6部分secondmodepth ./data/cub200/firstmodepth_2.pthoptimizer2 optim.SGD(ResNet.parameters(),lr0.001,momentum0.9) # 第198行代码定义带有退化学习率的SGD优化器。该优化器常用来对模型进行手动微调。有实验表明使用经过手动调节的SGD优化器在训练模型的后期效果优于Adam优化器。exp_lr_scheduler lr_scheduler.StepLR(optimizer2,step_size2,gamma0.9) # 由于退化学习率会在训练过程中不断地变小为了防止学习率过小最终无法进行权重需要对其设置最小值。当学习率低于该值时停止对退化学习率的操作。for param in ResNet.parameters(): # 所有参数设计为可训练param.requires_grad Trueif os.path.exists(secondmodepth):ResNet.load_state_dict(torch.load(secondmodepth)) # 加载本地模型else:ResNet.load_state_dict(torch.load(firstmodepth)) # 加载本地模型print(____使用较小的学习率对全部模型进行训练定义带有退化学习率的优化器______)for epoch in range(1,100):train(ResNet,device,train_loader,epoch,optimizer2)if optimizer2.state_dict()[param_groups][0][lr] 0.00001:exp_lr_scheduler.step()print(___lr:,optimizer2.state_dict()[param_groups][0][lr])test(ResNet,device,val_loader)# 保存模型torch.save(ResNet.state_dict(),secondmodepth)