tensorflow案例7--数据增强与测试集, 训练集, 验证集的构建

前言

  • 这次主要是学习数据增强, 训练集 验证集 测试集的构建等等的基本方法 , 数据集还是用的上一篇的猫狗识别;
  • 基础篇还剩下几个, 后面的难度会逐步提升;
  • 欢迎收藏 + 关注, 本人会持续更新.

文章目录

  • [1. 简介](#1. 简介)
  • [2. 案例测试](#2. 案例测试)
    • [1. 数据处理](#1. 数据处理)
      • [1. 导入库](#1. 导入库)
      • [2. 导入数据(训练集 测试集 验证集)](#2. 导入数据(训练集 测试集 验证集))
      • [3. 数据部分展示](#3. 数据部分展示)
      • [4. 数据归一化与内存加速](#4. 数据归一化与内存加速)
      • [5. 数据增强](#5. 数据增强)
      • [6. 将增强数据融合到原始数据中](#6. 将增强数据融合到原始数据中)
    • [2. 模型创建](#2. 模型创建)
    • [3. 模型训练](#3. 模型训练)
      • [1. 超参数设置](#1. 超参数设置)
      • [2. 模型训练](#2. 模型训练)
      • [3. 模型测试](#3. 模型测试)
    • [4. 其他方法增强数据](#4. 其他方法增强数据)

1. 简介

数据增强

💙 有时候数据很好, **就可以通过在原有的基础上做一些操作, ** 从而增加数据的数量, 使训练模型更加有效.

📶 对于基础的的增强 , 一般就是旋转, 在pytorch中一般是用transforms.Compose进行处理, 在tensorflow中,一般用的是tf.keras.layers.experimental.preprocessing.RandomFliptf.keras.layers.experimental.preprocessing.RandomRotation 进行数据增强, 👁 具体做法请看案例

当然还有其他的方法进行增强, 比如说添加噪音 , 👓 详情请看第四节, 4. 其他方法数据增强

数据增强加入模型中

一般有两个方法:

  1. 加入数据集(本文用的方法)
  2. 加入到模型中, 让模型训练的时候, 开始进行数据增强, 这个本文不介绍

注意: tensorflow和numpy 版本问题不同, 可能会出现比较多数据方面的错误, 本人这个案例最后也是在云平台上跑通的.

训练集划分

简单说一下训练集, 测试集, 验证集的区别:

  • 训练集: 用来训练模型的, 确定神经网络的各种参数, 相当于我们学习一样
  • 验证集: 在训练集中, 通过验证模型效果, 来调整模型参数, 这个就相当于我们月考一样
  • 测试集: 这个就是验证模型是都具有效果, 适用于其他数据, 这个就相当于我们大考

👀 在tensorflow中, 我们可以通过tf.keras.preprocessing.image_dataset_from_directory创建训练集和验证集, 但是不能创建测试集, 创建测试集的方法, 需要我们后面对数据进行分类, 如下:

python 复制代码
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. 导入库

python 复制代码
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)   # 输出存储在GPU
    tf.config.set_visible_devices([gpu0], "GPU")          # 选择第一块GPU
    
gpus
复制代码
[PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]

2. 导入数据(训练集 测试集 验证集)

python 复制代码
# 查看数据目录
import os, pathlib

data_dir = "./data/"
data_dir = pathlib.Path(data_dir)

classnames = [str(path) for path in os.listdir(data_dir)]
classnames
复制代码
['cat', 'dog']
python 复制代码
# 创建训练集和验证集

batch_size = 32
image_width, image_height = 224, 224

train_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没有提供直接分割测试集的函数,但是可以通过分割验证集的方法进行创建测试集

python 复制代码
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. 数据部分展示

python 复制代码
# 数据规格展示
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)
python 复制代码
# 部分图片数据展示
import matplotlib.pyplot as plt

train_one_batch = next(iter(train_ds))

plt.figure(figsize=(20, 10))

images, labels = train_one_batch

for 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. 数据归一化与内存加速

python 复制代码
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.RandomFliptf.keras.layers.experimental.preprocessing.RandomRotation 进行数据增强.

  • tf.keras.layers.experimental.preprocessing.RandomFlip:水平和垂直随机翻转每个图像.
  • tf.keras.layers.experimental.preprocessing.RandomRotation:随机旋转每个图像.
python 复制代码
# 封装整合
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. 将增强数据融合到原始数据中

python 复制代码
batch_size = 32
AUTOTUNE = tf.data.AUTOTUNE

def 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. 模型创建

python 复制代码
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. 超参数设置

python 复制代码
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. 模型训练

python 复制代码
epochs=20

history = 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. 模型测试

python 复制代码
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. 其他方法增强数据

这里是使数据变得模糊

python 复制代码
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
python 复制代码
# 随机选取一张照片
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"))


相关推荐
文心快码BaiduComate10 分钟前
百度云与光本位签署战略合作:用AI Agent 重构芯片研发流程
前端·人工智能·架构
风象南1 小时前
Claude Code这个隐藏技能,让我告别PPT焦虑
人工智能·后端
曲幽1 小时前
FastAPI压力测试实战:Locust模拟真实用户并发及优化建议
python·fastapi·web·locust·asyncio·test·uvicorn·workers
Mintopia2 小时前
OpenClaw 对软件行业产生的影响
人工智能
陈广亮2 小时前
构建具有长期记忆的 AI Agent:从设计模式到生产实践
人工智能
会写代码的柯基犬2 小时前
DeepSeek vs Kimi vs Qwen —— AI 生成俄罗斯方块代码效果横评
人工智能·llm
Mintopia3 小时前
OpenClaw 是什么?为什么节后热度如此之高?
人工智能
爱可生开源社区3 小时前
DBA 的未来?八位行业先锋的年度圆桌讨论
人工智能·dba
叁两6 小时前
用opencode打造全自动公众号写作流水线,AI 代笔太香了!
前端·人工智能·agent
敏编程6 小时前
一天一个Python库:jsonschema - JSON 数据验证利器
python