热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

《PaddlePaddle从入门到炼丹》八——模型的保存与使用

原文博客:Doi技术团队链接地址:https:blog.doiduoyi.comauthors1584446358138初心:记录优秀的D

原文博客:Doi技术团队
链接地址:https://blog.doiduoyi.com/authors/1584446358138
初心:记录优秀的Doi技术团队学习经历



前言

本系列教程中,前面介绍的都没有保存模型,训练之后也就结束了。那么本章就介绍如果在训练过程中保存模型,用于之后预测或者恢复训练,又或者由于其他数据集的预训练模型。本章会介绍三种保存模型和使用模型的方式。


训练模型

在训练模型的过程中我们可以随时保存模型,当时也可以在训练开始之前加载之前训练过程的模型。为了介绍这三个保存模型的方式,一共编写了三个Python程序进行介绍,分别是save_infer_model.pysave_use_params_model.pysave_use_persistables_model.py

导入相关的依赖库

import os
import shutil
import paddle as paddle
import paddle.dataset.cifar as cifar
import paddle.fluid as fluid

定义一个残差神经网络,这个是目前比较常用的一个网络。该神经模型可以通过增加网络的深度达到提高识别率,而不会像其他过去的神经模型那样,当网络继续加深时,反而会损失精度。

# 定义残差神经网络(ResNet)
def resnet_cifar10(ipt, class_dim):def conv_bn_layer(input,ch_out,filter_size,stride,padding,act='relu',bias_attr=False):tmp = fluid.layers.conv2d(input=input,filter_size=filter_size,num_filters=ch_out,stride=stride,padding=padding,bias_attr=bias_attr)return fluid.layers.batch_norm(input=tmp, act=act)def shortcut(input, ch_in, ch_out, stride):if ch_in != ch_out:return conv_bn_layer(input, ch_out, 1, stride, 0, None)else:return inputdef basicblock(input, ch_in, ch_out, stride):tmp = conv_bn_layer(input, ch_out, 3, stride, 1)tmp = conv_bn_layer(tmp, ch_out, 3, 1, 1, act=None, bias_attr=True)short = shortcut(input, ch_in, ch_out, stride)return fluid.layers.elementwise_add(x=tmp, y=short, act='relu')# 残差块def layer_warp(block_func, input, ch_in, ch_out, count, stride):tmp = block_func(input, ch_in, ch_out, stride)for i in range(1, count):tmp = block_func(tmp, ch_out, ch_out, 1)return tmpconv1 = conv_bn_layer(ipt, ch_out=16, filter_size=3, stride=1, padding=1)res1 = layer_warp(basicblock, conv1, 16, 16, 5, 1)res2 = layer_warp(basicblock, res1, 16, 32, 5, 2)res3 = layer_warp(basicblock, res2, 32, 64, 5, 2)pool = fluid.layers.pool2d(input=res3, pool_size=8, pool_type='avg', pool_stride=1)predict = fluid.layers.fc(input=pool, size=class_dim, act='softmax')return predict

定义输出成,这里使用的数据集是cifar数据集,这个数据集的图片是宽高都为32的3通道图片,所以这里定义的图片输入层的shape是[3, 32, 32]

# 定义输入层
image = fluid.layers.data(name='image', shape=[3, 32, 32], dtype='float32')
label = fluid.layers.data(name='label', shape=[1], dtype='int64')

获取残差神经网络的分类器,并指定分类大小是10,因为这个数据集有10个类别。

# 获取分类器
model = resnet_cifar10(image, 10)

获取交叉熵损失函数和平均准确率,模型获取的准确率是Top1的。

# 获取损失函数和准确率函数
cost = fluid.layers.cross_entropy(input=model, label=label)
avg_cost = fluid.layers.mean(cost)
acc = fluid.layers.accuracy(input=model, label=label)

获取测试程序,用于之后的测试使。

# 获取训练和测试程序
test_program = fluid.default_main_program().clone(for_test=True)

定义优化方法。

# 定义优化方法
optimizer = fluid.optimizer.AdamOptimizer(learning_rate=1e-3)
opts = optimizer.minimize(avg_cost)

获取训练和测试数据,使用的是cifar数据集,cifar数据集有两种,一种是100个类别的,一种是10个类别的,这里使用的是10个类别的。

# 获取CIFART数据
train_reader = paddle.batch(cifar.train10(), batch_size=32)
test_reader = paddle.batch(cifar.test10(), batch_size=32)

创建执行器,因为我们使用的网络是一个比较大的网络,而且图片也比之前的灰度图要大很多。之前的MNIST数据集的每张图片大小784,而现在的是3072。当然主要是网络比之前的要大很多很多,如果使用CPU训练,速度是非常慢的,所以最好使用GPU进行训练。

# 创建执行器,最好使用GPU,CPU速度太慢了
# place = fluid.CPUPlace()
place = fluid.CUDAPlace(0)
exe = fluid.Executor(place)
# 进行参数初始化
exe.run(fluid.default_startup_program())

加载模型

创建执行器之后,就可以加载之前训练的模型了,有两种加载模型的方式,对应着两种保存模型的方式。这两种模型,可以只使用一种就可以。


  • save_use_params_model.py加载之前训练保存的参数模型,对应的保存接口是fluid.io.save_params。使用这些模型参数初始化网络参数,进行训练

# 加载之前训练过的参数模型
save_path = 'models/params_model/'
if os.path.exists(save_path):print('使用参数模型作为预训练模型')fluid.io.load_params(executor=exe, dirname=save_path)

  • save_use_persistables_model.py加载之前训练保存的持久化变量模型,对应的保存接口是fluid.io.save_persistables。使用这些模型参数初始化网络参数,进行训练。

# 加载之前训练过的检查点模型
save_path = 'models/persistables_model/'
if os.path.exists(save_path):print('使用持久化变量模型作为预训练模型')fluid.io.load_persistables(executor=exe, dirname=save_path)

开始训练模型。

# 定义输入数据维度
feeder = fluid.DataFeeder(place=place, feed_list=[image, label])for pass_id in range(10):# 进行训练for batch_id, data in enumerate(train_reader()):train_cost, train_acc = exe.run(program=fluid.default_main_program(),feed=feeder.feed(data),fetch_list=[avg_cost, acc])# 每100个batch打印一次信息if batch_id % 100 == 0:print('Pass:%d, Batch:%d, Cost:%0.5f, Accuracy:%0.5f' %(pass_id, batch_id, train_cost[0], train_acc[0]))# 进行测试test_accs = []test_costs = []for batch_id, data in enumerate(test_reader()):test_cost, test_acc = exe.run(program=test_program,feed=feeder.feed(data),fetch_list=[avg_cost, acc])test_accs.append(test_acc[0])test_costs.append(test_cost[0])# 求测试结果的平均值test_cost = (sum(test_costs) / len(test_costs))test_acc = (sum(test_accs) / len(test_accs))print('Test:%d, Cost:%0.5f, Accuracy:%0.5f' % (pass_id, test_cost, test_acc))

没有加载之前保存的模型

Pass:0, Batch:0, Cost:2.73460, Accuracy:0.03125
Pass:0, Batch:100, Cost:1.93663, Accuracy:0.25000
Pass:0, Batch:200, Cost:2.02943, Accuracy:0.12500
Pass:0, Batch:300, Cost:1.94425, Accuracy:0.25000
Pass:0, Batch:400, Cost:1.87802, Accuracy:0.21875
Pass:0, Batch:500, Cost:1.71312, Accuracy:0.25000
Pass:0, Batch:600, Cost:1.94090, Accuracy:0.18750
Pass:0, Batch:700, Cost:2.08904, Accuracy:0.12500
Pass:0, Batch:800, Cost:1.89128, Accuracy:0.12500
Pass:0, Batch:900, Cost:1.95716, Accuracy:0.21875
Pass:0, Batch:1000, Cost:1.65181, Accuracy:0.34375

使用参数模型作为预训练模型训练时输出的信息:

使用参数模型作为预训练模型
Pass:0, Batch:0, Cost:0.27627, Accuracy:0.90625
Pass:0, Batch:100, Cost:0.40026, Accuracy:0.87500
Pass:0, Batch:200, Cost:0.54928, Accuracy:0.78125
Pass:0, Batch:300, Cost:0.56526, Accuracy:0.84375
Pass:0, Batch:400, Cost:0.53501, Accuracy:0.78125
Pass:0, Batch:500, Cost:0.18596, Accuracy:0.93750
Pass:0, Batch:600, Cost:0.23747, Accuracy:0.96875
Pass:0, Batch:700, Cost:0.45520, Accuracy:0.84375
Pass:0, Batch:800, Cost:0.86205, Accuracy:0.71875
Pass:0, Batch:900, Cost:0.36981, Accuracy:0.87500
Pass:0, Batch:1000, Cost:0.37483, Accuracy:0.81250

持久性变量模型作为预训练模型训练时输出的信息:

使用持久性变量模型作为预训练模型
Pass:0, Batch:0, Cost:0.51357, Accuracy:0.81250
Pass:0, Batch:100, Cost:0.64380, Accuracy:0.78125
Pass:0, Batch:200, Cost:0.69049, Accuracy:0.62500
Pass:0, Batch:300, Cost:0.52201, Accuracy:0.87500
Pass:0, Batch:400, Cost:0.47289, Accuracy:0.81250
Pass:0, Batch:500, Cost:0.15821, Accuracy:1.00000
Pass:0, Batch:600, Cost:0.36470, Accuracy:0.87500
Pass:0, Batch:700, Cost:0.25326, Accuracy:0.90625
Pass:0, Batch:800, Cost:0.92556, Accuracy:0.78125
Pass:0, Batch:900, Cost:0.27470, Accuracy:0.93750
Pass:0, Batch:1000, Cost:0.34562, Accuracy:0.87500

保存模型

训练结束之后,就可以进行保存模型。当然也不一样要全部训练结束才保存模型,我们可以在每一个Pass训练结束之后保存一次模型。这里使用三个程序分别保存,当然也可以一次全部保存。


  • save_infer_model.py保存预测模型,之后用于预测图像。通过使用这个方式保存的模型,之后预测是非常方便的,具体可以阅读预测部分。

# 保存预测模型
save_path = 'models/infer_model/'
# 删除旧的模型文件
shutil.rmtree(save_path, ignore_errors=True)
# 创建保持模型文件目录
os.makedirs(save_path)
# 保存预测模型
fluid.io.save_inference_model(save_path, feeded_var_names=[image.name], target_vars=[model], executor=exe)

  • save_use_params_model.py保存参数模型,之后用于初始化模型,进行训练。

# 保存参数模型
save_path = 'models/params_model/'
# 删除旧的模型文件
shutil.rmtree(save_path, ignore_errors=True)
# 创建保持模型文件目录
os.makedirs(save_path)
# 保存参数模型
fluid.io.save_params(executor=exe, dirname=save_path)

  • save_use_persistables_model.py保存持久化变量模型,之后用于初始化模型,进行训练。

# 保存持久化变量模型
save_path = 'models/persistables_model/'
# 删除旧的模型文件
shutil.rmtree(save_path, ignore_errors=True)
# 创建保持模型文件目录
os.makedirs(save_path)
# 保存持久化变量模型
fluid.io.save_persistables(executor=exe, dirname=save_path)

预测

在训练的时候使用fluid.io.save_inference_model接口保存的模型,可以通过以下use_infer_model.py程序预测,通过这个程序,读者会发现通过这个接口保存的模型,再次预测是非常简单的。

导入相关的依赖库

import paddle.fluid as fluid
from PIL import Image
import numpy as np

创建一个执行器,预测图片可以使用CPU执行,这个速度不会太慢。

# 创建执行器
place = fluid.CPUPlace()
exe = fluid.Executor(place)
exe.run(fluid.default_startup_program())

加载模型,这个是整个预测程序的重点,通过加载预测模型我们就可以轻松获取得到一个预测程序,输出参数的名称,以及分类器的输出。

# 保存预测模型路径
save_path = 'models/infer_model/'
# 从模型中获取预测程序、输入数据名称列表、分类器
[infer_program, feeded_var_names, target_var] = fluid.io.load_inference_model(dirname=save_path, executor=exe)

定义一个图像预处理的函数,这个函数可以统一图像大小,修改图像的存储顺序和图片的通道顺序,转换成numpy数据。

# 预处理图片
def load_image(file):im = Image.open(file)im = im.resize((32, 32), Image.ANTIALIAS)im = np.array(im).astype(np.float32)# PIL打开图片存储顺序为H(高度),W(宽度),C(通道)。# PaddlePaddle要求数据顺序为CHW,所以需要转换顺序。im = im.transpose((2, 0, 1))# CIFAR训练图片通道顺序为B(蓝),G(绿),R(红),# 而PIL打开图片默认通道顺序为RGB,因为需要交换通道。im = im[(2, 1, 0), :, :] # BGRim = im / 255.0im = np.expand_dims(im, axis=0)return im

获取数据并进行预测。这里对比之前的预测方式,不需要再输入一个模拟的标签,因为在保存模型的时候,已经对这部分进行修剪,去掉了这部分不必要的输入。

# 获取图片数据
img = load_image('image/cat.png')# 执行预测
result = exe.run(program=infer_program,feed={feeded_var_names[0]: img},fetch_list=target_var)

执行预测之后,得到一个数组,这个数组是表示每个类别的概率,获取最大概率的标签,并根据标签获取获取该类的名称。

# 显示图片并输出结果最大的label
lab = np.argsort(result)[0][0][-1]names = ['飞机', '汽车', '鸟', '猫', '鹿', '狗', '青蛙', '马', '船', '卡车']print('预测结果标签为:%d, 名称为:%s, 概率为:%f' % (lab, names[lab], result[0][0][lab]))

预测输出结果:

预测结果标签为:3, 名称为:猫, 概率为:0.864919

关于模型的保存和使用就介绍到这里,读者可以使用这个方式保存之前学过的模型。在这个基础上,下一章我们介绍如何使用预训练模型。

同步到百度AI Studio平台:https://aistudio.baidu.com/aistudio/projectDetail/38741
同步到科赛网K-Lab平台:https://www.kesci.com/home/project/5c3f495589f4aa002b845d6b
项目代码GitHub地址:https://github.com/yeyupiaoling/LearnPaddle2/tree/master/note8

注意: 最新代码以GitHub上的为准




上一章:《PaddlePaddle从入门到炼丹》七——强化学习

下一章:《PaddlePaddle从入门到炼丹》九——迁移学习



参考资料


  1. https://blog.csdn.net/qq_33200967/article/details/79095224
  2. http://www.paddlepaddle.org/documentation/docs/zh/1.2/api_cn/io_cn.html

推荐阅读
  • 视觉Transformer综述
    本文综述了视觉Transformer在计算机视觉领域的应用,从原始Transformer出发,详细介绍了其在图像分类、目标检测和图像分割等任务中的最新进展。文章不仅涵盖了基础的Transformer架构,还深入探讨了各类增强版Transformer模型的设计思路和技术细节。 ... [详细]
  • 本文详细介绍了如何在PyQt5中创建简易对话框,包括对话框的基本结构、布局管理以及源代码实现。通过实例代码,展示了如何设置窗口部件、布局方式及对话框的基本操作。 ... [详细]
  • A1166 峰会区域安排问题(25分)PAT甲级 C++满分解析【图论】
    峰会是指国家元首或政府首脑之间的会议。合理安排峰会的休息区是一项复杂的工作,理想的情况是邀请的每位领导人都是彼此的直接朋友。 ... [详细]
  • 使用Pandas DataFrame探索十大城市房价与薪资对比
    在本篇文章中,我们将通过Pandas库中的DataFrame工具,深入了解中国十大城市的房价与薪资水平,探讨哪些城市的生活成本更为合理。这是学习Python数据分析系列的第82篇原创文章,预计阅读时间约为6分钟。 ... [详细]
  • 使用R语言进行Foodmart数据的关联规则分析与可视化
    本文探讨了如何利用R语言中的arules和arulesViz包对Foodmart数据集进行关联规则的挖掘与可视化。文章首先介绍了数据集的基本情况,然后逐步展示了如何进行数据预处理、规则挖掘及结果的图形化呈现。 ... [详细]
  • java datarow_DataSet  DataTable DataRow 深入浅出
    本篇文章适合有一定的基础的人去查看,最好学习过一定net编程基础在来查看此文章。1.概念DataSet是ADO.NET的中心概念。可以把DataSet当成内存中的数据 ... [详细]
  • 探索CNN的可视化技术
    神经网络的可视化在理论学习与实践应用中扮演着至关重要的角色。本文深入探讨了三种有效的CNN(卷积神经网络)可视化方法,旨在帮助读者更好地理解和优化模型。 ... [详细]
  • 深入解析轻量级数据库 SQL Server Express LocalDB
    本文详细介绍了 SQL Server Express LocalDB,这是一种轻量级的本地 T-SQL 数据库解决方案,特别适合开发环境使用。文章还探讨了 LocalDB 与其他轻量级数据库的对比,并提供了安装和连接 LocalDB 的步骤。 ... [详细]
  • 本文介绍了进程的基本概念及其在操作系统中的重要性,探讨了进程与程序的区别,以及如何通过多进程实现并发和并行。文章还详细讲解了Python中的multiprocessing模块,包括Process类的使用方法、进程间的同步与异步调用、阻塞与非阻塞操作,并通过实例演示了进程池的应用。 ... [详细]
  • 深入解析Java并发之ArrayBlockingQueue
    本文详细探讨了ArrayBlockingQueue,这是一种基于数组实现的阻塞队列。ArrayBlockingQueue在初始化时需要指定容量,因此它是一个有界的阻塞队列。文章不仅介绍了其基本概念和数据结构,还深入分析了其源码实现,包括各种入队、出队、获取元素和删除元素的方法。 ... [详细]
  • 本文探讨了在Python中多线程与多进程的性能差异,特别是在处理CPU密集型任务和I/O密集型任务时的表现。由于全局解释器锁(GIL)的存在,多线程在利用多核CPU方面表现不佳,而多进程则能有效利用多核资源。 ... [详细]
  • iOS如何实现手势
    这篇文章主要为大家展示了“iOS如何实现手势”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“iOS ... [详细]
  • 本文探讨了在已知最终数组尺寸不会超过5000x10的情况下,如何利用预分配和调整大小的方法来优化Numpy数组的创建过程,以提高性能并减少内存消耗。 ... [详细]
  • 本文详细介绍了 Redis 中的主要数据类型,包括 String、Hash、List、Set、ZSet、Geo 和 HyperLogLog,并提供了每种类型的基本操作命令和应用场景。 ... [详细]
  • 本文详细探讨了 TensorFlow 中 `tf.identity` 函数的作用及其应用场景,通过对比直接赋值与使用 `tf.identity` 的差异,帮助读者更好地理解和运用这一函数。 ... [详细]
author-avatar
高粱_
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有