第1部分介紹了問題陳述的設置、數(shù)據(jù)預處理、遷移學習背后的直覺、特征提取、微調(diào)和模型評估。
第2部分介紹Flask應用程序的實現(xiàn)及其在Heroku上的后續(xù)部署。為了保持連續(xù)性,請遵循教程。
介紹
在這樣的環(huán)境中工作十分幸運:
(a)數(shù)基礎設施和體系結(jié)構(gòu)隨時可用
(b)數(shù)據(jù)由分析師處理
(c)MLOP由單獨的數(shù)據(jù)工程師部門處理。
決定實施一個端到端的DL項目,該項目將由三部分組成:
第1部分:設置(虛擬環(huán)境、訓練數(shù)據(jù)集等)、模型訓練(使用Keras微調(diào)、學習曲線監(jiān)控等)、測試。
第2部分:在Heroku上構(gòu)建Flask應用程序和部署。
本系列分為兩部分,旨在為你提供源代碼、提示以及在使用深度學習模型時常見的運行時錯誤。
相信,這些信息會派上用場。
Headsup:本文(以及隨后的文章)中的一些內(nèi)容將進行極其詳細的討論,因為其目的是讓人們(尤其是早期研究人員)理解一些設計決策背后的原因/優(yōu)點/缺點。
第1部分:設置
虛擬環(huán)境使用終端,在項目目錄中創(chuàng)建一個名為e2eproject的虛擬環(huán)境,并將其激活
python3 -m venv e2eproject
source e2eproject/bin/activate
數(shù)據(jù)集
我們將使用Kaggle提供的公開房屋房間數(shù)據(jù)集。
你可以手動下載它,然后將其移動到項目目錄中,或者使用終端中的以下命令將其直接下載到項目目錄中。
注意:在運行以下命令之前,請確保你在項目目錄中。
kaggle datasets download -d robinreni/house-rooms-image-dataset — unzip
任務
我們將進行一項圖像分類任務。特別是,我們將開發(fā)一個模型,根據(jù)臥室的圖像,檢測房子內(nèi)部是現(xiàn)代的(M類)還是舊的(O類)。
這種模型可能會在再抵押期間或出售房產(chǎn)時對房產(chǎn)估價有用。
正如你可能已經(jīng)注意到的,數(shù)據(jù)集是未標記的,然而,慷慨地提出要手動標記約450張圖像。(這些標簽已在Github倉庫中提供。)雖然這不是一個很大的數(shù)據(jù)集大小,但我們?nèi)匀荒軌蛟谝粋€測試集上實現(xiàn)幾乎80%的準確率。此外,我們將討論微調(diào)、改進模型度量等的適當技術(shù),以確定是否值得花費更多時間標記額外的數(shù)據(jù)點。
第二部分:模型訓練
讓我們創(chuàng)建一個model.ipynb筆記本。
安裝
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.a(chǎn)pplications import EfficientNetB0
from tensorflow.keras.callbacks import EarlyStopping
from tensorflow.keras.callbacks import ModelCheckpoint
from tensorflow.keras.layers import BatchNormalization
from tensorflow.keras.layers import Dropout
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Input
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.models import Model
from sklearn.metrics import classification_report, confusion_matrix
from sklearn.model_selection import train_test_split
from imutils import paths
from tqdm import tqdm
import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
import seaborn as sns
import numpy as np
import shutil
import os
注意:你可能需要進行一些pip install XXX才能使上述代碼正常工作。
輔助變量和函數(shù)
ORIG_INPUT_DATASET = "House_Room_Dataset/Bedroom"
TRAIN = "training"
VAL = evaluation"
TEST = "testing"
base_PATH = "dataset"
BATCH_SIZE = 32
CLASSES = ["Modern", "Old"]
我們將只處理臥室圖像,因此ORIG_INPUT_DATASET指向臥室子目錄。
base_PATH是指向我們將在其中存儲圖像的訓練、測試和驗證拆分的目錄的路徑。
def plot_hist(hist, metric):
if metric == 'auc':
plt.plot(hist.history["auc"])
plt.plot(hist.history["val_auc"])
else:
plt.plot(hist.history["loss"])
plt.plot(hist.history["val_loss"])
plt.style.use("ggplot")
plt.title("model {}".format(metric))
plt.ylabel("{}".format(metric))
plt.xlabel("epoch")
plt.legend(["train", "validation"], loc="upper left")
plt.show()
這是用于繪制兩種類型的學習曲線——AUC與epoch、損失與epoch的代碼。
注意:如果你使用的是auc以外的度量,比如準確率,請確保在上面的代碼片段中使用準確率替換auc和使用準確率替換val_auc。
加載標簽
(labels.txt已作為倉庫的一部分提供。)
# Reading labels from the txt file
with open("labels.txt", 'r') as f:
manual_labels = f.read()
# Extracting individual labels into a list
labels = [i for i in manual_labels]
len(labels)
********* OUTPUT **********
451
要檢查數(shù)據(jù)集是否平衡,請執(zhí)行以下操作:
from collections import Counter
print(Counter(labels).keys())
print(Counter(labels).values())
********* OUTPUT **********
dict_keys(['O', 'M'])
dict_values([271, 180])
在我們的數(shù)據(jù)集中,與現(xiàn)代房屋相比,我們有更多的老房子(盡管差距不是很大)。
因此,拋棄準確率,選擇一個更適合處理類別不平衡的指標,即AUC(ROC曲線下的面積)是有意義的。
訓練測試驗證拆分
在進行拆分之前,對文件名進行排序很重要,因為我們有前451個圖像的標簽(在House_Room_Dataset/Bedroom中),而不僅僅是任何隨機的451個圖像。
默認情況下,os.listdir()以隨機順序返回文件,我們不應該依賴它。
# sorting files in the order they appear
files = os.listdir(ORIG_INPUT_DATASET)
files.sort(key=lambda f: int(f.split('_')[1].split('.')[0]))
# checking to see the correct file order
files[:5]
********* OUTPUT **********
['bed_1.jpg', 'bed_2.jpg', 'bed_3.jpg', 'bed_4.jpg', 'bed_8.jpg']
現(xiàn)在我們知道了正確的451張圖片,讓我們繼續(xù)進行訓練測試證拆分。我們將分別分配約75%、15%和10%的數(shù)據(jù)用于訓練、驗證和測試。
# splitting files into train and test sets
trainX, testX, trainY, testY = train_test_split(files[:len(labels)],
labels,
stratify=labels,
train_size=0.90)
# further splitting of train set into train and val sets
trainX, valX, trainY, valY = train_test_split(trainX, trainY, stratify=trainY, train_size=0.85)
# Checking the size of train, test, eval
len(trainX), len(trainY), len(valX), len(valY), len(testX), len(testY)
********* OUTPUT **********
(344, 344, 61, 61, 46, 46)
使用Sklearn的train_test_split方法,我們首先將整個數(shù)據(jù)集拆分為train和test集,然后再將train數(shù)據(jù)拆分為訓練集和驗證集。
按標簽進行分層很重要,因為我們希望在所有三組(訓練、測試和驗證)中,現(xiàn)代房屋和舊房屋都按比例分布。