前文对EfficientNet的结构进行了解析,这里,我们把这个结构添加到Yolact中去。
模型源码已经上传,托管在github,直接下载即可,https://github.com/SpaceView/Yolact_EfficientNethttps://github.com/SpaceView/Yolact_EfficientNet
附带说明一下,添加不同Backbone时,最重要的就是要理解Yolact的结构,把Feature_map和FPN的连接弄清楚就没问题了。
在上文介绍EfficientNet时,各个输出层的结构是这样的,
self.channels == > [16, 24, 40, 112, 320] self.output_layers == > [0, 2, 4, 10, 15]
在我们的这个EfficientNet Backbone中,采用的正是这个结构。
其feature的输出结构是这样的(假设输入图片尺寸512x512),
p5.shape -- > torch.Size([1, 320, 16, 16]) p4.shape -- > torch.Size([1, 112, 32, 32]) p3.shape -- > torch.Size([1, 40, 64, 64]) p1.shape -- > torch.Size([1, 24, 128, 128]) p0.shape -- > torch.Size([1, 16, 256, 256])
在Yolact中,初次运行时假设图片被调整成550x550的尺寸;
因此,一张 x.shape == > torch.Size([1, 3, 550, 550]) 的图片,通过efficientnet生成的feature_maps的结构如下
feature_maps[0].shape == > torch.Size([1, 16, 275, 275]) feature_maps[1].shape == > torch.Size([1, 24, 138, 138]) feature_maps[2].shape == > torch.Size([1, 40, 69, 69]) feature_maps[3].shape == > torch.Size([1, 112, 35, 35]) feature_maps[4].shape == > torch.Size([1, 320, 18, 18])
因为只采用了最后3层,所以,最后feature_maps的输出是这样的
feature_maps[0].shape torch.Size([1, 40, 69, 69]) feature_maps[1].shape torch.Size([1, 112, 35, 35]) feature_maps[2].shape torch.Size([1, 320, 18, 18])
这三层就是源码中的selected_layers。输入给FPN的通道数由backbone.channels给出。
最近实在太忙了,后面的有时间再补充说明吧,源码已经上传了。
使用预训练的模型目前还没有测试,在原来的代码中,这里(Cannot download backbone weights · Issue #48 · zylo117/Yet-Another-EfficientDet-Pytorch · GitHub)提到,不能使用原来efficientnet的权重文件,例如efficientnet-b0-355c32eb.pth的权重文件。
因此,我的办法是,将Yolact运行一下,比如我用了100个iteration,然后把这个文件保存下来,也就是 yolact_EfficientNet_0_100.pth,然后,用这个保存下来的文件中的keys,替换掉原来efficientnet-b0-355c32eb.pth 中的keys,生成一个新的 efficientnet-b0-yolact 的权重文件,这样,就可以直接加载 efficientnet-b0-yolact 到模型中初始化这个Backbone的权重了。
具体如何替换请参考:match_and_rename_efficientnet_dict_keys.py
我在替换时还生成了2个keys的文本文件,如下,大家可以打开比较一下,具体差别在哪里。 efficientnet-b0_keys.txt yolact_EfficientNet_bacbone_keys.txt