自训练densenet的grad_cam可视化

使用torch自带的densenet,没有经过训练的grad_cam

import json
import os
import numpy as np
import torch
from PIL import Image
import matplotlib.pyplot as plt
from torchvision import models
from torchvision import transforms, models
from pytorch_grad_cam import GradCAM, ScoreCAM, GradCAMPlusPlus, AblationCAM, XGradCAM, EigenCAM, FullGrad
from pytorch_grad_cam.utils.image import show_cam_on_image


def main():
    # ----载入自己的模型,按照自己训练集训练的
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

    model = models.densenet121(pretrained=True)
    # model_weight_path = './model_weight/dense_model.pth'
    # model.load_state_dict(torch.load(model_weight_path, map_location=device))  # 加载权重
    model.eval()
    target_layers = [model.features[-1]]  # 拿到最后一个层结构
    print(target_layers)


    data_transform = transforms.Compose([transforms.ToTensor(),
                                         transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])
    # load image
    img_path = "./data/cat-dog300/dog/dog.11009.jpg"
    assert os.path.exists(img_path), "file: '{}' dose not exist.".format(img_path)
    img = Image.open(img_path).convert('RGB')
    img = np.array(img, dtype=np.uint8)
    # img = center_crop_img(img, 224)

    # [C, H, W]
    img_tensor = data_transform(img)
    # expand batch dimension
    # [C, H, W] -> [N, C, H, W]
    input_tensor = torch.unsqueeze(img_tensor, dim=0)
    # 实例化,输出模型,要计算的层
    cam = GradCAM(model=model, target_layers=target_layers, use_cuda=False)
    # 感兴趣的label
    target_category = 1  # tabby, tabby cat
    # target_category = 254  # pug, pug-dog
    # 计算cam图
    grayscale_cam = cam(input_tensor=input_tensor)  # 实例化
    # 将只传入的一张图的cam图提取出来
    grayscale_cam = grayscale_cam[0, :]
    # 变成彩色热力图的形式
    visualization = show_cam_on_image(img.astype(dtype=np.float32) / 255.,  # 将原图缩放到[0,1]之间
                                      grayscale_cam,
                                      use_rgb=True)
    # 展示出来
    json_path = './class_indices.json'
    assert os.path.exists(json_path), "file: '{}' dose not exist.".format(json_path)
    with open(json_path, "r") as f:
        class_indict = json.load(f)
    plt.title(class_indict[str(target_category)])
    plt.imshow(visualization)
    plt.show()


if __name__ == '__main__':
    main()

17行引入densenet121,28行载入图片,42行这个没什么用,图的题头,任意传了一张图,因为我的.json文件第一个是ants,第二个是bees,所以题头是bees,不影响。这个没有经过训练,关注点不准确很正常。

自训练densenet的grad_cam可视化_第1张图片

导入训练后的权重,对应17、18、19行,这个时候model_weight_path是自己训练出来的权重,加载进去

    model = models.densenet121(pretrained=False)
    model_weight_path = './model_weight/dense_model.pth'
    model.load_state_dict(torch.load(model_weight_path, map_location=device))  # 加载权重
自训练densenet的grad_cam可视化_第2张图片

这个图就很正确了,如果预训练遇到权重不匹配可以参考我另一篇博客

https://mp.csdn.net/mp_blog/creation/editor/127897670

用自己搭建的densenet网络显示热力图出现了一些问题,下面是我的densenet代码,完全正确,可以运行

import re
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.utils.model_zoo as model_zoo
from collections import OrderedDict


model_urls = {
    'densenet121': 'https://download.pytorch.org/models/densenet121-a639ec97.pth',
    'densenet169': 'https://download.pytorch.org/models/densenet169-b2777c0a.pth',
    'densenet201': 'https://download.pytorch.org/models/densenet201-c1103571.pth',
    'densenet161': 'https://download.pytorch.org/models/densenet161-8d451a50.pth',
}


# def densenet121(pretrained=False, **kwargs):
#     r"""Densenet-121 model from
#     `"Densely Connected Convolutional Networks" `_
#     Args:
#         pretrained (bool): If True, returns a model pre-trained on ImageNet
#     """
#     model = DenseNet(num_init_features=64, growth_rate=32, block_config=(6, 12, 24, 16),
#                      **kwargs)
#     if pretrained:
#         # '.'s are no longer allowed in module names, but pervious _DenseLayer
#         # has keys 'norm.1', 'relu.1', 'conv.1', 'norm.2', 'relu.2', 'conv.2'.
#         # They are also in the checkpoints in model_urls. This pattern is used
#         # to find such keys.
#         pattern = re.compile(
#             r'^(.*denselayer\d+\.(?:norm|relu|conv))\.((?:[12])\.(?:weight|bias|running_mean|running_var))$')
#         state_dict = model_zoo.load_url(model_urls['densenet121'])
#         for key in list(state_dict.keys()):
#             res = pattern.match(key)
#             if res:
#                 new_key = res.group(1) + res.group(2)
#                 state_dict[new_key] = state_dict[key]
#                 del state_dict[key]
#         model.load_state_dict(state_dict)
#     return model
#
#
# def densenet169(pretrained=False, **kwargs):
#     r"""Densenet-169 model from
#     `"Densely Connected Convolutional Networks" `_
#     Args:
#         pretrained (bool): If True, returns a model pre-trained on ImageNet
#     """
#     model = DenseNet(num_init_features=64, growth_rate=32, block_config=(6, 12, 32, 32),
#                      **kwargs)
#     if pretrained:
#         # '.'s are no longer allowed in module names, but pervious _DenseLayer
#         # has keys 'norm.1', 'relu.1', 'conv.1', 'norm.2', 'relu.2', 'conv.2'.
#         # They are also in the checkpoints in model_urls. This pattern is used
#         # to find such keys.
#         pattern = re.compile(
#             r'^(.*denselayer\d+\.(?:norm|relu|conv))\.((?:[12])\.(?:weight|bias|running_mean|running_var))$')
#         state_dict = model_zoo.load_url(model_urls['densenet169'])
#         for key in list(state_dict.keys()):
#             res = pattern.match(key)
#             if res:
#                 new_key = res.group(1) + res.group(2)
#                 state_dict[new_key] = state_dict[key]
#                 del state_dict[key]
#         model.load_state_dict(state_dict)
#     return model
#
#
# def densenet201(pretrained=False, **kwargs):
#     r"""Densenet-201 model from
#     `"Densely Connected Convolutional Networks" `_
#     Args:
#         pretrained (bool): If True, returns a model pre-trained on ImageNet
#     """
#     model = DenseNet(num_init_features=64, growth_rate=32, block_config=(6, 12, 48, 32),
#                      **kwargs)
#     if pretrained:
#         # '.'s are no longer allowed in module names, but pervious _DenseLayer
#         # has keys 'norm.1', 'relu.1', 'conv.1', 'norm.2', 'relu.2', 'conv.2'.
#         # They are also in the checkpoints in model_urls. This pattern is used
#         # to find such keys.
#         pattern = re.compile(
#             r'^(.*denselayer\d+\.(?:norm|relu|conv))\.((?:[12])\.(?:weight|bias|running_mean|running_var))$')
#         state_dict = model_zoo.load_url(model_urls['densenet201'])
#         for key in list(state_dict.keys()):
#             res = pattern.match(key)
#             if res:
#                 new_key = res.group(1) + res.group(2)
#                 state_dict[new_key] = state_dict[key]
#                 del state_dict[key]
#         model.load_state_dict(state_dict)
#     return model
#
#
# def densenet161(pretrained=False, **kwargs):
#     r"""Densenet-161 model from
#     `"Densely Connected Convolutional Networks" `_
#     Args:
#         pretrained (bool): If True, returns a model pre-trained on ImageNet
#     """
#     model = DenseNet(num_init_features=96, growth_rate=48, block_config=(6, 12, 36, 24),
#                      **kwargs)
#     if pretrained:
#         # '.'s are no longer allowed in module names, but pervious _DenseLayer
#         # has keys 'norm.1', 'relu.1', 'conv.1', 'norm.2', 'relu.2', 'conv.2'.
#         # They are also in the checkpoints in model_urls. This pattern is used
#         # to find such keys.
#         pattern = re.compile(
#             r'^(.*denselayer\d+\.(?:norm|relu|conv))\.((?:[12])\.(?:weight|bias|running_mean|running_var))$')
#         state_dict = model_zoo.load_url(model_urls['densenet161'])
#         for key in list(state_dict.keys()):
#             res = pattern.match(key)
#             if res:
#                 new_key = res.group(1) + res.group(2)
#                 state_dict[new_key] = state_dict[key]
#                 del state_dict[key]
#         model.load_state_dict(state_dict)
#     return model


class _DenseLayer(nn.Sequential):
    def __init__(self, num_input_features, growth_rate, bn_size, drop_rate):
        super(_DenseLayer, self).__init__()
        self.add_module('norm1', nn.BatchNorm2d(num_input_features)),
        self.add_module('relu1', nn.ReLU(inplace=True)),
        self.add_module('conv1', nn.Conv2d(num_input_features, bn_size *
                        growth_rate, kernel_size=1, stride=1, bias=False)),
        self.add_module('norm2', nn.BatchNorm2d(bn_size * growth_rate)),
        self.add_module('relu2', nn.ReLU(inplace=True)),
        self.add_module('conv2', nn.Conv2d(bn_size * growth_rate, growth_rate,
                        kernel_size=3, stride=1, padding=1, bias=False)),
        self.drop_rate = drop_rate

    def forward(self, x):
        new_features = super(_DenseLayer, self).forward(x)
        if self.drop_rate > 0:
            new_features = F.dropout(new_features,
                                    p=self.drop_rate,
                                    training=self.training
                                    )
        return torch.cat([x, new_features], 1)


class _DenseBlock(nn.Sequential):
    def __init__(self, num_layers, num_input_features, bn_size, growth_rate, drop_rate):
        super(_DenseBlock, self).__init__()
        for i in range(num_layers):
            layer = _DenseLayer(
                num_input_features + i * growth_rate,
                growth_rate,
                bn_size,
                drop_rate
            )
            self.add_module('denselayer%d' % (i + 1), layer)


class _Transition(nn.Sequential):
    def __init__(self, num_input_features, num_output_features):
        super(_Transition, self).__init__()
        self.add_module('norm', nn.BatchNorm2d(num_input_features))
        self.add_module('relu', nn.ReLU(inplace=True))
        self.add_module('conv', nn.Conv2d(num_input_features, num_output_features,
                                          kernel_size=1, stride=1, bias=False))
        self.add_module('pool', nn.AvgPool2d(kernel_size=2, stride=2))


class DenseNet(nn.Module):
    r"""Densenet-BC model class, based on
    `"Densely Connected Convolutional Networks" `_
    Args:
        growth_rate (int) - how many filters to add each layer (`k` in paper)
        block_config (list of 4 ints) - how many layers in each pooling block
        num_init_features (int) - the number of filters to learn in the first convolution layer
        bn_size (int) - multiplicative factor for number of bottle neck layers
          (i.e. bn_size * k features in the bottleneck layer)
        drop_rate (float) - dropout rate after each dense layer
        num_classes (int) - number of classification classes
    """

    def __init__(self, growth_rate=32, block_config=(6, 12, 24, 16),
                 num_init_features=64, bn_size=4, drop_rate=0, num_classes=1000):

        super(DenseNet, self).__init__()

        # First convolution
        self.features = nn.Sequential(OrderedDict([
            ('conv0', nn.Conv2d(3, num_init_features, kernel_size=7, stride=2, padding=3, bias=False)),
            ('norm0', nn.BatchNorm2d(num_init_features)),
            ('relu0', nn.ReLU(inplace=True)),
            ('pool0', nn.MaxPool2d(kernel_size=3, stride=2, padding=1)),
        ]))

        # Each denseblock
        num_features = num_init_features
        for i, num_layers in enumerate(block_config):
            block = _DenseBlock(num_layers=num_layers, num_input_features=num_features,
                                bn_size=bn_size, growth_rate=growth_rate, drop_rate=drop_rate)
            self.features.add_module('denseblock%d' % (i + 1), block)
            num_features = num_features + num_layers * growth_rate
            if i != len(block_config) - 1:
                trans = _Transition(num_input_features=num_features, num_output_features=num_features // 2)
                self.features.add_module('transition%d' % (i + 1), trans)
                num_features = num_features // 2

        # Final batch norm
        self.features.add_module('norm5', nn.BatchNorm2d(num_features))

        # Linear layer
        self.classifier = nn.Linear(num_features, num_classes)

        # Official init from torch repo.
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight)
            elif isinstance(m, nn.BatchNorm2d):
                nn.init.constant_(m.weight, 1)
                nn.init.constant_(m.bias, 0)
            elif isinstance(m, nn.Linear):
                nn.init.constant_(m.bias, 0)

    def forward(self, x):
        features = self.features(x)
        out = F.relu(features, inplace=True)
        out = F.avg_pool2d(out, kernel_size=7, stride=1).view(features.size(0), -1)
        out = self.classifier(out)
        return out


def densenet121(**kwargs):
    model = DenseNet(num_init_features=64, growth_rate=32, block_config=(6, 12, 24, 16), **kwargs)
    return model


if __name__ == '__main__':
    x = torch.randn([2, 3, 224, 224])
    model = densenet121()
    # summary(model, (3, 224, 224))
    print(model(x).size())
    print(model)

但是热力图报错

RuntimeError: mat1 and mat2 shapes cannot be multiplied (1x46080 and 1024x2)

D:\learnapp\pycharm\anaconda\envs\pytorch\python.exe "D:/learnapp/pycharm/PyCharm Community Edition 2022.1.2/code/work1/heatmap.py"
[BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)]
Traceback (most recent call last):
  File "D:/learnapp/pycharm/PyCharm Community Edition 2022.1.2/code/work1/heatmap.py", line 65, in 
    main()
  File "D:/learnapp/pycharm/PyCharm Community Edition 2022.1.2/code/work1/heatmap.py", line 47, in main
    grayscale_cam = cam(input_tensor=input_tensor)  # 实例化
  File "D:\learnapp\pycharm\anaconda\envs\pytorch\lib\site-packages\pytorch_grad_cam\base_cam.py", line 189, in __call__
    targets, eigen_smooth)
  File "D:\learnapp\pycharm\anaconda\envs\pytorch\lib\site-packages\pytorch_grad_cam\base_cam.py", line 74, in forward
    outputs = self.activations_and_grads(input_tensor)
  File "D:\learnapp\pycharm\anaconda\envs\pytorch\lib\site-packages\pytorch_grad_cam\activations_and_gradients.py", line 42, in __call__
    return self.model(x)
  File "D:\learnapp\pycharm\anaconda\envs\pytorch\lib\site-packages\torch\nn\modules\module.py", line 1110, in _call_impl
    return forward_call(*input, **kwargs)
  File "D:\learnapp\pycharm\PyCharm Community Edition 2022.1.2\code\work1\model_dense.py", line 227, in forward
    out = self.classifier(out)
  File "D:\learnapp\pycharm\anaconda\envs\pytorch\lib\site-packages\torch\nn\modules\module.py", line 1110, in _call_impl
    return forward_call(*input, **kwargs)
  File "D:\learnapp\pycharm\anaconda\envs\pytorch\lib\site-packages\torch\nn\modules\linear.py", line 103, in forward
    return F.linear(input, self.weight, self.bias)
RuntimeError: mat1 and mat2 shapes cannot be multiplied (1x46080 and 1024x2)

Process finished with exit code 1

找了半天也没找到哪里不匹配,打开自带的densenet对比,把224行改成下面这样,热力图就可以出来了

        out = F.adaptive_avg_pool2d(out, (1, 1))
        out = torch.flatten(out, 1)

你可能感兴趣的:(python,人工智能,深度学习)