# 37 微调
# 源数据集通常远复杂目标数据,效果更好
import matplotlib.pyplot as plt
import os
import torch
import torchvision
from torch import nn
from d2l import torch as d2l
# resnet18模型下载路径
os.environ['TORCH_HOME']=r'D:\worksoftware\PycharmProjects\pythonProject\torch_model'
# 下载,会主动在data文件夹下,下载名为hotdog.zip数据集
d2l.DATA_HUB['hotdog'] = (d2l.DATA_URL + 'hotdog.zip', 'fba480ffa8aa7e0febbb511d181409f899b9baa5')
data_dir = d2l.download_extract('hotdog')
# 读取
train_imgs = torchvision.datasets.ImageFolder(os.path.join(data_dir, 'train'))
test_imgs = torchvision.datasets.ImageFolder(os.path.join(data_dir, 'test'))
# for x, y in train_imgs:
#print(x.size) # 图片杂大小杂乱无章
#print(y) 标号1代表热狗,0代表其他类型,是个二分类数据集
#显示前8个正类样本图⽚和最后8张负类样本图⽚。
hotdogs = [train_imgs[i][0] for i in range(8)]
not_hotdogs = [train_imgs[-i - 1][0] for i in range(8)]
d2l.show_images(hotdogs + not_hotdogs, 2, 8, scale=1.4)
plt.show() # 这一行,不加不显示图片
# 数据增广
#Normalize() 函数的作用是将数据转换为标准正太分布,使模型更容易收敛
# 对每一个channel,([mean], [std]) (x-mean)/std
normalize = torchvision.transforms.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225])
#增广,也就是对图片剪切,调整大小,色彩,对比度等
# 224x224与imagnet一致,随机水平旋转,转换成张量,正则化
train_augs = torchvision.transforms.Compose([
torchvision.transforms.RandomResizedCrop(224),
torchvision.transforms.RandomHorizontalFlip(),
torchvision.transforms.ToTensor(),
normalize]
)
#CenterCrop:在图片的中间区域进行裁剪
test_augs = torchvision.transforms.Compose([
torchvision.transforms.Resize(256),
torchvision.transforms.CenterCrop(224),
torchvision.transforms.ToTensor(),
normalize]
)
# 定义和初始化模型
pretrained_net = torchvision.models.resnet18(pretrained=True)
#下载模型,pretrained=True:把训练好的参数也拿下来
print(pretrained_net.fc) # 最后的一层全连接层
# Linear(in_features=512, out_features=1000, bais=Ture)
finetune_net = torchvision.models.resnet18(pretrained=True)
finetune_net.fc = nn.Linear(finetune_net.fc.in_features, 2) # 替换最后一层,改为二分类(512, 2)
# 仅初始化最后一层权重,其他层不变
nn.init.xavier_uniform_(finetune_net.fc.weight)
# 微调模型
def train_fine_tuning(net, learning_rate, batch_size=128, num_epochs=5, param_group=True):
# 数据迭代处理
train_iter = torch.utils.data.DataLoader(
train_imgs = torchvision.datasets.ImageFolder(os.path.join(data_dir, 'train'),
transform=train_augs), batch_size=batch_size, shuffle=True)
test_iter = torch.utils.data.DataLoader(
test_imgs=torchvision.datasets.ImageFolder(os.path.join(data_dir, 'train'),
transform=train_augs), batch_size=batch_size, shuffle=True)
# 采用cpu/gpu运算,前面章节有介绍
devices = d2l.try_all_gpus()
#定义损失 reduction='none':输出损失就是一个和样本数相等的向量
loss = nn.CrossEntropyLoss(reduction='none')
# 非最后一层学习率为lr,最后一层学习率lr*10
# 这里还对权重w进行惩罚 lambd=0.0001
if param_group:
params_1x = [param for name, param in net.named_parameters()
if name not in ['fc.weight', 'fc.bias']]
trainer = torch.optim.SGD([{'params':params_1x},
{'params':net.fc.parameters(), 'lr':learning_rate*10}],
lr = learning_rate, weight_decay=0.001 )
else:
trainer = torch.optim.SGD(net.parameters(), lr = learning_rate, weight_decay=0.001)
d2l.train_ch13(net, train_iter, test_iter, loss, trainer, num_epochs, devices)
train_fine_tuning(finetune_net, 5e-5)
# 比较更新全部参数
scratch_net = torchvision.models.resnet18()
scratch_net.fc = nn.Linear(scratch_net.fc.in_features, 2)
train_fine_tuning(scratch_net,5e-4, param_group=False)
备注:仅学习使用无需任何打赏