对于提取网络模型特征中的某一层特征的方法有多种多样,其实都很容易想到,只是作者在学习的过程中是0基础的python,很多地方都看不懂,因此特意写下一篇关于特征提取的通用方法,以备大家少踩点坑:
提取网络模型中的某一层特征,最简单的方法就是在构建网络模型的时候处理,在调用该模型的时候将特征值输出即可。
上代码:
1 class Vgg16Model_pretrain(nn.Module): 2 def __init__(self,vgg16 = vgg16_default): 3 super(Vgg16Model_pretrain, self).__init__() 4 ##vgg16的特征提取层 5 self.features = vgg16.features 6 ## 添加新的全连接层 7 self.classifier = nn.Sequential( 8 nn.Linear(25088, 512), 9 nn.ReLU(), 10 nn.Dropout(p=0.5), 11 nn.Linear(512, 256), 12 nn.ReLU(), 13 nn.Dropout(p=0.5), 14 nn.Linear(256, vgg16numcluss), 15 nn.Softmax(dim=1) 16 ) 17 ## 定义网络的向前传播路径 18 def forward(self, x): 19 x = self.features(x) 20 x = x.view(x.size(0), -1) 21 output = self.classifier(x) 22 output_fea=self.classifier[:2](x) 23 return output,output_fea
比如这个我通过传入的vgg16_default(第二行)网络(官方标准的vgg16网络结构,这里是为了加快训练网络模型而是用的预训练好的),只需要他的features层(有31层)
分类层由自己定义*添加,我这里输出分类数目是vgg16numcluss,
关键地方:在forward中的输出,可以*选定指定层次的输出,这里我多了一个output_fea的输出,其意义是输出分类层的第二层的高层特征(Relu),如果说想输出中层特征,也可以依照次方法填加一个中间变量,令y = self.features[:30](x)这样,就可以输出features层的第30层特征。
如何使用:
在提取代码中:
见16行,输出的第二个变量即为所得到的高层特征。
这里,对图像的预处理有归一化这一操作,其中的方差和平均值是对测试集计算得到的。
1 test_data_transforms = transforms.Compose([ 2 # transforms.Resize(256), # 重置图像分辨率 3 transforms.ToTensor(), 4 # transforms.CenterCrop(IMAGE_SIZE), 5 transforms.Normalize([0.468636,0.470129,0.416165],[0.065697,0.060791,0.054082]) # 图像标准化处理 6 # [0.468636,0.470129,0.416165],[0.065697,0.060791,0.054082] 7 ]) 8 # 提取特征 9 def extract_feature(model, imgpath): 10 transform = test_data_transforms # 获取测试集所使用的transforms 11 model.to(device) # 加载到gpu 12 img = Image.open(imgpath) # 13 img = img.resize((224, 224)) # 该两个步骤是对图片处理,可以舍去,因为transforms会对其处理 14 tensor = transform(img).to(device) 15 tensor = tensor.resize_(1, 3, 224, 224) 16 _,result = model(Variable(tensor)) 17 result_tensor = result.data.cpu() # 转化回cpu的tensor类型 18 return result_tensor[0]