tensorflow - 如何在pytorch vgg16模型中进行类激活映射?

标签 tensorflow image-processing pytorch conv-neural-network torch

我写了一个pretrained vgg16图像分类模型及其层为

VGG(
  (features): Sequential(
    (0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): ReLU(inplace=True)
    (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (3): ReLU(inplace=True)
    (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (6): ReLU(inplace=True)
    (7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (8): ReLU(inplace=True)
    (9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (11): ReLU(inplace=True)
    (12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (13): ReLU(inplace=True)
    (14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (15): ReLU(inplace=True)
    (16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (17): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (18): ReLU(inplace=True)
    (19): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (20): ReLU(inplace=True)
    (21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (22): ReLU(inplace=True)
    (23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (24): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (25): ReLU(inplace=True)
    (26): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (27): ReLU(inplace=True)
    (28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (29): ReLU(inplace=True)
    (30): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (avgpool): AdaptiveAvgPool2d(output_size=(7, 7))
  (classifier): Sequential(
    (0): Linear(in_features=25088, out_features=4096, bias=True)
    (1): ReLU(inplace=True)
    (2): Dropout(p=0.5, inplace=False)
    (3): Linear(in_features=4096, out_features=4096, bias=True)
    (4): ReLU(inplace=True)
    (5): Dropout(p=0.5, inplace=False)
    (6): Linear(in_features=4096, out_features=1000, bias=True)
  )
)

经过一些最初的小问题,现在工作正常了。我想使用这个模型进行类激活映射 (CAM),以可视化 CNN 输出。我知道,为了做到这一点,我们首先必须获得 vgg16 中最后一个卷积层的激活,然后是最后一个全连接层的权重矩阵,最后取两者的点积。

首先,我使用此代码获取了查询图像的类索引

model.eval()
pred = model(img1.float())
class_idx = torch.argmax(pred).detach().numpy().tolist()
classes[class_idx]

然后我获取了最后一个卷积层激活的输入图像,其大小为torch.Size([1, 512, 14, 14])

last_conv_feat = torch.nn.Sequential(*list(model.features)[:30])
pred_a = last_conv_feat(img1.float())
print(pred_a.shape)

之后,我提取了 vgg16 分类器的全连接层的权重,其形状为 torch.Size([1000, 4096])

model.classifier[6].weight.shape

从这个权重矩阵中,我恢复了相关类别索引的权重参数

w_idx = model.classifier[6].weight[class_idx] # torch.Size([4096])

问题是卷积激活矩阵和全连接层的形状不匹配,一个是[1, 512, 14, 14],另一个是[4096]。如何获取这两个矩阵的点积并​​获得 CAM 输出?

最佳答案

这个特定模型不适合您指出的简单方法。您引用的 CAM 是从最后只有一个线性层的模型中提取的,前面是全局平均池化层,如下所示

features = MyConvolutions(x)
pooled_features = AveragePool(features)
predictions = Linear(pooled_features)

这通常适用于 ResNet 架构或其众多派生之一。因此,我的建议是,除非有特定原因使用 VGG,否则请采用 ResNet 架构。

--------编辑--------

如果您想使用 VGG,有两种选择:

  1. 简单的一个:切断 VGG 的最后三个(线性)层,用 AveragePooling 和单个线性层替换它们,并针对 ImageNet 或您正在使用的任何数据集进行微调。
  2. 通过将 VGG 的最后三层转换为卷积层(即无填充的 4096x512x7x7,然后是 4096x4096x1x1 和 1000x4096x1x1)来近似 CAM,并重新组织参数。整个东西现在只有卷积层,你可以像一个巨大的卷积滤波器一样操作它。唯一的问题:它的输出大小仍然是 1x1。因此,您需要放大图像(尝试放大 2 倍),然后将其与新创建的全卷积网络进行卷积。这将为您提供一个近似的 CAM。

关于tensorflow - 如何在pytorch vgg16模型中进行类激活映射?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62494963/

相关文章:

python - Keras + TensorFlow Realtime 训练图

algorithm - 从 3D 浮雕图像中提取深度图

python - SVD 与 matlab、numpy 和 pytorch

python - SpaCy - ValueError : operands could not be broadcast together with shapes (1, 2) (1,5)

python - 如何在带有gpu的tensorflow安装中处理 `GCC`?

python - 如何解决 "AttributeError: module ' google.protobuf.descriptor' has no attribute '_internal_create_key"?

python - 使用 SIFT OpenCV 处理大图像时出错

python - PyTorch 嵌入层引发 "expected...cuda...but got...cpu"错误

c++ - 在 C++ 中从 Tensorflow 的 .meta 文件加载图形以进行推理

r - R中的滑动窗口函数