目录
前言
一、前期工作
1.1 设置GPU
1.2 导入数据
1.3 查看数据
二、数据预处理
2.1 加载数据
2.2 可视化数据
2.3 再次检查数据
2.4 配置数据集
2.4.1 基本概念介绍
2.4.2 代码完成
三、构建CNN网络
四、训练模型
4.1 设置动态学习率
4.2 早停与保存最佳模型参数
4.3 模型训练
五、模型评估
5.1 Loss和Accuracy图
5.2 指定图片进行预测
六、改进
总结
前言
🍨 本文为
中的学习记录博客
[🔗365天深度学习训练营]
🍖 原作者:
[K同学啊]
说在前面
1)本周任务:基于CNN模型完成对两种品牌运动鞋图片的识别
2)运行环境:Python3.6、Pycharm2020、tensorflow2.4.0
一、前期工作
1.1 设置GPU
代码如下:
# 一、前期准备
# 1.1 设置GPU
from tensorflow import keras
from tensorflow.keras import layers, models
import os, PIL, pathlib
import matplotlib.pyplot as plt
import tensorflow as tf
gpus = tf.config.list_physical_devices("GPU")
if gpus:
gpu0 = gpus[0] # 如果有多个GPU,仅使用第0个GPU
tf.config.experimental.set_memory_growth(gpu0, True) # 设置GPU显存用量按需使用
tf.config.set_visible_devices([gpu0], "GPU")
print(gpus)
1.2 导入数据
代码如下:
# 1.2 导入数据
data_dir = "./data/"
data_dir = pathlib.Path(data_dir)
1.3 查看数据
代码如下:
# 1.3 查看数据
image_count = len(list(data_dir.glob('*/*/*.jpg')))
print("图片总数为:", image_count)
shoses = list(data_dir.glob('train/nike/*.jpg'))
PIL.Image.open(str(shoses[0]))
输出:
图片总数为: 578
二、数据预处理
2.1 加载数据
使用image_dataset_from_directory
方法将磁盘中的数据加载到tf.data.Dataset,
tf.keras.preprocessing.image_dataset_from_directory():是 TensorFlow 的 Keras 模块中的一个函数,用于从目录中创建一个图像数据集(dataset)。这个函数可以以更方便的方式加载图像数据,用于训练和评估神经网络模型
测试集与验证集的关系:
- 验证集并没有参与训练过程梯度下降过程的,狭义上来讲是没有参与模型的参数训练更新的。
- 但是广义上来讲,验证集存在的意义确实参与了一个“人工调参”的过程,我们根据每一个epoch训练之后模型在valid data上的表现来决定是否需要训练进行early stop,或者根据这个过程模型的性能变化来调整模型的超参数,如学习率,batch_size等等。因此,我们也可以认为,验证集也参与了训练,但是并没有使得模型去overfit验证集
- 因此,我们也可以认为,验证集也参与了训练,但是并没有使得模型去overfit验证集
代码如下:
# 二、数据预处理
# 2.1 加载数据集
batch_size = 32
img_height = 224
img_width = 224
train_ds = tf.keras.preprocessing.image_dataset_from_directory(
"./data/train/",
seed=123,
image_size=(img_height, img_width),
batch_size=batch_size)
val_ds = tf.keras.preprocessing.image_dataset_from_directory(
"./data/test/",
seed=123,
image_size=(img_height, img_width),
batch_size=batch_size)
class_names = train_ds.class_names
print(class_names)
输出如下:
Found 502 files belonging to 2 classes.
Found 76 files belonging to 2 classes.
['adidas', 'nike']
2.2 可视化数据
代码如下:
# 2.2 可视化数据
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")
输出:
2.3 再次检查数据
代码如下:
# 2.3再次检查数据
for image_batch, labels_batch in train_ds:
print(image_batch.shape)
print(labels_batch.shape)
break
输出:
(32, 224, 224, 3)
(32,)
情况说明:
Image_batch
是形状的张量(32,2224,224,3)。这是一批形状224x224x3的32张图片(最后一维指的是彩色通道RGB)。Label_batch
是形状(32,)的张量,这些标签对应32张图片
2.4 配置数据集
2.4.1 基本概念介绍
prefetch()
:CPU 正在准备数据时,加速器处于空闲状态。相反,当加速器正在训练模型时,CPU 处于空闲状态。因此,训练所用的时间是 CPU 预处理时间和加速器训练时间的总和。prefetch()
将训练步骤的预处理和模型执行过程重叠到一起。当加速器正在执行第 N 个训练步时,CPU 正在准备第 N+1 步的数据。这样做不仅可以最大限度地缩短训练的单步用时(而不是总用时),而且可以缩短提取和转换数据所需的时间。如果不使用prefetch()
,CPU 和 GPU/TPU 在大部分时间都处于空闲状态
然后使用prefetch()可显著减少空闲时间:
2.4.2 代码完成
# cache():将数据集缓存到内存当中,加速运行
AUTOTUNE = tf.data.AUTOTUNE
train_ds = train_ds.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)
代码如下:
# cache():将数据集缓存到内存当中,加速运行
AUTOTUNE = tf.data.AUTOTUNE
train_ds = train_ds.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)
三、构建CNN网络
卷积神经网络(CNN)的输入是张量 (Tensor) 形式的 (image_height, image_width, color_channels)
,包含了图像高度、宽度及颜色信息。不需要输入batch size
。color_channels 为 (R,G,B) 分别对应 RGB 的三个颜色通道(color channel)。在此示例中,我们的 CNN 输入形状是 (180, 180, 3)
。我们需要在声明第一层时将形状赋值给参数input_shape
网络结构图如下:
代码如下:
# 三、构建CNN网络
model = models.Sequential([
layers.experimental.preprocessing.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() # 打印网络结构
模型结构打印如下:
四、训练模型
在准备对模型进行训练之前,还需要再对其进行一些设置。以下内容是在模型的编译步骤中添加的:
- 损失函数(loss):用于衡量模型在训练期间的准确率。
- 优化器(optimizer):决定模型如何根据其看到的数据和自身的损失函数进行更新。
- 指标(metrics):用于监控训练和测试步骤。以下示例使用了准确率,即被正确分类的图像的比率
4.1 设置动态学习率
ExponentialDecay函数:tf.keras.optimizers.schedules.ExponentialDecay
是 TensorFlow 中的一个学习率衰减策略,用于在训练神经网络时动态地降低学习率。学习率衰减是一种常用的技巧,可以帮助优化算法更有效地收敛到全局最小值,从而提高模型的性能
🔍主要参数:
- decay_steps(衰减步数):学习率衰减的步数。在经过 decay_steps 步后,学习率将按照指数函数衰减。例如,如果 decay_steps 设置为 10,则每10步衰减一次。
- decay_rate(衰减率):学习率的衰减率。它决定了学习率如何衰减。通常,取值在 0 到 1 之间。
- staircase(阶梯式衰减):一个布尔值,控制学习率的衰减方式。如果设置为 True,则学习率在每个 decay_steps 步之后直接减小,形成阶梯状下降。如果设置为 False,则学习率将连续衰减
代码如下:
initial_learning_rate = 0.0001
lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(
initial_learning_rate,
decay_steps=10, # 敲黑板!!!这里是指 steps,不是指epochs
decay_rate=0.92, # lr经过一次衰减就会变成 decay_rate*lr
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'])
⚠️⚠️⚠️注:这里设置的动态学习率为:指数衰减型(ExponentialDecay)。在每一个epoch开始前,学习率(learning_rate)都将会重置为初始学习率(initial_learning_rate),然后再重新开始衰减。计算公式如下:learning_rate = initial_learning_rate * decay_rate ^ (step / decay_steps)
Tips:学习率大与学习率小的优缺点分析
- 学习率大:优点--加快学习速率,有助于跳出局部最优值;缺点--导致模型训练不收敛,单单使用大学习率容易导致模型不精确;
- 学习率小:优点--有助于模型收敛、模型细化,提高模型精度;缺点--很难跳出局部最优值,收敛缓慢
4.2 早停与保存最佳模型参数
🔍EarlyStopping()参数说明:
- monitor:被监测的数据
- min_delta:在被监测的数据中被认为是提升的最小变化, 例如,小于 min_delta 的绝对变化会被认为没有提升。
- patience:没有进步的训练轮数,在这之后训练就会被停止。
- verbose:详细信息模式。
- mode: {auto, min, max} 其中之一。 在 min 模式中, 当被监测的数据停止下降,训练就会停止;在 max 模式中,当被监测的数据停止上升,训练就会停止;在 auto 模式中,方向会自动从被监测的数据的名字中判断出来。
- baseline:要监控的数量的基准值。 如果模型没有显示基准的改善,训练将停止。
- estoe_best_weights:是否从具有监测数量的最佳值的时期恢复模型权重。 如果为 False,则使用在训练的最后一步获得的模型权重
代码如下:
# 4.2 早停与保存最佳模型参数
from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping
epochs = 50
# 保存最佳模型参数
checkpointer = ModelCheckpoint('best_model.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)
4.3 模型训练
代码如下:
# 4.3 模型训练
history = model.fit(train_ds,
validation_data=val_ds,
epochs=epochs,
callbacks=[checkpointer, earlystopper])
打印训练过程:
五、模型评估
5.1 Loss和Accuracy图
代码如下:
# 五、模型评估
# 5、1 Loss与Accuracy图
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.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()
训练结果可视化如下:
5.2 指定图片进行预测
代码如下:
# 5.2 指定图片进行预测
# 加载效果最好的模型权重
model.load_weights('best_model.h5')
from PIL import Image
import numpy as np
# img = Image.open("./45-data/Monkeypox/M06_01_04.jpg") #这里选择你需要预测的图片
img = Image.open("./data/test/nike/1.jpg") #这里选择你需要预测的图片
image = tf.image.resize(img, [img_height, img_width])
img_array = tf.expand_dims(image, 0)/255.0 # 记得做归一化处理(与训练集处理方式保持一致)
predictions = model.predict(img_array) # 这里选用你已经训练好的模型
print("预测结果为:",class_names[np.argmax(predictions)])
输出:
预测结果为: addidas
六、改进
从训练过程和指定预测的结果可以发现效果并不好,这里考虑修改initial_learning_rate,原始设置的是0.1,这里考虑将其调至0.001或0.0001
总结
本周在上周的基础上增加了动态学习率的设置,优化了训练过程,并实现了正确预测,也让我更加熟练基于Tensorflow框架下CNN模型搭建的流程,并对动态学习率初始值设置对结果影响进行了分析