目录
一、前言
-
>- **🍨 本文为[🔗
365天深度学习训练营](https://mp.weixin.qq.com/s/xLjALoOD8HPZcH563En8bQ) 中的学习记录博客**
-
>- **🍦 参考文章:
365天深度学习训练营-第
5周:运动鞋品牌识别(训练营内部成员可读)**
-
>- **🍖 原作者:[K同学啊](https://mp.weixin.qq.com/s/xLjALoOD8HPZcH563En8bQ)**
二、我的环境
语言环境:Python3.7
编译器:jupyter notebook
深度学习环境:TensorFlow2
三、代码实现
-
from tensorflow
import keras
-
from tensorflow.keras
import layers, models
-
import os, PIL, pathlib
-
import matplotlib.pyplot
as plt
-
import tensorflow
as tf
-
-
# GPU加载
-
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")
-
-
gpus
-
# 导入数据
-
data_dir =
"./hy-tmp/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]))
-
# 数据预处理
-
batch_size =
32
-
img_height =
224
-
img_width =
224
-
-
"""
-
关于image_dataset_from_directory()的详细介绍可以参考文章:https://mtyjkh.blog.csdn.net/article/details/117018789
-
"""
-
train_ds = tf.keras.preprocessing.image_dataset_from_directory(
-
"./hy-tmp/46-data/train/",
-
seed=
123,
-
image_size=(img_height, img_width),
-
batch_size=batch_size)
-
-
"""
-
关于image_dataset_from_directory()的详细介绍可以参考文章:https://mtyjkh.blog.csdn.net/article/details/117018789
-
"""
-
val_ds = tf.keras.preprocessing.image_dataset_from_directory(
-
"./hy-tmp/46-data/test/",
-
seed=
123,
-
image_size=(img_height, img_width),
-
batch_size=batch_size)
-
-
class_names = train_ds.class_names
-
print(class_names)
-
-
# 数据可视化
-
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")
-
-
# 再次检查数据
-
for image_batch, labels_batch
in train_ds:
-
print(image_batch.shape)
-
print(labels_batch.shape)
-
break
-
-
# 配置数据
-
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
-
"""
-
关于卷积核的计算不懂的可以参考文章:https://blog.csdn.net/qq_38251616/article/details/114278995
-
-
layers.Dropout(0.4) 作用是防止过拟合,提高模型的泛化能力。
-
关于Dropout层的更多介绍可以参考文章:https://mtyjkh.blog.csdn.net/article/details/115826689
-
"""
-
-
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()
# 打印网络结构
-
-
# 设置动态学习率
-
# 设置初始学习率
-
initial_learning_rate =
0.1
-
-
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'])
-
-
from tensorflow.keras.callbacks
import ModelCheckpoint, EarlyStopping
-
-
epochs =
50
-
# 断点续训
-
checkpoint_save_path =
"./best_model.h5"
-
if os.path.exists(checkpoint_save_path):
-
print(
'---------------load the model-----------------')
-
model.load_weights(checkpoint_save_path)
-
-
epochs =
50
-
-
checkpointer = ModelCheckpoint(
-
filepath=checkpoint_save_path,
-
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])
-
-
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()
-
-
from PIL
import Image
-
import numpy
as np
-
-
# img = Image.open("./45-data/Monkeypox/M06_01_04.jpg") #这里选择你需要预测的图片
-
img = Image.
open(
"./46-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)])
四、重点知识点
1、设置动态学习率
-
# 设置初始学习率
-
initial_learning_rate =
0.1
-
-
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'])
学习率大与学习率小的优缺点分析:
学习率大
优点:
- 1、加快学习速率。
- 2、有助于跳出局部最优值
缺点:
- 1、导致模型训练不收敛。
- 2、单单使用大学习率容易导致模型不精确。
学习率小
优点:
- 1、有助于模型收敛、模型细化。
- 2、提高模型精度。
缺点:
- 1、很难跳出局部最优值。
- 2、收敛缓慢。
注意:这里设置的动态学习率为:指数衰减型(ExponentialDecay)。在每一个epoch开始前,学习率(learning_rate)都将会重置为初始学习率(initial_learning_rate),然后再重新开始衰减。计算公式如下:
learning_rate = initial_learning_rate * decay_rate ^ (step / decay_steps)
2、早停与保存最佳模型参数
EarlyStopping()参数说明:
●monitor: 被监测的数据。
●min_delta: 在被监测的数据中被认为是提升的最小变化, 例如,小于 min_delta 的绝对变化会被认为没有提升。
●patience: 没有进步的训练轮数,在这之后训练就会被停止。
●verbose: 详细信息模式。
●mode: {auto, min, max} 其中之一。 在 min 模式中, 当被监测的数据停止下降,训练就会停止;在 max 模式中,当被监测的数据停止上升,训练就会停止;在 auto 模式中,方向会自动从被监测的数据的名字中判断出来。
●baseline: 要监控的数量的基准值。 如果模型没有显示基准的改善,训练将停止。
●estore_best_weights: 是否从具有监测数量的最佳值的时期恢复模型权重。 如果为 False,则使用在训练的最后一步获得的模型权重。
-
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)
五、总结并改进代码
验证集准确率大概在50%,再将轮数增加仍没有改变,查原因是学习率设置过大的原因。
将学习率改为2e-4,重新进行训练。
验证集准确率提升到了75%左右,想要继续提高准确率,可以在CNN网络里面每次池化层后面又增加了 Dropout(0.15)可以后期根据结果再调整Dropout的参数。
存储训练最佳模型的参数,加入断点续训功能。
调整CNN网络的参数,可以加卷积层池化层、增加训练轮次来提升准确率,最终结果和代码如下:可以看到验证集的准确率大概维持在85%左右
-
# 设置初始学习率
-
initial_learning_rate =
2e-4
-
-
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'])
-
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.Dropout(
0.15),
-
layers.Conv2D(
32, (
3,
3), activation=
'relu'),
# 卷积层2,卷积核3*3
-
layers.AveragePooling2D((
2,
2)),
# 池化层2,2*2采样
-
layers.Dropout(
0.15),
-
layers.Conv2D(
64, (
3,
3), activation=
'relu'),
-
layers.Dropout(
0.15),
-
-
layers.Flatten(),
# Flatten层,连接卷积层与全连接层
-
layers.Dense(
128, activation=
'relu'),
# 全连接层,特征进一步提取
-
layers.Dense(
len(class_names))
# 输出层,输出预期结果
-
])
-
-
model.summary()
# 打印网络结构
转载:https://blog.csdn.net/m0_58585940/article/details/127808093