icandle / CAMixerSR

CAMixerSR: Only Details Need More “Attention” (CVPR 2024)
https://arxiv.org/abs/2402.19289
Apache License 2.0
225 stars 13 forks source link

Figure 4 Predicted Mask m Visualization #22

Closed Harrypotter-zhs closed 3 months ago

Harrypotter-zhs commented 4 months ago

作者您好,我想问一下论文中图4的Predicted Mask m 的可视化是怎么实现的?我查看了问题17但是没有解决我的疑问。以及在训练过程和测试过程掩码的使用的方法为啥不一样?在问题17中作者您有说:直接使用掩码与图像直接相乘,这这种方式预设的块的分割方式没有对齐。测试只能是batch_index_select根据mask选择出使用卷积注意力的图像块和自注意力的图像块,然后使用batch_index_fill将两种图像块拼接到一张图像当中。期待作者您的回复。

  if self.training or train_mode:
      N_ = v.shape[1]
      v1,v2 = v*mask, vs*(1-mask)   
      qk1 = qk*mask 
  else:
      idx1, idx2 = mask
      _, N_ = idx1.shape
      v1,v2 = batch_index_select(v,idx1),batch_index_select(vs,idx2)
      qk1 = batch_index_select(qk,idx1)
icandle commented 4 months ago

训练和测试过程中的掩码使用的方法不一样是因为,在训练的时候我们是直接用一个掩码乘上特征图做分类的,而在推理的时候我们这个模块输出的是分割后的一个0-1的logit,问题17中将logit转为掩码的方法没有和我们的切割的方法对齐所以结果不一致,举个不恰当的例子,我们的掩码生成的顺序是先上后下先左后右的,而他恢复得到mask的顺序是先左右后上下的,如下,那这样恢复得到的mask看起来就是随机的。

0 3 6     0 1 2  
1 4 7     3 4 5
2 5 8     6 7 8 
Harrypotter-zhs commented 4 months ago

首先感谢您的耐心回复。 训练阶段生成的掩码中的1和0的数量对应着推理阶段属于idx1与idx2的元素数量,mask中的元素值为1的位置编号也就是对应idx1中元素数值。训练阶段直接用掩码相乘的方式得到0与1的分类结果,在推理阶段根据得到的位置信息idx也能得到相同分类结果,并且结合问题https://github.com/icandle/CAMixerSR/issues/19 只能使用两种方式来使用mask进行遮挡,能否这样理解?

icandle commented 3 months ago

是的,可以这样理解,用idx主要是为了减小推理时候的显存占用,不需要额外存储掩码和特征。

Harrypotter-zhs commented 3 months ago

嗯嗯,再次感谢作者的重视和解答。图4中的Predicted Mask m图(中间列)我不清楚是怎么绘制的,能麻烦作者您讲一下?

icandle commented 3 months ago

简单点说是利用pred_score归一化到0-1的值加上matplotlib的热力图,关键是在于predscore的结果是在-1维度进行的softmax所以都比较接近1,需要在-2维度做一次归一。

Harrypotter-zhs commented 3 months ago

好的,那我尝试做一下,我随后再关闭这个issue。 感谢作者您的解答!

Harrypotter-zhs commented 3 months ago

简单点说是利用pred_score归一化到0-1的值加上matplotlib的热力图,关键是在于predscore的结果是在-1维度进行的softmax所以都比较接近1,需要在-2维度做一次归一。

我还是不太懂这个在dim=-2进行归一化,我使用normalize(pred_score[:, :, 0], dim=2)操作,得到的结果没有为1的结果。我在网上查到了怎么绘制热力图。能否麻烦您再次解答疑惑?

icandle commented 3 months ago

在实际实现的时候,我们用gumbel_softmax是在mask = F.gumbel_softmax(pred_score, hard=True, dim=2)[:, :, 0:1]得到0/1的结果,在输出热力图的时候把这个gumbel_softmax换成dim=2的softmax的得到一个(0,1) tensor,这一步相当于对每一个块做二分类,再对其做dim=1的normalize得到不同块之间横向分数。

Harrypotter-zhs commented 3 months ago

如图所示 Snipaste_2024-07-15_20-39-44 我暂时只能做到形状相似,数值对不上,您说的方法肯定是可以的,我操作不当但是又不知道原因所在。红色的数值是对应idx1中的索引,黑色的数值是对应idx2的索引。

这个是我写的测试
score=F.softmax(pred_score, dim=2)[:,:,0]
print("score",score.shape,score)
score_v2 = F.normalize(score, dim=1) # 所有的值都很相近
print("score_v2",score_v2.shape, score_v2)
score_v2 = rearrange(score_v2,'b (h w) -> b h w', h=18, w=27)
# 这个就是要绘制热力图的内容
score_v2 = score_v2.squeeze(0).cpu().detach().numpy()
print("score_v2",score_v2.shape)

能否加您的联系方式?

icandle commented 3 months ago

可能是归一化有问题,你可以试试以把normalize换成(x-min)/(max-min)看看能不能把数值归一化到0-1,可以加我微信号,icandlewy。

Harrypotter-zhs commented 3 months ago

再次感谢您的重视和耐心解答。 我按照您的指导,进行归一化操作,得到了0-1之间的数值。红色表示注意力计算区域,黑色表示卷积计算区域。数值表示复杂度(复杂内容)。我已申请您的好友。

score_v2 = F.softmax(pred_score, dim=2)[:, :, 0]
print("score_v2",score_v2.shape)
max_score, _ = torch.max(score_v2, dim=1)
min_score, _ = torch.min(score_v2, dim=1)
# score_v2 = F.normalize(score_v2, dim=1)  #              
score_v2 = torch.div(torch.sub(score_v2, min_score), torch.sub(max_score , min_score))
score_v2 = rearrange(score_v2,'b (h w) -> b h w', h=18, w=27)  # 18 = h=H//wsize,27= w=W//wsize

如图所示: Snipaste_2024-07-16_10-25-35