卷積神經網路-AlexNet

發表於2024-06-21

AlexNet

一些前置知識

top-1 和top-5錯誤率

top-1錯誤率指的是在最後的n哥預測結果中,只有預測機率最大對應的類別是正確答案才算預測正確。
top-5錯誤率指的是在最後的n個預測結果中,只要預測機率最大的前五個中含有正確答案就算預測正確。

max-pooling層

最大池化又叫做subsampling,其主要作用是減少影像的高度和長度而深度(寬度)則不會改變。下面是一個列子:

fully-connect層

在全連線層中,其每個神經元都與前一層的所有神經元相連線,每個連線都有一個權重用於調節資訊傳遞的強度,並且每個神經元還有一個偏置項。

1000-way softmax

它其實也屬於全連線層,這個層原本包含1000個未歸一化的輸出,而softmax將這個向量轉換為機率分佈。計算方式如下:

\[P(y_i) = \frac{e^{z_i}}{\sum_{j = 1}^{1000}e^{z_j}} \]

non-saturating neurons

非飽和神經元是深度學習中一種設計神經元的理念,目的是避免神經元在訓練過程中出現飽和現象。飽和現象會導致梯度消失,進而使得模型難以訓練。下面是一些常見的非飽和啟用函式:

  • ReLU
  • Leaky ReLU
  • ELU
  • SELU

dropout

在訓練時以一定的機率將輸入置0,輸出時接受所有神經元的輸出,但要乘以機率(1-p)。使得模型在每次前向和反向傳播時都使用不同的子網路進行訓練,從而提高模型的泛化能力。這種方法有效地減少了神經元之間的共適應性(co-adaptation),迫使網路的每個神經元在更具魯棒性的特徵上進行學習。

缺點:收斂速度可能變慢。

網路結構


由於這篇文章在提出時沒有很好的GPU,估計視訊記憶體不夠?所有采用了雙GPU訓練的方法。具體來說上下兩塊GPU分別負責一般的引數,但是這其中也有資訊的融合,比如第3、6,7層。其次這裡輸出的影像維度應該有誤,應更正為2252253

演算法實現

import torch.nn as nn
import torch

class AlexNet(nn.Module):
    def __init__(self, num_classes=1000, init_weights=False):
        super(AlexNet, self).__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 48, kernel_size=11, stride=4, padding=2),  # input[3, 224, 224]  output[48, 55, 55]
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),                  # output[48, 27, 27]
            nn.Conv2d(48, 128, kernel_size=5, padding=2),           # output[128, 27, 27]
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),                  # output[128, 13, 13]
            nn.Conv2d(128, 192, kernel_size=3, padding=1),          # output[192, 13, 13]
            nn.ReLU(inplace=True),
            nn.Conv2d(192, 192, kernel_size=3, padding=1),          # output[192, 13, 13]
            nn.ReLU(inplace=True),
            nn.Conv2d(192, 128, kernel_size=3, padding=1),          # output[128, 13, 13]
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),                  # output[128, 6, 6]
        )
        self.classifier = nn.Sequential(
            nn.Dropout(p=0.5),
            nn.Linear(128 * 6 * 6, 2048),
            nn.ReLU(inplace=True),
            nn.Dropout(p=0.5),
            nn.Linear(2048, 2048),
            nn.ReLU(inplace=True),
            nn.Linear(2048, num_classes),
        )
        if init_weights:
            self._initialize_weights()

    def forward(self, x):
        x = self.features(x)
        x = torch.flatten(x, start_dim=1)
        x = self.classifier(x)
        return x

    def _initialize_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
                if m.bias is not None:
                    nn.init.constant_(m.bias, 0)
            elif isinstance(m, nn.Linear):
                nn.init.normal_(m.weight, 0, 0.01)
                nn.init.constant_(m.bias, 0)

相關文章