pytorch实现空洞卷积+残差网络实验(torch实现)

一: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实现)
要求:
从至少一个数据集上进行实验,这里我选取了车辆分类数据集,在给定结构的残差网络中,进行模型的搭建以及训练。
实验结构:
pytorch实现空洞卷积+残差网络实验(torch实现)_第1张图片

实验过程:
这里实验过程和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

你可能感兴趣的:(深度学习实验)