pytorch提取softmax前的特征并保存为txt文件

pytorch提取softmax前的特征并保存为txt文件

最近这段时间,一直在找一些有用的传统特征想用在我的下一个工作里面,但是发现很难找到一个合适的高维特征来解决手头的问题。然后就想能不能使用深度网络xceptionet,resnet以及densenet等来训练,将全连接层前的输入tensor(一般是1024D或者是2048D,当然多少维的都有)当做深度特征,然后再把这些特征用在后续的one-class SVM以及聚类中。
首先想到,能不能在深度学习的代码里面直接用接后续的操作(one-class SVM以及聚类),使用python实现后续的这些操作,但是这个显然有点难。因为平时习惯了(依赖) 使用MATLAB,直接调用一些工具,可以轻松实现这些目的。所以这时候,另外一条路就是,把想要的tensor保存到txt中输出来,再用MATLAB读取这些txt文件,后续操作就比较容易处理了。
查了一些资料,并进行了一些修改,形成了亲测可用的代码,话不多说先上码,代码后有比较详细的解释,希望能够帮到大家。

# -*- coding: utf-8 -*-
import os, torch, glob
import numpy as np
from torch.autograd import Variable
from PIL import Image  
from torchvision import models, transforms
import torch.nn as nn
import shutil
from densenet import *
features_dir = '/home/yaohaichao/densenet/features/'
 
def extractor(img_path, saved_path, net, use_gpu):
    transform = transforms.Compose([
            transforms.CenterCrop(224),
            transforms.ToTensor()]
    )
    
    img = Image.open(img_path)
    img = transform(img)
    
    x = Variable(torch.unsqueeze(img, dim=0).float(), requires_grad=False)
    if use_gpu:
        x = x.cuda()
        net = net.cuda()
    y = net(x).cpu()
    y = np.array(y)
    #print(y)
    #y = y.data.numpy()
    y = np.around(y, decimals=2)

    np.savetxt(saved_path, y, delimiter='\n')
    
if __name__ == '__main__':
    files_list = []
    files_list.extend(glob.glob(r"/home/yaohaichao/Dataset/TEST_qp10_obb/*.png"))
    
        
    use_gpu = torch.cuda.is_available()
    densenet_feature_extractor = densenet121(num_classes = 1024) #要提前知道你使用的网络在全连接层的输入维度即特征维度
    if use_gpu:
        densenet_feature_extractor = densenet_feature_extractor.cuda()
        densenet_feature_extractor = nn.DataParallel(densenet_feature_extractor)
   
    pretrained_dict = torch.load('/home/yaohaichao/densenet/output/epoch_29.pth')
    model_dict = densenet_feature_extractor.state_dict()
    pretrained_dict = {k: v for k, v in pretrained_dict.items() if k in model_dict}
    del pretrained_dict["module.classifier.weight"]
    del pretrained_dict["module.classifier.bias"]
    model_dict.update(pretrained_dict)
    densenet_feature_extractor.load_state_dict(model_dict)
    densenet_feature_extractor.classifier = nn.Linear(1024, 1024)
    torch.nn.init.eye_(densenet_feature_extractor.classifier.weight)
    
    densenet_feature_extractor.eval()
    for param in densenet_feature_extractor.parameters():
        param.requires_grad = False   

    for x_path in files_list:
        print(x_path)
        fx_path = os.path.join(features_dir, x_path[39:-4] + '.txt')
        extractor(x_path, fx_path, densenet_feature_extractor, use_gpu)

依次将”/home/yaohaichao/Dataset/TEST_qp10_obb/*.png”文件夹下的png图像读取出文件名形成一个list,加载已经训练好的pth模型,这里要注意,我们认为提特征这个过程是在测试阶段的,是在模型训练好了之后,在进行特征的提取。

    pretrained_dict = torch.load('/home/yaohaichao/densenet/output/epoch_29.pth')
    model_dict = densenet_feature_extractor.state_dict()
    pretrained_dict = {k: v for k, v in pretrained_dict.items() if k in model_dict}
    del pretrained_dict["module.classifier.weight"]
    del pretrained_dict["module.classifier.bias"]
    model_dict.update(pretrained_dict)
    densenet_feature_extractor.load_state_dict(model_dict)
    densenet_feature_extractor.classifier = nn.Linear(1024, 1024)

这段代码,是将已有模型加载进来,module.classifier.weight和module.classifier.bias在不同的模型里面也是不一样的,有的是module.fc.bias和module.fc.weight,这跟模型的定义有关系。
比较关键的是下面这两句:

densenet_feature_extractor.classifier = nn.Linear(1024, 1024)
torch.nn.init.eye_(densenet_feature_extractor.classifier.weight)

我们如何将1024的特征向量输出?这里的技巧是,将全连接层设置为1024×1024,并且将全连接层的weight设置成单位矩阵,这就使得这个网络的输出就是我们想要的特征。
如此,直接保存网络的输出就可以了。
注意,由于我要将保存的txt改名与相对应的图片一致,所以这里用了

fx_path = os.path.join(features_dir, x_path[39:-4] + '.txt')

x_path[39:-4]是在整个文件路径的字符串中提取了文件名。

    原文作者:大海潮
    原文地址: https://blog.csdn.net/qq_42815520/article/details/101114685
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞