最近在想着复现自己的第一篇论文,但是医学图像的处理方面对于初次接触它的我来说还是抽象了一点,花了一个星期勉强跟着视频操作了一下,对于这种没有文档的软件学习使用感觉需要更多的成本啊(碎碎念)
于是,我就一个星期没有正经编程了,今天上课正好无聊梳理了一下自己使用pytorch进行官方数据集识别的一个小过程,写下来算是复习一下吧
参考教材:跟李沐学ai文字版教程
使用res18微调CIFAE-10数据集
1. 加载数据集
CIFAR-10数据集,pytorch官方数据集,总共60000个样本,训练样本50000个,测试样本10000个。样本规模:34×34,特点:颜色和大小差异更为明显
1.1 pytorch加载数据集的流程
- Dataset定义数据的格式和数据的变换形式
- Dataloader使用iter形式读入批次数据
1.2 pytorch读入数据和加载的两种方式(这里只用第一种)
- 加载pytorch内置的数据集(MNIST、CIFAR-10之类的)
- 读入自己的数据集,需要自定义Dataset。提供一个初学者理解的项目树叶分类
- (在最高vote代码中完整展示了一个读入加载“自己”的数据集,然后微调res18识别一个较为复杂的数据集的全过程)
加载训练数据集
-
train = True(训练数据)、train = False(测试数据)
-
root = 存储/读取CIFAR10的路径
-
download = True(下载)、false(不下载_保证你的路径下有的话,可以离线进行,不过有云为什么不用云要为难自己的电脑呢,平台好的当我没说)
all_images = torchvision.datasets.CIFAR10(train = True, root="/content/drive/MyDrive/李沐深度学习/13. 计算机视觉/data", download=True)
test_images = torchvision.datasets.CIFAR10(train = False, root="/content/drive/MyDrive/李沐深度学习/13. 计算机视觉/data", download=True)
2. 展示数据集
李沐的课程使用的d2l工具包,没有的话可以换一个(plt.imshow差不多的),安装不了的直接下载那个数据包放在文档上级目录加载就行了
总体展示一下
d2l.show_images([all_images[i][0] for i in range(20)],4,5,scale = 0.8)
mac贴图片太麻烦了,懒得贴了,自己看一下图片长啥样就行了,意思一下
图像的处理
# 使用RGB通道的均值和标准差进行通道的标准化,这个数值先别管是怎么来的,也可以删了,因为我暂时也不知道这是干嘛的捏
normalize = torchvision.transforms.Normalize(
[0.485, 0.456, 0.406], [0.229, 0.224, 0.225]
)
image_size = 224
train_augs = torchvision.transforms.Compose([
torchvision.transforms.RandomHorizontalFlip(),
torchvision.transforms.RandomVerticalFlip(),
torchvision.transforms.Resize(image_size),
# color_aug,
# shape_aug,
torchvision.transforms.ToTensor(),
# 将图像的输入转换为四维张量,格式为
# (批量大小,通道数,高度,宽度)——批量大小也就是输入个数
normalize
])
test_augs = torchvision.transforms.Compose([
torchvision.transforms.Resize(image_size),
torchvision.transforms.ToTensor(),
normalize
])
重点:为数据集使用dataset、dataloader进行加载(root自己改改)
# dataset:train的dataset
# 加载官方数据集的方式:调用torchvision.datasets.相应的数据集
# root(存放路径,没有的话download必须为true)
# train:true_训练集/false_测试集
# transform:图像处理方式
# download:路径没有是否下载
batch_size = 256
train_dataset = torchvision.datasets.CIFAR10(
root="/content/drive/MyDrive/李沐深度学习/13. 计算机视觉/data",train=True,transform=train_augs,download=True)
train_dataloader = torch.utils.data.DataLoader(train_dataset,
batch_size=batch_size,shuffle=True,
num_workers=d2l.get_dataloader_workers(),drop_last=True)
test_dataset = torchvision.datasets.CIFAR10(
root="/content/drive/MyDrive/李沐深度学习/13. 计算机视觉/data",train=False,transform=test_augs,download=True)
test_dataloader = torch.utils.data.DataLoader(test_dataset,
batch_size=batch_size,shuffle=True,
num_workers=d2l.get_dataloader_workers(),drop_last=True)
获取训练img和label(使用的plt.imshow)
import matplotlib.pyplot as plt
image,label = next(iter(train_dataloader))
print(image.shape,label.shape)
plt.imshow(image[0][0])
torch.Size([256, 1, 224, 224])
torch.Size([256])
<matplotlib.image.AxesImage at 0x7f19a043cc10>
详细说明一下pytorch中对于图像的四维张量表示
(cin,channels,h,w)
- cin:输入样本数_256为一个批量大小的图片数
- channels:通道数
- h、w就不用说了(注意,原大小不是这个,直接放入res18需要224×224)
微调
原理:在远超训练样本的一个数据集上训练过的模型参数,即使输出样本与所需训练样本输出样本不相干,其训练参数仍被认为比随机初始化参数更为可靠。ImageNet数据集有超过1000w数据样本和1000类物品,我们实验的数据样本,哪怕是上面推荐的一个叶子分类的数据样本全部远远小于它。
使用微调进行迁移学习的步骤
- 在源数据集(例如ImageNet数据集)上预训练神经网络模型,即源模型。
- 创建一个新的神经网络模型,即目标模型。这将复制源模型上的所有模型设计及其参数(输出层除外)。我们假定这些模型参数包含从源数据集中学到的知识,这些知识也将适用于目标数据集。我们还假设源模型的输出层与源数据集的标签密切相关;因此不在目标模型中使用该层。
- 向目标模型添加输出层,其输出数是目标数据集中的类别数。
- 随机初始化该层的模型参数。在目标数据集(如椅子数据集)上训练目标模型。输出层将从头开始进行训练,而所有其他层的参数将根据源模型的参数进行微调。
pretrained_net.fc
使用记事本编程的可以直接查看使用ImageNet预训练的res18的输出层,out_features为1000,因为ImageNet中有1000类物品
我们的CIFAR-10只有10类物品,因此输出的全连接层应该是10
finetune_net = torchvision.models.resnet18(pretrained=True)
finetune_net.fc = nn.Linear(finetune_net.fc.in_features, 10)
# 初始化输出层的参数,使用简单一点的分布输出也行,在这里影响不大
nn.init.xavier_uniform_(finetune_net.fc.weight)
定义微调函数
# 如果param_group=True,输出层中的模型参数将使用十倍的学习率
def train_fine_tuning(net, learning_rate, batch_size = 256, num_epochs=5,
param_group=True):
train_iter = train_dataloader
test_iter = test_dataloader
devices = d2l.try_all_gpus()
loss = nn.CrossEntropyLoss(reduction="none")
# 这里自己理解。不行的话删了直接用else那里就很简单了
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)
微调res18
train_fine_tuning(finetune_net, 5e-5)