Pytorch有很多方便易用的包,今天要谈的是torchvision包,它包括3个子包,分别是: torchvison.datasets ,torchvision.models ,torchvision.transforms ,分别是预定义好的数据集(比如MNIST、CIFAR10等)、预定义好的经典网络结构(比如AlexNet、VGG、ResNet等)和预定义好的数据增强方法(比如Resize、ToTensor等)。这些方法可以直接调用,简化我们建模的过程,也可以作为我们学习或构建新的模型的参考。
1. 直接加载预训练模型 1 2 3 4 import torchvision.models as models resnet50 = models.resnet50(pretrained=True )
这样就导入了Resnet50的预训练模型了,如果只要网络结构,不需要预训练的参数来初始化,就填FALSE
值得注意的是,当你将模型设置为预训练模式的时候,模型输入的图片最好是经过相同方式归一化的3通道数据,即(3* H* W)H与W至少是224,图像必须被加载到(0,1)的范围内,然后再归一化到mean = [0.485, 0.456, 0.406]且std=[0.229,0.224,0.225]。可以使用pytorch自带的归一化函数
normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) Pytorch加载模型后,模型有两个状态,model.train()or model.eval()
当你在训练模型的时候,将模型置为model.train()
当你在测试模型的时候,将模型置为 model.eval(),设置为此种模式的时候,模型内部的权值不会改变.
2. 修改某一层 修改之后的模型的参数一般是默认初始化好了的,均值为0方差为1
1 2 3 4 5 6 7 以resnet为例,默认的是ImageNet的1000 类,比如我们要做二分类,分类猫和狗 resnet.fc = nn.Linear(2048 , 2 ) resnet 第一层卷积的卷积核是7 ,我们可能想改成5 ,那么可以通过以下方法修改: resnet.conv1 = nn.Conv2d(3 , 64 ,kernel_size=5 , stride=2 , padding=3 , bias=False )
如果是只想修改Resnet中的最后一层FC
1 2 3 4 5 6 7 8 9 import torchvision.models as models model = models.resnet50(pretrained=True ) fc_features = model.fc.in_features model.fc = nn.Linear(fc_features, 9
如果是想修改Densenet中的分类器,可以通过获得原模型中该层的名字来进行修改
如果层在sequential中。因为sequential类型没有定义setitem ,只有getitem 所以不能直接获取某一层并进行修改。就是sequential[0]=nn.Linear(fc_features, 9)是会报错的。
1 2 3 self.densenet161 = models.densenet161(pretrained=True ) self.densenet161.classifier = torch.nn.Linear(2208 , 4 )
可以自己对初始化方式做修改:
1 2 3 self.fc_loc[2 ].weight.data.zero_() self.fc_loc[2 ].bias.data.copy_(torch.tensor([1 , 0 , 0 , 0 , 1 , 0 ], dtype=torch.float))
3.加载部分预训练模型,可用于修改现有模型的结构 新定义的网络不能和pretrained的网络有相同名字的层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 对于具体的任务,很难保证模型和公开的模型完全一样,但是预训练模型的参数确实有助于提高训练的准确率,为了结合二者的优点,就需要我们加载部分预训练模型。 resnet50 = models.resnet50(pretrained=True ) model =Net(...) pretrained_dict =resnet50.state_dict() model_dict = model.state_dict() pretrained_dict = {k: v for k, v in pretrained_dict.items() if k in model_dict} model_dict.update(pretrained_dict) model.load_state_dict(model_dict) for p in freeze.parameters(): p.requires_grad = False for p in no_freeze.parameters(): p.requires_grad = True optimizer.SGD(filter(lambda p: p.requires_grad, model.parameters()), lr=1e-3 ) optim_param = [] for p in freeze.parameters(): p.requires_grad = False for p in no_freeze.parameters(): p.requires_grad = True optim_param.append(p) optimizer.SGD(optim_param, lr=1e-3 )
删除原本模型中的层,并添加新层:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Net (nn.Module) : def __init__ (self , model) : super(Net, self).__init__() self.resnet_layer = nn.Sequential(*list(model.children())[:-2 ]) self.transion_layer = nn.ConvTranspose2d(2048 , 2048 , kernel_size=14 , stride=3 ) self.pool_layer = nn.MaxPool2d(32 ) self.Linear_layer = nn.Linear(2048 , 8 ) def forward (self, x) : x = self.resnet_layer(x) x = self.transion_layer(x) x = self.pool_layer(x) x = x.view(x.size(0 ), -1 ) x = self.Linear_layer(x) return x
加载自己的模型
其实这个是保存和恢复模型,比如我们训练好的模型保存,然后加载用于测试。
方法一(推荐):
第一种方法也是官方推荐的方法,只保存和恢复模型中的参数。
使用这种方法,我们需要自己导入模型的结构信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 (1 )保存 torch.save(model.state_dict(), PATH) torch.save(resnet50.state_dict(),'ckp/model.pth' ) (2 )恢复 model = ModelClass(*args, **kwargs) model.load_state_dict(torch.load(PATH)) resnet=resnet50(pretrained=True ) resnet.load_state_dict(torch.load('ckp/model.pth' ))
方法二:
1 2 3 4 5 6 7 8 使用这种方法,将会保存模型的参数和结构信息。 (1 )保存 torch.save (model, PATH) (2 )恢复 model = torch.load(PATH)
模型训练知识点:
with torch.no_grad()
:PyTorch 将不再计算梯度,这将使得模型 forward 的时候,显存的需求大幅减少,速度大幅提高 。一般用在测试的时候。
4. 微调FineTune 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import torch.optim as optimimport torch.nn as nnmodel = torchvision.models.resnet18(pretrained=True ) for param in model.parameters(): param.requires_grad = False model.fc = nn.Linear(512 , 100 ) optimizer = optim.SGD(model.fc.parameters(), lr=1e-2 , momentum=0.9 ) ignored_params = list(map(id, model.fc.parameters())) base_params = filter(lambda p: id(p) not in ignored_params,model.parameters()) optimizer = optim.SGD([ {'params' : base_params}, {'params' : model.fc.parameters(), 'lr' : 1e-3 } ], lr=1e-2 , momentum=0.9 )