diff --git a/ci_scripts/api_white_list.txt b/ci_scripts/api_white_list.txt index 4c6a6bf113739606de13be095546ad38eb18714c..a50852af163ac286d3e8cba504078e746783fd79 100644 --- a/ci_scripts/api_white_list.txt +++ b/ci_scripts/api_white_list.txt @@ -7,3 +7,4 @@ paddle/optimizer/Dpsgd_cn.rst paddle/reader/ComposeNotAligned_cn.rst paddle/fluid/layers/scatter_cn.rst paddle/tensor/manipulation/scatter_cn.rst +paddle/distributed/fleet/Fleet_cn.rst diff --git a/doc/paddle/guides/index_cn.rst b/doc/paddle/guides/index_cn.rst index 22c01a2181ef8af898663ddcf6af1708ee994c5b..1771e283f6b50a5e14f17bc15dbeb9db8dd2aa12 100644 --- a/doc/paddle/guides/index_cn.rst +++ b/doc/paddle/guides/index_cn.rst @@ -2,23 +2,24 @@ 使用教程 ######## -PaddlePaddle (PArallel Distributed Deep LEarning)是一个易用、高效、灵活、可扩展的深度学习框架。 +飞桨开源框架(PaddlePaddle)是一个易用、高效、灵活、可扩展的深度学习框架。 -您可参考PaddlePaddle的 `Github `_ 了解详情,也可阅读 `版本说明 <../release_note_cn.html>`_ 了解新版本的特性。 - -让我们从学习PaddlePaddle基本概念这里开始: +您可参考飞桨框架的 `Github `_ 了解详情,也可阅读 `版本说明 <../release_note_cn.html>`_ 了解2.0beta版本的特性。 +让我们从学习飞桨的基本概念这里开始: - `Tensor概念介绍 `_ : 飞桨中数据的表示方式,Tensor概念介绍, -- `版本迁移 <./migration_cn.html>`_:介绍 Paddle 1 到Paddle 2的变化与Paddle1to2转换工具的使用。 -- `动态图转静态图 <./dygraph_to_static/index_cn.html>`_:介绍 Paddle 动态图转静态图的方法 -- `模型存储与载入 <./model_save_load_cn.html>`_:介绍 Paddle 模型与参数存储载入的方法 +- `飞桨框架2.0beta升级指南 <./upgrade_guide_cn.html>`_: 介绍飞桨开源框架2.0beta的主要变化和如何升级。 +- `版本迁移工具 <./migration_cn.html>`_: 介绍paddle1to2转换工具的使用。 +- `动态图转静态图 <./dygraph_to_static/index_cn.html>`_: 介绍飞桨动态图转静态图的方法 +- `模型存储与载入 <./model_save_load_cn.html>`_: 介绍飞桨模型与参数存储载入的方法 .. toctree:: :hidden: tensor_introduction.md + upgrade_guide_cn.md migration_cn.rst dygraph_to_static/index_cn.rst model_save_load_cn.rst diff --git a/doc/paddle/guides/migration_cn.rst b/doc/paddle/guides/migration_cn.rst index efd559c5fe334ba44fb8cdbee15e3f7dbd1ed7c3..e72dccbcdad39c7ea87d8a45ee6ef9cfe40b1d9d 100644 --- a/doc/paddle/guides/migration_cn.rst +++ b/doc/paddle/guides/migration_cn.rst @@ -1,43 +1,17 @@ -版本迁移 +版本迁移工具 ==================== -飞桨框架v2.0-beta,最重要的变化为API体系的全面升级以及动态图能力的全面完善。下文将简要介绍Paddle -2的变化。 +在飞桨框架2.0beta中,我们API的位置、命名、参数、行为,进行了系统性的调整和规范, 将API体系从1.X版本的 ``paddle.fluid.*`` 迁移到了 ``paddle.*`` 下。paddle.fluid目录下暂时保留了1.8版本API,主要是兼容性考虑,未来会被删除。 -主要变化 --------- - -在飞桨框架v2.0中,我们做了许多的升级。首先,全面完善了动态图模式,相较于静态图而言,动态图每次执行一个运算,可以立即得到结果,能够使算法的开发变得更加高效。此外,本版本对API目录,进行了较大的调整。将API体系从1.X版本的 -``paddle.fluid.*`` 迁移到了 ``paddle.*`` 下。原则上,Paddle -2仍支持Paddle 1下的所有语法。但是,我们会逐步废弃掉 ``paddle.fluid`` -下的API,强烈建议您将Paddle 1的代码迁移到Paddle -2下,以避免后续带来不必要的麻烦。下文将介绍手动与自动两种方式,来完成Paddle -1到Paddle 2的迁移。 - -手动将Paddle 1 的代码迁移到 Paddle 2 ------------------------------------- - -本节将介绍如何将您的代码手动的从Paddle 1迁移到Paddle 2。 - -1、API的变化 -~~~~~~~~~~~~ - -对于Paddle -1下的API,您可以通过我们提供的API升级表(TODO),查看每个API的升级关系,从而手动完成修改。 -### 2、句法的变化 在Paddle 1中,通过 ``with fluid.dygraph.guard():`` -开启动态图模式,在Paddle 2.0-beta中,可以直接通过 -``paddle.disable_static()``\ 开启动态图。 - -Paddle1to2 自动迁移您的代码到Paddle2 +使用版本迁移工具自动迁移您的paddle1.x的代码到Paddle2.0beta的代码 ------------------------------------ -Paddle 2 包含了许多API的变化,为了节约您将代码从Paddle 1迁移到Paddle -2的时间,我们提供了自动迁移工具–Paddle1to2,能够帮助您快速完成代码迁移。 +WARNING: 版本自动迁移工具并不能处理所有的情况,在使用本工具后,您仍然需要手工来进行检查并做相应的调整。 安装 ~~~~ -Paddle1to2可以通过pip的方式安装,方式如下: +paddle1to2工具可以通过pip的方式安装,方式如下: .. code:: ipython3 @@ -52,8 +26,7 @@ Paddle1to2 可以使用下面的方式,快速使用: ! paddle1to2 --inpath /path/to/model.py -这将在命令行中,以\ ``diff``\ 的形式,展示model.py从Paddle 1转换为Paddle -2的变化。如果您确认上述变化没有问题,只需要再执行: +这将在命令行中,以\ ``diff``\ 的形式,展示model.py从Paddle1.x转换为Paddle2.0beta的变化。如果您确认上述变化没有问题,只需要再执行: .. code:: ipython3 @@ -86,27 +59,24 @@ Paddle1to2 可以使用下面的方式,快速使用: 开始 ^^^^ -在使用Paddle 1to2前,需要确保您已经安装了Paddle 2.0-beta版本。 +在使用paddle1to2前,需要确保您已经安装了Paddle2.0beta版本。 .. code:: ipython3 import paddle print (paddle.__version__) - # TODO change to paddle 2.0-beta - .. parsed-literal:: - 0.0.0 + 2.0.0-beta0 -克隆\ `PaddlePaddle/models `__\ 来作为工具的测试。 +克隆\ `paddlePaddle/models `__\ 来作为工具的测试。 .. code:: ipython3 ! git clone https://github.com/PaddlePaddle/models - .. parsed-literal:: Cloning into 'models'... @@ -121,8 +91,7 @@ Paddle1to2 可以使用下面的方式,快速使用: 查看帮助文档 ^^^^^^^^^^^^ -paddle1to2 会随着 paddle -2.0-beta安装。所以您可以直接通过下面的方式,查看帮助文档。 +您可以直接通过下面的方式,查看帮助文档。 .. code:: ipython3 @@ -131,66 +100,66 @@ paddle1to2 会随着 paddle .. parsed-literal:: - usage: paddle1to2 [-h] [--log-level {DEBUG,INFO,WARNING,ERROR}] - [--no-log-file] [--log-filepath LOG_FILEPATH] --inpath - INPATH [--backup [BACKUP]] [--write] [--no-confirm] - [--refactor {refactor_import,norm_api_alias,args_to_kwargs,refactor_kwargs,api_rename,refactor_with,post_refactor}] - [--print-match] - - optional arguments: - -h, --help show this help message and exit - --log-level {DEBUG,INFO,WARNING,ERROR} - set log level, default is INFO - --no-log-file don't log to file - --log-filepath LOG_FILEPATH - set log file path, default is "report.log" - --inpath INPATH the file or directory path you want to upgrade. - --backup [BACKUP] backup directory, default is the "~/.paddle1to2/". - --write modify files in-place. - --no-confirm write files in-place without confirm, ignored without - --write. - --refactor {refactor_import,norm_api_alias,args_to_kwargs,refactor_kwargs,api_rename,refactor_with,post_refactor} - this is a debug option. Specify refactor you want to - run. If none, all refactors will be run. - --print-match this is a debug option. Print matched code and node - for each file. - - -Paddle 1的例子 + usage: paddle1to2 [-h] [--log-level {DEBUG,INFO,WARNING,ERROR}] + [--no-log-file] [--log-filepath LOG_FILEPATH] --inpath + INPATH [--backup [BACKUP]] [--write] [--no-confirm] + [--refactor {refactor_import,norm_api_alias,args_to_kwargs,refactor_kwargs,api_rename,refactor_with,post_refactor}] + [--print-match] + + optional arguments: + -h, --help show this help message and exit + --log-level {DEBUG,INFO,WARNING,ERROR} + set log level, default is INFO + --no-log-file don't log to file + --log-filepath LOG_FILEPATH + set log file path, default is "report.log" + --inpath INPATH the file or directory path you want to upgrade. + --backup [BACKUP] backup directory, default is the "~/.paddle1to2/". + --write modify files in-place. + --no-confirm write files in-place without confirm, ignored without + --write. + --refactor {refactor_import,norm_api_alias,args_to_kwargs,refactor_kwargs,api_rename,refactor_with,post_refactor} + this is a debug option. Specify refactor you want to + run. If none, all refactors will be run. + --print-match this is a debug option. Print matched code and node + for each file. + + +paddle1.x的例子 ^^^^^^^^^^^^^^ -这里是一个基于Paddle 1实现的一个mnist分类,部分内容如下: +这里是一个基于paddle1.x实现的一个mnist分类,部分内容如下: .. code:: ipython3 ! head -n 198 models/dygraph/mnist/train.py | tail -n 20 -.. parsed-literal:: +.. code:: ipython3 - with fluid.dygraph.guard(place): - if args.ce: - print("ce mode") - seed = 33 - np.random.seed(seed) - fluid.default_startup_program().random_seed = seed - fluid.default_main_program().random_seed = seed - - if args.use_data_parallel: - strategy = fluid.dygraph.parallel.prepare_context() - mnist = MNIST() - adam = AdamOptimizer(learning_rate=0.001, parameter_list=mnist.parameters()) - if args.use_data_parallel: - mnist = fluid.dygraph.parallel.DataParallel(mnist, strategy) - - train_reader = paddle.batch( - paddle.dataset.mnist.train(), batch_size=BATCH_SIZE, drop_last=True) - if args.use_data_parallel: - train_reader = fluid.contrib.reader.distributed_batch_reader( - train_reader) - - -使用Paddle1to2进行转化 + with fluid.dygraph.guard(place): + if args.ce: + print("ce mode") + seed = 33 + np.random.seed(seed) + fluid.default_startup_program().random_seed = seed + fluid.default_main_program().random_seed = seed + + if args.use_data_parallel: + strategy = fluid.dygraph.parallel.prepare_context() + mnist = MNIST() + adam = AdamOptimizer(learning_rate=0.001, parameter_list=mnist.parameters()) + if args.use_data_parallel: + mnist = fluid.dygraph.parallel.DataParallel(mnist, strategy) + + train_reader = paddle.batch( + paddle.dataset.mnist.train(), batch_size=BATCH_SIZE, drop_last=True) + if args.use_data_parallel: + train_reader = fluid.contrib.reader.distributed_batch_reader( + train_reader) + + +使用paddle1to2进行转化 ^^^^^^^^^^^^^^^^^^^^^^ paddle1to2支持单文件的转化,您可以通过下方的命令直接转化单独的文件。 @@ -227,8 +196,7 @@ paddle1to2支持单文件的转化,您可以通过下方的命令直接转化 - 本迁移工具不能完成所有API的迁移,有少量的API需要您手动完成迁移,具体信息可见WARNING。 -使用Paddle 2 +使用paddle 2 ~~~~~~~~~~~~ -完成迁移后,代码就从Paddle 1迁移到了Paddle 2,您就可以在Paddle -2下进行相关的开发。 +完成迁移后,代码就从paddle1.x迁移到了paddle2.0beta,您就可以在paddle2.0beta下进行相关的开发。 diff --git a/doc/paddle/guides/upgrade_guide_cn.md b/doc/paddle/guides/upgrade_guide_cn.md new file mode 100644 index 0000000000000000000000000000000000000000..6f15a4e70032cd3ea947ece370b617a0cf6c5ba8 --- /dev/null +++ b/doc/paddle/guides/upgrade_guide_cn.md @@ -0,0 +1,511 @@ +# 飞桨框架2.0beta升级指南 + +## 升级概要 +本版本是2.0版的公测版,相对1.8版本有重大升级,涉及开发方面的重要变化如下: + + - 动态图功能完善,动态图模下数据表示概念为Tensor,推荐使用动态图模式; + - API目录体系调整,API的命名和别名进行了统一规范化,虽然兼容老版API,但请使用新API体系开发; + - 数据处理、组网方式、模型训练、多卡启动、模型保存和推理等开发流程都有了对应优化,请对应查看说明; + +以上变化请仔细阅读本指南。对于已有模型的升级,我们还提供了2.0转换工具(见附录)提供更自动化的辅助。 +其他一些功能增加方面诸如动态图对量化训练、混合精度的支持、动静转换等方面不在本指南列出,具体可查看[Release Note](https://github.com/PaddlePaddle/Paddle/releases/tag/v2.0.0-beta0#)或对应文档。 + +## 一、动态图 + +### 推荐优先使用动态图模式 +飞桨2.0版本将会把动态图作为默认模式。2.0-beta版本虽然还未做默认切换,但推荐大家优先使用动态图模式,需要在程序开始时调用`paddle.disable_static`切换到动态图。2.0-rc版本后默认模式将切换为动态图,此行代码可删除。(2.0-rc版本后如果还想使用静态图,可通过调用`paddle.enable_static`切换)。 + +```python +import paddle + +# 2.0-beta版本需要调用下面代码,切换到动态图模式 +# 2.0-rc版本可以删除这一行 +paddle.disable_static() +``` + +### 使用Tensor概念表示数据 +静态图模式下,由于组网时使用的数据不能实时访问,Paddle用Variable来表示数据。 +动态图下,从直观性等角度考虑,将数据表示概念统一为Tensor。动态图下Tensor的创建主要有两种方法: + +1. 通过调用paddle.to_tensor函数,将python scalar/list,或者numpy.ndarray数据转换为Paddle的Tensor。具体使用方法,请查看官网的API文档。 + +```python +import paddle + +paddle.disable_static() +paddle.to_tensor(1) +paddle.to_tensor((1.1, 2.2)) +paddle.to_tensor(np.random.randn(3, 4)) +``` + +2. 通过调用``paddle.zeros, paddle.ones, paddle.full, paddle.arange, paddle.rand, paddle.randn, paddle.randint, paddle.normal, paddle.uniform`等函数,创建并返回Tensor。 + +## 二、API +### API目录结构 + +为了API组织更加简洁和清晰,将原来padddle.fluid.xxx的目录体系全新升级为paddle.xxx,并对子目录的组织进行了系统的条理化优化。同时还增加了高层API,可以高低搭配使用。paddle.fluid目录下暂时保留了1.8版本API,主要是兼容性考虑,未来会被删除。 +**基于2.0的开发任务,请使用paddle目录下的API,不要再使用paddle.fluid目录下的API。** 如果发现Paddle目录下有API缺失的情况,推荐使用基础API进行组合实现;您也可以通过在 [github](https://github.com/paddlepaddle/paddle) 上提issue的方式向我们反馈。 + +**2.0-beta版本的API 整体目录结构如下**: + +| 目录 | 功能和包含的API | +| :--- | --------------- | +| paddle.* | paddle根目录下保留了常用API的别名,当前包括:paddle.tensor和paddle.framework目录下的所有API | +| paddle.tensor | 跟tensor操作相关的API,比如:创建zeros, 矩阵运算matmul, 变换concat, 计算add, 查找argmax等 | +| paddle.nn | 跟组网相关的API,比如:Linear,卷积,LSTM,损失函数,激活函数等 | +| paddle.static.nn | 静态图下组网专用API,比如:输入占位符data, 全连接层fc, 控制流while_loop/cond | +| paddle.static | 静态图下基础框架相关API,比如:Variable, Program, Executor等 | +| paddle.framework | 框架通用API和动态图模式的API,比如:to_tensor, no_grad等 | +| paddle.optimizer | 优化算法相关API,比如:SGD,Adagrad, Adam等 | +| paddle.optimizer.lr_scheduler | 学习率衰减相关API | +| paddle.metric | 评估指标计算相关的API,比如:accuracy, auc等 | +| paddle.io | 数据输入输出相关API,比如:Dataset, DataLoader等 | +| paddle.device | 设备管理相关API,比如:CPUPlace, CUDAPlace等 | +| paddle.distributed | 分布式相关基础API | +| paddle.distributed.fleet | 分布式相关高层API | +| paddle.vision | 视觉领域API,比如,数据集,数据处理,常用基础网络结构,比如resnet | +| paddle.text | NLP领域API, 比如,数据集,数据处理,常用网络结构,比如Transformer | + +### API别名规则 + +- 为了方便用户使用,API会在不同的路径下建立别名: + - 所有framework, tensor目录下的API,均在paddle根目录建立别名;除少数特殊API外,其他API在paddle根目录下均没有别名。 + - paddle.nn目录下除functional目录以外的所有API,在paddle.nn目录下均有别名;functional目录中的API,在paddle.nn目录下均没有别名。 +- **推荐用户优先使用较短的路径的别名**,比如`paddle.add -> paddle.tensor.add`,推荐优先使用`paddle.add` +- 以下为一些特殊的别名关系,推荐使用左边的API名称: + - paddle.sigmoid -> paddle.tensor.sigmoid -> paddle.nn.functional.sigmoid + - paddle.tanh -> paddle.tensor.tanh -> paddle.nn.functional.tanh + - paddle.remainder -> paddle.mod -> paddle.floor_mod + - paddle.divide -> paddle.true_divide + - paddle.rand -> paddle.uniform + - paddle.randn -> paddle.standard_normal + - Optimizer.clear_grad -> Optimizer.clear_gradients + - Optimizer.set_state_dict -> Optimizer.set_dict + - Optimizer.get_lr -> Optimizer.current_step_lr + - Layer.clear_grad -> Layer.clear_gradients + - Layer.set_state_dict -> Layer.set_dict + +### 常用API名称变化 + +- 加、减、乘、除使用全称,不使用简称 +- 对于当前逐元素操作,不加elementwise前缀 +- 对于按照某一轴操作,不加reduce前缀 +- Conv, Pool, Dropout, BatchNorm, Pad组网类API根据输入数据类型增加1d, 2d, 3d后缀 + + | Paddle 1.8 API名称 | Paddle 2.0-beta 对应的名称| + | --------------- | ------------------------ | + | paddle.fluid.layers.elementwise_add | paddle.add | + | paddle.fluid.layers.elementwise_sub | paddle.subtract | + | paddle.fluid.layers.elementwise_mul | paddle.multiply | + | paddle.fluid.layers.elementwise_div | paddle.divide | + | paddle.fluid.layers.elementwise_max | paddle.maximum | + | paddle.fluid.layers.elementwise_min | paddle.minimum | + | paddle.fluid.layers.reduce_sum | paddle.sum | + | paddle.fluid.layers.reduce_prod | paddle.prod | + | paddle.fluid.layers.reduce_max | paddle.max | + | paddle.fluid.layers.reduce_min | paddle.min | + | paddle.fluid.layers.reduce_all | paddle.all | + | paddle.fluid.layers.reduce_any | paddle.any | + | paddle.fluid.dygraph.Conv2D | paddle.nn.Conv2d | + | paddle.fluid.dygraph.Conv2DTranspose | paddle.nn.ConvTranspose2d | + | paddle.fluid.dygraph.Pool2D | paddle.nn.MaxPool2d, paddle.nn.AvgPool2d | + +## 三、开发流程 +### 数据处理 +数据处理推荐使用**paddle.io目录下的Dataset,Sampler, BatchSampler, DataLoader接口**,不推荐reader类接口。一些常用的数据集已经在paddle.vision.datasets和paddle.text.datasets目录实现,具体参考API文档。 + +```python +from paddle.io import Dataset + +class MyDataset(Dataset): + """ + 步骤一:继承paddle.io.Dataset类 + """ + def __init__(self, mode='train'): + """ + 步骤二:实现构造函数,定义数据读取方式,划分训练和测试数据集 + """ + super(MyDataset, self).__init__() + + if mode == 'train': + self.data = [ + ['traindata1', 'label1'], + ['traindata2', 'label2'], + ['traindata3', 'label3'], + ['traindata4', 'label4'], + ] + else: + self.data = [ + ['testdata1', 'label1'], + ['testdata2', 'label2'], + ['testdata3', 'label3'], + ['testdata4', 'label4'], + ] + + def __getitem__(self, index): + """ + 步骤三:实现__getitem__方法,定义指定index时如何获取数据,并返回单条数据(训练数据,对应的标签) + """ + data = self.data[index][0] + label = self.data[index][1] + + return data, label + + def __len__(self): + """ + 步骤四:实现__len__方法,返回数据集总数目 + """ + return len(self.data) + +# 测试定义的数据集 +train_dataset = MyDataset(mode='train') +val_dataset = MyDataset(mode='test') + +print('=============train dataset=============') +for data, label in train_dataset: + print(data, label) + +print('=============evaluation dataset=============') +for data, label in val_dataset: + print(data, label) +``` + +### 组网方式 +#### Sequential 组网 + +针对顺序的线性网络结构我们可以直接使用Sequential来快速完成组网,可以减少类的定义等代码编写。 + +```python +import paddle +paddle.disable_static() + +# Sequential形式组网 +mnist = paddle.nn.Sequential( + paddle.nn.Flatten(), + paddle.nn.Linear(784, 512), + paddle.nn.ReLU(), + paddle.nn.Dropout(0.2), + paddle.nn.Linear(512, 10) +) +``` + +#### SubClass组网 + + 针对一些比较复杂的网络结构,就可以使用Layer子类定义的方式来进行模型代码编写,在`__init__`构造函数中进行组网Layer的声明,在`forward`中使用声明的Layer变量进行前向计算。子类组网方式也可以实现sublayer的复用,针对相同的layer可以在构造函数中一次性定义,在forward中多次调用。 + +```python +import paddle +paddle.disable_static() + +# Layer类继承方式组网 +class Mnist(paddle.nn.Layer): + def __init__(self): + super(Mnist, self).__init__() + + self.flatten = paddle.nn.Flatten() + self.linear_1 = paddle.nn.Linear(784, 512) + self.linear_2 = paddle.nn.Linear(512, 10) + self.relu = paddle.nn.ReLU() + self.dropout = paddle.nn.Dropout(0.2) + + def forward(self, inputs): + y = self.flatten(inputs) + y = self.linear_1(y) + y = self.relu(y) + y = self.dropout(y) + y = self.linear_2(y) + + return y + +mnist = Mnist() +``` + +### 模型训练 + +#### 使用高层API + +增加了paddle.Model高层API,大部分任务可以使用此API用于简化训练、评估、预测类代码开发。注意区别Model和Net概念,Net是指继承paddle.nn.Layer的网络结构;而Model是指持有一个Net实例,同时指定损失函数、优化算法、评估指标的可训练、评估、预测的实例。具体参考高层API的代码示例。 + +```python +import paddle +paddle.disable_static() + +train_dataset = paddle.vision.datasets.MNIST(mode='train') +test_dataset = paddle.vision.datasets.MNIST(mode='test') +lenet = paddle.vision.models.LeNet() + +# Mnist继承paddle.nn.Layer属于Net,model包含了训练功能 +model = paddle.Model(lenet) + +# 设置训练模型所需的optimizer, loss, metric +model.prepare( + paddle.optimizer.Adam(learning_rate=0.001, parameters=model.parameters()), + paddle.nn.CrossEntropyLoss(), + paddle.metric.Accuracy(topk=(1, 2)) + ) + +# 启动训练 +model.fit(train_dataset, epochs=2, batch_size=64, log_freq=200) + +# 启动评估 +model.evaluate(test_dataset, log_freq=20, batch_size=64) +``` + +#### 使用基础API + +```python +import paddle + +paddle.disable_static() +train_dataset = paddle.vision.datasets.MNIST(mode='train') +test_dataset = paddle.vision.datasets.MNIST(mode='test') +lenet = paddle.vision.models.LeNet() + +# 加载训练集 batch_size 设为 64 +train_loader = paddle.io.DataLoader(train_dataset, places=paddle.CPUPlace(), batch_size=64, shuffle=True) + +def train(): + epochs = 2 + adam = paddle.optimizer.Adam(learning_rate=0.001, parameters=lenet.parameters()) + # 用Adam作为优化函数 + for epoch in range(epochs): + for batch_id, data in enumerate(train_loader()): + x_data, y_data = data + predicts = lenet(x_data) + loss = paddle.nn.functional.cross_entropy(predicts, y_data, reduction='mean') + acc = paddle.metric.accuracy(predicts, y_data, k=1) + avg_acc = paddle.mean(acc) + loss.backward() + if batch_id % 100 == 0: + print("epoch: {}, batch_id: {}, loss is: {}, acc is: {}".format(epoch, batch_id, loss.numpy(), avg_acc.numpy())) + adam.step() + adam.clear_grad() +# 启动训练 +train() +``` + +### 单机多卡启动 +2.0增加paddle.distributed.spawn函数来启动单机多卡训练,同时原有的paddle.distributed.launch的方式依然保留。 + +#### 方式1、launch启动 + +##### 高层API场景 + +当调用paddle.Model高层来实现训练时,想要启动单机多卡训练非常简单,代码不需要做任何修改,只需要在启动时增加一下参数`-m paddle.distributed.launch`。 + +```bash +# 单机单卡启动,默认使用第0号卡 +$ python train.py + +# 单机多卡启动,默认使用当前可见的所有卡 +$ python -m paddle.distributed.launch train.py + +# 单机多卡启动,设置当前使用的第0号和第1号卡 +$ python -m paddle.distributed.launch --selected_gpus='0,1' train.py + +# 单机多卡启动,设置当前使用第0号和第1号卡 +$ export CUDA_VISIABLE_DEVICES='0,1' +$ python -m paddle.distributed.launch train.py +``` + +##### 基础API场景 + +如果使用基础API实现训练,想要启动单机多卡训练,需要对单机单卡的代码进行4处修改,具体如下: + +```python +import paddle +import paddle.distributed as dist + +paddle.disable_static() +train_dataset = paddle.vision.datasets.MNIST(mode='train') +test_dataset = paddle.vision.datasets.MNIST(mode='test') + +# 加载训练集 batch_size 设为 64 +train_loader = paddle.io.DataLoader(train_dataset, places=paddle.CPUPlace(), batch_size=64, shuffle=True) + +def train(): + # 第1处改动,初始化并行环境 + dist.init_parallel_env() + + # 第2处改动,增加paddle.DataParallel封装 + net = paddle.DataParallel(LeNet()) + epochs = 2 + adam = paddle.optimizer.Adam(learning_rate=0.001, parameters=net.parameters()) + # 用Adam作为优化函数 + for epoch in range(epochs): + for batch_id, data in enumerate(train_loader()): + x_data = data[0] + y_data = data[1] + predicts = net(x_data) acc = paddle.metric.accuracy(predicts, y_data, k=2) + avg_acc = paddle.mean(acc) + loss = paddle.nn.functional.cross_entropy(predicts, y_data) + + # 第3处改动,归一化loss + avg_loss = net.scale_loss(avg_loss) + avg_loss.backward() + # 第4处改动,同步梯度 + net.apply_collective_grads() + if batch_id % 100 == 0: + print("epoch: {}, batch_id: {}, loss is: {}, acc is: {}".format(epoch, batch_id, avg_loss.numpy(), avg_acc.numpy())) + adam.step() + adam.clear_grad() + +# 启动训练 +train() +``` + +修改完后保存文件,然后使用跟高层API相同的启动方式即可 + +```bash +# 单机单卡启动,默认使用第0号卡 +$ python train.py + +# 单机多卡启动,默认使用当前可见的所有卡 +$ python -m paddle.distributed.launch train.py + +# 单机多卡启动,设置当前使用的第0号和第1号卡 +$ python -m paddle.distributed.launch --selected_gpus '0,1' train.py + +# 单机多卡启动,设置当前使用第0号和第1号卡 +$ export CUDA_VISIABLE_DEVICES='0,1' +$ python -m paddle.distributed.launch train.py +``` + +#### 方式2、spawn启动 + +launch方式启动训练,以文件为单位启动多进程,需要用户在启动时调用`paddle.distributed.launch`,对于进程的管理要求较高。2.0版本增加了spawn启动方式,可以更好地控制进程,在日志打印、训练退出时更友好。 + +```bash +# 启动train多进程训练,默认使用所有可见的GPU卡 +if __name__ == '__main__': + dist.spawn(train) + +# 启动train函数2个进程训练,默认使用当前可见的前2张卡 +if __name__ == '__main__': + dist.spawn(train, nprocs=2) + +# 启动train函数2个进程训练,默认使用第4号和第5号卡 +if __name__ == '__main__': + dist.spawn(train, nprocs=2, selelcted_gpus='4,5') +``` + +### 模型保存 +Paddle保存的模型有两种格式,一种是训练格式,保存模型参数和优化器相关的状态,可用于恢复训练;一种是预测格式,保存预测的静态图网络结构以及参数,用于预测部署。 +#### 高层API场景 + +高层API下用于预测部署的模型保存方法为: + +```python +model = paddle.Model(Mnist()) +# 预测格式,保存的模型可用于预测部署 +model.save('mnist', training=False) +# 保存后可以得到预测部署所需要的模型 +``` + +#### 基础API场景 + +动态图训练的模型,可以通过动静转换功能,转换为可部署的静态图模型,具体做法如下: + +```python +import paddle +from paddle.jit import to_static +from paddle.static import InputSpec + +class SimpleNet(paddle.nn.Layer): + def __init__(self): + super(SimpleNet, self).__init__() + self.linear = paddle.nn.Linear(10, 3) + + # 第1处改动 + # 通过InputSpec指定输入数据的形状,None表示可变长 + # 通过to_static装饰器将动态图转换为静态图Program + @to_static(input_spec=[InputSpec(shape=[None, 10], name='x'), InputSpec(shape=[3], name='y')]) + def forward(self, x, y): + out = self.linear(x) + out = out + y + return out + +paddle.disable_static() + +net = SimpleNet() + +# 第2处改动 +# 保存静态图模型,可用于预测部署 +paddle.jit.save(net, './simple_net') +``` +### 推理 +推理库Paddle Inference的API做了升级,简化了写法,以及去掉了历史上冗余的概念。API的变化为纯增,原有API保持不变,但推荐新的API体系,旧API在后续版本会逐步删除。 + +#### C++ API + +重要变化: + +- 命名空间从 `paddle` 变更为 `paddle_infer` +- `PaddleTensor`, `PaddleBuf` 等被废弃,`ZeroCopyTensor` 变为默认 Tensor 类型,并更名为 `Tensor` +- 新增 `PredictorPool` 工具类简化多线程 predictor 的创建,后续也会增加更多周边工具 +- `CreatePredictor` (原 `CreatePaddlePredictor`) 的返回值由 `unique_ptr` 变为 `shared_ptr` 以避免 Clone 后析构顺序出错的问题 + +API 变更 + +| 原有命名 | 现有命名 | 行为变化 | +| ---------------------------- | ---------------------------- | ----------------------------- | +| 头文件 `paddle_infer.h` | 无变化 | 包含旧接口,保持向后兼容 | +| 无 | `paddle_inference_api.h` | 新API,可以与旧接口并存 | +| `CreatePaddlePredictor` | `CreatePredictor` | 返回值变为 shared_ptr | +| `ZeroCopyTensor` | `Tensor` | 无 | +| `AnalysisConfig` | `Config` | 无 | +| `TensorRTConfig` | 废弃 | | +| `PaddleTensor` + `PaddleBuf` | 废弃 | | +| `Predictor::GetInputTensor` | `Predictor::GetInputHandle` | 无 | +| `Predictor::GetOutputTensor` | `Predictor::GetOutputHandle` | 无 | +| | `PredictorPool` | 简化创建多个 predictor 的支持 | + +使用新 C++ API 的流程与之前完全一致,只有命名变化 + +```c++ +#include "paddle_infernce_api.h" +using namespace paddle_infer; + +Config config; +config.SetModel("xxx_model_dir"); + +auto predictor = CreatePredictor(config); + +// Get the handles for the inputs and outputs of the model +auto input0 = predictor->GetInputHandle("X"); +auto output0 = predictor->GetOutputHandle("Out"); + +for (...) { + // Assign data to input0 + MyServiceSetData(input0); + + predictor->Run(); + + // get data from the output0 handle + MyServiceGetData(output0); +} +``` + +#### Python API + +Python API 的变更与 C++ 基本对应,会在2.0RC版发布。 + + +## 附录 +### 2.0转换工具 +为了降级代码升级的成本,我们提供了转换工具,可以帮助将Paddle 1.8版本开发的代码,升级为2.0-beta的API。由于相比于Paddle 1.8版本,2.0-beta版本的API进行了大量的升级,包括API名称,参数名称,行为等。转换工具当前还不能覆盖所有的API升级;对于无法转换的API,转换工具会报错,提示用户手动升级。 + +https://github.com/PaddlePaddle/paddle1to2 + +对于转换工具没有覆盖的API,请查看官网的API文档,手动升级代码的API。 + +### 2.0文档教程 +以下提供了2.0版本的一些示例教程: + +您可以在官网[应用实践](https://www.paddlepaddle.org.cn/documentation/docs/zh/2.0-beta/tutorial/index_cn.html)栏目内进行在线浏览,也可以下载在这里提供的源代码: +https://github.com/PaddlePaddle/book/tree/develop/paddle2.0_docs + +### 2.0API升级列表 +- [Release Note](https://github.com/PaddlePaddle/Paddle/releases/tag/v2.0.0-beta0#) +- [API新增列表](https://github.com/PaddlePaddle/Paddle/wiki/Paddle-2.0beta-New-API-List) +- [API升级列表](https://github.com/PaddlePaddle/Paddle/wiki/Paddle-2.0beta-Upgraded-API-List)