- 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
- 🍖 原作者:K同学啊
前言
- 这个案例比较简单,无论是学习tensorflow还是学习神经网络,都是一个很好的案例;
- 这个案例主要用处是学习
tensorflow的API
,包含:检查是否GPU、图像数据加载与划分、拿取动态加载的数据、内存优化、神经网络构建、模型超参数设计、模型训练; - 欢迎收藏 + 关注,本人将持续更新💌💌💌💌💌💌。
1、tensorflow一些API讲解
查阅方法: 阿里巴巴通义千文;up主:K同学啊。
📘 判断是否支持gpu
# 查看是否支持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")
📖 图像数据加载与分类
用于从目录中加载图像数据并自动进行分类。这个函数可以直接生成一个 tf.data.Dataset
对象,非常适合用于训练深度学习模型。
tf.keras.preprocessing.image_dataset_from_directory(
directory,
labels="inferred",
label_mode="int",
class_names=None,
color_mode="rgb",
batch_size=32,
image_size=(256, 256),
shuffle=True,
seed=None,
validation_split=None,
subset=None,
interpolation="bilinear",
follow_links=False,
)
👁🗨参数说明:
- directory: 图像文件所在的根目录路径。
- labels: 标签的来源,默认为
"inferred"
,表示从目录结构中推断标签。其他选项包括"inferred"
和None
。 - label_mode: 标签的类型,默认为
"int"
,表示整数标签。其他选项包括"categorical"
(one-hot 编码)和"binary"
(二进制标签)。 - class_names: 类别名称列表。如果为
None
,则从目录结构中推断类别名称。 - color_mode: 图像的颜色模式,默认为
"rgb"
。其他选项包括"grayscale"
和"rgba"
。 - batch_size: 每个批次的图像数量,默认为 32。
- image_size: 图像的尺寸,默认为
(256, 256)
。 - shuffle: 是否在加载数据时打乱图像,默认为
True
。 - seed: 随机种子,用于打乱数据和拆分验证集,确保可重复性。
- validation_split: 验证集的比例,范围在 0 到 1 之间。如果为
None
,则不拆分验证集。 - subset: 指定要加载的数据子集,选项包括
"training"
和"validation"
。只有在validation_split
不为None
时才有效。 - interpolation: 图像缩放时使用的插值方法,默认为
"bilinear"
。其他选项包括"nearest"
、"bicubic"
等。 - follow_links: 是否跟随符号链接,默认为
False
。
👼 案例(划分训练集和验证集):
train_ds = tf.keras.preprocessing.image_dataset_from_directory(
directory = './data/',
validation_split = 0.2,
batch_size = 32,
seed = 42,
image_size = (224, 224),
subset = 'training',
shuffle = True
)
val_ds = tf.keras.preprocessing.image_dataset_from_directory(
directory = './data/',
validation_split = 0.2,
batch_size = 32,
seed = 42,
image_size = (224, 224),
subset = 'validation',
shuffle = True
)
🎉 拿取动态加载数据的批次:
API:train_ds.take(1)
,返回值:
- images,图片数据
- labels,分类标签,0,1,2……
📖 优化内存
-
shuffle():打乱数据,关于此函数的详细介绍可以参考:https://zhuanlan.zhihu.com/p/42417456
-
prefetch():预取数据,加速运行,prefetch()功能详细介绍:CPU 正在准备数据时,加速器处于空闲状态。相反,当加速器正在训练模型时,CPU 处于空闲状态。因此,训练所用的时间是 CPU 预处理时间和加速器训练时间的总和。prefetch()将训练步骤的预处理和模型执行过程重叠到一起。当加速器正在执行第 N 个训练步时,CPU 正在准备第 N+1 步的数据。这样做不仅可以最大限度地缩短训练的单步用时(而不是总用时),而且可以缩短提取和转换数据所需的时间。如果不使用prefetch(),CPU 和 GPU/TPU 在大部分时间都处于空闲状态:
-
cache():将数据集缓存到内存当中,加速运行
from tensorflow.data.experimental import AUTOTUNE
AUTOTUNE = tf.data.experimental.AUTOTUNE
# buffer_size:缓冲区大小
train_ds = train_ds.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE)
vals_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)
📳 模型构建
API:models.Sequential
容器,在 TensorFlow 中,用tf.keras.layers
模块提构建神经网络所需的各种层。这些层可以用来构建不同类型的神经网络模型,如卷积神经网络(CNN)、循环神经网络(RNN)等。下面是一些常用的层类型及其简要说明:
基础层
- Dense:全连接层,用于构建标准的前馈神经网络。
- 参数:
units
(输出维度),activation
(激活函数),use_bias
(是否使用偏置项)等。
- 参数:
- Activation:独立的激活层,可以应用于任何其他层的输出。
- 参数:
activation
(激活函数名或函数对象)。
- 参数:
- Dropout:用于防止过拟合,通过随机丢弃一部分神经元来实现。
- 参数:
rate
(丢弃率,即每个神经元被丢弃的概率)。
- 参数:
- Flatten:将多维输入展平成一维向量,常用于连接卷积层和全连接层之间。
- 参数:无。
卷积层
- Conv1D、Conv2D、Conv3D:一维、二维、三维卷积层,分别适用于时间序列数据、图像数据和视频数据。
- 参数:
filters
(滤波器数量),kernel_size
(卷积核大小),strides
(步长),padding
(填充方式),activation
(激活函数)等。
- 参数:
- SeparableConv1D、SeparableConv2D:深度可分离卷积层,用于减少计算量和参数数量。
- 参数与普通卷积层类似。
- DepthwiseConv2D:深度卷积层,用于处理通道之间的信息。
- 参数:
kernel_size
,strides
,padding
等。
- 参数:
池化层
- MaxPooling1D、MaxPooling2D、MaxPooling3D:最大池化层,用于降低数据的空间尺寸。
- 参数:
pool_size
(池化窗口大小),strides
,padding
等。
- 参数:
- AveragePooling1D、AveragePooling2D、AveragePooling3D:平均池化层,作用类似于最大池化层,但采用的是平均值而不是最大值。
- 参数与最大池化层相同。
循环层
- SimpleRNN:简单的循环神经网络层。
- 参数:
units
(输出维度),activation
,use_bias
等。
- 参数:
- LSTM:长短期记忆网络层,是一种特殊的 RNN 层,能够学习长期依赖关系。
- 参数与 SimpleRNN 相似。
- GRU:门控循环单元层,是 LSTM 的简化版本。
- 参数与 SimpleRNN 和 LSTM 相似。
正则化层
- BatchNormalization:批量归一化层,用于加速训练过程并减少内部协变量转移。
- 参数:
axis
(指定要进行归一化的轴),momentum
(移动平均的动量),epsilon
(防止除零的小值)等。
- 参数:
输入层
- InputLayer:显式定义模型的输入层。
- 参数:
input_shape
(输入张量的形状),batch_size
(批处理大小)等。
- 参数:
注意力机制相关层
- Attention:注意力机制层,用于在模型中引入注意力机制。
- 参数:
use_scale
(是否使用缩放因子),causal
(是否为因果注意力)等。
- 参数:
当然,这些只是 tf.keras.layers
模块提供的一部分层。
⏰ 超参数设置
API:model.compile
model.compile(
optimizer='adam', # 优化器
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False), # 损失函数
metrics=['accuracy'] # 准确率
)
- optimizer:
- 作用:指定优化算法,用于更新模型的权重以最小化损失函数。
- 常见选项
'adam'
:自适应矩估计(Adam)优化器,通常是一个不错的选择。'sgd'
:随机梯度下降(SGD)优化器。'rmsprop'
:均方根传播(RMSprop)优化器。'adagrad'
:Adagrad 优化器。- 你也可以使用自定义的优化器,例如
tf.keras.optimizers.Adam(learning_rate=0.001)
。
- loss:
- 作用:指定损失函数,用于衡量模型预测值与真实值之间的差距。
- 常见选项
tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False)
:用于多分类任务,当标签是整数时使用。tf.keras.losses.CategoricalCrossentropy(from_logits=False)
:用于多分类任务,当标签是 one-hot 编码时使用。tf.keras.losses.BinaryCrossentropy(from_logits=False)
:用于二分类任务。tf.keras.losses.MeanSquaredError()
:用于回归任务。
- metrics:
- 作用:指定评估模型性能的指标。
- 常见选项
'accuracy'
:分类任务中常用的准确率。'mse'
:均方误差,用于回归任务。'mae'
:平均绝对误差,用于回归任务。- 你也可以使用自定义的评估指标,例如
tf.keras.metrics.AUC()
。
🤞 模型训练
API:model.fit
history = model.fit(
x=train_ds, # 训练数据
validation_data=val_ds, # 验证数据
epochs=10, # 训练轮数
batch_size=32, # 批次大小(如果数据集已经是批处理形式,可以省略)
verbose=1, # 日志显示模式
callbacks=None # 回调函数列表
)
-
x:
- 作用:训练数据。可以是
tf.data.Dataset
对象、NumPy 数组、Python 列表等。 - 示例:
x=train_ds
- 作用:训练数据。可以是
-
y:
- 作用:训练数据的标签。如果
x
是tf.data.Dataset
对象,可以省略y
,因为tf.data.Dataset
已经包含了标签。 - 示例:
y=train_labels
(如果x
是 NumPy 数组)
- 作用:训练数据的标签。如果
-
validation_data:
- 作用:验证数据,用于在每个 epoch 结束时评估模型的性能。
- 示例:
validation_data=val_ds
-
epochs:
- 作用:训练的轮数,即模型将在整个训练数据集上迭代的次数。
- 示例:
epochs=10
-
batch_size:
- 作用:每个批次的样本数量。如果
x
是tf.data.Dataset
对象,通常不需要指定batch_size
,因为tf.data.Dataset
已经设置了批次大小。 - 示例:
batch_size=32
- 作用:每个批次的样本数量。如果
-
verbose:
-
作用
:日志显示模式。
0
:不输出日志。1
:输出进度条。2
:每个 epoch 输出一行记录。
-
示例:
verbose=1
-
-
callbacks:
-
作用:回调函数列表,用于在训练过程中执行特定的操作,如保存模型、早停、学习率调整等。
-
常见回调
:
tf.keras.callbacks.ModelCheckpoint
:定期保存模型。tf.keras.callbacks.EarlyStopping
:在验证性能不再提升时提前停止训练。tf.keras.callbacks.ReduceLROnPlateau
:在验证性能不再提升时降低学习率。
-
2、天气案例详解
数据量较小,模型泛化能力较差,仅适合学习,要分类的数据有四类,一共1000多张图片。
1、数据处理
1、导入库
import tensorflow as tf
from tensorflow.keras import datasets, layers, models
import numpy as np
# 查看是否支持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
输出:
[] // 说明本机tensorflow不是gpu版本,不支持gpu
2、图片类别
import os, PIL, pathlib
# 转化为pathlib对象
data_dir = './data/'
data_dir = pathlib.Path(data_dir)
data_paths = data_dir.glob('*')
classNums = [str(path).split('\\')[1] for path in data_paths]
classNums
输出:
['cloudy', 'rain', 'shine', 'sunrise']
3、数据划分
tf.keras.preprocessing.image_dataset_from_directory
是tensorflow中加载数据的API,用于处理数据集的划分功能.
在tf.keras.preprocessing.image_dataset_from_directory中,提供了如何划分训练集和验证集的选项,要注意的是:
- 当选择训练集的的时候,validation_split=0.2,说明选择0.8作为训练集;
- 当选择验证集的时候,validation_split=0.2,说明选择0.2作为验证集。
数据划分:
- 数据划分为训练集和验证集,训练集0.8,验证集0.2;
训练集、验证集、测试集:
- 训练集:用来训练模型,找寻数据特性,调整模型参数;
- 验证集:验证集没有参与模型训练,
定期评估模型性能
,但不参与模型参数的更新,所以在狭义的角度来看,他没有参与模型训练,从广义来看,参与了; - 测试集:用来检测模型,用于最终的评估模型性能。
batch_size = 32
# 加载数据
train_ds = tf.keras.preprocessing.image_dataset_from_directory(
directory = './data/',
validation_split = 0.2,
batch_size = 32,
seed = 42,
image_size = (224, 224),
subset = 'training',
shuffle = True
)
val_ds = tf.keras.preprocessing.image_dataset_from_directory(
directory = './data/',
validation_split = 0.2,
batch_size = 32,
seed = 42,
image_size = (224, 224),
subset = 'validation',
shuffle = True
)
Found 1125 files belonging to 4 classes.
Using 900 files for training.
Found 1125 files belonging to 4 classes.
Using 225 files for validation.
# 查看训练集名字,图片分类名字
class_names = train_ds.class_names
class_names
输出:
['cloudy', 'rain', 'shine', 'sunrise']
4、数据可视化
取批次函数:
train_ds.take(1),返回值:images,labels(下标)
import matplotlib.pyplot as plt
plt.figure(figsize=(20, 10))
for images, labels in train_ds.take(1): # 类别存储0, 1
for i in range(20): # 展示20
plt.subplot(5, 10, i + 1)
plt.imshow(images[i].numpy().astype("uint8"))
plt.title(class_names[labels[i]]) # 类别是存储0,1
plt.axis('off') # 去掉边框
# 查看图片批次、大小、颜色通道,和存储数据类别
for X, classes in train_ds:
print(X.shape)
print(classes)
break
(32, 224, 224, 3)
tf.Tensor([0 3 1 3 1 2 1 0 2 2 2 1 0 3 2 3 0 3 2 1 3 2 0 0 0 3 3 3 2 0 2 2], shape=(32,), dtype=int32)
5、数据配置
原理请看第一大点中有讲解。
from tensorflow.data.experimental import AUTOTUNE
AUTOTUNE = tf.data.experimental.AUTOTUNE
# buffer_size:缓冲区大小
train_ds = train_ds.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE)
vals_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)
2、网络构建
由于数据集少,故本模型用的模型层数少,一共由3层卷积、2层池化、1层dropout层、2层全连接层组成。
model = models.Sequential([
# 将像素从[0, 255] --> [0, 1]
layers.experimental.preprocessing.Rescaling(1./255, input_shape=(224, 224, 3)),
# 卷积层、池化层
layers.Conv2D(16, (3, 3), activation='relu', input_shape=(224, 224, 3)), # 卷积核 3 * 3
layers.AveragePooling2D((2, 2)),
layers.Conv2D(32, (3, 3), activation='relu'),
layers.AveragePooling2D((2, 2)),
layers.Conv2D(64, (3, 3), activation='relu'),
# dropout层
layers.Dropout(0.3),
# 全连接从层
layers.Flatten(),
layers.Dense(128, activation='relu'),
layers.Dense(len(class_names))
])
# 打印模型参数
model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
rescaling (Rescaling) (None, 224, 224, 3) 0
_________________________________________________________________
conv2d (Conv2D) (None, 222, 222, 16) 448
_________________________________________________________________
average_pooling2d (AveragePo (None, 111, 111, 16) 0
_________________________________________________________________
conv2d_1 (Conv2D) (None, 109, 109, 32) 4640
_________________________________________________________________
average_pooling2d_1 (Average (None, 54, 54, 32) 0
_________________________________________________________________
conv2d_2 (Conv2D) (None, 52, 52, 64) 18496
_________________________________________________________________
dropout (Dropout) (None, 52, 52, 64) 0
_________________________________________________________________
flatten (Flatten) (None, 173056) 0
_________________________________________________________________
dense (Dense) (None, 128) 22151296
_________________________________________________________________
dense_1 (Dense) (None, 4) 516
=================================================================
Total params: 22,175,396
Trainable params: 22,175,396
Non-trainable params: 0
_________________________________________________________________
3、模型训练
1、超参数设置
# 优化器
opt = tf.keras.optimizers.Adam(learning_rate=0.001) # 学习率:0.001
# 设置超参数
model.compile(optimizer=opt,
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
2、模型训练
epoches = 10
result = model.fit(
x = train_ds,
validation_data=val_ds,
epochs = epoches
)
Epoch 1/10
29/29 [==============================] - 17s 577ms/step - loss: 1.4328 - accuracy: 0.6056 - val_loss: 0.6638 - val_accuracy: 0.7067
Epoch 2/10
29/29 [==============================] - 17s 577ms/step - loss: 0.5417 - accuracy: 0.7789 - val_loss: 0.5179 - val_accuracy: 0.8000
Epoch 3/10
29/29 [==============================] - 16s 536ms/step - loss: 0.4496 - accuracy: 0.8267 - val_loss: 0.6159 - val_accuracy: 0.7467
Epoch 4/10
29/29 [==============================] - 14s 475ms/step - loss: 0.3856 - accuracy: 0.8456 - val_loss: 0.4435 - val_accuracy: 0.8578
Epoch 5/10
29/29 [==============================] - 15s 517ms/step - loss: 0.2932 - accuracy: 0.8789 - val_loss: 0.4393 - val_accuracy: 0.8400
Epoch 6/10
29/29 [==============================] - 15s 531ms/step - loss: 0.2014 - accuracy: 0.9278 - val_loss: 0.3550 - val_accuracy: 0.8844
Epoch 7/10
29/29 [==============================] - 16s 548ms/step - loss: 0.1977 - accuracy: 0.9222 - val_loss: 0.6002 - val_accuracy: 0.8089
Epoch 8/10
29/29 [==============================] - 15s 509ms/step - loss: 0.2144 - accuracy: 0.9122 - val_loss: 0.5215 - val_accuracy: 0.8489
Epoch 9/10
29/29 [==============================] - 14s 496ms/step - loss: 0.1975 - accuracy: 0.9211 - val_loss: 0.3932 - val_accuracy: 0.8800
Epoch 10/10
29/29 [==============================] - 16s 542ms/step - loss: 0.1055 - accuracy: 0.9589 - val_loss: 0.4329 - val_accuracy: 0.8756
4、模型效果展示
# 获取训练集和验证集损失率和准确率
acc = result.history['accuracy']
val_acc = result.history['val_accuracy']
loss = result.history['loss']
val_loss = result.history['val_loss']
epochs_range = range(epoches)
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()
准确率:
- 测试集准确率很好,验证集接近0.9,且有上升趋势,效果很好;
损失率:
- 测试集损失率次序降低,但是验证集损失率较高,说明模型泛化能力有待提高,当然这也跟数据集有关,数据集比较小,也有可能和网络结构有关,网络结构比较简单;