含完整代码、完整中文注释!!!!
目录
一、准备:
1、flower_data数据集
可以上官网进行下载:
Visual Geometry Group - 牛津大学https://www.robots.ox.ac.uk/~vgg/data/flowers/102/index.html
2、cat_to_name.json文件
二、运行代码:
代码主要内容:
1、导入各种库
2、引用图像的存放路径
3、制作好数据源
4、设置数据加载器,以用于深度学习模型的训练和验证
5、将Tensor格式的图像数据转换为可展示的图像,并创建一个图像展示区
6、创建一个迭代器来遍历验证数据集
7、加载models中提供的模型,并且直接用训练的好权重当做初始化参数
8、先下载resnet18,然后预选模型到你的本机
9、设置哪些层需要训练
10、优化器设置
11、训练模块
##########《基于经典网络架构训练图像分类模型---花朵识别分类》102种花的分类任务##########################################
print("1、导入各种库:")
# 导入操作系统模块,用于文件和目录的处理
import os
# 导入matplotlib的pyplot模块,用于绘图
import matplotlib.pyplot as plt
#%matplotlib inline
# NumPy库,用于数值计算
import numpy as np
# 导入PyTorch主库
import torch
# 导入PyTorch的神经网络模块
from torch import nn
# 导入PyTorch的优化器模块,用于模型训练
import torch.optim as optim
# 导入torchvision库,用于计算机视觉任务
import torchvision
#pip install torchvision
# torchvision的三大核心模块:transforms(数据转换),models(模型),datasets(数据集)
from torchvision import transforms, models, datasets
#https://pytorch.org/docs/stable/torchvision/index.html
# 导入imageio库,用于图像和视频的读写
import imageio
# 导入time库,用于时间相关操作
import time
# 导入warnings库,用于处理警告信息
import warnings
# 忽略所有的警告信息
warnings.filterwarnings("ignore")
# 导入random库,用于随机数生成
import random
# 导入sys库,用于与Python解释器和运行环境交互
import sys
# 导入copy库,用于复制对象
import copy
# 导入json库,用于处理JSON数据,JSON数据是一种轻量级的数据交换格式,基于文本,易于人阅读和编写,同时也易于机器解析和生成。
import json
# 导入PIL(Python Imaging Library)的Image模块,用于图像处理
from PIL import Image
# 导入torchvision.models中的ResNet模型
from torchvision.models import ResNet
########################################################################################################################
print("2、引用图像的存放路径:")
# 定义数据的主目录
data_dir = 'D:/pycharmDM/CNN8201532/flower_data'
# 定义训练集数据的目录,通过在主目录后面拼接"/train"子目录
train_dir = data_dir + 'D:/pycharmDM/CNN8201532/flower_data/train'
# 定义验证集数据的目录,通过在主目录后面拼接"/valid"子目录
valid_dir = data_dir + 'D:/pycharmDM/CNN8201532/flower_data/valid'
########################################################################################################################
print("3、制作好数据源:")
# 指定一个data_transforms图像处理、图像增强的方式、流程
# 定义数据转换规则字典,key为数据集类型(如训练集、验证集等),value为对应的数据转换操作
data_transforms = {
# 对训练集数据进行预处理
'train':
transforms.Compose([
# 将图像缩放到指定大小,这里为96x96像素
transforms.Resize([96, 96]),
#随机旋转,-45到45度之例随机选
transforms.RandomRotation(45),
#从中心开始裁剪
transforms.CenterCrop(64),
#随机水平翻转
transforms.RandomHorizontalFlip(p=0.5),
#随机垂直翻转
transforms.RandomVerticalFlip(p=0.5),
#参数1为亮度,参数2为对比度,参数3为饱和度,参数4为色相
transforms.ColorJitter(brightness=0.2, contrast=0.1, saturation=0.1, hue=0.1),
#概率转换成灰度率,3通道就是R-G-B
transforms.RandomGrayscale(p=0.025),
#转换成张量数据
transforms.ToTensor(),
#均值,标准差
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
# 对验证集数据进行预处理
'valid':
transforms.Compose([
# 将图像调整至64x64像素大小
transforms.Resize([64, 64]),
# 将PIL图像格式转换为Tensor格式
transforms.ToTensor(),
# 对图像数据进行归一化处理,使用预定义的均值和标准差
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
}
########################################################################################################################
print("4、设置数据加载器,以用于深度学习模型的训练和验证")
# 设置批次大小,即每次训练送入网络的样本数量
batch_size = 128
# 通过现成的文件夹目录结构来指定数据集,使用ImageFolder类加载数据
# image_datasets是一个字典,包含了训练集和验证集的数据集
image_datasets = {
x: datasets.ImageFolder(
# os.path.join用于组合目录路径,这里将data_dir与'train'或'valid'子目录组合
os.path.join(data_dir, x),
# 使用之前定义的data_transforms进行数据预处理
data_transforms[x])
for x in ['train', 'valid']}
# 指定好image_datasets, batch_size, shuffle,使用DataLoader加载数据
# dataloaders是一个字典,包含了训练集和验证集的数据加载器
dataloaders = {
x: torch.utils.data.DataLoader(
# 从image_datasets中获取对应的数据集
image_datasets[x],
# 每个批次的样本数量
batch_size,
# 是否在每个epoch开始时重新洗牌数据集,对于训练集设置为True
shuffle=True)
for x in ['train', 'valid']}
# 计算数据集中样本的总数,dataset_size是一个字典,包含了训练集和验证集的样本数量
dataset_size = {
x: len(image_datasets[x])
for x in ['train', 'valid']}
# 获取训练集的类别名称列表,用于后续处理和输出
class_names = image_datasets['train'].classes
print('(1)、输出文件夹内的序号名:')
print(class_names)
print('(2)、输出由torchvision.datasets.ImageFolder类实例组成的字典,这些实例分别对应于训练集和验证集:')
print(image_datasets)
print('(3)、显示这些数据加载器的引用:')
print(dataloaders)
print('(4)、键train和valid对应训练数据集的大小,以及训练数据集中样本值:')
print(dataset_size)
print('(5)、读取标签对应的实际名字')
cat_to_name_dath="D:\pycharmDM\CNN8201532\cat_to_name.json"
# with open('cat_to_name.json', 'r') as f:
with open(cat_to_name_dath, 'r') as f:
cat_to_name = json.load(f)
#打印字典结构,即标签对应的类别名
print('(6)、打印标签对应的类别名:')
print(cat_to_name)
########################################################################################################################
print("5、将Tensor格式的图像数据转换为可展示的图像,并创建一个图像展示区")
#展示下数据,将Tensor格式的图像转换为可展示的图像格式
def im_convert(tensor):
""" 展示数据 """
# 将图像数据从GPU(如果使用GPU的话)移动到CPU,确保数据可以在CPU上处理
image = tensor.to("cpu").clone().detach()
# 将Tensor转换为NumPy数组,并去掉多余的维度(如果有的话)
image = image.numpy().squeeze()
# 重新排列数组的维度,从(通道,高度,宽度)转换为(高度,宽度,通道)
image = image.transpose(1, 2, 0)
# 反标准化操作,使用之前预处理时的均值和标准差
image = image * np.array((0.229, 0.224, 0.225)) + np.array((0.485, 0.456, 0.406))
# 将图像像素值限制在0到1之间
image = image.clip(0, 1)
# 返回转换后的图像数据
return image
#创建一个大小为(20, 12)的图像展示区,用于展示多张图像
fig=plt.figure(figsize=(20, 12))
# 设置展示区的列数和行数
print("设置展示区的列数和行数为2行4列")
columns = 4
rows = 2
########################################################################################################################
print("6、创建一个迭代器来遍历验证数据集")
# 创建一个迭代器,用于从验证集数据加载器中逐个获取数据批次
dataiter = iter(dataloaders['valid'])
# 尝试从迭代器中获取下一个数据批次
try:
# 进入一个无限循环,尝试获取数据集的下一批数据
while True:
# 使用迭代器从数据加载器获取下一批输入和类别
inputs, classes = dataiter.__next__()
# 遍历这一批数据中的每一个样本
for idx in range(columns * rows):
# 创建子图
ax = fig.add_subplot(rows, columns, idx + 1, xticks=[], yticks=[])
# 设置子图的标题为样本所属类别的名称
# 注意:这里的class_names[classes[idx]]应该是一个类别ID,需要转换为实际的类别名称
# cat_to_name是一个字典,将类别ID映射到类别名称
ax.set_title(cat_to_name[str(int(class_names[classes[idx]]))])
# 在子图中显示图像
plt.imshow(im_convert(inputs[idx]))
# 显示图像
plt.show()
# 捕获StopIteration异常,当迭代器没有更多元素时会抛出这个异常
except StopIteration:
# 这里可以处理迭代结束的情况,比如关闭窗口或保存图像等
# 这是循环的正常结束,不需要特别处理,可以简单地pass跳过
pass
print("显示一张2行4列的图像,以及6张花朵的图像")
######################################################################################################################
print("7、加载models中提供的模型,并且直接用训练的好权重当做初始化参数")
#可选的比较多resnet、alexnel、vgg、squeetenet、densent、inception
model_name = 'resnet'
#是否用人家训练好的特征来做,True表示用别人的特征,咱先不更新
feature_extract = True
#是否用GPU训练
train_on_gpu = torch.cuda.is_available()
if not train_on_gpu:
print('(1)、CUDA是不可用的,使用CPU训练')
else:
print('(1)、CUDA可用,使用GPU训练')
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# 设定设备为GPU(如果有可用的CUDA设备则使用cuda:0,否则使用cpu)
def set_parameter_requires_grad(model, feature_extracting):
# 如果是特征抽取模式
if feature_extracting:
# 遍历模型的所有参数
for param in model.parameters():
# 将所有参数的requires_grad属性设置为False,即不计算梯度
param.requires_grad = False
#18层的能快点,条件好点的也可以选152(GPU环境下)
model_ft: ResNet = models.resnet18()
print("(2)、ResNet-18是一种深度卷积神经网络结构,它包含18层,如下")
print(model_ft)
######################################################################################################################
print("8、先下载resnet18,然后预选模型到你的本机")
def initialize_model(model_name, num_classes, feature_extract, use_pretrained=True):
# 始化模型变量,选择合适的模型,不同模型的初始化方法稍微有点区别
model_ft = None
input_size = 0
if model_name == "resnet":
""" Resnet18模型的初始化"""
#数值pretrained是预训练模型,指用别人训练好的模型和权重参数
# 加载预训练的ResNet18模型(如果use_pretrained为True,则加载预训练权重)
model_ft= models.resnet18(pretrained=use_pretrained)
#执行函数,把模型当中所有输入参数的值都false,就表示都不更新了
set_parameter_requires_grad(model_ft, feature_extract)
#重新定义一个全连接层,首先在刚才别人的模型中去找别人的全连接层fc
num_ftrs = model_ft.fc.in_features
model_ft.fc = nn.Sequential(nn.Linear(num_ftrs, 102),
nn.LogSoftmax(dim=1))
input_size = 64
elif model_name == "alexnet":
""" Alexnet
"""
model_ft = models.alexnet(pretrained=use_pretrained)
set_parameter_requires_grad(model_ft, feature_extract)
num_ftrs = model_ft.classifier[6].in_features
#重新写自己的全连接层,覆盖别人的fc,相当于重新赋值,我自己的层数num_classes是102
model_ft.classifier[6] = nn.Linear(num_ftrs, num_classes)
# 输入大小根据自己配置来
input_size = 64
elif model_name == "squeezenet":
""" Squeezenet
"""
model_ft = models.squeezenet1_0(pretrained=use_pretrained)
set_parameter_requires_grad(model_ft, feature_extract)
model_ft.classifier[1] = nn.Conv2d(512, num_classes, kernel_size=(1,1), stride=(1,1))
model_ft.num_classes = num_classes
input_size =64
elif model_name == "densenet":
""" Densenet
"""
model_ft = models.densenet121(pretrained=use_pretrained)
set_parameter_requires_grad(model_ft, feature_extract)
num_ftrs = model_ft.classifier.in_features
model_ft.classifier = nn.Linear(num_ftrs, num_classes)
input_size =64
elif model_name == "inception":
""" Inception v3
Be careful, expects (299,299) sized images and has auxiliary output
"""
model_ft = models.inception_v3(pretrained=use_pretrained)
set_parameter_requires_grad(model_ft, feature_extract)
# Handle the auxilary net
num_ftrs = model_ft.AuxLogits.fc.in_features
model_ft.AuxLogits.fc = nn.Linear(num_ftrs, num_classes)
# Handle the primary net
num_ftrs = model_ft.fc.in_features
model_ft.fc = nn.Linear(num_ftrs,num_classes)
input_size =64
else:
print("Invalid model name, exiting...")
exit()
return model_ft, input_size
########################################################################################################################
print("9、设置哪些层需要训练")
#构建一个模型model_ft
model_ft, input_size = initialize_model(model_name, 102, feature_extract, use_pretrained=True)
#GPU还是CPU计算,把模型model_ft拖入device
model_ft= model_ft.to(device)
#模型保存,名字自己起,会把自己训练得最好的模型保存下来,主要保存网络架构图和所有权重参数
#保存本地就不用重复做训练了,名字路径自己定
filename = 'huaduo829.pth'
#是否训练所有层,要训练所有层,就等于全部的参数
params_to_update = model_ft.parameters()
print('学习参数:')
# 如果在这个模型中,grad等于true,你需要权重参数的才把它放进这个if里面
# 放进if会默认会给的制空先制空,然后一个个往里传
if feature_extract:
params_to_update = []
for name, param in model_ft.named_parameters():
if param.requires_grad == True:
params_to_update.append(param)
print("\t", param)
else:
for name, param in model_ft.named_parameters():
if param.requires_grad == True:
print("\t", name)
########################################################################################################################
print("10、优化器设置")
#要训练啥参数,Adam是现在用得最多得优化器
#第一个参数:要更新的参数
#第二个参数:lr是、学习率,设置得稍小一点,小于0.001这样子
#params_to_update是已保存的要更新的东西,把它传入优化器
optimizer_ft = optim.Adam(params_to_update, lr=1e-2)
#指定一个衰减策略,学习率每7个epoch衰减成原来的1/10
#学习率lr会随着迭代次数iter开始慢慢减少,不过衰减策略可以自己定
#SterLR你告诉我什么时候衰减就什么时候衰减
#第一个参数:优化器
#第二个参数:表示累计10个epoch就执行一下衰减
scheduler = optim.lr_scheduler.StepLR(optimizer_ft, step_size=10, gamma=0.1)
# #损失函数,交叉熵,直接把预测值、真实值直接传入交叉熵损失函数中(报错)
# criterion = nn.CrossEntropyLoss()
#最后一层已经LogSoftmax()了,所以不能nn.CrossEntropyLoss()来计算了,nn.CrossEntropyLoss()相当于logSoftmax()和nn.NLLLoss()整合
criterion = nn.NLLLoss()
########################################################################################################################
print("11、训练模块")
#首先传入模型model,数据以数据集文件夹的形式,标签也是文件夹名字dataloaders
#还有损失函数riterion、优化器optimizer、默认迭代参数num_epoch、保存文件的路径filename,可自己指定
def train_model(model, dataloaders, criterion, optimizer, num_epochs=20, is_inception=False,filename=filename):
#当前时间记录
since = time.time()
#记录最好得一次,准确率一般会随着点次数的增加逐渐上升,最后在收尾处下降一点,所以准确率不一定在最后
#每经过一次迭代,就会比较一次正确率,如果没有更高,是不会做替换的
best_acc = 0
"""
checkpoint = torch.load(filename)
best_acc = checkpoint['best_acc']
model.load_state_dict(checkpoint['state_dict'])
optimizer.load_state_dict(checkpoint['optimizer'])
model.class_to_idx = checkpoint['mapping']
"""
#把模型放进CPU或GPU
model.to(device)
#训练过程中打印一堆损失和指标
#下面的训练集、验证集结果都会分别存入这四个地方
#(1)训练集的准确率
val_acc_history = []
#(2)验证集的准确率
train_acc_history = []
#(3)虚假损失
train_losses = []
#(4)建制损失
valid_losses = []
#取当前的学习率,字典结构
LRs = [optimizer.param_groups[0]['lr']]
#验证集比之前更好才会更新,记录最好的那次模型,后续会变的,先初始化
#复制权重参数copy.deepcopy(model.state_dict())
best_model_wts = copy.deepcopy(model.state_dict())
# 1.最外层是遍历一次epoch,每个epoch都包含训练阶段和验证阶段
# 一个个epoch来遍历
for epoch in range(num_epochs):
print('一、模型正在经历第几次训练/总共有几次训练(从0开始计数):')
#num_epochs=20???
print('Epoch {}/{}'.format(epoch+1, num_epochs))
#打印一个由100个连字符(-)组成的字符串
print('-' * 100)
# 2.训练阶段和验证阶段都需要去走前向传播,训练阶段比验证阶段多走一个参数更新
#每一个phase都包含一个训练和一个验证
for phase in ['train', 'valid']:
#为了遍历训练,它先从这个训练开始训练,不涉及参数更新·
if phase == 'train':
#训练
model.train()
else:
#验证
model.eval()
print("(1)、设置初始化损失函数和正确率都为0")
#初始化损失函数和正确率
running_loss = 0.0
running_corrects = 0
print("(2)、把数据都取个遍,for每次遍历都只拿一个epoch数据中的其中一部分")
#把这一部分计算出来,再计算一个平均值
for inputs, labels in dataloaders[phase]:
#取到的数据放到你的CPU或者GPU当中,相当于把标签信息放入设备中
inputs = inputs.to(device)
#取到的标签放到你的CPU或者GPU当中
labels = labels.to(device)
#梯度清零,每一次执行都要先清零再更新
optimizer.zero_grad()
with torch.set_grad_enabled(phase == 'train'):
if is_inception and phase == 'train':
outputs, aux_outputs = model(inputs)
loss1 = criterion(outputs, labels)
loss2 = criterion(aux_outputs, labels)
loss = loss1 + 0.4*loss2
else: # resnet执行的是这里
#只有训练的时候计算和更新梯度,这里的输出结果outputs是102
outputs = model(inputs)
#计算损失函数
loss = criterion(outputs, labels)
#计算准确率
_, preds = torch.max(outputs, 1)
#训练阶段才更新权重,验证阶段不需要更新权重
if phase == 'train':
#反向传播
loss.backward()
#相当于完成一次迭代
optimizer.step()
#计算损失
#0表示batch那个维度
running_loss += loss.item() * inputs.size(0)
#预测结果最大的和真实值是否一致
# running_corrects += torch.sum(preds == labels.data)
assert isinstance(labels.data, object)
running_corrects += torch.sum(preds == labels.data)
#累加的结果计算一下平均值
#例如:1个epoch等于200次迭代,那两百次迭代器就等于所有数据集,再除上数据集的一个总数
#相当于一个平均损失
epoch_loss: float = running_loss / dataset_size[phase]
#相当于一个平均正确率
epoch_acc = running_corrects.double() / len(dataloaders[phase].dataset)
#一个epoch我浪费了多少时间
#其实就是当前时间和之前的时间做一个减法,就一个epoch浪费了多少时间
time_elapsed = time.time() - since
#打印计算损失
print("(3)、计算损失:")
print('Time elapsed {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))
#打印正确率
print("(4)、正确率:")
print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))
#3、走完验证集后要做判断,保存最好用的权重参数,用当前的这次做一个替换,然后把最好的准确率、优化器这些参数都存进去
#得到最好的那次的模型######################################################
if phase == 'valid' and epoch_acc > best_acc:
best_acc = epoch_acc
best_model_wts = copy.deepcopy(model.state_dict())
state = {
#字典里key就是各层的名字,值就是训练好的权重,已更新的权重
'state_dict': model.state_dict(),
'best_acc': best_acc,
'optimizer': optimizer.state_dict(),
}
#把所有权重参数保存在本地,会对其做一个数据覆盖
torch.save(state, filename)
#####################################################################
#验证集
if phase == 'valid':
#把当前算出的结果存入验证集
val_acc_history.append(epoch_acc)
valid_losses.append(epoch_loss)
#学习率衰减
scheduler.step(epoch_loss)
#训练集
if phase == 'train':
# 把当前算出的结果存入训练集
train_acc_history.append(epoch_acc)
train_losses.append(epoch_loss)
print("(5)、优化器学习率:")
print('Optimizer learning rate : {:7f}'.format(optimizer_ft.param_groups[0]['lr']))
#遍历完后,保存当前学习率,累计十次左右,它的学习率才会出现衰减
LRs.append(optimizer_ft.param_groups[0]['lr'])
print()
#打印所花费的时间
time_elapsed = time.time() - since
print("二、训练所花费的时间:")
print('Training complete in {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))
print("三、最好的验证集:")
print('Best val Acc: {:4f}'.format(best_acc))
# 训练完后用最好的一次当做模型最终的结果
model.load_state_dict(best_model_wts)
return model, val_acc_history, train_acc_history, valid_losses, train_losses, LRs
#开始训练,先训练输出层
model_ft, val_acc_history, train_acc_history, valid_losses, train_losses, LRs = (
train_model(model_ft, dataloaders, criterion, optimizer_ft, num_epochs=20, is_inception=(model_name=="inception")))
###################################################################################################################
三、运行结果:
C:\Users\CZI\.conda\envs\pytorchfxl\python.exe D:\pycharmDM\AAAAAAAA\aa1.py
1、导入各种库:
2、引用图像的存放路径:
3、制作好数据源:
4、设置数据加载器,以用于深度学习模型的训练和验证
(1)、输出文件夹内的序号名:
['1', '10', '100', '101', '102', '11', '12', '13', '14', '15', '16', '17', '18', '19', '2', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '3', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '4', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '5', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '6', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '7', '70', '71', '72', '73', '74', '75', '76', '77', '78', '79', '8', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '9', '90', '91', '92', '93', '94', '95', '96', '97', '98', '99']
(2)、输出由torchvision.datasets.ImageFolder类实例组成的字典,这些实例分别对应于训练集和验证集:
{'train': Dataset ImageFolder
Number of datapoints: 6552
Root location: D:/pycharmDM/CNN8201532/flower_data\train
StandardTransform
Transform: Compose(
Resize(size=[96, 96], interpolation=bilinear, max_size=None, antialias=True)
RandomRotation(degrees=[-45.0, 45.0], interpolation=nearest, expand=False, fill=0)
CenterCrop(size=(64, 64))
RandomHorizontalFlip(p=0.5)
RandomVerticalFlip(p=0.5)
ColorJitter(brightness=(0.8, 1.2), contrast=(0.9, 1.1), saturation=(0.9, 1.1), hue=(-0.1, 0.1))
RandomGrayscale(p=0.025)
ToTensor()
Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
), 'valid': Dataset ImageFolder
Number of datapoints: 818
Root location: D:/pycharmDM/CNN8201532/flower_data\valid
StandardTransform
Transform: Compose(
Resize(size=[64, 64], interpolation=bilinear, max_size=None, antialias=True)
ToTensor()
Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
)}
(3)、显示这些数据加载器的引用:
{'train': <torch.utils.data.dataloader.DataLoader object at 0x0000019D487411C0>, 'valid': <torch.utils.data.dataloader.DataLoader object at 0x0000019D48741280>}
(4)、键train和valid对应训练数据集的大小,以及训练数据集中样本值:
{'train': 6552, 'valid': 818}
(5)、读取标签对应的实际名字
(6)、打印标签对应的类别名:
{'21': 'fire lily', '3': 'canterbury bells', '45': 'bolero deep blue', '1': 'pink primrose', '34': 'mexican aster', '27': 'prince of wales feathers', '7': 'moon orchid', '16': 'globe-flower', '25': 'grape hyacinth', '26': 'corn poppy', '79': 'toad lily', '39': 'siam tulip', '24': 'red ginger', '67': 'spring crocus', '35': 'alpine sea holly', '32': 'garden phlox', '10': 'globe thistle', '6': 'tiger lily', '93': 'ball moss', '33': 'love in the mist', '9': 'monkshood', '102': 'blackberry lily', '14': 'spear thistle', '19': 'balloon flower', '100': 'blanket flower', '13': 'king protea', '49': 'oxeye daisy', '15': 'yellow iris', '61': 'cautleya spicata', '31': 'carnation', '64': 'silverbush', '68': 'bearded iris', '63': 'black-eyed susan', '69': 'windflower', '62': 'japanese anemone', '20': 'giant white arum lily', '38': 'great masterwort', '4': 'sweet pea', '86': 'tree mallow', '101': 'trumpet creeper', '42': 'daffodil', '22': 'pincushion flower', '2': 'hard-leaved pocket orchid', '54': 'sunflower', '66': 'osteospermum', '70': 'tree poppy', '85': 'desert-rose', '99': 'bromelia', '87': 'magnolia', '5': 'english marigold', '92': 'bee balm', '28': 'stemless gentian', '97': 'mallow', '57': 'gaura', '40': 'lenten rose', '47': 'marigold', '59': 'orange dahlia', '48': 'buttercup', '55': 'pelargonium', '36': 'ruby-lipped cattleya', '91': 'hippeastrum', '29': 'artichoke', '71': 'gazania', '90': 'canna lily', '18': 'peruvian lily', '98': 'mexican petunia', '8': 'bird of paradise', '30': 'sweet william', '17': 'purple coneflower', '52': 'wild pansy', '84': 'columbine', '12': "colt's foot", '11': 'snapdragon', '96': 'camellia', '23': 'fritillary', '50': 'common dandelion', '44': 'poinsettia', '53': 'primula', '72': 'azalea', '65': 'californian poppy', '80': 'anthurium', '76': 'morning glory', '37': 'cape flower', '56': 'bishop of llandaff', '60': 'pink-yellow dahlia', '82': 'clematis', '58': 'geranium', '75': 'thorn apple', '41': 'barbeton daisy', '95': 'bougainvillea', '43': 'sword lily', '83': 'hibiscus', '78': 'lotus lotus', '88': 'cyclamen', '94': 'foxglove', '81': 'frangipani', '74': 'rose', '89': 'watercress', '73': 'water lily', '46': 'wallflower', '77': 'passion flower', '51': 'petunia'}
5、将Tensor格式的图像数据转换为可展示的图像,并创建一个图像展示区
设置展示区的列数和行数为2行4列
6、创建一个迭代器来遍历验证数据集
显示一张2行4列的图像,以及6张花朵的图像
7、加载models中提供的模型,并且直接用训练的好权重当做初始化参数
(1)、CUDA是不可用的,使用CPU训练
(2)、ResNet-18是一种深度卷积神经网络结构,它包含18层,如下
ResNet(
(conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
(maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
(layer1): Sequential(
(0): BasicBlock(
(conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
(1): BasicBlock(
(conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
)
(layer2): Sequential(
(0): BasicBlock(
(conv1): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
(bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
(conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(downsample): Sequential(
(0): Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2), bias=False)
(1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
)
(1): BasicBlock(
(conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
(conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
)
(layer3): Sequential(
(0): BasicBlock(
(conv1): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
(bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(downsample): Sequential(
(0): Conv2d(128, 256, kernel_size=(1, 1), stride=(2, 2), bias=False)
(1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
)
(1): BasicBlock(
(conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
)
(layer4): Sequential(
(0): BasicBlock(
(conv1): Conv2d(256, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
(bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
(conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(downsample): Sequential(
(0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False)
(1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
)
(1): BasicBlock(
(conv1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
(conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
)
(avgpool): AdaptiveAvgPool2d(output_size=(1, 1))
(fc): Linear(in_features=512, out_features=1000, bias=True)
)
8、先下载resnet18,然后预选模型到你的本机
9、设置哪些层需要训练
学习参数:
Parameter containing:
tensor([[-0.0021, -0.0243, 0.0430, ..., 0.0227, -0.0367, 0.0060],
[ 0.0417, -0.0054, 0.0050, ..., -0.0040, -0.0281, -0.0330],
[ 0.0076, -0.0204, 0.0272, ..., 0.0196, -0.0251, -0.0131],
...,
[-0.0211, -0.0361, -0.0306, ..., 0.0046, 0.0036, -0.0152],
[-0.0434, 0.0106, -0.0175, ..., -0.0311, -0.0359, 0.0227],
[-0.0259, -0.0265, -0.0234, ..., 0.0165, -0.0032, -0.0224]],
requires_grad=True)
Parameter containing:
tensor([ 0.0281, -0.0096, -0.0360, -0.0064, 0.0399, -0.0033, -0.0431, -0.0017,
0.0103, 0.0084, -0.0231, -0.0435, -0.0278, -0.0189, -0.0362, -0.0385,
0.0299, 0.0169, -0.0023, -0.0215, 0.0021, -0.0383, 0.0299, -0.0148,
0.0123, 0.0096, -0.0091, 0.0325, 0.0336, 0.0178, 0.0330, 0.0134,
-0.0077, -0.0008, -0.0112, 0.0217, 0.0281, -0.0098, -0.0312, 0.0040,
-0.0272, 0.0044, -0.0137, 0.0440, -0.0063, -0.0078, 0.0076, -0.0064,
0.0142, -0.0055, 0.0355, -0.0429, 0.0128, 0.0275, -0.0335, -0.0357,
0.0295, -0.0112, -0.0347, 0.0397, 0.0266, -0.0404, -0.0426, 0.0118,
0.0253, -0.0245, 0.0177, 0.0399, 0.0340, -0.0061, 0.0234, -0.0231,
-0.0297, -0.0360, 0.0380, 0.0267, 0.0192, 0.0234, 0.0015, -0.0035,
0.0121, 0.0031, 0.0210, 0.0241, -0.0377, -0.0047, 0.0411, -0.0423,
-0.0194, -0.0121, 0.0019, 0.0207, -0.0162, 0.0369, -0.0170, 0.0147,
-0.0030, 0.0226, -0.0376, 0.0033, -0.0303, -0.0344],
requires_grad=True)
9、优化器设置
10、训练模块
一、模型正在经历第几次训练/总共有几次训练(从0开始计数):
Epoch 1/20
----------------------------------------------------------------------------------------------------
(1)、设置初始化损失函数和正确率都为0
(2)、把数据都取个遍,for每次遍历都只拿一个epoch数据中的其中一部分
(3)、计算损失:
Time elapsed 0m 5s
(4)、正确率:
valid Loss: 5.3256 Acc: 0.0049
(5)、优化器学习率:
Optimizer learning rate : 0.010000
一、模型正在经历第几次训练/总共有几次训练(从0开始计数):
Epoch 2/20
----------------------------------------------------------------------------------------------------
(1)、设置初始化损失函数和正确率都为0
(2)、把数据都取个遍,for每次遍历都只拿一个epoch数据中的其中一部分
(3)、计算损失:
Time elapsed 0m 10s
(4)、正确率:
valid Loss: 5.3256 Acc: 0.0049
(5)、优化器学习率:
Optimizer learning rate : 0.010000
一、模型正在经历第几次训练/总共有几次训练(从0开始计数):
Epoch 3/20
----------------------------------------------------------------------------------------------------
(1)、设置初始化损失函数和正确率都为0
(2)、把数据都取个遍,for每次遍历都只拿一个epoch数据中的其中一部分
(3)、计算损失:
Time elapsed 0m 15s
(4)、正确率:
valid Loss: 5.3256 Acc: 0.0049
(5)、优化器学习率:
Optimizer learning rate : 0.010000
一、模型正在经历第几次训练/总共有几次训练(从0开始计数):
Epoch 4/20
----------------------------------------------------------------------------------------------------
(1)、设置初始化损失函数和正确率都为0
(2)、把数据都取个遍,for每次遍历都只拿一个epoch数据中的其中一部分
(3)、计算损失:
Time elapsed 0m 20s
(4)、正确率:
valid Loss: 5.3256 Acc: 0.0049
(5)、优化器学习率:
Optimizer learning rate : 0.010000
一、模型正在经历第几次训练/总共有几次训练(从0开始计数):
Epoch 5/20
----------------------------------------------------------------------------------------------------
(1)、设置初始化损失函数和正确率都为0
(2)、把数据都取个遍,for每次遍历都只拿一个epoch数据中的其中一部分
(3)、计算损失:
Time elapsed 0m 25s
(4)、正确率:
valid Loss: 5.3256 Acc: 0.0049
(5)、优化器学习率:
Optimizer learning rate : 0.010000
一、模型正在经历第几次训练/总共有几次训练(从0开始计数):
Epoch 6/20
----------------------------------------------------------------------------------------------------
(1)、设置初始化损失函数和正确率都为0
(2)、把数据都取个遍,for每次遍历都只拿一个epoch数据中的其中一部分
(3)、计算损失:
Time elapsed 0m 29s
(4)、正确率:
valid Loss: 5.3256 Acc: 0.0049
(5)、优化器学习率:
Optimizer learning rate : 0.010000
一、模型正在经历第几次训练/总共有几次训练(从0开始计数):
Epoch 7/20
----------------------------------------------------------------------------------------------------
(1)、设置初始化损失函数和正确率都为0
(2)、把数据都取个遍,for每次遍历都只拿一个epoch数据中的其中一部分
(3)、计算损失:
Time elapsed 0m 33s
(4)、正确率:
valid Loss: 5.3256 Acc: 0.0049
(5)、优化器学习率:
Optimizer learning rate : 0.010000
一、模型正在经历第几次训练/总共有几次训练(从0开始计数):
Epoch 8/20
----------------------------------------------------------------------------------------------------
(1)、设置初始化损失函数和正确率都为0
(2)、把数据都取个遍,for每次遍历都只拿一个epoch数据中的其中一部分
(3)、计算损失:
Time elapsed 0m 37s
(4)、正确率:
valid Loss: 5.3256 Acc: 0.0049
(5)、优化器学习率:
Optimizer learning rate : 0.010000
一、模型正在经历第几次训练/总共有几次训练(从0开始计数):
Epoch 9/20
----------------------------------------------------------------------------------------------------
(1)、设置初始化损失函数和正确率都为0
(2)、把数据都取个遍,for每次遍历都只拿一个epoch数据中的其中一部分
(3)、计算损失:
Time elapsed 0m 42s
(4)、正确率:
valid Loss: 5.3256 Acc: 0.0049
(5)、优化器学习率:
Optimizer learning rate : 0.010000
一、模型正在经历第几次训练/总共有几次训练(从0开始计数):
Epoch 10/20
----------------------------------------------------------------------------------------------------
(1)、设置初始化损失函数和正确率都为0
(2)、把数据都取个遍,for每次遍历都只拿一个epoch数据中的其中一部分
(3)、计算损失:
Time elapsed 0m 48s
(4)、正确率:
valid Loss: 5.3256 Acc: 0.0049
(5)、优化器学习率:
Optimizer learning rate : 0.010000
一、模型正在经历第几次训练/总共有几次训练(从0开始计数):
Epoch 11/20
----------------------------------------------------------------------------------------------------
(1)、设置初始化损失函数和正确率都为0
(2)、把数据都取个遍,for每次遍历都只拿一个epoch数据中的其中一部分
(3)、计算损失:
Time elapsed 0m 52s
(4)、正确率:
valid Loss: 5.3256 Acc: 0.0049
(5)、优化器学习率:
Optimizer learning rate : 0.010000
一、模型正在经历第几次训练/总共有几次训练(从0开始计数):
Epoch 12/20
----------------------------------------------------------------------------------------------------
(1)、设置初始化损失函数和正确率都为0
(2)、把数据都取个遍,for每次遍历都只拿一个epoch数据中的其中一部分
(3)、计算损失:
Time elapsed 0m 57s
(4)、正确率:
valid Loss: 5.3256 Acc: 0.0049
(5)、优化器学习率:
Optimizer learning rate : 0.010000
一、模型正在经历第几次训练/总共有几次训练(从0开始计数):
Epoch 13/20
----------------------------------------------------------------------------------------------------
(1)、设置初始化损失函数和正确率都为0
(2)、把数据都取个遍,for每次遍历都只拿一个epoch数据中的其中一部分
(3)、计算损失:
Time elapsed 1m 3s
(4)、正确率:
valid Loss: 5.3256 Acc: 0.0049
(5)、优化器学习率:
Optimizer learning rate : 0.010000
一、模型正在经历第几次训练/总共有几次训练(从0开始计数):
Epoch 14/20
----------------------------------------------------------------------------------------------------
(1)、设置初始化损失函数和正确率都为0
(2)、把数据都取个遍,for每次遍历都只拿一个epoch数据中的其中一部分
(3)、计算损失:
Time elapsed 1m 8s
(4)、正确率:
valid Loss: 5.3256 Acc: 0.0049
(5)、优化器学习率:
Optimizer learning rate : 0.010000
一、模型正在经历第几次训练/总共有几次训练(从0开始计数):
Epoch 15/20
----------------------------------------------------------------------------------------------------
(1)、设置初始化损失函数和正确率都为0
(2)、把数据都取个遍,for每次遍历都只拿一个epoch数据中的其中一部分
(3)、计算损失:
Time elapsed 1m 13s
(4)、正确率:
valid Loss: 5.3256 Acc: 0.0049
(5)、优化器学习率:
Optimizer learning rate : 0.010000
一、模型正在经历第几次训练/总共有几次训练(从0开始计数):
Epoch 16/20
----------------------------------------------------------------------------------------------------
(1)、设置初始化损失函数和正确率都为0
(2)、把数据都取个遍,for每次遍历都只拿一个epoch数据中的其中一部分
(3)、计算损失:
Time elapsed 1m 18s
(4)、正确率:
valid Loss: 5.3256 Acc: 0.0049
(5)、优化器学习率:
Optimizer learning rate : 0.010000
一、模型正在经历第几次训练/总共有几次训练(从0开始计数):
Epoch 17/20
----------------------------------------------------------------------------------------------------
(1)、设置初始化损失函数和正确率都为0
(2)、把数据都取个遍,for每次遍历都只拿一个epoch数据中的其中一部分
(3)、计算损失:
Time elapsed 1m 23s
(4)、正确率:
valid Loss: 5.3256 Acc: 0.0049
(5)、优化器学习率:
Optimizer learning rate : 0.010000
一、模型正在经历第几次训练/总共有几次训练(从0开始计数):
Epoch 18/20
----------------------------------------------------------------------------------------------------
(1)、设置初始化损失函数和正确率都为0
(2)、把数据都取个遍,for每次遍历都只拿一个epoch数据中的其中一部分
(3)、计算损失:
Time elapsed 1m 28s
(4)、正确率:
valid Loss: 5.3256 Acc: 0.0049
(5)、优化器学习率:
Optimizer learning rate : 0.010000
一、模型正在经历第几次训练/总共有几次训练(从0开始计数):
Epoch 19/20
----------------------------------------------------------------------------------------------------
(1)、设置初始化损失函数和正确率都为0
(2)、把数据都取个遍,for每次遍历都只拿一个epoch数据中的其中一部分
(3)、计算损失:
Time elapsed 1m 33s
(4)、正确率:
valid Loss: 5.3256 Acc: 0.0049
(5)、优化器学习率:
Optimizer learning rate : 0.010000
一、模型正在经历第几次训练/总共有几次训练(从0开始计数):
Epoch 20/20
----------------------------------------------------------------------------------------------------
(1)、设置初始化损失函数和正确率都为0
(2)、把数据都取个遍,for每次遍历都只拿一个epoch数据中的其中一部分
(3)、计算损失:
Time elapsed 1m 38s
(4)、正确率:
valid Loss: 5.3256 Acc: 0.0049
(5)、优化器学习率:
Optimizer learning rate : 0.010000
二、训练所花费的时间:
Training complete in 1m 38s
三、最好的验证集:
Best val Acc: 0.004890
进程已结束,退出代码为 0