>- ** 本文为[365天深度学习训练营](https://mp.weixin.qq.com/s/0dvHCaOoFnW8SCp3JpzKxg) 中的学习记录博客**
>- ** 原作者:[K同学啊](https://mtyjkh.blog.csdn.net/)**
1.知道如何配置环境
2.跑通模型(不报错)
3.储存模型,供后续使用
4.了解如何衡量模型训练结果是否是优秀
编译器:PyCharm Community
语言环境:python3.11.7
深度学习环境:TensorFlow 2.9.1
待补
打开pycharm,打开目标python脚本,调出终端输入conda info可以查询当前激活的Conda环境及其路径。也可用conda list命令来查看是否正确安装
conda info
conda list
原代码
import tensorflow as tf
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")
原有代码运行出现问题。gpt提示:使用了一个过时的 API。应该使用 tf.config.set_memory_growth
而不是 tf.config.experimental.set_memory_growth
。
import tensorflow as tf
gpus = tf. config.list_physical_devices("GPU")
# 如果有 GPU 可用,配置 TensorFlow 使用它们
if gpus:
gpu0 = gpus[0] # 只使用第一个 GPU
tf.config.set_memory_growth(gpu0, True) # 设置显存按需增长
tf.config.set_visible_devices([gpu0], "GPU")
(train_images, train_labels), (test_images, test_labels) = datasets.mnist.load_data()
tensorflow.keras.datasets
模块中导入 MNIST 数据集。datasets.mnist.load_data()
函数返回两个元组:一个是训练数据及其标签 (train_images
, train_labels
),另一个是测试数据及其标签 (test_images
, test_labels
)。train_images
和 test_images
是手写数字的图像数据,train_labels
和 test_labels
是对应的标签(即图像代表的数字)。train_images, test_images = train_images / 255.0, test_images / 255.0
train_images = train_images.reshape((60000, 28, 28, 1))
test_images = test_images.reshape((10000, 28, 28, 1))
train_images
和 test_images
的形状分别是 (60000, 28, 28)
和 (10000, 28, 28)
,表示每张图像是 28x28 的二维矩阵。reshape((60000, 28, 28, 1))
将训练图像重新调整为 (60000, 28, 28, 1)
的形状,其中 1
表示单通道(灰度图像)。测试图像也类似调整为 (10000, 28, 28, 1)
。model = models.Sequential([
layers.Conv2D(32,(3,3),activation='relu',input_shape=(28,28,1)),
layers.MaxPooling2D((2,2)),
layers.Conv2D(64,(3,3),activation='relu'),
layers.MaxPooling2D((2,2)),
layers.Flatten(),
layers.Dense(64,activation='relu'),
layers.Dense(10)
])
第一层:卷积
layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1))
Conv2D
是一个二维卷积层,它会对输入图像进行卷积操作。32
是输出的通道数,也就是卷积核的数量。(3, 3)
是卷积核的尺寸(高和宽)。activation='relu'
表示使用 ReLU 激活函数,使模型能够学习非线性特征。input_shape=(28, 28, 1)
定义了输入图像的形状。对于 MNIST 数据集,输入图像是 28x28 像素的单通道灰度图像。第二层:最大池化层
layers.MaxPooling2D((2, 2))
MaxPooling2D
是一个最大池化层,它会对输入进行下采样(取局部区域的最大值),从而减少数据的尺寸和计算量。(2, 2)
表示池化窗口的大小。这里使用 2x2 的窗口进行池化。第三层:卷积层
layers.Conv2D(64, (3, 3), activation='relu')
64
表示输出通道数增加到了 64 个。第四层:最大池化层
layers.MaxPooling2D((2, 2))
第五层:扁平层
layers.Flatten()
Flatten
层将多维输入(即图像数据)展平成一维,准备输入到全连接层中。第六层:全连接层
layers.Dense(64, activation='relu')
Dense
层是全连接层,每个神经元与上一层的所有神经元相连。64
表示这一层有 64 个神经元。activation='relu'
表示使用 ReLU 激活函数。第七层:输出层
layers.Dense(10)
10
表示这一层有 10 个神经元,对应于 MNIST 数据集的 10 个类别(数字 0 到 9)。设置模型的优化器、损失函数和评估指标,以便在训练过程中使用。这是机器学习模型的一个重要步骤,确保模型能够正确地学习和评估。
model.compile(
optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy']
)
optimizer='adam':
optimizer
参数指定了优化器,这里选择的是 Adam 优化器。loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True):
loss
参数指定了损失函数,这里选择的是稀疏分类交叉熵损失函数。SparseCategoricalCrossentropy
用于多分类问题,特别适用于目标标签是整数(如 0, 1, 2, ... 9)而不是独热编码(one-hot encoding)的情况。from_logits=True
表示模型的输出是 logits(未归一化的预测值)。在这种情况下,损失函数内部会先对 logits 进行 softmax 归一化,然后再计算交叉熵损失。metrics=['accuracy']:
metrics
参数指定了评估指标,这里选择的是准确率。通过调用 model.compile()
,你为模型配置了训练时所需的关键设置,包括:
这一步是训练模型前的必要步骤,它告诉 Keras 如何在训练过程中调整模型的权重、计算损失以及评估模型性能。
history = model.fit(
train_images,
train_labels,
epochs=10,
validation_data=(test_images,test_labels)
)
train_images:
train_labels:
train_images
中每张图像的实际分类标签(数字 0-9)。epochs=10:
epochs
参数指定了训练的轮次(epochs)数量。validation_data=(test_images, test_labels):
validation_data
参数用于指定验证集(图像和标签)。test_images
和 test_labels
分别是验证集的输入数据和标签,前面也已经进行了归一化和形状调整。调用 model.fit()
方法时,模型会执行以下操作:
训练模型:
train_images
和 train_labels
上进行训练。评估模型:
validation_data
(即 test_images
和 test_labels
)上进行评估。记录训练过程:
history
对象会记录训练过程中每个轮次的损失值和评估指标(如准确率)的变化情况。history.history
属性访问这些记录,用于绘制训练过程中的损失值和准确率变化曲线,以直观地了解模型的学习效果。假设你正在训练一个手写数字分类模型:
train_images
是 60000 张手写数字图像,train_labels
是对应的标签。test_images
是 10000 张手写数字图像,test_labels
是对应的标签。history
对象中,可以用于后续分析和可视化。你的程序中存在多个 OpenMP 运行时库的副本,这可能会导致性能下降或产生不正确的结果。OpenMP 是一个并行编程模型,常用于利用多核处理器进行并行计算。多个 OpenMP 运行时库的副本同时存在会引起冲突。
解决方法
设置环境变量 KMP_DUPLICATE_LIB_OK
为 TRUE
: 虽然这是一个不安全、不支持、且未记录的方法,但它可以让程序继续执行。需要注意,这可能会导致崩溃或产生不正确的结果。
在代码中添加以下几行:
import os
os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"
这种方法应作为临时解决方案,不建议长期使用。
# 绘制训练准确率和验证准确率
plt.plot(history.history['accuracy'], label='Train Accuracy')
plt.plot(history.history['val_accuracy'], label='Validation Accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend(loc='lower right')
plt.show()
# 绘制训练损失和验证损失
plt.plot(history.history['loss'], label='Train Loss')
plt.plot(history.history['val_loss'], label='Validation Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend(loc='upper right')
plt.show()
从损失和准确率曲线来看,模型在训练集上的表现非常好,但在验证集上的表现略有波动,这可能是过拟合的表现。过拟合是指模型在训练数据上表现良好,但在未见过的验证数据上表现不佳。
数据增强: 数据增强可以增加训练数据的多样性,帮助模型更好地泛化。
from tensorflow.keras.preprocessing.image import ImageDataGenerator
datagen = ImageDataGenerator(
rotation_range=10,
width_shift_range=0.1,
height_shift_range=0.1,
zoom_range=0.1
)
train_generator = datagen.flow(train_images, train_labels, batch_size=64)
正则化: 添加 Dropout 层或 L2 正则化项以减少过拟合。
model = models.Sequential([
layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)),
layers.MaxPooling2D((2, 2)),
layers.Conv2D(64, (3, 3), activation='relu'),
layers.MaxPooling2D((2, 2)),
layers.Flatten(),
layers.Dense(64, activation='relu', kernel_regularizer=tf.keras.regularizers.l2(0.01)),
layers.Dropout(0.5),
layers.Dense(10)
])
早停法: 使用早停法在验证集损失不再下降时停止训练,以防止过拟合。
from tensorflow.keras.callbacks import EarlyStopping
early_stopping = EarlyStopping(monitor='val_loss', patience=3, restore_best_weights=True)
history = model.fit(
train_generator,
epochs=50,
validation_data=(test_images, test_labels),
callbacks=[early_stopping]
)
调整学习率: 使用学习率调度器动态调整学习率。
from tensorflow.keras.callbacks import ReduceLROnPlateau
reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=2, min_lr=0.001)
history = model.fit(
train_generator,
epochs=50,
validation_data=(test_images, test_labels),
callbacks=[early_stopping, reduce_lr]
)
通过这些方法,可以帮助模型更好地泛化,提高验证集上的表现,减少过拟合现象。
在模型训练后可将模型储存,并可在另开的文件中随时调用该模型
model.save('D:/100 Deep learning projects(model)/mnist_handwritten_digit_recognition_model.h5')
调用语句
# 加载已保存的模型
model = load_model('D:/100 Deep learning projects(model)/mnist_handwritten_digit_recognition_model.h5')