使用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,不影响。这个没有经过训练,关注点不准确很正常。
导入训练后的权重,对应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)) # 加载权重
这个图就很正确了,如果预训练遇到权重不匹配可以参考我另一篇博客
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)