(1)使用torchvision
import torchvision.models as models
alexnet = models.alexnet(num_classes=1000, pretrained=True)
print(alexnet)
(2)使用pytorch hub
resnet50 = torch.hub.load('pytorch/vision', 'resnet50',pretrained=True)
print(resnet50)
按上述方法打印AlexNet的结构,可以发现AlexNet就是卷积层和池化层的堆叠,每个卷积层后面均紧跟一个ReLU激活函数。
###
AlexNet(
(features): Sequential(
(0): Conv2d(3, 64, kernel_size=(11, 11), stride=(4, 4), padding=(2, 2))
(1): ReLU(inplace=True)
(2): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
(3): Conv2d(64, 192, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
(4): ReLU(inplace=True)
(5): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
(6): Conv2d(192, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(7): ReLU(inplace=True)
(8): Conv2d(384, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(9): ReLU(inplace=True)
(10): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(11): ReLU(inplace=True)
(12): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(avgpool): AdaptiveAvgPool2d(output_size=(6, 6))
(classifier): Sequential(
(0): Dropout(p=0.5, inplace=False)
(1): Linear(in_features=9216, out_features=4096, bias=True)
(2): ReLU(inplace=True)
(3): Dropout(p=0.5, inplace=False)
(4): Linear(in_features=4096, out_features=4096, bias=True)
(5): ReLU(inplace=True)
(6): Linear(in_features=4096, out_features=1000, bias=True)
)
)
注意事项:
(1)nn.Conv2d的调用格式为:
nn.Conv2d(in_channels,out_channels,kernel_size,stride,padding)
其中
kernel_size,stride,padding参数的行列值不相等时,用元组()的形式给出,行列值相等则简写为一个标量即可,如kernel_size = 3
(2)激活函数可简写为nn.ReLU()
(3)AdaptiveAvgPool2d和AdaptiveMaxPool2d 与 MaxPool2d和AvgPool2d的区别在于前者工作独立于接收的输入张量,可以处理不同数据维度的架构
(4) Dropout(0.5)是指每个训练周期内50%的输入张量会被随机地置为0,防止过拟合
(5)BatchNorm是指批归一化,常见于深度残差网络,确保通过网络的每个小批次的均值为0,方差为1,对于浅层网络,BatchNorm的用处不大,但是对于深层网络,BatchNorm可以确保网络中的乘法不会失控,发生梯度消失或爆炸
整体思想:对resnet的整体架构进行微调,在最后加入新的网络模块来替代正常情况下完成ImageNet分类(1000类)的标准线形层。冻结所有的resnet层,训练时只更新新层中的参数,但要从冻结层得到激活值,使我们可以快速地训练新层,同时保留预训练层已经包含的信息。
冻结层的方法即停止梯度累计,方法如下:
from torchvision import models
transfer_model = models.ResNet50(pretrained = True)
for name,param in transfer_model.named_parameters():
param.requires_grad = False
#也可以不冻结BatchNorm层
for name,param in transfer_model.named_parameters():
if('bn' not in name):
param.requires_grad = False
#把最后的分类模块替换为新模块,以检测鱼和猫为例
#pytorch中resnet实现的定义将最后的分类部分存储为一个实例变量fc,因此这里直接替换fc即可(有的模型用的不是fc而是classifier,要加以区分)
transfer_model.fc = nn.Sequential(nn.Linear(transfer_model.fc.in_features,500),nn.ReLU(),nn.Dropout(),nn.Linear(500,2))
学习率(learning rate)是深度学习中最重要的超参数之一,过去通常使用网格搜索技术来穷尽搜索一个学习率值的子集,但这种方法很耗时间。
学习率的经验值为3e-4(即Karpathy常量)
为了找到最佳学习率,可以使用查找学习率的方法:在一个epoch周期内,从一个小的学习率开始,每一个小批次增加到一个更大的学习率直到epoch结束得到最大的学习率,计算每个学习率对应的损失值,然后选出使损失下降最快的学习率。
该过程的实现直接调用fast.ai库中的一个函数如下(注意使用该函数找到最佳学习率后,应提前保存并重新加载模型,恢复到调用find_lr之前的状态,重新初始化优化器,设置最佳学习率,继续进行训练):
find_lr(model, loss_fn, optimizer, init_value, final_value)
差分学习率是指用不同的学习率训练不同的层组,用于对模型预训练层的微调,比如修改resnet模型的优化器(第3层和第4层):
optimizer = optimizer.Adam([{'params':transfer_model.layer4.parameters(),'lr':found_lr/3},
{'params':transfer_model.layer3.parameters(),'lr':found_lr/9}], lr = found_lr)
#由于之前已经冻结全部预训练层,因此这里解冻第3和4层,使这些层的参数再次接受梯度,
unfreeze_layers= [transfer_model.layer3,transfer_model.layer4]
for layer in unfreeze_layer:
for param in layer.parameters():
param.requires_grad = True
(1)调整图像亮度、饱和度、对比度和色调
torchvision.transforms.ColorJitter(brightness=0, contrast=0, saturation=0, hue=0)
(2)水平或垂直翻转图像
torchvision.transforms.RandomHorizontalFlip(p = 0.5)
torchvision.transforms.RandomVerticalFlip(p = 0.5)
(3)随机转换图像灰度
torchvision.transforms.RandomGrayscale(p = 0.1)
(4)随机裁剪
torchvision.transforms.RandomCrop()
torchvision.transforms.RandomResizedCrop()
(5)随机旋转
torchvision.transforms.RandomRotation()
(6)填充
torchvision.transforms.Pad()
(7)仿射变换
torchvision.transforms.RandomAffine()
(8)颜色空间的Lambda转换
#使用Image.convert()函数可以将PIL图像从一个颜色空间转换到另一个颜色空间
def _random_colour_space(x):
output = x.convert("HSV")
return output
#封装成Lambda类
colour_transform = transforms.Lambda(lambda x: _random_colour_space(x))
random_colour_transform = torchvision.transforms.RandomApply([colour_transform])