- 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
- 🍖 原作者:K同学啊
前言
- 这次主要是学习数据增强, 训练集 验证集 测试集的构建等等的基本方法, 数据集还是用的上一篇的猫狗识别;
- 基础篇还剩下几个, 后面的难度会逐步提升;
- 欢迎收藏 + 关注, 本人会持续更新.
文章目录
- 1. 简介
- 数据增强
- 训练集划分
- 2. 案例测试
- 1. 数据处理
- 1. 导入库
- 2. 导入数据(训练集 测试集 验证集)
- 3. 数据部分展示
- 4. 数据归一化与内存加速
- 5. 数据增强
- 6. 将增强数据融合到原始数据中
- 2. 模型创建
- 3. 模型训练
- 1. 超参数设置
- 2. 模型训练
- 3. 模型测试
- 4. 其他方法增强数据
1. 简介
数据增强
💙 有时候数据很好, **就可以通过在原有的基础上做一些操作, ** 从而增加数据的数量, 使训练模型更加有效.
📶 对于基础的的增强, 一般就是旋转, 在pytorch
中一般是用transforms.Compose
进行处理, 在tensorflow
中,一般用的是tf.keras.layers.experimental.preprocessing.RandomFlip
与 tf.keras.layers.experimental.preprocessing.RandomRotation
进行数据增强, 👁 具体做法请看案例
当然还有其他的方法进行增强, 比如说添加噪音, 👓 详情请看第四节, 4. 其他方法数据增强
数据增强加入模型中
一般有两个方法:
- 加入数据集(本文用的方法)
- 加入到模型中, 让模型训练的时候, 开始进行数据增强, 这个本文不介绍
注意: tensorflow和numpy版本问题不同, 可能会出现比较多数据方面的错误, 本人这个案例最后也是在云平台上跑通的.
训练集划分
简单说一下训练集, 测试集, 验证集的区别:
- 训练集: 用来训练模型的, 确定神经网络的各种参数, 相当于我们学习一样
- 验证集: 在训练集中, 通过验证模型效果, 来调整模型参数, 这个就相当于我们月考一样
- 测试集: 这个就是验证模型是都具有效果, 适用于其他数据, 这个就相当于我们大考
👀 在tensorflow
中, 我们可以通过tf.keras.preprocessing.image_dataset_from_directory
创建训练集和验证集, 但是不能创建测试集, 创建测试集的方法, 需要我们后面对数据进行分类, 如下:
val_batches = tf.data.experimental.cardinality(val_ds)
# 创建测试集, 方法: 将验证集合拆成 5 分, 测试集占一份, 验证集占 4 份
test_ds = val_ds.take(val_batches // 2) # 取前 * 批次
val_ds = val_ds.skip(val_batches // 2) # 除了前 * 批次
解释:
tf.data.experimental.cardinality
获取数据批次大小.take
: 取前n批数据.skip
: 取除了前n批次数据
2. 案例测试
本次案例是对猫狗图像进行分类, 和上一期很像, 但是这个模型使用比较简单.
注意: 不同池化层, 效果有时候天差地别, 比如说: 这个案例用的是最大池化, 但是用平均池化的话, 效果极差
1. 数据处理
1. 导入库
import tensorflow as tf
from tensorflow.keras import layers, models, datasets
import numpy as np gpus = tf.config.list_physical_devices("GPU")if gpus:gpu0 = gpus[0]tf.config.experimental.set_memory_growth(gpu0, True) # 输出存储在GPUtf.config.set_visible_devices([gpu0], "GPU") # 选择第一块GPUgpus
[PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]
2. 导入数据(训练集 测试集 验证集)
# 查看数据目录
import os, pathlibdata_dir = "./data/"
data_dir = pathlib.Path(data_dir)classnames = [str(path) for path in os.listdir(data_dir)]
classnames
['cat', 'dog']
# 创建训练集和验证集batch_size = 32
image_width, image_height = 224, 224train_ds = tf.keras.preprocessing.image_dataset_from_directory('./data/',subset='training',validation_split=0.3,batch_size=batch_size,image_size=(image_width, image_height),shuffle=True,seed=42
)val_ds = tf.keras.preprocessing.image_dataset_from_directory('./data',subset='validation',validation_split=0.3,batch_size=batch_size,image_size=(image_width, image_height),shuffle=True,seed=42
)
Found 600 files belonging to 2 classes.
Using 420 files for training.
Found 600 files belonging to 2 classes.
Using 180 files for validation.
在tensorflow没有提供直接分割测试集的函数,但是可以通过分割验证集的方法进行创建测试集
val_batches = tf.data.experimental.cardinality(val_ds)
# 创建测试集, 方法: 将验证集合拆成 5 分, 测试集占一份, 验证集占 4 份
test_ds = val_ds.take(val_batches // 2) # 取前 * 批次
val_ds = val_ds.skip(val_batches // 2) # 取除了前 * 批次print("test batches: %d"%tf.data.experimental.cardinality(test_ds))
print("val batches: %d"%tf.data.experimental.cardinality(val_ds))
test batches: 3
val batches: 3
训练集: 验证集: 测试集 = 0.7 : 0.15 : 0.15
3. 数据部分展示
# 数据规格展示
for images, labels in train_ds.take(1):print("image: [N, W, H, C] ", images.shape)print("labels: ", labels)break
image: [N, W, H, C] (32, 224, 224, 3)
labels: tf.Tensor([0 1 1 0 0 0 1 0 0 0 0 1 0 1 0 0 0 1 1 1 1 0 1 1 0 1 1 0 1 0 1 0], shape=(32,), dtype=int32)
# 部分图片数据展示
import matplotlib.pyplot as plttrain_one_batch = next(iter(train_ds))plt.figure(figsize=(20, 10))images, labels = train_one_batchfor i in range(20):plt.subplot(5, 10, i + 1)plt.title(classnames[labels[i]])plt.imshow(images[i].numpy().astype('uint8'))plt.axis('off')plt.show()
4. 数据归一化与内存加速
from tensorflow.data.experimental import AUTOTUNE # 像素归一化, ---> [0, 1]
normalization_layer = layers.experimental.preprocessing.Rescaling(1.0 / 255)# 训练集、测试集像素归一化
train_ds = train_ds.map(lambda x, y : (normalization_layer(x), y))
val_ds = val_ds.map(lambda x, y : (normalization_layer(x), y))
test_ds = test_ds.map(lambda x, y : (normalization_layer(x), y))# 设置内存加速
AUTOTUNE = tf.data.experimental.AUTOTUNE # 打乱顺序加速, 测试集就不必了哈
train_ds = train_ds.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)
5. 数据增强
我们可以使用 tf.keras.layers.experimental.preprocessing.RandomFlip
与 tf.keras.layers.experimental.preprocessing.RandomRotation
进行数据增强.
tf.keras.layers.experimental.preprocessing.RandomFlip
:水平和垂直随机翻转每个图像.tf.keras.layers.experimental.preprocessing.RandomRotation
:随机旋转每个图像.
# 封装整合
data_augmentation = tf.keras.Sequential([tf.keras.layers.experimental.preprocessing.RandomFlip("horizontal_and_vertical"), # 垂直和水平反转tf.keras.layers.experimental.preprocessing.RandomRotation(0.2) # 随机翻转
])test_datas = next(iter(train_ds))test_images, test_labels = test_datas# 随机选取一个
test_image = tf.expand_dims(test_images[i], 0)plt.figure(figsize=(8, 8))
for i in range(9):augmented_image = data_augmentation(test_image) # 旋转ax = plt.subplot(3, 3, i + 1)plt.imshow(augmented_image[0]) plt.axis("off")
6. 将增强数据融合到原始数据中
batch_size = 32
AUTOTUNE = tf.data.AUTOTUNEdef prepare(ds):ds = ds.map(lambda x, y: (data_augmentation(x, training=True), y), num_parallel_calls=AUTOTUNE)return ds# 增强
train_ds = prepare(train_ds)
2. 模型创建
model = models.Sequential([# 第一层要输入维度layers.Conv2D(16, (3, 3), activation='relu', input_shape=(image_width, image_height, 3)),layers.MaxPooling2D((2,2)),layers.Conv2D(32, (3, 3), activation='relu'),layers.MaxPooling2D((2,2)),layers.Dropout(0.3),layers.Conv2D(32, (3, 3), activation='relu'),layers.MaxPooling2D((2,2)),layers.Dropout(0.3),layers.Flatten(),layers.Dense(128, activation='relu'),layers.Dense(len(classnames))
])model.summary()
Model: "sequential_1"
_________________________________________________________________Layer (type) Output Shape Param #
=================================================================conv2d (Conv2D) (None, 222, 222, 16) 448 max_pooling2d (MaxPooling2D (None, 111, 111, 16) 0 ) conv2d_1 (Conv2D) (None, 109, 109, 32) 4640 max_pooling2d_1 (MaxPooling (None, 54, 54, 32) 0 2D) dropout (Dropout) (None, 54, 54, 32) 0 conv2d_2 (Conv2D) (None, 52, 52, 32) 9248 max_pooling2d_2 (MaxPooling (None, 26, 26, 32) 0 2D) dropout_1 (Dropout) (None, 26, 26, 32) 0 flatten (Flatten) (None, 21632) 0 dense (Dense) (None, 128) 2769024 dense_1 (Dense) (None, 2) 258 =================================================================
Total params: 2,783,618
Trainable params: 2,783,618
Non-trainable params: 0
_________________________________________________________________
3. 模型训练
1. 超参数设置
opt = tf.keras.optimizers.Adam(learning_rate=0.001) # 学习率:0.001model.compile(optimizer = opt,loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),metrics = ['accuracy']
)
2. 模型训练
epochs=20history = model.fit(train_ds,validation_data=val_ds,epochs=epochs,verbose=1
)
Epoch 1/20
2024-11-22 18:03:21.866630: I tensorflow/stream_executor/cuda/cuda_dnn.cc:384] Loaded cuDNN version 8101
2024-11-22 18:03:23.553540: I tensorflow/stream_executor/cuda/cuda_blas.cc:1786] TensorFloat-32 will be used for the matrix multiplication. This will only be logged once.
14/14 [==============================] - 4s 36ms/step - loss: 0.7059 - accuracy: 0.5643 - val_loss: 0.6646 - val_accuracy: 0.6667
Epoch 2/20
14/14 [==============================] - 0s 27ms/step - loss: 0.6125 - accuracy: 0.6381 - val_loss: 0.6096 - val_accuracy: 0.7143
Epoch 3/20
14/14 [==============================] - 0s 15ms/step - loss: 0.5027 - accuracy: 0.7714 - val_loss: 0.5646 - val_accuracy: 0.7500
Epoch 4/20
14/14 [==============================] - 0s 14ms/step - loss: 0.4723 - accuracy: 0.7952 - val_loss: 0.5496 - val_accuracy: 0.7500
Epoch 5/20
14/14 [==============================] - 0s 14ms/step - loss: 0.4395 - accuracy: 0.7857 - val_loss: 0.6267 - val_accuracy: 0.7024
Epoch 6/20
14/14 [==============================] - 0s 13ms/step - loss: 0.3721 - accuracy: 0.8262 - val_loss: 0.5001 - val_accuracy: 0.7619
Epoch 7/20
14/14 [==============================] - 0s 14ms/step - loss: 0.4041 - accuracy: 0.8238 - val_loss: 0.4595 - val_accuracy: 0.7857
Epoch 8/20
14/14 [==============================] - 0s 13ms/step - loss: 0.3195 - accuracy: 0.8643 - val_loss: 0.4247 - val_accuracy: 0.8095
Epoch 9/20
14/14 [==============================] - 0s 13ms/step - loss: 0.3010 - accuracy: 0.8738 - val_loss: 0.3674 - val_accuracy: 0.8452
Epoch 10/20
14/14 [==============================] - 0s 14ms/step - loss: 0.3190 - accuracy: 0.8762 - val_loss: 0.3660 - val_accuracy: 0.8452
Epoch 11/20
14/14 [==============================] - 0s 15ms/step - loss: 0.2864 - accuracy: 0.8690 - val_loss: 0.3529 - val_accuracy: 0.8333
Epoch 12/20
14/14 [==============================] - 0s 13ms/step - loss: 0.2532 - accuracy: 0.8762 - val_loss: 0.2737 - val_accuracy: 0.8929
Epoch 13/20
14/14 [==============================] - 0s 13ms/step - loss: 0.2374 - accuracy: 0.9000 - val_loss: 0.2939 - val_accuracy: 0.8810
Epoch 14/20
14/14 [==============================] - 0s 15ms/step - loss: 0.2216 - accuracy: 0.8976 - val_loss: 0.2952 - val_accuracy: 0.8810
Epoch 15/20
14/14 [==============================] - 0s 13ms/step - loss: 0.2365 - accuracy: 0.9095 - val_loss: 0.2559 - val_accuracy: 0.9167
Epoch 16/20
14/14 [==============================] - 0s 13ms/step - loss: 0.2114 - accuracy: 0.9071 - val_loss: 0.2702 - val_accuracy: 0.8929
Epoch 17/20
14/14 [==============================] - 0s 15ms/step - loss: 0.2075 - accuracy: 0.9024 - val_loss: 0.2353 - val_accuracy: 0.9286
Epoch 18/20
14/14 [==============================] - 0s 13ms/step - loss: 0.1850 - accuracy: 0.9262 - val_loss: 0.1927 - val_accuracy: 0.9524
Epoch 19/20
14/14 [==============================] - 0s 13ms/step - loss: 0.1318 - accuracy: 0.9524 - val_loss: 0.1837 - val_accuracy: 0.9286
Epoch 20/20
14/14 [==============================] - 0s 15ms/step - loss: 0.1561 - accuracy: 0.9476 - val_loss: 0.1951 - val_accuracy: 0.9643
3. 模型测试
loss, acc = model.evaluate(test_ds)
print("Loss: ", loss)
print("Accuracy: ", acc)
3/3 [==============================] - 0s 8ms/step - loss: 0.2495 - accuracy: 0.9062
Loss: 0.24952644109725952
Accuracy: 0.90625
测试集准确率高, 模型效果良好
4. 其他方法增强数据
这里是使数据变得模糊
import random def aug_img(image):seed = (random.randint(0, 9), 0)stateless_random_brightness = tf.image.stateless_random_contrast(image, lower=0.1, upper=1.0, seed=seed)return stateless_random_brightness
# 随机选取一张照片
image = tf.expand_dims(test_images[i] * 255, 0) # 注意: 不乘255, 会出现黑色, 因为 像素在0 - 1中plt.figure(figsize=(8,8))
for i in range(9):image_show = aug_img(image)plt.subplot(3, 3, i + 1)plt.imshow(image_show[0].numpy().astype("uint8"))