CAM方法獲取顯著圖:基於pytorch的實現

CAM方法獲取顯著圖:基於pytorch的實現

 

轉:CAM實踐:基於pytorch的使用方法
原文地址:https://cloud.tencent.com/developer/article/1370937
非原創,直接copy的網上的,懶得打字,不喜勿噴

1、下載代碼

git clone https://github.com/metalbubble/CAM

文件夾下有一個pytorch_CAM.py的文件,利用這個便可以生成CAM了。
在這裏插入圖片描述

2、具體代碼

(1)導入需要的模塊

import io
import requests
from PIL import Image
from torchvision import models, transforms
from torch.autograd import Variable
from torch.nn import functional as F
import numpy as np
import cv2
import pdb
import json
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

(2)具體代碼詳解

# input image
LABELS_URL = 'https://s3.amazonaws.com/outcome-blog/imagenet/labels.json'
IMG_URL = 'http://media.mlive.com/news_impact/photo/9933031-large.jpg'
# 使用本地的圖片和下載到本地的labels.json文件
# LABELS_PATH = "labels.json"
# networks such as googlenet, resnet, densenet already use global average pooling at the end, so CAM could be used directly.
model_id = 1
# 選擇使用的網絡
if model_id == 1:
 net = models.squeezenet1_1(pretrained=True)
 finalconv_name = 'features' # this is the last conv layer of the network
elif model_id == 2:
 net = models.resnet18(pretrained=True)
 finalconv_name = 'layer4'
elif model_id == 3:
 net = models.densenet161(pretrained=True)
 finalconv_name = 'features'
# 有固定參數的作用,如norm的參數
net.eval()
# 獲取特定層的feature map
# hook the feature extractor
features_blobs = []
def hook_feature(module, input, output):
 features_blobs.append(output.data.cpu().numpy())
net._modules.get(finalconv_name).register_forward_hook(hook_feature)
# 得到softmax weight,
params = list(net.parameters()) # 將參數變換爲列表
weight_softmax = np.squeeze(params[-2].data.numpy()) # 提取softmax 層的參數
# 生成CAM圖的函數,完成權重和feature相乘操作
# CAMs = returnCAM(features_blobs[0], weight_softmax, [idx[0]])
def returnCAM(feature_conv, weight_softmax, class_idx):
 # generate the class activation maps upsample to 256x256
 size_upsample = (256, 256)
 bz, nc, h, w = feature_conv.shape # 獲取feature_conv特徵的尺寸
 output_cam = []
 # class_idx爲預測分值較大的類別的數字表示的數組,一張圖片中有N類物體則數組中N個元素
 for idx in class_idx:
 # weight_softmax中預測爲第idx類的參數w乘以feature_map(爲了相乘,故reshape了map的形狀)
 cam = weight_softmax[idx].dot(feature_conv.reshape((nc, h*w)))
 # 將feature_map的形狀reshape回去
 cam = cam.reshape(h, w)
 # 歸一化操作(最小的值爲0,最大的爲1)
 cam = cam - np.min(cam)
 cam_img = cam / np.max(cam)
 # 轉換爲圖片的255的數據
 cam_img = np.uint8(255 * cam_img)
 # resize 圖片尺寸與輸入圖片一致
 output_cam.append(cv2.resize(cam_img, size_upsample))
 return output_cam
# 數據處理,先縮放尺寸到(224*224),再變換數據類型爲tensor,最後normalize
normalize = transforms.Normalize(
 mean=[0.485, 0.456, 0.406],
 std=[0.229, 0.224, 0.225]
)
preprocess = transforms.Compose([
 transforms.Resize((224,224)),
 transforms.ToTensor(),
 normalize
])
# 通過requests庫獲取圖片並保存,若是本地圖片則只需要設置本地圖片的保存地址,以便後來提取便好
# img_path = "/../..jpg"
# img_pil = Image.open(img_path)
response = requests.get(IMG_URL)
img_pil = Image.open(io.BytesIO(response.content))
img_pil.save('test.jpg')
# 將圖片數據處理成所需要的可用的數據
img_tensor = preprocess(img_pil)
# 處理圖片爲Variable數據
img_variable = Variable(img_tensor.unsqueeze(0))
# 將圖片輸入網絡得到預測類別分值
logit = net(img_variable)
# download the imagenet category list
# 下載imageNet 分類標籤列表,並存儲在classes中(數字類別,類別名稱)
classes = {int(key):value for (key, value)
 in requests.get(LABELS_URL).json().items()}
# # 使用本地的 LABELS_PATH
# with open(LABELS_PATH) as f:
# data = json.load(f).items()
# classes = {int(key):value for (key, value) in data}
# 使用softmax打分
h_x = F.softmax(logit, dim=1).data.squeeze() # 分類分值
# 對分類的預測類別分值排序,輸出預測值和在列表中的位置
probs, idx = h_x.sort(0, True) 
# 轉換數據類型
probs = probs.numpy()
idx = idx.numpy()
# 輸出預測分值排名在前五的五個類別的預測分值和對應類別名稱
for i in range(0, 5):
 print('{:.3f} -> {}'.format(probs[i], classes[idx[i]]))
# generate class activation mapping for the top1 prediction
# 輸出與圖片尺寸一致的CAM圖片
CAMs = returnCAM(features_blobs[0], weight_softmax, [idx[0]])
# render the CAM and output
print('output CAM.jpg for the top1 prediction: %s'%classes[idx[0]])
# 將圖片和CAM拼接在一起展示定位結果結果
img = cv2.imread('test.jpg')
height, width, _ = img.shape
# 生成熱度圖
heatmap = cv2.applyColorMap(cv2.resize(CAMs[0],(width, height)), cv2.COLORMAP_JET)
result = heatmap * 0.3 + img * 0.5
cv2.imwrite('CAM.jpg', result)

(3)生成結果

注意:如果爲了快一點,不使用網絡的圖片以及文件的話,記得更改圖片地址和已下載文件地址!
測試圖片
結果圖片

CAM論文地址:

http://arxiv.org/pdf/1512.04150.pdf
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章