PyTorch 深度学习实践 第11讲(inception的使用)

Inception Moudel

1、卷积核超参数选择困难,自动找到卷积的最佳组合。

2、1x1卷积核,不同通道的信息融合。使用1x1卷积核虽然参数量增加了,但是能够显著的降低计算量(operations)

3、Inception Moudel由4个分支组成,要分清哪些是在Init里定义,哪些是在forward里调用。4个分支在dim=1(channels)上进行concatenate。24+16+24+24 = 88

第一个inception具体计算:

 

#实现inception model
import torch
import torch.nn as nn
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F
import torch.optim as optim
import matplotlib.pyplot as plt

batch_size=64
transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,),(0.3081,))])

train_dataset=datasets.MNIST(root="dataset/mnist",train='True',download="False",transform=transform)
train_loader=DataLoader(train_dataset,shuffle="True",batch_size=batch_size)
test_dataset=datasets.MNIST(root="dataset/mnist",train="False",download="False",transform=transform)
test_loader=DataLoader(test_dataset,shuffle="False",batch_size=batch_size)

class InceptionA(nn.Module):
    def __init__(self,in_channel):
        super(InceptionA,self).__init__()

        self.branch1x1=nn.Conv2d(in_channel,16,kernel_size=1)#输入外界通道数,经过1*1的卷积核,输出通道16

        self.branch5x5_1=nn.Conv2d(in_channel,16,kernel_size=1)#输入外界通道数,经过1*1的卷积核,输出通道16
        self.branch5x5_2=nn.Conv2d(16,24,kernel_size=5,padding=2)#连接branch5x5_1,输入通道16,输出通道24,经过5*5的卷积,padding=2表示在输入图像的每边填充2个像素,使得输出特征图与输入特征图的尺寸相同

        self.branch3x3_1=nn.Conv2d(in_channel,16,kernel_size=1)#输入外界通道数,经过1*1的卷积核,输出通道16
        self.branch3x3_2=nn.Conv2d(16,24,kernel_size=3,padding=1)#连接branch3x3_1,输入通道16,输出通道24,经过3*3的卷积,padding=1表示在输入图像的每边填充1个像素,使得输出特征图与输入特征图的尺寸相同
        self.branch3x3_3=nn.Conv2d(24,24,kernel_size=3,padding=1)#连接branch3x3_2,输入通道24,输出通道24,经过3*3的卷积,padding=1表示在输入图像的每边填充1个像素,使得输出特征图与输入特征图的尺寸相同

        self.batch_pool=nn.Conv2d(in_channel,24,kernel_size=1)#输入外界通道数,经过1*1的卷积核,输出通道24

    def forward(self,x):
        #处理路径1
        branch1=self.branch1x1(x)
        #处理路径2
        branch5=self.branch5x5_1(x)
        branch5=self.branch5x5_2(branch5)
        #处理路径3
        branch3=self.branch3x3_1(x)
        branch3=self.branch3x3_2(branch3)
        branch3=self.branch3x3_3(branch3)
        #处理路径4
        batch_pool=F.avg_pool2d(x,kernel_size=3,stride=1,padding=1)
        batch_pool=self.batch_pool(batch_pool)
        #4条路径进行融合
        outputs=[branch1,branch5,branch3,batch_pool]#outputs包含来自4条路径的4个特征图,他们具有相同的高度和宽度,不同的通道数
        return torch.cat(outputs,dim=1)#torch.cat()用于在指定维度上连接多个张量,此处将四个特征图在通道数这个维度上进行连接起来

class Net(nn.Module):
    def __init__(self):
        super(Net,self).__init__()

        self.conv1=nn.Conv2d(1,10,kernel_size=5)#原始图像单灰度维度为batch_size*1*28*28,经过卷积核5*5,变成batch_size*10*24*24
        self.conv2=nn.Conv2d(88,20,kernel_size=5)#输入通道88,经过5*5的卷积和输出通道为20
        #88的由来:经过inception的四条路径:16+24+24+24=88

        self.inception1=InceptionA(in_channel=10)#经过inception,输入通道10
        self.inception2=InceptionA(in_channel=20)#经过inception,输入通道20

        self.mp=nn.MaxPool2d(2)#经过最大池化层,池化层参数为2

        self.fc=nn.Linear(1408,10)#全连接层,输出10个维度(分类的10个维度)

    def forward(self,x):
        in_size=x.size(0)#得到原始数据的条数
        x = F.relu(self.mp(self.conv1(x)))#经过卷积层[batch_size*1*28*28--(1*10*5*5)-->batch_size*10*24*24],再经过池化层,--batch_size*10*12*12
        x=self.inception1(x)#经过inception,输入batch_size*10*12*12
        x = F.relu(self.mp(self.conv2(x)))
        x=self.inception2(x)
        x=x.view(in_size,-1)
        x=self.fc(x)
        return x

model=Net()

criterion=torch.nn.CrossEntropyLoss()#定义损失函数
optimizer=optim.SGD(model.parameters(),lr=0.01,momentum=0.5)#定义优化器,momentum称之为动量,取值范围为0-1,用于加快优化过程,使得梯度更新更加平滑地进行,不容易陷入局部最小值,0.5的取值表示考虑过去一半的梯度

def train(epoch):#训练函数
    running_loss=0.0
    for batch_idx,data in enumerate(train_loader,0):#enumerate将加载的数据集在每次的epoch中生成一个分批次,每个批次给与一个索引,从0开始赋值给batch_id
        inputs,labels=data#给x,y赋值
        optimizer.zero_grad()#训练之前梯度清零
        outputs=model(inputs)#进行预测
        loss=criterion(outputs,labels)#根据损失函数计算损失值
        loss.backward()#反向传递
        optimizer.step()#梯度更新
        running_loss+=loss.item()#对损失值进行求和
        if batch_idx%300==299:#每300个批次进行暑促,输出300个批次的平均损失值
            print("[%d,%5d]loss:%.8f"%(epoch+1,batch_idx+1,running_loss/300))
            running_loss=0#归零,重新进行记录

accuracy_list = []
def test():
    correct = 0
    total = 0
    with torch.no_grad():
        for data in test_loader:#只是为了将真实值与预测值进行对比,不需要在分批次
            images,targets=data#给x,y赋值
            output=model(images)#得到预测值
            _,predicted=torch.max(output.data,dim=1)#torch.max()函数,用于在指定维度上找到最大值
            #output.data是一个二维张量,每一行对应一个样本,对应列值代表每个类别的概率值,dim用于指定维度,意思是从每一行中找出值最大的
            #_表示占位符,用于存储最大值,predicted用于存储概率最大的索引,也就是概率最大的列,也就是我们的预测值
            #如果想要获取每一列的最大值,那么dim取0,pytorch中的维度从0开始编号,0表示列,1表示行
            total+=targets.size(0)#得到源数据的条数
            correct+=(predicted==targets).sum().item()#predicted==targets进行逐个元素的张量比较,得到一个布尔型张量,sum()进行布尔张量求和,因为都是张量计算后item()得到数值
        accuracy_list.append(100*correct/total)  # 将准确率添加到列表中
        print("accuracy on test set:%d %%"%(100*correct/total))
if __name__=="__main__":
    for epoch in range(30):
        train(epoch)
        test()

plt.plot(range(1,31), accuracy_list)  # x轴为epoch,y轴为准确率
plt.xlabel("Epoch")
plt.ylabel("Accuracy (%)")
plt.title("Accuracy vs. Epoch")
plt.grid(True)
plt.show()

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值