i am trying to generate a heatmap for image depending on weights from last conv layer in pretrained densenet121, but when i try to multiply the weights by the output of model in gives me this error:
“ValueError: operands could not be broadcast together with shapes (1024,) (7,7)”
this is the code :
import os
import torch
import urllib
from PIL import Image
from torchvision import transforms
import numpy as np
import cv2
# load the model
model = torch.hub.load('pytorch/vision:v0.9.0', 'densenet121', pretrained=True)
# or any of these variants
# model = torch.hub.load('pytorch/vision:v0.9.0', 'densenet169', pretrained=True)
# model = torch.hub.load('pytorch/vision:v0.9.0', 'densenet201', pretrained=True)
# model = torch.hub.load('pytorch/vision:v0.9.0', 'densenet161', pretrained=True)
model.eval()
filename = 'dog.jpg'
# get input image and apply preprocessing
input_image = Image.open(filename)
preprocess = transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])
input_tensor = preprocess(input_image)
input_batch = input_tensor.unsqueeze(0)
# output = model(input_batch)
# print(output.shape)
# The output has unnormalized scores. To get probabilities, you can run a softmax on it.
# probabilities = torch.nn.functional.softmax(output[0], dim=0)
# print(probabilities)
named_layers = dict(model.named_modules())
# for layer in named_layers:
# print(layer)
# print(named_layers['features.denseblock4.denselayer16'])
class densenet_last_layer(torch.nn.Module):
def __init__(self, model):
super(densenet_last_layer, self).__init__()
self.features = torch.nn.Sequential(
*list(model.children())[:-1]
)
def forward(self, x):
x = self.features(x)
x = torch.nn.functional.relu(x, inplace=True)
return x
conv_model = densenet_last_layer(model)
# print(conv_model)
input_batch = torch.autograd.Variable(input_batch)
conv_output = conv_model(input_batch)
# print(conv_output.shape)
conv_output = conv_output.cpu().data.numpy()
# conv_output = np.squeeze(conv_output)
# for state in model.state_dict():
# print(state)
weights = model.state_dict()['classifier.weight']
weights = weights.cpu().numpy()
bias = model.state_dict()['classifier.bias']
bias = bias.cpu().numpy()
# print(conv_output.shape)
heatmap = None
for i in range(0, len(weights)):
map = conv_output[0, i, :, :]
if i == 0:
heatmap = weights[i] * map
else:
heatmap += weights[i] * map
# ---- Blend original and heatmap
npHeatmap = heatmap.cpu().data.numpy()
transCrop = 224
imgOriginal = cv2.imread(filename, 1)
imgOriginal = cv2.resize(imgOriginal, (transCrop, transCrop))
cam = npHeatmap / np.max(npHeatmap)
cam = cv2.resize(cam, (transCrop, transCrop))
heatmap = cv2.applyColorMap(np.uint8(255 * cam), cv2.COLORMAP_JET)
img = heatmap * 0.5 + imgOriginal
cv2.imwrite(os.getcwd(), img)
print(model.state_dict()['classifier.weight'])
Based on the error message the heatmap
and imgOriginal
are two numpy arrays in different shapes, which cannot be accumulated:
heatmap = np.random.randn(1024,)
imgOriginal = np.random.randn(7, 7)
img = heatmap * 0.5 + imgOriginal
> ValueError: operands could not be broadcast together with shapes (1024,) (7,7)
so you would have to make sure the heatmap
has the same shape as imgOriginal
(or can be broadcasted).
I’m also unsure, what exactly is happening in these lines of code:
heatmap = weights[i] * map
as it seems you are indexing the weight
matrix of the last linear layer and are multiplying it with a channel of an output activation of a conv layer.
i am trying to generate heatmap but always have corrupted images…i am not sure about the logic of generating CAM but i will explain the steps i do so that if you can please help me…
1-) the first thing i load my trained model then remove the last classification layer from it to get the last conv layer.
2-) then i convert the image to tensor so i can feed it to the last convolutional layer and get the output feature map.
3-) i loop through the weights of classification layer of my trained model and then multiply the classification weights by output feature map.
that was the logic i do…i am not pretty sure it is right because i am new to deep learning and don’t have a lot of experience with it.
i would be very thankful for you help.
here is the code :
import os
import numpy as np
import time
import sys
from PIL import Image
import heatmap_test as ht
import cv2
import torch
import torch.nn as nn
import torch.backends.cudnn as cudnn
import torchvision
import torchvision.transforms as transforms
from densenet import densenet121
from densenet import densenet169
from densenet import densenet201
from densenet import DenseNet
from torchvision.transforms import ToTensor
class densenet_last_layer(torch.nn.Module):
def __init__(self, model):
super(densenet_last_layer, self).__init__()
# remove last classification layer
self.features = torch.nn.Sequential(
*list(model.children())[:-1]
)
def forward(self, x):
x = self.features(x)
x = torch.nn.functional.relu(x, inplace=True)
return x
class DrawHeatmap():
def __init__(self, pathModel, img, pathOutputFile):
model = densenet121(False)
modelCheckpoint = torch.load(pathModel, map_location=torch.device('cpu'))
model.load_state_dict(modelCheckpoint['state_dict'], strict=False)
named_layers = dict(model.named_modules())
model.eval()
weights = None
bias = None
for name, params in model.named_parameters():
print(name)
if name == 'classifier.weight':
weights = params
if name == 'classifier.bias':
bias = params
conv_model = densenet_last_layer(model)
# ---- Initialize the image transform - resize + normalize
normalize = transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
transformList = []
# transformList.append(transforms.Resize(transCrop))
transformList.append(transforms.ToTensor())
# transformList.append(normalize)
transformSequence = transforms.Compose(transformList)
imageData = Image.open(img).convert('RGB')
imageData = transformSequence(imageData)
imageData = imageData.unsqueeze(0)
input_img = torch.autograd.Variable(imageData)
output = conv_model(input_img)
# print(output.shape)
#
# output = output.cpu().data.numpy()
# output = np.squeeze(output)
print(output.shape)
heatmap = None
for i in range(0, len(weights)):
map = output[0, i, :, :]
if i == 0:
heatmap = weights[i] * map
else:
heatmap += weights[i] * map
npHeatmap = heatmap.cpu().data.numpy()
imgOriginal = cv2.imread(img, 1)
imgOriginal = cv2.resize(imgOriginal, (224, 224))
cam = npHeatmap / np.max(npHeatmap)
cam = cv2.resize(cam, (224, 224))
heatmap = cv2.applyColorMap(np.uint8(255 * cam), cv2.COLORMAP_JET)
img = heatmap * 0.5 + imgOriginal
cv2.imwrite(pathOutputFile, img)
pathInputImage = 'C:/Users/mahmo/Desktop/best projects/Stanford Code/cxr-code/00000001_000.png'
pathModel = 'C:/Users/mahmo/Desktop/best projects/Stanford Code/cxr-code/m-25012018-123527.pth.tar'
pathOutputImage = 'C:/Users/mahmo/Desktop/best projects/Stanford Code/cxr-code/heatmap_test.png'
h = DrawHeatmap(pathModel, pathInputImage, pathOutputImage)
# ht.draw_CAM(pathModel, pathInputImage, True)