【神经网络】(3) 卷积神经网络(CNN),案例:动物三分类,附python完整代码
各位同學好,今天和大家分享一下TensorFlow2.0深度學習中卷積神經網絡的案例。現在有貓、狗、熊貓圖片一千張,構建卷積神經網絡實現圖像的分類預測。
1. 數據加載
將訓練測試數據劃分好后放在同一個文件目錄下,使用tf.keras.preprocessing.image_dataset_from_directory()函數構造數據集。函數的具體用法見:tf.keras.preprocessing.image_dataset_from_directory_自在獨行的博客-CSDN博客_image_dataset_from_directory
對訓練數據和驗證數據進行one-hot編碼,便于計算損失,讀入圖像時統一圖片大小size為128*128。batch為64,每次迭代從中取64個樣本。class_names中保存的是根據文件夾名稱生成的標簽。
# 三分類,卷積神經網絡
import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers,optimizers,datasets,Sequential
import os # 設置一下輸出框打印的內容
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' # '2'輸出欄只打印error信息,其他亂七八糟的信息不打印#(1)數據獲取
# 加載訓練集數據
filepath1 = 'C:/Users/admin/.../train'
train_ds = tf.keras.preprocessing.image_dataset_from_directory(filepath1,label_mode='categorical', # "int", "categorical"表示onehot, "binary", or Noneseed=123,image_size=(128, 128), # resize圖片大小batch_size=64)# 加載驗證集數據
filepath2 = 'C:/Users/admin/.../new_data/val'
val_ds = tf.keras.preprocessing.image_dataset_from_directory(filepath2,label_mode='categorical',seed=123,image_size=(128, 128),batch_size=64)# 加載測試集數據
filepath3 = 'C:/Users/.../new_data/test'
test_ds = tf.keras.preprocessing.image_dataset_from_directory(filepath3,label_mode='int',seed=123,image_size=(128, 128),batch_size=64) # 類別名稱
class_names = train_ds.class_names
print('類別有:',class_names)
# 類別有: ['cats', 'dogs', 'panda']
2. 數據預處理
使用.map()對dataset中的數據進行processing函數中的操作,對每個點的像素值從[0,255]變成[-1,1],.shuffle()對數據集重新洗牌打散,但不改變x和y之間的對應關系。
train_ds.take(1) 是指從訓練集數據集中取出1個batch的數據,返回值img存放圖像數據,label存放圖像的標簽。
#(2)數據預處理
def processing(image, label): image = 2 * tf.cast(image, tf.float32) / 255.0 - 1 #[-1,1]之間label = tf.cast(label, tf.int32) # 修改數據類型return (image, label)train_ds = train_ds.map(processing).shuffle(10000) #洗牌
val_ds = val_ds.map(processing).shuffle(10000)
test_ds = test_ds.map(processing).shuffle(10000)#(2)數據檢查
for img, label in train_ds.take(1): # 取出一個batch的數據,一個batch有64個樣本print('img.shape:', img.shape) # img.shape: (64, 128, 128, 3)print('label.shape:', label.shape) # label.shape: (64, 3)# 數據集展示
import matplotlib.pyplot as plt
for img,label in train_ds.take(1): #取一個batchfor i in range(15):plt.subplot(3,5,i+1)plt.imshow(img[i]) # 每張圖像的shape為(4, 256, 256, 3) plt.xticks([]) # 不顯示xy軸坐標刻度plt.yticks([])
plt.show()
預處理后的圖像展示結果如下:
3. 網絡構建
這里構造一個6層的神經網絡,使用Sequential()容器堆疊網絡各層,layers.Conv2D()構造卷積層,卷積核size為3*3。layers.MaxPool2D()構造池化層,采用最大池化方法。指定padding='same'填充圖像,在傳播過程中保證生成的特征圖的size不變,只改變其channel。指定layers.Dropout(0.2)每次迭代該層每個神經元都有20%的概率被殺死,防止網絡出現過擬合現象。
在卷積池化層和全連接層之間需要指定一個Flatten層layers.Flatten(),輸入至全連接層的圖像需要是一個二維tensor,假設卷積池化層輸出的shape為[b,1,1,64],那么傳入全連接層的shape需要w是[b,64]
#(3)網絡構建
# ==1== 卷積和池化層,2次卷積1次池化
network = Sequential()
# unit1
network.add(layers.Conv2D(32, kernel_size=[3,3], strides=1, padding='same', activation=tf.nn.relu))
network.add(layers.Conv2D(32, kernel_size=[3,3], strides=1, padding='same', activation=tf.nn.relu))
network.add(layers.MaxPool2D(pool_size=[2,2], strides=2, padding='same'))
# unit2
network.add(layers.Conv2D(64, kernel_size=[3,3], strides=1, padding='same', activation=tf.nn.relu))
network.add(layers.Conv2D(64, kernel_size=[3,3], strides=1, padding='same', activation=tf.nn.relu))
network.add(layers.MaxPool2D(pool_size=[2,2], strides=2, padding='same'))
# dropout層
network.add(layers.Dropout(0.2)) #每個神經元都有0.2的概率被殺死# ==2== Flatten層,連接卷積池化層和全連接層
network.add(layers.Flatten())# ==3== 全連接層
network.add(layers.Dense(128, activation=tf.nn.relu))
network.add(layers.Dense(3)) # 輸出層logits層# ==4== 指定輸入層
network.build(input_shape=[None, 128, 128, 3])# ==5== 查看網絡結構
network.summary()
網絡結構如下,param代表該層網絡擁有的參數個數
Model: "sequential"
_________________________________________________________________Layer (type) Output Shape Param #
=================================================================conv2d_1 (Conv2D) (None, 128, 128, 32) 896 conv2d_2 (Conv2D) (None, 128, 128, 32) 9248 max_pooling2d_1 (MaxPoolin (None, 64, 64, 32) 0 g2D) conv2d_3 (Conv2D) (None, 64, 64, 64) 18496 conv2d_4 (Conv2D) (None, 64, 64, 64) 36928 max_pooling2d_2 (MaxPoolin (None, 32, 32, 64) 0 g2D) dropout_1 (Dropout) (None, 32, 32, 64) 0 flatten_1 (Flatten) (None, 65536) 0 dense_1 (Dense) (None, 128) 8388736 dense_2 (Dense) (None, 3) 387 =================================================================
Total params: 8,454,691
Trainable params: 8,454,691
Non-trainable params: 0
_________________________________________________________________
4. 網絡配置
采用學習率指數衰減的方法方法,tf.keras.optimizers.schedules.ExponentialDecay(),起初梯度變化大一點能更快接近目標,后續梯度變化不斷減小,越來越逼近最優點。設置早停策略,因為神經網絡在不斷迭代的過程中,準確率不會一直在上升,如果找到某一極值點,且后續多次迭代過程中,網絡效果沒有變的更優的跡象,就使用之前的極值點的結果作為最優解。
#(4)網絡配置
# 設置動態學習率指數衰減
exponential_decay = tf.keras.optimizers.schedules.ExponentialDecay(initial_learning_rate=0.001, #初始學習率decay_steps=2, # 衰減步長decay_rate=0.96) # 衰減率# 編譯
network.compile(optimizer=optimizers.Adam(learning_rate=exponential_decay), loss=tf.losses.CategoricalCrossentropy(from_logits=True), # 交叉熵損失metrics=['accuracy']) # 準確率指標# 早停策略
early_stopping = keras.callbacks.EarlyStopping(monitor = 'val_acc', # 驗證集的準確率作為指標patience = 10, # 最多忍受多少個次循環沒有改進restore_best_weights = True) # 發生早停時,自動尋找最優的monitor參數
5. 模型訓練
#(5)網絡訓練
# 指定訓練集、驗證集、迭代次數
# 訓練目標和驗證目標需要時one_hot編碼后的
model = network.fit(train_ds, # 訓練集validation_data=val_ds, # 驗證集 epochs=10, # 迭代多少次callbacks= early_stopping, # 回調函數,在訓練過程中的適當時機被調用shuffle = True, # 每輪迭代之前洗牌verbose = 1 # 0為不在標準輸出流輸出日志信息,1:顯示進度條,2:每個epoch輸出一行記錄)
由于時間關系,這里就簡單循環10次,效果如下
Epoch 1/10
33/33 [==============================] - ETA: 0s - loss: 1.1605 - accuracy: 0.4527 WARNING:tensorflow:Early stopping conditioned on metric `val_acc` which is not available. Available metrics are: loss,accuracy,val_loss,val_accuracy
33/33 [==============================] - 75s 2s/step - loss: 1.1605 - accuracy: 0.4527 - val_loss: 0.8374 - val_accuracy: 0.5796
#.................#
#.................#
Epoch 10/10
33/33 [==============================] - ETA: 0s - loss: 0.6362 - accuracy: 0.6985 WARNING:tensorflow:Early stopping conditioned on metric `val_acc` which is not available. Available metrics are: loss,accuracy,val_loss,val_accuracy
33/33 [==============================] - 96s 3s/step - loss: 0.6362 - accuracy: 0.6985 - val_loss: 0.6821 - val_accuracy: 0.6415
6. 模型評估
比較網絡訓練集和驗證集上的準確率和損失,繪圖比較
#(6)模型評估
# ==1== 計算準確率
train_acc = model.history['accuracy']
val_acc = model.history['val_accuracy']# ==2== 損失
train_loss = model.history['loss']
val_loss = model.history['val_loss']# ==3== 曲線圖
epochs_range = range(len(train_acc)) # 橫坐標,網絡循環了幾次# 準確率曲線
plt.figure(figsize=(10,5))
plt.subplot(1,2,1)
plt.plot(epochs_range, train_acc, label='Training_acc')
plt.plot(epochs_range, val_acc, label='validation_acc')
plt.legend()
plt.title('Accuracy')# 損失曲線
plt.subplot(1,2,2)
plt.plot(epochs_range, train_loss, label='Training_loss')
plt.plot(epochs_range, val_loss, label='validation_loss')
plt.legend()
plt.title('Loss')
如圖所示訓練集和驗證集的損失都逐漸下降,隨著迭代次數的增加,效果會更好,但要防止過擬合的現象出現。
7. 預測
采用測試集中的圖像數據對網絡進行預測,network.predict()得到輸入圖像分別屬于三個分類的數值,返回numpy類型,使用np.argmax()找到最大值的索引,該索引對應的class_names標簽就是預測得到的該圖像所屬的分類。
#(7)預測
test_pred = []
test_target = []for images, targets in test_ds: #取一個batch的測試集生成混淆矩陣for image, label in zip(images, targets): # 每次從batch中取出一組# 需要給圖片增加一個維度img_array = tf.expand_dims(image, axis=0) # 使用模型預測圖片中的動物prediction = network.predict(img_array)# 預測結果是預測值最大值索引對應的位置test_pred.append(class_names[np.argmax(prediction)])# 保存真實值的標簽test_target.append(class_names[label]) # label沒有做onehot編碼print('測試結果:',test_pred[:10])
print('真實結果:',test_target[:10])#(8)混淆矩陣
from sklearn.metrics import confusion_matrix
import seaborn as sns
import pandas as pd
plt.rcParams['font.sans-serif'] = ['SimSun'] #宋體
plt.rcParams['font.size'] = 15 #設置字體大小# 生成混淆矩陣
conf_numpy = confusion_matrix(test_target, test_pred)
# 將矩陣轉化為 DataFrame
conf_df = pd.DataFrame(conf_numpy, index=class_names ,columns=class_names) plt.figure(figsize=(8,7))sns.heatmap(conf_df, annot=True, fmt="d", cmap="BuPu")plt.title('混淆矩陣')
plt.ylabel('真實值')
plt.xlabel('預測值')
輸出的前10張圖片的預測結果如下:
測試結果: ['panda', 'dogs', 'cats', 'cats', 'panda', 'panda', 'panda', 'panda', 'dogs', 'panda']
真實結果: ['panda', 'dogs', 'dogs', 'cats', 'panda', 'panda', 'panda', 'panda', 'cats', 'panda']
為了更加清晰的展示預測值和真實值的關系,構建混淆矩陣,如圖。可見一個6層的卷積網絡經過10次循環后,對熊貓的預測精度最高,對狗的預測精度較低,需要增加網絡層數和循環次數。
總結
以上是生活随笔為你收集整理的【神经网络】(3) 卷积神经网络(CNN),案例:动物三分类,附python完整代码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【神经网络】(2) 网络优化,案例:服装
- 下一篇: 【神经网络】(4) 卷积神经网络(CNN