用Pytorch創建CNN字符識別模型


開始構建一個字符識別模型–定長字符分類模型。利用卷積神經網絡(Convolutional Neural Network ,CNN)從頭搭建一個字符識別模型,並講解卷積神經網絡的常見層。
學習目標:1. 學習CNN基礎和原理 2. 使用Pytorch框架構建CNN模型並完成訓練

1 CNN介紹

卷積神經網絡CNN 是深度學習最重要的一個分支。在傳統的圖像處理中的卷積就是過濾器。CNN在很多領域都表現優異,精度和速度比傳統計算學習算法高很多。特別是在計算機視覺領域,CNN是解決圖像分類、圖像檢索、物體檢測和語義分割的主流模型。
CNN是一種層次模型,輸入的是原始的像素數據。CNN通過卷積(convolution)、池化(pooling)、非線性激活函數(non-linear activation function)和全連接層(fully connected layer)構成。
卷積神經網絡在本質上是一種輸入到輸出的映射,它能夠學習大量的輸入與輸出之間的映射關係,而不需要任何輸入與輸出之間的精確的數學表達式,只要用已知的模式對卷積神經網絡加以訓練,網絡就具有輸入與輸出之間的映射能力。卷積網絡是有監督學習,所以它的樣本集都形如:(輸入向量,理想輸出向量)之類的向量對構成。
在訓練之前,所有權值都用一些不同的小隨機數進行初始化,小的隨機數可以保證網絡不會因權值太大而進入飽和狀態,從而導致訓練失敗。不同則保證網絡可以正常學習。
如果要是用相同的數去初始化矩陣,網絡會沒有學習的能力。

1.1 LeNet網絡結構(1998)

卷積神經網絡三個基本概念:局部感受野(Local Receptive Fields)、共享權值(Shared Weights)、池化(Pooling)。

  1. 局部感受野:局部感受野。對於一般的深度神經網絡,往往會把圖像的每一個像素點連接到全連接的每一個神經元中,而卷積神經網絡則是把每一個隱藏節點只連接到圖像的某個局部區域,從而減少參數訓練的數量。例如,一張1024×720的圖像,使用9×9的感受野,則只需要81個權值參數。對於一般的視覺也是如此,當觀看一張圖像時,更多的時候關注的是局部。
  2. 共享權值。在卷積神經網絡的卷積層中,神經元對應的權值是相同的,由於權值相同,因此可以減少訓練的參數量。共享的權值和偏置也被稱作卷積核或濾汲器。
  3. 池化。由於待處理的圖像往往都比較大,而在實際過程中,沒有必要對原圖進行分析,能夠有效獲得圖像的特徵纔是最主要的,因此可以採用類似於圖像壓縮的思想,對圖像進行卷積之後,通過一個下采樣過程,來調整圖像的大小。
    LeNet網絡結構,是非常經典的字符識別模型。兩個卷積層,兩個池化層,兩個全連接層組成。卷積核都是5×5,stride=1,池化層使用最大池化。

C1,C3,C5爲卷積層,S2,S4爲降採樣層,F6爲全連接層,還有一個輸出層。
下采樣的作用: 利用圖像的局部相關性原理,對圖像進行子抽樣,可以減少數據處理量,同時又保留有用的信息。
方式就是池化層:池化層一般有兩種方式:
(1) Max_Pooling: 選擇Pooling窗口中最大值最爲採樣值。
(2) Mean_Pooling: 將Pooling窗口中的所有值相加取平均,然後以平均值最爲採樣值。

上圖說明了卷積過程子+採樣過程。卷積過程中,用一個可訓練的過濾器fx去卷積一個輸入圖像,然後添加一個偏置bx ,得到卷積層Cx 。子採樣過程就是:每個鄰域4個像素變爲一個像素,然後加上標量Wx 加權,最後再增加偏置bx+1 ,接着通過一個sigmoid激活函數,產生一個大概縮小了4倍的特徵映射圖Sx+1。

主要參考來源:https://blog.csdn.net/weixin_42398658/article/details/84392845?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.nonecase

1.2 AlexNet(2012)

看文章待補充

1.3 VGG-16(2014)

看文章待補充

1.4 Inception-v1(2014) InceptionResNetV2 InceptionV3

看文章待補充

1.5 ResNet-50(2015) ResNeXt50

看文章待補充

2 Pytorch構建CNN模型

在Pytorch中構建CNN模型非常簡單,只需要定義好模型的參數和正向傳播即可,Pytorch會根據正向傳播自動計算反向傳播。 構建一個非常簡單的CNN,然後進行訓練。這個CNN模型包括兩個卷積層,最後並聯6個全連接層進行分類。

2.1 定義模型

import torch
torch.manual_seed(0)
torch.backends.cudnn.deterministic = False
torch.backends.cudnn.benchmark = True

import torchvision.models as models
import torchvision.transforms as transforms
import torchvision.datasets as datasets
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.autograd import Variable
from torch.utils.data.dataset import Dataset

# 定義模型
class SVHN_Model1(nn.Module):
    def __init__(self):
        super(SVHN_Model1, self).__init__()
        # CNN提取特徵模塊
        self.cnn = nn.Sequential(
            nn.Conv2d(3, 16, kernel_size=(3, 3), stride=(2, 2)),
            nn.ReLU(),  
            nn.MaxPool2d(2),
            nn.Conv2d(16, 32, kernel_size=(3, 3), stride=(2, 2)),
            nn.ReLU(), 
            nn.MaxPool2d(2),
        )
        # 
        self.fc1 = nn.Linear(32*3*7, 11)
        self.fc2 = nn.Linear(32*3*7, 11)
        self.fc3 = nn.Linear(32*3*7, 11)
        self.fc4 = nn.Linear(32*3*7, 11)
        self.fc5 = nn.Linear(32*3*7, 11)
        self.fc6 = nn.Linear(32*3*7, 11)
    
    def forward(self, img):        
        feat = self.cnn(img)
        feat = feat.view(feat.shape[0], -1)
        c1 = self.fc1(feat)
        c2 = self.fc2(feat)
        c3 = self.fc3(feat)
        c4 = self.fc4(feat)
        c5 = self.fc5(feat)
        c6 = self.fc6(feat)
        return c1, c2, c3, c4, c5, c6
    
model = SVHN_Model1()

在爲了追求精度,也可以使用在ImageNet數據集上的預訓練模型:

class SVHN_Model2(nn.Module):
    def __init__(self):
        super(SVHN_Model1, self).__init__()
                
        model_conv = models.resnet18(pretrained=True)
        model_conv.avgpool = nn.AdaptiveAvgPool2d(1)
        model_conv = nn.Sequential(*list(model_conv.children())[:-1])
        self.cnn = model_conv
        
        self.fc1 = nn.Linear(512, 11)
        self.fc2 = nn.Linear(512, 11)
        self.fc3 = nn.Linear(512, 11)
        self.fc4 = nn.Linear(512, 11)
        self.fc5 = nn.Linear(512, 11)
    
    def forward(self, img):        
        feat = self.cnn(img)
        # print(feat.shape)
        feat = feat.view(feat.shape[0], -1)
        c1 = self.fc1(feat)
        c2 = self.fc2(feat)
        c3 = self.fc3(feat)
        c4 = self.fc4(feat)
        c5 = self.fc5(feat)
        return c1, c2, c3, c4, c5

2.2 訓練代碼

# 損失函數
criterion = nn.CrossEntropyLoss()
# 優化器
optimizer = torch.optim.Adam(model.parameters(), 0.005)

loss_plot, c0_plot = [], []
# 迭代10個Epoch
for epoch in range(10):
    for data in train_loader:
        c0, c1, c2, c3, c4, c5 = model(data[0])
        loss = criterion(c0, data[1][:, 0]) + \
                criterion(c1, data[1][:, 1]) + \
                criterion(c2, data[1][:, 2]) + \
                criterion(c3, data[1][:, 3]) + \
                criterion(c4, data[1][:, 4]) + \
                criterion(c5, data[1][:, 5])
        loss /= 6
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        loss_plot.append(loss.item())
        c0_plot.append((c0.argmax(1) == data[1][:, 0]).sum().item()*1.0 / c0.shape[0])
        
    print(epoch)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章