Pytorch输出网络中间层特征可视化 您所在的位置:网站首页 神经网络可视化图 Pytorch输出网络中间层特征可视化

Pytorch输出网络中间层特征可视化

2024-06-02 07:53| 来源: 网络整理| 查看: 265

Pytorch输出网络中间层特征可视化

本文主要介绍了如何提取特定层的特征,然后对它进行可视化。最后给出了不同网络的应用案例。 推荐一个GITHUN实现可视化的工具地址

整体步骤 加载已经预训练好的模型使用单张图片作为输入针对想要查看的特征提取层记录结果网络中的特征提取结果的shape为batch_size, filter_nums, H, W, 因此要使用transpose函数对其维度进行转换将tensor转为numpy, 然后根据预处理中transform进行的操作将逆操作后得到[0,1]区间的图像将得到的filter_nums张图片拼接后输出 案例1: 自定义的模型(可修改forward) 1. 存储特征提取结果

没有听说过SiameseNetwork不重要,只需要知道如何暂存特征的结果并输出即可 最简单的做法就是在forward函数当中截取想要的结果并存储 下面给出网络的结构

class SiameseNetwork(nn.Module): def __init__(self): super().__init__() self.cnn1 = nn.Sequential( nn.ReflectionPad2d(1), nn.Conv2d(1, 4, kernel_size=3), nn.ReLU(inplace=True), nn.BatchNorm2d(4), nn.ReflectionPad2d(1), nn.Conv2d(4, 8, kernel_size=3), nn.ReLU(inplace=True), nn.BatchNorm2d(8), nn.ReflectionPad2d(1), nn.Conv2d(8, 8, kernel_size=3), nn.ReLU(inplace=True), nn.BatchNorm2d(8), ) self.fc1 = nn.Sequential( nn.Linear(8 * 100 * 100, 500), nn.ReLU(inplace=True), nn.Linear(500, 500), nn.ReLU(inplace=True), nn.Linear(500, 5)) self.fc2 = torch.nn.Linear(5, 1) def forward_once(self, x, type=1): output = self.cnn1(x) if type == 1: self.featuremap1 = output else: self.featuremap2 = output output = output.view(output.size()[0], -1) output = self.fc1(output) return output def forward(self, input1, input2): output1 = self.forward_once(input1, 1) output2 = self.forward_once(input2, 2) x = torch.abs(output1 - output2) x = self.fc2(x) return x

我们需要可视化的通常是卷积之后的结果, 也就是CNN层的输出, 因此这里将self.cnn1(x)的结果存储到了self.featuremap当中 核心代码如下, 其中的type 是什么不重要,与该网络的应用有关。

if type == 1: self.featuremap1 = output else: self.featuremap2 = output 2. 加载模型,输入单组图片

SiameseNetwork的输入需要有两张图片, 这里我将其封装为一个函数

其中关键的代码都已经给出了注释

net = SiameseNetwork() # 定义模型 net.load_state_dict(torch.load(f'net30.pth')) # 加载与训练好的模型 transform_test = transforms.Compose([transforms.Resize((100, 100)), transforms.ToTensor()]) # 定义预处理操作 def test_one(path1, path2): '''单对图片测试''' img1 = Image.open(path1).convert('L') img2 = Image.open(path2).convert('L') img_tensor1 = transform_test(img1) img_tensor2 = transform_test(img2) img_tensor1.unsqueeze_(0) # 给tensor添加一个维度,模拟为batch=1 img_tensor2.unsqueeze_(0) output = net(img_tensor1, img_tensor2) # 单组图片进入网络得到结果 feature_output1 = net.featuremap1.transpose(1, 0).cpu() feature_output2 = net.featuremap2.transpose(1, 0).cpu() feature_out1 = torchvision.utils.make_grid(feature_output1) feature_out2 = torchvision.utils.make_grid(feature_output2) feature_imshow(feature_out1, 'feature_out1') feature_imshow(feature_out2, 'feature_out2') # euclidean_distance = F.pairwise_distance(output1, output2) euclidean_distance = torch.sigmoid(output) concatenated = torch.cat((img_tensor1, img_tensor2), 0) imshow(torchvision.utils.make_grid(concatenated), 'Similarity: {:.2f}'.format(euclidean_distance.item()))

下面对提取特征的函数给出具体介绍,使用net.featuremap1操作来获取特征, 这里的featuremap1 也对应了我之前存储时候的self.featuremap1

transpose(1, 0).cpu() 是因为此时的特征为torch.Size([1, 8, 100, 100]) , 也就是(batch_size, filter_nums, H, W) 转换后才能方便输出

feature_output1 = net.featuremap1.transpose(1, 0).cpu() feature_output2 = net.featuremap2.transpose(1, 0).cpu()

下面的代码是将若干幅图像拼成一幅图像, 在本文中feature_output有8张图片, 具体可以去百度搜torchvision.utils.make_grid功能

feature_out1 = torchvision.utils.make_grid(feature_output1) feature_out2 = torchvision.utils.make_grid(feature_output2)

最重要的可视化函数是feature_imshow

首先读入inp, 转换为plt期望的格式 因为本文使用的transform没有针对mean和std进行处理, 传入的图像默认是在(0,1)之间的,所以这里不用进行逆操作,后文的其他案例会给出这种情况的解决办法。 np.clip(inp, 0, 1) 将小于0的像素都变为0,大于1的像素都变为1 不然会产生如下报错信息

Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).

剩下 的就是简单的plt展示了,也没什么好解释的。

def feature_imshow(inp, title=None): """Imshow for Tensor.""" inp = inp.detach().numpy().transpose((1, 2, 0)) # 将通道数放在最后一维 inp = np.clip(inp, 0, 1) plt.imshow(inp) if title is not None: plt.title(title) plt.pause(0.001) # pause a bit so that plots are updated 3. 中间层特征结果

这里做的是汉字的比对,输入图片, 下图是经过特征提取之后的结果,清晰的学习到了汉字的特征。 在这里插入图片描述 在这里插入图片描述

案例2: torchvision.models中的预训练模型

详细的流程已经在上面讲了, 这里就给出此类pretrain过的模型应该如果输出中间结果的思路, 以inceptionV3为例

1.加载模型

这种模型可以直接从models自带的类中下载

model = models.inception_v3(pretrained=True, aux_logits=False)

在这里插入图片描述

2. 便利模型

可以采用下面代码的方式来便利网络, 不过这种方式通常在forwad中进行

for name, layer in model.named_modules(): if 'conv' in name: print(layer)

拓展: 通过下面这种简单的方式就可以将卷积层的结构都保存下来

out_put = [] for name, layer in model.named_modules(): x = layer(x) if 'conv' in name: out_put.append(layer(x))

在这里插入图片描述

for name, layer in model.named_modules(): if name == '0': feature_layer = nn.Sequential(*list(layer.children())[:2]) print(feature_layer)

这里通过*list(layer.children())[:2]来对网络解包,选取想要的部分 在这里插入图片描述 因为这里是网络的第一层,因此可以直接拿来使用, 如果你想要网络的后面某层中的卷积操作,需要保证前面的过程也完整的进行下来。

3. 可视化中间特征

因为本案例中的transforms我才去了自定义mean和std来进行Normalize

tf = transforms.Compose([ transforms.Resize(299), transforms.RandomRotation(15), transforms.CenterCrop(resize), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ])

因此在feature_imshow函数中我们可以利用mean和std来对图像归一化, 得到更好的呈现结果。

def feature_imshow(inp, title=None): inp = inp.detach().numpy().transpose((1, 2, 0)) mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225] inp = std * inp + mean inp = np.clip(inp, 0, 1) plt.imshow(inp) if title is not None: plt.title(title) plt.axis('off') plt.pause(0.001) # pause a bit so that plots are updated plt.clf()

输入图像 在这里插入图片描述 中间特征(这里没有专门训练过,仅仅拿pretrain的来跑) 在这里插入图片描述



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有