以下所有模型输入为224*224的图片,输出层为2个神经元(即可实现二分类问题, 更改输出神经元个数以实现多分类)


LeNet(1998)

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
import torch
import torch.nn as nn


class LeNet(nn.Module):

def __init__(self):
super(LeNet,self).__init__()
self.conv1 = nn.Sequential(
nn.Conv2d(1, 6, 5, 1, 2),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2)
)
self.conv2 = nn.Sequential(
nn.Conv2d(6, 16, 5),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2)
)
self.conv3 = nn.Sequential(
nn.Linear(16*5*5, 120),
nn.ReLU()
)
self.fc2 = nn.Sequential(
nn.Linear(120, 84),
nn.ReLU()
)
self.fc3 = nn.Linear(84, 10)

def forward(self,x):
x = self.conv1(x)
x = self.conv2(x)

x = x.view(x.size(0), -1)
x = self.conv3(x)
x = self.fc2(x)
x = self.fc3(x)
return x


AlexNet(2012)

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
import torch
import torch.nn as nn


class AlexNet(nn.Module):

def __init__(self):
super(AlexNet, self).__init__()
self.features = nn.Sequential(
nn.Conv2d(in_channels=3, out_channels=96, kernel_size=11, stride=4, padding=3),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2),

nn.Conv2d(in_channels=96, out_channels=256, kernel_size=5, stride=1, padding=2),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2),

nn.Conv2d(in_channels=256, out_channels=384, kernel_size=3, stride=1, padding=1),
nn.ReLU(inplace=True),

nn.Conv2d(in_channels=384, out_channels=384, kernel_size=3, stride=1, padding=1),
nn.ReLU(inplace=True),

nn.Conv2d(in_channels=384, out_channels=256, kernel_size=3, stride=1, padding=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2)
)

self.classifier = nn.Sequential(
nn.Dropout(),
nn.Linear(256*6*6, 4096),
nn.ReLU(inplace=True),

nn.Dropout(),
nn.Linear(4096, 1024),
nn.ReLU(inplace=True),

nn.Linear(1024, 2)
)

def forward(self, x):
# print(x.size())
x = self.features(x)
# print(x.size())
x = x.view(x.size(0), 256*6*6)
x = self.classifier(x)
return x


VGG(2014)

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
import torch
import torch.nn as nn


class VGG16(nn.Module):

def __init__(self):
super(VGG16, self).__init__()
self.features = nn.Sequential(
nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, stride=1),
nn.ReLU(inplace=True),
nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, stride=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),

nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, stride=1),
nn.ReLU(inplace=True),
nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, stride=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),

nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, stride=1),
nn.ReLU(inplace=True),
nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1),
nn.ReLU(inplace=True),
nn.Conv2d(in_channels=256, out_channels=256, kernel_size=1, stride=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),

nn.Conv2d(in_channels=256, out_channels=512, kernel_size=3, stride=1),
nn.ReLU(inplace=True),
nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1),
nn.ReLU(inplace=True),
nn.Conv2d(in_channels=512, out_channels=512, kernel_size=1, stride=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),

nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1),
nn.ReLU(inplace=True),
nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1),
nn.ReLU(inplace=True),
nn.Conv2d(in_channels=512, out_channels=512, kernel_size=1, stride=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2)
)
self.classifier = nn.Sequential(
nn.Dropout(),
nn.Linear(512*3*3, 4096),
nn.ReLU(inplace=True),

nn.Dropout(),
nn.Linear(4096, 4096),
nn.ReLU(inplace=True),

nn.Linear(4096, 2)
)

def forward(self, x):
# print(x.size())
x = self.features(x)
# print(x.size())
x = x.view(x.size(0), 512*3*3)
x = self.classifier(x)
return x


InceptionV1(2014)

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
import torch
import torch.nn as nn


class InceptionModule(nn.Module):

def __init__(self, in_channels, out_channels_1, reduce_3, out_channels_3, reduce_5, out_channels_5, pool_proj):
super(InceptionModule, self).__init__()
self.branch_1 = nn.Sequential(
nn.Conv2d(in_channels, out_channels_1, kernel_size=1, stride=1, bias=False),
nn.BatchNorm2d(out_channels_1),
nn.ReLU(inplace=True)
)
self.branch_2 = nn.Sequential(
nn.Conv2d(in_channels, reduce_3, kernel_size=1, stride=1, bias=False),
nn.BatchNorm2d(reduce_3),
nn.ReLU(inplace=True),
nn.Conv2d(reduce_3, out_channels_3, kernel_size=3, stride=1, padding=1, bias=False),
nn.BatchNorm2d(out_channels_3),
nn.ReLU(inplace=True)
)
self.branch_3 = nn.Sequential(
nn.Conv2d(in_channels, reduce_5, kernel_size=1, stride=1, bias=False),
nn.BatchNorm2d(reduce_5),
nn.ReLU(inplace=True),
nn.Conv2d(reduce_5, out_channels_5, kernel_size=5, stride=1, padding=2, bias=False),
nn.BatchNorm2d(out_channels_5),
nn.ReLU(inplace=True)
)
self.branch_4 = nn.Sequential(
nn.MaxPool2d(kernel_size=3, stride=1, padding=1),
nn.Conv2d(in_channels, pool_proj, kernel_size=1, stride=1, bias=False),
nn.BatchNorm2d(pool_proj),
nn.ReLU(inplace=True)
)

def forward(self, x):
# print(self.branch_1(x).shape, self.branch_2(x).shape, self.branch_3(x).shape, self.branch_4(x).shape)
return torch.cat([self.branch_1(x), self.branch_2(x), self.branch_3(x), self.branch_4(x)], dim=1)


class InceptionV1(nn.Module):

def __init__(self, num_classes=2):
super(InceptionV1, self).__init__()
self.stage1 = nn.Sequential(
nn.Conv2d(in_channels=3, out_channels=64, kernel_size=7, stride=2, padding=3, bias=False),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1),
nn.Conv2d(in_channels=64, out_channels=64, kernel_size=1, stride=1, bias=False),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True)
)
self.stage2 = nn.Sequential(
nn.Conv2d(in_channels=64, out_channels=192, kernel_size=3, stride=1, padding=1, bias=False),
nn.BatchNorm2d(192),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
)
self.stage3 = nn.Sequential(
# InceptionModule(in_channels, out_channels_1, reduce_3, out_channels_3, reduce_5, out_channels_5, pool_proj)
InceptionModule(192, 64, 96, 128, 16, 32, 32),
InceptionModule(256, 128, 128, 192, 32, 96, 64),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
)
self.stage4 = nn.Sequential(
InceptionModule(480, 192, 96, 208, 16, 48, 64),
InceptionModule(512, 160, 112, 224, 24, 64, 64),
InceptionModule(512, 128, 128, 256, 24, 64, 64),
InceptionModule(512, 112, 144, 288, 32, 64, 64),
InceptionModule(528, 256, 160, 320, 32, 128, 128),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
)
self.stage5 = nn.Sequential(
InceptionModule(832, 256, 160, 320, 32, 128, 128),
InceptionModule(832, 384, 192, 384, 48, 128, 128),
)
self.avg_pool = nn.AvgPool2d(kernel_size=7)
self.classifier = nn.Sequential(
nn.Dropout(0.4),
nn.Linear(1024, num_classes)
)

def forward(self, x):
x = self.stage1(x)
x = self.stage2(x)
x = self.stage3(x)
x = self.stage4(x)
x = self.stage5(x)
x = self.avg_pool(x)
x = x.view(x.size(0), -1)
x = self.classifier(x)
return x


ResNet-18/34/50/101/152(2015)

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
import torch
from torch import nn
from torch.nn import functional as F


class ResidualBlock(nn.Module):

def __init__(self, inchannel, outchannel, stride=1, shortcut=None):
super(ResidualBlock, self).__init__()

# left_2 for ResNet-18/34, left_3 for ResNet-50/101/152
self.left_2 = nn.Sequential(
nn.Conv2d(inchannel, outchannel, 3, stride, 1, bias=False),
nn.BatchNorm2d(outchannel),
nn.ReLU(inplace=True),
nn.Conv2d(outchannel, outchannel, 3, 1, 1, bias=False),
nn.BatchNorm2d(outchannel)
)
self.left_3 = nn.Sequential(
nn.Conv2d(inchannel, outchannel, 1, 1, bias=False),
nn.BatchNorm2d(outchannel),
nn.ReLU(inplace=True),
nn.Conv2d(outchannel, outchannel, 3, stride, 1, bias=False),
nn.BatchNorm2d(outchannel),
nn.ReLU(inplace=True),
nn.Conv2d(outchannel, outchannel, 1, 1, bias=False),
nn.BatchNorm2d(outchannel)
)
self.right = shortcut

def forward(self, x):
out = self.left_2(x)
print(out.shape)
resisdual = x if self.right is None else self.right(x)
out += resisdual
return F.relu(out)


class ResNet34(nn.Module):

def __init__(self, num_classes=2):
super(ResNet34, self).__init__()
self.layer1 = nn.Sequential(
nn.Conv2d(3, 64, 7, 2, 3, bias=False),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True),
nn.MaxPool2d(3, 2, 1)
)
# ResNet-18: 2,2,2,2 ResNet-34: 3,4,6,3
# ResNet-50: 3,4,6,3 ResNet-101: 3,4,23,3 ResNet-152: 3,8,36,3
self.layer2 = self._make_layer(64, 128, 3)
self.layer3 = self._make_layer(128, 256, 4, stride=2)
self.layer4 = self._make_layer(256, 512, 6, stride=2)
self.layer5 = self._make_layer(512, 512, 3, stride=2)
self.avg_pool = nn.AvgPool2d(kernel_size=7)
self.classifier = nn.Linear(512, num_classes)

def _make_layer(self, inchannel, outchannel, block_num, stride=1):
# 1*1 Conv Projection
shortcut = nn.Sequential(
nn.Conv2d(inchannel, outchannel, 1, stride, bias=False),
nn.BatchNorm2d(outchannel)
)

layers = []
layers.append(ResidualBlock(inchannel, outchannel, stride, shortcut))

for i in range(1, block_num):
layers.append(ResidualBlock(outchannel, outchannel))
return nn.Sequential(*layers)

def forward(self, x):
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
x = self.layer4(x)
x = self.layer5(x)
x = self.avg_pool(x)
x = x.view(x.size(0), -1)
x = self.classifier(x)
return x


MobileNetV1(2017)

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
import torch
import torch.nn as nn


class MobileNetV1(nn.Module):

def __init__(self):
super(MobileNetV1, self).__init__()
def conv_bn(inp, oup, stride):
return nn.Sequential(
nn.Conv2d(inp, oup, 3, stride, 1, bias=False),
nn.BatchNorm2d(oup),
nn.ReLU(inplace=True)
)
def conv_dw(inp, oup, stride):
return nn.Sequential(
nn.Conv2d(inp, inp, 3, stride, 1, groups=inp, bias=False),
nn.BatchNorm2d(inp),
nn.ReLU(inplace=True),

nn.Conv2d(inp, oup, 1, 1, 0, bias=False),
nn.BatchNorm2d(oup),
nn.ReLU(inplace=True),
)
self.model = nn.Sequential(
conv_bn(3, 32, 2),
conv_dw(32, 64, 1),
conv_dw(64, 128, 2),
conv_dw(128, 128, 1),
conv_dw(128, 256, 2),
conv_dw(256, 256, 1),
conv_dw(256, 512, 2),
conv_dw(512, 512, 1),
conv_dw(512, 512, 1),
conv_dw(512, 512, 1),
conv_dw(512, 512, 1),
conv_dw(512, 512, 1),
conv_dw(512, 1024, 2),
conv_dw(1024, 1024, 1),
nn.AvgPool2d(7),
)
self.fc = nn.Linear(1024, 2)

def forward(self, x):
x = self.model(x)
x = x.view(-1, 1024)
x = self.fc(x)
return x


MobileNetV2(2018)

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
import torch.nn as nn
import math


def conv_bn(inp, oup, stride):
return nn.Sequential(
nn.Conv2d(inp, oup, 3, stride, 1, bias=False),
nn.BatchNorm2d(oup),
nn.ReLU6(inplace=True)
)


def conv_1x1_bn(inp, oup):
return nn.Sequential(
nn.Conv2d(inp, oup, 1, 1, 0, bias=False),
nn.BatchNorm2d(oup),
nn.ReLU6(inplace=True)
)


def make_divisible(x, divisible_by=8):
import numpy as np
return int(np.ceil(x * 1. / divisible_by) * divisible_by)


class InvertedResidual(nn.Module):

def __init__(self, inp, oup, stride, expand_ratio):
super(InvertedResidual, self).__init__()
self.stride = stride
assert stride in [1, 2]

hidden_dim = int(inp * expand_ratio)
self.use_res_connect = self.stride == 1 and inp == oup

if expand_ratio == 1:
self.conv = nn.Sequential(
# dw
nn.Conv2d(hidden_dim, hidden_dim, 3, stride, 1, groups=hidden_dim, bias=False),
nn.BatchNorm2d(hidden_dim),
nn.ReLU6(inplace=True),
# pw-linear
nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False),
nn.BatchNorm2d(oup),
)
else:
self.conv = nn.Sequential(
# pw
nn.Conv2d(inp, hidden_dim, 1, 1, 0, bias=False),
nn.BatchNorm2d(hidden_dim),
nn.ReLU6(inplace=True),
# dw
nn.Conv2d(hidden_dim, hidden_dim, 3, stride, 1, groups=hidden_dim, bias=False),
nn.BatchNorm2d(hidden_dim),
nn.ReLU6(inplace=True),
# pw-linear
nn.Conv2d(hidden_dim, oup, 1, 1, 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, n_class=2, input_size=224, width_mult=1.):
super(MobileNetV2, self).__init__()
block = InvertedResidual
input_channel = 32
last_channel = 1280
interverted_residual_setting = [
# t, c, n, s
[1, 16, 1, 1],
[6, 24, 2, 2],
[6, 32, 3, 2],
[6, 64, 4, 2],
[6, 96, 3, 1],
[6, 160, 3, 2],
[6, 320, 1, 1],
]

# building first layer
assert input_size % 32 == 0
# input_channel = make_divisible(input_channel * width_mult) # first channel is always 32!
self.last_channel = make_divisible(last_channel * width_mult) if width_mult > 1.0 else last_channel
self.features = [conv_bn(3, input_channel, 2)]

# building inverted residual blocks
for t, c, n, s in interverted_residual_setting:
output_channel = make_divisible(c * width_mult) if t > 1 else c
for i in range(n):
if i == 0:
self.features.append(block(input_channel, output_channel, s, expand_ratio=t))
else:
self.features.append(block(input_channel, output_channel, 1, expand_ratio=t))
input_channel = output_channel

# building last several layers
self.features.append(conv_1x1_bn(input_channel, self.last_channel))

# make it nn.Sequential
self.features = nn.Sequential(*self.features)

# building classifier
self.classifier = nn.Linear(self.last_channel, n_class)
self._initialize_weights()

def forward(self, x):
x = self.features(x)
x = x.mean(3).mean(2)
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_()


MobileNetV3(2019)

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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.autograd import Variable
import math


class HardSwish(nn.Module):

def __init__(self, inplace=True):
super(HardSwish, self).__init__()
self.relu6 = nn.ReLU6(inplace=inplace)
def forward(self, x):
return x * (self.relu6(x+3)) / 6


class HardSigmoid(nn.Module):
def __init__(self, inplace=True):
super(HardSigmoid, self).__init__()
self.relu6 = nn.ReLU6(inplace=inplace)
def forward(self, x):
return (self.relu6(x+3)) / 6


ACT_FNS = {
'RE': nn.ReLU6(inplace=True),
'HS': HardSwish(),
'HG': HardSigmoid()
}


def _make_divisible(v, divisor, min_value=None):
if min_value is None:
min_value = divisor
new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)
if new_v < 0.9 * v:
new_v += divisor
return new_v


def conv_3x3_bn(inp, oup, stride, nl='RE'):
return nn.Sequential(
nn.Conv2d(inp, oup, 3, stride, 1, bias=False),
nn.BatchNorm2d(oup),
ACT_FNS[nl]
)


def conv_1x1(inp, oup, nl='RE', with_se=False):
if with_se:
return nn.Sequential(
nn.Conv2d(inp, oup, 1, 1, 0, bias=False),
SqueezeAndExcite(oup, reduction=4),
ACT_FNS[nl]
)
else:
return nn.Sequential(
nn.Conv2d(inp, oup, 1, 1, 0, bias=False),
ACT_FNS[nl]
)


def conv_1x1_bn(inp, oup, nl='RE', with_se=False):
if with_se:
return nn.Sequential(
nn.Conv2d(inp, oup, 1, 1, 0, bias=False),
SqueezeAndExcite(oup, reduction=4),
nn.BatchNorm2d(oup),
ACT_FNS[nl]
)
else:
return nn.Sequential(
nn.Conv2d(inp, oup, 1, 1, 0, bias=False),
nn.BatchNorm2d(oup),
ACT_FNS[nl]
)


class SqueezeAndExcite(nn.Module):

def __init__(self, n_features, reduction=4):
super(SqueezeAndExcite, self).__init__()
if n_features % reduction != 0:
raise ValueError('n_features must be divisible by reduction (default = 4)')
self.linear1 = nn.Linear(n_features, n_features // reduction, bias=True)
self.nonlin1 = ACT_FNS['RE']
self.linear2 = nn.Linear(n_features // reduction, n_features, bias=True)
self.nonlin2 = ACT_FNS['HG']

def forward(self, x):
y = F.avg_pool2d(x, kernel_size=x.size()[2:4])
y = y.permute(0, 2, 3, 1)
y = self.nonlin1(self.linear1(y))
y = self.nonlin2(self.linear2(y))
y = y.permute(0, 3, 1, 2)
y = x * y
return y


class InvertedResidual(nn.Module):

def __init__(self, inp, oup, kernel, stride, expand_size, nl='RE', with_se=False):
super(InvertedResidual, self).__init__()
assert stride in [1, 2]

hidden_dim = expand_size

self.identity = stride == 1 and inp == oup

self.pw = nn.Sequential(
nn.Conv2d(inp, hidden_dim, 1, 1, 0, bias=False),
nn.BatchNorm2d(hidden_dim),
ACT_FNS[nl],
)

self.dw = nn.Sequential(
nn.Conv2d(hidden_dim, hidden_dim, kernel, stride, kernel//2, groups=hidden_dim, bias=False),
nn.BatchNorm2d(hidden_dim),
ACT_FNS[nl],
)

self.se = nn.Sequential(
SqueezeAndExcite(hidden_dim, reduction=4)
)

self.pw_linear = nn.Sequential(
nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False),
nn.BatchNorm2d(oup),
)

if with_se: # with squeeze and excite
if expand_size == oup: # exp_ratio = 1
self.conv = nn.Sequential(
self.dw,
self.se,
self.pw_linear,
)
else:
self.conv = nn.Sequential(
self.pw,
self.dw,
self.se,
self.pw_linear,
)
else:
if expand_size == oup:
self.conv = nn.Sequential(
self.dw,
self.pw_linear,
)
else:
self.conv = nn.Sequential(
self.pw,
self.dw,
self.pw_linear,
)

def forward(self, x):
if self.identity:
return x + self.conv(x)
else:
return self.conv(x)


class MobileNetV3(nn.Module):

# NOTE: [kernel, expansion, output, SE, NL, s]
cfg = [(3, 16, 16, True, 'RE', 2),
(3, 72, 24, False, 'RE', 2),
(3, 88, 24, False, 'RE', 1),
(5, 96, 40, True, 'HS', 2),
(5, 240, 40, True, 'HS', 1),
(5, 240, 40, True, 'HS', 1),
(5, 120, 48, True, 'HS', 1),
(5, 144, 48, True, 'HS', 1),
(5, 288, 96, True, 'HS', 2),
(5, 576, 96, True, 'HS', 1),
(5, 576, 96, True, 'HS', 1)]

def __init__(self, num_classes=2, input_size=224, width_mult=1.):
super(MobileNetV3, self).__init__()
# building first layer
assert input_size % 32 == 0
input_channel = _make_divisible(16 * width_mult, 8)
self.conv0 = conv_3x3_bn(3, input_channel, 2, nl='HS')
layers = []
# building inverted residual blocks
block = InvertedResidual
# for t, c, n, s in self.cfgs:
for kernel, expansion, output_channel, se, nl, stride in self.cfg:
layers.append(block(input_channel, output_channel, kernel, stride, expansion, nl=nl, with_se=se))
input_channel = output_channel
self.features = nn.Sequential(*layers)

# building last several layers
self.conv1 = conv_1x1_bn(input_channel, expansion, nl='HS', with_se=False)
input_channel = expansion

self.avgpool = nn.AvgPool2d(input_size // 32, stride=1)
output_channel = _make_divisible(1280 * width_mult, 8) if width_mult > 1.0 else 1280
self.conv2 = conv_1x1(input_channel, output_channel, nl='HS', with_se=False)
self.classifier = nn.Linear(output_channel, num_classes)

self._initialize_weights()

def forward(self, x):
x = self.conv0(x)
x = self.features(x)
x = self.conv1(x)
x = self.avgpool(x)
x = self.conv2(x)
x = x.view(x.size(0), -1)
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_()


ShuffleNetV2(2019)

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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.autograd import Variable
from collections import OrderedDict
from torch.nn import init
import math


# model = ShuffleNetV2()
# input: 3*?*?


def conv_bn(inp, oup, stride):
return nn.Sequential(
nn.Conv2d(inp, oup, 3, stride, 1, bias=False),
nn.BatchNorm2d(oup),
nn.ReLU(inplace=True)
)


def conv_1x1_bn(inp, oup):
return nn.Sequential(
nn.Conv2d(inp, oup, 1, 1, 0, bias=False),
nn.BatchNorm2d(oup),
nn.ReLU(inplace=True)
)

def channel_shuffle(x, groups):
batchsize, num_channels, height, width = x.data.size()

channels_per_group = num_channels // groups

# reshape
x = x.view(batchsize, groups,
channels_per_group, height, width)

x = torch.transpose(x, 1, 2).contiguous()

# flatten
x = x.view(batchsize, -1, height, width)

return x

class InvertedResidual(nn.Module):

def __init__(self, inp, oup, stride, benchmodel):
super(InvertedResidual, self).__init__()
self.benchmodel = benchmodel
self.stride = stride
assert stride in [1, 2]

oup_inc = oup//2

if self.benchmodel == 1:
#assert inp == oup_inc
self.banch2 = nn.Sequential(
# pw
nn.Conv2d(oup_inc, oup_inc, 1, 1, 0, bias=False),
nn.BatchNorm2d(oup_inc),
nn.ReLU(inplace=True),
# dw
nn.Conv2d(oup_inc, oup_inc, 3, stride, 1, groups=oup_inc, bias=False),
nn.BatchNorm2d(oup_inc),
# pw-linear
nn.Conv2d(oup_inc, oup_inc, 1, 1, 0, bias=False),
nn.BatchNorm2d(oup_inc),
nn.ReLU(inplace=True),
)
else:
self.banch1 = nn.Sequential(
# dw
nn.Conv2d(inp, inp, 3, stride, 1, groups=inp, bias=False),
nn.BatchNorm2d(inp),
# pw-linear
nn.Conv2d(inp, oup_inc, 1, 1, 0, bias=False),
nn.BatchNorm2d(oup_inc),
nn.ReLU(inplace=True),
)

self.banch2 = nn.Sequential(
# pw
nn.Conv2d(inp, oup_inc, 1, 1, 0, bias=False),
nn.BatchNorm2d(oup_inc),
nn.ReLU(inplace=True),
# dw
nn.Conv2d(oup_inc, oup_inc, 3, stride, 1, groups=oup_inc, bias=False),
nn.BatchNorm2d(oup_inc),
# pw-linear
nn.Conv2d(oup_inc, oup_inc, 1, 1, 0, bias=False),
nn.BatchNorm2d(oup_inc),
nn.ReLU(inplace=True),
)

@staticmethod
def _concat(x, out):
# concatenate along channel axis
return torch.cat((x, out), 1)

def forward(self, x):
if 1==self.benchmodel:
x1 = x[:, :(x.shape[1]//2), :, :]
x2 = x[:, (x.shape[1]//2):, :, :]
out = self._concat(x1, self.banch2(x2))
elif 2==self.benchmodel:
out = self._concat(self.banch1(x), self.banch2(x))

return channel_shuffle(out, 2)


class ShuffleNetV2(nn.Module):

def __init__(self, n_class=1000, input_size=224, width_mult=1.):
super(ShuffleNetV2, self).__init__()

assert input_size % 32 == 0

self.stage_repeats = [4, 8, 4]
# index 0 is invalid and should never be called.
# only used for indexing convenience.
if width_mult == 0.5:
self.stage_out_channels = [-1, 24, 48, 96, 192, 1024]
elif width_mult == 1.0:
self.stage_out_channels = [-1, 24, 116, 232, 464, 1024]
elif width_mult == 1.5:
self.stage_out_channels = [-1, 24, 176, 352, 704, 1024]
elif width_mult == 2.0:
self.stage_out_channels = [-1, 24, 224, 488, 976, 2048]
else:
raise ValueError(
"""{} groups is not supported for
1x1 Grouped Convolutions""".format(num_groups))

# building first layer
input_channel = self.stage_out_channels[1]
self.conv1 = conv_bn(3, input_channel, 2)
self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
self.features = []

# building inverted residual blocks
for idxstage in range(len(self.stage_repeats)):
numrepeat = self.stage_repeats[idxstage]
output_channel = self.stage_out_channels[idxstage+2]
for i in range(numrepeat):
if i == 0:
#inp, oup, stride, benchmodel):
self.features.append(InvertedResidual(input_channel, output_channel, 2, 2))
else:
self.features.append(InvertedResidual(input_channel, output_channel, 1, 1))
input_channel = output_channel


# make it nn.Sequential
self.features = nn.Sequential(*self.features)

# building last several layers
self.conv_last = conv_1x1_bn(input_channel, self.stage_out_channels[-1])
self.globalpool = nn.Sequential(nn.AvgPool2d(int(input_size/32)))

# building classifier
self.classifier = nn.Sequential(nn.Linear(self.stage_out_channels[-1], n_class))

def forward(self, x):
x = self.conv1(x)
x = self.maxpool(x)
x = self.features(x)
x = self.conv_last(x)
x = self.globalpool(x)
x = x.view(-1, self.stage_out_channels[-1])
x = self.classifier(x)
return x