在准备好数据集和模型后,就可以将数据送入模型中启动训练评估了,概括地讲包括如下几步:
模型训练:训练包括多轮迭代(epoch),每轮迭代遍历一次训练数据集,并且每次从中获取一小批(mini-batch)样本,送入模型执行前向计算得到预测值,并计算预测值(predict_label)与真实值(true_label)之间的损失函数值(loss)。执行梯度反向传播,并根据设置的优化算法(optimizer)更新模型的参数。观察每轮迭代的 loss 值减小趋势,可判断模型训练效果。
模型评估:将测试数据集送入训练好的模型进行评估,得到预测值,计算预测值与真实值之间的损失函数值(loss),并计算评价指标值(metric),便于评估模型效果。
模型推理:将待验证的数据(样本)送入训练好的模型执行推理,观察并验证推理结果(标签)是否符合预期。
飞桨框架提供了两种训练、评估与推理的方法:
使用飞桨高层 API:先用 paddle.Model 对模型进行封装,然后通过 Model.fit 、 Model.evaluate 、 Model.predict 等完成模型的训练、评估与推理。该方式代码量少,适合快速上手。
使用飞桨基础 API:提供了损失函数、优化器、评价指标、更新参数、反向传播等基础组件的实现,可以更灵活地应用到模型训练、评估与推理任务中,当然也可以很方便地自定义一些组件用于相关任务中。
高层 API 如 Model.fit 、 Model.evaluate 、 Model.predict 等都可以通过基础 API 实现,本文先介绍高层 API 的使用方式,然后将高层 API 拆解为基础 API 介绍,方便对比学习。
开始之前,需要使用下面的命令安装 Python 的 matplotlib 库,用于可视化图片。
# 使用 pip 工具安装 matplotlib ! python3 -m pip install matplotlib -i https:
模型训练时,需要用到 CPU、 GPU 等计算处理器资源,由于飞桨框架的安装包是区分处理器类型的,默认情况下飞桨框架会根据所安装的版本自动选择对应硬件,比如安装的 GPU 版本的飞桨,则自动使用 GPU 训练模型,无需手动指定。因此一般情况下,无需执行此步骤。
但是如果安装的 GPU 版本的飞桨框架,想切换到 CPU 上训练,则可通过 paddle.device.set_device 修改。如果本机有多个 GPU 卡,也可以通过该 API 选择指定的卡进行训练,不指定的情况下则默认使用 'gpu:0'。
import paddle paddle.device.set_device("cpu")
需要注意的是,使用 paddle.device.set_device 时,只能使用 CUDA_VISIBLE_DEVICES 设置范围内的显卡,例如可以设置export CUDA_VISIBLE_DEVICES=0,1,2 和 paddle.device.set_device('gpu:0'),但是设置 export CUDA_VISIBLE_DEVICES=1 和 paddle.device.set_device('gpu:0') 时会冲突报错。
注:
本文仅以单机单卡场景为例,介绍模型训练的方法,如果需要使用单机多卡、多机多卡训练,请参考如下章节:分布式训练。
飞桨框架除了支持在 CPU、GPU 上训练,还支持在百度昆仑芯 XPU、华为昇腾 NPU 等 AI 计算处理器上训练,对应的训练指导请参考 硬件支持 章节。
模型训练前,需要先完成数据集的加载和模型组网,以 MNIST 手写数字识别任务为例,代码示例如下:
from paddle.vision.transforms import Normalize transform = Normalize(mean=[127.5], std=[127.5], data_format="CHW") train_dataset = paddle.vision.datasets.MNIST(mode="train", transform=transform) test_dataset = paddle.vision.datasets.MNIST(mode="test", transform=transform) mnist = paddle.nn.Sequential( paddle.nn.Flatten(1, -1), paddle.nn.Linear(784, 512), paddle.nn.ReLU(), paddle.nn.Dropout(0.2), paddle.nn.Linear(512, 10), )
以手写数字识别任务为例,使用高层 API 进行模型训练、评估与推理的步骤如下:
使用高层 API 训练模型前,可使用 paddle.Model 将模型封装为一个实例,方便后续进行训练、评估与推理。代码如下:
model = paddle.Model(mnist)
用 paddle.Model 完成模型的封装后,需通过 Model.prepare 进行训练前的配置准备工作,包括设置优化算法、Loss 计算方法、评价指标计算方法:
优化器(optimizer):即寻找最优解的方法,可计算和更新梯度,并根据梯度更新模型参数。飞桨框架在 paddle.optimizer 下提供了优化器相关 API。并且需要为优化器设置合适的学习率,或者指定合适的学习率策略,飞桨框架在 paddle.optimizer.lr 下提供了学习率策略相关的 API。
损失函数(loss):用于评估模型的预测值和真实值的差距,模型训练过程即取得尽可能小的 loss 的过程。飞桨框架在 paddle.nn Loss层 提供了适用不同深度学习任务的损失函数相关 API。
评价指标(metrics):用于评估模型的好坏,不同的任务通常有不同的评价指标。飞桨框架在 paddle.metric 下提供了评价指标相关 API。
model.prepare( optimizer=paddle.optimizer.Adam( learning_rate=0.001, parameters=model.parameters() ), loss=paddle.nn.CrossEntropyLoss(), metrics=paddle.metric.Accuracy(), )
示例中使用 Adam 优化器,设置优化器的学习率 learning_rate=0.001,并传入封装好的全部模型参数 model.parameters 用于后续更新;使用交叉熵损失函数 CrossEntropyLoss 用于分类任务评估;使用分类任务常用的准确率指标 Accuracy 计算模型在训练集上的精度。
做好模型训练的前期准备工作后,调用 Model.fit 接口来启动训练。 训练过程采用二层循环嵌套方式:内层循环完成整个数据集的一次遍历,采用分批次方式;外层循环根据设置的训练轮次完成数据集的多次遍历。因此需要指定至少三个关键参数:训练数据集,训练轮次和每批次大小:
训练数据集:传入之前定义好的训练数据集。
训练轮次(epoch):训练时遍历数据集的次数,即外循环轮次。
批次大小(batch_size):内循环中每个批次的训练样本数。
除此之外,还可以设置样本乱序(shuffle)、丢弃不完整的批次样本(drop_last)、同步/异步读取数据(num_workers) 等参数,另外可通过 Callback 参数传入回调函数,在模型训练的各个阶段进行一些自定义操作,比如收集训练过程中的一些数据和参数,详细介绍可参见 自定义 Callback 章节。
model.fit(train_dataset, epochs=5, batch_size=64, verbose=1)
The loss value printed in the log is the current step, and the metric is the average value of previous steps. Epoch 1/5 step 10/938 [..............................] - loss: 0.9679 - acc: 0.4109 - ETA: 13s - 14ms/stepstep 938/938 [==============================] - loss: 0.1158 - acc: 0.9020 - 10ms/step Epoch 2/5 step 938/938 [==============================] - loss: 0.0981 - acc: 0.9504 - 10ms/step Epoch 3/5 step 938/938 [==============================] - loss: 0.0215 - acc: 0.9588 - 10ms/step Epoch 4/5 step 938/938 [==============================] - loss: 0.0134 - acc: 0.9643 - 10ms/step Epoch 5/5 step 938/938 [==============================] - loss: 0.3371 - acc: 0.9681 - 11ms/step
示例中传入数据集 train_dataset 进行迭代训练,共遍历 5 轮(epochs=5),每轮迭代中分批次取数据训练,每批次 64 个样本(batch_size=64),并打印训练过程中的日志(verbose=1)。 从打印日志中可观察到损失函数 loss 值减小,精度指标 acc 值提高的趋势,说明模型训练取得了成效。
训练好模型后,可在事先定义好的测试数据集上,使用 Model.evaluate 接口完成模型评估操作,结束后根据在 Model.prepare 中定义的 loss 和 metric 计算并返回相关评估结果。
返回格式是一个字典:
只包含loss, {'loss': xxx}
包含loss和一个评估指标, {'loss': xxx, 'metric name': xxx}
包含loss和多个评估指标, {'loss': xxx, 'metric name1': xxx, 'metric name2': xxx}
eval_result = model.evaluate(test_dataset, verbose=1) print(eval_result)
Eval begin... step 10000/10000 [==============================] - loss: 2.3842e-07 - acc: 0.9714 - 2ms/step Eval samples: 10000 {'loss': [2.384186e-07], 'acc': 0.9714}
示例中返回一个 loss 和 一个 acc 准确率指标的结果。在模型之前未"见过"的测试集上,评估出仍然有 98.1% 的准确率,验证了模型在该任务上取得不错的效果。
高层 API 中提供了 Model.predict 接口,可对训练好的模型进行推理验证。只需传入待执行推理验证的样本数据,即可计算并返回推理结果。
返回格式是一个列表:
模型是单一输出:[(numpy_ndarray_1, numpy_ndarray_2, …, numpy_ndarray_n)]
模型是多输出:[(numpy_ndarray_1, numpy_ndarray_2, …, numpy_ndarray_n), (numpy_ndarray_1, numpy_ndarray_2, …, numpy_ndarray_n), …]
如果模型是单一输出,则输出的形状为 [1, n],n 表示数据集的样本数。其中每个 numpy_ndarray_n 是对应原始数据经过模型计算后得到的预测结果,类型为 numpy 数组,例如 mnist 分类任务中,每个 numpy_ndarray_n 是长度为 10 的 numpy 数组。
如果模型是多输出,则输出的形状为[m, n],m 表示标签的种类数,在多标签分类任务中,m 会根据标签的数目而定。
test_result = model.predict(test_dataset) print(len(test_result)) print(test_result[0][0]) img, label = test_dataset[0] pred_label = test_result[0][0].argmax() print("true label: {}, pred label: {}".format(label[0], pred_label)) from matplotlib import pyplot as plt plt.imshow(img[0])
Predict begin... step 10000/10000 [==============================] - 2ms/step Predict samples: 10000 1 [[ -6.512169 -6.7076845 0.5048795 1.6733919 -9.670526 -1.6352568 -15.833721 13.87411 -8.215239 1.5966017]] true label: 7, pred label: 7 <matplotlib.image.AxesImage at 0x7f95f014f4d0>
示例中对测试集 test_dataset 中每一个样本执行预测,测试数据集中包含 10000 个数据,因此将取得 10000 个预测输出。
打印第一个样本数据的预测输出,可以看到,在手写数字识别任务中,经过模型的计算得到一个数组 [[ -6.5593615 -6.4680595 -1.4708003 2.1043894 -11.743436 -4.4516582 -14.733968 12.036645 -6.582403 -1.8672216]],取其中最大的值(12.036645)的下标(对应 label 7),即得到该样本数据的预测结果(pred label: 7),可视化该样本图像(true label: 7),与预测结果一致,说明模型准确预测了样本图像上的数字。
除了上面介绍的三个 API 之外, paddle.Model 类也提供了其他与训练、评估与推理相关的 API:
Model.train_batch:在一个批次的数据集上进行训练;
Model.eval_batch:在一个批次的数据集上进行评估;
Model.predict_batch:在一个批次的数据集上进行推理。
这三个 API 与上面介绍的三个 API 的输入数据的维度有所不同,详细介绍可参考对应 API 文档。
除了通过高层 API 实现模型的训练、评估与推理,飞桨框架也同样支持通过基础 API。简单来说, Model.prepare 、 Model.fit 、 Model.evaluate 、 Model.predict 都是由基础 API 封装而来。下面通过拆解高层 API 到基础 API 的方式,来了解如何用基础 API 完成模型训练、评估与推理。
飞桨框架通过基础 API 对模型进行训练,对应高层 API 的 Model.prepare 与 Model.fit ,一般包括如下几个步骤:
加载训练数据集、声明模型、设置模型实例为 train 模式
设置优化器、损失函数与各个超参数
设置模型训练的二层循环嵌套,并在内层循环嵌套中设置如下内容
3.1 从数据读取器 DataLoader 获取一批次训练数据
3.2 执行一次预测,即经过模型计算获得输入数据的预测值
3.3 计算预测值与数据集标签的损失
3.4 计算预测值与数据集标签的准确率
3.5 将损失进行反向传播
3.6 打印模型的轮数、批次、损失值、准确率等信息
3.7 执行一次优化器步骤,即按照选择的优化算法,根据当前批次数据的梯度更新传入优化器的参数
3.8 将优化器的梯度进行清零
train_loader = paddle.io.DataLoader(train_dataset, batch_size=64, shuffle=True) mnist.train() epochs = 5 optim = paddle.optimizer.Adam(parameters=mnist.parameters()) loss_fn = paddle.nn.CrossEntropyLoss() for epoch in range(epochs): for batch_id, data in enumerate(train_loader()): x_data = data[0] y_data = data[1] predicts = mnist(x_data) loss = loss_fn(predicts, y_data) acc = paddle.metric.accuracy(predicts, y_data) loss.backward() if (batch_id + 1) % 900 == 0: print( "epoch: {}, batch_id: {}, loss is: {}, acc is: {}".format( epoch, batch_id + 1, loss.numpy(), acc.numpy() ) ) optim.step() optim.clear_grad()
epoch: 0, batch_id: 900, loss is: [0.06991791], acc is: [0.96875] epoch: 1, batch_id: 900, loss is: [0.02878829], acc is: [1.] epoch: 2, batch_id: 900, loss is: [0.07192856], acc is: [0.96875] epoch: 3, batch_id: 900, loss is: [0.20411499], acc is: [0.96875] epoch: 4, batch_id: 900, loss is: [0.13589518], acc is: [0.96875]
飞桨框架通过基础 API 对训练好的模型进行评估,对应高层 API 的 Model.evaluate 。与模型训练相比,模型评估的流程有如下几点不同之处:
加载的数据从训练数据集改为测试数据集
模型实例从 train 模式改为 eval 模式
不需要反向传播、优化器参数更新和优化器梯度清零
test_loader = paddle.io.DataLoader(test_dataset, batch_size=64, drop_last=True) loss_fn = paddle.nn.CrossEntropyLoss() mnist.eval() for batch_id, data in enumerate(test_loader()): x_data = data[0] y_data = data[1] predicts = mnist(x_data) loss = loss_fn(predicts, y_data) acc = paddle.metric.accuracy(predicts, y_data) if (batch_id + 1) % 30 == 0: print( "batch_id: {}, loss is: {}, acc is: {}".format( batch_id + 1, loss.numpy(), acc.numpy() ) )
batch_id: 30, loss is: [0.23106411], acc is: [0.953125] batch_id: 60, loss is: [0.4329119], acc is: [0.90625] batch_id: 90, loss is: [0.07333981], acc is: [0.96875] batch_id: 120, loss is: [0.00324837], acc is: [1.] batch_id: 150, loss is: [0.0857158], acc is: [0.96875]
飞桨框架通过基础 API 对训练好的模型执行推理,对应高层 API 的 Model.predict 。模型的推理过程相对独立,是在模型训练与评估之后单独进行的步骤。只需要执行如下步骤:
加载待执行推理的测试数据,并将模型设置为 eval 模式
读取测试数据并获得预测结果
对预测结果进行后处理
test_loader = paddle.io.DataLoader(test_dataset, batch_size=64, drop_last=True) mnist.eval() for batch_id, data in enumerate(test_loader()): x_data = data[0] predicts = mnist(x_data) print("predict finished") img, label = test_loader().next() pred_label = mnist(img)[0].argmax() print( "true label: {}, pred label: {}".format( label[0].item(), pred_label[0].item() ) ) from matplotlib import pyplot as plt plt.imshow(img[0][0])
predict finished true label: 7, pred label: 7 <matplotlib.image.AxesImage at 0x7f95f009be50>
本节中介绍了在飞桨框架中使用高层 API 进行模型训练、评估和推理的方法,并拆解出对应的基础 API 实现方法。需要注意的是,这里的推理仅用于模型效果验证,实际生产应用中,则可使用飞桨提供的一系列推理部署工具,满足服务器端、移动端、网页/小程序等多种环境的模型部署上线需求,具体可参见 推理部署 章节。
同时,飞桨的高层 API 和基础 API 可以组合使用,并不是完全割裂开的,这样有助于开发者更便捷地完成算法迭代。示例代码如下:
from paddle.vision.models import LeNet class FaceNet(paddle.nn.Layer): def __init__(self): super().__init__() self.backbone = LeNet() self.outLayer1 = paddle.nn.Sequential( paddle.nn.Linear(10, 512), paddle.nn.ReLU(), paddle.nn.Dropout(0.2) ) self.outLayer2 = paddle.nn.Linear(512, 10) def forward(self, inputs): out = self.backbone(inputs) out = self.outLayer1(out) out = self.outLayer2(out) return out model = paddle.Model(FaceNet()) optim = paddle.optimizer.Adam(learning_rate=1e-3, parameters=model.parameters()) model.prepare( optim, paddle.nn.CrossEntropyLoss(), metrics=paddle.metric.Accuracy() ) model.fit(train_dataset, test_dataset, epochs=5, batch_size=64, verbose=1)
The loss value printed in the log is the current step, and the metric is the average value of previous steps. Epoch 1/5 step 938/938 [==============================] - loss: 0.0863 - acc: 0.9369 - 22ms/step Eval begin... step 157/157 [==============================] - loss: 0.1034 - acc: 0.9741 - 8ms/step Eval samples: 10000 Epoch 2/5 step 938/938 [==============================] - loss: 0.0366 - acc: 0.9769 - 21ms/step Eval begin... step 157/157 [==============================] - loss: 0.0047 - acc: 0.9835 - 8ms/step Eval samples: 10000 Epoch 3/5 step 938/938 [==============================] - loss: 0.0073 - acc: 0.9813 - 21ms/step Eval begin... step 157/157 [==============================] - loss: 0.0345 - acc: 0.9818 - 9ms/step Eval samples: 10000 Epoch 4/5 step 938/938 [==============================] - loss: 0.0025 - acc: 0.9842 - 21ms/step Eval begin... step 157/157 [==============================] - loss: 0.0033 - acc: 0.9834 - 8ms/step Eval samples: 10000 Epoch 5/5 step 938/938 [==============================] - loss: 0.0294 - acc: 0.9859 - 20ms/step Eval begin... step 157/157 [==============================] - loss: 0.0039 - acc: 0.9834 - 7ms/step Eval samples: 10000
相关知识
模型训练、评估与推理
快速部署模型和训练模型
深入剖析训练与模型评估:从数据集划分到过拟合处理与优化策略
动物模型与评估丨小鼠异动症模型及评估
宠物训练效果评估与改进
小动物医学诊疗思路推理:以问题为导向的体格检查和临床病理学评估
宠物行为训练的目标与进展评估
动物模型与评估丨浅析小鼠驼背行为评估(hunchback)
宠物训练的有效性如何评估训练成果
【深度学习实验】前馈神经网络(九):整合训练、评估、预测过程(Runner)
网址: 模型训练、评估与推理 https://m.mcbbbk.com/newsview155416.html
上一篇: 教育评估与改进:基于大数据的学习 |
下一篇: 培训效果评估操作指南 |