一:pytorch实现空洞卷积实验(torch实现)
要求:
从至少一个数据集上进行实验,同理,这里我选取了车辆分类数据集(后面的实验都是用的车辆分类数据集),主要在之前利用torch.nn实现二维卷积的基础上,为解决感受野比较的问题,将普通的卷积修改为空洞卷积,并且卷几率符合HDC条件(这里我选取了1,2,5),并且堆叠了2层HDC,即一共六层卷积层。
实验过程:
注:所谓的空洞卷积,与https://blog.csdn.net/qq_37534947/article/details/109726153的torch.nn实现的二维卷积除了模型的定义部分不一样之外,其他的如:数据集、画图、计时、优化器等都是一样的,当然参数设置可能会有些不同,主要在实验结果区分,所以我这里主要针对模型定义做相关介绍。
1.1 空洞卷积模型定义
1. #pytorch封装卷积层
2. class ConvModule(nn.Module):
3. def __init__(self):
4. super(ConvModule,self).__init__()
5. #定义六层卷积层
6. #两层HDC(1,2,5,1,2,5)
7. self.conv = nn.Sequential(
8. #第一层 (3-1)*1+1=3 (64-3)/1 + 1 =62
9. nn.Conv2d(in_channels = 3,out_channels = 32,kernel_size = 3 , stride = 1,padding=0,dilation=1),
10. nn.BatchNorm2d(32),
11. # inplace-选择是否进行覆盖运算
12. nn.ReLU(inplace=True),
13. #第二层 (3-1)*2+1=5 (62-5)/1 + 1 =58
14. nn.Conv2d(in_channels = 32,out_channels = 32,kernel_size = 3 , stride = 1,padding=0,dilation=2),
15. nn.BatchNorm2d(32),
16. # inplace-选择是否进行覆盖运算
17. nn.ReLU(inplace=True),
18. #第三层 (3-1)*5+1=11 (58-11)/1 +1=48
19. nn.Conv2d(in_channels = 32,out_channels = 64,kernel_size = 3 , stride = 1,padding=0,dilation=5),
20. nn.BatchNorm2d(64),
21. # inplace-选择是否进行覆盖运算
22. nn.ReLU(inplace=True),
23. #第四层(3-1)*1+1=3 (48-3)/1 + 1 =46
24. nn.Conv2d(in_channels = 64,out_channels = 64,kernel_size = 3 , stride = 1,padding=0,dilation=1),
25. nn.BatchNorm2d(64),
26. # inplace-选择是否进行覆盖运算
27. nn.ReLU(inplace=True),
28. #第五层 (3-1)*2+1=5 (46-5)/1 + 1 =42
29. nn.Conv2d(in_channels = 64,out_channels = 64,kernel_size = 3 , stride = 1,padding=0,dilation=2),
30. nn.BatchNorm2d(64),
31. # inplace-选择是否进行覆盖运算
32. nn.ReLU(inplace=True),
33. #第六层 (3-1)*5+1=11 (42-11)/1 +1=32
34. nn.Conv2d(in_channels = 64,out_channels = 128,kernel_size = 3 , stride = 1,padding=0,dilation=5),
35. nn.BatchNorm2d(128),
36. # inplace-选择是否进行覆盖运算
37. nn.ReLU(inplace=True)
38.
39. )
40. #输出层,将通道数变为分类数量
41. self.fc = nn.Linear(128,num_classes)
42.
43. def forward(self,x):
44. #图片经过三层卷积,输出维度变为(batch_size,C_out,H,W)
45. out = self.conv(x)
46. #使用平均池化层将图片的大小变为1x1,第二个参数为最后输出的长和宽(这里默认相等了)
47. out = F.avg_pool2d(out,32)
48. #将张量out从shape batchx128x1x1 变为 batch x128
49. out = out.squeeze()
50. #输入到全连接层将输出的维度变为3
51. out = self.fc(out)
52. return out
注:可以从上面可以看出一共有6个空洞卷积层,其空洞率分别是1、2、5、1、2、5;1、2、5不包含大于1的公约数,所以其是包含2个的HDC,然后其每一层的输入和输出的算法见注释。
二:pytorch实现残差实验(torch实现)
要求:
从至少一个数据集上进行实验,这里我选取了车辆分类数据集,在给定结构的残差网络中,进行模型的搭建以及训练。
实验结构:
实验过程:
这里实验过程和4上面大部分一样,主要是模型设计不同,所以这里主要介绍一下给定的残差网络的模型实现代码。
2.1残差网络块的实现
1. #残差网络块
2. #每个残差块都是两层
3. #默认3*3卷积下padding为1,则大小不会变化,如变化则是步长引起的。
4. class ResidualBlock(nn.Module):
5. def __init__(self, nin, nout, size, stride=1, shortcut=True):
6. super(ResidualBlock, self).__init__()
7. #两层卷积层
8. #不同步长只有第一层卷积层不同
9. self.block1 = nn.Sequential(nn.Conv2d(nin, nout, size, stride, padding=1),
10. nn.BatchNorm2d(nout),
11. nn.ReLU(inplace=True),
12. nn.Conv2d(nout, nout, size, 1, padding=1),
13. nn.BatchNorm2d(nout))
14. self.shortcut = shortcut
15. #解决通道数变化以及步长不为1引起的图片大小的变化
16. self.block2 = nn.Sequential(nn.Conv2d(nin, nout, size, stride, 1),
17. nn.BatchNorm2d(nout))
18. self.relu = nn.ReLU(inplace=True)
19.
20. def forward(self, input):
21. x = input
22. out = self.block1(x)
23. '''''若输入输出维度相等直接相加,不相等改变输入的维度--包括大小和通道'''
24. if self.shortcut:
25. out = x + out
26. else:
27. out = out + self.block2(x)
28. out = self.relu(out)
29. return out
注:这部分主要借鉴的是ppt和网上残差的实现,主要定义了每个残差块内的卷积操作,给定的残差结构内都是两个卷积,,所以这里的self.block1就是其实现,然后因为在残差块的开始会有通道的改变,以及步长的改变,从而导致图片的长和宽变化,所以定义了self.shortcut定义是否会导致变化,然后利用self.block2定义的卷积进行改变输入的大小使得通道可以相加
2.2模型定义
1. #定义给定的残差结构
2. class resnet(nn.Module):
3. def __init__(self):
4. super(resnet, self).__init__()
5. self.block = nn.Sequential(nn.Conv2d(3, 64, 3, stride=1, padding=1),
6. nn.BatchNorm2d(64),
7. nn.ReLU())
8. #t表示2个相同的残差块,每个残差块两个卷积
9. self.d1 = self.make_layer(64, 64, 3, stride=1, t=2)
10. self.d2 = self.make_layer(64, 128, 3, stride=2, t=2)
11. self.d3 = self.make_layer(128, 256, 3, stride=2, t=2)
12. self.d4 = self.make_layer(256, 512, 3, stride=2, t=2)
13.
14. self.avgp = nn.AvgPool2d(8)
15. self.exit = nn.Linear(512, 3)
16.
17. def make_layer(self, in1, out1, ksize, stride, t):
18. layers = []
19. for i in range(0, t):
20. if i == 0 and in1 != out1:
21. layers.append(ResidualBlock(in1, out1, ksize, stride, None))
22. else:
23. layers.append(ResidualBlock(out1, out1, ksize, 1, True))
24. return nn.Sequential(*layers)
25.
26. def forward(self, input):
27. x = self.block(input) # 输出维度 64 * 64 * 64 C * H * W
28. x = self.d1(x) # 输出维度 64 * 54 * 54
29. x = self.d2(x) # i=0 步长为2,输出维度128 * 32 * 32
30. x = self.d3(x) # i=0 步长为2,输出维度256 * 16 * 16
31. x = self.d4(x) # i=0 步长为2,输出维度512 * 8 * 8
32. x = self.avgp(x) # 512 * 1 * 1
33. #将张量out从shape batchx512x1x1 变为 batch x512
34. x = x.squeeze()
35. output = self.exit(x)
36. return output
注:这部分就是主要的模型结构的实现,定义了make_layer函数可以进行相同连续残差块的计算,然后调用之前定义好的残差块。
完整代码及数据集下载,见:https://download.csdn.net/download/qq_37534947/13117846