刘二大人 Advanced CNN with Pytorch代码实现

Advanced CNN代码实现

Advanced CNN

  • 步骤
    • Prepare dataset
    • Design model using Class
    • Construct loss and optimizer
    • Training cycle


步骤

引入库

#引入torch
import torch
#从torchvision中引入图像转换
from torchvision import transforms
#从torchvision中引入数据集
from torchvision import datasets
#从torch的工具中的数据引入数据加载器
from torch.utils.data import DataLoader
#引入torch中的神经网络的激活函数(relu)
import torch.nn.functional as F
#引入torch中优化器
import torch.optim as optimle

Prepare dataset

#batch_size的大小是64
batch_size = 64
#用Compose组合多个transform操作
transform = transforms.Compose([
    #ToTensor将图像中的字节转换成tensor;
    transforms.ToTensor(),
    #Normalize将数据进行标准化,1是均值,2是标准差
    transforms.Normalize((0.1307, ),(0.3081, ))
])
#训练数据集的MNIST的数据集的根在mnist文件夹中
train_dataset = datasets.MNIST(root='../dataset/mnist',
                              #让训练等于真,提取训练集
                              train=True,
                              #下载等于真,下载数据集
                              download=True,
                              #transform直接应用上面的transform
                              transform=transform)
#训练加载器是数据加载器,引入训练数据集
train_loader = DataLoader(train_dataset,
                         #shuffle为真,将数据打乱
                         shuffle=True,
                         #batch的大小为前面设定好的大小
                         batch_size=batch_size)
#测试数据集的MNIST的数据集的根在mnist文件夹中
test_dataset = datasets.MNIST(root='../dataset/mnist/',
                             #训练为假,测试为真
                             train=False,
                             #下载为真,就是下载
                             download=True,
                             #transform直接应用上面的transform
                             transform=transform)
#测试加载器是数据加载器,引入测试数据集
test_loader = DataLoader(test_dataset,
                        #shuffle为假,不将数据打乱
                        shuffle=False,
                        #batch的大小为前面设定好的大小 
                        batch_size=batch_size)

Design model using Class

#设InceptionA为一个类,继承自Module模块
class InceptionA(torch.nn.Module):
    #自身初始化,初始输入通道需要代入自己设定的值。
    def __init__(self,in_channels):
        #调用父类初始化器
        super(InceptionA,self).__init__()
        #创建一个1x1的卷积通道,输入通道,输出通道是16,卷积核是1
        self.branch1x1 = torch.nn.Conv2d(in_channels,16,kernel_size=1)
        
        #创建5x5的卷积通道,输入通道,输出通道是16,卷积核是1
        self.branch5x5_1 = torch.nn.Conv2d(in_channels,16,kernel_size=1)
        #输入通道是16,输出通道是24,卷积核是5,为了保证维度大小不变,在外面围两圈
        self.branch5x5_2 = torch.nn.Conv2d(16,24,kernel_size=5,padding=2)
        
        #创建3x3的卷积通道,输入通道,输出通道是16,卷积核是1
        self.branch3x3_1 = torch.nn.Conv2d(in_channels,16,kernel_size=1)
        #输入通道是16,输出通道是24,卷积核是3,为了保证维度大小不变,在外面围一圈
        self.branch3x3_2 = torch.nn.Conv2d(16,24,kernel_size=3,padding=1)
        #输入通道是24,输出通道是24,卷积核是3,为了保证维度大小不变,在外面围一圈
        self.branch3x3_3 = torch.nn.Conv2d(24,24,kernel_size=3,padding=1)
        
        #池化层分支是卷积模型的输入通道数,输出通道数是24,卷积核是1个
        self.branch_pool = torch.nn.Conv2d(in_channels,24,kernel_size=1)
        
    #定义前向反馈
    def forward(self,x):
        #直接将x代入1x1得卷积中,得到结果
        branch1x1 = self.branch1x1(x)
        
        #将x直接代入到第一个5x5的卷积通道
        branch5x5 = self.branch5x5_1(x)
        #将第一个卷积通道的结果代入第二个通道求出结果
        branch5x5 = self.branch5x5_2(branch5x5)
        
        #将x直接代入到第一个3x3的卷积通道
        branch3x3 = self.branch3x3_1(x)
        #将第一个卷积通道的结果代入第二个通道求出结果
        branch3x3 = self.branch3x3_2(branch3x3)
        #将第二个卷积通道的结果代入第三个通道求出结果
        branch3x3 = self.branch3x3_3(branch3x3)
        
        #池化层是用的均值池化定义x,卷积核是3,步长是1,padding是1围一圈
        branch_pool = F.avg_pool2d(x,kernel_size=3,stride=1,padding=1)
        #将均值池化好的数据代入卷积层求出结果
        branch_pool = self.branch_pool(branch_pool)
        
        #输出等于这四个分支1x1,5x5,3x3,池化形成的一个数组
        outputs = [branch1x1,branch5x5, branch3x3,branch_pool]
        #用cat方法沿着输出的数据的维度为1方式将他们拼接起来
        return torch.cat(outputs,dim=1) #维度 batch chennel weight height
#设Net为一个类,继承自Module模块,网络
class Net(torch.nn.Module):
    #自身初始化
    def __init__(self):
        #调用父类初始化器
        super(Net,self).__init__()
        #第一层卷积层是用Conv2d模块,输入1,输出10,核5
        self.conv1 = torch.nn.Conv2d(1,10,kernel_size=5)
        #第二层卷积层是用Conv2d模块,输入88,输出20,核5。88是因为四个分支的总通道是88
        self.conv2 = torch.nn.Conv2d(88,20,kernel_size=5)
        #将输入通道10代入到InceptionA模型中
        self.incep1 = InceptionA(in_channels=10)
        #将输入通道20代入到InceptionA模型中
        self.incep2 = InceptionA(in_channels=20)
        
        #最大池化层是引入MaxPool2d模块,设卷积核数量为2
        self.mp = torch.nn.MaxPool2d(2)
        #全连接层是线性模型将输入1408变成输出10。经过每张28*28图像包括1408个元素
        self.fc = torch.nn.Linear(1408,10)
    #定义自身前馈计算
    def forward(self,x):
        #定义batch的大小是数据张量的第0个维度的数据,也就是样本的数量
        in_size = x.size(0)
        #先做卷积在做池化,最后激活
        x = F.relu(self.mp(self.conv1(x)))
        #将x代入到incep1中,求结果
        x = self.incep1(x)
        #先做卷积在做池化,最后激活
        x = F.relu(self.mp(self.conv2(x)))
        #将x代入到incep2中,求结果
        x = self.incep2(x)
        #用view改变x的形状,行为batch的大小,列自动计算得到
        x = x.view(in_size,-1)
        #代入线性模型求出结果
        x = self.fc(x)
        #返回x
        return x
model = Net() 
#定义装置,如果cuda是能用的,那你就用第一个显卡用cuda跑,否则用cpu跑
#device = torch.device("cuda:0"if torch.cuda.is_available()else"cpu")
#让模型在GPU上跑
#model.to(device)

Construct loss and optimizer

#损失的标准是交叉熵损失
criterion = torch.nn.CrossEntropyLoss()
#用优化模块中的SGD优化模型中所有的参数,学习率为0.01,加入动量为0.5,加入一个惯性,优化方向
optimizer = optim.SGD(model.parameters(),lr=0.01,momentum=0.5)

Training cycle

#定义训练过程,epoch是循环次数
def train(epoch):
    #设初始损失值是0
    running_loss = 0.0
    #batch_idx表示进行多少次的batch的迭代,data是数据,用列举的方法将train_loader的数据提取出来,从0开始
    for batch_idx, data in enumerate(train_loader,0):
        #将输入x和相应的目标y从数据中拿出来
        inputs, target = data
        #将输入和目标y都放到GPU上面
        #inputs, target = inputs.to(device),target.to(device)
        #用优化模块进行梯度归零
        optimizer.zero_grad()
        #将输入代入模型,求出输出y
        outputs = model(inputs)
        #将目标和输出代入标准器,计算损失
        loss = criterion(outputs, target)
        #反向传播
        loss.backward()
        #优化更新
        optimizer.step()
        #损失标量求和,求总的损失值
        running_loss += loss.item()
        #如果迭代次数除以300的余数等于299,每300轮输出一次
        if batch_idx % 300 == 299:
            #输出[%d代表是一位整数,%5d代表是5位,位数不够用空格填充],损失用小数点后三位浮点型表示。
            #%用于格式化输出的连接符号,总的循环次数+1,batch的循环次数+1,损失除以2000轮,求一次损失
            print('[%d,%5d] loss:%.3f'%(epoch + 1,batch_idx + 1,running_loss / 2000))
            #将损失归零
            running_loss = 0.0
def test():
    #正确的数量初始为0
    correct = 0
    #总数为0
    total = 0
    #用with方式让torch不计算梯度
    with torch.no_grad():
        #for循环data在测试加载器中
        for data in test_loader:
            #输入和目标送到数据里面
            inputs, target = data
            #将输入和目标y都放到GPU上面
            #inputs, target = inputs.to(device),target.to(device)
            #将输入代入模型,求输出
            outputs = model(inputs)
            #用torch中的max函数,沿着输出的数据的维度为1方式,找到最大值和最大值的下标,
            #_是最大值,predicted是最大值的下标
            _, predicted = torch.max(outputs.data,dim=1)
            #总数等于标签的size取第0个元素相加求得总数
            total += target.size(0)
            #正确是预测和标签相等标量求和
            correct += (predicted == target).sum().item()
    #输出%d代表整数,%%代表%,%格式化输出得连接符号,正确除总数乘100
    print('Accuracy on test set: %d %%' % (100 * correct / total)) 
#封装到if语句里面
if __name__ == '__main__':
    #循环10次
    for epoch in range(10):
        #训练
        train(epoch)
        #测试
        test()

你可能感兴趣的:(Pytorch,pytorch,cnn,深度学习)