TensorFlow2 學習——CNN圖像分類

TensorFlow2 學習——CNN圖像分類

1. 導包

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

2. 圖像分類 fashion_mnist

  • 數據處理
    # 原始數據
    (X_train_all, y_train_all),(X_test, y_test) = tf.keras.datasets.fashion_mnist.load_data()
    
    # 訓練集、驗證集拆分
    X_train, X_valid, y_train, y_valid = train_test_split(X_train_all, y_train_all, test_size=0.25)
    
    # 數據標準化,你也可以用除以255的方式實現歸一化
    # 注意最後reshape中的1,代表圖像只有一個channel,即當前圖像是灰度圖
    scaler = StandardScaler()
    X_train_scaled = scaler.fit_transform(X_train.reshape(-1, 28 * 28)).reshape(-1, 28, 28, 1)
    X_valid_scaled = scaler.transform(X_valid.reshape(-1, 28 * 28)).reshape(-1, 28, 28, 1)
    X_test_scaled = scaler.transform(X_test.reshape(-1, 28 * 28)).reshape(-1, 28, 28, 1)
    
  • 構建CNN模型
    model = tf.keras.models.Sequential()
    # 多個卷積層
    model.add(tf.keras.layers.Conv2D(filters=32, kernel_size=[5, 5], padding="same", activation="relu", input_shape=(28, 28, 1)))
    model.add(tf.keras.layers.MaxPool2D(pool_size=[2, 2], strides=2))
    model.add(tf.keras.layers.Conv2D(filters=64, kernel_size=[5, 5], padding="same", activation="relu"))
    model.add(tf.keras.layers.MaxPool2D(pool_size=[2, 2], strides=2))
    # 將前面卷積層得出的多維數據轉爲一維
    # 7和前面的kernel_size、padding、MaxPool2D有關
    # Conv2D: 28*28 -> 28*28 (因爲padding="same")
    # MaxPool2D: 28*28 -> 14*14
    # Conv2D: 14*14 -> 14*14 (因爲padding="same")
    # MaxPool2D: 14*14 -> 7*7
    model.add(tf.keras.layers.Reshape(target_shape=(7 * 7 * 64,)))
    # 傳入全連接層
    model.add(tf.keras.layers.Dense(1024, activation="relu"))
    model.add(tf.keras.layers.Dense(10, activation="softmax"))
    
    # compile
    model.compile(loss = "sparse_categorical_crossentropy",
                 optimizer = "sgd",
                 metrics = ["accuracy"])
    
  • 模型訓練
    callbacks = [
        tf.keras.callbacks.EarlyStopping(min_delta=1e-3, patience=5)
    ]
    
    history = model.fit(X_train_scaled, y_train, epochs=15, 
                        validation_data=(X_valid_scaled, y_valid),
                        callbacks = callbacks)
    
    Train on 50000 samples, validate on 10000 samples
    Epoch 1/15
    50000/50000 [==============================] - 17s 343us/sample - loss: 0.5707 - accuracy: 0.7965 - val_loss: 0.4631 - val_accuracy: 0.8323
    Epoch 2/15
    50000/50000 [==============================] - 13s 259us/sample - loss: 0.3728 - accuracy: 0.8669 - val_loss: 0.3573 - val_accuracy: 0.8738
    ...
    Epoch 13/15
    50000/50000 [==============================] - 12s 244us/sample - loss: 0.1625 - accuracy: 0.9407 - val_loss: 0.2489 - val_accuracy: 0.9112
    Epoch 14/15
    50000/50000 [==============================] - 12s 240us/sample - loss: 0.1522 - accuracy: 0.9451 - val_loss: 0.2584 - val_accuracy: 0.9104
    Epoch 15/15
    50000/50000 [==============================] - 12s 237us/sample - loss: 0.1424 - accuracy: 0.9500 - val_loss: 0.2521 - val_accuracy: 0.9114
    
  • 作圖
    def plot_learning_curves(history):
        pd.DataFrame(history.history).plot(figsize=(8, 5))
        plt.grid(True)
        #plt.gca().set_ylim(0, 1)
        plt.show()
        
    plot_learning_curves(history)
    
    歷史記錄作圖
  • 測試集評估準確率
    model.evaluate(X_test_scaled, y_test)
    
    [0.269884311157465, 0.9071]
    
  • 可以看到使用CNN後,圖像分類的準確率明顯提升了。之前的模型是0.8747,現在是0.9071。

3. 圖像分類 Dogs vs. Cats

3.1 原始數據

cat圖像

3.2 利用Dataset加載圖片

  • 由於原始圖片過多,我們不能將所有圖片一次加載入內存。Tensorflow爲我們提供了便利的Dataset API,可以從硬盤中一批一批的加載數據,以用於訓練。
  • 處理本地圖片路徑與標籤
    # 訓練數據的路徑
    train_dir = "C:/Users/Skey/Downloads/datasets/cat_vs_dog/train/"
    
    train_filenames = [] # 所有圖片的文件名
    train_labels = [] # 所有圖片的標籤
    for filename in os.listdir(train_dir):
        train_filenames.append(train_dir + filename)
        if (filename.startswith("cat")):
            train_labels.append(0) # 將cat標記爲0
        else:
            train_labels.append(1) # 將dog標記爲1
    
    # 數據隨機拆分
    X_train, X_valid, y_train, y_valid = train_test_split(train_filenames, train_labels, test_size=0.2)
    
  • 定義一個解碼圖片的方法
    def _decode_and_resize(filename, label):
        image_string = tf.io.read_file(filename)            # 讀取圖片
        image_decoded = tf.image.decode_jpeg(image_string)  # 解碼
        image_resized = tf.image.resize(image_decoded, [256, 256]) / 255.0 # 重置size,並歸一化
        return image_resized, label
    
  • 定義 Dataset,用於加載圖片數據
    # 訓練集
    train_dataset = tf.data.Dataset.from_tensor_slices((train_filenames, train_labels))
    train_dataset = train_dataset.map(
        map_func=_decode_and_resize, # 調用前面定義的方法,解析filename,轉爲特徵和標籤
        num_parallel_calls=tf.data.experimental.AUTOTUNE)
    train_dataset = train_dataset.shuffle(buffer_size=128) # 設置緩衝區大小
    train_dataset = train_dataset.batch(32) # 每批數據的量
    train_dataset = train_dataset.prefetch(tf.data.experimental.AUTOTUNE) # 啓動預加載圖片,也就是說CPU會提前從磁盤加載數據,不用等上一次訓練完後再加載
    
    # 驗證集
    valid_dataset = tf.data.Dataset.from_tensor_slices((valid_filenames, valid_labels))
    valid_dataset = valid_dataset.map(
        map_func=_decode_and_resize,
        num_parallel_calls=tf.data.experimental.AUTOTUNE)
    valid_dataset = valid_dataset.batch(32)
    

3.3 構建CNN模型,並訓練

  • 構建模型與編譯

    model = tf.keras.Sequential([
    	# 卷積,32個filter(卷積核),每個大小爲3*3,步長爲1
        tf.keras.layers.Conv2D(32, 3, activation='relu', input_shape=(256, 256, 3)),
        # 池化,默認大小2*2,步長爲2
        tf.keras.layers.MaxPooling2D(),
        tf.keras.layers.Conv2D(32, 5, activation='relu'),
        tf.keras.layers.MaxPooling2D(),
        tf.keras.layers.Flatten(),
        tf.keras.layers.Dense(64, activation='relu'),
        tf.keras.layers.Dense(2, activation='softmax')
    ])
    
    model.compile(
        optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),
        loss=tf.keras.losses.sparse_categorical_crossentropy,
        metrics=[tf.keras.metrics.sparse_categorical_accuracy]
    )
    
  • 模型總覽

    model.summary()
    
    Model: "sequential_1"
    _________________________________________________________________
    Layer (type)                 Output Shape              Param #   
    =================================================================
    conv2d_2 (Conv2D)            (None, 254, 254, 32)      896       
    _________________________________________________________________
    max_pooling2d_2 (MaxPooling2 (None, 127, 127, 32)      0         
    _________________________________________________________________
    conv2d_3 (Conv2D)            (None, 123, 123, 32)      25632     
    _________________________________________________________________
    max_pooling2d_3 (MaxPooling2 (None, 61, 61, 32)        0         
    _________________________________________________________________
    flatten_1 (Flatten)          (None, 119072)            0         
    _________________________________________________________________
    dense_2 (Dense)              (None, 64)                7620672   
    _________________________________________________________________
    dense_3 (Dense)              (None, 2)                 130       
    =================================================================
    Total params: 7,647,330
    Trainable params: 7,647,330
    Non-trainable params: 0
    
  • 開始訓練

    model.fit(train_dataset, epochs=10, validation_data=valid_dataset)
    
    • 由於數據量大,此處訓練時間較久
    • 需要注意的是此處打印的step,每個step指的是一個batch(例如32個樣本一個batch)
  • 模型評估

    test_dataset = tf.data.Dataset.from_tensor_slices((valid_filenames, valid_labels))
    test_dataset = test_dataset.map(_decode_and_resize)
    test_dataset = test_dataset.batch(32)
    
    print(model.metrics_names)
    print(model.evaluate(test_dataset))
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章