Tensorflow 2.x 使用 MobileNetV2 微调模型优化训练花卉图像识别模型 (2024)

一、模型微调

https://blog.csdn.net/qq_43692950/article/details/128518757

深度学习模型应用于小型图像数据集场景下,一般由于数据量的局限性,导致模型提取特征有限,进而影响识别的准确度,一种常用且非常高效的优化方式便是使用预训练网络模型。将一个已在大型数据集(例如ImageNet)上训练好的模型作为基础模型。在此基础上对自己的数据集再进行训练,即使新的数据集和原始数据集完全不同的情况下也可以得到很好的特诊提取。

使用预训练网络有两种方法:特征提取(feature extraction)微调模型(fine-tuning)

  • 特征提取(feature extraction):使用预训练的优秀模型和权重来从新样本中提取特征,并移除原始的分类层,给到一个新的分类器,从头开始训练,之前的权重会随着反向传播进行修改。

  • 微调模型(fine-tuning):使用预训练的优秀模型和权重来从新样本中提取特征,并移除原始的分类层,最后同样给到一个新的分类器,但不同的是预训练模型的全部或某些层的权重被冻结,不会随着反向传播进行修改,只是略微调整了模型结构,这种方式不会破坏原始预训练模型的参数。

一般我们选取模型,都是基于ImageNet 上预训练过的用于图像分类的模型,在 keras 中可以在 keras.applications 下拿到各种网络模型结构,例如 VGG16、VGG19、Xception、ResNet、ResNetV2、 ResNeXt、InceptionV3、MobileNet、MobileNetV2、DenseNet 等。这些模型都是基于ImageNet 1000 分类的模型。

下面是 keras 中对各个模型的介绍:

https://keras.io/zh/applications/

其中各个模型在 ImageNet 上的Top1Top5 的准确率如下

模型大小Top-1 准确率Top-5 准确率参数数量深度
Xception88 MB0.7900.94522,910,480126
VGG16528 MB0.7130.901138,357,54423
VGG19549 MB0.7130.900143,667,24026
ResNet5098 MB0.7490.92125,636,712-
ResNet101171 MB0.7640.92844,707,176-
ResNet152232 MB0.7660.93160,419,944-
ResNet50V298 MB0.7600.93025,613,800-
ResNet101V2171 MB0.7720.93844,675,560-
ResNet152V2232 MB0.7800.94260,380,648-
ResNeXt5096 MB0.7770.93825,097,128-
ResNeXt101170 MB0.7870.94344,315,560-
InceptionV392 MB0.7790.93723,851,784159
InceptionResNetV2215 MB0.8030.95355,873,736572
MobileNet16 MB0.7040.8954,253,86488
MobileNetV214 MB0.7130.9013,538,98488
DenseNet12133 MB0.7500.9238,062,504121
DenseNet16957 MB0.7620.93214,307,880169
DenseNet20180 MB0.7730.93620,242,984 201
NASNetMobile23 MB0.7440.9195,326,716-
NASNetLarge343 MB0.8250.96088,949,818-

例如:查看 VGG16 模型的结构,其中如果权重文件不存在则会自动下载,其中里面的参数在第二点进行了说明:

from tensorflow import kerasmodel = keras.applications.VGG16(weights='imagenet', include_top=True)model.summary()

打印出下面内容,可以看出输入是 (224, 224, 3) 大小的三维图片,输出是一个 1000 分类的模型:

Model: "vgg16"_________________________________________________________________Layer (type) Output Shape Param # =================================================================input_1 (InputLayer) [(None, 224, 224, 3)] 0 _________________________________________________________________block1_conv1 (Conv2D) (None, 224, 224, 64) 1792 _________________________________________________________________block1_conv2 (Conv2D) (None, 224, 224, 64) 36928 _________________________________________________________________block1_pool (MaxPooling2D) (None, 112, 112, 64) 0 _________________________________________________________________block2_conv1 (Conv2D) (None, 112, 112, 128) 73856 _________________________________________________________________block2_conv2 (Conv2D) (None, 112, 112, 128) 147584 _________________________________________________________________block2_pool (MaxPooling2D) (None, 56, 56, 128) 0 _________________________________________________________________block3_conv1 (Conv2D) (None, 56, 56, 256) 295168 _________________________________________________________________block3_conv2 (Conv2D) (None, 56, 56, 256) 590080 _________________________________________________________________block3_conv3 (Conv2D) (None, 56, 56, 256) 590080 _________________________________________________________________block3_pool (MaxPooling2D) (None, 28, 28, 256) 0 _________________________________________________________________block4_conv1 (Conv2D) (None, 28, 28, 512) 1180160 _________________________________________________________________block4_conv2 (Conv2D) (None, 28, 28, 512) 2359808 _________________________________________________________________block4_conv3 (Conv2D) (None, 28, 28, 512) 2359808 _________________________________________________________________block4_pool (MaxPooling2D) (None, 14, 14, 512) 0 _________________________________________________________________block5_conv1 (Conv2D) (None, 14, 14, 512) 2359808 _________________________________________________________________block5_conv2 (Conv2D) (None, 14, 14, 512) 2359808 _________________________________________________________________block5_conv3 (Conv2D) (None, 14, 14, 512) 2359808 _________________________________________________________________block5_pool (MaxPooling2D) (None, 7, 7, 512) 0 _________________________________________________________________flatten (Flatten) (None, 25088) 0 _________________________________________________________________fc1 (Dense) (None, 4096) 102764544 _________________________________________________________________fc2 (Dense) (None, 4096) 16781312 _________________________________________________________________predictions (Dense) (None, 1000) 4097000 

使用 VGG16 预测图片分类,图片如下:

Tensorflow 2.x 使用 MobileNetV2 微调模型优化训练花卉图像识别模型 (1)

from tensorflow import kerasimport tensorflow as tfimport matplotlib.pyplot as pltfrom tensorflow.keras.preprocessing.image import img_to_arrayfrom tensorflow.keras.preprocessing.image import load_imgplt.rcParams['font.sans-serif'] = ['SimHei']model = keras.applications.VGG16(weights='imagenet', include_top=True)img_path = './img/dog.jpg'image = load_img(img_path, target_size=(224, 224))image = img_to_array(image)# 预测y_predictions = model.predict(tf.expand_dims(image, 0))# 解析标签y_lable = keras.applications.vgg16.decode_predictions(y_predictions)plt.imshow(image / 255.0)plt.title('预测结果:' y_lable[0][0][1] ',概率:' str("%.2f" % (y_lable[0][0][2] * 100)) '%')plt.show()

预测结果:

Tensorflow 2.x 使用 MobileNetV2 微调模型优化训练花卉图像识别模型 (2)

二、使用 MobileNetV2 微调模型优化训练花卉图像识别

这里对 MobileNetV2 模型去除最后的分类器层,其余卷积层权重均被冻结,在最后,再加上两层全连接层和一层分类层。

keras 中,applications 下的模型结构,如果想去除最后的全链接层,只需设置 include_top=False 即可,其中 weights 参数默认为 imagenet 表示使用 imagenet 上的权重,例如:

from tensorflow import kerasmodel = keras.applications.VGG16(weights='imagenet', include_top=False, input_shape=(224, 224, 3))model.summary()

运行后,对比第一点打印的结构,可以看出最后全链接层都被移除掉了:

Tensorflow 2.x 使用 MobileNetV2 微调模型优化训练花卉图像识别模型 (3)

同样在 keras 中冻结参数也非常容易,只需设置 Model.trainable = False 即可,例如:

mobienet = keras.applications.MobileNetV2(weights='imagenet', include_top=False, input_shape=(180, 180, 3)) # 冻结权重mobienet.trainable = False

下面开始基于 MobileNetV2 微调训练花卉数据集,整体模型如下所示:

Tensorflow 2.x 使用 MobileNetV2 微调模型优化训练花卉图像识别模型 (4)
下面使用 keras 构建模型结构:

import tensorflow as tffrom tensorflow import keras# 定义模型类class Model(): # 初始化结构 def __init__(self, checkpoint_path, log_path, model_path, num_classes, img_width, img_height): # checkpoint 权重保存地址 self.checkpoint_path = checkpoint_path # 训练日志保存地址 self.log_path = log_path # 训练模型保存地址: self.model_path = model_path # 数据统一大小并归一处理 resize_and_rescale = tf.keras.Sequential([ keras.layers.Resizing(img_width, img_height), keras.layers.Rescaling(1. / 255) ]) # 数据增强 data_augmentation = tf.keras.Sequential([ # 翻转 keras.layers.RandomFlip("horizontal_and_vertical"), # 旋转 keras.layers.RandomRotation(0.2), # 对比度 keras.layers.RandomContrast(0.3), # 随机裁剪 # tf.keras.layers.RandomCrop(IMG_SIZE, IMG_SIZE), # 随机缩放 keras.layers.RandomZoom(height_factor=0.3, width_factor=0.3), ]) # MobileNetV2 模型结构 mobienet = keras.applications.MobileNetV2(weights='imagenet', include_top=False, input_shape=(180, 180, 3)) # 冻结权重 mobienet.trainable = False # 初始化模型结构 self.model = keras.Sequential([ resize_and_rescale, data_augmentation, mobienet, keras.layers.Flatten(), keras.layers.Dense(1024, kernel_initializer=keras.initializers.truncated_normal(stddev=0.05), kernel_regularizer=keras.regularizers.l2(0.001), activation=tf.nn.relu), keras.layers.Dense(256, kernel_initializer=keras.initializers.truncated_normal(stddev=0.05), kernel_regularizer=keras.regularizers.l2(0.001), activation=tf.nn.relu), keras.layers.Dense(num_classes, activation='softmax') ]) # 编译模型 def compile(self): # 输出模型摘要 self.model.build(input_shape=(None, 180, 180, 3)) self.model.summary() # 定义训练模式 self.model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy']) # 训练模型 def train(self, train_ds, val_ds): # tensorboard 训练日志收集 tensorboard = keras.callbacks.TensorBoard(log_dir=self.log_path) # 训练过程保存 Checkpoint 权重,防止意外停止后可以继续训练 model_checkpoint = keras.callbacks.ModelCheckpoint(self.checkpoint_path, # 保存模型的路径 # monitor='val_loss', # 被监测的数据。 verbose=0, # 详细信息模式,0 或者 1 save_best_only=True, # 如果 True, 被监测数据的最佳模型就不会被覆盖 save_weights_only=True, # 如果 True,那么只有模型的权重会被保存 (model.save_weights(filepath)),否则的话,整个模型会被保存,(model.save(filepath)) mode='auto', # {auto, min, max}的其中之一。 如果 save_best_only=True,那么是否覆盖保存文件的决定就取决于被监测数据的最大或者最小值。 对于 val_acc,模式就会是 max,而对于 val_loss,模式就需要是 min,等等。 在 auto模式中,方向会自动从被监测的数据的名字中判断出来。 period=3 # 每3个epoch保存一次权重 ) # 填充数据,迭代训练 self.model.fit( train_ds, # 训练集 validation_data=val_ds, # 验证集 epochs=30, # 迭代周期 verbose=2, # 训练过程的日志信息显示,一个epoch输出一行记录 callbacks=[tensorboard, model_checkpoint] ) # 保存训练模型 self.model.save(self.model_path) def evaluate(self, val_ds): # 评估模型 test_loss, test_acc = self.model.evaluate(val_ds) return test_loss, test_acc

处理数据集,其中使用 80% 的图像进行训练,20% 的图像进行验证。:

import tensorflow as tfimport pathlibfrom tensorflow import kerasdef getData(): # 加载数据集 path = "F:/Tensorflow/datasets/flower/flower_photos" # 解析目录 data_dir = pathlib.Path(path) # keras 加载数据集 batch_size = 20 img_height = 180 img_width = 180 # 使用 80% 的图像进行训练,20% 的图像进行验证。 class_names = ['daisy', 'dandelion', 'roses', 'sunflowers', 'tulips'] train_ds = keras.utils.image_dataset_from_directory( data_dir, validation_split=0.2, subset="training", image_size=(img_height, img_width), batch_size=batch_size, shuffle=True, seed=123, interpolation='bilinear', crop_to_aspect_ratio=True, labels='inferred', class_names=class_names, color_mode='rgb' ) val_ds = keras.utils.image_dataset_from_directory( data_dir, validation_split=0.2, subset="validation", image_size=(img_height, img_width), batch_size=batch_size, shuffle=True, seed=123, interpolation='bilinear', crop_to_aspect_ratio=True, labels='inferred', class_names=class_names, color_mode='rgb' ) AUTOTUNE = tf.data.AUTOTUNE train_ds = train_ds.cache().prefetch(buffer_size=AUTOTUNE) val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE) return train_ds, val_ds, len(class_names), img_width, img_height

开始训练模型:

def main(): # 加载数据集 train_ds, val_ds, num_classes, img_width, img_height = getData() checkpoint_path = './checkout/' log_path = './log' model_path = './model/model.h5' # 构建模型 model = Model(checkpoint_path, log_path, model_path, num_classes, img_width, img_height) # 编译模型 model.compile() # 训练模型 model.train(train_ds, val_ds) # 评估模型 test_loss, test_acc = model.evaluate(val_ds) print(test_loss, test_acc)if __name__ == '__main__': main()

运行后可以看到打印的网络结构:

Tensorflow 2.x 使用 MobileNetV2 微调模型优化训练花卉图像识别模型 (5)

从训练日志中,可以看到 loss 一直在减小:

Tensorflow 2.x 使用 MobileNetV2 微调模型优化训练花卉图像识别模型 (6)

Tensorflow 2.x 使用 MobileNetV2 微调模型优化训练花卉图像识别模型 (7)
最后看下 tensorboard 中可视化的损失及准确率:

tensorboard --logdir=log/train

Tensorflow 2.x 使用 MobileNetV2 微调模型优化训练花卉图像识别模型 (8)
使用浏览器访问:http://localhost:6006/ 查看结果:

Tensorflow 2.x 使用 MobileNetV2 微调模型优化训练花卉图像识别模型 (9)

三、模型预测

训练后会在 model 下生成 model.h5 模型,下面直接加载该模型进行预测:

import tensorflow as tfimport pathlibfrom tensorflow import kerasimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['SimHei']def main(): # 加载数据集 path = "F:/Tensorflow/datasets/flower/flower_photos" # 解析目录 data_dir = pathlib.Path(path) # keras 加载数据集 batch_size = 32 img_height = 180 img_width = 180 class_names = ['daisy', 'dandelion', 'roses', 'sunflowers', 'tulips'] class_names_cn = ['雏菊', '蒲公英', '玫瑰', '向日葵', '郁金香'] val_ds = keras.utils.image_dataset_from_directory( data_dir, validation_split=0.2, subset="validation", image_size=(img_height, img_width), batch_size=batch_size, shuffle=True, seed=123, interpolation='bilinear', crop_to_aspect_ratio=True, labels='inferred', class_names=class_names, color_mode='rgb' ) model = keras.models.load_model('./model/model.h5') for image_batch, labels_batch in val_ds.take(3): plt.figure(figsize=(10, 10)) for i in range(9): plt.subplot(3, 3, i 1) softmax = model.predict(tf.expand_dims(image_batch[i], 0)) y_label = tf.argmax(softmax, axis=1).numpy()[0] plt.imshow(image_batch[i].numpy().astype("uint8")) plt.title('预测结果:' class_names_cn[y_label] ',概率:' str("%.2f" % softmax[0][y_label]) ',真实结果:' class_names_cn[labels_batch[i]]) plt.axis('off') plt.show()if __name__ == '__main__': main()

Tensorflow 2.x 使用 MobileNetV2 微调模型优化训练花卉图像识别模型 (10)
Tensorflow 2.x 使用 MobileNetV2 微调模型优化训练花卉图像识别模型 (11)
Tensorflow 2.x 使用 MobileNetV2 微调模型优化训练花卉图像识别模型 (12)

这篇好文章是转载于:学新通技术网

Tensorflow 2.x 使用 MobileNetV2 微调模型优化训练花卉图像识别模型 (2024)

References

Top Articles
Latest Posts
Article information

Author: Moshe Kshlerin

Last Updated:

Views: 6489

Rating: 4.7 / 5 (77 voted)

Reviews: 84% of readers found this page helpful

Author information

Name: Moshe Kshlerin

Birthday: 1994-01-25

Address: Suite 609 315 Lupita Unions, Ronnieburgh, MI 62697

Phone: +2424755286529

Job: District Education Designer

Hobby: Yoga, Gunsmithing, Singing, 3D printing, Nordic skating, Soapmaking, Juggling

Introduction: My name is Moshe Kshlerin, I am a gleaming, attractive, outstanding, pleasant, delightful, outstanding, famous person who loves writing and wants to share my knowledge and understanding with you.