Python人工智能 | 十七.Keras搭建分類神經網絡及MNIST數字圖像案例分析
從本專欄開始,作者正式研究Python深度學習、神經網絡及人工智能相關知識。前一篇文章詳細講解了Keras環境搭建、入門基礎及回歸神經網絡案例。本篇文章將通過Keras實現分類學習,以MNIST數字圖片為例進行講解。基礎性文章,希望對您有所幫助!

本專欄主要結合作者之前的博客、AI經驗、“莫煩”老師的視頻學習心得和相關文章及論文介紹,后面隨著深入會講解更多的Python人工智能案例及應用。基礎性文章,希望對您有所幫助,如果文章中存在錯誤或不足之處,還請海涵~作者作為人工智能的菜鳥,希望大家能與我在這一筆一劃的博客中成長起來,該專欄作者會用心撰寫,望對得起讀者,共勉!
文章目錄:
- 一.什么是分類學習
- 1.Classification
- 2.MNIST
- 二.Keras實現MNIST分類
- 三.總結
代碼下載地址(歡迎大家關注點贊):
- https://github.com/eastmountyxz/
- AI-for-TensorFlow
- https://github.com/eastmountyxz/
- AI-for-Keras
學Python近八年,認識了很多大佬和朋友,感恩。作者的本意是幫助更多初學者入門,因此在github開源了所有代碼,也在公眾號同步更新。深知自己很菜,得拼命努力前行,編程也沒有什么捷徑,干就對了。希望未來能更透徹學習和撰寫文章,也能在讀博幾年里學會真正的獨立科研。同時非常感謝參考文獻中的大佬們的文章和分享。
- https://blog.csdn.net/eastmount
一.什么是分類學習
1.Classification
我們之前文章解決的都是回歸問題,它預測的是一個連續分布的值,例如房屋的價格、汽車的速度、Pizza的價格等。而當我們遇到需要判斷一張圖片是貓還是狗時,就不能再使用回歸解決了,此時需要通過分類學習,把它分成計算機能夠識別的那一類(貓或狗)。

如上圖所示,通常來說,計算機處理的東西和人類有所不同,無論是聲音、圖片還是文字,它們都只能以數字0或1出現在計算機神經網絡里。神經網絡看到的圖片其實都是一堆數字,對數字的加工處理最終生成另一堆數字,并且具有一定認知上的意義,通過一點點的處理能夠得知計算機到底判斷這張圖片是貓還是狗。
分類(Classification) 屬于有監督學習中的一類,它是數據挖掘、機器學習和數據科學中一個重要的研究領域。分類模型類似于人類學習的方式,通過對歷史數據或訓練集的學習得到一個目標函數,再用該目標函數預測新數據集的未知屬性。分類模型主要包括兩個步驟:
- 訓練。給定一個數據集,每個樣本都包含一組特征和一個類別信息,然后調用分類算法訓練模型。
- 預測。利用生成的模型對新的數據集(測試集)進行分類預測,并判斷其分類結果。
通常為了檢驗學習模型的性能會使用校驗集。數據集會被分成不相交的訓練集和測試集,訓練集用來構造分類模型,測試集用來檢驗多少類標簽被正確分類。

那么,回歸和分類有什么區別呢?
分類和回歸都屬于監督學習,它們的區別在于:回歸是用來預測連續的實數值,比如給定了房屋面積來預測房屋價格,返回的結果是房屋價格;而分類是用來預測有限的離散值,比如判斷一個人是否患糖尿病,返回值是“是”或“否”。也就是說,明確對象屬于哪個預定義的目標類,預定義的目標類是離散值時為分類,連續值時為回歸。
2.MNIST
MNIST是手寫體識別數據集,它是非常經典的一個神經網絡示例。MNIST圖片數據集包含了大量的數字手寫體圖片,如下圖所示,我么可以嘗試用它進行分類實驗。

MNIST數據集是含標注信息的,上圖分別表示數字5、0、4和1。該數據集共包含三部分:
- 訓練數據集:55,000個樣本,mnist.train
- 測試數據集:10,000個樣本,mnist.test
- 驗證數據集:5,000個樣本,mnist.validation
通常,訓練數據集用來訓練模型,驗證數據集用來檢驗所訓練出來的模型的正確性和是否過擬合,測試集是不可見的(相當于一個黑盒),但我們最終的目的是使得所訓練出來的模型在測試集上的效果(這里是準確性)達到最佳。
如下圖所示,數據是以該形式被計算機所讀取,比如28*28=784個像素點,白色的地方都是0,黑色的地方表示有數字的,總共有55000張圖片。

MNIST數據集中的一個樣本數據包含兩部分內容:手寫體圖片和對應的label。這里我們用xs和ys分別代表圖片和對應的label,訓練數據集和測試數據集都有xs和ys,使用mnist.train.images和mnist.train.labels表示訓練數據集中圖片數據和對應的label數據。
如下圖所示,它表示由2828的像素點矩陣組成的一張圖片,這里的數字784(2828)如果放在我們的神經網絡中,它就是x輸入的大小,其對應的矩陣如下圖所示,類標label為1。

最終MNIST的訓練數據集形成了一個形狀為55000*784位的tensor,也就是一個多維數組,第一維表示圖片的索引,第二維表示圖片中像素的索引(tensor中的像素值在0到1之間)。
這里的y值其實是一個矩陣,這個矩陣有10個位置,如果它是1的話,它在1的位置(第2個數字)上寫1,其他地方寫0;如果它是2的話,它在2的位置(第3個數字)上寫1,其他位置為0。通過這種方式對不同位置的數字進行分類,例如用[0,0,0,1,0,0,0,0,0,0]來表示數字3,如下圖所示。

mnist.train.labels是一個55000*10的二維數組,如下圖所示。它表示55000個數據點,第一個數據y表示5,第二個數據y表示0,第三個數據y表示4,第四個數據y表示1。

知道了MNIST數據集的組成,以及x和y具體的含義,我們就開始編寫Keras吧!
二.Keras實現MNIST分類
本文通過Keras搭建一個分類神經網絡,再訓練MNIST數據集。其中X表示圖片,28*28,y對應的是圖像的標簽。
第一步,導入擴展包。
import numpy as np from keras.datasets import mnist from keras.utils import np_utils from keras.models import Sequential from keras.layers import Dense, Activation from keras.optimizers import RMSprop
第二步,載入MNIST數據及預處理。
- X_train.reshape(X_train.shape[0], -1) / 255
- 將每個像素點進行標準化處理,從0-255轉換成0-1的范圍。
- np_utils.to_categorical(y_train, nb_classes=10)
- 調用up_utils將類標轉換成10個長度的值,如果數字是3,則會在對應的地方標記為1,其他地方標記為0,即{0,0,0,1,0,0,0,0,0,0}。
由于MNIST數據集是Keras或TensorFlow的示例數據,所以我們只需要下面一行代碼,即可實現數據集的讀取工作。如果數據集不存在它會在線下載,如果數據集已經被下載,它會被直接調用。
# 下載MNIST數據 # X shape(60000, 28*28) y shape(10000, ) (X_train, y_train), (X_test, y_test) = mnist.load_data() # 數據預處理 X_train = X_train.reshape(X_train.shape[0], -1) / 255 # normalize X_test = X_test.reshape(X_test.shape[0], -1) / 255 # normalize # 將類向量轉化為類矩陣 數字 5 轉換為 0 0 0 0 0 1 0 0 0 0 矩陣 y_train = np_utils.to_categorical(y_train, num_classes=10) y_test = np_utils.to_categorical(y_test, num_classes=10)
第三步,創建神經網絡層。
前面介紹創建神經網絡層的方法是定義之后,利用add()添加神經層。
- model = Sequential()
- model.add(Dense(output_dim=1, input_dim=1))
而這里采用另一種方法,在Sequential()定義的時候通過列表添加神經層。同時需要注意,這里增加了神經網絡激勵函數并調用RMSprop加速神經網絡。
- from keras.layers import Dense, Activation
- from keras.optimizers import RMSprop
該神經網絡層為:
- 第一層為Dense(32, input_dim=784),它將傳入的784轉換成32個輸出
- 該數據加載一個激勵函數Activation(‘relu’),并轉換成非線性化數據
- 第二層為Dense(10),它輸出為10個單位。同時Keras定義神經層會默認其輸入為上一層的輸出,即32(省略)
- 接著加載一個激勵函數Activation(‘softmax’),用于分類
# Another way to build your neural net
model = Sequential([
Dense(32, input_dim=784), # 輸入值784(28*28) => 輸出值32
Activation('relu'), # 激勵函數 轉換成非線性數據
Dense(10), # 輸出為10個單位的結果
Activation('softmax') # 激勵函數 調用softmax進行分類
])
# Another way to define your optimizer
rmsprop = RMSprop(lr=0.001, rho=0.9, epsilon=1e-08, decay=0.0)
# We add metrics to get more results you want to see
# 激活神經網絡
model.compile(
optimizer = rmsprop, # 加速神經網絡
loss = 'categorical_crossentropy', # 損失函數
metrics = ['accuracy'], # 計算誤差或準確率
)
第四步,神經網絡訓練及預測。
print("Training")
model.fit(X_train, y_train, nb_epoch=2, batch_size=32)
print("Testing")
loss, accuracy = model.evaluate(X_test, y_test)
print("loss:", loss)
print("accuracy:", accuracy)
完整代碼:
# -*- coding: utf-8 -*-
"""
Created on Fri Feb 14 16:43:21 2020
@author: Eastmount CSDN YXZ
O(∩_∩)O Wuhan Fighting!!!
"""
import numpy as np
from keras.datasets import mnist
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers import Dense, Activation
from keras.optimizers import RMSprop
#---------------------------載入數據及預處理---------------------------
# 下載MNIST數據
# X shape(60000, 28*28) y shape(10000, )
(X_train, y_train), (X_test, y_test) = mnist.load_data()
# 數據預處理
X_train = X_train.reshape(X_train.shape[0], -1) / 255 # normalize
X_test = X_test.reshape(X_test.shape[0], -1) / 255 # normalize
# 將類向量轉化為類矩陣 數字 5 轉換為 0 0 0 0 0 1 0 0 0 0 矩陣
y_train = np_utils.to_categorical(y_train, num_classes=10)
y_test = np_utils.to_categorical(y_test, num_classes=10)
#---------------------------創建神經網絡層---------------------------
# Another way to build your neural net
model = Sequential([
Dense(32, input_dim=784), # 輸入值784(28*28) => 輸出值32
Activation('relu'), # 激勵函數 轉換成非線性數據
Dense(10), # 輸出為10個單位的結果
Activation('softmax') # 激勵函數 調用softmax進行分類
])
# Another way to define your optimizer
rmsprop = RMSprop(lr=0.001, rho=0.9, epsilon=1e-08, decay=0.0) #學習率lr
# We add metrics to get more results you want to see
# 激活神經網絡
model.compile(
optimizer = rmsprop, # 加速神經網絡
loss = 'categorical_crossentropy', # 損失函數
metrics = ['accuracy'], # 計算誤差或準確率
)
#------------------------------訓練及預測------------------------------
print("Training")
model.fit(X_train, y_train, nb_epoch=2, batch_size=32) # 訓練次數及每批訓練大小
print("Testing")
loss, accuracy = model.evaluate(X_test, y_test)
print("loss:", loss)
print("accuracy:", accuracy)
運行代碼,首先會下載MNIT數據集。
Using TensorFlow backend. Downloading data from https://s3.amazonaws.com/img-datasets/mnist.npz 11493376/11490434 [==============================] - 18s 2us/step
接著輸出兩次訓練的結果,可以看到誤差不斷減小、正確率不斷增大。最終測試輸出的誤差loss為“0.185575”,正確率為“0.94690”。

如果讀者想更直觀地查看我們數字分類的圖形,可以定義函數并顯示。

此時的完整代碼如下所示:
# -*- coding: utf-8 -*-
"""
Created on Fri Feb 14 16:43:21 2020
@author: Eastmount CSDN YXZ
O(∩_∩)O Wuhan Fighting!!!
"""
import numpy as np
from keras.datasets import mnist
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers import Dense, Activation
from keras.optimizers import RMSprop
import matplotlib.pyplot as plt
from PIL import Image
#---------------------------載入數據及預處理---------------------------
# 下載MNIST數據
# X shape(60000, 28*28) y shape(10000, )
(X_train, y_train), (X_test, y_test) = mnist.load_data()
#------------------------------顯示圖片------------------------------
def show_mnist(train_image, train_labels):
n = 6
m = 6
fig = plt.figure()
for i in range(n):
for j in range(m):
plt.subplot(n,m,i*n+j+1)
index = i * n + j #當前圖片的標號
img_array = train_image[index]
img = Image.fromarray(img_array)
plt.title(train_labels[index])
plt.imshow(img, cmap='Greys')
plt.show()
show_mnist(X_train, y_train)
# 數據預處理
X_train = X_train.reshape(X_train.shape[0], -1) / 255 # normalize
X_test = X_test.reshape(X_test.shape[0], -1) / 255 # normalize
# 將類向量轉化為類矩陣 數字 5 轉換為 0 0 0 0 0 1 0 0 0 0 矩陣
y_train = np_utils.to_categorical(y_train, num_classes=10)
y_test = np_utils.to_categorical(y_test, num_classes=10)
#---------------------------創建神經網絡層---------------------------
# Another way to build your neural net
model = Sequential([
Dense(32, input_dim=784), # 輸入值784(28*28) => 輸出值32
Activation('relu'), # 激勵函數 轉換成非線性數據
Dense(10), # 輸出為10個單位的結果
Activation('softmax') # 激勵函數 調用softmax進行分類
])
# Another way to define your optimizer
rmsprop = RMSprop(lr=0.001, rho=0.9, epsilon=1e-08, decay=0.0) #學習率lr
# We add metrics to get more results you want to see
# 激活神經網絡
model.compile(
optimizer = rmsprop, # 加速神經網絡
loss = 'categorical_crossentropy', # 損失函數
metrics = ['accuracy'], # 計算誤差或準確率
)
#------------------------------訓練及預測------------------------------
print("Training")
model.fit(X_train, y_train, nb_epoch=2, batch_size=32) # 訓練次數及每批訓練大小
print("Testing")
loss, accuracy = model.evaluate(X_test, y_test)
print("loss:", loss)
print("accuracy:", accuracy)
三.總結
寫到這里,這篇文章就結束了。本文主要通過Keras實現了一個分類學習的案例,并詳細介紹了MNIST手寫體識別數據集。
最后,希望這篇基礎性文章對您有所幫助,如果文章中存在錯誤或不足之處,還請海涵~作為人工智能的菜鳥,我希望自己能不斷進步并深入,后續將它應用于圖像識別、網絡安全、對抗樣本等領域,指導大家撰寫簡單的學術論文,一起加油!