ZF4444 / MMAL-Net

This is a PyTorch implementation of the paper "Multi-branch and Multi-scale Attention Learning for Fine-Grained Visual Categorization (MMAL-Net)" (Fan Zhang, Meng Li, Guisheng Zhai, Yizhao Liu).
250 stars 57 forks source link

如何产生Part images的相关问题 #27

Closed interflow-miao closed 3 years ago

interflow-miao commented 3 years ago

尊敬的作者您好! 首先非常感谢您分享出的优秀成果。我在看您源码的时候,碰到了一点问题。 我在config.py文件中看到了如下信息:

windows info for CUB

N_list = [2, 3, 2]
proposalN = sum(N_list)  # proposal window num
window_side = [128, 192, 256]
iou_threshs = [0.25, 0.25, 0.25]
ratios = [[4, 4], [3, 5], [5, 3],
          [6, 6], [5, 7], [7, 5],
          [8, 8], [6, 10], [10, 6], [7, 9], [9, 7], [7, 10], [10, 7]]

【问题一】 您在论文中提到,part image是通过滑动窗口得到的,我看代码中最后得到的part image大小是用双线性插值到224*224的对吗?那上面的这些参数具体代表什么意思呢?N_list = [2, 3, 2]这个设定我不太理解,既然后面用于非极大值抑制的iou_threshs都是0.25,为什么要分三个?(不知道我理解得对不对)然后ratios是滑动窗的尺寸比例吗?那window_side又是什么呢?

【问题二】 然后关于APPM这块的源码我也读不太懂,可能上述参数的具体含义我理解不清楚导致我读代码的时候碰到比较多的问题,ratios在这里面代表的什么我一直理解不了。能麻烦您帮我注释以下代码的含义吗?非常感谢!! class APPM(nn.Module): def init(self): super(APPM, self).init() self.avgpools = [nn.AvgPool2d(ratios[i], 1) for i in range(len(ratios))]

def forward(self, proposalN, x, ratios, window_nums_sum, N_list, iou_threshs, DEVICE='cuda'):
    batch, channels, _, _ = x.size()
    avgs = [self.avgpools[i](x) for i in range(len(ratios))]

    # feature map sum
    fm_sum = [torch.sum(avgs[i], dim=1) for i in range(len(ratios))]

    all_scores = torch.cat([fm_sum[i].view(batch, -1, 1) for i in range(len(ratios))], dim=1)   #cat拼接张量
    windows_scores_np = all_scores.data.cpu().numpy()   #.cpu()将数据的处理设备从其他设备(如.cuda()拿到cpu上),不会改变变量类型,转换后仍然是Tensor变量。
                                                          # ,t.numpy()将Tensor变量转换为ndarray变量
    window_scores = torch.from_numpy(windows_scores_np).to(DEVICE).reshape(batch, -1)  #torch.from_numpy()方法把数组转换成张量,且二者共享内存,对张量进行修改比如重新赋值,那么原始数组也会相应发生改变。

    # nms
    proposalN_indices = []
    for i, scores in enumerate(windows_scores_np):
        indices_results = []
        for j in range(len(window_nums_sum)-1):
            indices_results.append(nms(scores[sum(window_nums_sum[:j+1]):sum(window_nums_sum[:j+2])], proposalN=N_list[j], iou_threshs=iou_threshs[j],
                                       coordinates=coordinates_cat[sum(window_nums_sum[:j+1]):sum(window_nums_sum[:j+2])]) + sum(window_nums_sum[:j+1]))
        # indices_results.reverse()
        proposalN_indices.append(np.concatenate(indices_results, 1))   # reverse

    proposalN_indices = np.array(proposalN_indices).reshape(batch, proposalN)
    proposalN_indices = torch.from_numpy(proposalN_indices).to(DEVICE)
    proposalN_windows_scores = torch.cat(
        [torch.index_select(all_score, dim=0, index=proposalN_indices[i]) for i, all_score in enumerate(all_scores)], 0).reshape(
        batch, proposalN)

    return proposalN_indices, proposalN_windows_scores, window_scores

再一次感谢您卓越的工作,祝您科研顺利,期待您的回复~
ZF4444 commented 3 years ago

您好: 对于问题一: 1.通过滑动窗口的想法,可以把原始图像划分成许多窗口,为了便于卷积运算,然后将选出的窗口统一缩放成224*244; 2.N_list,window_side还有iou_threshs中的元素是一一对应的,比如,window side为128(在原图上的尺寸)的窗口以0.25为iou阈值选出前两个,ratios里的每一行对应window side里的每个元素所指定大小窗口在特征图上的尺寸,将ratios中的元素乘以网络的output stride 32就是窗口在原图中映射的大小 对于问题二: 1.知道ratios是每个窗口在特征图上的尺寸后,self.avgpools = [nn.AvgPool2d(ratios[i], 1) for i in range(len(ratios))] 便可以理解,就是计算不同尺寸窗口在特征图上的全局平均值

希望我讲清楚了(* ̄︶ ̄)

interflow-miao commented 3 years ago

感谢您的回复! 讲得非常清楚,解决了我的问题!您太棒了,非常感谢~(^▽^)