要进行paddlepaddle Fluid单机训练,需要准备数据和配置简单网络。当配置简单的网络完毕后,可以得到两个fluid.Program,startup_program和main_program。默认情况下,可以使用fluid.default_startup_program()与fluid.default_main_program()获取全局的fluid.Program。
1:定义网络简单模型
import paddle.fluid as fluid image=fluid.layers.data(name="image",shape=[784]) label=fluid.layers.data(name="label",shape=[1]) hidden=fluid.layers.fc(input=image,size=100,act='relu') prediction=fluid.layers.fc(input=hidden,size=10,act='softmax') loss=fluid.layers.mean( fluid.layers.cross_entropy( input=prediction, label=label ) ) sgd=fluid.optimizer.SGD(learning_rate=0.001).minimize(loss) exe=fluid.Executor(fluid.CUDAPlace(0)) exe.run(program=fluid.default_startup_program()) #如果使用多GPU训练,参数需要在GPU0上初始化,再由fluid.ParalleExecutor #分发到多显卡上。
2:初始化参数
2.1 参数随机初始化
用户配置完模型后,参数初始化操作会被写入到fluid.default_startup_program()
中。使用 fluid.Executor()
运行 这一程序,即可在全局 fluid.global_scope()
中随机初始化参数。例如:
exe=fluid.Executor(fluid.CUDAPlace(0))
exe.run(program=fluid.default_satrt_program())
如果使用多GPU训练,参数需要在GPU0上初始化,再经由fluid.ParallelExecutor分发到多张显卡上。
2.2 载入预定义参数
在神经网络训练过程中,经常会需要载入预定义模型,进而继续训练。如何载入预定义参数进行预训练,即载入预定义模型。
2.2.1保存与载入模型变量
paddlepaddle fluid中,所欲模型变量都用fluid.Variable()作为基类进行表示。模型变量可以分为以下几种类别:
模型变量包括:模型参数、长期变量和临时变量。
2.2.1.1: 模型参数:
模型参数是深度学习中被训练和学习变量,在训练过程中,训练框架根据反向传播算法计算出每个模型参数当前的梯度,并用优化器根据梯度对参数进行更新。模型的训练过程本质上可以看作是模型参数不断迭代更新的过程。在paddlepaddle fluid中,模型参数使用fluid.framwork.Parameter来表示,这是一个fluid.Variable()的派生类,除了fluid.Variable()具有的各项性质之外,fluid.framework.parameter还可以配置自身的初始化方法、更新率等属性。
2.2.1.2 长期变量
长期变量指的是在整个训练过程中持续存在、不会因为一个迭代的结束而被销毁的变量,例如动态调节的全局学习率等。在paddlepaddle fluid中,长期变量通过将fluid.Variable()的persistable属性设置为true来表示。
2.2.1.3 临时变量
不属于上面两个类别的所有模型变量都是临时变量,这种类型的变量只在一个训练迭代中存在,在每一个迭代结束后, 所有的临时变量都会被销毁,然后在下一个迭代开始之前,又会先构造出新的临时变量供本轮迭代使用。 一般情况下模型中的大部分变量都属于这一类别,例如输入的训练数据、一个普通的layer的输出等等。
2.2.2 如何保存模型变量
根据用途的不同,我们需要保存的模型变量也不同的。例如,如果我们只想保存模型用来进行以后的预测,那么只保存模型就足够了。单如果我们需要保存一个checkpoint以备将来恢复模型训练,那么我们应该将各种长期变量都保存下来,甚至还需要基类当前epoch和step的id。因为一些模型变量虽然不是参数,但是对于模型训练依然必不可少。
因此根据需求的不同,有两套分别进行模型的参数和checkpoint的保存。
2.2.2.1保存模型用于对新样本的预测
import paddle.fluid as fluid exe=fluid.Executor(fluid.CPUPlace()) param_path="./my_paddle_model" prog=fluid.default_main_program() fluid.io.save_params(executor=exe,dirname=param_path,main_program=None)
上面的例子中使用fluid.io.save_params函数,paddlepadlle Fluid会对默认fluid.program也就是prog中所有模型变量进行扫描,筛选出其中 所有的模型参数,并将这些参数保存到指定的param_path之中。
2.2.2.2保存checkpoint用于恢复训练
在训练过程中,我们可能希望在一些节点上将当前的训练状态保存下来, 以便在将来需要的时候恢复训练环境继续进行训练。这一般被称作“checkpoint”。 想要保存checkpoint,可以使用 fluid.io.save_checkpiont()
接口。
path="./checkpoints" prog=fluid.default_main_program() trainer_args={"epoch_id":200, "step_id":20 } fluid.io.save_checkpoint(executor=exe, checkpoint_dir=path, trainer_args=trainer_args, main_progrm=prog, max_num_checkpoints=3 )
上面的例子中,通过调用 fluid.io.save_checkpoint
函数,PaddlePaddle Fluid会对默认 fluid.Program
也就是 prog
中的所有模型变量进行扫描, 根据一系列内置的规则自动筛选出其中所有需要保存的变量,并将他们保存到指定的 path
目录下。
fluid.io.save_checkpoint
的各个参数中, trainer_id
在单机情况下设置为0即可; trainer_args
为一个Python dict,用于给定当前的epoch_id和step_id; max_num_checkpoints
用于表示的最大checkpoint数量, 如果目录中已经存在的checkpoint数量超过这个值,那最早的checkpoint将被删除。
2.2.3 如何载入模型变量
与模型变量保存相对应,有两套分别载入模型的参数和载入模型的checkpoint。
2.2.3.1载入模型用于对新样本的预测
对于通过fluid.io.save_params保存的模型,可以使用fluid.io.load_params来进行载入。
例如:
import paddle.fluid as fluid exe=fluid.Executor(fluid.CPUPlace()) param_path="./my_paddle_model" prog=fluid.default_main_program() fluid.io.load_params(executor=exe,dirname=param_path, mian_program=prog)
通过使用fluid.io.load_params函数,paddlepaddle fluid会对屏prog中的所有模型变量进行扫描,筛选出其中所有模型参数,并尝试从param_path只用读取加载它们。需要格外注意的是,这里的 prog
必须和调用 fluid.io.save_params
时所用的 prog
中的前向部分完全一致,且不能包含任何参数更新的操作。如果两者存在不一致, 那么可能会导致一些变量未被正确加载;如果错误地包含了参数更新操作,那可能会导致正常预测过程中参数被更改。 这两个 fluid.Program
之间的关系类似于训练 fluid.Program
和测试 fluid.Program
之间。
生成测试 fluid.Program
通过clone克隆训练fluid.Program,生成测试fluid.program。
program.clone()方法可以复制出新的fluid.program。通过设置Program.clone(for_test=True)复制含有用于测试操作Program。
import paddle.fluid as fluid img = fluid.layers.data(name="image", shape=[784]) prediction = fluid.layers.fc( input=fluid.layers.fc(input=img, size=100, act='relu'), size=10, act='softmax' ) label = fluid.layers.data(name="label", shape=[1], dtype="int64") loss = fluid.layers.mean(fluid.layers.cross_entropy(input=prediction, label=label)) acc = fluid.layers.accuracy(input=prediction, label=label) test_program = fluid.default_main_program().clone(for_test=True) adam = fluid.optimizer.Adam(learning_rate=0.001) adam.minimize(loss)
在使用 Optimizer
之前,将 fluid.default_main_program()
复制成一个 test_program
。之后使用测试数据运行 test_program
,就可以做到运行测试程序,而不影响训练结果。
分别配置训练fluid.Program 和测试fluid.program
如果训练程序和测试程序相差较大时,用户也可以通过完全定义两个不同的 fluid.Program
,分别进行训练和测试。在PaddlePaddle Fluid中,所有的参数都有名字。如果两个不同的操作,甚至两个不同的网络使用了同样名字的参数,那么他们的值和内存空间都是共享的。
PaddlePaddle Fluid中使用 fluid.unique_name
包来随机初始化用户未定义的参数名称。通过 fluid.unique_name.guard
可以确保多次调用某函数参数初始化的名称一致。
import paddle.fluid as fluid def network(is_test): file_obj = fluid.layers.open_files(filenames=["test.recordio"] if is_test else ["train.recordio"], ...) img, label = fluid.layers.read_file(file_obj) hidden = fluid.layers.fc(input=img, size=100, act="relu") hidden = fluid.layers.batch_norm(input=hidden, is_test=is_test) ... return loss with fluid.unique_name.guard(): train_loss = network(is_test=False) sgd = fluid.optimizer.SGD(0.001) sgd.minimize(train_loss) test_program = fluid.Program() with fluid.unique_name.guard(): with fluid.program_gurad(test_program, fluid.Program()): test_loss = network(is_test=True)
2.2.3.2载入checkpoint用于恢复训练
对于通过fluid.io.save_checkpoint保存的模型,可以使用fluid.io.load_checkpoint来进行载入
import paddle.fluid as fluid exe = fluid.Executor(fluid.CPUPlace()) path = "./checkpoints" prog = fluid.default_main_program() fluid.io.load_checkpoint(executor=exe, checkpoint_dir=path, serial=9, main_program=prog)
2.3 训练
神经网络训练过程中,经常需要载入预定义模型,进而继续进行训练。下面介绍单卡和多卡上模型训练过程
2.3.1单卡训练
执行单卡训练可以使用 fluid.Executor()
中的 run()
方法,运行训练fluid.Program
即可。在运行的时候,用户可以通过 run(feed=...)
参数传入数据;用户可以通过 run(fetch=...)
获取持久的数据。例如:
loss = fluid.layers.mean(...) exe = fluid.Executor(...) # the result is an numpy array result = exe.run(feed={"image": ..., "label": ...}, fetch_list=[loss])
2.3.2 多卡训练
执行多卡训练使用fluid.ParalleExecutor运行训练fluid.Program。例如:
train_exe = fluid.ParallelExecutor(use_cuda=True, loss_name=loss.name, main_program=fluid.default_main_program()) train_exe.run(fetch_list=[loss.name], feed={...})
这里有几点注意事项:
ParallelExecutor
的构造函数需要指明要执行的fluid.Program
, 并在执行过程中不能修改。默认值是fluid.default_main_program()
。ParallelExecutor
需要明确指定是否使用 CUDA 显卡进行训练。在显卡训练模式下会占用全部显卡。用户可以配置 CUDA_VISIBLE_DEVICES 来修改占用的显卡。