1. DPN网络概述
DPN(Dual Path Network)作为一种深度卷积神经网络,它在ResNet架构的基础上,引入了多个不同层次的特征,大大提升了神经网络的准确率。DPN 网络通过融合不同卷积核大小的特征图,得到更稳定的模型,避免了单一网络结构的过拟合。此外,DPN网络的结构,从旁支结构到中间并联结构,更好地保持了网络的平衡和全局信息的传递,因此具有比ResNet更优秀的表现。
2. PyTorch实现DPN网络
2.1 DPN模型结构
DPN的结构如下图所示:
图1:DPN网络结构
DPN网络由两部分组成:第一部分是一个主干网络,其由多个连续的DPN块组成;第二部分则是全局的平均池化和分类层。各DPN块的结构如下图所示:
图2:DPN块结构
DPN块由两个完全不同的路径组成,从而保持了网络的平衡和全局信息的传递。其中,第一条路径由一个带有1×1卷积的变换层和两个带有3×3卷积的变换层组成;第二个路径则由两个带有1×1和3×3卷积的变换层组成。这两个路径得到的特征图被concat起来,以增加网络的宽度和信息量。
2.2 DPN网络的实现
PyTorch实现DPN网络的代码如下所示,这里展示的是DPN92模型的实现,它依据上述结构,包含3个主要部分:DPN块、DPN主干、DPN分类器。
import torch.nn as nn
class DPNBlock(nn.Module):
def __init__(self, in_channels, mid_channels, out_channels, groups):
super(DPNBlock, self).__init__()
self.conv1x1_1 = nn.Conv2d(in_channels, mid_channels, kernel_size=1)
self.parallel_conv3x3 = nn.Sequential(
nn.Conv2d(mid_channels, mid_channels, kernel_size=3, stride=1, padding=1, groups=groups),
nn.Conv2d(mid_channels, out_channels, kernel_size=1)
)
self.conv1x1_2 = nn.Conv2d(in_channels, out_channels, kernel_size=1)
self.bn = nn.BatchNorm2d(2*out_channels)
self.relu = nn.ReLU(inplace=True)
def forward(self, x):
out = self.conv1x1_1(x)
out = self.parallel_conv3x3(out)
merge = self.conv1x1_2(x)
merge = self.bn(torch.cat([out, merge], dim=1))
return self.relu(merge)
class DPN(nn.Module):
def __init__(self, cfg, in_channels=3, os=32):
super(DPN, self).__init__()
self.os = os
self.in_channels = in_channels
# 前64个通道数为64的标准Block,输出128个
self.conv1 = nn.Conv2d(self.in_channels, 64, kernel_size=3, stride=2, padding=1, bias=False)
self.bn1 = nn.BatchNorm2d(64)
self.relu = nn.ReLU(inplace=True)
self.pool1 = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
# 连续的DPN块
self.layer1 = self._make_layer(cfg[0], 64, 256, 64)
self.layer2 = self._make_layer(cfg[1], 256, 512, 128, stride=2)
self.layer3 = self._make_layer(cfg[2], 512, 1024, 256, stride=2)
self.layer4 = self._make_layer(cfg[3], 1024, 2048, 512, stride=2)
# 分类层
self.avgpool = nn.AvgPool2d(kernel_size=7, stride=1)
self.fc = nn.Linear(2048, 1000)
def forward(self, x):
x = self.conv1(x)
x = self.bn1(x)
x = self.relu(x)
x = self.pool1(x)
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
x = self.layer4(x)
x = self.avgpool(x)
x = self.fc(x)
return x
def _make_layer(self, num_layers, in_channels, mid_channels, out_channels, stride=1):
layers = [DPNBlock(in_channels, mid_channels, out_channels, groups=32)]
for i in range(num_layers-1):
layers.append(DPNBlock(out_channels*2, mid_channels, out_channels, groups=32))
return nn.Sequential(*layers)
def dpn92():
cfg = {
'num_blocks': [3,4,20,3],
'plane': [256,512,1024,2048],
'dpn_groups': 32,
'num_classes': 1000
}
return DPN(cfg, in_channels=3, os=32)
接下来,我们可以使用上述DPN92的网络结构来训练我们的数据集。
3. 总结
DPN网络的提出,思路简单,但取得了很好的效果。它在保持ResNet网络的优点不变的前提下,通过途径结构等技巧,使得网络具有更大的感受野,局部组件的高重复性也实现了融合,为后续深度学习的一系列模型提供了新的思路和实践经验。