天池實戰-街景字符編碼識別-task3模型建立

寫在前面的話

前兩節我們進行了數據的預處理,介紹了賽題的相關背景:天池實戰-街景字符編碼識別-task1賽題理解,通過Pytorch 批量讀取圖像數據並進行圖像預處理:天池實戰-街景字符編碼識別-task2數據預處理

這節我們通過CNN模型完成字符識別功能,並且介紹如何在Pytorch 下進行模型的建立



關於CNN模型

想必在使用Pytorch 之前你應該對CNN有一個基本的瞭解,最少得了解CNN一般都包括哪些層,每層都是用來幹嘛的這些,至於說建模和調參這些你可以先不用知道,在Pytorch 的使用中你會看到。



Pytorch 模型創建

在Pytorch 中建立模型只需要定義好模型的參數和正向傳播即可,Pytorch會根據正向傳播自動計算反向傳播。

那麼我們的問題就可以優化成建立CNN模型的正向傳播,在Pytorch 中包括這兩步:

  1. 構建子模塊(比如LeNet裏面的卷積層,池化層,全連接層)
  2. 拼接子模塊(有了子模塊,我們把子模塊按照一定的順序,邏輯進行拼接起來得到最終的模型)

構建子模塊

這一步主要是建立自己的模型,繼承nn.Module,並在 __init__()方法中實現相關子模塊的構建

說到這不知道你有沒有想起上一節在讀取讀取的時候,同樣是繼承了Pytorch 的基類Dataset和DataLoader,不同的是這裏需要集成nn.Module這個基類。


拼接子模塊

基於上面創建的模型在模型的forward()方法中進行模塊的拼接,相當於我們需要定義前向傳播的每個層

不同的是在module中會自己計算反向傳播,我們只需要定義前向傳播即可。


nn.Module 類

在nn.Module中,有8個以有序字典形式存在的屬性,用於管理整個模型

  • _parameters: 存儲管理屬於nn.Parameter類的屬性,例如權值,偏置等參數
  • _modules: 存儲管理nn.Module類,比如模型中構建的子模塊、卷積層、池化層等會存儲在modules中
  • _buffers: 存儲管理緩衝屬性
  • *_hooks: 存儲管理鉤子函數(5個鉤子函數)

子模塊的構建機制如下:

  • 創建一個大的Module 繼承nn.Module 這個基類,並且在這個大的基類中有很多的子模塊,子模塊同樣繼承於nn.Module,在Module 的__init__方法中,會先通過調用父類的初始化方法進行8個屬性的初始化。
  • 然後在構建每個子模塊的時候,先初始化然後被__setattr__方法通過判斷value 的類型將其保存到相應的屬性字典中(例如module 類型、parameter類型),然後通過賦值的方式賦給相應的子模塊的成員。

通過上述兩步便完成了一個子模塊的構建,我們通過構建一個個這樣的子模塊,最終構成整個Module。


總結一下Module:

  • 一個module可以包含多個子module(卷積層、池化層、全連接層等)
  • 一個module相當於一個運算,必須實現forware()函數(前向傳播),module會自己計算反向傳播
  • 每個module都有8個字典管理它的屬性(最常用的是_parameters, _modules

上節在學習Dataset的時候瞭解到DataLoader,可以實現對圖像的批處理,那麼同樣的道理我們已經創建了一個個的子Module,也會存在一個模型容器Containers。



模型容器Containers

模型容器中包含3個子模塊,分別是nn.Sequential,nn.ModuleList和nn.ModuleDict

nn.Sequential

這是nn.module的容器,用於按順序包裝一組網絡層

在深度學習中,弱化了特徵工程部分,偏向於讓網絡自己提取特徵,然後進行分類或者回歸任務。

所以一般選擇以全連接層爲界限,將網絡模型劃分爲特徵提取模塊和分類模塊,在模型前面加上卷積層讓網絡自己學習提取特徵,在通過全連接層進行分類等任務。

那麼我們在創建模型的時候就可以這樣定義:

class LeNetSequential(nn.Module):
	def __init__(self, classes):
        super(LeNetSequential, self).__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 6, 5),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.Conv2d(6, 16, 5),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),)

		self.classifier = nn.Sequential(
            nn.Linear(16*5*5, 120),
            nn.ReLU(),
            nn.Linear(120, 84),
            nn.ReLU(),
            nn.Linear(84, classes),)

    def forward(self, x):
        x = self.features(x)
        x = x.view(x.size()[0], -1)
        x = self.classifier(x)
        return x

上面是創建了一個LeNet的模型,其中模型包括兩部分,分別是features進行特徵提取和classifier進行分類,然後通過Sequential包裝起來,相比而言forward函數只需要:features、形狀變換、classifier

我們可以發現其實Sequential是滿足以下規律的:

  • 順序性:各網絡層之間嚴格按照順序構建,這時候一定要注意前後層數據的關係
  • forward:自帶的forward裏,通過for循環依次執行前向傳播運算

nn.ModuleList

nn.ModuleList是nn.module的容器, 用於包裝一組網絡層, 以迭代方式調用網絡層。 主要方法:

  • append(): 在ModuleList後面添加網絡層
  • extend(): 拼接兩個ModuleList
  • insert(): 指定在ModuleList中位置插入網絡層

這個方法的作用其實類似於我們的列表,只不過元素換成網絡層而已


nn.ModuleDict

nn.ModuleDict是nn.module的容器, 用於包裝一組網絡層, 以索引方式調用網絡層。主要方法:

  • clear(): 清空ModuleDict
  • items(): 返回可迭代的鍵值對(key-value pairs)
  • keys(): 返回字典的鍵(key)
  • values(): 返回字典的值(value)
  • pop(): 返回一對鍵值對, 並從字典中刪除

總結一下Sequential
  • nn.Sequential:順序性,各網絡層之間嚴格按順序執行
  • nn.ModuleList:迭代性,常用於大量重複網構建,通過for循環即可實現
  • nn.ModuleDict:索引性,常用於可選擇的網絡層



實操代碼

在本次項目的特徵提取模塊,通過resnet18模型作特徵提取模塊,也就相當於我們不需要再構建子模塊,直接使用resnet18的子模塊即可

代碼如下:

class SVHN_Model1(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

總結

本節通過對Pytorch下模型構建流程的分析,介紹了Pytorch下Module、Containers的用法和相關構建流程。在本次項目中通過resnet18對特徵進行提取,通過5個全連接層實現分類的目的

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