卷積神經網絡(AlexNet)調參技巧總結

這篇博客講講對AlexNet如何調參,最近因爲科研的原因,對卷積神經網絡進行了調參,忙活了大概一兩個星期,期間對AlexNet進行了全方面、多層次、寬領域的調參,總結了一些調參技巧,在這兒總結一下。
調參的技巧,我打算從兩個方面來講,一個是模型,一個是訓練參數。

環境參數

  1. Pytorch 0.4.1
  2. torchvision 0.1.8
  3. Python 3.6.3
  4. CUDA 8.0.61
  5. Linux + Pycharm

模型參數

首先我擺出原始的模型代碼,是AlexNet的代碼,這個在網上很常見。

{% asset_img 1.png AlexNet模型結構圖 %}

模型代碼:

class AlextNet(nn.Module):
    def __init__(self, in_channel, n_class):
        super(AlextNet, self).__init__()
        # 第一階段
        self.conv1 = nn.Sequential(
            nn.Conv2d(in_channel, 96, kernel_size=11, stride=4),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2)
        )
        # 第二階段
        self.conv2 = nn.Sequential(
            nn.Conv2d(96, 256, kernel_size=5, padding=2),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2)
        )
        # 第三階段
        self.conv3 = nn.Sequential(
            nn.Conv2d(256, 384, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(384, 384, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(384, 256, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2)
        )
        # 第四階段 全連接層
        self.fc = nn.Sequential(
            nn.Linear(1*1*256, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(0.5),
            nn.Linear(4096, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(0.5),
            nn.Linear(4096, n_class) # AlexNet上面是1000 ...如果測試的話用MNIST則可以使用10
        )
    # 向前傳播
    def forward(self, x):
        con1_x = self.conv1(x)
        con2_x = self.conv2(con1_x)
        con3_x = self.conv3(con2_x)
        lin_x = con3_x.view(con3_x.size(0), -1)
        y_hat = self.fc(lin_x)
        return y_hat

這個就是卷積神經網絡的核心代碼,這段代碼如何看,在我之前的博客《DCGAN模型講解及避坑指南》 中已經講的很詳細了。這裏不再贅述。

這個模型是由兩大部分組成,卷積層和全連接層。可以看到參數也非常多,因此可以調節的部分也非常多。

模型調參技巧-卷積層

首先在《卷積神經網絡的卷積核大小、個數,卷積層數如何確定呢?》 講述了相當全面的卷積核以及卷積層的參數確定。

  • 卷積核

卷積核是卷積神經網絡的核心,卷積核的大小設置,我都是設置爲3×3,一個方面是因爲我的圖片比較小,還有一個原因是這個卷積核是最小的並且能夠體現出上下左右中方位信息的卷積核。

  • 池化層

池化層的窗口大小是2×2,可以搭配stride =2 的步幅,這是爲了層加深就需要使下采樣速度更慢。

  • 層數

開始的代碼是三層卷積層,但是效果一直都一般,後來沒辦法,我添加了一個卷積層。卷積層達到了四層,而卷積核有五個。一般來說,卷積核的個數最好是奇數個。

模型調參技巧-全連接層

卷積層是用來把圖片的特徵提取出來,而全連接層是根據提取出來的特徵將圖片進行分類。在這篇《Dropout 層應該加在什麼地方?》 中講述了dropout層應該放置的位置。一般都要放置在全連接層中,我也嘗試了放置在卷積層中,但是效果一般。(原因是:卷積層參數比較少,不容易過擬合)。這篇博客還記錄了外文論文和博客關於這一觀點的例子。

其次是全連接層的dropout層的參數設置。我的個人經驗是,不要設置地太大,我一般設置在0.1~0.3之間。

我經常看網上有人推薦使用softmax進行分類,但是實際上在我的代碼裏面crossEntropyloss()函數裏面就包含了softmax,在這篇博客《PyTorch學習》裏面講過。

訓練參數調參技巧

這個訓練參數其實說的不太好,準確來說應該是,圖片的參數和模型訓練過程中遇到的參數的調整。

訓練參數調參技巧-圖片讀取

這個圖片讀取的方法,在我之前的博客《基於Pytorch對WGAN_gp模型進行調參總結》裏面也講過,主要用的函數代碼是:

data_transforms = {
    'train': transforms.Compose([
        transforms.Grayscale(1),
        transforms.Resize(256),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
    ]),
    'test': transforms.Compose([
        transforms.Grayscale(1),
        transforms.Resize(256),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
    ])
}
train_dataset = datasets.ImageFolder(os.path.join(CNN_data_dir, 'exp1_train'),data_transforms['train'])
train_loader = torch.utils.data.DataLoader(train_dataset batch_size = BATCH_SIZE ,shuffle = True ,num_workers = 8)

這段代碼的意思就是按照data_trandform的形式進行讀取,讀取之後按照指定的batch_sizeshuffle方式進行載入數據。開始的時候我對這部分代碼不以爲意,想着就是簡單的數據載入,沒什麼可以改的地方。因爲我看網上給出的分類代碼,這部分的參數都差不多,所以我想改點參數應該沒什麼影響,後來發現我錯了!!!

特別有效的參數是:transforms.CenterCrop()這個函數是將更改大小之後的圖片進行剪裁,是對圖片的中心部分進行剪裁。剛開始我在這設置的參數是96,訓練的準確率一直在85%左右徘徊,但是將參數改爲224之後,訓練準確率達到驚人的92%,本人感覺十分滿意。

訓練參數調參技巧-優化器(Optimizer

這個優化器也是調參非常關鍵的部分,因爲優化器控制了梯度變化的方式,如果優化器搭配地好,將顯著提升訓練集的準確率。

優化器可以調節的參數主要包括:優化器的種類, 學習率, weight_decay等。在這篇博客《當前訓練神經網絡最快的方式:AdamW優化算法+超級收斂》中 講了不同的優化器的設置,尤其是L2正則化的參數設置,L2正則化就是weight_decay參數,這個參數可以防止過擬合。

除此之外還有學習率需要調節,學習率在程序迭代過程中,隨着loss值的下降,還需要繼續削減,因此可以設置一個判斷語句,只要等到迭代條件達到某一程度時就可以就可以繼續減小其值。

當然由於GAN添加了一些生成的數據到訓練集中,因此會導致過擬合(測試集中的數據都是原始數據,模型學習到的是原始數據和生成數據的模樣,這樣也可以很定性地理解這個問題)也就不奇怪了,我在這篇《讀書筆記:對抗過擬合》博客中找到一些對抗過擬合的方法。比如早停止,dropout,數據增強等方法。

展望

我在這篇博客《Pytorch實戰2:ResNet-18實現Cifar-10圖像分類(測試集分類準確率95.170%)》裏面看到,使用ResNet-18實現圖像分類的功能,效果也非常好。如果後期,有需要通過不同的網絡進行對比試驗,這是一個好的參照點。

參考文獻

《Dropout 層應該加在什麼地方?》

《當前訓練神經網絡最快的方式:AdamW優化算法+超級收斂》

《讀書筆記:對抗過擬合》

《卷積神經網絡的卷積核大小、個數,卷積層數如何確定呢?》

《PyTorch學習》

《Pytorch實戰2:ResNet-18實現Cifar-10圖像分類(測試集分類準確率95.170%)》

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