上一篇:《搞清楚這個老六的真面目!逐層‘剝開’人工智慧中的卷積神經網路(CNN)》
序言:現在讓我們開始走進卷積神經網路(CNN)的世界裡。和傳統程式設計完全不同,在人工智慧的程式程式碼裡,您看不到明確的演算法規則,看到的只是神經網路的配置說明。這裡的程式碼不會像傳統程式設計那樣去具體實現每個功能。比如說,如果您想讓電腦分辨貓和狗,您不需要寫程式碼去解釋貓和狗長得什麼樣,而是透過描述神經網路的配置,讓它在訓練過程中透過資料自己學會。描述就像藝術,如何恰到好處地增添一筆,才能帶來非凡的效果?這正是設計人工智慧的精髓!!
(點一點關注,避免未來更新無法及時通知您)
在前面的知識中,我們建立了一個能夠識別時裝影像的神經網路。為了方便,這裡是完整的程式碼:
import tensorflow as tf
data = tf.keras.datasets.fashion_mnist
(training_images, training_labels), (test_images, test_labels) = data.load_data()
training_images = training_images / 255.0
test_images = test_images / 255.0
model = tf.keras.models.Sequential([
tf.keras.layers.Flatten(input_shape=(28, 28)),
tf.keras.layers.Dense(128, activation=tf.nn.relu),
tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
model.fit(training_images, training_labels, epochs=5)
要將其轉換為卷積神經網路,我們只需在模型定義中使用卷積層。同時,我們還會新增池化層。
要實現一個卷積層,您將使用 tf.keras.layers.Conv2D 型別。它接受一些引數,比如層中要使用的卷積數量、卷積的大小、啟用函式等。
例如,下面是一個作為神經網路輸入層的卷積層:
tf.keras.layers.Conv2D(64, (3, 3), activation='relu',
input_shape=(28, 28, 1)),
在這裡,我們希望這一層學習到 64 個卷積。它會隨機初始化這些卷積,並隨著時間推移,學習出最適合將輸入值與其標籤匹配的濾波器值。(3, 3) 表示濾波器的大小。之前我展示過 3 × 3 的例子。
在這裡,我們指定濾波器大小為 3 × 3,這也是最常見的濾波器大小;您可以根據需要更改,但通常會看到像 5 × 5 或 7 × 7 這樣的奇數軸,因為濾波器會從影像邊緣去除畫素,稍後您會看到具體效果。
activation 和 input_shape 引數與之前相同。因為我們在這個示例中使用的是 Fashion MNIST,所以形狀仍然是 28 × 28。不過要注意,因為 Conv2D 層是為多色影像設計的,所以我們將第三維指定為 1,因此輸入形狀是 28 × 28 × 1。彩色影像的第三引數通常是 3,因為它們以 R、G、B 三個通道的值儲存。
接下來是在神經網路中使用池化層的方法。通常您會在卷積層之後立即使用它:
tf.keras.layers.MaxPooling2D(2, 2),
在圖 3-4 的示例中,我們將影像分成 2 × 2 的小塊,並在每個小塊中選取最大值。這個操作可以引數化,以定義池的大小。這裡的 (2, 2) 表示我們的池大小為 2 × 2。
現在,讓我們來看看使用 CNN 處理 Fashion MNIST 的完整程式碼:
import tensorflow as tf
data = tf.keras.datasets.fashion_mnist
(training_images, training_labels), (test_images, test_labels) = data.load_data()
training_images = training_images.reshape(60000, 28, 28, 1)
training_images = training_images / 255.0
test_images = test_images.reshape(10000, 28, 28, 1)
test_images = test_images / 255.0
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(64, (3, 3), activation='relu',
input_shape=(28, 28, 1)),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(128, activation=tf.nn.relu),
tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
model.fit(training_images, training_labels, epochs=50)
model.evaluate(test_images, test_labels)
classifications = model.predict(test_images)
print(classifications[0])
print(test_labels[0])
這裡有一些需要注意的地方。還記得之前我說過輸入影像的形狀必須與 Conv2D 層的預期相匹配嗎?我們將其更新為 28 × 28 × 1 的影像嗎?資料也需要相應地重塑。28 × 28 表示影像的畫素數量,而 1 表示顏色通道的數量。對於灰度影像,通常為 1;對於彩色影像,則為 3,因為它有三個通道(紅色、綠色和藍色),數字表示該顏色的強度。
因此,在對影像進行歸一化之前,我們還需要將每個陣列重塑為帶有額外維度的形狀。以下程式碼將我們的訓練資料集從 60,000 張每張 28 × 28 的影像(因此是一個 60,000 × 28 × 28 的陣列)更改為 60,000 張每張 28 × 28 × 1 的影像:
training_images = training_images.reshape(60000, 28, 28, 1)
然後我們對測試資料集執行相同的操作。
還要注意,在最初的深度神經網路(DNN)中,我們在將輸入傳遞到第一個 Dense 層之前使用了一個 Flatten 層。而這裡的輸入層中,我們省略了這一層,只需指定輸入形狀。注意,在經過卷積和池化後,在進入 Dense 層之前,資料將被展平。
將該網路在相同的資料上訓練 50 個週期,與第 2 章中展示的網路相比,我們可以看到準確率有顯著提升。之前的例子在 50 個週期後在測試集上達到了 89% 的準確率,而這個網路在大約一半的週期(24 或 25 個)就能達到 99%。所以我們可以看到,新增摺積層確實提高了神經網路的影像分類能力。接下來讓我們看看影像在網路中的傳遞過程,以更深入理解其工作原理。
探索卷積網路
您可以使用 model.summary 命令檢查您的模型。當您在我們一直在處理的 Fashion MNIST 卷積網路上執行它時,您會看到類似這樣的結果:
Model: "sequential"
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 26, 26, 64) 640
max_pooling2d (MaxPooling2D) (None, 13, 13, 64) 0
conv2d_1 (Conv2D) (None, 11, 11, 64) 36928
max_pooling2d_1 (MaxPooling2 (None, 5, 5, 64) 0
flatten (Flatten) (None, 1600) 0
dense (Dense) (None, 128) 204928
dense_1 (Dense) (None, 10) 1290
=================================================================
Total params: 243,786
Trainable params: 243,786
Non-trainable params: 0
我們先來看一下“輸出形狀”列,以瞭解這裡發生了什麼。我們的第一層會處理 28 × 28 的影像,並應用 64 個濾波器。但是,由於濾波器是 3 × 3 的,影像周圍會丟失 1 畫素的邊框,從而將整體資訊減少到 26 × 26 畫素。參考圖 3-6,如果我們將每個方框看作影像中的一個畫素,第一個可能的濾波操作會從第二行、第二列開始。右側和底部也會出現相同的情況。
圖 3-6:執行濾波器時丟失畫素
因此,一個 A × B 畫素大小的影像在經過 3 × 3 濾波器後會變成 (A–2) × (B–2) 畫素。同樣地,5 × 5 的濾波器會將其變成 (A–4) × (B–4),依此類推。由於我們使用的是 28 × 28 的影像和 3 × 3 的濾波器,所以我們的輸出現在是 26 × 26。
接下來,池化層是 2 × 2 的,因此影像在每個軸上會縮小一半,變成 (13 × 13)。下一個卷積層會進一步縮小到 11 × 11,而下一個池化層再進行四捨五入後,會將影像縮小到 5 × 5。
這樣一來,當影像經過兩層卷積後,結果將會是多個 5 × 5 的小影像。那麼會有多少個呢?我們可以在引數數列(Param #)中看到。
每個卷積是一個 3 × 3 的濾波器,加上一個偏置。還記得之前在密集層中,公式是 Y = mX + c 嗎?其中 m 是我們的引數(即權重),c 是偏置。這裡的原理類似,只不過濾波器是 3 × 3 的,因此需要學習 9 個引數。因為我們定義了 64 個卷積,總共有 640 個引數(每個卷積有 9 個引數加一個偏置,總共 10 個,然後有 64 個卷積)。
MaxPooling 層並不會學習任何內容,它只是縮小影像的尺寸,因此沒有學習引數,所以顯示為 0。
接下來的卷積層有 64 個濾波器,但每一個濾波器都會跨前一個 64 個濾波器進行相乘,每個濾波器有 9 個引數。我們為新的 64 個濾波器中的每一個都增加一個偏置,因此引數總數應為 (64 × (64 × 9)) + 64,得出 36,928 個需要網路學習的引數。
如果這裡有些複雜,您可以嘗試將第一層的卷積數量改為一個不同的值,比如 10。您會發現第二層的引數數量變為 5,824,即 (64 × (10 × 9)) + 64。
當我們完成第二次卷積時,影像變為 5 × 5,且我們有 64 個這樣的影像。將這些相乘後,我們得到 1,600 個值,這些值會傳入一個包含 128 個神經元的密集層。每個神經元有一個權重和一個偏置,總共 128 個神經元,因此網路要學習的引數數量是 ((5 × 5 × 64) × 128) + 128,得出 204,928 個引數。
最後一層密集層有 10 個神經元,接受前一個 128 個神經元的輸出,因此學習的引數數量為 (128 × 10) + 10,即 1,290。
總引數數量就是這些的總和:243,786。
訓練這個網路需要我們學習這 243,786 個引數的最佳組合,以便將輸入影像與標籤匹配。由於引數更多,訓練過程會更慢,但從結果可以看到,它也構建了更準確的模型!
當然,在這個資料集中我們仍然受限於影像是 28 × 28、單色且居中的。接下來我們將使用卷積來探索更復雜的資料集,其中包含馬和人的彩色影像,我們會嘗試判斷影像中是馬還是人。在這種情況下,主體不一定會像 Fashion MNIST 那樣居中,所以我們必須依賴卷積來捕捉辨別特徵。
本篇我們自己動手描述了一個卷積神經網路,下一篇,我們就用這個CNN神經網路去分辨出人類與動物(馬)。