天天看點

PyTorch ------GoogLeNet卷積神經網絡實作mnist手寫體識别

  • 計劃将所有的經典模型使用pytorch在搞一遍
  • 接上一篇NIN現實mnist手寫識别
  • 使用經典模型GoogLeNet模型實作相同的功能
  • GoogLeNet論文原文位址

GoogLeNet簡介

GoogLeNet是2014年提出的一種全新的深度學習結構,在這之前的AlexNet、VGG、NIN等結構都通過增大網絡深度(層數)來獲得更好的訓練效果,但層數的增加會帶來很多負作用,比如overfit、梯度消失、梯度爆炸等。inception從另一種角度來提升訓練結果:在相同的計算量下能提取到更多的特征,進而提升性能

  • GoogLeNet 由Inception基礎塊組成
  • Inception塊相當于一個有4條子線路的小網絡,它通過不同的filter卷積層和最大池化層來并行抽取資訊,并使用1X1卷積層減少通道數進而降低模型複雜度.
  • 可以自定義的超參數是每個層的輸出通道數沒我們以此來控制模型的複雜度.
  • inception 經曆了V1、V2、V3、V4 多個版本發展,不斷調整完善
  • inception V1 Block structure:
    • PyTorch ------GoogLeNet卷積神經網絡實作mnist手寫體識别
    • 前面也介紹過1X1卷積核的作用:
      • 為了減少次元,消除計算瓶頸
      • 增加深度而不會降低性能
      • 還用于修正線性激活函數,
      • 還可以減少很多的可訓練參數

GoogLeNet模型

  • 完整模型結構
  • PyTorch ------GoogLeNet卷積神經網絡實作mnist手寫體識别
    • GoogLeNet采用了可以重複堆疊使用的Inception Block 該做法,與前面介紹的VGG類似
    • GoogLeNet采用GAP代替全連接配接層,與前面介紹的NIN子產品的想法也類似
    • 汲取前面模型的優點
  • GoogLeNet網絡結構細節表圖:
  • PyTorch ------GoogLeNet卷積神經網絡實作mnist手寫體識别
  • 輸入原始圖檔尺寸224X224X3
  • 上表中“#3x3 reduce”,“#5x5 reduce”表示在3x3,5x5卷積操作之前使用了1x1卷積的數量
  • 其他的都可以看懂,就不解釋了
  • 下面還是老節目,上代碼:

    import sys import torch import torch.nn as nn import torch.optim as optim import time import torchvision import torchvision.transforms as transforms from torchviz import make_dot import matplotlib.pyplot as plt import torch.nn.functional as F device = torch.device(“cuda” if torch.cuda.is_available() else “cpu”) class GlobalAvgPool2d(nn.Module): #全局平均池化層可通過将池化視窗形狀設定成輸入的高和寬實作 def init(self): super(GlobalAvgPool2d, self).init() def forward(self, x): return F.avg_pool2d(x, kernel_size=x.size()[2:]) class FlattenLayer(torch.nn.Module): def init(self): super(FlattenLayer, self).init() def forward(self, x): # x shape: (batch, *, *, …) return x.view(x.shape[0], -1) #計算準确率 def evaluate_accuracy(data_iter,net,device = torch.device(“cpu”)): #建立 正确率 和 總個數 acc_sum ,n = torch.tensor([0],dtype=torch.float32,device=device),0 for X,y in data_iter: # 适配 裝置 X,y = X.to(device),y.to(device) # 設定 驗證模式 net.eval() with torch.no_grad(): #隔離開 不要計算在計算圖内 y = y.long()#在這裡将y轉成long确實是不必要的。但是在計算交叉熵時,Pytorch強制要求y是long acc_sum += torch.sum((torch.argmax(net(X),dim=1) == y)) # 累計預測正确的個數 n += y.shape[0] # 累計總的标簽個數 return acc_sum.item() / n #下載下傳資料 組裝好訓練資料 測試資料 def load_data_fashion_mnist(batch_size,resize = None,root = “./dataset/input/FashionMNIST2065”): trans = [] if resize: # 做資料增強 處理 将圖檔轉化為 規定大小 資料内容不會丢失 等比例 處理 trans.append(torchvision.transforms.Resize(size=resize)) #将 圖檔 類型 轉化為Tensor類型 trans.append(torchvision.transforms.ToTensor()) #将圖檔 增強方式 添加到Compose 類中處理 transform = torchvision.transforms.Compose(trans) #讀取訓練資料 mnist_train = torchvision.datasets.FashionMNIST(root=root,train=True,download=False,transform = transform) #讀取 測試資料 mnist_test = torchvision.datasets.FashionMNIST(root = root,train=False,download=False,transform = transform) #資料加載器 在訓練 測試階段 使用多線程按批采樣資料 預設不使用多線程 num_worker 表示設定的線程數量 train_iter = torch.utils.data.DataLoader(mnist_train,batch_size = batch_size,shuffle = True,num_workers = 2) test_iter = torch.utils.data.DataLoader(mnist_test,batch_size = batch_size,shuffle = False,num_workers = 2) return train_iter,test_iter batch_size = 16 #如出現“out of memory”的報錯資訊,可減小batch_size或resize train_iter,test_iter = load_data_fashion_mnist(batch_size,224) def train_fit(net,train_iter,test_iter,batch_size,optimizer,device,num_epochs): #将讀取的資料 拷貝到 指定的GPU上 net = net.to(device) print("tainning on ",device) #設定 損失函數 交叉熵損失函數 loss = torch.nn.CrossEntropyLoss() #設定訓練次數 for epoch in range(num_epochs): train_l_sum,train_acc_sum,n,batch_count,start = 0.0,0.0,0,0,time.time() # 讀取批量資料 進行訓練 for X,y in train_iter: X = X.to(device) y = y.to(device) # 訓練結果 y_hat = net(X) # 計算 預測與标簽分布 差異 l = loss(y_hat,y) # 優化函數 梯度置為零 # 1、因為梯度可以累加 # 2、每批采樣的梯度不同,隻需記錄本次樣本的梯度 optimizer.zero_grad() # 反向求導 l.backward() # 更新權重參數 optimizer.step() train_l_sum += l.cpu().item() #train_acc_sum += (torch.argmax(y_hat,dim = 1) == y).cpu().item() #将張量元素值累計 train_acc_sum += (y_hat.argmax(dim=1) == y).sum().cpu().item() n += y.shape[0] batch_count += 1 test_acc = evaluate_accuracy(test_iter,net) print(‘epoch %d, loss %.4f, train acc %.3f, test acc %.3f, time %.1f sec’ % (epoch + 1, train_l_sum / batch_count, train_acc_sum / n, test_acc, time.time() - start)) #建立Inception block class Inception(nn.Module): def init(self,in_c,c1,c2,c3,c4): super(Inception,self).init() self.p1_1 = nn.Conv2d(in_c,c1,kernel_size=1) self.p2_1 = nn.Conv2d(in_c,c1,kernel_size=1) self.p2_2 = nn.Conv2d(c2[0],c2[1],kernel_size=3,padding=1) self.p3_1 = nn.Conv2d(in_c,c3[0],kernel_size=1) self.p3_2 = nn.Conv2d(c3[0],c3[1],kernel_size=5,padding=2) self.p4_1 = nn.MaxPool2d(kernel_size=3,stride=1,padding=1) self.p4_2 = nn.Conv2d(in_c,c4,kernel_size=1) def forward(self, x): p1 = F.relu(self.p1_1(x)) p2 = F.relu(self.p2_2(F.relu(self.p2_1(x)))) p3 = F.relu(self.p3_2(F.relu(self.p3_1(x)))) p4 = F.relu(self.p4_2(F.relu(self.p4_1(x)))) return torch.cat((p1,p2,p3,p4),dim=1) b1 = nn.Sequential( nn.Conv2d(1,64,kernel_size=7,stride=2,padding=3), nn.ReLU(), nn.MaxPool2d(kernel_size=3,stride=2,padding=1) ) b2 = nn.Sequential( nn.Conv2d(64,64,kernel_size=1), nn.Conv2d(64,192,kernel_size=3,padding=1), nn.MaxPool2d(kernel_size=3,stride=2,padding=1) ) b3 = nn.Sequential( Inception(192,64,(96,128),(16,32),32), Inception(256,128,(128,192),(32,96),64), nn.MaxPool2d(kernel_size=3,stride=2,padding=1) ) b4 = nn.Sequential( Inception(192,64,(96,128),(16,32),32), Inception(512,160,(112,224),(24,64),64), Inception(512,128,(128,256),(24,64),64), Inception(512,112,(144,288),(32,64),64), Inception(528,256,(160,320),(32,128),128), nn.MaxPool2d(kernel_size=3,stride=2,padding=1) ) b5 = nn.Sequential( Inception(832,256,(160,320),(32,128),128), Inception(832,384,(192,384),(48,128),128), GlobalAvgPool2d() ) net = nn.Sequential(b1,b2,b3,b4,b5, FlattenLayer(), nn.Linear(1024,10) ) print(“net:\n”,net) X = torch.rand(1,1,96,96) for blk in net.children(): X = blk(X) print(“out shape”,X.shape) lr,num_epochs = 0.001,5 optimizer = torch.optim.Adam(net.parameters(),lr= lr) train_fit(net,train_iter,test_iter,batch_size,optimizer,device=device,num_epochs = num_epochs) 上訓練圖:

    PyTorch ------GoogLeNet卷積神經網絡實作mnist手寫體識别

繼續閱讀