使用PyTorch簡單實現卷積神經網絡模型

  這裏咱們會用 Python 實現三個簡單的卷積神經網絡模型:LeNet 、AlexNet 、VGGNet,首先咱們須要瞭解三大基礎數據集:MNIST 數據集、Cifar 數據集和 ImageNet 數據集html

三大基礎數據集

MNIST 數據集網絡

  MNIST數據集是用做手寫體識別的數據集。MNIST 數據集包含 60000 張訓練圖片,10000 張測試圖片。其中每一張圖片都是 0~9 中的一個數字。圖片尺寸爲 28×28。因爲數據集中數據相對比較簡單,人工標註錯誤率僅爲 0.2%。架構

Cifar 數據集app

  Cifar 數據集是一個圖像分類數據集。分爲 Cifar-10 和 Cifar-100 兩個數據集。Cifar 數據集中的圖片爲 32×32 的彩色圖片,這些圖片是由 Alex Krizhenevsky 教授、Vinod Nair 博士和 Geoffrey Hilton 教授整理的。Cifar-10 數據集收集了來自 10 個不一樣種類的 60000 張圖片,這些種類有:飛機、汽車、鳥、貓、鹿、狗、青蛙、馬、船和卡車。在 Cifar-10 數據集上,人工標註的正確率爲94%。ide

ImageNet數據集函數

  ImageNet 數據集是一個大型圖像數據集,由斯坦福大學的李飛飛教授帶頭整理而成。在 ImageNet 中,近 1500 萬張圖片關聯到 WordNet 中 20000 個名次同義詞集上。ImageNet 每一年舉行計算機視覺相關的競賽, ImageNet 的數據集涵蓋計算機視覺的各個研究方向,其用作圖像分類的數據集是 ILSVRC2012 圖像分類數據集。學習

  ILSVRC2012 數據集的數據和 Cifar-10 數據集一致,識別圖像中主要物體,其包含了來自 1000 個種類的 120 萬張圖片,每張圖片只屬於一個種類,大小從幾千字節到幾百萬字節不等。卷積神經網絡也正是在此數據集上一戰成名。測試

 

三種經典的卷積神經網絡模型

  三種經典的卷積神經網絡模型:LeNetAlexNetVGGNet。這三種卷積神經網絡的結構不算特別複雜,下面使用 PyTorch 進行實現url

LeNet模型
spa

  LeNet 具體指的是 LeNet-5。LeNet-5 模型是 Yann LeCun 教授於 1998 年在論文 Gradient-based learning applied to document recognition 中提出的,它是第一個成功應用於數字識別問題的卷積神經網絡。在 MNIST 數據集上,LeNet-5 模型能夠達到大約 99.2% 的正確率。LeNet-5 模型總共有7層,包括有2個卷積層,2個池化層,2個全鏈接層和一個輸出層,下圖展現了 LeNet-5 模型的架構。

 使用 PyTorch 實現

class LeNet(nn.Module):
    def __init__(self):
        super(LeNet, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1   = nn.Linear(16*5*5, 120)
        self.fc2   = nn.Linear(120, 84)
        self.fc3   = nn.Linear(84, 10)
    def forward(self, x):
        out = F.relu(self.conv1(x))
        out = F.max_pool2d(out, 2)
        out = F.relu(self.conv2(out))
        out = F.max_pool2d(out, 2)
        out = out.view(out.size(0), -1)
        out = F.relu(self.fc1(out))
        out = F.relu(self.fc2(out))
        out = self.fc3(out)
        return out
PyTorch 實現 LeNet 模型

 

AlexNet模型

  Alex Krizhevsky 提出了卷積神經網絡模型 AlexNet。AlexNet 在卷積神經網絡上成功地應用了 Relu,Dropout 和 LRN 等技巧。在 ImageNet 競賽上,AlexNet 以領先第二名 10% 的準確率而奪得冠軍。成功地展現了深度學習的威力。它的網絡結構以下:

  因爲當時GPU計算能力不強,AlexNet使用了兩個GPU並行計算,如今能夠用一個GPU替換。以單個GPU的AlexNet模型爲例,包括有:5個卷積層,3個池化層,3個全鏈接層。其中卷積層和全鏈接層包括有relu層,在全鏈接層中還有dropout層。具體參數的配置能夠看下圖

 使用 PyTorch 實現

class AlexNet(nn.Module):
    def __init__(self, num_classes):
        super(AlexNet, self).__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 96, kernel_size=11, stride=4, padding=2),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
            nn.Conv2d(64, 256, kernel_size=5, padding=2),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
            nn.Conv2d(192, 384, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(384, 256, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(256, 256, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
        )
        self.classifier = nn.Sequential(
            nn.Dropout(),
            nn.Linear(256 * 6 * 6, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(),
            nn.Linear(4096, 4096),
            nn.ReLU(inplace=True),
            nn.Linear(4096, num_classes),
        )
    def forward(self, x):
        x = self.features(x)
        x = x.view(x.size(0), 256 * 6 * 6)
        x = self.classifier(x)
        return x
PyTorch 實現 AlexNet 模型

 

VGGNet模型

  VGGNet是牛津大學計算機視覺組和Google DeepMind公司的研究人員一塊兒研發的一種卷積神經網絡。經過堆疊3×3 的小型卷積核和2×2的最大池化層,VGGNet成功地構築了最深達19層的卷積神經網絡。因爲VGGNet的拓展性強,遷移到其餘圖片數據上的泛化性比較好,可用做遷移學習。

下圖爲 VGG16 的總體架構圖

  從左至右,一張彩色圖片輸入到網絡,白色框是卷積層,紅色是池化,藍色是全鏈接層,棕色框是預測層。預測層的做用是將全鏈接層輸出的信息轉化爲相應的類別機率,而起到分類做用。

能夠看到 VGG16 是13個卷積層+3個全鏈接層疊加而成。

使用 PyTorch 實現

cfg = {
    'VGG11': [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
    'VGG13': [64, 64, 'M', 128, 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
    'VGG16': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M'],
    'VGG19': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512, 512, 'M', 512, 512, 512, 512, 'M'],
}
class VGG(nn.Module):
    def __init__(self, vgg_name):
        super(VGG, self).__init__()
        self.features = self._make_layers(cfg[vgg_name])
        self.classifier = nn.Linear(512, 10)
    def forward(self, x):
        out = self.features(x)
        out = out.view(out.size(0), -1)
        out = self.classifier(out)
        return out
    def _make_layers(self, cfg):
        layers = []
        in_channels = 3
        for x in cfg:
            if x == 'M':
                layers += [nn.MaxPool2d(kernel_size=2, stride=2)]
            else:
                layers += [nn.Conv2d(in_channels, x, kernel_size=3, padding=1),
                           nn.BatchNorm2d(x),
                           nn.ReLU(inplace=True)]
                in_channels = x
        layers += [nn.AvgPool2d(kernel_size=1, stride=1)]
        return nn.Sequential(*layers)
PyTorch 實現 VGGNet 模型

 

  VGG16 是基於大量真實圖像的 ImageNet 圖像庫預訓練的網絡

  VGG16 對應的供 keras 使用的模型人家已經幫咱們訓練好,咱們將學習好的 VGG16 的權重遷移(transfer)到本身的卷積神經網絡上做爲網絡的初始權重,這樣咱們本身的網絡不用從頭開始從大量的數據裏面訓練,從而提升訓練速度。這裏的遷移就是平時所說的遷移學習。

from keras.models import Sequential
from keras.layers.core import Flatten, Dense, Dropout
from keras.layers.convolutional import Convolution2D, MaxPooling2D, ZeroPadding2D
from keras.optimizers import SGD
import cv2, numpy as np


def VGG_16(weights_path=None):
    model = Sequential()
    model.add(ZeroPadding2D((1, 1), input_shape=(3, 244, 244))) # 卷積輸入層指定輸入圖像大小(網絡開始輸入(3,224,224)的圖像數據,即一張寬224,高244的彩色RGB圖片)
    model.add(Convolution2D(64, 3, 3, activation='relu')) # 64個3*3的卷積核,生成64*244*244的圖像
    model.add(ZeroPadding2D(1, 1)) # 補0,(1, 1)表示橫向和縱向都補0,保證卷積後圖像大小不變,能夠用padding='valid'參數代替
    model.add(Convolution2D(64, 3, 3, activation='relu')) # 再次卷積操做,生成64*244*244的圖像,激活函數是relu
    model.add(MaxPooling2D((2, 2), strides=(2, 2))) # pooling操做,至關於變成64*112*112,小矩陣是(2,2),步長(2,2),指的是橫向每次移動2格,縱向每次移動2格。

    # 再往下,同理,只不過是卷積核個數依次變成128,256,512,而每次按照這樣池化以後,矩陣都要縮小一半。
    model.add(ZeroPadding2D((1, 1)))
    model.add(Convolution2D(128, 3, 3, activation='relu'))
    model.add(ZeroPadding2D((1, 1)))
    model.add(Convolution2D(128, 3, 3, activation='relu'))
    model.add(MaxPooling2D((2, 2), strides=(2, 2))) # 128*56*56

    model.add(ZeroPadding2D((1, 1)))
    model.add(Convolution2D(256, 3, 3, activation='relu'))
    model.add(ZeroPadding2D((1, 1)))
    model.add(Convolution2D(256, 3, 3, activation='relu'))
    model.add(ZeroPadding2D((1, 1)))
    model.add(Convolution2D(256, 3, 3, activation='relu'))
    model.add(MaxPooling2D((2, 2), strides=(2, 2)))  # 256*28*28

    model.add(ZeroPadding2D((1, 1)))
    model.add(Convolution2D(512, 3, 3, activation='relu'))
    model.add(ZeroPadding2D((1, 1)))
    model.add(Convolution2D(512, 3, 3, activation='relu'))
    model.add(ZeroPadding2D((1, 1)))
    model.add(Convolution2D(512, 3, 3, activation='relu'))
    model.add(MaxPooling2D((2, 2), strides=(2, 2)))  # 512*14*14

    model.add(ZeroPadding2D((1, 1)))
    model.add(Convolution2D(512, 3, 3, activation='relu'))
    model.add(ZeroPadding2D((1, 1)))
    model.add(Convolution2D(512, 3, 3, activation='relu'))
    model.add(ZeroPadding2D((1, 1)))
    model.add(Convolution2D(512, 3, 3, activation='relu'))
    model.add(MaxPooling2D((2, 2), strides=(2, 2)))  # 128*7*7
    # 13層卷積和池化以後,數據變成了512 * 7 * 7

    model.add(Flatten) # 壓平上述向量,變成一維512*7*7=25088
    # 三個全鏈接層
    '''
    4096只是個經驗值,其餘數固然能夠,試試效果,只要不要小於要預測的類別數,這裏要預測的類別有1000種,
    因此最後預測的全鏈接有1000個神經元。若是你想用VGG16 給本身的數據做分類任務,這裏就須要改爲你預測的類別數。
    '''
    model.add(Dense(4096, activation='relu')) # 全鏈接層有4096個神經元,參數個數是4096*25088
    model.add(Dropout(0.5)) # 0.5的機率拋棄一些鏈接
    model.add(Dense(4096, activation='relu'))  # 全鏈接層有4096個神經元,參數個數是4096*25088
    model.add(Dropout(0.5))  # 0.5的機率拋棄一些鏈接
    model.add(Dense(1000, activation='softmax'))

    if weights_path:
        model.load_weights(weights_path)
    return model

# 若是要設計其餘類型的CNN網絡,就是將這些基本單元好比卷積層個數、全鏈接個數按本身須要搭配變換,
使用 Keras 實現 VGG16
# 模型須要事先下載
model = VGG_16('vgg16_weights.h5')

sgd = SGD(lr=0.1, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(optimizer=sgd, loss='categorical_crossentropy')

# 加載圖片
def load_image(img):
    im = cv2.resize(cv2.imread(img), (224, 224)).astype(np.float32)
    im[:,:,0] -= 103.939
    im[:,:,1] -= 116.779
    im[:,:,2] -= 123.68
    im = im.transpose((2, 0, 1))
    im = np.expand_dims(im, axis=0)
    return im

# 讀取vgg16類別的文件
f = open('synset_words.txt', 'r')
lines = f.readline()
f.close()

def predict(url):
    im = load_image(url)
    pre = np.argmax(model.predict(im))
    print(lines[pre])
    
# 測試圖片
predict('xx.jpg')
測試 VGG16 模型

 

           

 

 

參考:https://www.cnblogs.com/wmr95/articles/7814892.html          

相關文章
相關標籤/搜索