2021-11-02

标题类激活图(CAM)实现

参考文章:类激活图(CAM)代码+原理详解【pytorch亲测有效】
在此基础上去除了预测信息。解释都在代码中:

from __future__ import print_function, division
import os
from PIL import Image
import matplotlib.pyplot as plt
import torch
from model_SERes_2 import resnet50
from torchvision import models, transforms
import cv2
import numpy as np
from tqdm import tqdm


device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# 数据处理部分
data_transform = transforms.Compose(
        [transforms.Resize(256),
         transforms.CenterCrop(224),
         transforms.ToTensor(),
         transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])

# 加载模型和权重
model = resnet50(num_classes=30)
weights_path = "./resNet50.pth"
assert os.path.exists(weights_path), "file: '{}' dose not exist.".format(weights_path)
model.load_state_dict(torch.load(weights_path, map_location=device))

# 这部分不怎么懂
def returnCAM(feature_conv, weight_softmax, class_idx):
    bz, nc, h, w = feature_conv.shape  # 1,2048,7,7
    output_cam = []
    for idx in class_idx:  # 若只输出预测概率最大值结果不需要for循环
        feature_conv = feature_conv.reshape((nc, h * w))
        cam = weight_softmax[idx].dot(
            feature_conv.reshape((nc, h * w)).detach().numpy()) # (2048, ) * (2048, 7*7) -> (7*7, ) (n,)是一个数组,既不是行向量也不是列向量
        cam = cam.reshape(h, w)
        cam_img = (cam - cam.min()) / (cam.max() - cam.min())  # Normalize
        cam_img = np.uint8(255 * cam_img)  # Format as CV_8UC1 (as applyColorMap required)
        output_cam.append(cam_img)
    return output_cam


# get weight matrix of full connection
fc_weights = model.state_dict()['fc.weight'].cpu().numpy()  # [2,2048]


model.eval()

"""
对一个文件夹内的图片进行处理
path:当前路径下存放待处理图片的文件夹,图片从1顺序命名
save_img:文件保存文件夹
"""
path = "05"
imgs_list = os.listdir(path)
imgs_list.sort(key=lambda x: int(x[:-4]))
imgs_path = [os.path.join(path, x) for x in imgs_list]
val_bar = tqdm(imgs_path)
save_img = "./save4_picture"
if not os.path.exists(save_img):
    os.mkdir(save_img)

for index, img_path in enumerate(val_bar, start=1):
    # 图片保存路径
    save_path = save_img + "/cam" + str(index) + ".jpg"

    img = Image.open(img_path).convert('RGB')
    img_tensor = data_transform(img).unsqueeze(0)  # [1,3,224,224]
    inputs = img_tensor

    logit = model(inputs)  # [1,2] -> [ 3.3207, -2.9495]
    h_x = torch.nn.functional.softmax(logit, dim=1).data.squeeze()  # tensor([0.9981, 0.0019])
    probs, idx = h_x.sort(0, True)  # sorted in descending order

    probs = probs.cpu().numpy()  # if tensor([0.0019,0.9981]) ->[0.9981, 0.0019]
    idx = idx.cpu().numpy()  # [1, 0]

    # 得到最后一层卷积层
    img_1 = model.conv1(img_tensor)
    img_1 = model.bn1(img_1)
    img_1 = model.relu(img_1)
    img_1 = model.maxpool(img_1)
    img_1 = model.layer1(img_1)
    img_1 = model.layer2(img_1)
    img_1 = model.layer3(img_1)
    features = model.layer4(img_1)

    # features = model.finalconv.cpu().numpy()  # [1,2048,7,7]

    CAMs = returnCAM(features, fc_weights, [idx[0]])  # output the most probability class activate map

    img = cv2.imread(img_path)
    height, width, _ = img.shape  # get input image size
    heatmap = cv2.applyColorMap(cv2.resize(CAMs[0], (width, height)),
                                cv2.COLORMAP_JET)  # CAM resize match input image size
    heatmap[np.where(CAMs[0] <= 100)] = 0
    result = heatmap * 0.3 + img * 0.5  # ratio

    cv2.imwrite(save_path, result)

    val_bar.desc = "done"
    # print("*****done:{index}*****".format(index=index), end="\r")
print()
print("Finishing")

说明

我模型前向传播部分如下,我模型训练好了,在模型中加入self.finalconv = x.detach(),训练好的权重不能用,所以我用如下得到最后一层卷积层。

img_1 = model.conv1(img_tensor)
    img_1 = model.bn1(img_1)
    img_1 = model.relu(img_1)
    img_1 = model.maxpool(img_1)
    img_1 = model.layer1(img_1)
    img_1 = model.layer2(img_1)
    img_1 = model.layer3(img_1)
    features = model.layer4(img_1)

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值