You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python实现Grad-CAM时批量循环报错:TypeError类型错误排查

Grad-CAM实现中的批量遍历错误解决

问题背景

我正在尝试实现Grad-CAM方法,代码如下:

for idx, (data, target, meta) in enumerate(tqdm(dataloader_test)):
        print('idx', idx)
        data, target = map(lambda x: x.to(device), (data, target))
        output = model(data)
        output[:,5].sum().backward()
        grads=grad[0].cpu().data.numpy().squeeze()
        fmap=activation[0].cpu().data.numpy().squeeze()
        tmp=grads.reshape([grads.shape[0],-1])
        # Get the mean value of the gradients of every featuremap
        weights=np.mean(tmp,axis=1)
        cam = np.zeros(grads.shape[1:])
        for i,w in enumerate(weights):
            cam += w*fmap[i,:]
        #relu
        cam=(cam>0)*cam
        #cam = np.maximum(cam, 0)
        #print("cam.shape",cam.shape)
        #normalize heatmap
        cam=cam/cam.max()*224
        
        
        for data in range(idx):
            #print('shape data', data.size)
            npic = np.array(torchvision.transforms.ToPILImage()(data).convert('RGB'))
            cam = cv2.resize(cam,(npic.shape[1], npic.shape[0]))
            heatmap=cv2.applyColorMap(np.uint8(cam),cv2.COLORMAP_JET)
            cam_img=npic*0.7+heatmap*0.3
            print(cam_img.shape)
            cv2.imwrite('./visualize/map'+str(count)+'.jpg', cam_img)
            count = count + 1

运行时触发错误:

raise TypeError(f"pic should be Tensor or ndarray. Got {type(pic)}.")

TypeError: pic should be Tensor or ndarray. Got <class 'int'>.

我认为问题出在批量数据的遍历方式上,无法正确获取需要处理的样本,求解决思路。


解决思路

1. 核心错误定位

内层循环for data in range(idx)完全覆盖了外层的data批量张量,这里的data变成了从0到idx-1的整数,传给torchvision.transforms.ToPILImage()时自然不符合输入要求(需要张量或数组),导致类型错误。

2. 正确的批量样本遍历方式

要处理当前batch中的每个样本,有两种正确方式:

方式一:直接遍历批量张量

# 替换原内层循环
for sample in data:
    # 将单个样本张量转为PIL图像再转numpy数组
    npic = np.array(torchvision.transforms.ToPILImage()(sample).convert('RGB'))
    # 复制原始CAM避免后续修改影响其他样本
    current_cam = cv2.resize(cam, (npic.shape[1], npic.shape[0]))
    heatmap = cv2.applyColorMap(np.uint8(current_cam), cv2.COLORMAP_JET)
    cam_img = npic * 0.7 + heatmap * 0.3
    # 转成uint8格式再保存
    cv2.imwrite(f'./visualize/map{count}.jpg', np.uint8(cam_img))
    count += 1

方式二:按索引遍历批量张量

# 替换原内层循环
for i in range(data.shape[0]):
    sample = data[i]
    npic = np.array(torchvision.transforms.ToPILImage()(sample).convert('RGB'))
    current_cam = cv2.resize(cam, (npic.shape[1], npic.shape[0]))
    heatmap = cv2.applyColorMap(np.uint8(current_cam), cv2.COLORMAP_JET)
    cam_img = npic * 0.7 + heatmap * 0.3
    cv2.imwrite(f'./visualize/map{count}.jpg', np.uint8(cam_img))
    count += 1

3. 额外优化点

  • 单样本独立CAM计算:当前代码中output[:,5].sum().backward()是对整个batch的类别5求和后反向传播,得到的是batch内所有样本的平均梯度。如果需要为每个样本生成独立的CAM,需要循环每个样本单独计算:
    for i in range(data.shape[0]):
        model.zero_grad()  # 每次反向传播前清零梯度
        output = model(data)
        output[i, 5].backward()  # 仅对第i个样本的类别5求导
        # 提取梯度、特征图、计算当前样本的CAM...
        # 后续可视化逻辑...
    
  • 避免CAM变量污染:每次处理样本时复制原始CAM,不要直接修改全局的cam变量,防止后续样本使用被resize后的CAM。
  • 图像保存格式修正:cam_img是浮点数数组,转成np.uint8后再保存,避免颜色失真。

内容的提问来源于stack exchange,提问作者peony

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 14:17:00