-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathMobileNetV2.py
137 lines (119 loc) · 4.74 KB
/
MobileNetV2.py
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import torch.nn as nn
import math
def conv_bn(inp, oup, stride ):
'''
该函数分别进行3x3卷积
BN
ReLU6操作
'''
return nn.Sequential(
nn.Conv2d(inp, oup,kernel_size= 3, stride= stride, padding= 1, bias=False),
nn.BatchNorm2d(oup),
nn.ReLU6(inplace=True)
)
def conv_1x1_bn(inp, oup):
return nn.Sequential(
nn.Conv2d(inp, oup, kernel_size = 1, stride= 1, padding= 0, bias=False),
nn.BatchNorm2d(oup),
nn.ReLU6(inplace=True)
)
class InvertedResidual(nn.Module):
def __init__(self, inp, oup, stride, expand_ratio):
super(InvertedResidual, self).__init__()
self.stride = stride
assert stride in [1, 2]
self.use_res_connect = self.stride == 1 and inp == oup
self.conv = nn.Sequential(
# pw
nn.Conv2d(inp, inp * expand_ratio,kernel_size = 1, stride= 1, padding=0, bias=False),
nn.BatchNorm2d(inp * expand_ratio),
nn.ReLU6(inplace=True),
# dw
nn.Conv2d(inp * expand_ratio, inp * expand_ratio, kernel_size =3, stride= stride, padding=1, groups=inp * expand_ratio, bias=False),
nn.BatchNorm2d(inp * expand_ratio),
nn.ReLU6(inplace=True),
# pw-linear
nn.Conv2d(inp * expand_ratio, oup, kernel_size =1, stride= 1, padding=0, bias=False),
nn.BatchNorm2d(oup),
)
def forward(self, x):
if self.use_res_connect:
return x + self.conv(x)
else:
return self.conv(x)
class MobileNetV2(nn.Module):
def __init__(self,args):
super(MobileNetV2, self).__init__()
# 配置某些block的stride,满足downsampling的需求
s1, s2 = 2, 2
if args.downsampling == 16:
s1, s2 = 2, 1
elif args.downsampling == 8:
s1, s2 = 1, 1
'''
network_settings网络的相关配置,从该参数可以看出,Mobile-Net由9个部分组成,
姑且叫做Mobile block。
network_settings中:
't'表示Inverted Residuals的扩征系数
'c'表示该block输出的通道数
‘n’表示当前block由几个残差单元组成
's'表示当前block的stride
'''
# setting of inverted residual blocks
self.interverted_residual_setting = [
# t, c, n, s
[1, 16, 1, 1],
[6, 24, 2, s2],
[6, 32, 3, 2],
[6, 64, 4, 2],
[6, 96, 3, 1],
[6, 160, 3, 2],
[6, 320, 1, 1],
]
# building first layer
assert args.img_height % 32 == 0
input_channel = int(32 * args.width_multiplier)
self.last_channel = int(1280 * args.width_multiplier) if args.width_multiplier > 1.0 else 1280
#第一层,
self.features = [conv_bn(inp =3, oup =input_channel, stride = s1)]
#中间block,一共7个,
# Layers from 1 to 7
# building inverted residual blocks
for t, c, n, s in self.interverted_residual_setting:
output_channel = int(c * args.width_multiplier)
for i in range(n):
if i == 0:
self.features.append(InvertedResidual(input_channel, output_channel, s, t))
else:
self.features.append(InvertedResidual(input_channel, output_channel, 1, t))
input_channel = output_channel
# building last several layers
self.features.append(conv_1x1_bn(input_channel, self.last_channel))
self.features.append(nn.AvgPool2d(kernel_size = (args.img_height // args.downsampling, args.img_width // args.downsampling)))
# make it nn.Sequential
self.features = nn.Sequential(*self.features)
# building classifier
self.classifier = nn.Sequential(
nn.Dropout(),
nn.Linear(self.last_channel,args.num_classes),
)
self._initialize_weights()
def forward(self, x):
x = self.features(x)
x = x.view(-1, self.last_channel)
x = self.classifier(x)
return x
def _initialize_weights(self):
for m in self.modules():
if isinstance(m, nn.Conv2d):
n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
m.weight.data.normal_(0, math.sqrt(2. / n))
if m.bias is not None:
m.bias.data.zero_()
elif isinstance(m, nn.BatchNorm2d):
m.weight.data.fill_(1)
m.bias.data.zero_()
elif isinstance(m, nn.Linear):
n = m.weight.size(1)
m.weight.data.normal_(0, 0.01)
m.bias.data.zero_()