Skip to content

Commit 236a0f2

Browse files
committed
增加已完成的模型
1 parent 65b917d commit 236a0f2

File tree

7 files changed

+316
-7
lines changed

7 files changed

+316
-7
lines changed

CIFAR10_code/nets/AlexNet.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def test():
5959
x = torch.randn(2,3,32,32)
6060
y = net(x)
6161
print(y.size())
62-
from torchsummary import summary
62+
from torchinfo import summary
6363
device = 'cuda' if torch.cuda.is_available() else 'cpu'
6464
net = net.to(device)
6565
summary(net,(3,32,32))

CIFAR10_code/nets/DenseNet.py

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
2+
"""
3+
DenseNet in pytorch
4+
see the details in papaer
5+
[1] Gao Huang, Zhuang Liu, Laurens van der Maaten, Kilian Q. Weinberger.
6+
Densely Connected Convolutional Networks
7+
https://arxiv.org/abs/1608.06993v5
8+
"""
9+
import torch
10+
import torch.nn as nn
11+
12+
class Bottleneck(nn.Module):
13+
"""
14+
Dense Block
15+
这里的growth_rate=out_channels, 就是每个Block自己输出的通道数。
16+
先通过1x1卷积层,将通道数缩小为4 * growth_rate,然后再通过3x3卷积层降低到growth_rate。
17+
"""
18+
# 通常1×1卷积的通道数为GrowthRate的4倍
19+
expansion = 4
20+
21+
def __init__(self, in_channels, growth_rate):
22+
super(Bottleneck, self).__init__()
23+
zip_channels = self.expansion * growth_rate
24+
self.features = nn.Sequential(
25+
nn.BatchNorm2d(in_channels),
26+
nn.ReLU(True),
27+
nn.Conv2d(in_channels, zip_channels, kernel_size=1, bias=False),
28+
nn.BatchNorm2d(zip_channels),
29+
nn.ReLU(True),
30+
nn.Conv2d(zip_channels, growth_rate, kernel_size=3, padding=1, bias=False)
31+
)
32+
33+
def forward(self, x):
34+
out = self.features(x)
35+
out = torch.cat([out, x], 1)
36+
return out
37+
38+
39+
class Transition(nn.Module):
40+
"""
41+
改变维数的Transition层 具体包括BN、ReLU、1×1卷积(Conv)、2×2平均池化操作
42+
先通过1x1的卷积层减少channels,再通过2x2的平均池化层缩小feature-map
43+
"""
44+
# 1×1卷积的作用是降维,起到压缩模型的作用,而平均池化则是降低特征图的尺寸。
45+
def __init__(self, in_channels, out_channels):
46+
super(Transition, self).__init__()
47+
self.features = nn.Sequential(
48+
nn.BatchNorm2d(in_channels),
49+
nn.ReLU(True),
50+
nn.Conv2d(in_channels, out_channels, kernel_size=1, bias=False),
51+
nn.AvgPool2d(2)
52+
)
53+
54+
def forward(self, x):
55+
out = self.features(x)
56+
return out
57+
# DesneNet-BC
58+
# B 代表 bottleneck layer(BN-RELU-CONV(1x1)-BN-RELU-CONV(3x3))
59+
# C 代表压缩系数(0<=theta<=1)
60+
import math
61+
class DenseNet(nn.Module):
62+
"""
63+
Dense Net
64+
paper中growth_rate取12,维度压缩的参数θ,即reduction取0.5
65+
且初始化方法为kaiming_normal()
66+
num_blocks为每段网络中的DenseBlock数量
67+
DenseNet和ResNet一样也是六段式网络(一段卷积+四段Dense+平均池化层),最后FC层。
68+
第一段将维数从3变到2 * growth_rate
69+
70+
(3, 32, 32) -> [Conv2d] -> (24, 32, 32) -> [layer1] -> (48, 16, 16) -> [layer2]
71+
->(96, 8, 8) -> [layer3] -> (192, 4, 4) -> [layer4] -> (384, 4, 4) -> [AvgPool]
72+
->(384, 1, 1) -> [Linear] -> (10)
73+
74+
"""
75+
def __init__(self, num_blocks, growth_rate=12, reduction=0.5, num_classes=10):
76+
super(DenseNet, self).__init__()
77+
self.growth_rate = growth_rate
78+
self.reduction = reduction
79+
80+
num_channels = 2 * growth_rate
81+
82+
self.features = nn.Conv2d(3, num_channels, kernel_size=3, padding=1, bias=False)
83+
self.layer1, num_channels = self._make_dense_layer(num_channels, num_blocks[0])
84+
self.layer2, num_channels = self._make_dense_layer(num_channels, num_blocks[1])
85+
self.layer3, num_channels = self._make_dense_layer(num_channels, num_blocks[2])
86+
self.layer4, num_channels = self._make_dense_layer(num_channels, num_blocks[3], transition=False)
87+
self.avg_pool = nn.Sequential(
88+
nn.BatchNorm2d(num_channels),
89+
nn.ReLU(True),
90+
nn.AvgPool2d(4),
91+
)
92+
self.classifier = nn.Linear(num_channels, num_classes)
93+
94+
self._initialize_weight()
95+
96+
def _make_dense_layer(self, in_channels, nblock, transition=True):
97+
layers = []
98+
for i in range(nblock):
99+
layers += [Bottleneck(in_channels, self.growth_rate)]
100+
in_channels += self.growth_rate
101+
out_channels = in_channels
102+
if transition:
103+
out_channels = int(math.floor(in_channels * self.reduction))
104+
layers += [Transition(in_channels, out_channels)]
105+
return nn.Sequential(*layers), out_channels
106+
107+
def _initialize_weight(self):
108+
for m in self.modules():
109+
if isinstance(m, nn.Conv2d):
110+
nn.init.kaiming_normal_(m.weight.data)
111+
if m.bias is not None:
112+
m.bias.data.zero_()
113+
114+
def forward(self, x):
115+
out = self.features(x)
116+
out = self.layer1(out)
117+
out = self.layer2(out)
118+
out = self.layer3(out)
119+
out = self.layer4(out)
120+
out = self.avg_pool(out)
121+
out = out.view(out.size(0), -1)
122+
out = self.classifier(out)
123+
return out
124+
125+
def DenseNet121():
126+
return DenseNet([6,12,24,16], growth_rate=32)
127+
128+
def DenseNet169():
129+
return DenseNet([6,12,32,32], growth_rate=32)
130+
131+
def DenseNet201():
132+
return DenseNet([6,12,48,32], growth_rate=32)
133+
134+
def DenseNet161():
135+
return DenseNet([6,12,36,24], growth_rate=48)
136+
137+
def densenet_cifar():
138+
return DenseNet([6,12,24,16], growth_rate=12)
139+
140+
141+
def test():
142+
net = densenet_cifar()
143+
x = torch.randn(1,3,32,32)
144+
y = net(x)
145+
print(y.size())
146+
from torchinfo import summary
147+
device = 'cuda' if torch.cuda.is_available() else 'cpu'
148+
net = net.to(device)
149+
summary(net,(1,3,32,32))
150+
151+
test()
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ def test():
4545
x = torch.randn(2,3,32,32)
4646
y = net(x)
4747
print(y.size())
48-
from torchsummary import summary
48+
from torchinfo import summary
4949
device = 'cuda' if torch.cuda.is_available() else 'cpu'
5050
net = net.to(device)
51-
summary(net,(3,32,32))
51+
summary(net,(2,3,32,32))
5252

CIFAR10_code/nets/MobileNetv1.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,6 @@ def test():
7979
from torchinfo import summary
8080
device = 'cuda' if torch.cuda.is_available() else 'cpu'
8181
net = net.to(device)
82-
summary(net,(32,3,32,32))
82+
summary(net,(2,3,32,32))
8383

8484
test()

CIFAR10_code/nets/MobileNetv2.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,6 @@ def test():
9999
from torchinfo import summary
100100
device = 'cuda' if torch.cuda.is_available() else 'cpu'
101101
net = net.to(device)
102-
summary(net,(32,3,32,32))
102+
summary(net,(2,3,32,32))
103103

104104
test()

CIFAR10_code/nets/ResNet.py

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
'''
2+
ResNet in PyTorch.
3+
Reference:
4+
[1] Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun
5+
Deep Residual Learning for Image Recognition. arXiv:1512.03385
6+
'''
7+
import torch
8+
import torch.nn as nn
9+
class BasicBlock(nn.Module):
10+
"""
11+
对于浅层网络,如ResNet-18/34等,用基本的Block
12+
基础模块没有压缩,所以expansion=1
13+
"""
14+
expansion = 1
15+
def __init__(self, in_channels, out_channels, stride=1):
16+
super(BasicBlock,self).__init__()
17+
self.features = nn.Sequential(
18+
nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False),
19+
nn.BatchNorm2d(out_channels),
20+
nn.ReLU(True),
21+
nn.Conv2d(out_channels,out_channels, kernel_size=3, stride=1, padding=1, bias=False),
22+
nn.BatchNorm2d(out_channels)
23+
)
24+
# 如果输入输出维度不等,则使用1x1卷积层来改变维度
25+
self.shortcut = nn.Sequential()
26+
if stride != 1 or in_channels != self.expansion * out_channels:
27+
self.shortcut = nn.Sequential(
28+
nn.Conv2d(in_channels, self.expansion * out_channels, kernel_size=1, stride=stride, bias=False),
29+
nn.BatchNorm2d(self.expansion * out_channels),
30+
)
31+
def forward(self, x):
32+
out = self.features(x)
33+
# print(out.shape)
34+
out += self.shortcut(x)
35+
out = torch.relu(out)
36+
return out
37+
38+
39+
class Bottleneck(nn.Module):
40+
"""
41+
对于深层网络,我们使用BottleNeck,论文中提出其拥有近似的计算复杂度,但能节省很多资源
42+
zip_channels: 压缩后的维数,最后输出的维数是 expansion * zip_channels
43+
针对ResNet50/101/152的网络结构,主要是因为第三层是第二层的4倍的关系所以expansion=4
44+
"""
45+
expansion = 4
46+
47+
def __init__(self, in_channels, zip_channels, stride=1):
48+
super(Bottleneck, self).__init__()
49+
out_channels = self.expansion * zip_channels
50+
self.features = nn.Sequential(
51+
nn.Conv2d(in_channels, zip_channels, kernel_size=1, bias=False),
52+
nn.BatchNorm2d(zip_channels),
53+
nn.ReLU(inplace=True),
54+
nn.Conv2d(zip_channels, zip_channels, kernel_size=3, stride=stride, padding=1, bias=False),
55+
nn.BatchNorm2d(zip_channels),
56+
nn.ReLU(inplace=True),
57+
nn.Conv2d(zip_channels, out_channels, kernel_size=1, bias=False),
58+
nn.BatchNorm2d(out_channels)
59+
)
60+
self.shortcut = nn.Sequential()
61+
if stride != 1 or in_channels != out_channels:
62+
self.shortcut = nn.Sequential(
63+
nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False),
64+
nn.BatchNorm2d(out_channels)
65+
)
66+
67+
def forward(self, x):
68+
out = self.features(x)
69+
# print(out.shape)
70+
out += self.shortcut(x)
71+
out = torch.relu(out)
72+
return out
73+
74+
class ResNet(nn.Module):
75+
"""
76+
不同的ResNet架构都是统一的一层特征提取、四层残差,不同点在于每层残差的深度。
77+
对于cifar10,feature map size的变化如下:
78+
(32, 32, 3) -> [Conv2d] -> (32, 32, 64) -> [Res1] -> (32, 32, 64) -> [Res2]
79+
-> (16, 16, 128) -> [Res3] -> (8, 8, 256) ->[Res4] -> (4, 4, 512) -> [AvgPool]
80+
-> (1, 1, 512) -> [Reshape] -> (512) -> [Linear] -> (10)
81+
"""
82+
def __init__(self, block, num_blocks, num_classes=10, verbose = False):
83+
super(ResNet, self).__init__()
84+
self.verbose = verbose
85+
self.in_channels = 64
86+
self.features = nn.Sequential(
87+
nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False),
88+
nn.BatchNorm2d(64),
89+
nn.ReLU(inplace=True)
90+
)
91+
#使用_make_layer函数生成上表对应的conv2_x, conv3_x, conv4_x, conv5_x的结构
92+
self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1)
93+
self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2)
94+
self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2)
95+
self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2)
96+
# cifar10经过上述结构后,到这里的feature map size是 4 x 4 x 512 x expansion
97+
# 所以这里用了 4 x 4 的平均池化
98+
self.avg_pool = nn.AvgPool2d(kernel_size=4)
99+
self.classifer = nn.Linear(512 * block.expansion, num_classes)
100+
101+
def _make_layer(self, block, out_channels, num_blocks, stride):
102+
# 第一个block要进行降采样
103+
strides = [stride] + [1] * (num_blocks - 1)
104+
layers = []
105+
for stride in strides:
106+
layers.append(block(self.in_channels, out_channels, stride))
107+
# 如果是Bottleneck Block的话需要对每层输入的维度进行压缩,压缩后再增加维数
108+
# 所以每层的输入维数也要跟着变
109+
self.in_channels = out_channels * block.expansion
110+
return nn.Sequential(*layers)
111+
112+
def forward(self, x):
113+
out = self.features(x)
114+
if self.verbose:
115+
print('block 1 output: {}'.format(out.shape))
116+
out = self.layer1(out)
117+
if self.verbose:
118+
print('block 2 output: {}'.format(out.shape))
119+
out = self.layer2(out)
120+
if self.verbose:
121+
print('block 3 output: {}'.format(out.shape))
122+
out = self.layer3(out)
123+
if self.verbose:
124+
print('block 4 output: {}'.format(out.shape))
125+
out = self.layer4(out)
126+
if self.verbose:
127+
print('block 5 output: {}'.format(out.shape))
128+
out = self.avg_pool(out)
129+
out = out.view(out.size(0), -1)
130+
out = self.classifer(out)
131+
return out
132+
133+
def ResNet18(verbose=False):
134+
return ResNet(BasicBlock, [2,2,2,2],verbose=verbose)
135+
136+
def ResNet34(verbose=False):
137+
return ResNet(BasicBlock, [3,4,6,3],verbose=verbose)
138+
139+
def ResNet50(verbose=False):
140+
return ResNet(Bottleneck, [3,4,6,3],verbose=verbose)
141+
142+
def ResNet101(verbose=False):
143+
return ResNet(Bottleneck, [3,4,23,3],verbose=verbose)
144+
145+
def ResNet152(verbose=False):
146+
return ResNet(Bottleneck, [3,8,36,3],verbose=verbose)
147+
148+
def test():
149+
net = ResNet34()
150+
x = torch.randn(2,3,32,32)
151+
y = net(x)
152+
print(y.size())
153+
from torchinfo import summary
154+
device = 'cuda' if torch.cuda.is_available() else 'cpu'
155+
net = net.to(device)
156+
summary(net,(2,3,32,32))
157+
158+
test()

CIFAR10_code/nets/VGG.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ def test():
4343
x = torch.randn(2,3,32,32)
4444
y = net(x)
4545
print(y.size())
46-
from torchsummary import summary
46+
from torchinfo import summary
4747
device = 'cuda' if torch.cuda.is_available() else 'cpu'
4848
net = net.to(device)
49-
summary(net,(3,32,32))
49+
summary(net,(2,3,32,32))
5050

5151
test()

0 commit comments

Comments
 (0)