第1部分介绍了问题陈述的设置、数据预处理、迁移学习背后的直觉、特征提取、微调和模型评估。
第2部分介绍Flask应用程序的实现及其在Heroku上的后续部署。为了保持连续性,请遵循教程。
介绍
在这样的环境中工作十分幸运:
(a)数基础设施和体系结构随时可用
(b)数据由分析师处理
(c)MLOP由单独的数据工程师部门处理。
决定实施一个端到端的DL项目,该项目将由三部分组成:
第1部分:设置(虚拟环境、训练数据集等)、模型训练(使用Keras微调、学习曲线监控等)、测试。
第2部分:在Heroku上构建Flask应用程序和部署。
本系列分为两部分,旨在为你提供源代码、提示以及在使用深度学习模型时常见的运行时错误。
相信,这些信息会派上用场。
Headsup:本文(以及随后的文章)中的一些内容将进行极其详细的讨论,因为其目的是让人们(尤其是早期研究人员)理解一些设计决策背后的原因/优点/缺点。
第1部分:设置
虚拟环境使用终端,在项目目录中创建一个名为e2eproject的虚拟环境,并将其激活
python3 -m venv e2eproject
source e2eproject/bin/activate
数据集
我们将使用Kaggle提供的公开房屋房间数据集。
你可以手动下载它,然后将其移动到项目目录中,或者使用终端中的以下命令将其直接下载到项目目录中。
注意:在运行以下命令之前,请确保你在项目目录中。
kaggle datasets download -d robinreni/house-rooms-image-dataset — unzip
任务
我们将进行一项图像分类任务。特别是,我们将开发一个模型,根据卧室的图像,检测房子内部是现代的(M类)还是旧的(O类)。
这种模型可能会在再抵押期间或出售房产时对房产估价有用。
正如你可能已经注意到的,数据集是未标记的,然而,慷慨地提出要手动标记约450张图像。(这些标签已在Github仓库中提供。)虽然这不是一个很大的数据集大小,但我们仍然能够在一个测试集上实现几乎80%的准确率。此外,我们将讨论微调、改进模型度量等的适当技术,以确定是否值得花费更多时间标记额外的数据点。
第二部分:模型训练
让我们创建一个model.ipynb笔记本。
安装
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.applications 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才能使上述代码正常工作。
辅助变量和函数
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
要检查数据集是否平衡,请执行以下操作:
from collections import Counter
print(Counter(labels).keys())
print(Counter(labels).values())
********* OUTPUT **********
dict_keys(['O', 'M'])
dict_values([271, 180])
在我们的数据集中,与现代房屋相比,我们有更多的老房子(尽管差距不是很大)。
因此,抛弃准确率,选择一个更适合处理类别不平衡的指标,即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']
现在我们知道了正确的451张图片,让我们继续进行训练测试证拆分。我们将分别分配约75%、15%和10%的数据用于训练、验证和测试。
# 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方法,我们首先将整个数据集拆分为train和test集,然后再将train数据拆分为训练集和验证集。
按标签进行分层很重要,因为我们希望在所有三组(训练、测试和验证)中,现代房屋和旧房屋都按比例分布。