TensorFlow2 學習——MLP圖像分類

TensorFlow2 學習——MLP圖像分類

導包

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import tensorflow as tf
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split

原始數據

  • 加載數據集
    # 衣物類圖片數據集 fashion_mnist
    # 訓練集All,測試集
    (X_train_all, y_train_all),(X_test, y_test) = tf.keras.datasets.fashion_mnist.load_data()
    
    # 手寫數字數據集mnist
    # tf.keras.datasets.mnist.load_data()
    
  • 查看數據集
    # 查看數據維度
    print(X_train_all.shape)
    # 查看標籤種類
    print(set(y_train_all))
    

數據作圖

  • 單個圖片數據分析
    # 其中一張圖片的數據
    print(X_train_all[0])
    
    • 此處會打印一個28*28的矩陣
    • 矩陣內的值表示0-255的灰度值(即代表圖片的一個像素)
  • 展示單張圖片
    def show_single_image(img_arr):
        plt.imshow(img_arr, cmap="binary")
        plt.show()
    
    show_single_image(X_train_all[1])
    
    單張圖片
  • 展示多張圖片
    def show_images(n_rows, n_cols, x_data, y_data, class_names):
        assert len(x_data) == len(y_data)
        assert n_rows * n_cols < len(x_data)
        
        plt.figure(figsize=(n_cols * 1.5, n_rows * 1.5))
        for row in range(n_rows):
            for col in range(n_cols):
                index = row * n_cols + col
                plt.subplot(n_rows, n_cols, index + 1)
                plt.imshow(x_data[index], cmap="binary", interpolation="nearest")
                plt.axis("off")
                plt.title(class_names[y_data[index]])
        plt.show()
    
    class_names = ["T-shirt", "Trouser", "Pullover", "Dress", "Coat", "Sandal", "Shirt", "Sneaker", "Bag", "Ankle boot"]
    
    show_images(3, 5, X_train_all, y_train_all, class_names)
    
    多張圖片

數據劃分與標準化

  • 訓練集、驗證集拆分
    # X_train, X_valid = X_train_all[:50000], X_train_all[50000:]
    # y_train, y_valid = y_train_all[:50000], y_train_all[50000:]
    X_train, X_valid, y_train, y_valid = train_test_split(X_train_all, y_train_all, test_size=0.25)
    
    print("train: ", X_train.shape, y_train.shape)
    print("valid: ", X_valid.shape, y_valid.shape)
    print(" test: ", X_test.shape, y_test.shape)
    
  • 數據標準化
    scaler = StandardScaler()
    X_train_scaled = scaler.fit_transform(X_train.reshape(-1, 28 * 28)).reshape(-1, 28, 28)
    X_valid_scaled = scaler.transform(X_valid.reshape(-1, 28 * 28)).reshape(-1, 28, 28)
    X_test_scaled = scaler.transform(X_test.reshape(-1, 28 * 28)).reshape(-1, 28, 28)
    
    print(X_train_scaled.max(), X_train_scaled.min())
    

構建模型並訓練

  • 搭建神經網絡層

    # relu: y = max(0, x)
    # softmax: 用於解決多分類問題,將向量變成概率分佈
    #          x = [x1, x2, x3]
    #          sum = e^x1 + e^x2 + e^x3
    #          y = [e^x1/sum, e^x2/sum, e^x3/sum]
    
    # 方法1
    # model = tf.keras.models.Sequential()
    # model.add(tf.keras.layers.Flatten(input_shape=[28, 28]))
    # model.add(tf.keras.layers.Dense(300, activation="relu"))
    # model.add(tf.keras.layers.Dense(100, activation="relu"))
    # model.add(tf.keras.layers.Dense(10, activation="softmax"))
    
    # 方法2
    model = tf.keras.models.Sequential([
        tf.keras.layers.Flatten(input_shape=[28, 28]),
        tf.keras.layers.Dense(200, activation="relu"),
        tf.keras.layers.Dense(150, activation="relu"),
        # tf.keras.layers.Dropout(0.5), # 添加Dropout層,可以抑制過擬合。0.5表示丟棄50%單元
        tf.keras.layers.Dense(100, activation="relu"),
        tf.keras.layers.Dense(10, activation="softmax")
    ])
    
    # 方法3 函數式
    # input = tf.keras.Input(shape=(28, 28))
    # x = tf.keras.layers.Flatten()(input)
    # x = tf.keras.layers.Dense(200, activation="relu")(x)
    # x = tf.keras.layers.Dense(150, activation="relu")(x)
    # x = tf.keras.layers.Dense(100, activation="relu")(x)
    # output = tf.keras.layers.Dense(10, activation="softmax")(x)
    
    # model = tf.keras.Model(inputs=input, outputs=output)
    
    # 方法4 定義一個類,繼承tf.keras.Model
    # class My_Model(tf.keras.Model):
    #    def __init__(self):
    #    def call(self, inputs):
    
    • Flatten用於降維,例如此處將28*28的矩陣打散爲784個特徵的一維向量
    • Dense是全連接層,接收上一層的所有參數
      • 第一個參數,指的是本層有多少個神經元節點
      • 第二個參數,activation是激活函數,用於處理接收到的數據,包括relu、sigmoid、softmax等
    • 最後一個Dense,節點數被設置爲10,因爲本數據標籤只有10類,因此最後只有10種輸出
  • 模型編譯

    model.compile(loss = "sparse_categorical_crossentropy",
                 optimizer = "adam", 
                 metrics = ["accuracy"])
    
    • loss 代表損失函數的計算方式
      • 例如還可以寫成mse、categorical_crossentropy等
      • 此處因爲是多分類問題,所以可以採用sparse_categorical_crossentropy或categorical_crossentropy
      • 如要使用categorical_crossentropy,需要將標籤數據轉換爲onehot編碼形式,代碼如下
        y_train_onehot = tf.keras.utils.to_categorical(y_train)
        y_valid_onehot = tf.keras.utils.to_categorical(y_valid)
        y_test_onehot = tf.keras.utils.to_categorical(y_test)
        
    • optimizer 代表優化的方式
      • 例如sgd、rmsprop、adam等
      • 需要調節其內部參數,可以寫成tf.keras.optimizers.Adam(lr=0.001)
    • metrics 代表了模型評判標準,會隨着訓練時打印
  • 模型總覽

    model.summary()
    
    Model: "sequential_13"
    _________________________________________________________________
    Layer (type)                 Output Shape              Param #   
    =================================================================
    flatten_13 (Flatten)         (None, 784)               0         
    _________________________________________________________________
    dense_46 (Dense)             (None, 200)               157000    
    _________________________________________________________________
    dense_47 (Dense)             (None, 150)               30150     
    _________________________________________________________________
    dense_48 (Dense)             (None, 100)               15100     
    _________________________________________________________________
    dense_49 (Dense)             (None, 10)                1010      
    =================================================================
    Total params: 203,260
    Trainable params: 203,260
    Non-trainable params: 0
    
    • Layer列 - 是我們構建的網絡層
    • Output Shape列 - 是當前網絡層的信息
      • 第一個參數None是樣本數,因爲構建模型時並不知道等會兒需要訓練多少數據,因此是None
      • 第二個參數是該層神經元節點的個數
    • Param # - 是該網絡層待訓練參數的個數
      • 計算公式:上一層節點個數 * 本層節點個數 + 本層節點個數 = 本層參數個數
      • 例如 784 * 200 + 200 = 157000,200 * 150 + 150 = 30150
      • 其實就是說,本層每個節點針對上一層的所有節點分別都有一個權重w,最後本層每個節點還有一個偏置值b
  • 開始訓練模型

    # X_train_scaled 即訓練集特徵
    # y_train 即訓練集標籤
    # epochs 是訓練的批次數
    # validation_data 用於指定驗證集
    history = model.fit(X_train_scaled, y_train, epochs=10, validation_data=(X_valid_scaled, y_valid))
    
    • 訓練過程較慢,需等待
    • 其中 loss: 0.2208 - accuracy: 0.9171 代表了訓練集的損失值、準確的
    • 其中 val_loss: 0.3333 - val_accuracy: 0.8916 代表了驗證集的損失值、準確的

模型評估與預測

  • 查看模型訓練歷史記錄
    pd.DataFrame(history.history)
    
  • 利用歷史記錄作圖
    pd.DataFrame(history.history).plot(figsize=(8, 5))
    plt.grid(True)
    #plt.gca().set_ylim(0, 1)
    plt.show()
    
    歷史記錄作圖
  • 使用測試集進行模型評估
    model.evaluate(X_test_scaled, y_test)
    
    • 輸出結果示例 [0.35619084103703497, 0.8747]
    • 第一個是損失值,第二個是準確率
  • 利用模型進行預測
    • 使用predict進行預測
      # 使用predict進行預測
      result = model.predict(X_test_scaled[0:1])
      
      print(result) # 10個類別,每個類別都有一個概率
      print(result.sum()) # 所有類別概率和爲1
      print(result.max(), np.argmax(result)) # 概率最大的就是預測的類別
      
      [[4.1775929e-09 4.8089838e-10 9.2707603e-10 7.3885815e-08 5.2114243e-11
        2.4399082e-03 1.8424946e-09 9.9424636e-03 2.9137237e-12 9.8761755e-01]]
      1.0
      0.98761755 9
      
    • 使用predict_classes直接得到預測的類別
      # 使用predict_classes直接得到預測的類別
      print(model.predict_classes(X_test_scaled)[:30])
      print(y_test[:30])
      
      [9 2 1 1 6 1 4 6 5 7 4 5 8 3 4 1 2 2 8 0 2 5 7 5 1 2 6 0 9 6]
      [9 2 1 1 6 1 4 6 5 7 4 5 7 3 4 1 2 4 8 0 2 5 7 9 1 4 6 0 9 3]
      

其他:回調Callback的使用

  • Callback
    • Tensorboard - 生成Tensorboard記錄,方便查看
    • EarlyStopping - 用於提前停止訓練。本次loss與上次loss之差小於min_delta達到patience次,那就停止訓練
    • ModelChackpoint - 保存模型,save_best_only保存最佳的
  • 代碼示例
    import os
    
    # windows下寫.\callbacks,linux下寫./callbacks,或者都寫callbacks(不指定前面的斜槓/反斜槓)
    logdir = ".\callbacks" 
    if not os.path.exists(logdir):
        os.mkdir(logdir)
    ouput_model_file = os.path.join(logdir, "fashion_mnist_model.h5")
    
    callbacks = [
        tf.keras.callbacks.TensorBoard(logdir),
        tf.keras.callbacks.ModelCheckpoint(ouput_model_file, save_best_only=True),
        tf.keras.callbacks.EarlyStopping(min_delta=1e-3, patience=5)
    ]
    
    history = model.fit(X_train_scaled, y_train, epochs=20,
                        validation_data=(X_valid_scaled, y_valid),
                        callbacks = callbacks)
    
  • 查看Tensorboard的命令 tensorboard --logdir callbacks的目錄
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章