本文参考链接:https://www.paddlepaddle.org.cn/documentation/docs/zh/beginners_guide/programming_guide/programming_guide.html
1.数据的表示和定义:paddle以Tensor来表示数据,Tensor是神经网络中传递的一种数据格式,简单理解就是多维数组
2. 使用paddle来创建数据(两种方式):
方式一:
fluid.data(name, shape, dtype='float32', lod_level=0)
方式二:
fluid.layers.fill_constant.fill_constant(shape, dtype, value, force_cpu=False, out=None)
使用方式二创建一个维度为[3, 4], 数据类型为int64的Tensor,其中所有元素均为16的代码如下
import paddle.fluid as fluid
data = fluid.layers.fill_constant(shape=[3, 4], value=16, dtype='int64')
print(data)
打印结果为
name: "fill_constant_0.tmp_0"
type {
type: LOD_TENSOR
lod_tensor {
tensor {
data_type: INT64
dims: 3
dims: 4
}
}
}
persistable: false
在网络运行过程中如果要查看Tensor中的数值有两种方式
方式一:利用 paddle.fluid.layers.Print
创建一个打印操作, 打印正在访问的Tensor
例如:
import paddle.fluid as fluid
data = fluid.layers.fill_constant(shape=[3, 4], value=16, dtype='int64')
data = fluid.layers.Print(data, message="Print data:")
place = fluid.CPUPlace()
exe = fluid.Executor(place)
exe.run(fluid.default_startup_program())
ret = exe.run()
打印结果为:
1577945741 Print data: The place is:CPUPlace
Tensor[fill_constant_0.tmp_0]
shape: [3,4,]
dtype: __int64
data: 16,16,16,16,16,16,16,16,16,16,16,16,
方式二为直接将变量添加到fetch_list中,后面再示例
3.组建网络
目标是实现一个加法运算,而在paddle中,关于计算类的API函数大多在paddle.fluid.layers
模块中
下面通过paddle.fluid.layers.elementwise_add()来实现用户输入数据的加法计算
例如:
import paddle.fluid as fluid
# 定义变量
a = fluid.data(name="a", shape=[None, 1], dtype='int64')
b = fluid.data(name="b", shape=[None, 1], dtype='int64')
# 组建网络(此处网络仅由一个操作构成,即elementwise_add)
result = fluid.layers.elementwise_add(a,b)
# 准备运行网络
cpu = fluid.CPUPlace() # 定义运算设备,这里选择在CPU下训练
exe = fluid.Executor(cpu) # 创建执行器
exe.run(fluid.default_startup_program()) # 网络参数初始化
# 读取输入数据
import numpy
data_1 = int(input("Please enter an integer: a="))
data_2 = int(input("Please enter an integer: b="))
x = numpy.array([[data_1]])
y = numpy.array([[data_2]])
# 运行网络
outs = exe.run(
feed={'a':x, 'b':y}, # 将输入数据x, y分别赋值给变量a,b
fetch_list=[result] # 通过fetch_list参数指定需要获取的变量结果
)
# 输出计算结果
print("%d+%d=%d" % (data_1,data_2,outs[0][0]))
出错了,看了下错误信息
我将a,b的变量类型都改为了int32,再次运行
有结果了,不过有警告,看不懂,先不管
这时如果想要获取在网络运行中a,b的值,可以将a,b一并加入到fetch_list中
例如:
# 运行网络
outs = exe.run(
feed={'a':x, 'b':y}, # 将输入数据x, y分别赋值给变量a,b
fetch_list=[a,b,result] # 通过fetch_list参数指定需要获取的变量结果
)
print(outs)
# 输出计算结果
结果为:
[array([[6]], dtype=int32), array([[7]], dtype=int32), array([[13]], dtype=int32)]
4.组建更复杂的网络
Paddle提供顺序、分支和循环三种执行逻辑,用户可以通过组合描述任意复杂的模型
顺序执行:
##定义一个数据类型为float32的二维数据组变量x,第一维的维度是未知的,第二维维度是13,所以x的形状可以表示为[None, 13]
x = fluid.data(name='x', shape=[None, 13], dtype='float32')
#预测的y值
y_predict = fluid.layers.fc(input=x, size=1, act=None)
##定义一个数据类型为float32的二维数据组变量y,第一维的维度是未知的,第二维维度是1,所以x的形状可以表示为[None, 1]
#喂入神经网络的y
y = fluid.data(name='y', shape=[None, 1], dtype='float32')
# 计算cost
cost = fluid.layers.square_error_cost(input=y_predict, label=y)
条件分支:
Paddle提供了 fluid.layers.Switch
和 fluid.layers.IfElse
两个API来实现条件分支的操作
ifelse
class paddle.fluid.layers.IfElse(cond, name=None)
这个类用于实现paddle的条件分支,每个IFElse包含两个block,true_block和false_block,cond为条件,条件符合则执行true_block中的语句块,不符合则执行false_block中的语句块,cond是一个shape为[N,1],数据类型为bool的二维数组
例如:
# 以下代码完成的功能:对x中大于0的数据减去10,对x中小于0的数据加上10,并将所有的数据求和
import numpy as np
import paddle.fluid as fluid
x = fluid.layers.data(name='x', shape=[4,1], append_batch_size=False, dtype='float32')
y = fluid.layers.data(name='y', shape=[4,1], append_batch_size=False, dtype='float32')
x_d = np.array([[3], [1], [-2], [-3]]).astype(np.float32)
y_d = np.zeros((4, 1)).astype(np.float32)
# 比较x, y对元素的大小,输出cond, cond是shape为[4, 1],数据类型为bool的2-D tensor。
# 根据输入数据x_d, y_d,可以推断出cond中的数据为[[true], [true], [false], [false]]
cond = fluid.layers.greater_than(x, y)
# 同其他常见OP不同的是,该OP返回的ie是一个IfElse OP的对象
ie = fluid.layers.IfElse(cond)
with ie.true_block():
# 在这个block中,根据cond条件,获取x中对应条件为true维度的数据,并减去10
out_1 = ie.input(x)
out_1 = out_1 - 10
ie.output(out_1)
with ie.false_block():
# 在这个block中,根据cond条件,获取x中对应条件为false维度的数据,并加上10
out_1 = ie.input(x)
out_1 = out_1 + 10
ie.output(out_1)
# 根据cond条件将两个block中处理后的数据进行合并,此处的output为输出,类型为List,List中的元素类型为Variable。
output = ie() # [array([[-7.], [-9.], [ 8.], [ 7.]], dtype=float32)]
# 将输出List中的第一个Variable获取出来,并计算所有元素和
out = fluid.layers.reduce_sum(output[0])
exe = fluid.Executor(fluid.CPUPlace())
exe.run(fluid.default_startup_program())
res = exe.run(fluid.default_main_program(), feed={"x":x_d, "y":y_d}, fetch_list=[out])
print(res)
# [array([-1.], dtype=float32)]
内部函数:
通过调用对象中的 with ie.true_block() 函数构建block,将条件为true下的计算逻辑放入此block中。如果没有构建相应的block,则对应条件维度下的输入数据不做改变。
通过调用对象中的 with ie.false_block() 函数构建block,将条件为false下的计算逻辑放入此block中。如果没有构建相应的block,则对应条件维度下的输入数据不做改变。
out = ie.input(x) 会将x中对应条件维度的数据获取出来放入到out中,支持block内部处理多个输入。
ie.output(out) 会将结果写入对应条件的输出中。
对象内部有 __call__() 函数,即通过对 output = ie() 的调用,将条件分别为True,False的block内部所有的输出进行融合作为整体的输出,输出的类型为列表,列表中每个元素的类型为Variable。
循环
while:
class paddle.fluid.layers.While(cond, is_test=False, name=None)
该类用于实现while循环控制功能,只要循环条件cond为True,就循环执行while循环体中的语句,直到cond为False为止。
参数:
cond (Variable) – 用于判断循环继续进行的条件,为数据类型bool型的Tensor,其shape必须为[1]。
is_test (bool,可选) – 用于表明是否在测试阶段执行,默认值为False。
name (str,可选) - 具体用法请参见 Name ,一般无需设置,默认值为None。
例如:
# 该示例代码展示整数循环+1,循环10次,输出计数结果
import paddle.fluid as fluid
import numpy as np
i = fluid.layers.fill_constant(shape=[1], dtype='int64', value=0) # 循环计数器
loop_len = fluid.layers.fill_constant(shape=[1],dtype='int64', value=10) # 循环次数
cond = fluid.layers.less_than(x=i, y=loop_len) # 循环条件 比较i和loop_len
while_op = fluid.layers.While(cond=cond)
with while_op.block(): # 循环体
i = fluid.layers.increment(x=i, value=1, in_place=True) #往上计数加1
fluid.layers.less_than(x=i, y=loop_len, cond=cond) # 更新循环条件
exe = fluid.Executor(fluid.CPUPlace())
exe.run(fluid.default_startup_program())
res = exe.run(fluid.default_main_program(), feed={}, fetch_list=[i])
print(res) # [array([10])]
5.一个完整的网络示例
一个典型的模型通常包括4个部分:输入数据定义,搭建网络(模型前向计算逻辑),定义损失函数,选择优化算法
下面通过一个简单的数据预测网络(线性回归),来完整的展示如何使用Paddle静态图方式完成一个深度学习模型的组建和训练
问题描述:给定一组数据
例如:
import paddle.fluid as fluid
import numpy
# 1.定义输入变量
# 假设输入数据X=[1 2 3 4],Y=[2 4 6 8],在网络中定义:
train_data = numpy.array([[1.0], [2.0], [3.0], [4.0]]).astype('float32')
y_true = numpy.array([[2.0], [4.0], [6.0], [8.0]]).astype('float32')
# 2.搭建网络(定义前向计算逻辑)
#
# 接下来需要定义预测值与输入的关系,本次使用一个简单的线性回归函数进行预测:
x = fluid.data(name='x', shape=[None, 1], dtype='float32')
y = fluid.data(name='y', shape=[None, 1], dtype='float32')
y_predict = fluid.layers.fc(input=x, size=1, act=None)
# 3.添加损失函数
# 完成模型搭建后,如何评估预测结果的好坏呢?我们通常在设计的网络中添加损失函数,以计算真实值与预测值的差。
# 在本例中,损失函数采用均方差函数:
#定义损失函数
cost = fluid.layers.square_error_cost(input=y_predict, label=y)
avg_cost = fluid.layers.mean(cost)
# 4.网络优化
# 确定损失函数后,可以通过前向计算得到损失值,并根据损失值对网络参数进行更新,
# 最简单的算法是随机梯度下降法:w=w−η⋅g,由 fluid.optimizer.SGD 实现:
#选择优化方法
sgd_optimizer = fluid.optimizer.SGD(learning_rate=0.01)
sgd_optimizer.minimize(avg_cost)
#网络参数初始化
cpu = fluid.CPUPlace()
exe = fluid.Executor(cpu)
exe.run(fluid.default_startup_program())
#开始训练,迭代100次
for i in range(100):
outs = exe.run(
feed={'x':train_data, 'y':y_true},
fetch_list=[y_predict, avg_cost])
print(outs)#输出如下:
'''
[array([[2.2844574],
[4.137839 ],
[5.9912205],
[7.8446016]], dtype=float32), array([0.03103533], dtype=float32)]
'''
可以看到迭代100次后,预测值y(predict)与真实值y_true已经差别不大