- 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
- 🍖 原作者:K同学啊
目录
- 一、创建环境
- 二、前期准备
- 2.1 设置GPU
- 2.2 导入数据
- 2.3 数据预处理
- 2.3.1 加载数据
- 2.3.2 查看图像的标签
- 2.4 数据可视化
- 三、构建简单的CNN网络(卷积神经网络)
- 3.1 网络结构
- 3.2 编译模型
- 四、训练模型
- 五、模型预测
- 六、总结
一、创建环境
- 🏡我的环境:
- ● 语言环境:Python3.8
- ● 深度学习环境:TensorFlow2
运行环境: colab
二、前期准备
2.1 设置GPU
import tensorflow as tfgpus = tf.config.list_physical_devices("GPU")if gpus:gpu0 = gpus[0] #如果有多个GPU,仅使用第0个GPUtf.config.experimental.set_memory_growth(gpu0, True) #设置GPU显存用量按需使用tf.config.set_visible_devices([gpu0],"GPU")
2.2 导入数据
import os,PIL,pathlib
import matplotlib.pyplot as plt
import numpy as np
from tensorflow import keras
from tensorflow.keras import layers,modelsdata_dir = "/content/drive/MyDrive/k-data/weather_photos"
data_dir = pathlib.Path(data_dir)image_count = len(list(data_dir.glob('*/*.jpg')))
print("图片总数为:",image_count)
输出:
roses = list(data_dir.glob('sunrise/*.jpg'))
PIL.Image.open(str(roses[0]))
输出:
2.3 数据预处理
2.3.1 加载数据
image_dataset_from_directory 函数是 TensorFlow 库中的一个工具函数,用于从文件系统中的目录创建图像数据集。这个函数可以自动读取指定目录中的图像文件,并按照一定的规则将它们组织成批次(batch)
batch_size = 32
img_height = 180
img_width = 180# 使用 TensorFlow 库中的 `tf.keras.preprocessing.image_dataset_from_directory()` 函数来创建一个测试图像数据集
train_ds = tf.keras.preprocessing.image_dataset_from_directory(data_dir, # 图像文件的目录路径validation_split=0.2, # 指定了从数据集中分割出20%的数据用作验证集subset="training", # 返回的数据集是用于训练的子集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.2,subset="validation",seed=123,image_size=(img_height, img_width),batch_size=batch_size)
2.3.2 查看图像的标签
class_names = train_ds.class_names
print(class_names)
输出:
2.4 数据可视化
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")
输出:
三、构建简单的CNN网络(卷积神经网络)
3.1 网络结构
⭐卷积层
卷积层是卷积神经网络(CNN)中的基础组件,它通过一组可学习的过滤器(或内核)在输入数据(如图像)上进行卷积操作,以提取局部特征和模式;这些过滤器在整个输入数据上滑动,并通过元素相乘和求和生成特征图,每个特征图代表输入数据在特定过滤器下的特征响应,整个过程通过权值共享和局部连接减少参数数量,使得网络能够高效地学习图像的层次化表示。
⭐池化层
在图像处理中,由于图像中存在较多冗余信息,可用某一区域子块的统计信息(如最大值或均值等)来刻画该区域中所有像素点呈现的空间分布模式,以替代区域子块中所有像素点取值,这就是卷积神经网络中池化(pooling)操作。
池化层可对提取到的特征信息进行降维,实现下采样,同时保留了特征图中主要信息,一方面使特征图变小,简化网络计算复杂度;另一方面进行特征压缩,提取主要特征,增加平移不变性,减少过拟合风险。但其实池化更多程度上是一种计算性能的一个妥协,强硬地压缩特征的同时也损失了一部分信息。
num_classes = 4model = models.Sequential([layers.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*3layers.AveragePooling2D((2, 2)), # 池化层2,2*2采样layers.Conv2D(64, (3, 3), activation='relu'), # 卷积层3,卷积核3*3layers.Dropout(0.3), # 让神经元以一定的概率停止工作,防止过拟合,提高模型的泛化能力。layers.Flatten(), # Flatten层,连接卷积层与全连接层layers.Dense(128, activation='relu'), # 全连接层,特征进一步提取layers.Dense(num_classes) # 输出层,输出预期结果
])model.summary() # 打印网络结构
输出:
3.2 编译模型
● 损失函数(loss):用于衡量模型在训练期间的准确率。
● 优化器(optimizer):决定模型如何根据其看到的数据和自身的损失函数进行更新。
● 指标(metrics):用于监控训练和测试步骤。以下示例使用了准确率,即被正确分类的图像的比率。
# 设置优化器
opt = tf.keras.optimizers.Adam(learning_rate=0.001)model.compile(optimizer=opt,loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),metrics=['accuracy'])
四、训练模型
-
history
: 用来存储训练过程中的相关信息,比如损失(loss)和准确率(accuracy)等指标。在训练结束后,可以通过这个变量来分析模型的训练效果。 -
model.fit(...)
: 调用模型的fit
方法,用于训练模型。fit
方法接收多个参数,其中最重要的包括训练数据和标签,以及一些训练配置。 -
train_images
和train_labels
: 这两个参数分别代表训练数据和对应的标签。train_images
是模型训练时使用的特征数据,而train_labels
是这些特征数据对应的正确输出标签。 -
epochs=10
: 这个参数指定了训练过程中要进行的迭代次数,也就是整个训练数据集要被模型遍历多少次。 -
validation_data=(test_images, test_labels)
: 这个参数提供了在每个epoch结束后用于验证模型性能的数据。test_images
和test_labels
分别代表测试数据和标签。这样,模型在每个epoch训练结束后都会在测试集上评估一次,以监控模型的泛化能力。
epochs = 10history = model.fit(train_ds,validation_data=val_ds,epochs=epochs
)
输出:
五、模型预测
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']loss = history.history['loss']
val_loss = history.history['val_loss']epochs_range = range(epochs)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()
输出:
六、总结
本文将采用CNN实现多云、下雨、晴、日出四种天气状态的识别。较上篇文章,本文为了增加模型的泛化能力,新增了Dropout层并且将最大池化层调整成了平均池化层。
Dropout是一种正则化技术,用于通过在训练过程中随机丢弃(即暂时移除)网络中的一些神经元来减少过拟合。
Dropout的工作原理:
- 随机丢弃:在每次训练迭代中,Dropout以一定的概率(通常是一个超参数,如0.5)随机选择网络中的神经元,并将其暂时从网络中移除。这意味着这些神经元在当前迭代中不会对损失函数的计算和梯度更新产生影响。
- 保留激活:被保留的神经元将正常参与到前向传播和反向传播过程中。
- 权重重缩放:由于Dropout在训练过程中减少了神经元的数量,因此通常需要对剩余神经元的权重进行重缩放,以保持网络的表达能力。这通常通过在前向传播过程中对激活值进行缩放来实现。
Dropout的优点:
- 减少过拟合:通过随机丢弃神经元,模型不能过度依赖任何单一的神经元,这迫使网络学习更加鲁棒的特征表示。
- 模型平均:Dropout可以看作是训练多个不同架构的神经网络并进行集成的一种形式,因为每次迭代中被丢弃的神经元都不同,从而相当于训练了多个不同的模型。
- 计算效率:尽管Dropout增加了一些计算复杂性,但它不需要额外的参数或存储空间,因此在计算资源有限的情况下仍然是一种实用的技术。