MECLabTUDA / M3d-Cam

MIT License
306 stars 40 forks source link

if my model has multiple output, It happens to error. #13

Closed chengjianhong closed 3 years ago

chengjianhong commented 3 years ago

hi, if my model has multiple output, It happens to error as follows.

   x1_1, x2_1, x3_1,x4_1, encoder_output = self.encode(x)
  File "/homeb/jhcheng/userfolder/workspace/TransBTS-main/models/TransBTS/TransBTS_downsample8x_skipconnection_2.py", line 292, in encode
    x1_1, x2_1, x3_1, x4_1 = self.Unet(x)
  File "/homeb/jhcheng/anaconda3/envs/py37-torch/lib/python3.7/site-packages/torch/nn/modules/module.py", line 731, in _call_impl
    hook_result = hook(self, input, result)
  File "/homeb/jhcheng/anaconda3/envs/py37-torch/lib/python3.7/site-packages/medcam/backends/grad_cam.py", line 38, in forward_hook_
    output = medcam_utils.unpack_tensors_with_gradients(output)
  File "/homeb/jhcheng/anaconda3/envs/py37-torch/lib/python3.7/site-packages/medcam/medcam_utils.py", line 211, in unpack_tensors_with_gradients
    raise ValueError("Cannot unpack unknown data type.")
ValueError: Cannot unpack unknown data type.
Karol-G commented 3 years ago

Hi,

multiple outputs are currently not supported, sorry.

Best Karol

cloudyliy commented 3 years ago

Has your problem been solved? I also encountered a similar problem. Thank you!

cloudyliy commented 3 years ago

hi, if my model has multiple output, It happens to error as follows.

   x1_1, x2_1, x3_1,x4_1, encoder_output = self.encode(x)
  File "/homeb/jhcheng/userfolder/workspace/TransBTS-main/models/TransBTS/TransBTS_downsample8x_skipconnection_2.py", line 292, in encode
    x1_1, x2_1, x3_1, x4_1 = self.Unet(x)
  File "/homeb/jhcheng/anaconda3/envs/py37-torch/lib/python3.7/site-packages/torch/nn/modules/module.py", line 731, in _call_impl
    hook_result = hook(self, input, result)
  File "/homeb/jhcheng/anaconda3/envs/py37-torch/lib/python3.7/site-packages/medcam/backends/grad_cam.py", line 38, in forward_hook_
    output = medcam_utils.unpack_tensors_with_gradients(output)
  File "/homeb/jhcheng/anaconda3/envs/py37-torch/lib/python3.7/site-packages/medcam/medcam_utils.py", line 211, in unpack_tensors_with_gradients
    raise ValueError("Cannot unpack unknown data type.")
ValueError: Cannot unpack unknown data type.

Has your problem been solved? I also encountered a similar problem. Thank you

WAMAWAMA commented 3 years ago

just try this script👍 https://github.com/WAMAWAMA/some_demo/blob/main/medcam_demo4multi_input_output.py @cloudyliy @chengjianhong

from medcam import medcam
import torchvision.models as tvmodels
import torch
import torch.nn as nn
try:
    from wama.utils import show2D
    # https://github.com/WAMAWAMA/wama_medic
    # a medical image precessing toolbox
    flag = True
except:
    flag = False
    pass

def tensor2numpy(tensor):
    return tensor.data.cpu().numpy()

class Net1(nn.Module):
    """
    multi-input & multi-output(多输入多输出模型)
    """
    def __init__(self):
        super().__init__()
        self.backbone = nn.Sequential(*list(tvmodels.resnet50(num_classes=1000, pretrained=False).children())[:-1])
        self.linear1 = nn.Linear(256, 128)
        self.linear2 = nn.Linear(2048+128, 2)
    def forward(self, input):
        """
        :param input1:shape in(x,3,x,x)
        :param input2:shape in(x,256)
        :return:
        """
        inputs1, inputs2 = input
        f1 = torch.squeeze(self.backbone(inputs1),3)
        f1 = torch.squeeze(f1,2)
        f2 = self.linear1(inputs2)
        f3 = torch.cat([f1,f2], 1)
        print(f1.shape, f2.shape, f3.shape)
        return [self.linear2(f3)]*3

class Net2(nn.Module):
    def __init__(self, model):
        """
        "coat" model (外套网络,用来改变输入输出)
        """
        super().__init__()
        self.model = model
        self.input = None
    def get_input(self, input):
        """
        for catching real input(负责导入真正的input)
        :param input:
        :return:
        """
        self.input = input
    def forward(self, inputs):
        """
        modify code to force output shape
        :param inputs: fake input , but shape of the fake_input will be used by medcam
        :param inputs: 假的input,但是形状会被medcam提取,用于reshape返回的attention map
        :return:
        """
        print(inputs.shape)
        if self.input is None:
            raise ValueError('self.input is None')

        out = self.model(self.input)
        return out[0]

# original network (构建原始网络)
input = [torch.ones([2,3,256,256]), torch.ones([2,256])]
model = Net1()
output = model(input)
_ = [print(i.shape) for i in output]

# use the "coat" network to packing the original network (构建外套网络)
model = Net2(model)
model.get_input(input)
output = model(torch.ones([2,3,128,128]))
print(output.shape)

# get layer name (提取层name)
name_list = [name for name,_ in model.named_parameters()]

# get and visualize the attention map (提取 attention map)
conv = name_list[156].split('.weight')[0]
print(conv) # model.backbone.7.2.conv3
model_c = medcam.inject(model, replace = True, label = 0 ,layer = conv)
model_c = medcam.inject(model, replace = True, label = 0)
model_c.get_input(input) # catch real input
attention = model_c(torch.ones([2,2, 1,1]))
print(attention.shape)
if flag:
    show2D(tensor2numpy(torch.squeeze(attention[0, 0, :, :])))

conv = name_list[126].split('.weight')[0]
print(conv) # model.backbone.6.5.conv3
model_c = medcam.inject(model, replace = True, label = 0 ,layer = conv)
model_c.get_input(input) # catch real input
attention = model_c(torch.ones([2,3,128,128]))
print(attention.shape)
if flag:
    show2D(tensor2numpy(torch.squeeze(attention[0, 0, :, :])))

conv = name_list[69].split('.weight')[0]
print(conv) # model.backbone.5.3.conv3
model_c = medcam.inject(model, replace = True, label = 0 ,layer = conv)
model_c.get_input(input) # catch real input
attention = model_c(torch.ones([2,3,128,128]))
print(attention.shape)
if flag:
    show2D(tensor2numpy(torch.squeeze(attention[0, 0, :, :])))
chengjianhong commented 3 years ago

Thanks.