From e4539a63aeb21e602b5e1dfef490be5e5858cd7a Mon Sep 17 00:00:00 2001 From: Chen Long Date: Thu, 10 Sep 2020 09:07:04 +0800 Subject: [PATCH] Fix migration guide (#2578) * add migration test=develop * fix_logs test=develop * fix_migration_guide and add dygraph to static test=develop * fix_install test=develop * fix install and args * fix_style test=develop * fix docs test=develop --- .../dygraph_to_static/grammar_list_cn.rst | 116 +++++++++ .../guides/dygraph_to_static/index_cn.rst | 13 + .../program_translator_cn.rst | 182 ++++++++++++++ doc/paddle/guides/index_cn.rst | 6 +- doc/paddle/guides/migration.rst | 7 - doc/paddle/guides/migration_cn.rst | 237 +++++++++++++++++- 6 files changed, 547 insertions(+), 14 deletions(-) create mode 100644 doc/paddle/guides/dygraph_to_static/grammar_list_cn.rst create mode 100644 doc/paddle/guides/dygraph_to_static/index_cn.rst create mode 100644 doc/paddle/guides/dygraph_to_static/program_translator_cn.rst delete mode 100644 doc/paddle/guides/migration.rst diff --git a/doc/paddle/guides/dygraph_to_static/grammar_list_cn.rst b/doc/paddle/guides/dygraph_to_static/grammar_list_cn.rst new file mode 100644 index 000000000..b067ecb7f --- /dev/null +++ b/doc/paddle/guides/dygraph_to_static/grammar_list_cn.rst @@ -0,0 +1,116 @@ +ProgramTranslator支持的语法 +========================== + +ProgramTranslator本质是把Python运行语法转写为PaddlePaddle静态图代码,但是Python语法的表达能力和PaddlePaddle静态图表达能力存在不同,这使得一些代码无法被转换。 + +本章节我们将详细讲述在动转静过程中支持转化哪些语法,不支持哪些语法,并且讲述如何改写代码能够解决语法不支持的场景。 + +动转静支持的语法分为以下几个大类: + +控制流相关关键词 +------------------ + +控制流指if-elif-else,while等能够控制程序语句执行顺序的关键字。PaddlePaddle静态图通过cond,while_loop API来实现条件判断和循环,如果动态图Python控制流的判断条件/循环条件依赖 Paddle Tensor,动转静后会被转化为等价的Paddle控制流接口,否则仍然使用Python控制流逻辑运行。在动转静过程中这些关键字的转化情况为: + +1. if-elif-else 条件 + +当 ``if <条件>`` 中的条件是Tensor时,ProgramTranslator会把该if-elif-else语句转化为等价的cond API语句。否则会按普通Python if-elif-else的逻辑运行。需注意cond支持的Tensor只能是numel为1的bool Tensor,所以请使用这种Tensor进行条件判断,其他Tensor会报错。 + +2. while 循环 + +当while循环中的条件是Tensor时,ProgramTranslator会把该while语句转化为等价的while_loop API语句,否则会按普通Python while运行。需注意while循环条件中的Tensor只能是numel为1的bool Tensor,所以请使用这种Tensor进行条件判断,其他Tensor会报错。 + + +3. for 循环 + +3.1 ``for _ in range(__)`` 循环 + +ProgramTranslator先将其转化为等价的Python while循环,然后按while循环的逻辑进行动静转换。 + +3.2 ``for _ in x`` 循环 + +当x是Python容器或迭代器,则会用普通Python逻辑运行。当x是Tensor时,会转化为循环中每次对应拿出x[0], x[1], ... 。 + +3.3 ``for idx, val in enumerate(x)`` 循环 + +当x是Python容器或迭代器,则会用普通Python逻辑运行。当x是Tensor时,idx会转化为依次0,1,...的1-D Tensor。val会转化为循环中每次对应拿出x[0], x[1], ... 。 + +4. break,continue + +ProgramTranslator 可以支持在循环中添加break,continue语句,其底层实现原理是对于要break,continue的部分在相应时候使用cond在一定条件下跳过执行。 + +5. return + +ProgramTranslator 支持在循环,条件判断中return结果而不需要一定在函数末尾return。也能够支持return不同长度tuple和不同类型的Tensor。其底层实现原理是对return后的部分相应使用cond在一定条件下跳过执行。 + + +一些需要转化的运算类型 +------------------------ + +1. +,-,*,/,** 等Python内置运算 + +由于静态图有重载这些基本运算符,所以这些被ProgramTranslator转化后都适用相应重载的运算符,动转静支持此类运算。 + +2. and,or,not 逻辑运算 + +Python内置and,or,not逻辑运算关键词,ProgramTranslator在语句的运算时会判断逻辑运算关键词运行的对象是否是Tensor,如果都是Tensor,我们将其转化为静态图对应的逻辑运算接口并运行。 + +3. 类型转化 + +动态图中可以直接用Python的类型转化语法来转化Tensor类型。例如x是Tensor时,float(x)可以将x的类型转化为float。ProgramTranslator在运行时判断x是否是Tensor,如果是,则在动转静时使用静态图cast接口转化相应的Tensor类型。 + +Python 函数相关 +--------------------- + +1. print + +如果x是Tensor,在动态图模式中print(x)可以打印x的值。在动转静过程中我们把此转化为静态图的Print接口实现,使得在静态图中也能打印。如果print的参数不是Tensor,那么我们没有把相应print语句进行转写。 + +2. len + +如果x是Tensor,在动态图模式中len(x)可以获得x第0维度的长度。在动转静中我们把此转化为静态图shape接口,并返回shape的第0维。另外如果x是个TensorArray,那么len(x)将会使用静态图接口control_flow.array_length返回TensorArray的长度。对于其他情况,动转静时会按照普通Python len函数运行。 + +3. lambda 表达式 + +动转静允许写带有Python lambda表达式的语句,并且我们会适当改写使得返回对应结果。 + +4. 函数内再调用函数 + +对于函数内调用其他函数的情况,ProgramTranslator也会对内部的函数递归地进行动转静,这样做的好处是可以在最外层函数加一次装饰器就能进行动转静,而不需要每个函数都加装饰器。 + +报错异常相关 +-------------- + +1. assert + +如果x是Tensor,在动态图中可以通过assert x来强制x为True或者非0值,在动转静中我们把此转化为静态图Assert接口支持此功能。 + + +Python基本容器 +--------------- + +1. list:对于一个list如果里面元素都是Tensor,那么动转静会转化其为TensorArray,静态图TensorArray可以支持append,pop,修改操作。因此ProgramTranslator在元素皆为Tensor的list中支持上面三种操作。换言之,其他list操作,比如sort无法支持。对于list中并非所有元素是Tensor的情况,ProgramTranslator会将其作为普通Python list运行。 + +2. dict:ProgramTranslator会将相应的dict中的Tensor添加进静态图Program,因此使用dict是动转静支持的语法。 + +动转静无法正确运行的情况 +-------------------------- + +1. Reshape后的变量调用其shape作为Paddle API参数。 + +具体表现比如 ``x = reshape(x, shape=shape_tensor)`` ,再使用 ``x.shape[0]`` 的值进行其他操作。这种情况会由于动态图和静态图的本质不同而使得动态图能够运行,但静态图运行失败。其原因是动态图情况下,API是直接返回运行结果,因此 ``x.shape`` 在经过reshape运算后是确定的。但是在转化为静态图后,因为静态图API只是组网,``shape_tensor`` 的值在组网时是不知道的,所以 ``reshape`` 接口组网完,静态图并不知道 ``x.shape`` 的值。PaddlePaddle静态图用-1表示未知的shape值,此时 ``x`` 的shape每个维度会被设为-1,而不是期望的值。 + +遇到这类情况我们建议尽量固定shape值,减少reshape操作。 + +2. 多重list嵌套读写Tensor + +具体表现如 ``l = [[tensor1, tensor2], [tensor3, tensor4]]`` ,因为现在静态图将元素全是Tensor的list转化为TensorArray,而Paddle的TensorArray还不支持多维数组,因此这种情况无法动转静正确运行。 + +遇到这类情况我们建议尽量用一维list,或者自己使用PaddlePaddle的create_array,array_read,array_write接口编写为TensorArray。 + +3. Tensor值在被装饰函数中转成numpy array进行运算 + +具体表现为在被装饰函数中没有返回Tensor时就使用 ``numpy.array(tensor)`` 将Tensor转化为numpy array并使用numpy接口进行运算。这种情况在动态图下因为Tensor有值是可以正常运行的,但是在静态图时由于Tensor只是组网变量,在没有运行时没有数值,因此无法进行numpy运算。 + +遇到这种情况我们建议在动转静的函数中尽量使用PaddlePaddle接口替代numpy接口进行运算。 + diff --git a/doc/paddle/guides/dygraph_to_static/index_cn.rst b/doc/paddle/guides/dygraph_to_static/index_cn.rst new file mode 100644 index 000000000..40ab04d3e --- /dev/null +++ b/doc/paddle/guides/dygraph_to_static/index_cn.rst @@ -0,0 +1,13 @@ +############### +动态图转静态图 +############### + +- `动态图转静态图 `_ :介绍了动态图转静态图的基本使用方法和架构原理 + +- `支持语法列表 `_ :介绍了动态图转静态图支持的语法以及罗列不支持的语法写法 + +.. toctree:: + :hidden: + + grammar_list_cn.rst + program_translator_cn.rst diff --git a/doc/paddle/guides/dygraph_to_static/program_translator_cn.rst b/doc/paddle/guides/dygraph_to_static/program_translator_cn.rst new file mode 100644 index 000000000..0475097fb --- /dev/null +++ b/doc/paddle/guides/dygraph_to_static/program_translator_cn.rst @@ -0,0 +1,182 @@ +动态图转静态图 +================ + +PaddlePadde的动态图具有接口易用、Python风格的编程体验、友好的debug交互等优点。在动态图模式下,代码是按照我们编写的顺序依次执行。这种机制更符合python程序员的习惯,可以很方便地将大脑中的想法快速地转化为实际代码,也更容易调试。但在部分性能方面,python速度负担太大,无法与C++相提并论。因此在工业界部署很多地方(如大型推荐系统、移动端)都倾向于直接使用C++来提速。 + +此时,静态图在部署方面更具有性能的优势。静态图程序在编译执行时,先搭建模型的神经网络结构,然后再对神经网络执行计算操作。预先搭建好的神经网络可以脱离python依赖,在C++端被重新解析执行。 + +动态图代码更易编写和debug,但在部署性能上,静态图更具优势。因此我们新增了动态图转静态图的功能,支持用户依然使用动态图编写组网代码。PaddlePaddle会对用户代码进行分析,自动转换为静态图网络结构,兼顾了动态图易用性和静态图部署性能两方面优势。 + +基本使用方法 +-------------- + +PaddlePaddle提供了两种动态图转静态图的方式,基于动态图trace的转换与基于源代码级别的转换的ProgramTranslator。 + +1. 基于trace的TracedLayer: + +trace是指在模型运行时记录下其运行过哪些算子。TracedLayer就是基于这种技术,在一次执行动态图的过程中,记录所有运行的算子,并构建和保存静态图模型。一个使用例子如下: + +我们先定义一个简单的Fully Connected网络: + +.. code-block:: python + + import numpy as np + import paddle + + class SimpleFcLayer(paddle.nn.Layer): + def __init__(self, feature_size, batch_size, fc_size): + super(SimpleFCLayer, self).__init__() + self._linear = paddle.nn.Linear(feature_size, fc_size) + self._offset = paddle.to_tensor( + np.random.random((batch_size, fc_size)).astype('float32')) + + def forward(self, x): + fc = self._linear(x) + return fc + self._offset + + +接下来是TracedLayer如何存储模型: + +.. code-block:: python + import paddle + from paddle.jit import TracedLayer + + paddle.disable_static() + + fc_layer = SimpleFcLayer(3, 4, 2) + in_np = np.random.random([3, 4]).astype('float32') + # 将numpy的ndarray类型的数据转换为Tensor类型 + input_var = paddle.to_tensor(in_np) + # 通过 TracerLayer.trace 接口将命令式模型转换为声明式模型 + out_dygraph, static_layer = TracedLayer.trace(fc_layer, inputs=[input_var]) + save_dirname = './saved_infer_model' + # 将转换后的模型保存 + static_layer.save_inference_model(save_dirname, feed=[0], fetch=[0]) + + +载入的模型可以使用静态图方式运行 + +.. code-block:: python + + place = paddle.CPUPlace() + exe = paddle.Executor(place) + program, feed_vars, fetch_vars = paddle.io.load_inference_model(save_dirname, exe) + fetch, = exe.run(program, feed={feed_vars[0]: in_np}, fetch_list=fetch_vars) + + +但是也正如我们阐述的原理,trace只是记录了一次执行涉及算子,若在用户的模型代码中,包含了依赖数据条件(包括输入的值或者shape)的控制流分支,即根据数据条件触发运行不同的算子,则TracedLayer无法正常工作。比如下面 + + +.. code-block:: python + + import paddle + + def func(input_var) + # if判断与输入input_var的shape有关 + if input_var.shape[0] > 1: + return paddle.cast(input_var, "float64") + else: + return paddle.cast(input_var, "int64") + + paddle.disable_static() + in_np = np.array([-2]).astype('int') + input_var = paddle.to_tensor(in_np) + out = func(input_var) + + +上例如果在使用TracedLayer.trace(func, inputs=[input_var]),由于trace只能记录if-else其中跑的一次算子,模型就无法按用户想要的根据input_var的形状进行if-else控制流保存。类似的控制流还有while/for循环的情况 + +2. 基于源代码转写的ProgramTranslator + +对于依赖数据的控制流,我们使用基于源代码转写的ProgramTranslator来进行动态图转静态图。其基本原理是通过分析python代码来将动态图代码转写为静态图代码,并在底层自动帮用户使用执行器运行。其基本使用方法十分简便,只需要在要转化的函数(该函数也可以是用户自定义动态图Layer的forward函数)前添加一个装饰器@paddle.jit.to_static,上面的例子转化如下,并且可以依旧使用该函数运行得到结果: + +.. code-block:: python + + import paddle + + @paddle.jit.to_static + def func(input_var) + # if判断与输入input_var的shape有关 + if input_var.shape[0] > 1: + out = paddle.cast(input_var, "float64") + else: + out = paddle.cast(input_var, "int64") + + paddle.disable_static() + in_np = np.array([-2]).astype('int') + input_var = paddle.to_tensor(in_np) + func(input_var) + + +若要存储转化后的静态图模型,可以调用paddle.jit.save,我们再以SimpleFcLayer为例,需要在SimpleFcLayer的forward函数添加装饰器: + +.. code-block:: python + + import numpy as np + import paddle + + class SimpleFcLayer(paddle.nn.Layer): + def __init__(self, feature_size, batch_size, fc_size): + super(SimpleFCLayer, self).__init__() + self._linear = paddle.nn.Linear(feature_size, fc_size) + self._offset = paddle.to_tensor( + np.random.random((batch_size, fc_size)).astype('float32')) + + @paddle.jit.to_static + def forward(self, x): + fc = self._linear(x) + return fc + self._offset + + +存储该模型可以使用paddle.jit.save接口: + +.. code-block:: python + + import paddle + + paddle.disable_static() + + fc_layer = SimpleFcLayer(3, 4, 2) + in_np = np.random.random([3, 4]).astype('float32') + input_var = paddle.to_tensor(in_np) + out = fc_layer(input_var) + + paddle.jit.save(mnist, "./mnist_dy2stat", input_spec=[input_var]) + +内部架构原理 +-------------- + +TracedLayer的原理就是trace,相对简单,因此我们在这里不展开描述。本节将主要阐述ProgramTranslator基于源代码将动态图代码转化为静态图代码。 + + +转化过程发生在用户开始调用被装饰的函数,转换过程在装饰器中实现。我们将内部涉及的过程分为以下几步: + +1. 函数与缓存 + +动态图转静态图的主体是函数(Function)。对于函数内包含的PaddlePaddle接口,如果是仅计算相关算子代码语句,那么因为PaddlePaddle动态图和静态图接口一致,我们不需要额外转换这些代码为静态图代码。但是对于动态图,此类代码接口是直接运行计算和返回结果,而对于静态图此类代码接口其实是组网。那么如果被转化的函数被调用多次,动态图转静态图后会多次组网添加对应算子,这显然会导致问题。为了解决这个问题以及为了加速动转静转化过程,我们维护了被装饰器装饰的函数(Function)与其输入形状(shape),数据类型(dtype)映射到被转化后组网的Program的缓存(Cache)。当要被转化的函数命中缓存,我们直接用对应存储的Program运行静态图得到结果,否则我们才进行语句转化,并且转化成功后的Program存储进缓存。 + +2. 动态图源码转AST(抽象语法树) + +动态图转静态图的最核心部分类似一个编译器,解析动态图代码语句为AST,再对应AST进行改写,最后反转回成静态图代码。从函数转化为代码字符串可以使用Python的inspect.getsource。从字符串Python提供了自带的ast库来解析字符串为 `AST `_ ,但是由于python2,python3的语法略有不同,为了避免我们需要额外处理这些python2,python3的不同情况,我们使用了统一python2,python3的开源AST处理 `gast库 `_ 。这些接口使得函数转化为AST没有本质上的困难。 + +3. AST改写和静态图源码转换 + +这部分为动转静最核心的部分,我们对支持的各种语法进行ast转写。其中最重要的python控制流,if-else,while,for循环被分别分析转化为PaddlePaddle静态图接口cond,while_loop等接口实现。我们对想转化的每一种主要语法创建一个Transformer(这里的Transformer是python ast转写的概念,而不是自然语言处理NLP领域的Transformer),每个Transformer扫一遍AST并进行对应的改写。最后被转化完成的AST我们使用gast提供的接口转回成源码。 + +4. 静态图源码作为动态图一部分运行的技术 + +为了动静转化更加易用和被转化的代码能在动态图中复用,我们在拥有源码后运行生成Program,并将这个Program作为一个大op,包装成动态图的一个op,这样既能把用户的代码转为静态图提速或者保存部署,另一方面如果用户想在python层使用生成的静态图代码作为动态图的一部分继续训练或者别的动态图运算也是可以直接使用。 + +5. 易用性与Debug功能在动转静过程的实现 + +正如AST转写类似编译器,而一般编译器都会提供debug断点,报错,输出一些中间代码等功能。我们在进行动转静时,万一用户的动态图代码出错,或者用户想断点调试,或者用户想看看被转化后的静态图代码是否符合其预期,我们也希望能够像编译器一样提供这些易用性功能,使得动转静兼顾性能和部署同时还具有易用性。我们这里将列出这些功能的实现方式 + +A. 报错对应到动态图代码行。由于被转化后的静态图代码和原动态图代码不同,python运行出错时会报静态图的错误,因此我们在每一次AST转写时添加AST节点对应的原动态图代码行等信息,在python报错栈中将静态图的报错转化成对应的动态图源码报错 + +B. 设置断点功能。我们保留了被转化后代码的中的pdb.set_trace(), 用户可以使用这种方式进行断点调试 + +C. 查看最后转化的静态图代码。我们输出为一个StaticLayer class,这个StaticLayer可以直接被调用,但是也存储转化后的代码,可以调用StaticLayer.code来获得转化后的代码。 + +D. 输出中间转化状态代码,甚至不同语法Transformer转化的代码,比如经过for循环转化后代码是什么样的。我们开放接口设定了log level来让用户可以打印中间状态转化的代码。 + + diff --git a/doc/paddle/guides/index_cn.rst b/doc/paddle/guides/index_cn.rst index b65b23d7e..004c9ee75 100644 --- a/doc/paddle/guides/index_cn.rst +++ b/doc/paddle/guides/index_cn.rst @@ -8,7 +8,8 @@ PaddlePaddle (PArallel Distributed Deep LEarning)是一个易用、高效、灵 让我们从学习PaddlePaddle基本概念这里开始: -- `版本转换工具 <./migration_cn.html>`_:介绍 Paddle转换工具的使用 +- `版本转换工具 <./migration_cn.html>`_:介绍 Paddle 1 到Paddle 2的变化与Paddle1to2转换工具的使用。 +- `动态图转静态图 <./dygraph_to_static/index_cn.html>`_:介绍 Paddle 动态图转静态图的方法 - `模型存储与载入 <./model_save_load_cn.html>`_:介绍 Paddle 模型与参数存储载入的方法 @@ -16,4 +17,5 @@ PaddlePaddle (PArallel Distributed Deep LEarning)是一个易用、高效、灵 :hidden: migration_cn.rst - model_save_load_cn.rst \ No newline at end of file + dygraph_to_static/index_cn.rst + model_save_load_cn.rst diff --git a/doc/paddle/guides/migration.rst b/doc/paddle/guides/migration.rst deleted file mode 100644 index 669408696..000000000 --- a/doc/paddle/guides/migration.rst +++ /dev/null @@ -1,7 +0,0 @@ -.. _guides_migration: - -================== -Migration Tools -================== - -how to use migration tools to upgrade your codes. diff --git a/doc/paddle/guides/migration_cn.rst b/doc/paddle/guides/migration_cn.rst index be0f4c6eb..bc9dec661 100644 --- a/doc/paddle/guides/migration_cn.rst +++ b/doc/paddle/guides/migration_cn.rst @@ -1,7 +1,234 @@ -.. _cn_guides_migration: +Paddle 1 to Paddle 2 +==================== -============ -版本转换工具 -============ +飞桨框架v2.0-beta,最重要的变化为API体系的全面升级以及动态图能力的全面完善。下文将简要介绍Paddle +2的变化。 -这是版本转换工具的说明。 +主要变化 +-------- + +在飞桨框架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 +------------------------------------ + +Paddle 2 包含了许多API的变化,为了节约您将代码从Paddle 1迁移到Paddle +2的时间,我们提供了自动迁移工具–Paddle1to2,能够帮助您快速完成代码迁移。 + +安装 +~~~~ + +Paddle1to2可以通过pip的方式安装,方式如下: + +.. code:: ipython3 + + ! pip install -U paddle1to2 + +基本用法 +~~~~~~~~ + +Paddle1to2 可以使用下面的方式,快速使用: + +.. code:: ipython3 + + ! paddle1to2 --inpath /path/to/model.py + +这将在命令行中,以\ ``diff``\ 的形式,展示model.py从Paddle 1转换为Paddle +2的变化。如果您确认上述变化没有问题,只需要再执行: + +.. code:: ipython3 + + ! paddle1to2 --inpath /path/to/model.py --write + +就会原地改写model.py,将上述变化改写到您的源文件中。 +注意:我们会默认备份源文件,到~/.paddle1to2/下。 + +参数说明如下: + +- –inpath 输入文件路径,可以为单个文件或文件夹。 +- –write + 是否原地修改输入的文件,默认值False,表示不修改。如果为True,表示对文件进行原地修改。添加此参数也表示对文件进行原地修改。 +- –backup + 可选,是否备份源文件,默认值为\ ``~/.paddle1to2/``\ ,在此路径下备份源文件。 +- –no-log-file + 可选,是否需要输出日志文件,默认值为False,即输出日志文件。 +- –log-filepath + 可选,输出日志的路径,默认值为\ ``report.log``\ ,输出日志文件的路径。 +- –no-confirm + 可选,输入文件夹时,是否逐文件确认原地写入,只在\ ``--write``\ 为True时有效,默认值为False,表示需要逐文件确认。 +- –log-level 可选,log级别,可为[‘DEBUG’,‘INFO’,‘WARNING’,‘ERROR’] + 默认值:\ ``INFO`` +- –refactor 可选,debug时使用。 +- –print-match 可选,debug时使用。 + +使用教程 +~~~~~~~~ + +开始 +^^^^ + +在使用Paddle 1to2前,需要确保您已经安装了Paddle 2.0-beta版本。 + +.. code:: ipython3 + + import paddle + print (paddle.__version__) + # TODO change to paddle 2.0-beta + + +.. parsed-literal:: + + 0.0.0 + + +克隆\ `PaddlePaddle/models `__\ 来作为工具的测试。 + +.. code:: ipython3 + + ! git clone https://github.com/PaddlePaddle/models + + +.. parsed-literal:: + + Cloning into 'models'... + remote: Enumerating objects: 8, done. + remote: Counting objects: 100% (8/8), done. + remote: Compressing objects: 100% (8/8), done. + remote: Total 35011 (delta 1), reused 0 (delta 0), pack-reused 35003 + Receiving objects: 100% (35011/35011), 356.97 MiB | 1.53 MiB/s, done. + Resolving deltas: 100% (23291/23291), done. + + +查看帮助文档 +^^^^^^^^^^^^ + +paddle1to2 会随着 paddle +2.0-beta安装。所以您可以直接通过下面的方式,查看帮助文档。 + +.. code:: ipython3 + + ! paddle1to2 -h + + +.. 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的例子 +^^^^^^^^^^^^^^ + +这里是一个基于Paddle 1实现的一个mnist分类,部分内容如下: + +.. code:: ipython3 + + ! head -n 198 models/dygraph/mnist/train.py | tail -n 20 + + +.. parsed-literal:: + + 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支持单文件的转化,您可以通过下方的命令直接转化单独的文件。 + +.. code:: ipython3 + + !paddle1to2 --inpath models/dygraph/mnist/train.py + +注意,对于参数的删除及一些特殊情况,我们都会打印WARNING信息,需要您仔细核对相关内容。 +如果您觉得上述信息没有问题,可以直接对文件进行原地修改,方式如下: + +.. code:: ipython3 + + !paddle1to2 --inpath models/dygraph/mnist/train.py --write + +此时,命令行会弹出下方的提示: + +.. code:: ipython3 + + "models/dygraph/mnist/train.py" will be modified in-place, and it has been backed up to "/Users/chenlong/.paddle1to2/train.py_backup_2020_09_09_20_35_15_037821". Do you want to continue? [Y/n]: + +输入\ ``y`` +后即开始执行代码迁移。为了高效完成迁移,我们这里采用了原地写入的方式。此外,为了防止特殊情况,我们会备份转换前的代码到 +``~/.paddle1to2`` 目录下,如果需要,您可以在备份目录下找到转换前的代码。 + +代码迁移完成后,会生成一个report.log文件,记录了迁移的详情。内容如下: + +.. code:: ipython3 + + ! cat report.log + +注意事项 +~~~~~~~~ + +- 本迁移工具不能完成所有API的迁移,有少量的API需要您手动完成迁移,具体信息可见WARNING。 + +使用Paddle 2 +~~~~~~~~~~~~ + +完成迁移后,代码就从Paddle 1迁移到了Paddle 2,您就可以在Paddle +2下进行相关的开发。 -- GitLab