【tf.keras】basic 01: Classify images of clothing

從TensorFlow2.0開始集成了Keras,變爲了tensorflow.keras模塊,其中,原Keras框架的一些方法已經丟棄,爲了快速上手Keras,實現工程部署,從本篇文章開始更新基於TensorFlow 2.1.0的Keras使用系列教程。教程以小白視角編寫,重要語句都做了註釋。本文是該系列教程的第一篇。通過 Fashion MNIST 數據集實現圖像分類,熟悉TensorFlow和Keras的建模流程和基本用法。


代碼環境:

python version: 3.7.6 (default, Jan  8 2020, 20:23:39) [MSC v.1916 64 bit (AMD64)]
tensorflow version: 2.1.0

注:本文所有代碼在 jupyter notebook 中編寫並測試通過。



1.Fashion MNIST 數據集

Fashion MNIST數據集包含10個類別的70,000張灰度圖像。下圖顯示了低分辨率(28 x 28像素)的單個衣​​物:
在這裏插入圖片描述
Fashion MNIST旨在替代經典MNIST數據集,通常被用作計算機視覺機器學習程序的“ Hello,World”。這兩個數據集用於驗證算法是否按預期工作,是測試和調試代碼的benchmark。本文例子使用60,000張圖像訓練網絡,使用10,000張圖像評估網絡學習圖像分類的準確率。直接從TensorFlow導入和加載Fashion MNIST數據:

導入表要的包:

import sys
import tensorflow as tf
from tensorflow import keras
print('python version:',sys.version)
print('tensorflow version:',tf.__version__)

加載數據集:

fashion_mnist = keras.datasets.fashion_mnist
(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()
# load_data()方法的返回值爲:Tuple of Numpy arrays: (x_train, y_train), (x_test, y_test)

Fashion MNIST 中的圖像是28x28 NumPy數組,像素值範圍是0到255。標籤是整數數組,範圍是0到9,分別對應於圖像表示的衣服真實標籤爲:

Label	Class
0		T-shirt/top
1		Trouser
2		Pullover
3		Dress
4		Coat
5		Sandal
6		Shirt
7		Sneaker
8		Bag
9		Ankle boot

原數據集中不包含真實標籤,爲方便繪圖,首先用一個列表保存真實標籤:

class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
               'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']

注意:在下載數據集的時候,可能會出現下載不全導致報錯:【EOFError: Compressed file ended before the end-of-stream marker was reached】。解決方法:刪除路徑下對應的數據集文件之後,重新下載即可,比如我的在:【C:\Users\34123.keras\datasets】。無需科學上網,否則報SSL錯誤。下載比較慢或者卡死的話,直接從github下載,然後放到該路徑下:
在這裏插入圖片描述


2. 數據可視化與預處理

1.基本信息

train_images.shape
#(60000,28,28)
train_labels
#array([9, 0, 0, ..., 3, 0, 5], dtype=uint8)
len(train_labels)
# 60000
len(test_labels)
# 10000

2.在訓練網絡之前,必須對數據進行預處理。檢查訓練集中第一張圖像的像素值:

plt.figure()
plt.imshow(train_images[0])
plt.colorbar()
plt.grid(False)
plt.show()

在這裏插入圖片描述

可以看到,其像素值落在0到255之間。
[1] matplotlib.pyplot.colorbar 官方文檔

3.將這些值除以255,縮放到0到1,然後再將其輸入神經網絡模型。

train_images = train_images / 255.0
test_images = test_images / 255.0

4.爲了驗證數據的格式正確,顯示訓練集中的前25個圖像,並在每個圖像下方顯示類別名稱:

plt.figure(figsize=(10,10), dpi=200)
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)
    plt.xlabel(class_names[train_labels[i]])
plt.show()

在這裏插入圖片描述


3. 建模

3.1 定義模型

model = keras.Sequential([
    keras.layers.Flatten(input_shape=(28, 28)),
    keras.layers.Dense(128, activation='relu'),
    keras.layers.Dense(10)
])

該網絡的第一層 tf.keras.layers.Flatten 將圖像格式從二維數組(28 x 28像素)轉換爲一維數組(28 * 28 = 784像素)。可以將這一層看作是堆疊圖像中的像素行並將它們排成一行。該層沒有學習參數,只會格式化數據。

像素展平後,添加兩層 tf.keras.layers.Dense 層,即全連接層。第一個Dense層有128個節點(或神經元)。第二層(也是最後一層,即輸出層)返回長度爲 10 的logits數組。每個節點包含一個得分,指示當前圖像屬於10個類別中的哪一類。


3.2 編譯模型

在訓練模型之前,需要進行一些其他設置。這些是在模型的編譯步驟中添加的:

  • 優化器:基於模型看到的數據及其損失函數來更新模型的方式,即權重更新方式。
  • 損失函數:衡量模型在訓練過程中的準確性。訓練過程即爲最小化損失函數的過程。
  • 指標:用於監視訓練和測試過程。本例使用準確率爲指標(正確分類的圖像分數)。
model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])

3.3 訓練模型

訓練神經網絡模型需要執行以下步驟:

  • 將訓練數據輸入模型(fit)。本例中,訓練數據爲train_images和train_labels組成的數組。
  • 模型學習關聯圖像和標籤。
  • 配置模型對測試集進行預測(本例爲test_images數組)。
  • 驗證預測是否與test_labels數組中的標籤匹配。
model.fit(train_images, train_labels, epochs=10)

輸出:

Train on 60000 samples
Epoch 1/10
60000/60000 [==============================] - 8s 128us/sample - loss: 0.4929 - accuracy: 0.8267
Epoch 2/10
60000/60000 [==============================] - 5s 89us/sample - loss: 0.3701 - accuracy: 0.8675
Epoch 3/10
60000/60000 [==============================] - 5s 86us/sample - loss: 0.3331 - accuracy: 0.8773
Epoch 4/10
60000/60000 [==============================] - 5s 91us/sample - loss: 0.3099 - accuracy: 0.8868
Epoch 5/10
60000/60000 [==============================] - 5s 87us/sample - loss: 0.2930 - accuracy: 0.8926
Epoch 6/10
60000/60000 [==============================] - 5s 83us/sample - loss: 0.2792 - accuracy: 0.8964
Epoch 7/10
60000/60000 [==============================] - 5s 88us/sample - loss: 0.2673 - accuracy: 0.9010
Epoch 8/10
60000/60000 [==============================] - 5s 88us/sample - loss: 0.2565 - accuracy: 0.9046
Epoch 9/10
60000/60000 [==============================] - 5s 87us/sample - loss: 0.2461 - accuracy: 0.9075
Epoch 10/10
60000/60000 [==============================] - 5s 90us/sample - loss: 0.2392 - accuracy: 0.9112
<tensorflow.python.keras.callbacks.History at 0x17b19ed3948>

模型訓練時,會打印損失和準確率指標。該模型在訓練數據上達到約91%(0.9112)的精度。


3.4 評估模型

接下來,比較模型在測試數據集上的表現:

test_loss, test_acc = model.evaluate(test_images,  test_labels, verbose=2)
print('\nTest accuracy:', test_acc)

輸出:

10000/10000 - 1s - loss: 0.3307 - accuracy: 0.8846
Test accuracy: 0.8846

事實證明,測試數據集的準確性略低於訓練數據集的準確性。訓練準確性和測試準確性之間的差距表示出現了過擬合。當機器學習模型在新的輸入數據上的表現比訓練數據上的表現差時,即認爲發生了過擬合。過擬合的模型“存儲”訓練數據集中的噪聲和細節,從而對新數據的模型性能產生負面影響。有關更多欠擬合和過擬抑制策略,下篇介紹。


4. 查看預測結果

訓練模型可以預測某些圖像。模型的輸出爲線性的logits。通過softmax層可以將logits轉換爲更容易解釋的概率。【注:對數 (logits):分類模型生成的原始(非標準化)預測向量,通常會傳遞給標準化函數。如果模型要解決多類別分類問題,則對數通常變成 softmax 函數的輸入。之後,softmax 函數會生成一個(標準化)概率向量,對應於每個可能的類別。】

4.1 測試集預測

添加softmax層實現分類概率預測:

probability_model = tf.keras.Sequential([model, tf.keras.layers.Softmax()])
predictions = probability_model.predict(test_images)

預測:

predictions[0]

輸出:

array([6.1835679e-09, 5.0825996e-11, 1.7550703e-10, 1.2875578e-15,
       5.0945664e-11, 1.6961206e-04, 6.4031923e-08, 3.5876669e-03,
       1.0340054e-08, 9.9624264e-01], dtype=float32)

預測是10個數字組成的數組,表示模型對圖像對應於10種不同服裝中的每一種的置信度。查看置信度最高的標籤:

np.argmax(predictions[0])

輸出:

9

即模型對測試集中第一張圖片的預測爲標籤 9,其對應的真實標籤爲 Ankle boot


4.2 預測結果可視化

查看真實圖片與預測:

def plot_image(i, predictions_array, true_label, img):
    '''
    該函數實現打印預測的圖片
    '''
    predictions_array, true_label, img = predictions_array, true_label[i], img[i]
    plt.grid(False)
    plt.xticks([]) # 屏蔽座標顯示,下同
    plt.yticks([])

    plt.imshow(img, cmap=plt.cm.binary)

    predicted_label = np.argmax(predictions_array) # 取出預測最大概率的標籤
    
    if predicted_label == true_label:
        color = 'blue'
    else:
        color = 'red'

    plt.xlabel("{} {:2.0f}% ({})".format(class_names[predicted_label], # 打印預測標籤
                            100*np.max(predictions_array), # 打印置信度
                            class_names[true_label]), # 打印真實標籤
                            color=color)

def plot_value_array(i, predictions_array, true_label):
    '''
    該函數實現繪製概率柱狀圖
    '''
    predictions_array, true_label = predictions_array, true_label[i]
    
    plt.grid(False) # 屏蔽格線顯示
    plt.xticks(range(10))
    plt.yticks([]) 
    thisplot = plt.bar(range(10), predictions_array, color="#777777") # 繪製柱狀圖
    plt.ylim([0, 1]) # 設置y軸刻度顯示範圍
    
    predicted_label = np.argmax(predictions_array) # 取出預測標籤

    thisplot[predicted_label].set_color('red') # 設置柱狀圖中預測標籤的顏色
    thisplot[true_label].set_color('blue') 
    
def merged_result(i):
    '''
    該函數實現彙總以上兩個函數輸出結果,提供預測某張照片索引的接口
    '''
    plt.figure(figsize=(6,3), dpi=150)
    plt.subplot(1,2,1)
    plot_image(i, predictions[i], test_labels, test_images)
    plt.subplot(1,2,2)
    plot_value_array(i, predictions[i],  test_labels)
    plt.show()

預測:

i = 12
merged_result(i)

在這裏插入圖片描述

i = 450
merged_result(i)

輸出:
在這裏插入圖片描述
輸出多個預測結果:

def plot_images(num_rows, num_cols):
    '''
    該函數實現多個預測結果輸出
    '''
    num_images = num_rows*num_cols # 繪製圖片數量
    
    plt.figure(figsize=(2*2*num_cols, 2*num_rows), dpi=150) # 設置畫布尺寸
    
    for i in range(num_images):
        plt.subplot(num_rows, 2*num_cols, 2*i+1) # 第i個子圖的位置
        plot_image(i, predictions[i], test_labels, test_images)
        plt.subplot(num_rows, 2*num_cols, 2*i+2)
        plot_value_array(i, predictions[i], test_labels)

    plt.tight_layout()
    plt.show()
    
   
num_rows = 5
num_cols = 3
plot_images(num_rows, num_cols)

輸出:
在這裏插入圖片描述


4.3 單張圖片預測

def predict_image(i):
    
    img = test_images[i] # shape=(28,28)
    img = (np.expand_dims(img,0)) # shape=(1,28,28),轉化成列表格式,訓練集和測試集的shape爲(None,28,28)
    predictions_single = probability_model.predict(img)  # 預測
    print('predictions_single:\n', predictions_single)
    plot_value_array(1, predictions_single[0], test_labels) # 繪圖
    _ = plt.xticks(range(10), class_names, rotation=45) # 設置x軸座標刻度
    print('predict label:', np.argmax(predictions_single[0]))
    print('true label:', test_labels[i])

predict_image(66)    

輸出:

predictions_single:
 [[0.19836323 0.01996289 0.1276678  0.28869623 0.05913025 0.044572
  0.25288364 0.00403849 0.00407252 0.00061292]]
predict label: 3
true label: 2

在這裏插入圖片描述


參考:
https://www.tensorflow.org/tutorials/keras/classification

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章