基于MobileNetV2的石头剪刀布图像分类迁移学习实现99%验证准确率在计算机视觉任务中从头训练一个卷积神经网络往往需要大量数据和计算资源。本文将展示如何利用迁移学习技术通过微调预训练的MobileNetV2模型在石头剪刀布Rock-Paper-Scissors小数据集上实现99%以上的验证准确率。1. 环境准备与数据加载首先确保已安装必要的Python库!pip install tensorflow tensorflow-datasets matplotlib石头剪刀布数据集包含2520张训练图像和372张测试图像每类石头、剪刀、布样本数量均衡。我们可以直接从Google存储桶下载import tensorflow as tf import tensorflow_datasets as tfds import matplotlib.pyplot as plt # 加载数据集 (ds_train, ds_test), ds_info tfds.load( rock_paper_scissors, split[train, test], shuffle_filesTrue, as_supervisedTrue, with_infoTrue ) # 查看数据集信息 print(f训练集样本数: {ds_info.splits[train].num_examples}) print(f测试集样本数: {ds_info.splits[test].num_examples}) print(f类别数: {ds_info.features[label].num_classes})数据增强是防止小数据集过拟合的关键技术。我们定义以下增强管道def preprocess(image, label): # 统一图像尺寸为224x224MobileNetV2的默认输入尺寸 image tf.image.resize(image, [224, 224]) # 归一化到[-1,1]范围 image (image / 127.5) - 1 return image, label def augment(image, label): # 随机水平翻转 image tf.image.random_flip_left_right(image) # 随机旋转-15°到15° image tf.image.rot90(image, ktf.random.uniform(shape[], minval0, maxval4, dtypetf.int32)) # 随机亮度调整 image tf.image.random_brightness(image, max_delta0.2) return preprocess(image, label) # 应用数据增强到训练集 ds_train ds_train.map(augment, num_parallel_callstf.data.AUTOTUNE) ds_train ds_train.shuffle(1024).batch(32).prefetch(tf.data.AUTOTUNE) # 测试集只做预处理不做增强 ds_test ds_test.map(preprocess, num_parallel_callstf.data.AUTOTUNE) ds_test ds_test.batch(32).prefetch(tf.data.AUTOTUNE)2. MobileNetV2基础模型加载MobileNetV2是一个轻量级的深度卷积网络特别适合移动端和嵌入式设备。我们加载在ImageNet上预训练的权重base_model tf.keras.applications.MobileNetV2( input_shape(224, 224, 3), include_topFalse, weightsimagenet, poolingavg # 使用全局平均池化替代Flatten ) # 冻结基础模型的所有层 base_model.trainable False # 添加自定义分类头 model tf.keras.Sequential([ base_model, tf.keras.layers.Dropout(0.5), # 添加Dropout防止过拟合 tf.keras.layers.Dense(3, activationsoftmax) ]) model.compile( optimizertf.keras.optimizers.Adam(learning_rate0.001), losssparse_categorical_crossentropy, metrics[accuracy] ) model.summary()模型结构关键点输入尺寸224x224x3基础模型参数量1.4M全部冻结可训练参数量6K仅分类头3. 初始训练阶段我们先训练模型的顶层分类头同时保持基础模型冻结initial_epochs 10 history model.fit( ds_train, validation_datads_test, epochsinitial_epochs ) # 绘制训练曲线 def plot_learning_curves(history): plt.figure(figsize(12, 4)) plt.subplot(1, 2, 1) plt.plot(history.history[accuracy], labelTraining Accuracy) plt.plot(history.history[val_accuracy], labelValidation Accuracy) plt.title(Accuracy over Time) plt.legend() plt.subplot(1, 2, 2) plt.plot(history.history[loss], labelTraining Loss) plt.plot(history.history[val_loss], labelValidation Loss) plt.title(Loss over Time) plt.legend() plt.show() plot_learning_curves(history)典型结果训练准确率~98%验证准确率~95%4. 微调阶段解冻部分层为了进一步提升性能我们解冻基础模型的部分顶层并进行微调# 解冻基础模型的后20层 base_model.trainable True fine_tune_at len(base_model.layers) - 20 for layer in base_model.layers[:fine_tune_at]: layer.trainable False # 使用更小的学习率 model.compile( optimizertf.keras.optimizers.Adam(learning_rate0.0001), losssparse_categorical_crossentropy, metrics[accuracy] ) # 继续训练 fine_tune_epochs 10 total_epochs initial_epochs fine_tune_epochs history_fine model.fit( ds_train, initial_epochhistory.epoch[-1], epochstotal_epochs, validation_datads_test ) # 合并训练历史并绘制 acc history.history[accuracy] history_fine.history[accuracy] val_acc history.history[val_accuracy] history_fine.history[val_accuracy] loss history.history[loss] history_fine.history[loss] val_loss history.history[val_loss] history_fine.history[val_loss] plt.figure(figsize(12, 4)) plt.subplot(1, 2, 1) plt.plot(acc, labelTraining Accuracy) plt.plot(val_acc, labelValidation Accuracy) plt.axvline(len(history.history[accuracy]), linestyle--, colorgray) plt.title(Accuracy over Time) plt.legend() plt.subplot(1, 2, 2) plt.plot(loss, labelTraining Loss) plt.plot(val_loss, labelValidation Loss) plt.axvline(len(history.history[loss]), linestyle--, colorgray) plt.title(Loss over Time) plt.legend() plt.show()微调后典型结果训练准确率~99.5%验证准确率~99%5. 模型评估与部署最后评估模型性能并保存# 在测试集上评估 test_loss, test_acc model.evaluate(ds_test) print(f\n测试准确率: {test_acc:.2%}) # 保存模型 model.save(rps_mobilenetv2.h5) # 转换为TensorFlow Lite格式用于移动设备 converter tf.lite.TFLiteConverter.from_keras_model(model) tflite_model converter.convert() with open(rps_mobilenetv2.tflite, wb) as f: f.write(tflite_model)混淆矩阵分析可以帮助我们了解模型在不同类别上的表现import numpy as np from sklearn.metrics import confusion_matrix import seaborn as sns # 收集测试集所有预测 y_true [] y_pred [] for images, labels in ds_test.unbatch(): y_true.append(labels.numpy()) y_pred.append(np.argmax(model.predict(tf.expand_dims(images, axis0)))) # 计算混淆矩阵 cm confusion_matrix(y_true, y_pred) class_names [石头, 布, 剪刀] plt.figure(figsize(6, 6)) sns.heatmap(cm, annotTrue, fmtd, cmapBlues, xticklabelsclass_names, yticklabelsclass_names) plt.xlabel(预测标签) plt.ylabel(真实标签) plt.title(混淆矩阵) plt.show()常见优化技巧尝试不同的解冻层数通常解冻最后10-30层使用学习率衰减策略增加数据增强的多样性尝试不同的优化器如RMSprop在实际部署中可以使用以下代码进行单张图像预测def predict_image(image_path): img tf.keras.preprocessing.image.load_img(image_path, target_size(224, 224)) img_array tf.keras.preprocessing.image.img_to_array(img) img_array (img_array / 127.5) - 1 # 与训练相同的归一化 img_array tf.expand_dims(img_array, 0) # 添加批次维度 predictions model.predict(img_array) score tf.nn.softmax(predictions[0]) class_names [石头, 布, 剪刀] print( 这张图像最可能是 {}置信度 {:.2f}% .format(class_names[np.argmax(score)], 100 * np.max(score)) )
石头剪刀布数据集迁移学习:MobileNetV2 微调实现 99% 验证准确率
基于MobileNetV2的石头剪刀布图像分类迁移学习实现99%验证准确率在计算机视觉任务中从头训练一个卷积神经网络往往需要大量数据和计算资源。本文将展示如何利用迁移学习技术通过微调预训练的MobileNetV2模型在石头剪刀布Rock-Paper-Scissors小数据集上实现99%以上的验证准确率。1. 环境准备与数据加载首先确保已安装必要的Python库!pip install tensorflow tensorflow-datasets matplotlib石头剪刀布数据集包含2520张训练图像和372张测试图像每类石头、剪刀、布样本数量均衡。我们可以直接从Google存储桶下载import tensorflow as tf import tensorflow_datasets as tfds import matplotlib.pyplot as plt # 加载数据集 (ds_train, ds_test), ds_info tfds.load( rock_paper_scissors, split[train, test], shuffle_filesTrue, as_supervisedTrue, with_infoTrue ) # 查看数据集信息 print(f训练集样本数: {ds_info.splits[train].num_examples}) print(f测试集样本数: {ds_info.splits[test].num_examples}) print(f类别数: {ds_info.features[label].num_classes})数据增强是防止小数据集过拟合的关键技术。我们定义以下增强管道def preprocess(image, label): # 统一图像尺寸为224x224MobileNetV2的默认输入尺寸 image tf.image.resize(image, [224, 224]) # 归一化到[-1,1]范围 image (image / 127.5) - 1 return image, label def augment(image, label): # 随机水平翻转 image tf.image.random_flip_left_right(image) # 随机旋转-15°到15° image tf.image.rot90(image, ktf.random.uniform(shape[], minval0, maxval4, dtypetf.int32)) # 随机亮度调整 image tf.image.random_brightness(image, max_delta0.2) return preprocess(image, label) # 应用数据增强到训练集 ds_train ds_train.map(augment, num_parallel_callstf.data.AUTOTUNE) ds_train ds_train.shuffle(1024).batch(32).prefetch(tf.data.AUTOTUNE) # 测试集只做预处理不做增强 ds_test ds_test.map(preprocess, num_parallel_callstf.data.AUTOTUNE) ds_test ds_test.batch(32).prefetch(tf.data.AUTOTUNE)2. MobileNetV2基础模型加载MobileNetV2是一个轻量级的深度卷积网络特别适合移动端和嵌入式设备。我们加载在ImageNet上预训练的权重base_model tf.keras.applications.MobileNetV2( input_shape(224, 224, 3), include_topFalse, weightsimagenet, poolingavg # 使用全局平均池化替代Flatten ) # 冻结基础模型的所有层 base_model.trainable False # 添加自定义分类头 model tf.keras.Sequential([ base_model, tf.keras.layers.Dropout(0.5), # 添加Dropout防止过拟合 tf.keras.layers.Dense(3, activationsoftmax) ]) model.compile( optimizertf.keras.optimizers.Adam(learning_rate0.001), losssparse_categorical_crossentropy, metrics[accuracy] ) model.summary()模型结构关键点输入尺寸224x224x3基础模型参数量1.4M全部冻结可训练参数量6K仅分类头3. 初始训练阶段我们先训练模型的顶层分类头同时保持基础模型冻结initial_epochs 10 history model.fit( ds_train, validation_datads_test, epochsinitial_epochs ) # 绘制训练曲线 def plot_learning_curves(history): plt.figure(figsize(12, 4)) plt.subplot(1, 2, 1) plt.plot(history.history[accuracy], labelTraining Accuracy) plt.plot(history.history[val_accuracy], labelValidation Accuracy) plt.title(Accuracy over Time) plt.legend() plt.subplot(1, 2, 2) plt.plot(history.history[loss], labelTraining Loss) plt.plot(history.history[val_loss], labelValidation Loss) plt.title(Loss over Time) plt.legend() plt.show() plot_learning_curves(history)典型结果训练准确率~98%验证准确率~95%4. 微调阶段解冻部分层为了进一步提升性能我们解冻基础模型的部分顶层并进行微调# 解冻基础模型的后20层 base_model.trainable True fine_tune_at len(base_model.layers) - 20 for layer in base_model.layers[:fine_tune_at]: layer.trainable False # 使用更小的学习率 model.compile( optimizertf.keras.optimizers.Adam(learning_rate0.0001), losssparse_categorical_crossentropy, metrics[accuracy] ) # 继续训练 fine_tune_epochs 10 total_epochs initial_epochs fine_tune_epochs history_fine model.fit( ds_train, initial_epochhistory.epoch[-1], epochstotal_epochs, validation_datads_test ) # 合并训练历史并绘制 acc history.history[accuracy] history_fine.history[accuracy] val_acc history.history[val_accuracy] history_fine.history[val_accuracy] loss history.history[loss] history_fine.history[loss] val_loss history.history[val_loss] history_fine.history[val_loss] plt.figure(figsize(12, 4)) plt.subplot(1, 2, 1) plt.plot(acc, labelTraining Accuracy) plt.plot(val_acc, labelValidation Accuracy) plt.axvline(len(history.history[accuracy]), linestyle--, colorgray) plt.title(Accuracy over Time) plt.legend() plt.subplot(1, 2, 2) plt.plot(loss, labelTraining Loss) plt.plot(val_loss, labelValidation Loss) plt.axvline(len(history.history[loss]), linestyle--, colorgray) plt.title(Loss over Time) plt.legend() plt.show()微调后典型结果训练准确率~99.5%验证准确率~99%5. 模型评估与部署最后评估模型性能并保存# 在测试集上评估 test_loss, test_acc model.evaluate(ds_test) print(f\n测试准确率: {test_acc:.2%}) # 保存模型 model.save(rps_mobilenetv2.h5) # 转换为TensorFlow Lite格式用于移动设备 converter tf.lite.TFLiteConverter.from_keras_model(model) tflite_model converter.convert() with open(rps_mobilenetv2.tflite, wb) as f: f.write(tflite_model)混淆矩阵分析可以帮助我们了解模型在不同类别上的表现import numpy as np from sklearn.metrics import confusion_matrix import seaborn as sns # 收集测试集所有预测 y_true [] y_pred [] for images, labels in ds_test.unbatch(): y_true.append(labels.numpy()) y_pred.append(np.argmax(model.predict(tf.expand_dims(images, axis0)))) # 计算混淆矩阵 cm confusion_matrix(y_true, y_pred) class_names [石头, 布, 剪刀] plt.figure(figsize(6, 6)) sns.heatmap(cm, annotTrue, fmtd, cmapBlues, xticklabelsclass_names, yticklabelsclass_names) plt.xlabel(预测标签) plt.ylabel(真实标签) plt.title(混淆矩阵) plt.show()常见优化技巧尝试不同的解冻层数通常解冻最后10-30层使用学习率衰减策略增加数据增强的多样性尝试不同的优化器如RMSprop在实际部署中可以使用以下代码进行单张图像预测def predict_image(image_path): img tf.keras.preprocessing.image.load_img(image_path, target_size(224, 224)) img_array tf.keras.preprocessing.image.img_to_array(img) img_array (img_array / 127.5) - 1 # 与训练相同的归一化 img_array tf.expand_dims(img_array, 0) # 添加批次维度 predictions model.predict(img_array) score tf.nn.softmax(predictions[0]) class_names [石头, 布, 剪刀] print( 这张图像最可能是 {}置信度 {:.2f}% .format(class_names[np.argmax(score)], 100 * np.max(score)) )