深度学习实验2:卷积神经网络

深度学习实验2:卷积神经网络

二维卷积实验

手写二维卷积

导入相应的库

#导入相应的库
import torch  
import numpy as np  
import random  
from matplotlib import pyplot as plt  
import torch.utils.data as Data  
from PIL import Image  
import os  
from torch import nn  
import torch.optim as optim  
from torch.nn import init  
import torch.nn.functional as F  
import time  
import torchvision
from torchvision import transforms,datasets
from shutil import copy, rmtree
import json

将数据集放在对应的文件夹,按照3:1的比例划分数据集,将数据集的75%作为训练集,25%作为测试集,并生成相应的文件夹,将划分好的是数据集保存在里。
定义一个函数用来生成相应的文件夹

1.	def mk_file(file_path: str):
2.	    if os.path.exists(file_path):
3.	        # 如果文件夹存在,则先删除原文件夹在重新创建
4.	        rmtree(file_path)
5.	    os.makedirs(file_path)

定义划分数据集的函数split_data(),将数据集进行划分为训练集和测试集。首先读取每一类图片的文件名,然后将其打乱,并将其保存到对应的文件夹内。

1.	#定义函数划分数据集
2.	def split_data():
3.	    random.seed(0)
4.	    # 将数据集中25%的数据划分到验证集中
5.	    split_rate = 0.25
6.	
7.	    # 指向你解压后的flower_photos文件夹
8.	    cwd = os.getcwd()
9.	    data_root = os.path.join(cwd, "data_set")
10.	    origin_car_path = os.path.join(data_root, "car_set")
11.	    assert os.path.exists(origin_car_path), "path '{}' does not exist.".format(origin_flower_path)
12.	
13.	    car_class = [cla for cla in os.listdir(origin_car_path)
14.	                    if os.path.isdir(os.path.join(origin_car_path, cla))]
15.	
16.	    # 建立保存训练集的文件夹
17.	    train_root = os.path.join(data_root, "train")
18.	    mk_file(train_root)
19.	    for cla in car_class:
20.	        # 建立每个类别对应的文件夹
21.	        mk_file(os.path.join(train_root, cla))
22.	
23.	    # 建立保存验证集的文件夹
24.	    test_root = os.path.join(data_root, "test")
25.	    mk_file(test_root)
26.	    for cla in car_class:
27.	        # 建立每个类别对应的文件夹
28.	        mk_file(os.path.join(test_root, cla))
29.	        
30.	    for cla in car_class:
31.	        cla_path = os.path.join(origin_car_path, cla)
32.	        images = os.listdir(cla_path)
33.	        num = len(images)
34.	        # 随机采样验证集的索引
35.	        eval_index = random.sample(images, k=int(num*split_rate))
36.	        for index, image in enumerate(images):
37.	            if image in eval_index:
38.	                # 将分配至验证集中的文件复制到相应目录
39.	                image_path = os.path.join(cla_path, image)
40.	                new_path = os.path.join(test_root, cla)
41.	                copy(image_path, new_path)
42.	            else:
43.	                # 将分配至训练集中的文件复制到相应目录
44.	                image_path = os.path.join(cla_path, image)
45.	                new_path = os.path.join(train_root, cla)
46.	                copy(image_path, new_path)
47.	            print("\r[{}] processing [{}/{}]".format(cla, index+1, num), end="")  # processing bar
48.	        print()
49.	
50.	    print("processing done!")
51.	split_data()

将划分好的数据集利用DataLoader进行迭代读取,ImageFolder是pytorch中通用的数据加载器,不同类别的车辆放在不同的文件夹,ImageFolder可以根据文件夹的名字进行相应的转化。这里定义一个batch size为32.

1.	device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
2.	print("using {} device.".format(device))
3.	
4.	data_transform = {"train": transforms.Compose([transforms.Resize((64,64)),
5.	                               transforms.RandomHorizontalFlip(),
6.	                                transforms.ToTensor(),
7.	                              transforms.Normalize((0.5,0.5,0.5),
8.	                                                     (0.5,0.5,0.5))]),
9.	          "test": transforms.Compose([transforms.Resize((64,64)),
10.	                                      transforms.ToTensor(),
11.	                              transforms.Normalize((0.5,0.5,0.5),
12.	                                                    (0.5,0.5,0.5))])}
13.	
14.	data_root =os.getcwd()
15.	image_path = os.path.join(data_root,"data_set")
16.	print(image_path)
17.	
18.	
19.	train_dataset = datasets.ImageFolder(root=os.path.join(image_path,"train"),
20.	                                     transform = data_transform["train"])
21.	
22.	train_num = len(train_dataset)
23.	print(train_num)
24.	
25.	batch_size = 32
26.	
27.	train_loader = torch.utils.data.DataLoader(train_dataset,
28.	                                         batch_size = batch_size,
29.	                                           shuffle = True,
30.	                                           num_workers = 0)
31.	
32.	
33.	test_dataset = datasets.ImageFolder(root=os.path.join(image_path,"test"),
34.	                              transform = data_transform["test"])
35.	
36.	test_num = len(test_dataset)
37.	print(test_num)#val_num = 364
38.	test_loader = torch.utils.data.DataLoader(test_dataset,
39.	                                         batch_size = batch_size,
40.	                                          shuffle=False,
41.	                                           num_workers = 0)
42.	
43.	print("using {} images for training, {} images for validation .".format(train_num,test_num))

自定义卷积通道

  1. #自定义单通道卷积
2.	def corr2d(X,K):
3.	    X:输入,shape (batch_size,H,W) 
4.	    K:卷积核,shape (k_h,k_w) 
5.	 单通道 
6.	    '''
7.	    batch_size,H,W = X.shape
8.	    k_h,k_w = K.shape
9.	    #初始化结果矩阵
10.	    Y = torch.zeros((batch_size,H-k_h+1,W-k_w+1)).to(device)
11.	    for i in range(Y.shape[1]):  
12.	        for j in range(Y.shape [2]):  
13.	            Y[:,i,j] = (X[:,i:i+k_h,j:j+k_w]* K).sum()  
14.	    return Y
15.	#自定义多通道卷积
16.	def corr2d_multi_in(X,K):
17.	    '''
18.	    输入X:维度(batch_size,C_in,H, W)
19.	    卷积核K:维度(C_in,k_h,k_w)  
20.	    输出:维度(batch_size,H_out,W_out)  
21.	    '''
22.	    #先计算第一通道  
23.	    res = corr2d(X[:,0,:,:], K[0,:,:])  
24.	    for i in range(1, X.shape[1]):  
25.	        #按通道相加  
26.	        res += corr2d(X[:,i,:,:], K[i,:,:])  
27.	    return res  
28.	#自定义多个多通道卷积  
29.	def corr2d_multi_in_out(X, K):  
30.	 # X: shape (batch_size,C_in,H,W)  
31.	 # K: shape (C_out,C_in,h,w)  
32.	# Y: shape(batch_size,C_out,H_out,W_out)  
33.	    return torch.stack([corr2d_multi_in(X, k) for k in K],dim=1) 

自定义卷积层

  1. #自定义卷积层
2.	class MyConv2D(nn.Module):  
3.	    def __init__(self,in_channels, out_channels,kernel_size):  
4.	        super(MyConv2D,self).__init__()  
5.	        #初始化卷积层的2个参数:卷积核、偏差  
6.	       #isinstance判断类型  
7.	        if isinstance(kernel_size,int):  
8.	            kernel_size = (kernel_size,kernel_size)  
9.	            self.weight = nn.Parameter(torch.randn((out_channels, in_channels) + kernel_size)).to(device)  
10.	            self.bias = nn.Parameter(torch.randn(out_channels,1,1)).to(device)  
11.	    def forward(self,x):    #x:输入图片,维度(batch_size,C_in,H,W) 
12.	        return corr2d_multi_in_out(x,self.weight) + self.bias

添加自定义卷积层到模块中

1.	#添加自定义卷积层到模块中  
2.	class MyConvModule(nn.Module):  
3.	    def __init__(self):  
4.	        super(MyConvModule,self).__init__()  
5.	        #定义一层卷积层  
6.	        self.conv = nn.Sequential(  
7.	            MyConv2D(in_channels = 3,out_channels = 32,kernel_size = 3),  
8.	            nn.BatchNorm2d(32),  
9.	            # inplace-选择是否进行覆盖运算  
10.	            nn.ReLU(inplace=True))  
11.	        #输出层,将通道数变为分类数量  
12.	        self.fc = nn.Linear(32,num_classes)  
13.	
14.	    def forward(self,x):  
15.	        #图片经过一层卷积,输出维度变为(batch_size,C_out,H,W)  
16.	        out = self.conv(x)  
17.	        #使用平均池化层将图片的大小变为1x1,第二个参数为最后输出的长和宽(这里默认相等了)64-3/1 + 1 =62  
18.	        out = F.avg_pool2d(out,62)  
19.	        #将张量out从shape batchx32x1x1 变为 batch x32  
20.	        out = out.squeeze()  
21.	        #输入到全连接层将输出的维度变为3  
22.	        out = self.fc(out)  
23.	        return out  

定义超参数

1.	num_classes = 3  
2.	lr = 0.001
3.	epochs = 5 

初始化模型、定义损失函数和优化器

1.	#初始化模型、定义损失函数和优化器
2.	#初始化模型  
3.	net = MyConvModule().to(device)  
4.	#使用多元交叉熵损失函数  
5.	criterion = nn.CrossEntropyLoss()  
6.	#使用Adam优化器  
7.	optimizer = optim.Adam(net.parameters(),lr = lr)  

定义模型训练和测试函数,输出训练集和测试集的损失和精确度

1.	def train_epoch(net, data_loader, device):  
2.	
3.	    net.train() #指定当前为训练模式  
4.	    train_batch_num = len(data_loader) #记录共有多少个batch   
5.	    total_1oss = 0 #记录Loss  
6.	    correct = 0 #记录共有多少个样本被正确分类  
7.	    sample_num = 0 #记录样本总数  
8.	
9.	    #遍历每个batch进行训练  
10.	    for batch_idx, (data,target) in enumerate (data_loader): 
11.	        t1 = time.time()
12.	        #将图片放入指定的device中  
13.	        data = data.to(device).float()  
14.	        #将图片标签放入指定的device中  
15.	        target = target.to(device).long()  
16.	        #将当前梯度清零  
17.	        optimizer.zero_grad()  
18.	        #使用模型计算出结果  
19.	        output = net(data)  
20.	        #计算损失  
21.	        loss = criterion(output, target.squeeze())  
22.	        #进行反向传播  
23.	        loss.backward()  
24.	        optimizer.step()  
25.	        #累加loss  
26.	        total_1oss += loss.item( )  
27.	        #找出每个样本值最大的idx,即代表预测此图片属于哪个类别  
28.	        prediction = torch.argmax(output, 1)  
29.	        #统计预测正确的类别数量  
30.	        correct += (prediction == target).sum().item()  
31.	        #累加当前的样本总数  
32.	        sample_num += len(prediction)
33.	        #if batch_idx//5 ==0:
34.	        t2 = time.time()
35.	        print("processing:{}/{},消耗时间{}s".
36.	                      format(batch_idx+1,len(data_loadera),t2-t1))
37.	            
38.	    #计算平均oss与准确率  
39.	    loss = total_1oss / train_batch_num  
40.	    acc = correct / sample_num  
41.	    return loss, acc  
42.	
43.	def test_epoch(net, data_loader, device):  
44.	    net.eval() #指定当前模式为测试模式  
45.	    test_batch_num = len(data_loader)  
46.	    total_loss = 0  
47.	    correct = 0  
48.	    sample_num = 0  
49.	    #指定不进行梯度变化  
50.	    with torch.no_grad():  
51.	        for batch_idx, (data, target) in enumerate(data_loader):  
52.	            data = data.to(device).float()  
53.	            target = target.to(device).long()   
54.	            output = net(data)  
55.	            loss = criterion(output, target)  
56.	            total_loss += loss.item( )  
57.	            prediction = torch.argmax(output, 1)  
58.	            correct += (prediction == target).sum().item()  
59.	            sample_num += len(prediction)  
60.	    loss = total_loss / test_batch_num  
61.	    acc = correct / sample_num  
62.	    return loss,acc 

开始训练

1.	#### 存储每一个epoch的loss与acc的变化,便于后面可视化  
2.	train_loss_list = []  
3.	train_acc_list = []  
4.	test_loss_list = []  
5.	test_acc_list = []  
6.	time_list = []  
7.	timestart = time.time()  
8.	#进行训练  
9.	for epoch in range(epochs):  
10.	    #每一个epoch的开始时间  
11.	    epochstart = time.time()  
12.	
13.	    #在训练集上训练  
14.	    train_loss, train_acc = train_epoch(net,data_loader=train_loader, device=device )  
15.	    #在测试集上验证  
16.	    test_loss, test_acc = test_epoch(net,data_loader=test_loader, device=device)  
17.	
18.	    #每一个epoch的结束时间  
19.	    elapsed = (time.time() - epochstart)  
20.	    #保存各个指际  
21.	    train_loss_list.append(train_loss)  
22.	    train_acc_list.append(train_acc )  
23.	    test_loss_list.append(test_loss)  
24.	    test_acc_list.append(test_acc)  
25.	    time_list.append(elapsed)  
26.	    print('epoch %d, train_loss %.6f,test_loss %.6f,train_acc %.6f,test_acc %.6f,Time used %.6fs'%(epoch+1, train_loss,test_loss,train_acc,test_acc,elapsed))  
27.	#计算总时间  
28.	timesum = (time.time() - timestart)  
29.	print('The total time is %fs',timesum) 

3.1.2 torch.nn实现二维卷积
与手写二维卷积除了模型定义和绘制训练图像部分代码不同以外,其他均相同,主要针对模型定义以及绘图函数进行介绍
定义模型
利用torch.nn模块定义模型,卷积层设为三层,输入为64×64,经过三层卷积过后其大小变为58×58

1.	   #pytorch封装卷积层
2.	class ConvModule(nn.Module):  
3.	    def __init__(self):  
4.	        super(ConvModule,self).__init__()  
5.	        #定义三层卷积层  
6.	        self.conv = nn.Sequential(  
7.	            #第一层  
8.	            nn.Conv2d(in_channels = 3,out_channels = 32,
9.	                         kernel_size = 3 , stride = 1,padding=0),  
10.	            nn.BatchNorm2d(32),  
11.	            # inplace-选择是否进行覆盖运算  
12.	            nn.ReLU(inplace=True),  
13.	            #第二层  
14.	            nn.Conv2d(in_channels = 32,out_channels = 64,
15.	                         kernel_size = 3 , stride = 1,padding=0),  
16.	            nn.BatchNorm2d(64),  
17.	            # inplace-选择是否进行覆盖运算  
18.	            nn.ReLU(inplace=True),  
19.	            #第三层  
20.	            nn.Conv2d(in_channels = 64,out_channels = 128,
21.	                        kernel_size = 3 , stride = 1,padding=0),  
22.	            nn.BatchNorm2d(128),  
23.	            # inplace-选择是否进行覆盖运算  
24.	            nn.ReLU(inplace=True)  
25.	        )  
26.	        #输出层,将通道数变为分类数量  
27.	        self.fc = nn.Linear(128,num_classes)  
28.	
29.	    def forward(self,x):  
30.	        #图片经过三层卷积,输出维度变为(batch_size,C_out,H,W)  
31.	        out = self.conv(x)  
32.	        #使用平均池化层将图片的大小变为1x1,第二个参数为最后输出的长和宽(这里默认相等了)(64-3)/1 + 1 =62  (62-3)/1+1 =60 (60-3)/1+1 =58  
33.	        out = F.avg_pool2d(out,58)  
34.	        #将张量out从shape batchx128x1x1 变为 batch x128  
35.	        out = out.squeeze()  
36.	        #输入到全连接层将输出的维度变为3  
37.	        out = self.fc(out)  
38.	        return out  

定义绘制loss图像的函数,函数输入可变参数,我们可以输入多个train_loss,test_loss参数,然后进行绘图,默认横坐标为epoch,纵坐标为loss,也可以根据实际进行调整,本次实验所有的绘图均由Draw_Curve()函数完成,后面不再赘叙。

1. 	import matplotlib.pyplot as plt
2. 	def Draw_Curve(*args,xlabel = "epoch",ylabel = "loss"):#
3. 	    for i in args:
4. 	        x = np.linspace(0,len(i[0]),len(i[0]))  
5. 	        plt.plot(x,i[0],label=i[1],linewidth=1.5)  
6. 	    plt.xlabel(xlabel)
7. 	    plt.ylabel(ylabel)
8. 	    plt.legend()
9. 	    plt.show()
10. 	Draw_Curve([train_acc,"train_acc"],[test_acc,"test_acc"],ylabel = "acc")
11. 	Draw_Curve([train_loss,"train_loss"],[test_loss,"test_loss"])

不同超参数的对比分析

学习lr对模型的影响,选择学习率lr=0.1、0.01、0.001、0.0001、0.00001进行模型训练。
Batch size对模型的影响,通过设置batch size为16、32、64、128进行模型训练,评估模型的损失和准确率

Alexnet网络

可以参考之前的博文

由于输入的图像为64×64,如果按照原始的Alax网络的参数进行定义网络,第一个卷积层的卷积核尺寸为11×11,步长stride为4,导致卷积过后的一些图像尺寸过小,丢失了图像特征,影响模型的精度。因此,本次实验,根据实验数据集的图像特点,对Alexnet网络的特征提取部分参数进行了修改,具体网络结构见图2:

图2 Alexnet网络结构

1.	class AlexNet(nn.Module):
2.	    def __init__(self,num_classes = 1000,init_weights = False):
3.	        super(AlexNet,self).__init__()
4.	        self.features = nn.Sequential(#输入64×64×3
5.	            nn.Conv2d(3,48,kernel_size=3,stride=1,padding=1),#64,64,48
6.	            nn.ReLU(inplace=True),
7.	            nn.MaxPool2d(kernel_size=2,stride=2),#32,32,48
8.	
9.	            nn.Conv2d(48,128,kernel_size=3,padding=1),#32,32,128
10.	            nn.ReLU(inplace=True),
11.	            nn.MaxPool2d(kernel_size=2,stride=2),#16,16,128
12.	
13.	            nn.Conv2d(128,192,kernel_size=3,padding=1),#16,16,192
14.	            nn.ReLU(inplace=True),
15.	
16.	            nn.Conv2d(192,192,kernel_size=3,stride=2,padding=1),#8,8,192
17.	            nn.ReLU(inplace=True),
18.	
19.	            nn.Conv2d(192,128,kernel_size=3,padding=1),#8,8,128
20.	            nn.ReLU(inplace=True),
21.	            nn.MaxPool2d(kernel_size=2,stride=2),#4,4,128
22.	        )
23.	        self.classifier = nn.Sequential(
24.	            nn.Dropout(p=0.5),
25.	            nn.Linear(128*4*4,2048),
26.	            nn.ReLU(inplace=True),
27.	            nn.Dropout(p=0.5),
28.	            nn.Linear(2048,2048),
29.	            nn.ReLU(inplace=True),
30.	            nn.Linear(2048,num_classes),
31.	        )
32.	        if init_weights:
33.	            self._initialize_weights()
34.	
35.	    def forward(self,x):
36.	        x = self.features(x)
37.	        x = torch.flatten(x,start_dim=1)
38.	        x = self.classifier(x)
39.	        return x

3.2 空洞卷积实验
为了增加增加卷积层的感受野,将普通卷积的改为空洞卷积,空洞卷积网络的搭建定义了三个卷积层,空洞率为分别为1、2、5,符合HDC条件。本次实验的其他部分和二维卷积实验部分相同。

1.	#pytorch封装卷积层  
2.	class ConvModule(nn.Module):  
3.	    def __init__(self):  
4.	        super(ConvModule,self).__init__()  
5.	        #定义一个空洞率为1、2、5的三层空洞卷积 
6.	        self.conv = nn.Sequential(  
7.	            #第一层 (3-1)*1+1=3 (64+2-3)/2 + 1 =32   
8.	            nn.Conv2d(in_channels = 3,out_channels = 32,kernel_size = 3 , stride = 2,padding=1,dilation=1),  
9.	            nn.BatchNorm2d(32),  
10.	            # inplace-选择是否进行覆盖运算  
11.	            nn.ReLU(inplace=True),  
12.	            #第二层 (3-1)*2+1=5 (32-5)/2 + 1 =14.5   
13.	            nn.Conv2d(in_channels = 32,out_channels = 64,kernel_size = 3 , stride = 2,padding=0,dilation=2),  
14.	            nn.BatchNorm2d(64),  
15.	            # inplace-选择是否进行覆盖运算  
16.	            nn.ReLU(inplace=True),  
17.	            #第三层 (3-1)*5+1=11  (14-11)/2 +1=2  
18.	            nn.Conv2d(in_channels = 64,out_channels = 128,kernel_size = 3 , stride = 2,padding=0,dilation=5),  
19.	            nn.BatchNorm2d(128),  
20.	            # inplace-选择是否进行覆盖运算  
21.	            nn.ReLU(inplace=True),          
22.	        )  
23.	        #输出层,将通道数变为分类数量  
24.	
25.	        self.fc = nn.Linear(128,num_classes)  
26.	        
27.	    def forward(self,x):  
28.	        #图片经过三层卷积,输出维度变为(batch_size,C_out,H,W)  
29.	        out = self.conv(x)  
30.	        #使用平均池化层将图片的大小变为1x1,第二个参数为最后输出的长和宽(这里默认相等了)   
31.	        out = F.avg_pool2d(out,2)  
32.	        #将张量out从shape batchx128x1x1 变为 batch x128  
33.	        out = out.squeeze()  
34.	        #输入到全连接层将输出的维度变为3  
35.	        out = self.fc(out)  
36.	        return out 

3.3 残差网络实验
定义resnet网络的残差模块ResidualBlock。

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  

模型定义

1.	class resnet(nn.Module):  
2.	    def __init__(self):  
3.	        super(resnet, self).__init__()  
4.	        self.block = nn.Sequential(nn.Conv2d(3, 64, 3, stride=1, padding=1),  
5.	                                   nn.BatchNorm2d(64),  
6.	                                   nn.ReLU())  
7.	        #t表示2个相同的残差块,每个残差块两个卷积  
8.	        self.d1 = self.make_layer(64, 64, 3, stride=1, t=2)  
9.	        self.d2 = self.make_layer(64, 128, 3, stride=2, t=2)  
10.	        self.d3 = self.make_layer(128, 256, 3, stride=2, t=2)  
11.	        self.d4 = self.make_layer(256, 512, 3, stride=2, t=2)  
12.	        self.avgp = nn.AvgPool2d(8)  
13.	        self.exit = nn.Linear(512, 3)  
14.	        
15.	    def make_layer(self, in1, out1, ksize, stride, t):  
16.	        layers = []  
17.	        for i in range(0, t):  
18.	            if i == 0 and in1 != out1:  
19.	                layers.append(ResidualBlock(in1, out1, ksize, stride, None))  
20.	            else:  
21.	                layers.append(ResidualBlock(out1, out1, ksize, 1, True))  
22.	        return nn.Sequential(*layers)  
23.	    
24.	    def forward(self, input):  
25.	        x = self.block(input)  #64 * 64 * 64    C * H * W  
26.	        x = self.d1(x)  # 64 * 54 * 54  
27.	        x = self.d2(x)  # 128 * 32 * 32  
28.	        x = self.d3(x)  # 256 * 16 * 16   
29.	        x = self.d4(x)  # 512 * 8 * 8  
30.	        x = self.avgp(x)  # 512 * 1 * 1  
31.	        #将张量out从shape batchx512x1x1 变为 batch x512  
32.	        x = x.squeeze()  
33.	        output = self.exit(x)  
34.	        return output  

利用空洞卷积改写残差网络
在残差模块的第一个卷积层的膨胀率改为2,为了保证残差边可以与卷积之后的结果与之相加,在残差边上的卷积层将膨胀率改为2,使数据尺寸可以相加,重新对输入与输出图片尺寸进行计算。发现改变之后网络计算变得更加耗时,因此本次实验在一次卷积之后,堆叠两个残差模块。

1.	class ResidualBlock(nn.Module):  
2.	    def __init__(self, nin, nout, size, stride=1, shortcut=True)
3.	        super(ResidualBlock, self).__init__()  
4.	        #两层卷积层  
5.	        #不同步长只有第一层卷积层不同  
6.	        self.block1 = nn.Sequential(nn.Conv2d(nin, nout, size, stride, padding=1,dilation=2), # (3-1)*2+1=5  
7.	                                    nn.BatchNorm2d(nout),  
8.	                                    nn.ReLU(inplace=True),  
9.	                                    nn.Conv2d(nout, nout, size, 1, padding=1,dilation=1), # 
10.	                                    nn.BatchNorm2d(nout))  
11.	        self.shortcut = shortcut  
12.	        #解决通道数变化以及步长不为1引起的图片大小的变化 
13.	        self.block2 = nn.Sequential(nn.Conv2d(nin, nout, size, stride, 1,dilation=2),  
14.	                                    nn.BatchNorm2d(nout))  
15.	        self.relu = nn.ReLU(inplace=True)  
16.	        
17.	    def forward(self, input):  
18.	        x = input  
19.	        out = self.block1(x)  
20.	'''若输入输出维度相等直接相加,不相等改变输入的维度--包括大小和通道'  
21.	        if self.shortcut:  
22.	            out = x + out  
23.	        else:  
24.	            out = out + self.block2(x)  
25.	        out = self.relu(out)  
26.	        return out  
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值