(一)paddle1.8 静态图基础知识

一. 静态图基础概念

Paddle静态图中有以下几个基本的概念,包括:

  • Variable变量:包括网络中可学习参数、占位符和常量Variable等。Variable的值可以是int32float64等多种任何的类型。

  • Tensor数据和LoDTensor数据:Tensor和LoDTensor是paddle中的数据形式,和其他框架一样,Tensor可以简单理解成一个多维数组;而LoDTensor数据主要用于变长序列的数据表达。LoDTensor将长度不一致的维度拼接为一个维度,并引入了一个索引数据结构(LoD)来将张量进行辨识。

  • Operator操作(简称OP):在paddle中,所有对数据的操作都由Operator表示。例如,加减乘除的操作在Paddle中称为一个OP。

  • Program 程序Program描述了整个网络的计算过程。一个Program的集合通常包含初始化程序(startup_program)与主程序(main_program) 。初始化程序用于初始化,一般只运行一次来初始化参数,主程序将会包含用来训练的网络结构和变量。在每个mini batch中运行并更新权重。

  • Executor 执行器:用户完成对 Program 的定义后,需要使用Executor 执行器来执行Program,同时配置好feed输入数据(对应fulid.data占位符)和fecth_list输出列表。
    Executor 实际上将 Program 转化为C++后端可以执行的代码,以提高运行效率。

  • Name参数:一般用来作为网络层输出、权重的前缀标识。在 ParamAttr 中,可通过指定 name 参数实现多个网络层的权重共享

在paddle的静态图编程模式中,其基本的思路如下:

  • 首先,用户需要定义一些Operator,定义好后,系统会默认将这些Operator添加到fluid.default_main_program这个Program中;

  • 然后,初始化一个Executor 执行器,同时配置好Executor 执行器调用的硬件资源(CPU或GPU);

  • 最后,利用Executor 执行器运行Program的初始化程序(startup_program)与主程序(main_program)。

以下代码实现了这个基本思想:

import paddle.fluid as fluid
import numpy

# 1.定义占位符Variable变量,类似tf的placeholder
a = fluid.data(name="a",shape=[1],dtype='float32')
b = fluid.data(name="b",shape=[1],dtype='float32')

# 2.定义Operator,用户没有自定义Program时,系统自动添加到default_main_program()中
result = fluid.layers.elementwise_add(a,b)


# 3.定义执行器并指定硬件设备
cpu = fluid.core.CPUPlace() # 指定执行的设备为CPU
exe = fluid.Executor(cpu)

# 4.执行器运行默认的初始化startup_program()
exe.run(fluid.default_startup_program())

# 5. 执行器运行系统默认的main_program()
x = numpy.array([5]).astype("float32")
y = numpy.array([7]).astype("float32")
outs = exe.run(program=fluid.default_main_program(),
        feed={'a':x,'b':y}, # feed: 输入数据,用一个map输入,与占位符数据对应
        fetch_list=[result]) # fetch_list: 输出数据列表

# 6. 打印输出结果,[array([12.], dtype=float32)]
print( outs )

二. 静态图基本概念详解

1. Variable变量
  • 创建可学习参数

包括网络权重W、偏置b等可学习参数可以用一下方法创建:

w = fluid.layers.create_parameter(name="w",shape=[1],dtype='float32')
  • 创建占位 Variable

静态图模式下,通常不知道实际输入的信息,因此需要一个类似于tf.palceholder的占位变量,来接收输入数据,如下:

x = fluid.data(name="x", shape=[None,3,None], dtype="int64")

当遇到类似batch size这种无法确定的维度时,可以先指定为 None,程序执行过程中再确定。

  • 常量 Variable

Fluid 通过 fluid.layers.fill_constant 来实现常量Variable,

data = fluid.layers.fill_constant(shape=[1], value=0, dtype='int64')

注:Paddle高度集成化,一般用不到这级别的方法。例如可以使用构造一个全连接层。

2. Tensor 和 LodTensor

Tensor就是多维数组,而 LodTensor是Paddle中对Tensor的扩充。

在nlp的任务中,一个batch中包含多个句子,句子的长度可能会不一致,不能直接输入网络中。为了解决这种长度不一致问题,Paddle提供了两种解决方案:

  • padding,即在句子的结尾(或开头)添加padding;
  • LoDTensor,tensor中同时保存序列的长度信息;

LoDTensor的思想是将一个多维tensor进行flatten铺平,然后用一个额外LoD索引数组来记录结构信息。

例如,在NLP中,假设batch_size是2,在一个batch内,第一个序列包含一个单词,第二个序列话包含三个单词,则可以表示如下Tensor:


"""
# Tensor:

text = [
    array([[1]], dtype=int32), 
    array([[2],
           [3],
           [4]], dtype=int32)
]


"""

这个Tensor如果不作padding,则不能直接输入到模型中,
而如果将其转化为如下格式,便可以解决这个问题。

"""
# text对应的LoDTensor:

lod: {{0, 1, 4}}
	dim: 4, 1
	layout: NCHW
	dtype: int
	data: [1 2 3 4]


"""

LoDTensor中的data是text进行flatten的结果,lod索引列表记录
原来的序列信息,其中lod={{0, 1, 4}}表示data中[0,1)是第一个序列,[1,4)表示第二个序列

  • 创建 LoD-Tensor

# 1. 创建 LoD-Tensor

import paddle.fluid as fluid
import numpy as np

a = fluid.create_lod_tensor(np.array([[1], [2],[3],[4]]).astype('int32'), [[1,3]], fluid.CPUPlace())

#查看lod-tensor
print(a)

#查看lod索引
print(a.lod())


#查看lod-tensor嵌套层数
print (len(a.recursive_sequence_lengths()))

#查看最基础元素个数
print (sum(a.recursive_sequence_lengths()[-1]))

"""
output:

	lod: {{0, 1, 4}}
	dim: 4, 1
	layout: NCHW
	dtype: int
	data: [1 2 3 4]

[[0, 1, 4]]
1
4

"""
3. Program

paddle.fluid.Program的方法用于创建Program。在深度学习中,一般包含训练和测试两个阶段,在训练阶段包含需要进行反向传播更新参数,而测试阶段则不需要,因此通常训练和测试阶段的网络模型会被拆分成两个不同的Program进行

对于一个Program,会包含startup_program 来执行一些参数初始化工作
以及一个main_program 来容纳网络的OP。由于网络的训练和测试需要参数共享,因此当train阶段和test阶段使用同一个startup_program时,训练和测试程序的所有参数将会拥有同样的名字。在Paddle Fluid中同样的变量名便可以实现共享权重。因而实现了使训练和测试程序的参数共享,如以下代码所示:


import paddle.fluid as fluid
import six

def print_prog(prog):
    for name, value in sorted(six.iteritems(prog.block(0).vars)):
        print(value)
    for op in prog.block(0).ops:
        print("op type is {}".format(op.type))
        print("op inputs are {}".format(op.input_arg_names))
        print("op outputs are {}".format(op.output_arg_names))
        for key, value in sorted(six.iteritems(op.all_attrs())):
            if key not in ['op_callstack', 'op_role_var']:
                print(" [ attrs: {}:   {} ]".format(key, value))

def network():
    img = fluid.layers.data(name='image', shape=[784])
    hidden = fluid.layers.fc(input=img, size=200, act='relu')
    hidden = fluid.layers.dropout(hidden, dropout_prob=0.5)
    loss = fluid.layers.cross_entropy(
        input=fluid.layers.fc(hidden, size=10, act='softmax'),
        label=fluid.layers.data(name='label', shape=[1], dtype='int64'))
    avg_loss = fluid.layers.mean(loss)
    return avg_loss

train_program_2 = fluid.Program()
startup_program_2 = fluid.Program()
test_program_2 = fluid.Program()
with fluid.program_guard(train_program_2, startup_program_2):
    with fluid.unique_name.guard():
        avg_loss = network()
        sgd = fluid.optimizer.SGD(learning_rate=1e-3)
        sgd.minimize(avg_loss)
        
# 使用训练阶段的启动程序
with fluid.program_guard(test_program_2, startup_program_2):
    with fluid.unique_name.guard():
        avg_loss = network()
print_prog(test_program_2)

以test_program_2的定义可以使用Program.clone()进行代码简化,得到同样的结果,详见官网教程的Program API

其他:

  • Program中包括至少一个 Block ,Block 可以理解为一个由OP组成的代码块,当用户不指定Program式,系统将使用默认的 default_startup_programdefault_main_program将OP自动填入default_main_program 。

  • fluid.program_guard:可以使用with fluid.program_guard(main_program,, startup_program)将with 下的OP和Variable添加进指定的全局主程序(main program)和启动程序(startup program)。而当定义的网络不需要startup_program初始化各变量时,可以传入一个临时的program。

  • Program接口还存在查看num_blocks、list_vars()变量和all_parameters() 参数等多个属性。

4. Executor运行器
1. 初始化

paddle.fluid.Executor(place=None)中place为 fluid.CPUPlace()或fluid.CUDAPlace(N)|或None。

place该参数表示Executor执行所在的设备,这里的N为GPU对应的ID。
当该参数为 None 时:

  • 当安装的Paddle为CPU版时,默认运行设置会设置成 CPUPlace() ,
  • 而当Paddle为GPU版时,默认运行设备会设置成 CUDAPlace(0) 。默认值为None。
2. 方法
  • close()方法: 关闭执行器。
  • run()方法: 执行指定的Program或者CompiledProgram
  • train_from_datase()方法: 从预定义的数据集中训练。 数据集在paddle.fluid.dataset中定义。
  • infer_from_dataset()方法: infer_from_dataset的文档与train_from_dataset几乎完全相同,只是在分布式训练中,推进梯度将在infer_from_dataset中禁用。
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
知识蒸馏(Knowledge Distillation)是一种将大型模型的知识传递给小型模型的方法,从而实现小型模型的性能提升。在PaddlePaddle 2.0中,可以通过以下步骤实现知识蒸馏: 1. 加载大型模型和训练数据 ```python import paddle import paddle.nn.functional as F # 加载大型模型 teacher_model = paddle.Model(teacher_net) teacher_model.prepare() # 加载训练数据 train_dataset = paddle.vision.datasets.MNIST(mode='train') train_loader = paddle.io.DataLoader(train_dataset, batch_size=32, shuffle=True) ``` 2. 定义小型模型 ```python # 定义小型模型 class StudentNet(paddle.nn.Layer): def __init__(self): super(StudentNet, self).__init__() self.fc1 = paddle.nn.Linear(784, 256) self.fc2 = paddle.nn.Linear(256, 128) self.fc3 = paddle.nn.Linear(128, 10) def forward(self, x): x = F.relu(self.fc1(x)) x = F.relu(self.fc2(x)) x = self.fc3(x) return x student_net = StudentNet() ``` 3. 定义知识蒸馏损失函数 ```python # 定义知识蒸馏损失函数 def distillation_loss(logits_s, logits_t, T): p_s = F.softmax(logits_s / T, axis=1) p_t = F.softmax(logits_t / T, axis=1) loss = -p_t * F.log_softmax(logits_s / T, axis=1) loss = paddle.mean(loss) return loss ``` 4. 定义优化器和学习率 ```python # 定义优化器和学习率 optimizer = paddle.optimizer.Adam(parameters=student_net.parameters(), learning_rate=0.001) lr_scheduler = paddle.optimizer.lr.ExponentialDecay(learning_rate=0.001, gamma=0.95, verbose=True) ``` 5. 训练小型模型并进行知识蒸馏 ```python # 训练小型模型并进行知识蒸馏 for epoch in range(10): for batch_id, data in enumerate(train_loader()): x, y = data logits_t = teacher_model.predict_batch(x) logits_s = student_net(x) loss = distillation_loss(logits_s, logits_t, T=10.0) loss.backward() optimizer.step() optimizer.clear_grad() if batch_id % 100 == 0: print('Epoch [{}/{}], Batch [{}/{}], Loss: {:.4f}'.format(epoch+1, 10, batch_id+1, len(train_loader), loss.numpy()[0])) lr_scheduler.step() ``` 在训练过程中,我们首先使用大型模型对训练数据进行预测,并将预测结果作为知识蒸馏的“标签”,然后使用小型模型对训练数据进行预测,并计算知识蒸馏损失函数。最后,使用优化器对小型模型的参数进行更新,重复以上步骤直至训练结束。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值