torch:1.11.0(使用resnet34和VGG16做特征提取使用的pytorch版本是1.9.1)
在数据集中,以文件名对图片的类型进行划分,我们只需要提取文件名的前3个字符判断其为“dog”或者“cat”便可以对每张图片打上相对应的标签。
参考代码如下:
root_dir="./train"importosfromPILimportImageimgs_name=os.listdir(root_dir)imgs_path=[]labels_data=[]fornameinimgs_name:ifname[:3]=="dog":label=0ifname[:3]=="cat":label=1img_path=os.path.join(root_dir,name)imgs_path.append(img_path)labels_data.append(label)数据集部分图片如下:
为了提高模型的能力,可以使用pytorch自带的Transforms对图片进行处理变换。在训练时,可以对图片进行一定的剪裁,旋转,但是在验证的时候,并不需要进行这些操作。
#对训练图片进行处理变换my_transforms=transforms.Compose([transforms.Resize(75),transforms.RandomResizedCrop(64),#随机裁剪一个area然后再resizetransforms.RandomHorizontalFlip(),#随机水平翻转transforms.ToTensor(),transforms.Normalize(mean=[0.485,0.456,0.406],std=[0.229,0.224,0.225])])#对验证集的图片进行处理变换valid_transforms=transforms.Compose([transforms.Resize((64,64)),transforms.ToTensor(),transforms.Normalize(mean=[0.485,0.456,0.406],std=[0.229,0.224,0.225])])在以下3个模型中,模型接收的输入为(3,64,64)规格的图片。同时在数据增强阶段对图片进行标准化。标准化所使用的std和mean为ImageNet的值。
模型对应的简化图,如下所示:
代码参考如下:
importtorch.nn.functionalasFclassMyNet(nn.Module):def__init__(self):super(MyNet,self).__init__()self.conv1=nn.Sequential(nn.Conv2d(3,32,kernel_size=3),nn.ReLU(),nn.BatchNorm2d(32),nn.MaxPool2d(2,2),nn.Dropout(0.25))self.conv2=nn.Sequential(nn.Conv2d(32,64,kernel_size=3),nn.ReLU(),nn.BatchNorm2d(64),nn.MaxPool2d(2,2),nn.Dropout(0.25))self.conv3=nn.Sequential(nn.Conv2d(64,128,kernel_size=3),nn.ReLU(),nn.BatchNorm2d(128),nn.MaxPool2d(2,2),nn.Dropout(0.25))self.fc=nn.Sequential(nn.Linear(128*6*6,256),nn.Dropout(0.2),nn.Linear(256,2),)defforward(self,x):x=self.conv1(x)x=self.conv2(x)x=self.conv3(x)x=x.view(x.size(0),-1)x=self.fc(x)returnF.log_softmax(x,dim=1)模型二:使用resnet34做特征提取模型二的网络结构的简化图如下所示,resnet34使用的是torchvision中自带的模型,去除最后一层的全连接层,将前面的卷积层用于特征提取。然后将特征提取的结果进行Flatten,输入到全连接层,最终输出预测结果。
参考代码:
#使用Resnet特征resnet=models.resnet34(pretrained=True)modules=list(resnet.children())[:-2]#deletethelastfclayer.res_feature=nn.Sequential(*modules).eval()#训练时,不改变resnet参数#定义网络classMyNet(nn.Module):def__init__(self,resnet_feature):super(MyNet,self).__init__()self.resnet_feature=resnet_featureself.fc=nn.Sequential(nn.Linear(512*2*2,256),nn.Dropout(0.25),nn.Linear(256,2))defforward(self,x):x=self.resnet_feature(x)x=x.view(x.size(0),-1)x=self.fc(x)returnF.log_softmax(x,dim=1)模型三:resnet34&vgg16做特征提取模型三相比较于模型二,使用了两个网络进行特征提取,然后将输出的特征在channel维进行concat,再将concat后的结果输入到全连接层,最终得到预测结果。
#使用VGG特征model=models.vgg16(pretrained=True)vgg_feature=model.features#训练的时候忘记设置vgg模式为eval(),也就是说vgg的参数在训练的时候会发生改变#使用Resnet特征resnet=models.resnet34(pretrained=True)modules=list(resnet.children())[:-2]#deletethelastfclayer.res_feature=nn.Sequential(*modules).eval()importtorch.nn.functionalasFclassMyNet(nn.Module):def__init__(self,resnet_feature,vgg_feature):super(MyNet,self).__init__()self.resnet_feature=resnet_featureself.vgg_feature=vgg_featureself.fc=nn.Sequential(nn.Linear(1024*2*2,256),nn.Dropout(0.25),nn.Linear(256,2))defforward(self,x):x1=self.resnet_feature(x)x2=self.vgg_feature(x)#将特征融合在一起x=torch.cat((x1,x2),1)x=x.view(x.size(0),-1)x=self.fc(x)returnF.log_softmax(x,dim=1)trick在训练时,可以动态的改变学习率,使用pytorch的lr_scheduler在训练的过程中动态修改学习率。