Fork me on GitHub

DeepLab简介及其pytorch实现

different_rate

本文实现了使用pytorch搭建DeepLab。算是第一批采用Pytorch的吧,到目前为止,网上还没有类似的实现。

DeepLab简介

DeepLab文章的下载地址:https://arxiv.org/abs/1606.00915

该文章的主要思想之一:
提出了Atrous convolution(带孔卷积)。
扩大视野但不增加计算量。

所谓的带孔卷积,就是在卷积核之间加上0。rate参数为2(torch中对应的参数为dilation)的示意图如下
Atrous convolution(rate=2)

rate = 2就是在原卷积核相邻两个元素之间补上一个0,假设原卷积核为3x3,rate = 2的带孔卷积核的大小就为3+(3-1) × (rate-1)=5

下图是不同rate的带孔卷积。

different_rate

rate = 12 为例,带孔卷积的核的大小为:3+(3-1)x(12-1)=25,即新卷积核的大小为:25*25

总的来说,对于rate=r的带孔卷积,在连接着的卷积核元素间插入r-1个元素。因此,扩展后的卷积核大小为$k_{new}=k+(k-1)(r-1)$。

pytorch实现deeplab

笔者主要目的是实现一下不同视野的concat过程。

在torch中,卷积函数如下:

1
2
import torch.nn as nn
nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)

其中的dilation参数就是带孔卷积的参数(也就是tensorFlow下的rate),默认情况下为1,就是普通的卷积,所以带孔卷积只需要修改这个参数就可以了。

比如说,我们已经写好了不同的视野下的卷积,然后需要将他们的feature map叠加起来,torch中使用torch.cat(inputs, dimension=0)函数来进行叠加。torch的参数一般是四个维度的:[n_batch_size, n_feature_map, height, weight],所以参数中的dimension = 1就是对feature map叠加。代码如下:

1
x = torch.cat([x2, x3, x4, x5], dim=1)

叠加的这一步非常容易出错,原因在于,要求叠加的所有图片大小是一样的。而视野不同导致的卷积核的大小不同,也会导致最终输出的图像大小的变化,因此,需要恰当的调整zero-padding的数目来使得最终输出图像的大小保持一致。

另外稍微提一下,全连接层的输入向量大小的确定方法。全连接层是将上一步所得到的图像reshape为一个一维的向量之后,作为它的输入,因此,输入向量的长度为: in_channels = nFeatureMap * height * weight

网络整体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 10, kernel_size=5, padding=1)
self.conv2 = nn.Conv2d(10, 10, kernel_size=5, padding=1)
self.conv2_drop = nn.Dropout2d()
self.fc1 = nn.Linear(40 * 4 * 5 * 5, 50)
self.fc2 = nn.Linear(50, 10)
self.conv_rate_1 = nn.Conv2d(10, 20, kernel_size=3, dilation=2, padding=2)
self.conv_rate_2 = nn.Conv2d(20, 40, kernel_size=3, dilation=3, padding=3)
self.conv_rate_3 = nn.Conv2d(20, 40, kernel_size=3, dilation=4, padding=4)
self.conv_rate_4 = nn.Conv2d(20, 40, kernel_size=3, dilation=5, padding=5)
self.conv_rate_5 = nn.Conv2d(20, 40, kernel_size=1, padding=0)
def forward(self, x):
x = F.max_pool2d(F.relu(self.conv1(x)), 2)
x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))
x = self.conv_rate_1(x)
x2 = self.conv_rate_2(x)
x3 = self.conv_rate_3(x)
x4 = self.conv_rate_4(x)
x5 = self.conv_rate_5(x)
# print(x.data.shape)
# print(x2.data.shape)
# print(x3.data.shape)
# print(x4.data.shape)
# print(x5.data.shape)
x = torch.cat([x2, x3, x4, x5], dim=1)
# for FC
x = x.view(-1, self.num_flat_features(x)) # origin is 320
x = F.relu(self.fc1(x)) # fc->relu
x = F.dropout(x, training=self.training) # dropout
x = self.fc2(x)
return F.log_softmax(x)
def num_flat_features(self, x):
size = x.size()[1:] # all dimensions except the batch dimension
num_features = 1
for s in size:
num_features *= s
return num_features

------ 本文结束感谢您的阅读 ------
坚持原创技术分享,您的支持将鼓励我继续创作!