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()