天天看點

TensorFlow2學習九、實作基礎CNN

一、簡介

本文實作基礎Convolutional Neural Network (CNN),資料集使用 CIFAR images。

卷積神經網絡是一種多層神經網絡,擅長處理圖像特别是大圖像的相關機器學習問題,它通過一系列方法,将資料量龐大的圖像識别問題不斷降維,最終使其能夠被訓練。CNN最早由Yann LeCun提出并應用在手寫字型識别上(MINST)。LeCun提出的網絡稱為LeNet,其網絡結構如下:

TensorFlow2學習九、實作基礎CNN

典型的卷積網絡,由卷積層、池化層、全連接配接層組成。其中卷積層與池化層配合,組成多個卷積組,逐層提取特征,最終通過若幹個全連接配接層完成分類。

1. 卷積

TensorFlow2學習九、實作基礎CNN

如圖所示,我們有一個5x5的圖像,我們用一個3x3的卷積核:

1  0  1

0  1  0

1  0  1      

來對圖像進行卷積操作(可以了解為有一個滑動視窗,把卷積核與對應的圖像像素做乘積然後求和),得到了3x3的卷積結果。

這個過程我們可以了解為我們使用一個過濾器(卷積核)來過濾圖像的各個小區域,進而得到這些小區域的特征值。

在實際訓練過程中,卷積核的值是在學習過程中學到的。

2. 池化

池化簡單的說就是下采樣。池化的過程如下圖所示:

TensorFlow2學習九、實作基礎CNN

上圖中,我們可以看到,原始圖檔是20x20的,我們對其進行下采樣,采樣視窗為10x10,最終将其下采樣成為一個2x2大小的特征圖。

之是以這麼做的原因,是因為即使做完了卷積,圖像仍然很大(因為卷積核比較小),是以為了降低資料次元,就進行下采樣。

之是以能這麼做,是因為即使減少了許多資料,特征的統計屬性仍能夠描述圖像,而且由于降低了資料次元,有效地避免了過拟合。

在實際應用中,池化根據下采樣的方法,分為最大值下采樣(Max-Pooling)與平均值下采樣(Mean-Pooling)。

3. 全連接配接層 (fully connected layers,FC)

在整個卷積神經網絡中起到“分類器”的作用。如果說卷積層、池化層和激活函數層等操作是将原始資料映射到隐層特征空間的話,全連接配接層則起到将學到的“分布式特征表示”映射到樣本标記空間的作用。在實際使用中,全連接配接層可由卷積操作實作:對前層是全連接配接的全連接配接層可以轉化為卷積核為1x1的卷積;而前層是卷積層的全連接配接層可以轉化為卷積核為hxw的全局卷積,h和w分别為前層卷積結果的高和寬。

4. CIFAR10介紹

該資料集共有60000張彩色圖像,這些圖像是32*32,分為10個類,每類6000張圖。這裡面有50000張用于訓練,構成了5個訓練批,每一批10000張圖;另外10000用于測試,單獨構成一批。測試批的資料裡,取自10類中的每一類,每一類随機取1000張。抽剩下的就随機排列組成了訓練批。注意一個訓練批中的各類圖像并不一定數量相同,總的來看訓練批,每一類都有5000張圖。

二、TensorFlow2.0實作的基礎cnn

1. 導入tensorflow

import tensorflow as tf

from tensorflow.keras import datasets, layers, models
import matplotlib.pyplot as plt      

2. 下載下傳CIFAR10資料集

(train_images, train_labels), (test_images, test_labels) = datasets.cifar10.load_data()

# Normalize pixel values to be between 0 and 1
train_images, test_images = train_images / 255.0, test_images / 255.0      

3. 檢視資料

這裡顯示25張圖檔和其分類,看看分類是否正确:

class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer','dog', 'frog', 'horse', 'ship', 'truck']

plt.figure(figsize=(10,10))
for i in range(25):
    plt.subplot(5,5,i+1)
    plt.xticks([])
    plt.yticks([])
    plt.grid(False)
    plt.imshow(train_images[i], cmap=plt.cm.binary)
    # The CIFAR labels happen to be arrays, 
    # which is why you need the extra index
    plt.xlabel(class_names[train_labels[i][0]])
plt.show()      

4. 建立模型和池化層

model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
# 顯示模型資訊
model.summary()      
TensorFlow2學習九、實作基礎CNN

上面可以看到每個池化層輸出是3維張量(高, 寬,通道數). 每個池化層輸出的通道數取悶在于第一個變量值(如32,64). 如果算力足夠,可以為每個池化層添加更多的通道數.

5. 全連接配接層

model.add(layers.Flatten()) # 3維 轉為 1維
model.add(layers.Dense(64, activation='relu'))  # 激活函數relu
model.add(layers.Dense(10, activation='softmax'))  # 激活函數softmax CIFAR有10個類别輸出,是以softmax這裡參數設定為10
# 再看看模型情況
model.summary()      
TensorFlow2學習九、實作基礎CNN

6. 編譯和訓練模型

model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

history = model.fit(train_images, train_labels, epochs=10, 
                    validation_data=(test_images, test_labels))      

7. 評估模型

plt.plot(history.history['accuracy'], label='accuracy')
plt.plot(history.history['val_accuracy'], label = 'val_accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.ylim([0.5, 1])
plt.legend(loc='lower right')

test_loss, test_acc = model.evaluate(test_images,  test_labels, verbose=2)      
TensorFlow2學習九、實作基礎CNN
print(test_acc)      

繼續閱讀