PyTorch实现经典分类网络

发布 : 2020-01-25 分类 : 深度学习 浏览 :

使用 PyTorch 实现经典的卷积神经网络。
从 LeNet 到 DenseNet 介绍
项目地址

LeNet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class LeNet(nn.Module):
def __init__(self):
super(LeNet, self).__init__()
self.conv = nn.Sequential(
nn.Conv2d(1, 6, 5),
nn.Sigmoid(),
nn.AvgPool2d(2, 2),
nn.Conv2d(6, 16, 5),
nn.Sigmoid(),
nn.AvgPool2d(2, 2)
)
self.fc = nn.Sequential(
nn.Linear(16 * 4 * 4, 120),
nn.Sigmoid(),
nn.Linear(120, 84),
nn.Sigmoid(),
nn.Linear(84, 10)
)

def forward(self, img):
feature = self.conv(img)
output = self.fc(feature.view(feature.shape[0], -1))
return output

AlexNet

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

class AlexNet(nn.Module):
def __init__(self, classes=1000):
super(AlexNet, self).__init__()
self.classes = classes
self.conv = nn.Sequential(
nn.Conv2d(3, 96, 11, 4),
nn.ReLU(),
nn.MaxPool2d(3, 2),
nn.Conv2d(96, 256, 5, 1, 2),
nn.ReLU(),
nn.MaxPool2d(3, 2),
nn.Conv2d(256, 384, 3, 1, 1),
nn.ReLU(),
nn.Conv2d(384, 384, 3, 1, 1),
nn.ReLU(),
nn.Conv2d(384, 256, 3, 1, 1),
nn.ReLU(),
nn.MaxPool2d(3, 2)
)
self.fc = nn.Sequential(
nn.Linear(6 * 6 * 256, 4096),
nn.ReLU(),
nn.Dropout(0.5),
nn.Linear(4096, 4096),
nn.ReLU(),
nn.Dropout(0.5),
nn.Linear(4096, self.classes) # 使用交叉熵作为损失函数,无需使用Softmax
)

def forward(self, img):
self.feature = self.conv(img)
self.out = self.fc(self.feature.view(self.feature.shape[0], -1))
return self.out

VGG16

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 FlattenLayer(nn.Module):
def __init__(self):
super(FlattenLayer, self).__init__()

def forward(self, X):
return X.view(X.shape[0], -1)


class VGG16(nn.Module):
def __init__(self, conv_arch, fc_features, fc_hidden_units=4096, classes=1000):
super(VGG16, self).__init__()
self.conv_arch = conv_arch
self.fc_features = fc_features
self.fc_hidden_units = fc_hidden_units
self.classes = classes
self.net = nn.Sequential()
for i, (num_convs, in_channels, out_channels) in enumerate(self.conv_arch):
self.net.add_module("vgg_block_" + str(i), self.vgg_block(num_convs, in_channels, out_channels))
self.fc = nn.Sequential(
FlattenLayer(),
nn.Linear(self.fc_features, self.fc_hidden_units),
nn.ReLU(),
nn.Dropout(0.5),
nn.Linear(self.fc_hidden_units, self.fc_hidden_units),
nn.ReLU(),
nn.Dropout(0.5),
nn.Linear(self.fc_hidden_units, self.classes)
)
self.net.add_module("fc", self.fc)

def vgg_block(self, num_convs, in_channels, out_channels):
blocks = []
for i in range(num_convs):
if i == 0:
blocks.append(nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1))
else:
blocks.append(nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1))
blocks.append(nn.ReLU())
blocks.append(nn.MaxPool2d(3, 2))
return nn.Sequential(*blocks)

def forward(self, X):
return self.net(X)

NIN

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
class GlobalAvgPool2d(nn.Module):
def __init__(self):
super(GlobalAvgPool2d, self).__init__()

def forward(self, x):
return F.avg_pool2d(x, kernel_size=x.size()[2:])


class FlattenLayer(nn.Module):
def __init__(self):
super(FlattenLayer, self).__init__()

def forward(self, X):
return X.view(X.shape[0], -1)


class NIN(nn.Module):
def __init__(self, classes):
self.classes = classes
super(NIN, self).__init__()
self.net = nn.Sequential(
self.nin_block(3, 96, kernel_size=11, stride=4, padding=0),
nn.MaxPool2d(kernel_size=3, stride=2),
self.nin_block(96, 256, kernel_size=5, stride=1, padding=2),
nn.MaxPool2d(kernel_size=3, stride=2),
self.nin_block(256, 384, kernel_size=3, stride=1, padding=1),
nn.MaxPool2d(kernel_size=3, stride=2),
nn.Dropout(0.5),
self.nin_block(384, self.classes, kernel_size=3, stride=1, padding=1),
GlobalAvgPool2d(),
FlattenLayer()
)

def nin_block(self, in_channels, out_channels, kernel_size, stride, padding):
block = nn.Sequential(
nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding),
nn.ReLU(),
nn.Conv2d(out_channels, out_channels, kernel_size=1),
nn.ReLU(),
nn.Conv2d(out_channels, out_channels, kernel_size=1),
nn.ReLU()
)
return block

def forward(self, img):
return self.net(img)

GoogLeNet

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
class FlattenLayer(nn.Module):
def __init__(self):
super(FlattenLayer, self).__init__()

def forward(self, X):
return X.view(X.shape[0], -1)

class GlobalAvgPool2d(nn.Module):
def __init__(self):
super(GlobalAvgPool2d, self).__init__()

def forward(self, x):
return F.avg_pool2d(x, kernel_size=x.size()[2:])


class Inception(nn.Module):
# c1-c4为四条线路输出的通道数
def __init__(self, in_c, c1, c2, c3, c4):
super(Inception, self).__init__()
self.p1_1 = nn.Conv2d(in_c, c1, kernel_size=1)

self.p2_1 = nn.Conv2d(in_c, c2[0], 1)
self.p2_2 = nn.Conv2d(c2[0], c2[1], kernel_size=3, padding=1)

self.p3_1 = nn.Conv2d(in_c, c3[0], kernel_size=1)
self.p3_2 = nn.Conv2d(c3[0], c3[1], kernel_size=5, padding=2)

self.p4_1 = nn.MaxPool2d(kernel_size=3, stride=1, padding=1)
self.p4_2 = nn.Conv2d(in_c, c4, kernel_size=1)

def forward(self, x):
p1 = F.relu(self.p1_1(x))
p2 = F.relu(self.p2_2(F.relu((self.p2_1(x)))))
p3 = F.relu(self.p3_2(F.relu(self.p3_1(x))))
p4 = F.relu(self.p4_2(self.p4_1(x)))
return torch.cat((p1, p2, p3, p4), dim=1)


class GoogleNet(nn.Module):
def __init__(self, classes):
self.classes = classes
super(GoogleNet, self).__init__()
self.b1 = nn.Sequential(
nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3),
nn.ReLU(),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
)
self.b2 = nn.Sequential(
nn.Conv2d(64, 64, kernel_size=1),
nn.Conv2d(64, 192, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
)
self.b3 = nn.Sequential(
Inception(192, 64, (96, 128), (16, 32), 32),
Inception(256, 128, (128, 192), (32, 96), 64),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
)
self.b4 = nn.Sequential(
Inception(480, 192, (96, 208), (16, 48), 64),
Inception(512, 160, (112, 224), (24, 64), 64),
Inception(512, 128, (128, 256), (24, 64), 64),
Inception(512, 112, (144, 288), (32, 64), 64),
Inception(528, 256, (160, 320), (32, 128), 128),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
)
self.b5 = nn.Sequential(
Inception(832, 256, (160, 320), (32, 128), 128),
Inception(832, 384, (192, 384), (48, 128), 128),
GlobalAvgPool2d(),
nn.Dropout(0.4),
FlattenLayer(),
nn.Linear(1024, self.classes)
)
self.net = nn.Sequential(
self.b1, self.b2, self.b3, self.b4, self.b5
)

def forward(self, x):
return self.net(x)

ResNet

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
class FlattenLayer(nn.Module):
def __init__(self):
super(FlattenLayer, self).__init__()

def forward(self, X):
return X.view(X.shape[0], -1)


class GlobalAvgPool2d(nn.Module):
def __init__(self):
super(GlobalAvgPool2d, self).__init__()

def forward(self, x):
return F.avg_pool2d(x, kernel_size=x.size()[2:])


class Residual(nn.Module):
def __init__(self, in_channels, out_channels, same_shape=True):
super(Residual, self).__init__()
self.stride = 1 if same_shape else 2
self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=self.stride, padding=1)
self.bn1 = nn.BatchNorm2d(out_channels)
self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1)
self.bn2 = nn.BatchNorm2d(out_channels)
if not same_shape: # 通过1x1卷积核,步长为2.统一两个特征图shape,保证加法运算正常
self.conv3 = nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=2)
else:
self.conv3 = None

def forward(self, X):
Y = F.relu(self.bn1(self.conv1(X)))
Y = F.relu(self.bn2(self.conv2(Y)))
if self.conv3 is not None:
X = self.conv3(X)
return F.relu(X + Y)


class ResNet(nn.Module):
def __init__(self, classes=1000):
super(ResNet, self).__init__()
self.classes = classes
self.net = nn.Sequential()
self.b1 = nn.Sequential(
nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3),
nn.BatchNorm2d(64),
nn.ReLU(),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
)
self.net.add_module("block1", self.b1)
self.net.add_module("resnet_block_1", self.resnet_block(64, 64, 2, is_first_block=True))
self.net.add_module("resnet_block_2", self.resnet_block(64, 128, 2))
self.net.add_module("resnet_block_3", self.resnet_block(128, 256, 2))
self.net.add_module("resnet_block_4", self.resnet_block(256, 512, 2))
self.net.add_module("global_avg_pool", GlobalAvgPool2d())
self.net.add_module("flatten", FlattenLayer())
self.net.add_module('fc', nn.Linear(512, self.classes))

def resnet_block(self, in_channels, out_channels, num_residuals, is_first_block=False):
if is_first_block:
assert in_channels == out_channels # 整个模型的第一块的输入通道数等于输出通道数

block = []
for i in range(num_residuals):
if i == 0 and not is_first_block:
block.append(Residual(in_channels, out_channels, same_shape=False))
else:
block.append(Residual(out_channels, out_channels)) # 第一块输入通道数与输出通道数相等
return nn.Sequential(*block)

def forward(self, X):
return self.net(X)

DenseNet

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
class FlattenLayer(nn.Module):
def __init__(self):
super(FlattenLayer, self).__init__()

def forward(self, X):
return X.view(X.shape[0], -1)


class GlobalAvgPool2d(nn.Module):
def __init__(self):
super(GlobalAvgPool2d, self).__init__()

def forward(self, x):
return F.avg_pool2d(x, kernel_size=x.size()[2:])


class DenseBlock(nn.Module):
def __init__(self, in_channels, out_channels, num_conv):
super(DenseBlock, self).__init__()
self.out_channels = out_channels

layers = []
for i in range(num_conv):
in_c = in_channels + i * self.out_channels
layers.append(self.conv_block(in_c, self.out_channels))

self.net = nn.ModuleList(layers)
self.out_channels = in_channels + num_conv * out_channels

def conv_block(self, in_channels, out_channels):
block = nn.Sequential(
nn.BatchNorm2d(in_channels),
nn.ReLU(),
nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1)
)
return block

def forward(self, X):
for layer in self.net:
Y = layer(X)
X = torch.cat((X, Y), dim=1)
return X


class DenseNet(nn.Module):
def __init__(self, classes):
super(DenseNet, self).__init__()
self.classes = classes
self.net = nn.Sequential(
nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3),
nn.BatchNorm2d(64),
nn.ReLU(),
nn.MaxPool2d(kernel_size=3, stride=2)
)

num_channels, growth_rate = 64, 32 # 当前通道数64,每层增加32通道(即每层卷积输出通道为32)
num_convs_in_dense_block = [4, 4, 4, 4] # 每个dense block 卷积数

for i, num_convs in enumerate(num_convs_in_dense_block):
block = DenseBlock(num_channels, growth_rate, num_convs)
self.net.add_module("dense_block_%d" % i, block)

num_channels = block.out_channels # 上一个块的输出通道数

if i != len(num_convs_in_dense_block) - 1:
self.net.add_module("trainsition_block_%d" % i, self.transition_block(num_channels, num_channels // 2))
num_channels = num_channels // 2

self.net.add_module("BN", nn.BatchNorm2d(num_channels))
self.net.add_module("relu", nn.ReLU())
self.net.add_module("global_avg_pool", GlobalAvgPool2d())
self.net.add_module("flatten", FlattenLayer())
self.net.add_module("fc", nn.Linear(num_channels, self.classes))

def forward(self, X):
return self.net(X)

def transition_block(self, in_channels, out_channels):
block = nn.Sequential(
nn.BatchNorm2d(in_channels),
nn.ReLU(),
nn.Conv2d(in_channels, out_channels, kernel_size=1),
nn.AvgPool2d(kernel_size=2, stride=2)
)
return block

参考

代码结构主要参考李沐老师的《动手学深度学习》,原书使用 MXNET 框架实现,这里简单转为 PyTorch 实现。

本文作者 : HeoLis
原文链接 : https://ishero.net/PyTorch%E5%AE%9E%E7%8E%B0%E7%BB%8F%E5%85%B8%E5%88%86%E7%B1%BB%E7%BD%91%E7%BB%9C.html
版权声明 : 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!

学习、记录、分享、获得

微信扫一扫, 向我投食

微信扫一扫, 向我投食