【深度学习实验】—— TensorFlow 实现鞋类识别
- 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
- 🍖 原作者:K同学啊
文章目录
1. 简介 & 数据集介绍
利用 TensorFlow,通过构建三层卷积神经网络(CNN)实现鞋类识别。
数据集中有 Adidas、Nike 两类数据,每类数据 280 张左右的图片。
2. 环境
- 语言环境:Python 3.12.7
- 编译器:Jupyter Notebook
- 深度学习环境:TensorFlow 2.21.0
3. 代码实现
3.1 前期准备
3.1.1 设置GPU & 导入库
导入必要的库并配置 GPU 显存增长,以解决在 Windows 环境下可能出现的显存占用或驱动兼容性问题。
from tensorflow import keras
from tensorflow.keras import layers,models
import os, PIL, pathlib
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping
from PIL import Image
import numpy as np
from datetime import datetime
gpus = tf.config.list_physical_devices("GPU")
if gpus:
gpu0 = gpus[0]
tf.config.experimental.set_memory_growth(gpu0, True)
tf.config.set_visible_devices([gpu0],"GPU")
gpus
3.1.2 数据集统计与预览
通过 pathlib 扫描本地目录统计 578 张图像,并使用 PIL 打开一张图片进行直观确认。
data_dir = "./Data/46-data/"
data_dir = pathlib.Path(data_dir)
image_count = len(list(data_dir.glob('*/*/*.jpg')))
print("图片总数为:",image_count)
roses = list(data_dir.glob('train/nike/*.jpg'))
PIL.Image.open(str(roses[0]))

3.2 数据预处理
3.2.1 数据集划分与预处理
设定了图像输入尺寸(224x224)和批次大小(batch_size=32),使用 image_dataset_from_directory 接口从本地目录中自动加载训练数据集。
batch_size = 32
img_height = 224
img_width = 224
train_ds = tf.keras.preprocessing.image_dataset_from_directory( "./Data/46-data/train/", seed=123, image_size=(img_height, img_width), batch_size=batch_size)

val_ds = tf.keras.preprocessing.image_dataset_from_directory( "./Data/46-data/test/", seed=123, image_size=(img_height, img_width), batch_size=batch_size)

3.2.2 类别识别
提取并打印分类名称。
class_names = train_ds.class_names
print(class_names)

3.2.3 可视化
利用 matplotlib 绘制前 20 张图片及其标签。
plt.figure(figsize=(20, 10))
for images, labels in train_ds.take(1):
for i in range(20):
ax = plt.subplot(5, 10, i + 1)
plt.imshow(images[i].numpy().astype("uint8"))
plt.title(class_names[labels[i]])
plt.axis("off")

3.2.4 整体数据检查
确保数据加载正确。
for image_batch, labels_batch in train_ds:
print(image_batch.shape)
print(labels_batch.shape)
break

3.3 模型建立与训练
3.3.1 数据集配置与模型建立
使用 cache() 和 prefetch() 方法优化数据加载性能。接着定义了一个卷积神经网络(CNN),包括归一化层(Rescaling)、多个卷积层(Conv2D)与池化层(AveragePooling2D)、防止过拟合的 Dropout 层,以及最后的全连接层(Dense)。
AUTOTUNE = tf.data.AUTOTUNE
train_ds = train_ds.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)
model = models.Sequential([
layers.Rescaling(1./255, input_shape=(img_height, img_width, 3)),
layers.Conv2D(16, (3, 3), activation='relu', input_shape=(img_height, img_width, 3)), # 卷积层1,卷积核3*3
layers.AveragePooling2D((2, 2)), # 池化层1,2*2采样
layers.Conv2D(32, (3, 3), activation='relu'), # 卷积层2,卷积核3*3
layers.AveragePooling2D((2, 2)), # 池化层2,2*2采样
layers.Dropout(0.3),
layers.Conv2D(64, (3, 3), activation='relu'), # 卷积层3,卷积核3*3
layers.Dropout(0.3),
layers.Flatten(), # Flatten层,连接卷积层与全连接层
layers.Dense(128, activation='relu'), # 全连接层,特征进一步提取
layers.Dense(len(class_names)) # 输出层,输出预期结果
])
model.summary() # 打印网络结构

3.3.2 模型训练
设置了指数衰减的动态学习率(ExponentialDecay),使用了 Adam 优化器,并配置了交叉熵损失函数(SparseCategoricalCrossentropy)和准确率评估指标,最后对模型进行了 compile(编译)。同时定义了 ModelCheckpoint(自动保存验证集准确率最高的权重)和 EarlyStopping(在模型不再提升时提前停止训练)两个回调函数。然后调用 model.fit() 开始在训练集上训练模型,并在验证集上进行验证。
# 设置初始学习率
initial_learning_rate = 0.001
lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay( initial_learning_rate, decay_steps=10, decay_rate=0.92, staircase=True)
# 将指数衰减学习率送入优化器
optimizer = tf.keras.optimizers.Adam(learning_rate=lr_schedule)
model.compile(optimizer=optimizer, loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=['accuracy'])
epochs = 50
# 保存最佳模型参数
checkpointer = ModelCheckpoint('best_model.weights.h5', monitor='val_accuracy', verbose=1, save_best_only=True, save_weights_only=True)
# 设置早停
earlystopper = EarlyStopping(monitor='val_accuracy', min_delta=0.001, patience=20, verbose=1)
history = model.fit(train_ds, validation_data=val_ds, epochs=epochs, callbacks=[checkpointer, earlystopper])
Epoch 1/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 285ms/step - accuracy: 0.5077 - loss: 3.5627
Epoch 1: val_accuracy improved from None to 0.51316, saving model to best_model.weights.h5
16/16 ━━━━━━━━━━━━━━━━━━━━ 7s 326ms/step - accuracy: 0.4980 - loss: 2.0907 - val_accuracy: 0.5132 - val_loss: 0.6907
Epoch 2/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 279ms/step - accuracy: 0.4635 - loss: 0.6936
Epoch 2: val_accuracy improved from 0.51316 to 0.57895, saving model to best_model.weights.h5
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 309ms/step - accuracy: 0.4841 - loss: 0.6938 - val_accuracy: 0.5789 - val_loss: 0.6858
Epoch 3/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 287ms/step - accuracy: 0.5302 - loss: 0.6935
Epoch 3: val_accuracy did not improve from 0.57895
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 295ms/step - accuracy: 0.5398 - loss: 0.6931 - val_accuracy: 0.5526 - val_loss: 0.6826
Epoch 4/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 283ms/step - accuracy: 0.5781 - loss: 0.6862
Epoch 4: val_accuracy improved from 0.57895 to 0.60526, saving model to best_model.weights.h5
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 312ms/step - accuracy: 0.5717 - loss: 0.6840 - val_accuracy: 0.6053 - val_loss: 0.6666
Epoch 5/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 281ms/step - accuracy: 0.5544 - loss: 0.6797
Epoch 5: val_accuracy improved from 0.60526 to 0.63158, saving model to best_model.weights.h5
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 309ms/step - accuracy: 0.5418 - loss: 0.6759 - val_accuracy: 0.6316 - val_loss: 0.6618
Epoch 6/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 281ms/step - accuracy: 0.5846 - loss: 0.6695
Epoch 6: val_accuracy improved from 0.63158 to 0.64474, saving model to best_model.weights.h5
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 311ms/step - accuracy: 0.6096 - loss: 0.6655 - val_accuracy: 0.6447 - val_loss: 0.6598
Epoch 7/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 289ms/step - accuracy: 0.6385 - loss: 0.6593
Epoch 7: val_accuracy improved from 0.64474 to 0.69737, saving model to best_model.weights.h5
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 321ms/step - accuracy: 0.6096 - loss: 0.6506 - val_accuracy: 0.6974 - val_loss: 0.6675
Epoch 8/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 279ms/step - accuracy: 0.6216 - loss: 0.6446
Epoch 8: val_accuracy did not improve from 0.69737
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 287ms/step - accuracy: 0.6355 - loss: 0.6531 - val_accuracy: 0.6711 - val_loss: 0.6464
Epoch 9/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 277ms/step - accuracy: 0.5825 - loss: 0.6371
Epoch 9: val_accuracy did not improve from 0.69737
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 284ms/step - accuracy: 0.6235 - loss: 0.6289 - val_accuracy: 0.6579 - val_loss: 0.6592
Epoch 10/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 281ms/step - accuracy: 0.6826 - loss: 0.6301
Epoch 10: val_accuracy did not improve from 0.69737
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 289ms/step - accuracy: 0.6892 - loss: 0.6129 - val_accuracy: 0.6184 - val_loss: 0.6212
Epoch 11/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 280ms/step - accuracy: 0.5976 - loss: 0.6062
Epoch 11: val_accuracy did not improve from 0.69737
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 288ms/step - accuracy: 0.6514 - loss: 0.5875 - val_accuracy: 0.6974 - val_loss: 0.6181
Epoch 12/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 276ms/step - accuracy: 0.7444 - loss: 0.5683
Epoch 12: val_accuracy improved from 0.69737 to 0.71053, saving model to best_model.weights.h5
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 305ms/step - accuracy: 0.7311 - loss: 0.5561 - val_accuracy: 0.7105 - val_loss: 0.5797
Epoch 13/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 277ms/step - accuracy: 0.7301 - loss: 0.5075
Epoch 13: val_accuracy did not improve from 0.71053
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 286ms/step - accuracy: 0.7251 - loss: 0.5127 - val_accuracy: 0.7105 - val_loss: 0.5837
Epoch 14/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 283ms/step - accuracy: 0.7656 - loss: 0.4769
Epoch 14: val_accuracy did not improve from 0.71053
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 292ms/step - accuracy: 0.7729 - loss: 0.4783 - val_accuracy: 0.6974 - val_loss: 0.5600
Epoch 15/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 284ms/step - accuracy: 0.7834 - loss: 0.4398
Epoch 15: val_accuracy did not improve from 0.71053
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 292ms/step - accuracy: 0.7908 - loss: 0.4519 - val_accuracy: 0.7105 - val_loss: 0.5480
Epoch 16/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 284ms/step - accuracy: 0.8387 - loss: 0.3951
Epoch 16: val_accuracy did not improve from 0.71053
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 292ms/step - accuracy: 0.8127 - loss: 0.4240 - val_accuracy: 0.7105 - val_loss: 0.6107
Epoch 17/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 284ms/step - accuracy: 0.7870 - loss: 0.4414
Epoch 17: val_accuracy improved from 0.71053 to 0.73684, saving model to best_model.weights.h5
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 314ms/step - accuracy: 0.8267 - loss: 0.4179 - val_accuracy: 0.7368 - val_loss: 0.5986
Epoch 18/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 282ms/step - accuracy: 0.8177 - loss: 0.4031
Epoch 18: val_accuracy did not improve from 0.73684
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 290ms/step - accuracy: 0.8207 - loss: 0.3951 - val_accuracy: 0.7368 - val_loss: 0.5541
Epoch 19/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 282ms/step - accuracy: 0.8616 - loss: 0.3534
Epoch 19: val_accuracy did not improve from 0.73684
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 290ms/step - accuracy: 0.8426 - loss: 0.3776 - val_accuracy: 0.7368 - val_loss: 0.5556
Epoch 20/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 281ms/step - accuracy: 0.8451 - loss: 0.3608
Epoch 20: val_accuracy did not improve from 0.73684
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 289ms/step - accuracy: 0.8406 - loss: 0.3743 - val_accuracy: 0.7237 - val_loss: 0.5515
Epoch 21/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 277ms/step - accuracy: 0.8528 - loss: 0.3456
Epoch 21: val_accuracy did not improve from 0.73684
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 285ms/step - accuracy: 0.8546 - loss: 0.3503 - val_accuracy: 0.7237 - val_loss: 0.5604
Epoch 22/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 280ms/step - accuracy: 0.8579 - loss: 0.3518
Epoch 22: val_accuracy did not improve from 0.73684
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 287ms/step - accuracy: 0.8606 - loss: 0.3433 - val_accuracy: 0.7237 - val_loss: 0.5564
Epoch 23/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 283ms/step - accuracy: 0.8909 - loss: 0.3008
Epoch 23: val_accuracy did not improve from 0.73684
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 291ms/step - accuracy: 0.8725 - loss: 0.3321 - val_accuracy: 0.7237 - val_loss: 0.5584
Epoch 24/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 282ms/step - accuracy: 0.8545 - loss: 0.3606
Epoch 24: val_accuracy did not improve from 0.73684
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 291ms/step - accuracy: 0.8725 - loss: 0.3243 - val_accuracy: 0.7237 - val_loss: 0.5602
Epoch 25/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 286ms/step - accuracy: 0.8657 - loss: 0.3317
Epoch 25: val_accuracy did not improve from 0.73684
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 294ms/step - accuracy: 0.8785 - loss: 0.3203 - val_accuracy: 0.7237 - val_loss: 0.5765
Epoch 26/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 277ms/step - accuracy: 0.8953 - loss: 0.2755
Epoch 26: val_accuracy did not improve from 0.73684
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 285ms/step - accuracy: 0.8665 - loss: 0.3153 - val_accuracy: 0.7237 - val_loss: 0.5567
Epoch 27/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 282ms/step - accuracy: 0.8745 - loss: 0.3155
Epoch 27: val_accuracy did not improve from 0.73684
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 290ms/step - accuracy: 0.8825 - loss: 0.3124 - val_accuracy: 0.7105 - val_loss: 0.5894
Epoch 28/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 285ms/step - accuracy: 0.8178 - loss: 0.3716
Epoch 28: val_accuracy did not improve from 0.73684
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 293ms/step - accuracy: 0.8665 - loss: 0.3111 - val_accuracy: 0.7237 - val_loss: 0.5577
Epoch 29/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 274ms/step - accuracy: 0.9186 - loss: 0.2583
Epoch 29: val_accuracy did not improve from 0.73684
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 282ms/step - accuracy: 0.8825 - loss: 0.3063 - val_accuracy: 0.7237 - val_loss: 0.5775
Epoch 30/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 278ms/step - accuracy: 0.8715 - loss: 0.3093
Epoch 30: val_accuracy did not improve from 0.73684
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 286ms/step - accuracy: 0.8825 - loss: 0.3072 - val_accuracy: 0.7105 - val_loss: 0.5743
Epoch 31/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 274ms/step - accuracy: 0.8595 - loss: 0.3241
Epoch 31: val_accuracy did not improve from 0.73684
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 282ms/step - accuracy: 0.8805 - loss: 0.3024 - val_accuracy: 0.7237 - val_loss: 0.5659
Epoch 32/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 279ms/step - accuracy: 0.9079 - loss: 0.2788
Epoch 32: val_accuracy did not improve from 0.73684
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 287ms/step - accuracy: 0.8904 - loss: 0.2967 - val_accuracy: 0.7105 - val_loss: 0.5784
Epoch 33/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 283ms/step - accuracy: 0.8796 - loss: 0.2954
Epoch 33: val_accuracy did not improve from 0.73684
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 290ms/step - accuracy: 0.8825 - loss: 0.2914 - val_accuracy: 0.7105 - val_loss: 0.5761
Epoch 34/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 278ms/step - accuracy: 0.8655 - loss: 0.3137
Epoch 34: val_accuracy did not improve from 0.73684
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 286ms/step - accuracy: 0.8904 - loss: 0.2881 - val_accuracy: 0.7237 - val_loss: 0.5736
Epoch 35/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 286ms/step - accuracy: 0.8911 - loss: 0.2903
Epoch 35: val_accuracy did not improve from 0.73684
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 294ms/step - accuracy: 0.8884 - loss: 0.2935 - val_accuracy: 0.7105 - val_loss: 0.5798
Epoch 36/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 284ms/step - accuracy: 0.9075 - loss: 0.2710
Epoch 36: val_accuracy did not improve from 0.73684
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 291ms/step - accuracy: 0.8964 - loss: 0.2915 - val_accuracy: 0.7105 - val_loss: 0.5756
Epoch 37/50
16/16 ━━━━━━━━━━━━━━━━━━━━ 0s 280ms/step - accuracy: 0.9041 - loss: 0.2777
Epoch 37: val_accuracy did not improve from 0.73684
16/16 ━━━━━━━━━━━━━━━━━━━━ 5s 287ms/step - accuracy: 0.8984 - loss: 0.2778 - val_accuracy: 0.7105 - val_loss: 0.5745
Epoch 37: early stopping
4. 模型评估
提取训练历史记录(History)中的 Loss 和 Accuracy 数据,使用 Matplotlib 将训练集和验证集的准确率、损失值变化绘制成折线图,用于分析模型是否收敛或过拟合。
current_time = datetime.now()
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs_range = range(len(loss))
plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)
plt.plot(epochs_range, acc, label='Training Accuracy')
plt.plot(epochs_range, val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')
plt.xlabel(current_time)
plt.subplot(1, 2, 2)
plt.plot(epochs_range, loss, label='Training Loss')
plt.plot(epochs_range, val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()

加载之前保存的“最佳模型权重”(best_model.weights.h5),读取一张全新的测试图片,经过统一的尺寸缩放和维度扩展等预处理后,送入模型进行预测,并输出预测结果。
# 加载效果最好的模型权重
model.load_weights('best_model.weights.h5')
img = Image.open("./Data/46-data/test/adidas/1.jpg")
image = tf.image.resize(img, [img_height, img_width])
img_array = tf.expand_dims(image, 0)
predictions = model.predict(img_array)
print("预测结果为:",class_names[np.argmax(predictions)])

更多推荐


所有评论(0)