Tensorflow使用MobileNetV2进行迁移学习,预测是否带口罩

口罩数据下载地址,https://storage.googleapis.com/kaggle-data-sets/1057064/1777920/bundle/archive.zip?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=gcp-kaggle-com%40kaggle-161607.iam.gserviceaccount.com%2F20240417%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20240417T061608Z&X-Goog-Expires=259200&X-Goog-SignedHeaders=host&X-Goog-Signature=57dfd13a0ca16ccf6ef81b193cb68fa784aa20509f4d6eee602b5ff6f83608fbadc1384e3ef67180a90823fe93b09fcfc29fbe0c005e4e511c40996c96cee05bcbabbcfbd51fbb08644eccbf6cb06274450477f8624b26d897848dd80885f788f32f9430000e316ec9b01d84ebd40edbda4a8a20c5f46abbcb1ae75b9525af56806bb23cb4482bde8888cfbe6d889e5bb971f053141187d8ca102812efdc08d8a76ea995f4d66cfd0076a430f250991e2179053adefda493473718d80980079a602c671805f8ee365565d00b300846eb86fea793e196531e489c09ed1247f36f32132cb4be005247848d8a4fdc6aee6aacc15e6822108651baedf8cadd3de183

本例使用Tensorflow Model Zoo中的MobileNetV2进行迁移学习,预测人是否带了面罩。
完整的jupyter notebook地址如下,
simple_learn/deep_learning/18_training_neural_network_with_keras/18. Training Neural Network with Keras.ipynb · master · zhuge20100104 / cpp_practice · GitLab

代码如下,

# 各种import
# imutils是openCV的一部分,需要安装openCV-python

from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.applications import MobileNetV2
from tensorflow.keras.layers import AveragePooling2D
from tensorflow.keras.layers import Dropout
from tensorflow.keras.layers import Flatten
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Input
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.applications.mobilenet_v2 import preprocess_input
from tensorflow.keras.preprocessing.image import img_to_array
from tensorflow.keras.preprocessing.image import load_img
from tensorflow.keras.utils import to_categorical
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelBinarizer
from sklearn.metrics import classification_report
import matplotlib.pyplot as plt
import numpy as np
import os
# from imutils import paths

# 超参数
# 这里只搞两个epochs的原因,jupyter默认只用一个核,比较慢。所以训练两个epoch玩一下,实际上 20个epochs效果比较好
INIT_LR = 1e-4
EPOCHES = 2
BS = 32
DIRECTORY = 'dataset'

# 读入图片和label数据,label默认是目录名,待会还要转换
data = []
labels = []

# preprocess_input 函数的主要作用是对输入图像进行预处理,以便将其输入到 MobileNetV2 模型中进行推断或训练。具体来说,这个函数会执行以下操作:

# 归一化:将图像的像素值从 [0, 255] 范围归一化到 [-1, 1] 范围。这是神经网络模型通常需要的输入格式,因为它有助于模型训练的稳定性和收敛速度。
# 颜色通道调整:对于 MobileNetV2,preprocess_input 还会将图像的颜色通道从 RGB 格式转换为 BGR 格式(即蓝色、绿色和红色通道的顺序会被调换)。
# 这是因为 MobileNetV2 和其他一些模型是在这种颜色空间下训练的。

for category in os.listdir(DIRECTORY):
    path_ = os.path.join(DIRECTORY, category)
    for img in os.listdir(path_):
        img_path = os.path.join(path_, img)
        image = load_img(img_path, target_size=(224, 224))
        image = img_to_array(image)
        image = preprocess_input(image)
        data.append(image)
        labels.append(category)

print(labels[:10])

# 预处理数据,转换labels成 onehot encoding
lb = LabelBinarizer()
labels = lb.fit_transform(labels)
labels = to_categorical(labels)

data = np.array(data, dtype='float32')
labels = np.array(labels)

labels[:-10]

# 分割训练集和测试集
# stratify参数含义
# 在train_test_split函数中,stratify参数用于确保训练集和测试集中的类别比例与原始数据集中的类别比例相同。
# 这在处理不平衡数据集时特别有用,因为它有助于确保模型在训练时能够接触到所有类别的样本,并在测试时能够公平地评估模型对所有类别的性能。
# 具体来说,当您使用stratify参数时,您需要提供一个与输入数据相对应的标签数组或列表。
#train_test_split函数将根据这些标签的类别分布来划分数据,确保训练集和测试集中的类别比例与原始数据集中的比例一致

(trainX, testX, trainY, testY) = train_test_split(data, labels, test_size=0.2, stratify=labels, random_state=42)

# 图像增强
aug = ImageDataGenerator(
    rotation_range=20,
    zoom_range=0.15,
    width_shift_range=0.2,
    height_shift_range=0.2,
    shear_range=0.15,
    horizontal_flip=True,
    fill_mode='nearest'
)

# Load the MobileNetV2 network, ensuring the head FC layer sets are left off
# include_top=False, 把最后一个avg_pool和Dense全连接层去掉了

baseModel = MobileNetV2(weights='imagenet', include_top=False, input_tensor=Input(shape=(224, 224, 3)))

baseModel.summary()

# Construct the head of the model that will be placed on top of the base model
headModel = baseModel.output
headModel = AveragePooling2D(pool_size=(7, 7))(headModel)
headModel = Flatten(name='flatten')(headModel)
headModel = Dense(128, activation='relu')(headModel)
headModel = Dropout(0.5)(headModel)
headModel = Dense(2, activation='softmax')(headModel)

# Place the head FC model on top of the baseModel, 
# This will become the actual model we will train
model = Model(inputs=baseModel.input, outputs=headModel)

# 不更新basemodel的权重,网络太大了,更新起来比较耗算力
# loop over all layers in the base model and freezed them so they will not be 
# updated during the first training process
for layer in baseModel.layers:
    layer.trainable = False

# 编译模型
# Compile our model
print('[INFO] compiling model...')
opt = Adam(learning_rate=INIT_LR, decay=INIT_LR/EPOCHES)
model.compile(loss='binary_crossentropy', optimizer=opt, metrics=['accuracy'])

# fit 模型,包括增强后的图像数据
# train accuracy 和 validation accuray的值一样 或者类似的时候,比较好,说明bias比较正常,
# 如果 validation accuracy 比 train accuracy要高, 说明bias较大,出问题了

# Train the head of the network
print('[INFO] training head...')
history = model.fit(
    aug.flow(trainX, trainY, batch_size=BS),
    steps_per_epoch=len(trainX) // BS,
    validation_data=(testX, testY),
    validation_steps=len(testX) // BS,
    epochs=EPOCHES
)


# make predictions on the testing set
print('[INFO] evaluating network...')
predIdxs = model.predict(testX, batch_size=BS) 

# 打印classification_report
predIdxs = np.argmax(predIdxs, axis=1)
print(classification_report(testY.argmax(axis=1), predIdxs, target_names=lb.classes_))

# 保存模型到硬盘
print('[INFO] saving mask detector model...')
model.save('mask_detector.keras')

# train和validation的accuracy
# train和validation的loss
# 走到一块叫converge[收敛]

# 显示训练集和验证集的acc和loss曲线
acc = history.history["accuracy"]
val_acc = history.history["val_accuracy"]
loss = history.history["loss"]
val_loss = history.history["val_loss"]

plt.subplot(1, 2, 1)
plt.plot(acc, label='Training Accuracy')
plt.plot(val_acc, label='Validation Accuracy')
plt.title('Training and Validation Accuracy')
plt.legend()

plt.subplot(1, 2, 2)
plt.plot(loss, label='Training Loss')
plt.plot(val_loss, label='Validation Loss')
plt.title('Training and Validation Loss')
plt.legend()

程序输出的结果如下,


image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容