Keras TensorFlow教程:使用自己的数据集进行训练
大多數Keras教程都嘗試使用圖像分類數據集(如MNIST(手寫識別)或基本對象CIFAR-10(基本對象識別))來開啟Keras庫的基礎知識學習。
這篇文章將對Keras入門教程進行不同的嘗試。使用自定義數據集訓練第一個神經網絡和卷積神經網絡——將深度學習應用您自己的數據集,而不是Keras內置的數據集。
使用Keras訓練您的第一個簡單神經網絡不需要很多代碼,但是我們將逐步開始,逐步進行,以確保您了解如何在自己的自定義數據集上訓練網絡的過程。
今天介紹的步驟包括:
1. 安裝Keras和其依賴庫
2. 從磁盤加載數據
3. 訓練和測試數據分組
4. 定義模型
5. 編譯模型
6. 訓練模型
7. 評估模型
8. 使用訓練的模型進行預測
這看起來似乎需要很多步驟,但是我向您保證,一旦我們開始使用示例,您將看到示例是線性的、直觀的,并且將幫助您了解使用Keras訓練神經網絡的基礎知識。
實質上,使用MINST或者CIFARr10訓練集相當于只是調用了內置的函數,訓練、測試數據分組創建模型等都已預定義好, 當我們嘗試使用自己的數據集時,我們可能會抓耳撓腮考慮下邊幾個問題:
- 這些輔助函數從何處加載數據?
- 磁盤上的數據集應采用什么格式?
- 如何將數據集加載到內存中?
- 我需要執行哪些預處理步驟?
在此Keras教程中,我們將使用名為“動物數據集”的自定義數據集。
1. 此數據集的目的是將圖像正確分類: 貓 小狗 大熊貓
使用此自定義數據集可以使您了解:
1. 如何在磁盤上組織數據集
2. 如何從磁盤加載圖像和分類標簽
3. 如何將數據劃分為訓練和測試數據
4. 如何在訓練數據上訓練您的第一個Keras神經網絡
5. 如何根據測試數據評估模型
6. 如何在訓練和測試劃分之外的全新數據上復用訓練過的模型
按照本Keras教程中的步驟進行操作,只要您使用下面詳述的項目/目錄結構,就可以將“動物”數據集換成您選擇的任何數據集。
抓取數據集可參考:
- Bing Images
- Google Images
2. 項目結構
cats、dogs、panda文件夾下文件數至少1000個,并且相同。某個文件夾下文件多可能導致訓練出的模型有偏差;
3. 開始寫我們的代碼
(1)配置環境
-
ubuntu上 TensorFlow2.0安裝:
-
windows上 TensorFlow2.0安裝:
pip install tensorflow==2.0.0 # or tensorflow-gpu==2.0.0
(2)簡單神經網絡模型及卷積神經網絡模型
- train_simple_nn.py 第一個簡單神經網絡的模型
- train_vgg.py 更完整的SimpleVGGNet的卷積網絡模型
# train_simple_nn.py# 訓練第一個簡單的 Keras 模型# Python的必備繪圖包 我們指定matplotlib 使用“ Agg” 后使我們能夠將繪圖保存到磁盤
import matplotlibmatplotlib.use("Agg")# 導入必要的模塊包
# scikit-learn庫將幫助我們對標簽進行二值化處理,拆分數據以進行訓練/測試以及在終端生成訓練報告
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
# 您正在閱讀本教程以了解Keras,它是TensorFlow和其他深度學習后端的高級前端, 2017年Keras并入了TensorFlow
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.optimizers import SGD
# imutils 便利功能包 我們將使用paths 生成用于訓練的圖像文件路徑列表
from imutils import paths
import matplotlib.pyplot as plt
# numpy Python中進行數值處理的包 必備包之一
import numpy as np
# argparse 模塊是內置于Python中的模塊,將動態處理命令行提供的信息
import argparse
import random
import pickle
import cv2
import os# 1. 構建命令行參數
# --dataset 磁盤上圖像數據集的路徑
# --model 訓練得到的模型的輸出路徑
# --label-bin 序列化的二進制標簽文件的輸出路徑
# --plot 輸出訓練圖(精確度、損失)圖像文件的路徑,我們將通過該圖判斷模型擬合是否 過度/不足
ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset", required=True,help="path to input dataset of images")
ap.add_argument("-m", "--model", required=True,help="path to output trained model")
ap.add_argument("-l", "--label-bin", required=True,help="path to output label binarizer")
ap.add_argument("-p", "--plot", required=True,help="path to output accuracy/loss plot")
args = vars(ap.parse_args())# 2. 從磁盤加載數據
print("[INFO] loading images...")
# 初始化 數據和分類標簽列表
data = []
labels = []# 抓取imagePaths 并隨機洗牌(randomly shuffle)
# paths.list_images() 很方便的返回路徑中的所有圖片列表 播下種子因此隨機重排序是可重現的。
imagePaths = sorted(list(paths.list_images(args["dataset"])))
random.seed(42)
random.shuffle(imagePaths)# 循環遍歷所有的圖片
for imagePath in imagePaths:# 加載圖像,忽略寬高比縮放到 32*32 像素,展平數據為 32*32*3 = 3072 像素圖像, 并存儲到list中# resize數據是至關重要的,因為neural network需要這樣的維度,不同神經網絡需要不同的維度# 展平數據使我們可以輕松地將原始像素強度傳遞到輸入層神經元。稍后您會看到,對于VGGNet,我們將卷傳遞到網絡,因為它是卷積的。該示例只是一個簡單的非卷積網絡-我們將在后文中介紹一個更高級的示例image = cv2.imread(imagePath)image = cv2.resize(image, (32, 32)).flatten()data.append(image)# 從圖像路徑中提取分類標簽并存儲到分類標簽數組中label = imagePath.split(os.path.sep)[-2]labels.append(label)# 將像素強度的縮放范圍從[0,255]縮放到[0,1](常見的預處理步驟)。轉換array 為 NumPy數組
data = np.array(data, dtype="float") / 255.0
labels = np.array(labels)# 3. 構建訓練和測試數據分組
# 將數據劃分為75%的訓練數據和25%的測試數據
# 通常分配一定比例的數據用于訓練,而分配較小比例的數據用于測試。 scikit-learn提供了方便的train_test_split 函數為我們拆分數據
(trainX, testX, trainY, testY) = train_test_split(data,labels, test_size=0.25, random_state=42)# 我們的分類標簽當前以字符串表示; 但是,Keras會假定兩者都:標簽被編碼為整數 而且,對這些標簽執行單熱編碼,使每個標簽表示為矢量而不是整數
# 要完成此編碼,我們可以使用scikit-learn 中的LabelBinarizer
# 將標簽從 integer 轉換為 vector
# 初始化LabelBinaries 調用fit_transform zai trainY中找到所有唯一的類標簽并將他們轉換為單熱編碼的標簽
# testY 上執行單熱編碼
# 由于數組中只有一個是 1,因此成為單熱編碼
# [1, 0, 0] # corresponds to cats
# [0, 1, 0] # corresponds to dogs
# [0, 0, 1] # corresponds to panda
lb = LabelBinarizer()
trainY = lb.fit_transform(trainY)
testY = lb.transform(testY)# 4. 定義您的Keras模型架構
# 使用Keras定義我們的神經網絡架構。在這里,我們將使用一個具有一個輸入層,兩個隱藏層和一個輸出層的網絡:
# define the 3072-1024-512-3 architecture using Keras
# 32*32*3 = 3072 拼合的輸入圖像中的像素 第一個隱藏層由1024節點 第二個隱藏層有512節點 最終輸出層中的節點數將為可能的類標簽的數目-
# 在這種情況下,輸出層將具有三個節點,每個節點對應一個類標簽(“ cats”,“ dogs” ”和“ panda”)。
model = Sequential()
model.add(Dense(1024, input_shape=(3072,), activation="sigmoid"))
model.add(Dense(512, activation="sigmoid"))
model.add(Dense(len(lb.classes_), activation="softmax"))# 5. 編譯Keras模型
# 初始化學習速度和要訓練的時期總數
INIT_LR = 0.01
EPOCHS = 80
# 使用隨機梯度下降(SGD Stochastic Gradient Descent)優化器編譯模型,“categorical_crossentropy”作為損失函數
# 分類交叉熵(Categorical cross-entropy)被用作幾乎所有訓練執行分類的網絡的損失函數。
# 唯一的例外是2-class classification (2類分類 其中只有兩個可能的類標簽),在這種情況下,選擇“ binary_crossentropy”
print("[INFO] training network...")
opt = SGD(lr=INIT_LR)
model.compile(loss="categorical_crossentropy", optimizer=opt,metrics=["accuracy"])# 6. “擬合”Keras模型使其適合數據
# 訓練神經網絡
# batch_size 控制通過網絡傳遞的每組數據的大小。較大的GPU將能夠容納較大的批處理大小。建議從32或者64開始,然后逐步增加
H = model.fit(x=trainX, y=trainY, validation_data=(testX, testY),epochs=EPOCHS, batch_size=32)# 7. 評估Keras模型
# 我們已經訓練了實際模型,現在我們需要根據測試數據對其進行評估。
# 重要的是,我們必須對測試數據進行評估,以便我們能夠對模型進行從未被訓練過的數據進行無偏(或盡可能接近無偏)表示。
# 要評估我們的Keras模型,我們可以結合使用.predict 模型的方法以及scikit-learn 中的category_report :
print("[INFO] evaluating network...")
predictions = model.predict(x=testX, batch_size=32)
print(classification_report(testY.argmax(axis=1),predictions.argmax(axis=1), target_names=lb.classes_))
# plot the training loss and accuracy
N = np.arange(0, EPOCHS)
plt.style.use("ggplot")
plt.figure()
plt.plot(N, H.history["loss"], label="train_loss")
plt.plot(N, H.history["val_loss"], label="val_loss")
plt.plot(N, H.history["accuracy"], label="train_acc")
plt.plot(N, H.history["val_accuracy"], label="val_acc")
plt.title("Training Loss and Accuracy (Simple NN)")
plt.xlabel("Epoch #")
plt.ylabel("Loss/Accuracy")
plt.legend()
plt.savefig(args["plot"])# 8.保存模型和二進制標簽文件
print("[INFO] serializing network and label binarizer...")
model.save(args["model"], save_format="h5")
f = open(args["label_bin"], "wb")
f.write(pickle.dumps(lb))
f.close()
(3)第一個卷積神經網絡
train_vgg.py# 訓練第一個卷積神經網絡
# python train_vgg.py --dataset animals --model output/smallvggnet.model \
# --label-bin output/smallvggnet_lb.pickle \
# --plot output/smallvggnet_plot.png# 在Google相冊中,如果您在搜索框中輸入“ dog”,則將返回照片庫中的狗的圖片-我很確定該圖片搜索引擎功能已使用CNN。
# 圖像搜索引擎并不是CNN的唯一用例-我敢打賭,您的想法已經開始提出各種可應用于深度學習的想法。
#
# SmallVggnet 精確度76% 高于 之前的普通模型 60%# 設置matplotlib為Agg,因此圖像可以保存在磁盤上
import matplotlib
matplotlib.use("Agg")
# 導入必要的包
from pyimagesearch.smallvggnet import SmallVGGNet
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
# 我們將使用ImageDataGenerator擴充數據。我幾乎總是建議使用數據擴充,這樣會導致模型更好地推廣。
# 數據擴充涉及對現有訓練數據添加隨機旋轉,平移,剪切和縮放比例。
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.optimizers import SGD
from imutils import paths
import matplotlib.pyplot as plt
import numpy as np
import argparse
import random
import pickle
import cv2
import os# 構建命令行參數
ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset", required=True,help="path to input dataset of images")
ap.add_argument("-m", "--model", required=True,help="path to output trained model")
ap.add_argument("-l", "--label-bin", required=True,help="path to output label binarizer")
ap.add_argument("-p", "--plot", required=True,help="path to output accuracy/loss plot")
args = vars(ap.parse_args())# --dataset: 磁盤上圖像數據集的路徑
# --model: 我們的模型將序列化并輸出到磁盤。此參數包含輸出模型文件的路徑。確保對模型進行相應命名,以免覆蓋以前訓練過的模型(例如簡單的神經網絡模型)。
# --label-bin: 數據集標簽被序列化到磁盤的路徑
# --plot:輸出訓練圖圖像文件的路徑。我們將檢查該圖,以檢查數據是否過度/不足。每次通過更改參數來訓練模型時,都應在命令行中指定不同的繪圖文件名,以便在筆記本或注釋文件中擁有與訓練筆記相對應的繪圖歷史記錄。# 初始化數據和標簽類
print("[INFO] loading images...")
data = []
labels = []# 獲取圖像路徑并隨機洗牌(給定42的隨機種子,以重新結果)
imagePaths = sorted(list(paths.list_images(args["dataset"])))
random.seed(42)
random.shuffle(imagePaths)# 循環遍歷輸入圖像
for imagePath in imagePaths:# 加載圖像,resize到64*64(SmallVGGNet所需的輸入空間尺寸) 并存儲道list中image = cv2.imread(imagePath)image = cv2.resize(image, (64, 64))# 一個關鍵的區別是我們不會為神經網絡拼合數據,因為它是卷積的data.append(image)# 從圖像路徑中提取分類標簽并添加到list中label = imagePath.split(os.path.sep)[-2]labels.append(label)# scale 像素強度到 [0,1]
data = np.array(data, dtype="float") / 255.0
labels = np.array(labels)# 分組訓練數據(75%)和測試數據(25%)一個建議是80/20比例去看一下是否有明顯提高
(trainX, testX, trainY, testY) = train_test_split(data,labels, test_size=0.25, random_state=42)# 初始化類標簽器 將類標簽器從整數轉換為向量
# 標簽二值化這樣后續可以進行一鍵熱編碼,并在腳本的后面將標簽二值化器序列化為pickle文件
lb = LabelBinarizer()
trainY = lb.fit_transform(trainY)
testY = lb.transform(testY)# 構建圖像加強生成器
# 圖像增強使我們可以通過隨機旋轉,移動,剪切,縮放和翻轉從現有的訓練數據中構建“其他”訓練數據。
# 數據擴充通常是以下關鍵步驟:
# -避免過度擬合
# -確保模型能很好地泛化 我建議您始終執行數據增強,除非您有明確的理由不這樣做。
aug = ImageDataGenerator(rotation_range=30, width_shift_range=0.1,height_shift_range=0.1, shear_range=0.2, zoom_range=0.2,horizontal_flip=True, fill_mode="nearest")# 初始化 構建 VGG-like Convolutional Neural Network
model = SmallVGGNet.build(width=64, height=64, depth=3,classes=len(lb.classes_))# 初始化初始學習率,訓練次數,訓練批次
INIT_LR = 0.01
EPOCHS = 75
BS = 32# initialize the model and optimizer (you'll want to use
# binary_crossentropy for 2-class classification)
# 編譯模型
# 初始化模型及在二值分類中的二值交叉熵優化器
print("[INFO] training network...")
opt = SGD(lr=INIT_LR, decay=INIT_LR / EPOCHS)
model.compile(loss="categorical_crossentropy", optimizer=opt,metrics=["accuracy"])# 訓練網絡
# model.fit 可同時處理訓練和即時擴充的增強數據。
# 我們必須將訓練數據作為第一個參數傳遞給生成器。生成器將根據我們先前進行的設置生成批量的增強訓練數據。
H = model.fit(x=aug.flow(trainX, trainY, batch_size=BS),validation_data=(testX, testY), steps_per_epoch=len(trainX) // BS,epochs=EPOCHS)# 評估網絡模型
print("[INFO] evaluating network...")
predictions = model.predict(x=testX, batch_size=32)
print(classification_report(testY.argmax(axis=1),predictions.argmax(axis=1), target_names=lb.classes_))# 畫出訓練精確度和損失圖
N = np.arange(0, EPOCHS)
plt.style.use("ggplot")
plt.figure()
plt.plot(N, H.history["loss"], label="train_loss")
plt.plot(N, H.history["val_loss"], label="val_loss")
plt.plot(N, H.history["accuracy"], label="train_acc")
plt.plot(N, H.history["val_accuracy"], label="val_acc")
plt.title("Training Loss and Accuracy (SmallVGGNet)")
plt.xlabel("Epoch #")
plt.ylabel("Loss/Accuracy")
plt.legend()
plt.savefig(args["plot"])# 保存模型和類標簽器到磁盤
print("[INFO] serializing network and label binarizer...")
model.save(args["model"], save_format="h5")
f = open(args["label_bin"], "wb")
f.write(pickle.dumps(lb))
f.close()
(4)ImageDataGenerator
使用ImageDataGenerator擴充數據,是為了使模型更好地推廣,泛化
數據擴充涉及對現有訓練數據添加隨機旋轉,平移,剪切和縮放比例。
(5)SGD 隨機梯度下降損失函數
使用隨機梯度下降(SGD Stochastic Gradient Descent)優化器編譯模型,“categorical_crossentropy”作為損失函數
分類交叉熵(Categorical cross-entropy)被用作幾乎所有訓練執行分類的網絡的損失函數。
唯一的例外是2-class classification (2類分類 其中只有兩個可能的類標簽),在這種情況下,選擇“ binary_crossentropy”.
(6) 簡單的神經網絡 與 卷積神經網絡訓練結果對比
| 簡單神經網絡 | 卷積神經網絡 | |
|---|---|---|
| 訓練速度 | 快 3s/Epoch | 慢 50s/Step |
| 準確度 | 近60% | 75% |
| 泛化能力 | 弱 | 強 |
簡單的神經網絡訓練速度快,精確度稍低;
卷積神經網絡訓練速度慢,精確度高,由于數據集經過了數據增強具有比較好的泛化能力;
同樣的數據下的預測精確度:
簡單神經網絡預測結果:
卷積神經網絡預測結果:
簡單神經網絡訓練損失/精確度圖:
卷積神經網絡損失/精確度圖:
ps: 啃英文對我來說有點難,又有點簡單。這是我大學無比喜歡上的課,后來也會記單詞,英漢互譯的看詩集。這一篇文章確實有點難啃,有些學術名詞我不是很懂,不過我在努力,學習的感覺真的太好了。
晚安~~~
參考: https://www.pyimagesearch.com/2018/09/10/keras-tutorial-how-to-get-started-with-keras-deep-learning-and-python/
總結
以上是生活随笔為你收集整理的Keras TensorFlow教程:使用自己的数据集进行训练的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 停在那里是哪首歌啊?
- 下一篇: Keras ImageDataGener