PaddlePaddle概述
PaddlePaddle简介
- PaddlePaddle(Parallel Distributed Deep Learning,中文名飞桨)是百度公司推出的开源、易学习、易使用的分布式深度学习平台
PaddlePaddle优点
- 易用性。语法简洁,API的设计干净清晰
- 丰富的模型库。借助于其丰富的模型库,可以非常容易的复现一些经典方法
- 全中文说明文档。首家完整支持中文文档的深度学习平台
- 运行速度快。充分利用 GPU 集群的性能,为分布式环境的并行计算进行加速
PaddlePaddle缺点
- 教材少
- 学习难度大、曲线陡峭
行业应用
学习资源
- 官网:https://www.paddlepaddle.org.cn/
- 百度云智学院:http://abcxueyuan.cloud.baidu.com/#/courseDetail?id=14958
- AIStudio:https://aistudio.baidu.com/aistudio/projectoverview/public/1
体系结构
体系结构
总体架构
编译与执行过程
- 用户编写的python程序通过调用 Paddle 提供的算子,向Program中添加变量(Tensor)以及对变量的操作(Operators 或者 Layers)
- 原始Program在框架内部转换为中间描述语言:ProgramDesc
- Transpiler 接受一段 ProgramDesc ,输出一段变化后的ProgramDesc,作为后端Executor 最终需要执行的 Program
- 执行 ProgramDesc 中定义的 Operator(可以类比为程序语言中的指令),在执行过程中会为 Operator 创建所需的输入输出并进行管理
三个重要术语
- Fluid:定义程序执行流程
- Program:对用户来说一个完整的程序
- Executor:执行器,执行程序
快速开始
# helloworld示例
import paddle.fluid as fluid
# 创建两个类型为int64, 形状为1*1张量
x = fluid.layers.fill_constant(shape=[1], dtype="int64", value=5)
y = fluid.layers.fill_constant(shape=[1], dtype="int64", value=1)
z = x + y # z只是一个对象,没有run,所以没有值
# 创建执行器
place = fluid.CPUPlace() # 指定在CPU上执行
exe = fluid.Executor(place) # 创建执行器
result = exe.run(fluid.default_main_program(),fetch_list=[z]) #返回哪个结果
print(result) # result为多维张量
基本概念与操作
基本概念
张量
- 张量(Tensor): 多维数组或向量,同其它主流深度学习框架一样,PaddlePaddle使用张量来承载数据
- 张量示例:灰度图像为二维张量(矩阵),彩色图像为三维张量
LoDTensor
- LoD(Level-of-Detail) Tensor是Paddle的高级特性,是对Tensor的一种扩充。LoDTensor通过牺牲灵活性来提升训练的效率。
- LoDTensor用来处理变长数据信息,将长度不一致的维度拼接为一个大的维度,并引入了一个索引数据结构(LoD)来将张量分割成序列。
- 假设一个mini-batch中有3个句子,每个句子中分别包含3个、1个和2个单词,我们可以用(3+1+2)xD维Tensor 加上一些索引信息来表示这个mini-batch:
- 假设存在一个mini-batch中包含3个句子、1个句子和2个句子的文章,每个句子都由不同数量的单词组成,则这个mini-batch的可以表示为2-Level的LoDTensor:
Layer
- 表示一个独立的计算逻辑,通常包含一个或多个operator(操作),如layers.relu表示ReLU计算;layers.pool2d表示pool操作。Layer的输入和输出为Variable。
Variable
- 表示一个变量,在paddle中,Variable 基本等价于Tensor。Variable进入Layer计算,然后Layer返回Variable。创建变量方式:
- Paddle 中存在三种 Variable:
- 模型中的可学习参数:包括网络权重、偏置,生存期和整个训练任务一样长。通过 fluid.layers.create_parameter 来创建可学习参数
- 占位 Variable:Paddle 中使用 fluid.data 来接收输入数据,fluid.data 需要提供输入 Tensor 的形状信息,当遇到无法确定的维度时,相应维度指定为 None
- 常量 Variable:通过 fluid.layers.fill_constant 来实现常量Variable
Program
- Program包含Variable定义的多个变量和Layer定义的多个计算,是一套完整的计算逻辑。从用户角度来看,Program是顺序、完整执行的。program 的作用是存储网络结构,但不存储参数
- 用户完成网络定义后,一段 Paddle 程序中通常存在2 个Program
- fluid.default_startup_program:定义了模型参数初始化、优化器参数初始化、reader初始化等各种操作。该program可以由框架自动生成,使用时无需显式地创建
- fluid.default_main_program :定义了神经网络模型,前向反向计算,以及模型参数更新、优化器参数更新等各种操作
Scope
- scope 在 paddle 里可以看作变量空间,存储fluid创建的变量。变量存储于unordered_map 数据结构中,该结构类似于python中的dict,键是变量的名字,值是变量的指针。
- 一 个 p a d d l e 程 序 有 一 个 默 认的全局s c o pe (可以通过fluid.global_scope() 获取)。如果没有主动创建scope并且通过fluid.scope_guard() 替换当前 scope,那么所有参数都在全局scope中。参数创建的时机不是在组网时,而是在executor.run() 执行时。
- program 和 scope 配合,才能表达完整模型(模型=网络结构+参数)
Executor
- Executor用来接收并执行Program,会一次执行Program中定义的所有计算。通过feed来传入参数,通过fetch_list来获取执行结果。
place = fluid.CPUPlace() # 指定在CPU上执行
exe = fluid.Executor(place) # 创建执行器
outs = exe.run(fluid.default_main_program(), # 默认程序上执行
feed=params, # 喂入参数
fetch_list=[result]) # 获取结果
Place
- PaddlePaddle可以运行在Intel CPU,Nvidia GPU,ARMCPU和更多嵌入式设备上,可以通过Place用来指定执行的设备(CPU或GPU)。
place = fluid.CPUPlace() # 指定在CPU上执行
place = fluid.CUDAPlace() # 指定在GPU上执行
Optimizer
- 优化器,用于优化网络,一般用来对损失函数做梯度下降优化,从而求得最小损失值
程序执行步骤
执行两个张量计算
import paddle.fluid as fluid
import numpy
# 创建x, y两个2行3列,类型为float32的变量(张量)
x = fluid.layers.data(name="x", shape=[2, 3], dtype="float32")
y = fluid.layers.data(name="y", shape=[2, 3], dtype="float32")
x_add_y = fluid.layers.elementwise_add(x, y) # 两个张量按元素相加
x_mul_y = fluid.layers.elementwise_mul(x, y) # 两个张量按元素相乘
place = fluid.CPUPlace() # 指定在CPU上执行
exe = fluid.Executor(place) # 创建执行器
exe.run(fluid.default_startup_program()) # 初始化网络
a = numpy.array([[1, 2, 3],
[4, 5, 6]]) # 输入x, 并转换为数组
b = numpy.array([[1, 1, 1],
[2, 2, 2]]) # 输入y, 并转换为数组
params = {"x": a, "y": b}
outs = exe.run(fluid.default_main_program(), # 默认程序上执行
feed=params, # 喂入参数
fetch_list=[x_add_y, x_mul_y]) # 获取结果
for i in outs:
print(i)
编写简单线性回归
- 给出输入样本
- 给出实际输出样本
- 找出 y = wx+b 公式中的 w 和 b
- 定义输入数据、实际输出结果
- 将数据送入神经网络进行训练(全连接网络,即分类器)
- 根据实际输出、预测输出之间的损失值,进行梯度下降,直到收敛到极小值为止
- 神经网络,选择
fluid.layers.fc()
,该函数在神经网络中建立一个全连接层。接收多个输入,为每个输入分配一个权重w, 并维护一个偏置值b;预测时产生一个输出 - 损失函数:回归问题,选择均方差
fluid.layers.square_error_cost()
和fluid.layers.mean()
作为损失函数 - 优化器:随机梯度下降优化器
fluild.SGD
,做梯度下降计算
# paddle实现线性回归
import paddle
import paddle.fluid as fluid
import numpy as np
import matplotlib.pyplot as plt
# 1. 准备数据
train_data = np.array([[0.5],
[0.6],
[0.8],
[1.1],
[1.4]]).astype('float32')
y_true = np.array([[5.0],
[5.5],
[6.0],
[6.8],
[6.8]]).astype('float32')
# 2. 定义模型,损失函数,优化器
x = fluid.layers.data(name='x',
shape=[1], # 一维
dtype='float32') # 类型
y = fluid.layers.data(name='y',
shape=[1], # 一维
dtype='float32') # 类型
# 全连接模型 线性模型
y_predict = fluid.layers.fc(input=x, # 输入
size=1, # 输出个数值
act=None) # 不使用激活函数
# 损失函数(均方误差)
cost = fluid.layers.square_error_cost(input=y_predict, # 预测值
label=y) # 真实值
avg_cost = fluid.layers.mean(cost) # 均方误差
# 优化器
optimzer = fluid.optimizer.SGD(learning_rate=0.01) # 学习率
optimzer.minimize(avg_cost) # 指定优化的目标函数
# 3. 训练
# 执行器
place = fluid.CPUPlace() # CPU
exe = fluid.Executor(place) # 执行器
exe.run(fluid.default_startup_program()) # 初始化
costs = [] # 存放损失值
iters = [] # 存放迭代次数
params = {'x':train_data,'y':y_true}# 参数字典
for i in range(50):
out = exe.run(
program=fluid.default_main_program(),
feed=params, # 参数字典
fetch_list=[y_predict,avg_cost]) # 要返回的值
iters.append(i) # 存放迭代次数
costs.append(out[1][0]) # 记录损失值
print("i: %d,cost: %f"%(i,out[1][0]))
# 4. 可视化
# 线性模型可视化
tmp = np.random.rand(10, 1) # 生成10行1列的均匀随机数组
tmp = tmp * 2 # 范围放大到0~2之间
tmp.sort(axis=0) # 排序
print("10个x:", tmp)
x_test = np.array(tmp).astype("float32")
params = {"x": x_test, "y": x_test} # y参数不参加计算,只需传一个参数避免报错
y_out = exe.run(feed=params,
fetch_list=[y_predict.name]) # 预测
y_test = y_out[0]
print("预测的10个y值:", y_test)
# 损失函数可视化
plt.figure("Trainging")
plt.title("Training Cost", fontsize=24)
plt.xlabel("Iter", fontsize=14)
plt.ylabel("Cost", fontsize=14)
plt.plot(iters, costs, color="red", label="Training Cost") # 绘制损失函数曲线
plt.grid() # 绘制网格线
plt.savefig("train.png") # 保存图片
# 线性模型可视化
plt.figure("Inference")
plt.title("Linear Regression", fontsize=24)
plt.plot(x_test, y_test, color="red", label="inference") # 绘制模型线条
plt.scatter(train_data, y_true) # 原始样本散点图
plt.legend()
plt.grid() # 绘制网格线
plt.savefig("infer.png") # 保存图片
plt.show() # 显示图片
fluid API结构图
数据准备
数据准备
深度学习数据读取要求
- 从文件读入数据。因为程序无法保存大量数据,数据一般保存到文件中,所以需要单独的数据读取操作
- 批量快速读入。深度学习样本数据量较大,需要快速、高效读取(批量读取模式)
- 随机读入。为了提高模型泛化能力,有时需要随机读取数据(随机读取模式)
使用reader
import paddle
def reader_creator(filepath):
def reader():
with open(filepath,"r") as f:
lines = f.readlines()
for line in lines:
yield line
return reader
reader = reader_creator('test.txt')
#从上一个reader中以随机方式读取数据
shuffle = paddle.reader.shuffle(reader, # 原读取器
10) # 打乱间隔
#从上一个随机读取器中,分批次读取数据
batch = paddle.batch(shuffle,
3) # 每个批次3个
for data in batch():# 从原始顺序读取器读取
print(data,end='')
实现多元回归
- 数据量:506笔
- 特征数量:13个(见右图)
- 标签:价格中位数
- 任务:根据样本数据,预测房价中位数(回归问题)
思路
波士顿房价预测
import paddle
import numpy as np
import os
import paddle.fluid as fluid
import matplotlib.pyplot as plt
# 1.准备数据
BUF_SIZE = 500 # 样本随机处理笔数
BATCH_SIZE = 20 # 批次大小
# boston_reader
boston_reader = paddle.dataset.uci_housing.train() # 训练集读取器
# 随机读取器
random_reader = paddle.reader.shuffle(boston_reader,
buf_size=BUF_SIZE) # 间隔多少个样本打乱一次
# 批量读取器
train_reader = paddle.batch(random_reader,
batch_size=BATCH_SIZE) # 每个批次有多少个样本
# 打印查看
# for i in train_reader():
# print(i)
# break
# 2.定义模型损失函数优化器
# 占位符
x = fluid.layers.data(name='x', # 名称
shape=[13], # 形状 一维,13个值
dtype='float32') # 数据类型
y = fluid.layers.data(name='y', # 名称
shape=[1], # 形状 一维,1个值
dtype='float32') # 数据类型
# 线性模型
y_predict = fluid.layers.fc(input=x, # 输入
size=1, # 输出个数值
act=None) # 不使用激活函数
# 损失函数(均方误差)
cost = fluid.layers.square_error_cost(input=y_predict, # 预测值
label=y) # 真实值
avg_cost = fluid.layers.mean(cost) # 均方误差
# 优化器
optimzer = fluid.optimizer.SGD(learning_rate=0.001) # 学习率
optimzer.minimize(avg_cost) # 指定优化的目标函数
# 3.训练保存模型
# 执行器
place = fluid.CPUPlace() # CPU
exe = fluid.Executor(place) # 执行器
exe.run(fluid.default_startup_program()) # 初始化
# feeder
feeder = fluid.DataFeeder(feed_list=[x, y], # 喂入哪些参数
place=place) # 在哪个设备上运行
iter = 0
iters = [] # 存放迭代次数
train_costs = [] # 存放损失值
for epoch in range(220): # 外层循环控制轮次
i = 0
for data in train_reader(): # 内层循环控制批次
i += 1
c = exe.run(
program=fluid.default_main_program(),
feed=feeder.feed(data), # feed()方法返回字典
fetch_list=[avg_cost]) # 要返回的值
if i % 10 == 0:
print("epoch: %d,cost: %f" % (epoch, c[0][0]))
iter = iter + BATCH_SIZE
iters.append(iter) # 存放迭代次数
train_costs.append(c[0][0]) # 记录损失值
# 训练过程可视化
plt.figure("Training Cost")
plt.title("Training Cost", fontsize=24)
plt.xlabel("iter", fontsize=14)
plt.ylabel("cost", fontsize=14)
plt.plot(iters, train_costs, color="red", label="Training Cost")
plt.grid()
plt.savefig("train.png")
# 4.加载推理模型
## 测试集reader
infer_reader = paddle.batch(
paddle.dataset.uci_housing.test(), # 测试集
batch_size=200) # 只有102笔数据,实际是一次性读取
test_data = next(infer_reader()) # 读取一批数据
# 取出输入标签部分
test_x = np.array([d[0] for d in test_data]).astype('float32')
test_y = np.array([d[1] for d in test_data]).astype('float32')
# 参数字典
params = {'x': test_x,'y': test_y}
# 执行推理
results = exe.run(
feed=params, # 喂入的参数
fetch_list=[y_predict]) # 要返回的值
# print(results)
#
infer_result = [] # 预测值列表
ground_truths = [] # 真实值列表
# 取出每一个样本存入列表
for i in results[0]:
infer_result.append(i)
for i in test_y:
ground_truths.append(i)
## 绘图
plt.figure("Infer Result")
plt.title("Infer Result")
plt.xlabel("Ground Truth")
plt.ylabel("Infer Result")
x = np.arange(1, 30) # 产生一个均匀数组,作为斜线x坐标
y = x # 斜线y坐标
plt.plot(x, y) # 绘制y=x斜线
plt.scatter(ground_truths, infer_result,
color="green", label="Test")
plt.grid() # 网格线
plt.legend() # 图例
plt.savefig("predict.png") # 图片保存到文件
plt.show()
执行结果
模型保存与加载
import paddle
import numpy as np
import os
import paddle.fluid as fluid
import matplotlib.pyplot as plt
# 1.准备数据
BUF_SIZE = 500 # 样本随机处理笔数
BATCH_SIZE = 20 # 批次大小
#boston_reader
boston_reader = paddle.dataset.uci_housing.train() # 训练集读取器
# 随机读取器
random_reader = paddle.reader.shuffle(boston_reader,
buf_size=BUF_SIZE)# 间隔多少个样本打乱一次
# 批量读取器
train_reader = paddle.batch(random_reader,
batch_size=BATCH_SIZE) # 每个批次有多少个样本
# 打印查看
# for i in train_reader():
# print(i)
# break
# 2.定义模型损失函数优化器
# 占位符
x = fluid.layers.data(name='x', # 名称
shape=[13], # 形状 一维,13个值
dtype='float32') # 数据类型
y = fluid.layers.data(name='y', # 名称
shape=[1], # 形状 一维,1个值
dtype='float32') # 数据类型
# 线性模型
y_predict = fluid.layers.fc(input=x, # 输入
size=1, # 输出个数值
act=None) # 不使用激活函数
# 损失函数(均方误差)
cost = fluid.layers.square_error_cost(input=y_predict, # 预测值
label=y) # 真实值
avg_cost = fluid.layers.mean(cost) # 均方误差
# 优化器
optimzer = fluid.optimizer.SGD(learning_rate=0.001) # 学习率
optimzer.minimize(avg_cost) # 指定优化的目标函数
# 3.训练保存模型
# 执行器
place = fluid.CPUPlace() # CPU
exe = fluid.Executor(place) # 执行器
exe.run(fluid.default_startup_program()) # 初始化
# feeder
feeder = fluid.DataFeeder(feed_list=[x,y], # 喂入哪些参数
place=place)# 在哪个设备上运行
iter = 0
iters = [] # 存放迭代次数
train_costs = [] # 存放损失值
for epoch in range(10): # 外层循环控制轮次
i = 0
for data in train_reader(): # 内层循环控制批次
i += 1
c = exe.run(
program=fluid.default_main_program(),
feed=feeder.feed(data), # feed()方法返回字典
fetch_list=[avg_cost]) # 要返回的值
if i % 10 == 0:
print("epoch: %d,cost: %f"%(epoch,c[0][0]))
iter = iter + BATCH_SIZE
iters.append(iter) # 存放迭代次数
train_costs.append(c[0][0]) # 记录损失值
# 保存模型
model_save_dir = 'model/' # 模型保存目录
if not os.path.exists(model_save_dir):
os.mkdir(model_save_dir) # 不存在就创建
# 保存用于可以增量训练的模型
# fluid.io.save_persistables()
# 保存用于推理的模型
fluid.io.save_inference_model(model_save_dir, # 模型保存目录
['x'], # 模型预测时需要喂入的参数名称
[y_predict], # 模型预测结果
exe) # 执行器
# 训练过程可视化
plt.figure("Training Cost")
plt.title("Training Cost", fontsize=24)
plt.xlabel("iter", fontsize=14)
plt.ylabel("cost", fontsize=14)
plt.plot(iters, train_costs, color="red", label="Training Cost")
plt.grid()
plt.savefig("train.png")
# 4.加载推理模型
infer_exe = fluid.Executor(place) # 用于推理的执行器
# 加载模型
# infer_prog 专门用于推理的program
# feed_vars 执行推理时需要传入的参数列表
# fetch_targets 预测结果从这里获取
# model_save_dir 保存路径
# infer_exe 执行器
infer_prog,feed_vars,fetch_targets = fluid.io.load_inference_model(model_save_dir,infer_exe)
## 测试集reader
infer_reader = paddle.batch(
paddle.dataset.uci_housing.test(),#测试集
batch_size=200) # 只有102笔数据,实际是一次性读取
test_data = next(infer_reader())#读取一批数据
# 取出输入标签部分
test_x = np.array([d[0] for d in test_data]).astype('float32')
test_y = np.array([d[1] for d in test_data]).astype('float32')
# 参数字典
params = {feed_vars[0]:test_x}
# 执行推理
results = infer_exe.run(
program=infer_prog,
feed=params, # 喂入的参数
fetch_list=[fetch_targets]) # 要返回的值
# print(results)
#
infer_result = [] # 预测值列表
ground_truths = [] # 真实值列表
# 取出每一个样本存入列表
for i in results[0]:
infer_result.append(i)
for i in test_y:
ground_truths.append(i)
## 绘图
plt.figure("Infer Result")
plt.title("Infer Result")
plt.xlabel("Ground Truth")
plt.ylabel("Infer Result")
x = np.arange(1, 30) # 产生一个均匀数组,作为斜线x坐标
y = x # 斜线y坐标
plt.plot(x, y) # 绘制y=x斜线
plt.scatter(ground_truths, infer_result,
color="green", label="Test")
plt.grid() # 网格线
plt.legend() # 图例
plt.savefig("predict.png")#图片保存到文件
plt.show()
最后一次更新于2023-07-26 15:07
0 条评论