365天深度学习训练营-第T6周:好莱坞明星识别

  •   本文为365天深度学习训练营 中的学习记录博客
  • 原作者:K同学啊

 我的环境:

  • 语言环境:Python3.10.7
  • 编译器:VScode
  • 深度学习环境:TensorFlow2

 一、前期工作: 

1、导入数据集

import os, PIL, pathlib
import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, models
import matplotlib.pyplot as plt

data_dir = "D:\T6star"
print(type(data_dir))
data_dir = pathlib.Path(data_dir)
print(type(data_dir))

data_dir = pathlib.Path(data_dir)这行代码的作用是将一个字符串路径转换为`pathlib`模块中的`Path`对象。`Path`对象提供了一组方法来操作文件路径,例如访问文件名、父目录、文件扩展名等。

通过将字符串路径转换为`Path`对象,可以更方便地进行路径操作,例如拼接路径、创建文件或目录、检查路径是否存在等。`Path`对象还提供了一些便捷的方法来处理文件和目录,例如复制文件、删除文件、遍历目录等。

将`data_dir`字符串转换为`Path`对象后,可以使用`Path`对象的方法来执行与路径相关的操作,例如:

- `data_dir.name`:获取路径中的文件名
- `data_dir.parent`:获取路径中的父目录
- `data_dir.exists()`:检查路径是否存在
- `data_dir.mkdir()`:创建目录
- `data_dir.is_file()`:检查路径是否为文件
- `data_dir.is_dir()`:检查路径是否为目录

通过使用`Path`对象可以更方便地处理文件路径,并执行各种文件和目录操作,而无需手动解析字符串路径。

运行结果: 

 

 2.查看图片数量

image_count = len(list(data_dir.glob("*/*.jpg")))
print("图片数目:", image_count)

运行结果:

3.查看测试图片

roses = list(data_dir.glob("Jennifer Lawrence/*.jpg"))
image_path = str(roses[0])
 
# Open the image using PIL
image = PIL.Image.open(image_path)
 
# Display the image using matplotlib
plt.imshow(image)
plt.axis("off") 
plt.show()

 

运行结果:

365天深度学习训练营-第T6周:好莱坞明星识别_第1张图片

 二、数据预处理 :

1.格式设置、划分训练集及数据集、图片标签展示

#设施图片格式
batch_size = 32
img_height = 224
img_width = 224
 
#划分训练集
#train_ds = tf.keras.preprocessing.image_dataset_from_directory(
#    "D:\T6star",
#    seed = 123,
#    image_size = (img_height, img_width),
#    batch_size = batch_size)

train_ds = tf.keras.preprocessing.image_dataset_from_directory(
    data_dir,
    validation_split = 0.1,
    subset = "training",
    label_mode = "categorical",
    seed = 123,
    image_size = (img_height, img_width),
    batch_size = batch_size
)

 
#划分验证集
#val_ds = tf.keras.preprocessing.image_dataset_from_directory(
#    "D:\T6star",
#    seed = 123,
#    image_size = (img_height, img_width),
#    batch_size = batch_size
#)

val_ds = tf.keras.preprocessing.image_dataset_from_directory(
    data_dir,
    validation_split = 0.1,
    subset = "validation",
    label_mode = "categorical",
    seed = 123,
    image_size = (img_height, img_width),
    batch_size = batch_size
)

 
#查看标签
class_names = train_ds.class_names
print(class_names)
 

 运行结果:

 

 2.数据可视化

#数据可视化
plt.figure(figsize = (20, 10))
 
for images, labels in train_ds.take(1):
  for i in range(20):
    plt.subplot(5, 10, i + 1)
    plt.imshow(images[i].numpy().astype("uint8"))
    plt.title(class_names[labels[i]])
    plt.axis("off")
plt.show()

plt.figure(figsize = (20, 10)) 创建一个图形对象,并指定其大小为20x10英寸

for images, labels in train_ds.take(1): 遍历train_ds数据集中的第一个批次,每个批次包含一批图和对应的标签。这里使用take(1)函数从数据集中获取一个批次。

plt.subplot(5, 10, i +1) 在图形对象中创建一个子图,这里的子图是一个5x10的网格,并将当前子图设置为第i+1个位置。

 plt.imshow(images[i].numpy().astype("uint8")) 使用Matplotlib的imshow函数显示当前图像。images[i]是当前图像的张量表示,使用.numpy()将其转换为NumPy数组,并使用.astype("uint8")将数据类型转换为uint8以便显示。

plt.title(class_names[labels[i]]) 为当前图像设置标题,标题内容是通过索引labels[i]从class_names列表中获取的类别名称。

plt.axis(“off”) 是 Matplotlib 库中的一个函数调用,它用于控制图像显示时的坐标轴是否可见。
具体来说,当参数为 “off” 时,图像的坐标轴会被关闭,不会显示在图像周围。这个函数通常在 plt.imshow() 函数之后调用,以便在显示图像时去掉多余的细节信息,仅仅显示图像本身。
运行结果:

 3.检验数据、配置数据

#检验数据
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)

配置数据集的预处理和性能优化:

tf.data.AUTOTUNE常量,它的作用是自动选择合适的数值作为性能优化参数,以充分利用可用的系统资源。

`train_ds`和`val_ds`是训练集和验证集的数据集对象,在上述段代码中,以下操作被应用于这两个数据集:

1. `.cache()`该方法将数据集缓存到内存中或本地磁盘上,以便在训练过程中快速重用数据。这可以提高训练效率,特别是当数据集无法一次性全部加载到内存时。
2. `.shuffle(1000)`该方法对数据集进行随机化操作,打乱样本的顺序。参数`1000`表示要使用的缓冲区大小,它定义了打乱操作所使用的元素数量。这有助于使训练更具随机性,提高模型的泛化能力。
3. `.prefetch(buffer_size=AUTOTUNE)`该方法用于数据集的预取操作。参数`buffer_size`指定了要预取的元素数量。`AUTOTUNE`常量的值由之前定义的`tf.data.AUTOTUNE`决定,它会自动根据可用的系统资源动态选择合适的缓冲区大小,以加速数据加载。这样,当模型在训练时,预取操作可以在后台异步加载数据,从而减少模型等待数据的时间。

通过这些数据集配置操作,可以在训练过程中加速数据加载和预处理,从而提高训练的效率,并确保数据集在训练过程中始终提供足够的数据供应给模型。

三、搭建CNN网络

#设置Sequential模型,创建神经网络
model = models.Sequential([
    layers.experimental.preprocessing.Rescaling(1./ 255, input_shape = (img_height, img_width, 3)),
    #定义了一个图像预处理层,即 Rescaling 层。该层会将图像的像素值缩放到 [0, 1] 之间,以便模型更好地学习图像特征。
    #其中,1. / 255 是缩放的因子,input_shape 则是可选参数,用于指定输入图像的大小。

    #由于神经网络算法通常对输入数据有一定的要求(如数据必须位于同一尺度或范围内),因此在训练神经网络之前,通常需要对输入数据进行预处理。
    #在这个例子中,将图像的像素值除以 255,可以将像素值缩放到 [0, 1] 范围内。这样做不仅可以提高模型训练的效果,还可以加速模型训练的收敛。

    layers.Conv2D(16, (3, 3), activation = "relu", input_shape = (img_height, img_width)),
    layers.AveragePooling2D((2, 2)),
    layers.Conv2D(32, (3, 3), activation = "relu"),
    layers.AveragePooling2D((2, 2)),
    layers.Dropout(0.5),
    layers.Conv2D(64, (3, 3), activation = "relu"),
    layers.AveragePooling2D((2, 2)),
    layers.Dropout(0.5),
    layers.Conv2D(128, (3, 3), activation = "relu"),
    #layers.AveragePooling2D((2, 2)),
    layers.Dropout(0.5),

    layers.Flatten(),
    layers.Dense(128, activation = "relu"),
    layers.Dense(len(class_names))
])

model.summary()

运行结果:

  四、编译 

#设置动态学习率
initial_learning_rate = 1e-4
lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(
    initial_learning_rate,
    decay_steps = 30,
    decay_rate = 0.92,
    staircase = True
)
 
#设置优化器
opt = keras.optimizers.Adam(learning_rate=lr_schedule)
model.compile(
    #设置优化器为Adam优化器
    optimizer = opt,
    #设置损失函数为交叉熵损失函数
    loss = keras.losses.SparseCategoricalCrossentropy(from_logits=True),
    #设置性能指标列表,将在模型训练时对列表中的指标进行监控
    metrics = ['accuracy']
)

from_logits 参数是用于控制模型的输出是否经过概率转换。

from_logits=True 时,表示模型的输出没有经过概率转换,即模型的输出是未经归一化的原始值。这通常适用于模型的最后一层没有经过 softmax 函数的情况。在这种情况下,训练过程中会应用 softmax 函数来将输出转换为概率分布,并计算交叉熵损失。

from_logits=False 时,表示模型的输出已经经过了概率转换,即模型的输出已经是一个概率分布。这通常适用于模型的最后一层已经经过 softmax 函数的情况。在这种情况下,训练过程中不会再应用 softmax 函数,而是直接使用模型输出的概率分布与标签计算交叉熵损失。

损失函数Loss详解:
1. binary_ crossentropy (对数损失函数)
与sigmoid相对应的损失函数,针对于二分类问题。

2. categorical crossentropy (多分类的对数损失函数)
与softmax相对应的损失函数,如果是one -hot编码,则使用
categorical_ crossentropy 

3. sparse_ categorical crossentropy (稀疏性多分类的对数损失函数)
与 softmax相对应的损失函数,如果是整数编码,则使用sparse_ categorical_ crossentropy

函数原型
1 tf .keras .losses .SparseCategoricalCrossentropy(
from_logits=False,
reduction=losses_utils. ReductionV2. AUTO,
name=' sparse_categorical_ crossentropy'
)
参数说明: .
from_logits :为True时,会将y_pred转化为概率 (用softmax) ,否则不进行转换,通常情况下用True结果更稳定;
reduction :类型为tf.keras.losses. Reduction,对loss进行处理,默认是AUTO;
name : name

通过指数衰减学习率,初始学习率为 `0.0001`,每经过 `30` 步衰减一次,衰减率为 `0.92`,并且采用阶梯函数进行衰减。调度器对象 `lr_schedule` 可以在训练过程中根据指定的规则自动调整学习率。

学习率大与学习率小的优缺点分析:
学习率大
优点:
。1、加快学习速率。
。2、有助于跳出局部最优值。
●缺点:
。1、 导致模型训练不收敛。
0 2、单单使用大学习率容易导致模型不精确。
学习率小.
优点:
。1、有助于模型收敛、模型细化。
0 2、提高模型精度。
● 缺点:
。1、很难跳出局部最优值。
。2、收敛缓慢。

这里设置的动态学习率为:指数衰减型(ExponentialDecay) 。在每一-个epoch开始前, 学习率
(learning_ rate) 都将会重置为初始学习率(initial. _learning. rate),然后再重新开始衰减。计算公式如下: 

learning_ rate = initial. learning. _rate * decay_ rate ^ (step / decay_ steps) 

五、训练模型

#模型训练 早停与保存最佳模型参数
from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping

epochs = 100

checkpoint = 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
                )

history = model.fit(
    train_ds,
    validation_data = val_ds,
    epochs = epochs,
    callbacks = [checkpoint, earlystopper]
)

代码添加了一个新的回调函数 `EarlyStopping`,用于在训练过程中实现早停(early stopping)机制。

`EarlyStopping` 是 Keras 中的一个回调函数,它监视指定的指标(在这个例子中是验证准确率 `'val_accuracy'`),并根据预先设置的条件来判断是否停止训练。

参数解释如下:

monitor:要监视的指标,这里是验证准确率。
min_delta:用于定义要监视指标的最小变化量,当指标的变化小于该值时,将被视为没有进一步改进。
patience:允许没有进一步改进的训练轮数的数量。如果在连续的 `patience` 轮中没有进一步改进,则训练将提前停止。
verbose:控制是否显示早停信息的详细程度,设为 `1` 表示显示信息。

在训练过程中,当验证准确率不再改进或改进量非常小(小于 `min_delta`)时,`EarlyStopping` 回调函数会触发停止训练的操作,从而防止模型过拟合或在不再有进一步改进时继续训练。

将 EarlyStopping 回调函数添加到 callbacks 列表中,如下所示:
callbacks = [checkpointer, earlystopper]

callbacks 列表是在模型训练过程中使用的回调函数的集合。

在机器学习中,回调函数是一种机制,可以在训练过程中的不同阶段执行特定的操作。这些操作可以包括保存模型、记录指标、调整学习率、可视化训练进度等。

在 Keras 中,可以通过创建回调函数对象并将其添加到 `callbacks` 列表中来定义和配置这些操作。在模型的训练过程中,Keras 将自动调用这些回调函数,并在合适的时间点执行相应的操作。

常见的回调函数包括:

- `ModelCheckpoint`:用于保存模型的权重或整个模型的回调函数。
- `EarlyStopping`:在验证指标不再改进时提前停止训练的回调函数。
- `TensorBoard`:用于将训练指标和可视化图表保存为 TensorBoard 日志的回调函数。
- `ReduceLROnPlateau`:在验证指标不再改进时降低学习率的回调函数。

通过使用回调函数,可以在模型训练过程中实现更复杂的功能和控制,以提高模型的性能和训练效果。将这些回调函数添加到 `callbacks` 列表中,传递给 `model.fit()` 方法,就可以在训练过程中执行相应的操作。

在例程中callbacks = [checkpointer, earlystopper]除了保存模型权重外,还会检查验证准确率是否满足早停的条件,以便在适当的时候停止训练。

365天深度学习训练营-第T6周:好莱坞明星识别_第2张图片

 六、模型评估

1.Loss和Acc图

#模型评估
loss = history.history['loss']
val_loss = history.history['val_loss']
 
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
 
epochs_range = range(len(loss))
 
plt.figure(figsize = (12, 4))
 
plt.subplot(1, 2, 1)
plt.plot(epochs_range, acc, label = "Training Acc")
plt.plot(epochs_range, val_acc, label = "Validation Acc")
plt.legend(loc = 'lower right')
plt.title("Training And Validation Acc")
 
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()

运行结果: 

365天深度学习训练营-第T6周:好莱坞明星识别_第3张图片

2.指定结果进行预测

model.load_weights('best_model.h5')
from PIL import Image
import numpy as np
img = Image.open("D:/T6star/Hugh Jackman/001_9adc92c2.jpg") 
image = tf.image.resize(img, [img_height, img_width]) 
img_array = tf.expand_dims(image, 0)
predictions = model.predict(img_array)
#这个函数用于对输入图像进行分类预测。它使用已经训练好的模型来对输入数据进行推断,并输出每个类别的概率分布。
print("预测结果为:", class_names[np.argmax(predictions)])

运行结果: 

你可能感兴趣的:(深度学习,人工智能)