未验证 提交 af4654b6 编写于 作者: S SunAhong1993 提交者: GitHub

Add docs and project convertor code (#571)

* fix the convert.py args

* fix teh pad and add log_softmax

* rewrite docs

* rewrite docs

* rewrite docs

* rewrite docs

* rewrite docs

* Update torch.narrow.md

* Update x2paddle_model_zoo.md

* Update x2paddle_model_zoo.md

* fix the README.md

* Update README.md

* add code

* rm

* Update README.md

* Update demo.md

* Update README.md

* Update README.md

* remove tools

* modify README

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update demo.md

* Update demo.md

* Update demo.md

* Update demo.md

* Update demo.md

* add commitid

* Update pytorch2paddle.md

* Update README.md

* Update demo.md

* Update FAQ.md

* Update README.md

* Update README.md

* Update __init__.py

* Update torch.zeros.md

* Update README.md

* Update README.md

* Update README.md

* Update torchvision.models.md
上级 01e67698
...@@ -4,18 +4,16 @@ ...@@ -4,18 +4,16 @@
![python version](https://img.shields.io/badge/python-3.5+-orange.svg) ![python version](https://img.shields.io/badge/python-3.5+-orange.svg)
## 简介 ## 简介
X2Paddle用于不同框架模型或项目到PaddlePaddle框架模型或项目的迁移,旨在为飞桨开发者提升框架间迁移的效率。 X2Paddle用于不同框架模型或项目到PaddlePaddle框架模型或项目的转换,旨在为飞桨开发者提升框架间转换的效率。
X2Paddle支持Caffe/TensorFlow/ONNX/PyTorch的预测模型,一步转换至PaddlePaddle预测模型;同时,支持PyTorch训练项目,转换至PaddlePaddle项目,助力用户在PaddlePaddlePaddle上进行模型训练。 X2Paddle主要有***2大功能***
1. ***预测模型转换***:X2Paddle支持Caffe/TensorFlow/ONNX/PyTorch的预测模型,一步转换至PaddlePaddle预测模型。
### 架构设计 2. ***训练项目转换***:heart::heart::PyTorch训练项目,转换至PaddlePaddle项目,助力用户在PaddlePaddlePaddle上进行模型训练。
X2Paddle的架构设计着重考虑了对多深度学习框架的的支持以及代码的易读性、易扩展性,并且在多个层面的对转换后OP进行优化处理。
![](./docs/images/frame.png)
### 特性 ### 特性
- **支持主流深度学习框架**:目前已经支持Caffe/TensorFlow/ONNX/PyTorch四大框架的迁移,涵盖目前市面主流深度学习框架。 - **支持主流深度学习框架**:目前已经支持Caffe/TensorFlow/ONNX/PyTorch四大框架的预测模型的转换,PyTorch训练项目的转换,涵盖了目前市面主流深度学习框架。
- **支持的模型丰富**:在主流的CV和NLP模型上均支持转换,涵盖了19+个Caffe模型转换、27+个TensorFlow模型转换、32+个ONNX模型转换、27+个PyTorch模型转换、2+个PyTorch项目转换 - **支持的模型丰富**:在主流的CV和NLP模型上均支持转换,涵盖了19+个Caffe预测模型转换、27+个TensorFlow预测模型转换、32+个ONNX预测模型转换、27+个PyTorch预测模型转换、2+个PyTorch训练项目转换,详见 ***[支持列表](./docs/introduction/x2paddle_model_zoo.md)***
- **简洁易用**:一条命令行或者一个API即可完成模型转换。 - **简洁易用**:一条命令行或者一个API即可完成模型转换。
...@@ -30,7 +28,7 @@ X2Paddle的架构设计着重考虑了对多深度学习框架的的支持以及 ...@@ -30,7 +28,7 @@ X2Paddle的架构设计着重考虑了对多深度学习框架的的支持以及
- tensorflow : tensorflow == 1.14.0 - tensorflow : tensorflow == 1.14.0
- caffe : 无 - caffe : 无
- onnx : onnx >= 1.6.0 - onnx : onnx >= 1.6.0
- pytorch:torch >=1.5.0 (script方式暂不支持1.7.0) - pytorch:torch >=1.5.0 (预测模型转换中的script方式暂不支持1.7.0+)
## 安装 ## 安装
### 方式一:源码安装 ### 方式一:源码安装
...@@ -47,7 +45,7 @@ python setup.py install ...@@ -47,7 +45,7 @@ python setup.py install
pip install x2paddle --index https://pypi.python.org/simple/ pip install x2paddle --index https://pypi.python.org/simple/
``` ```
## 快速开始 ## 快速开始
### 预测模型转换 ### 功能一:预测模型转换
| 参数 | 作用 | | 参数 | 作用 |
| -------------------- | ------------------------------------------------------------ | | -------------------- | ------------------------------------------------------------ |
| --framework | 源模型类型 (tensorflow、caffe、onnx) | | --framework | 源模型类型 (tensorflow、caffe、onnx) |
...@@ -56,55 +54,53 @@ pip install x2paddle --index https://pypi.python.org/simple/ ...@@ -56,55 +54,53 @@ pip install x2paddle --index https://pypi.python.org/simple/
| --save_dir | 指定转换后的模型保存目录路径 | | --save_dir | 指定转换后的模型保存目录路径 |
| --model | 当framework为tensorflow/onnx时,该参数指定tensorflow的pb模型文件或onnx模型路径 | | --model | 当framework为tensorflow/onnx时,该参数指定tensorflow的pb模型文件或onnx模型路径 |
| --caffe_proto | **[可选]** 由caffe.proto编译成caffe_pb2.py文件的存放路径,当存在自定义Layer时使用,默认为None | | --caffe_proto | **[可选]** 由caffe.proto编译成caffe_pb2.py文件的存放路径,当存在自定义Layer时使用,默认为None |
| --define_input_shape | **[可选]** For TensorFlow, 当指定该参数时,强制用户输入每个Placeholder的shape,见[文档Q2](./docs/user_guides/FAQ.md) | | --define_input_shape | **[可选]** For TensorFlow, 当指定该参数时,强制用户输入每个Placeholder的shape,见[文档Q2](./docs/inference_model_convertor/FAQ.md) |
| --paddle_type | **[可选]** 该参数指定转换为动态图代码(dygraph)或者静态图代码(static),默认为dygraph |
#### TensorFlow #### TensorFlow
```shell
x2paddle --framework=tensorflow --model=tf_model.pb --save_dir=pd_model
``` ```
x2paddle --framework=tensorflow --model=tf_model.pb --save_dir=pd_model --paddle_type dygraph 【注意】目前只支持FrozenModel格式的TensorFlow模型到PaddlePaddle模型的转换,若为checkpoint或者SavedModel格式的TensorFlow模型参见[文档](./docs/inference_model_convertor/export_tf_model.md)导出FrozenModel格式模型。
```
#### Caffe #### Caffe
```shell
x2paddle --framework=caffe --prototxt=deploy.prototxt --weight=deploy.caffemodel --save_dir=pd_model
``` ```
x2paddle --framework=caffe --prototxt=deploy.prototxt --weight=deploy.caffemodel --save_dir=pd_model --paddle_type dygraph 【注意】若caffe模型中出现自定义层,需要按照[相关流程](./docs/inference_model_convertor/add_caffe_custom_layer.md)自行添加自定义层的转换代码。
```
#### ONNX #### ONNX
```shell
x2paddle --framework=onnx --model=onnx_model.onnx --save_dir=pd_model
``` ```
x2paddle --framework=onnx --model=onnx_model.onnx --save_dir=pd_model --paddle_type dygraph 【注意】如若需要将PyTorch模型转换为ONNX模型,可参见[PyTorch2ONNX转换文档](./docs/inference_model_convertor/pytorch2onnx.md)
```
#### PyTorch #### PyTorch
PyTorch仅支持API使用方式,详见[PyTorch预测模型转换文档](./docs/user_guides/pytorch2paddle.md) PyTorch仅支持API使用方式,详见[PyTorch预测模型转换文档](./docs/inference_model_convertor/pytorch2paddle.md)
### 训练项目转换 ***[预测模型转换常见问题](./docs/inference_model_convertor/FAQ.md)***
#### PyTorch
【待更新】可安装[分支](https://github.com/PaddlePaddle/X2Paddle/tree/pytorch_project_convertor)源码进行使用。
详见[PyTorch训练项目转换文档](https://github.com/SunAhong1993/X2Paddle/blob/code_convert_last/docs/pytorch_project_convertor/README.md)
### 功能二:训练项目转换:heart: :heart:
## 小工具 | 参数 | 作用 |
X2Paddle提供了工具解决如下问题,详见[tools/README.md](tools/README.md) |----------|--------------|
1. 检测模型是否在PaddleLite中支持 |--convert_torch_project | 表示使用对PyTorch Project进行转换的功能 |
2. 合并模型参数文件 |--project_dir | PyTorch的项目路径 |
|--save_dir | 指定转换后项目的保存路径 |
|--pretrain_model | **[可选]**需要转换的预训练模型的路径(文件后缀名为“.pth”、“.pt”、“.ckpt”)或者包含预训练模型的文件夹路径,转换后的模型将将保在当前路径,后缀名为“.pdiparams” |
```shell
x2paddle --convert_torch_project --project_dir=torch_project --save_dir=paddle_project --pretrain_model=model.pth
```
【注意】需要搭配预处理和后处理一起使用,详细可参见[训练项目转换文档](./docs/pytorch_project_convertor/README.md)。 此外,我们为用户提供了:star:[PyTorch-PaddlePaddle API映射表](docs/pytorch_project_convertor/API_docs/README.md):star:供用户查阅。
## 使用相关文档 ***[训练项目转换常见问题](./docs/pytorch_project_convertor/FAQ.md)***
1. [X2Paddle使用过程中常见问题](./docs/user_guides/FAQ.md)
2. [如何导出TensorFlow的Frozen Model](./docs/user_guides/export_tf_model.md)
3. [PyTorch模型导出为ONNX模型](./docs/user_guides/pytorch2onnx.md)
4. [X2Paddle添加内置的Caffe自定义层](./docs/user_guides/add_caffe_custom_layer.md)
5. [转换后PaddlePaddle预测模型简介](./docs/user_guides/pd_folder_introduction.py)
6. [Paddle到ONNX的转换](https://github.com/PaddlePaddle/Paddle2ONNX)
7. [X2Paddle测试模型库](./docs/introduction/x2paddle_model_zoo.md)
8. [X2Paddle支持的op列表](./docs/introduction/op_list.md)
## 转换教程 ## 转换教程
1. [TensorFlow预测模型转换教程](./docs/demo/tensorflow2paddle.ipynb) 1. [TensorFlow预测模型转换教程](./docs/inference_model_convertor/demo/tensorflow2paddle.ipynb)
2. [PyTorch预测模型转换教程](./docs/demo/pytorch2paddle.ipynb) 2. [PyTorch预测模型转换教程](./docs/inference_model_convertor/demo/pytorch2paddle.ipynb)
3. [PyTorch训练项目转换教程](./docs/pytorch_project_convertor/demo.md)
## 更新历史 ## 更新历史
2020.12.09 **2020.12.09**
1. 新增PyTorch2Paddle转换方式,转换得到Paddle动态图代码,并动转静获得inference_model。 1. 新增PyTorch2Paddle转换方式,转换得到Paddle动态图代码,并动转静获得inference_model。
方式一:trace方式,转换后的代码有模块划分,每个模块的功能与PyTorch相同。 方式一:trace方式,转换后的代码有模块划分,每个模块的功能与PyTorch相同。
方式二:script方式,转换后的代码按执行顺序逐行出现。 方式二:script方式,转换后的代码按执行顺序逐行出现。
...@@ -112,7 +108,7 @@ X2Paddle提供了工具解决如下问题,详见[tools/README.md](tools/README ...@@ -112,7 +108,7 @@ X2Paddle提供了工具解决如下问题,详见[tools/README.md](tools/README
3. 新增TensorFlow op映射(14个):Neg、Greater、FloorMod、LogicalAdd、Prd、Equal、Conv3D、Ceil、AddN、DivNoNan、Where、MirrorPad、Size、TopKv2。 3. 新增TensorFlow op映射(14个):Neg、Greater、FloorMod、LogicalAdd、Prd、Equal、Conv3D、Ceil、AddN、DivNoNan、Where、MirrorPad、Size、TopKv2。
4. 新增Optimizer模块,主要包括op融合、op消除功能,转换后的代码可读性更强,进行预测时耗时更短。 4. 新增Optimizer模块,主要包括op融合、op消除功能,转换后的代码可读性更强,进行预测时耗时更短。
2021.04.30 **2021.04.30**
1. 新增支持转换的模型:[SwinTransformer](https://github.com/microsoft/Swin-Transformer/)[BASNet](https://github.com/xuebinqin/BASNet)[DBFace](https://github.com/dlunion/DBFace)[EasyOCR](https://github.com/JaidedAI/EasyOCR)[CifarNet](https://github.com/tensorflow/models/blob/master/research/slim/nets/cifarnet.py)等。 1. 新增支持转换的模型:[SwinTransformer](https://github.com/microsoft/Swin-Transformer/)[BASNet](https://github.com/xuebinqin/BASNet)[DBFace](https://github.com/dlunion/DBFace)[EasyOCR](https://github.com/JaidedAI/EasyOCR)[CifarNet](https://github.com/tensorflow/models/blob/master/research/slim/nets/cifarnet.py)等。
2. 支持Windows上使用本工具。 2. 支持Windows上使用本工具。
3. 新增TensorFlow op映射(4个):SplitV、ReverseV2、BatchToSpaceND、SpaceToBatchND。 3. 新增TensorFlow op映射(4个):SplitV、ReverseV2、BatchToSpaceND、SpaceToBatchND。
...@@ -120,6 +116,11 @@ X2Paddle提供了工具解决如下问题,详见[tools/README.md](tools/README ...@@ -120,6 +116,11 @@ X2Paddle提供了工具解决如下问题,详见[tools/README.md](tools/README
5. 新增ONNX op映射(1个):DepthToSpace。 5. 新增ONNX op映射(1个):DepthToSpace。
6. 新增Caffe op映射(1个):MemoryData。 6. 新增Caffe op映射(1个):MemoryData。
## 贡献代码 **2021.05.13**
- 新增PyTorch训练项目功能:
支持转换的项目有[StarGAN](https://github.com/yunjey/stargan)[Ultra-Light-Fast-Generic-Face-Detector-1MB](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB)
## :hugs:贡献代码:hugs:
我们非常欢迎您为X2Paddle贡献代码或者提供使用建议。如果您可以修复某个issue或者增加一个新功能,欢迎给我们提交Pull Requests 我们非常欢迎您为X2Paddle贡献代码或者提供使用建议。如果您可以修复某个issue或者增加一个新功能,欢迎给我们提交Pull Requests,如果有PyTorch训练项目转换需求欢迎随时提issue~
# 一、 introduction
1. op_list.md:当前转换各个框架支持的op。
2. x2paddle_model_zoo.md:测试过的模型列表。
# 二、 user_guides
1. FQA.md:常见问题集合。
2. add_caffe_custom_layer.md:添加caffe自定义Layer的方法,以及当前支持的自定义Layer列表。
3. export_tf_model.md:导出本工具支持的TensorFlow模型。
4. pytorch2onnx.md:将PyTorch导出为ONNX。
5. pytorch2paddle.md:将PyTorch模型转换为Paddle模型。
## 常见问题 ## 常见问题
**Q1. TensorFlow模型转换过程中,提示『Unknown shape for input tensor[tensor name: "input"], Please define shape of input here』?** **Q1. TensorFlow模型转换过程中,提示『Unknown shape for input tensor[tensor name: "input"], Please define shape of input here』?**
A:该提示信息表示无法从TensorFlow的pb模型中获取到输入tensor(tensor名为"input:)的shape信息,所以需要用户手动在提示后输入详细的shape信息,如None,224,224,3 其中None表示Batch A:该提示信息表示无法从TensorFlow的pb模型中获取到输入tensor(tensor名为"input:)的shape信息,所以需要用户手动在提示后输入详细的shape信息,如None,224,224,3 其中None表示Batch
**Q2. TensorFlow模型转换失败怎么解决?** **Q2. TensorFlow模型转换失败怎么解决?**
A: 如果并非是由缺少OP导致,那可能是由于TensorFlow模型转换时(NHWC->NCHW格式转换导致),在这种情况下,采用如下方式进行转换,同时固化输入大小的方式,继续尝试转换,见如下命令,转换过程中,根据提示,输入相应tensor的固化shape大小 A: 如果并非是由缺少OP导致,那可能是由于TensorFlow模型转换时(NHWC->NCHW格式转换导致),在这种情况下,采用如下方式进行转换,同时固化输入大小的方式,继续尝试转换,见如下命令,转换过程中,根据提示,输入相应tensor的固化shape大小
``` ```
x2paddle -f tensorflow -m tf.pb -s pd-model --without_data_format_optimization --define_input_shape x2paddle -f tensorflow -m tf.pb -s pd-model --define_input_shape
``` ```
> 1. 目前Tensorflow的CV模型大部分均为`NHWC`的输入格式,而Paddle的默认输入格式为`NCHW`,因此X2Paddle在转换过程中,会对如`axis`, `shape`等参数进行转换,适应Paddle的NCHW格式。但在这种情况下,可能会由于TensorFlow模型太复杂,导致出错。 指定`--without_data_format_optimization`后,会停止对`axis`,`shape`等参数的优化(这可能会带来一定数量的transpose操作)
**Q3. ONNX模型转换过程中,提示『Unknown shape for input tensor[tensor name: "input"] -> shape: ['batch', 'sequence'], Please define shape of input here』** **Q3. ONNX模型转换过程中,提示『Unknown shape for input tensor[tensor name: "input"] -> shape: ['batch', 'sequence'], Please define shape of input here』**
A:该提示信息表示从ONNX的模型中获取到输入tensor(tensor名为"input:)的shape是语义象征性的['batch', 'sequence'],而不是dim为int类型的shape,从而可能会因为部分node的shape无法推理,导致转换失败。所以用户可以尝试手动在提示后输入详细的shape信息,如:-1,3,224,224 其中-1表示Batch A:该提示信息表示从ONNX的模型中获取到输入tensor(tensor名为"input:)的shape是语义象征性的['batch', 'sequence'],而不是dim为int类型的shape,从而可能会因为部分node的shape无法推理,导致转换失败。所以用户可以尝试手动在提示后输入详细的shape信息,如:-1,3,224,224 其中-1表示Batch。
**Q4. Paddle模型转至ONNX模型过程中,提示『The parameter normalized of multiclass_nms OP of Paddle is False, which has diff with ONNX』**
A: 此提示为警告信息,模型仍然会正常进行转换。Paddle中`fluid.layers.multiclass_nms`算子中提供了`normalized`参数,用于表示输入box是否进行了归一化。而ONNX中的NMS算子只支持`normalized`参数为True的情况,当你转换的模型(一般是YOLOv3模型)中该参数为`False`的情况下,转换后的模型可能会与原模型存在diff。
**Q5. Paddle模型转至ONNX模型过程中,提示『Converting this model to ONNX need with static input shape, please fix input shape of this model』** **Q4. 如果我的tensorflow模型是checkpoint或者SavedModel格式,怎么办?**
A: 此提示为错误信息,表示该模型的转换需要固定的输入大小: A:我们提供相关文档将export_tf_model.md
> 1. 模型来源于PaddleX导出,可以在导出的命令中,指定--fixed_input_shape=[Height,Width],详情可见:[PaddleX模型导出文档](https://github.com/PaddlePaddle/PaddleX/blob/develop/docs/deploy/export_model.md)。
> 2. 模型来源于PaddleDetection导出,可以在导出模型的时候,指定 TestReader.inputs_def.image_shape=[Channel,Height,Width], 详情可见:[PaddleDetection模型导出文档](https://github.com/PaddlePaddle/PaddleDetection/blob/master/docs/advanced_tutorials/deploy/EXPORT_MODEL.md#设置导出模型的输入大小)。
> 3. 模型来源于自己构建,可在网络构建的`fluid.data(shape=[])`中,指定shape参数来固定模型的输入大小。
**Q6. 进行动态图转换时,提示『Fail to generate inference model! Problem happend while export inference model from python code...』** **Q4. 进行动态图转换时,提示『Fail to generate inference model! Problem happend while export inference model from python code...』**
A: 此提示为无法将动态图代码转换为静态图模型,有两种可能: A: 此提示为无法将动态图代码转换为静态图模型,有两种可能:
> 使用动态图代码确认转换后的代码是否正确,可使用如下代码进行确认: > 使用动态图代码确认转换后的代码是否正确,可使用如下代码进行确认:
``` ```
...@@ -40,3 +32,6 @@ from pd_model_dygraph.x2paddle_code import main ...@@ -40,3 +32,6 @@ from pd_model_dygraph.x2paddle_code import main
out =main(ipt) out =main(ipt)
``` ```
> 若运行代码无误,则说明代码中有op不支持动转静,我们将会再未来支持;若报错,则说明pytorch2paddle转换出错,请提issue,我们将及时回复。 > 若运行代码无误,则说明代码中有op不支持动转静,我们将会再未来支持;若报错,则说明pytorch2paddle转换出错,请提issue,我们将及时回复。
**Q5. 目前支持了哪些op的转换呢?**
A: 可详见[X2Paddle支持的op列表](./docs/introduction/op_list.md)
...@@ -5,7 +5,7 @@ PyTorch2Paddle支持trace和script两种方式的转换,均是PyTorch动态图 ...@@ -5,7 +5,7 @@ PyTorch2Paddle支持trace和script两种方式的转换,均是PyTorch动态图
## 环境依赖 ## 环境依赖
python == 2.7 | python >= 3.5 python == 2.7 | python >= 3.5
paddlepaddle >= 1.8.0 paddlepaddle >= 2.0.0
pytorch:torch >=1.5.0 (script方式暂不支持1.7.0) pytorch:torch >=1.5.0 (script方式暂不支持1.7.0)
**使用trace方式需安装以下依赖** **使用trace方式需安装以下依赖**
......
## 架构设计
X2Paddle的架构设计着重考虑了对多深度学习框架的的支持以及代码的易读性、易扩展性。预测模型转换在多个层面的对转换后OP进行优化处理,转换后的模型可直接用于预测部署;训练代码转换则运用了AST的方式进行转换,转换后的代码与源代码格式一致。2种方式的转换满足不同人的需求。
![](../images/frame.png)
# X2Paddle模型测试库 # X2Paddle转换库
> 目前X2Paddle支持80+的TensorFlow OP,30+的Caffe Layer,60+的ONNX OP,110+的PyTorch Aten,10+的PyTorch Prim,覆盖了大部分CV分类模型常用的操作。我们在如下模型列表中测试了X2Paddle的转换。
**注:** 受限于不同框架的差异,部分模型可能会存在目前无法转换的情况,如TensorFlow中包含控制流的模型,NLP模型等。对于CV常见的模型,如若您发现无法转换或转换失败,存在较大diff等问题,欢迎通过[ISSUE反馈](https://github.com/PaddlePaddle/X2Paddle/issues/new)的方式告知我们(模型名,代码实现或模型获取方式),我们会及时跟进:) ## TensorFlow预测模型
## TensorFlow
| 模型 | 代码 | | 模型 | 代码 |
|------|----------| |------|----------|
...@@ -28,7 +25,7 @@ ...@@ -28,7 +25,7 @@
| Bert(chinese_L-12_H-768_A-12) | [code](https://github.com/google-research/bert#pre-trained-models) | | Bert(chinese_L-12_H-768_A-12) | [code](https://github.com/google-research/bert#pre-trained-models) |
| Bert(multi_cased_L-12_H-768_A-12) | [code](https://github.com/google-research/bert#pre-trained-models) | | Bert(multi_cased_L-12_H-768_A-12) | [code](https://github.com/google-research/bert#pre-trained-models) |
## Caffe ## Caffe预测模型
| 模型 | 代码 | | 模型 | 代码 |
|-------|--------| |-------|--------|
...@@ -51,7 +48,7 @@ ...@@ -51,7 +48,7 @@
## ONNX ## ONNX预测模型
**注:** 部分模型来源于PyTorch,PyTorch的转换可参考[pytorch_to_onnx.md](pytorch_to_onnx.md) **注:** 部分模型来源于PyTorch,PyTorch的转换可参考[pytorch_to_onnx.md](pytorch_to_onnx.md)
| 模型 | 来源 | operator version|备注| | 模型 | 来源 | operator version|备注|
...@@ -72,11 +69,12 @@ ...@@ -72,11 +69,12 @@
| EfficientNet | [pytorch(personal practice)](https://github.com/rwightman/gen-efficientnet-pytorch) |9| | EfficientNet | [pytorch(personal practice)](https://github.com/rwightman/gen-efficientnet-pytorch) |9|
| SqueezeNet | [onnx official](https://s3.amazonaws.com/download.onnx/models/opset_9/squeezenet.tar.gz) |9| | SqueezeNet | [onnx official](https://s3.amazonaws.com/download.onnx/models/opset_9/squeezenet.tar.gz) |9|
|Ultra-Light-Fast-Generic-Face-Detector-1MB| [onnx_model](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/models/onnx)|9 | |Ultra-Light-Fast-Generic-Face-Detector-1MB| [onnx_model](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/models/onnx)|9 |
|BERT| [pytorch(huggingface)](https://github.com/huggingface/transformers/blob/master/notebooks/04-onnx-export.ipynb)|11|转换时需指定input shape,见[文档Q3](../user_guides/FAQ.md)| |BERT| [pytorch(huggingface)](https://github.com/huggingface/transformers/blob/master/notebooks/04-onnx-export.ipynb)|11|转换时需指定input shape,见[文档Q3](../inference_model_convertor/FAQ.md)|
|GPT2| [pytorch(huggingface)](https://github.com/huggingface/transformers/blob/master/notebooks/04-onnx-export.ipynb)|11|转换时需指定input shape,见[文档Q3](../user_guides/FAQ.md)| |GPT2| [pytorch(huggingface)](https://github.com/huggingface/transformers/blob/master/notebooks/04-onnx-export.ipynb)|11|转换时需指定input shape,见[文档Q3](../inference_model_convertor/FAQ.md)|
|CifarNet | [tensorflow](https://github.com/tensorflow/models/blob/master/research/slim/nets/cifarnet.py)|9||
## PyTorch ## PyTorch预测模型
| 模型 | 代码 | 备注 | | 模型 | 代码 | 备注 |
|------|----------|------| |------|----------|------|
...@@ -98,4 +96,15 @@ ...@@ -98,4 +96,15 @@
| XLMRobertaForTokenClassification|[code](https://huggingface.co/transformers/model_doc/xlmroberta.html) |只支持trace模式| | XLMRobertaForTokenClassification|[code](https://huggingface.co/transformers/model_doc/xlmroberta.html) |只支持trace模式|
| EasyOCR_detector|[code](https://github.com/JaidedAI/EasyOCR/blob/master/easyocr/detection.py) |-| | EasyOCR_detector|[code](https://github.com/JaidedAI/EasyOCR/blob/master/easyocr/detection.py) |-|
| EasyOCR_recognizer|[code](https://github.com/JaidedAI/EasyOCR/blob/master/easyocr/recognition.py) |-| | EasyOCR_recognizer|[code](https://github.com/JaidedAI/EasyOCR/blob/master/easyocr/recognition.py) |-|
| SwinTransformer|[code](https://github.com/microsoft/Swin-Transformer/) |-|
| BASNet|[code](https://github.com/xuebinqin/BASNet) |-|
| DBFace |[code](https://github.com/dlunion/DBFacet) |-|
## PyTorch训练项目
| 模型 | 转换前代码 | 转换后代码 |
|------|----------|------|
| StaGAN | [code](https://github.com/yunjey/stargan)|[code](https://github.com/SunAhong1993/stargan/tree/paddle)|
| Ultra-Light-Fast-Generic-Face-Detector | [code](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB) |[code](https://github.com/SunAhong1993/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/paddle)|
**注:** 受限于不同框架的差异,部分模型可能会存在目前无法转换的情况,如TensorFlow中包含控制流的模型,NLP模型等。对于CV常见的模型,如若您发现无法转换或转换失败,存在较大diff等问题,欢迎通过[ISSUE反馈](https://github.com/PaddlePaddle/X2Paddle/issues/new)的方式告知我们(模型名,代码实现或模型获取方式),我们会及时跟进:
# PyTorch-PaddlePaddle API对应表
本文档梳理了常用PyTorch 1.8.1 API与PaddlePaddle 2.0.0 API对应关系和差异分析。根据文档对应关系,有PyTorch使用经验的用户,可根据对应关系,快速熟悉PaddlePaddle的API使用。
## [基础操作类](./ops/README.md)
## [组网类](./nn/README.md)
## [Loss类](./loss/README.md)
## [工具类](./utils/README.md)
## [视觉类](./vision/README.md)
***持续更新...***
***持续更新...***## Loss类
| 序号 | PyTorch API | PaddlePaddle API | 备注 |
| ---- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
| 1 | [torch.nn.L1Loss](https://pytorch.org/docs/stable/generated/torch.nn.L1Loss.html?highlight=l1loss#torch.nn.L1Loss) | [paddle.nn.loss.L1Loss](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/loss/L1Loss_cn.html#l1loss) | 功能一致,PyTroch存在废弃参数`size_average``reduce`。 |
| 2 | [torch.nn.MSELoss](https://pytorch.org/docs/stable/generated/torch.nn.MSELoss.html?highlight=mseloss#torch.nn.MSELoss) | [paddle.nn.MSELoss](https://pytorch.org/docs/stable/generated/torch.nn.MSELoss.html?highlight=mseloss#torch.nn.MSELoss) | 功能一致,PyTroch存在废弃参数`size_average``reduce`。 |
| 3 | [torch.nn.CrossEntropyLoss](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/loss/CrossEntropyLoss_cn.html#crossentropyloss) | [paddle.nn.CrossEntropyLoss](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/loss/CrossEntropyLoss_cn.html#crossentropyloss) | [差异对比](torch.nn.CrossEntropyLoss.md) |
| 4 | [torch.nn.KLDivLoss](https://pytorch.org/docs/stable/generated/torch.nn.KLDivLoss.html?highlight=kldivloss#torch.nn.KLDivLoss) | [paddle.nn.KLDivLoss](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/loss/KLDivLoss_cn.html) | [差异对比](torch.nn.KLDivLoss.md) |
| 5 | [torch.nn.BCELoss](https://pytorch.org/docs/stable/generated/torch.nn.BCELoss.html?highlight=bceloss#torch.nn.BCELoss) | [paddle.nn.BCELoss](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/loss/BCELoss_cn.html#bceloss) | 功能一致,PyTroch存在废弃参数`size_average``reduce`。 |
| 6 | [torch.nn.BCEWithLogitsLoss](https://pytorch.org/docs/stable/generated/torch.nn.BCEWithLogitsLoss.html?highlight=bcewithlogitsloss#torch.nn.BCEWithLogitsLoss) | [paddle.nn.BCEWithLogitsLoss](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/loss/BCEWithLogitsLoss_cn.html#bcewithlogitsloss) | 功能一致,PyTroch存在废弃参数`size_average``reduce`。 |
| 7 | [torch.nn.SmoothL1Loss](https://pytorch.org/docs/stable/generated/torch.nn.SmoothL1Loss.html?highlight=torch%20nn%20smoothl1loss#torch.nn.SmoothL1Loss) | [paddle.nn.SmoothL1Loss](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/loss/SmoothL1Loss_cn.html#smoothl1loss) | 功能一致,参数名不一致,PyTroch存在废弃参数`size_average``reduce`。 |
***持续更新...***
## torch.nn.CrossEntropyLoss
### [torch.nn.CrossEntropyLoss](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/loss/CrossEntropyLoss_cn.html#crossentropyloss)
```python
torch.nn.CrossEntropyLoss(weight=None,
size_average=None,
ignore_index=-100,
reduce=None,
reduction='mean')
```
### [paddle.nn.CrossEntropyLoss](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/loss/CrossEntropyLoss_cn.html#crossentropyloss)
```python
paddle.nn.CrossEntropyLoss(weight=None,
ignore_index=-100,
reduction='mean',
soft_label=False,
axis=-1,
use_softmax=True,
name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| size_average | - | PyTorch废弃参数。 |
| reduce | - | PyTorch废弃参数。 |
| - | use_softmax | 表示在使用交叉熵之前是否计算softmax,PyTorch无此参数。 |
| - | soft_label | 指明label是否为软标签,PyTorch无此参数。 |
| - | axis | 表示进行softmax计算的维度索引,PyTorch无此参数。 |
### 功能差异
#### 计算方式
***PyTorch***:只支持在使用交叉熵之前计算softmax且为硬标签的计算方式。
***PaddlePaddle***:支持使用交叉熵之前是否计算softmax的设置,且支持软、硬标签两种计算方式,其计算方式可参见[文档](https://www.paddlepaddle.org.cn/documentation/docs/en/api/paddle/nn/layer/loss/CrossEntropyLoss_en.html)
## torch.nn.KLDivLoss
### [torch.nn.KLDivLoss](https://pytorch.org/docs/stable/generated/torch.nn.KLDivLoss.html?highlight=kldivloss#torch.nn.KLDivLoss)
```python
torch.nn.KLDivLoss(size_average=None,
reduce=None,
reduction='mean',
log_target=False)
```
### [paddle.nn.KLDivLoss](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/loss/KLDivLoss_cn.html)
```python
paddle.nn.KLDivLoss(reduction='mean')
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| size_average | - | PyTorch废弃参数。 |
| reduce | - | PyTorch废弃参数。 |
| log_target | - | 表示是否对目标值进行log处理,PaddlePaddle无此参数。 |
### 功能差异
#### 计算方式
***PyTorch***
> 当`log_target`为`True`时:
> $ l(input,label)= e^{target}∗(label−input) $
>
> 当`log_target`为`False`时:
> 1. $ l(input,label)=target*(log(target)-input) $
> 2. $ l(input,label) $中值小于0的取0
***PaddlePaddle***
> $ l(input,label)=label∗(log(label)−input) $
在PaddlePaddle中可使用如下代码组合实现该API。
```python
import paddle
# 定义KLDivLoss
class KLDivLoss(paddle.nn.Layer):
def __init__(self,
size_average=None,
reduce=None,
reduction='mean',
log_target=False):
super().__init__()
self.reduction = reduction
self.log_target = log_target
def forward(self, input, target):
if self.log_target:
out = paddle.exp(target) * (target - input)
else:
out_pos = target * (paddle.log(target) - input)
zeros = paddle.zeros_like(out_pos)
out = paddle.where(target > 0, out_pos, zeros)
out_sum = paddle.sum(out)
if self.reduction == "sum":
return out_sum
elif self.reduction == "batchmean":
n = input.shape[0]
return out_sum / n
elif self.reduction == "mean":
return paddle.mean(out)
else:
return out
# 构造输入
import numpy as np
shape = (5, 20)
x = np.random.uniform(-10, 10, shape).astype('float32')
target = np.random.uniform(-10, 10, shape).astype('float32')
# 计算loss
kldiv_criterion = KLDivLoss()
pred_loss = kldiv_criterion(paddle.to_tensor(x),
paddle.to_tensor(target))
```
## 组网类
| 序号 | PyTorch API | PaddlePaddle API | 备注 |
| ---- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
| 1 | [torch.nn.Conv1d](https://pytorch.org/docs/stable/generated/torch.nn.Conv1d.html?highlight=torch%20nn%20conv1d#torch.nn.Conv1d) | [paddle.nn.Conv1D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/conv/Conv1D_cn.html#conv1d) | [差异对比](torch.nn.Conv1d.md) |
| 2 | [torch.nn.Conv2d](https://pytorch.org/docs/stable/generated/torch.nn.Conv2d.html?highlight=conv2d#torch.nn.Conv2d) | [paddle.nn.Conv2D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/conv/Conv2D_cn.html#conv2d) | [差异对比](torch.nn.Conv2d.md) |
| 3 | [torch.nn.Conv3d](https://pytorch.org/docs/stable/generated/torch.nn.Conv3d.html?highlight=conv3d#torch.nn.Conv3d) | [paddle.nn.Conv3D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/conv/Conv3D_cn.html#conv3d) | [差异对比](torch.nn.Conv3d.md) |
| 4 | [torch.nn.ConvTranspose1d](https://pytorch.org/docs/stable/generated/torch.nn.ConvTranspose1d.html?highlight=torch%20nn%20convtranspose1d#torch.nn.ConvTranspose1d) | [paddle.nn.Conv1DTranspose](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/conv/Conv1DTranspose_cn.html#conv1dtranspose) | [差异对比](torch.nn.ConvTranspose1d.md) |
| 5 | [torch.nn.ConvTranspose2d](https://pytorch.org/docs/stable/generated/torch.nn.ConvTranspose2d.html?highlight=convtranspose2d#torch.nn.ConvTranspose2d) | [paddle.nn.Conv2DTranspose](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/conv/Conv2DTranspose_cn.html#conv2dtranspose) | [差异对比](torch.nn.ConvTranspose2d.md) |
| 6 | [torch.nn.ConvTranspose3d](https://pytorch.org/docs/stable/generated/torch.nn.ConvTranspose3d.html?highlight=convtranspose3d#torch.nn.ConvTranspose3d) | [paddle.nn.Conv3DTranspose](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/conv/Conv3DTranspose_cn.html#conv3dtranspose) | [差异对比](torch.nn.ConvTranspose3d.md) |
| 7 | [torch.nn.Linear](https://pytorch.org/docs/stable/generated/torch.nn.Linear.html?highlight=linear#torch.nn.Linear) | [paddle.nn.Linear](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Linear_cn.html#linear) | [差异对比](torch.nn.Linear.md) |
| 8 | [torch.nn.MaxPool1d](https://pytorch.org/docs/stable/generated/torch.nn.MaxPool1d.html?highlight=maxpool1d#torch.nn.MaxPool1d) | [paddle.nn.MaxPool1D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/pooling/MaxPool1D_cn.html#maxpool1d) | [差异对比](torch.nn.MaxPool1d.md) |
| 9 | [torch.nn.MaxPool2d](https://pytorch.org/docs/stable/generated/torch.nn.MaxPool2d.html?highlight=maxpool2d#torch.nn.MaxPool2d) | [paddle.nn.MaxPool2D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/pooling/MaxPool2D_cn.html#maxpool2d) | [差异对比](torch.nn.MaxPool2d.md) |
| 10 | [torch.nn.MaxPool3d](https://pytorch.org/docs/stable/generated/torch.nn.MaxPool3d.html?highlight=maxpool3d#torch.nn.MaxPool3d) | [paddle.nn.MaxPool3D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/pooling/MaxPool3D_cn.html#maxpool3d) | [差异对比](torch.nn.MaxPool3d.md) |
| 11 | [torch.nn.MaxUnpool1d](https://pytorch.org/docs/stable/generated/torch.nn.MaxUnpool1d.html?highlight=unpool#torch.nn.MaxUnpool1d) | 无对应实现 | [组合实现](torch.nn.MaxUnpool1d.md) |
| 12 | [torch.nn.MaxUnpool2d](https://pytorch.org/docs/stable/generated/torch.nn.MaxUnpool2d.html?highlight=unpool#torch.nn.MaxUnpool2d) | 无对应实现 | [组合实现](torch.nn.MaxUnpool2d.md) |
| 13 | [torch.nn.MaxUnpool3d](https://pytorch.org/docs/stable/generated/torch.nn.MaxUnpool3d.html?highlight=unpool#torch.nn.MaxUnpool3d) | 无对应实现 | [组合实现](torch.nn.MaxUnpool3d.md) |
| 14 | [torch.nn.AvgPool1d](https://pytorch.org/docs/stable/generated/torch.nn.AvgPool1d.html?highlight=avgpool1d#torch.nn.AvgPool1d) | [paddle.nn.AvgPool1D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/pooling/AvgPool1D_cn.html#avgpool1d) | [差异对比](torch.nn.AvgPool1d.md) |
| 15 | [torch.nn.AvgPool2d](https://pytorch.org/docs/stable/generated/torch.nn.AvgPool2d.html?highlight=avgpool2d#torch.nn.AvgPool2d) | [paddle.nn.AvgPool2D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/pooling/AvgPool2D_cn.html#avgpool2d) | [差异对比](torch.nn.AvgPool2d.md) |
| 16 | [torch.nn.AvgPool3d](https://pytorch.org/docs/stable/generated/torch.nn.AvgPool3d.html?highlight=avgpool3d#torch.nn.AvgPool3d) | [paddle.nn.AvgPool3D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/pooling/AvgPool3D_cn.html#avgpool3d) | [差异对比](torch.nn.AvgPool3d.md) |
| 17 | [torch.nn.AdaptiveMaxPool1d](https://pytorch.org/docs/stable/generated/torch.nn.AdaptiveMaxPool1d.html?highlight=adaptivemaxpool1d#torch.nn.AdaptiveMaxPool1d) | [paddle.nn.AdaptiveMaxPool1D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/pooling/AdaptiveMaxPool1D_cn.html#adaptivemaxpool1d) | 功能一致,参数名不一致 |
| 18 | [torch.nn.AdaptiveMaxPool2d](https://pytorch.org/docs/stable/generated/torch.nn.AdaptiveMaxPool2d.html?highlight=adaptivemaxpool2d#torch.nn.AdaptiveMaxPool2d) | [paddle.nn.AdaptiveMaxPool2D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/pooling/AdaptiveMaxPool2D_cn.html#adaptivemaxpool2d) | 功能一致,参数名不一致 |
| 19 | [torch.nn.AdaptiveMaxPool3d](https://pytorch.org/docs/stable/generated/torch.nn.AdaptiveMaxPool3d.html?highlight=adaptivemaxpool3d#torch.nn.AdaptiveMaxPool3d) | [paddle.nn.AdaptiveMaxPool3D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/pooling/AdaptiveMaxPool3D_cn.html#adaptivemaxpool3d) | 功能一致,参数名不一致 |
| 20 | [torch.nn.AdaptiveAvgPool1d](https://pytorch.org/docs/stable/generated/torch.nn.AdaptiveAvgPool1d.html?highlight=adaptiveavgpool1d#torch.nn.AdaptiveAvgPool1d) | [paddle.nn.AdaptiveAvgPool1D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/pooling/AdaptiveAvgPool1D_cn.html#adaptiveavgpool1d) | 功能一致,参数名不一致 |
| 21 | [torch.nn.AdaptiveAvgPool2d](https://pytorch.org/docs/stable/generated/torch.nn.AdaptiveAvgPool2d.html?highlight=adaptiveavgpool2d#torch.nn.AdaptiveAvgPool2d) | [paddle.nn.AdaptiveAvgPool2D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/pooling/AdaptiveAvgPool2D_cn.html#adaptiveavgpool2d) | 功能一致,参数名不一致 |
| 22 | [torch.nn.AdaptiveAvgPool3d](https://pytorch.org/docs/stable/generated/torch.nn.AdaptiveAvgPool3d.html?highlight=adaptiveavgpool3d#torch.nn.AdaptiveAvgPool3d) | [paddle.nn.AdaptiveAvgPool3D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/pooling/AdaptiveAvgPool3D_cn.html#adaptiveavgpool3d) | 功能一致,参数名不一致 |
| 23 | [torch.nn.ConstantPad1d](https://pytorch.org/docs/stable/generated/torch.nn.ConstantPad1d.html?highlight=pad#torch.nn.ConstantPad1d) | [paddle.nn.Pad1D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Pad1D_cn.html#pad1d) | [差异对比](torch.nn.ConstantPad1d.md) |
| 24 | [torch.nn.ConstantPad2d](https://pytorch.org/docs/stable/generated/torch.nn.ConstantPad2d.html?highlight=pad#torch.nn.ConstantPad2d) | [paddle.nn.Pad2D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Pad2D_cn.html#pad2d) | [差异对比](torch.nn.ConstantPad2d.md) |
| 25 | [torch.nn.ConstantPad3d](https://pytorch.org/docs/stable/generated/torch.nn.ConstantPad3d.html?highlight=pad#torch.nn.ConstantPad3d) | [paddle.nn.Pad3D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Pad3D_cn.html#pad3d) | [差异对比](torch.nn.ConstantPad3d.md) |
| 26 | [torch.nn.ReflectionPad1d](https://pytorch.org/docs/stable/generated/torch.nn.ReflectionPad1d.html?highlight=pad#torch.nn.ReflectionPad1d) | [paddle.nn.Pad1D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Pad1D_cn.html#pad1d) | [差异对比](torch.nn.ReflectionPad1d.md) |
| 27 | [torch.nn.ReflectionPad2d](https://pytorch.org/docs/stable/generated/torch.nn.ReflectionPad2d.html?highlight=pad#torch.nn.ReflectionPad2d) | [paddle.nn.Pad2D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Pad2D_cn.html#pad2d) | [差异对比](torch.nn.ReflectionPad2d.md) |
| 28 | [torch.nn.ReplicationPad1d](https://pytorch.org/docs/stable/generated/torch.nn.ReplicationPad1d.html?highlight=pad#torch.nn.ReplicationPad1d) | [paddle.nn.Pad1D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Pad1D_cn.html#pad1d) | [差异对比](torch.nn.ReplicationPad1d.md) |
| 29 | [torch.nn.ReplicationPad2d](https://pytorch.org/docs/stable/generated/torch.nn.ReplicationPad2d.html?highlight=pad#torch.nn.ReplicationPad2d) | [paddle.nn.Pad2D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Pad2D_cn.html#pad2d) | [差异对比](torch.nn.ReplicationPad2d.md) |
| 30 | [torch.nn.ReplicationPad3d](https://pytorch.org/docs/stable/generated/torch.nn.ReplicationPad3d.html?highlight=pad#torch.nn.ReplicationPad3d) | [paddle.nn.Pad3D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Pad3D_cn.html#pad3d) | [差异对比](torch.nn.ReplicationPad3d.md) |
| 31 | [torch.nn.BatchNorm1d](https://pytorch.org/docs/stable/generated/torch.nn.BatchNorm1d.html?highlight=torch%20nn%20batchnorm1d#torch.nn.BatchNorm1d) | [paddle.nn.BatchNorm1D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/norm/BatchNorm1D_cn.html#batchnorm1d) | [差异对比](torch.nn.BatchNorm1d.md) |
| 32 | [torch.nn.BatchNorm2d](https://pytorch.org/docs/stable/generated/torch.nn.BatchNorm2d.html?highlight=batchnorm2d#torch.nn.BatchNorm2d) | [paddle.nn.BatchNorm2D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/norm/BatchNorm2D_cn.html#batchnorm2d) | [差异对比](torch.nn.BatchNorm2d.md) |
| 33 | [torch.nn.BatchNorm3d](https://pytorch.org/docs/stable/generated/torch.nn.BatchNorm3d.html?highlight=torch%20nn%20batchnorm3d#torch.nn.BatchNorm3d) | [paddle.nn.BatchNorm3D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/norm/BatchNorm3D_cn.html#batchnorm3d) | [差异对比](torch.nn.BatchNorm3d.md) |
| 34 | [torch.nn.Upsample](https://pytorch.org/docs/stable/generated/torch.nn.Upsample.html?highlight=upsample#torch.nn.Upsample) | [paddle.nn.Upsample](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Upsample_cn.html#upsample) | [差异对比](torch.nn.Upsample.md) |
| 35 | [torch.nn.Dropout](https://pytorch.org/docs/stable/generated/torch.nn.Dropout.html?highlight=dropout#torch.nn.Dropout) | [paddle.nn.Dropout](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Dropout_cn.html#dropout) | [差异对比](torch.nn.Dropout.md) |
| 36 | [torch.nn.Dropout2d](https://pytorch.org/docs/stable/generated/torch.nn.Dropout2d.html?highlight=dropout2d#torch.nn.Dropout2d) | [paddle.nn.Dropout2D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Dropout2D_cn.html#dropout2d) | [差异对比](torch.nn.Dropout2d.md) |
| 37 | [torch.nn.Dropout3d](https://pytorch.org/docs/stable/generated/torch.nn.Dropout3d.html?highlight=dropout3d#torch.nn.Dropout3d) | [paddle.nn.Dropout3D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Dropout3D_cn.html#dropout3d) | [差异对比](torch.nn.Dropout3d.md) |
| 38 | [torch.nn.LSTM](https://pytorch.org/docs/stable/generated/torch.nn.LSTM.html?highlight=lstm#torch.nn.LSTM) | [paddle.nn.LSTM](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/rnn/LSTM_cn.html#lstm) | [差异对比](torch.nn.LSTM.md) |
| 39 | [torch.nn.GRU](https://pytorch.org/docs/stable/generated/torch.nn.GRU.html?highlight=torch%20nn%20gru#torch.nn.GRU) | [paddle.nn.GRU](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/rnn/GRU_cn.html#gru) | [差异对比](torch.nn.GRU.md) |
| 40 | [torch.nn.Embedding](https://pytorch.org/docs/stable/generated/torch.nn.Embedding.html?highlight=embedding#torch.nn.Embedding) | [paddle.nn.Embedding](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Embedding_cn.html#embedding) | [差异对比](torch.nn.Embedding.md) |
| 41 | [torch.nn.ELU](https://pytorch.org/docs/stable/generated/torch.nn.ELU.html?highlight=elu#torch.nn.ELU) | [paddle.nn.ELU](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/activation/ELU_cn.html#elu) | 功能一致,PaddlePaddle未定义`inplace`参数表示在不更改变量的内存地址的情况下,直接修改变量的值 |
| 42 | [torch.nn.Hardsigmoid](https://pytorch.org/docs/stable/generated/torch.nn.Hardsigmoid.html?highlight=hardsigmoid#torch.nn.Hardsigmoid) | [paddle.nn.Hardsigmoid](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/activation/Hardsigmoid_cn.html#hardsigmoid) | 功能一致,PaddlePaddle未定义`inplace`参数表示在不更改变量的内存地址的情况下,直接修改变量的值 |
| 43 | [torch.nn.LeakyReLU](https://pytorch.org/docs/stable/generated/torch.nn.LeakyReLU.html?highlight=leakyrelu#torch.nn.LeakyReLU) | [paddle.nn.LeakyReLU](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/activation/LeakyReLU_cn.html#leakyrelu) | 功能一致,PaddlePaddle未定义`inplace`参数表示在不更改变量的内存地址的情况下,直接修改变量的值 |
| 44 | [torch.nn.PReLU](https://pytorch.org/docs/stable/generated/torch.nn.PReLU.html?highlight=prelu#torch.nn.PReLU) | [paddle.nn.PReLU](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/activation/PReLU_cn.html#prelu) | 功能一致 |
| 45 | [torch.nn.ReLU](https://pytorch.org/docs/stable/generated/torch.nn.ReLU.html?highlight=relu#torch.nn.ReLU) | [paddle.nn.ReLU](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/activation/ReLU_cn.html#relu) | 功能一致,PaddlePaddle未定义`inplace`参数表示在不更改变量的内存地址的情况下,直接修改变量的值 |
| 46 | [torch.nn.Softmax](https://pytorch.org/docs/stable/generated/torch.nn.Softmax.html?highlight=softmax#torch.nn.Softmax) | [paddle.nn.Softmax](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/activation/Softmax_cn.html#softmax) | 功能一致,参数名不一致 |
***持续更新...***
# torch.nn.AvgPool1d
### [torch.nn.AvgPool1d](https://pytorch.org/docs/stable/generated/torch.nn.AvgPool1d.html?highlight=avgpool1d#torch.nn.AvgPool1d)
```python
torch.nn.AvgPool1d(kernel_size,
stride=None,
padding=0,
ceil_mode=False,
count_include_pad=True)
```
### [paddle.nn.AvgPool1D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/pooling/AvgPool1D_cn.html#avgpool1d)
```python
paddle.nn.AvgPool1D(kernel_size,
stride=None,
padding=0,
exclusive=True,
ceil_mode=False,
name=None)
```
### 功能差异
#### 池化方式
***PyTorch***: 使用`count_include_pad`表示是否使用额外padding的值计算平均池化结果,默认为True。
***PaddlePaddle***:使用`exclusive`表示是否不使用额外padding的值计算平均池化结果,默认为True。
## torch.nn.AvgPool2d
### [torch.nn.AvgPool2d](https://pytorch.org/docs/stable/generated/torch.nn.AvgPool2d.html?highlight=avgpool2d#torch.nn.AvgPool2d)
```python
torch.nn.AvgPool2d(kernel_size,
stride=None,
padding=0,
ceil_mode=False,
count_include_pad=True,
divisor_override=None)
```
### [paddle.nn.AvgPool2D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/pooling/AvgPool2D_cn.html#avgpool2d)
```python
paddle.nn.AvgPool2D(kernel_size,
stride=None,
padding=0,
ceil_mode=False,
exclusive=True,
divisor_override=None,
data_format='NCHW',
name=None)
```
### 功能差异
#### 池化方式
***PyTorch***: 使用`count_include_pad`表示是否使用额外padding的值计算平均池化结果,默认为True。
***PaddlePaddle***:使用`exclusive`表示是否不使用额外padding的值计算平均池化结果,默认为True。
## torch.nn.AvgPool3d
### [torch.nn.AvgPool3d](https://pytorch.org/docs/stable/generated/torch.nn.AvgPool3d.html?highlight=avgpool3d#torch.nn.AvgPool3d)
```python
torch.nn.AvgPool3d(kernel_size,
stride=None,
padding=0,
ceil_mode=False,
count_include_pad=True,
divisor_override=None)
```
### [paddle.nn.AvgPool3D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/pooling/AvgPool3D_cn.html#avgpool3d)
```python
paddle.nn.AvgPool3D(kernel_size,
stride=None,
padding=0,
ceil_mode=False,
exclusive=True,
divisor_override=None,
data_format='NCDHW',
name=None)
```
### 功能差异
#### 池化方式
***PyTorch***: 使用`count_include_pad`表示是否使用额外padding的值计算平均池化结果,默认为True。
***PaddlePaddle***:使用`exclusive`表示是否不使用额外padding的值计算平均池化结果,默认为True。
## torch.nn.BatchNorm1d
### [torch.nn.BatchNorm1d](https://pytorch.org/docs/stable/generated/torch.nn.BatchNorm1d.html?highlight=torch%20nn%20batchnorm1d#torch.nn.BatchNorm1d)
```python
torch.nn.BatchNorm1d(num_features,
eps=1e-05,
momentum=0.1,
affine=True,
track_running_stats=True)
```
### [paddle.nn.BatchNorm1D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/norm/BatchNorm1D_cn.html#batchnorm1d)
```python
paddle.nn.BatchNorm1D(num_features,
momentum=0.9,
epsilon=1e-05,
weight_attr=None,
bias_attr=None,
data_format='NCL',
use_global_stats=True,
name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| eps | epsilon | 为了数值稳定加在分母上的值。 |
| - | weight_attr | 指定权重参数属性的对象。如果为False, 则表示每个通道的伸缩固定为1,不可改变。默认值为None,表示使用默认的权重参数属性。 |
| - | bias_attr | 指定偏置参数属性的对象。如果为False, 则表示每一个通道的偏移固定为0,不可改变。默认值为None,表示使用默认的偏置参数属性。 |
| affine | - | 是否进行反射变换,PaddlePaddle无此参数。 |
| track_running_stats | use_global_stats | 表示是否已加载的全局均值和方差。 |
### 功能差异
#### 输入格式
***PyTorch***:只支持`NCL`的输入。
***PaddlePaddle***:支持`NCL``NLC`两种格式的输入(通过`data_format`设置)。
#### 反射变换设置
当PyTorch的反射变换设置为`False`,表示weight和bias不进行更新,由于PaddlePaddle不具备这一功能,可使用如下代码组合实现该API。
```python
class BatchNorm1D(paddle.nn.BatchNorm1D):
def __init__(self,
num_features,
eps=1e-05,
momentum=0.1,
affine=True,
track_running_stats=True):
momentum = 1 - momentum
weight_attr = None
bias_attr = None
if not affine:
weight_attr = paddle.ParamAttr(learning_rate=0.0)
bias_attr = paddle.ParamAttr(learning_rate=0.0)
super().__init__(
num_features,
momentum=momentum,
epsilon=eps,
weight_attr=weight_attr,
bias_attr=bias_attr,
use_global_stats=track_running_stats)
```
## torch.nn.BatchNorm2d
### [torch.nn.BatchNorm2d](https://pytorch.org/docs/stable/generated/torch.nn.BatchNorm2d.html?highlight=batchnorm2d#torch.nn.BatchNorm2d)
```python
torch.nn.BatchNorm2d(num_features,
eps=1e-05,
momentum=0.1,
affine=True,
track_running_stats=True)
```
### [paddle.nn.BatchNorm2D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/norm/BatchNorm2D_cn.html#batchnorm2d)
```python
paddle.nn.BatchNorm2D(num_features,
momentum=0.9,
epsilon=1e-05,
weight_attr=None,
bias_attr=None,
data_format='NCHW',
use_global_stats=True,
name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| eps | epsilon | 为了数值稳定加在分母上的值。 |
| - | weight_attr | 指定权重参数属性的对象。如果为False, 则表示每个通道的伸缩固定为1,不可改变。默认值为None,表示使用默认的权重参数属性。 |
| - | bias_attr | 指定偏置参数属性的对象。如果为False, 则表示每一个通道的偏移固定为0,不可改变。默认值为None,表示使用默认的偏置参数属性。 |
| affine | - | 是否进行反射变换,PaddlePaddle无此参数。 |
| track_running_stats | use_global_stats | 表示是否已加载的全局均值和方差。 |
### 功能差异
#### 输入格式
***PyTorch***:只支持`NCHW`的输入。
***PaddlePaddle***:支持`NCHW``NHWC`两种格式的输入(通过`data_format`设置)。
#### 反射变换设置
当PyTorch的反射变换设置为`False`,表示weight和bias不进行更新,由于PaddlePaddle不具备这一功能,可使用如下代码组合实现该API。
```python
class BatchNorm2D(paddle.nn.BatchNorm2D):
def __init__(self,
num_features,
eps=1e-05,
momentum=0.1,
affine=True,
track_running_stats=True):
momentum = 1 - momentum
weight_attr = None
bias_attr = None
if not affine:
weight_attr = paddle.ParamAttr(learning_rate=0.0)
bias_attr = paddle.ParamAttr(learning_rate=0.0)
super().__init__(
num_features,
momentum=momentum,
epsilon=eps,
weight_attr=weight_attr,
bias_attr=bias_attr,
use_global_stats=track_running_stats)
```
## torch.nn.BatchNorm3d
### [torch.nn.BatchNorm3d](https://pytorch.org/docs/stable/generated/torch.nn.BatchNorm3d.html?highlight=torch%20nn%20batchnorm3d#torch.nn.BatchNorm3d)
```python
torch.nn.BatchNorm3d(num_features,
eps=1e-05,
momentum=0.1,
affine=True,
track_running_stats=True)
```
### [paddle.nn.BatchNorm3D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/norm/BatchNorm3D_cn.html#batchnorm3d)
```python
paddle.nn.BatchNorm3D(num_features,
momentum=0.9,
epsilon=1e-05,
weight_attr=None,
bias_attr=None,
data_format='NCDHW',
use_global_stats=True,
name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| eps | epsilon | 为了数值稳定加在分母上的值。 |
| - | weight_attr | 指定权重参数属性的对象。如果为False, 则表示每个通道的伸缩固定为1,不可改变。默认值为None,表示使用默认的权重参数属性。 |
| - | bias_attr | 指定偏置参数属性的对象。如果为False, 则表示每一个通道的偏移固定为0,不可改变。默认值为None,表示使用默认的偏置参数属性。 |
| affine | - | 是否进行反射变换,PaddlePaddle无此参数。 |
| track_running_stats | use_global_stats | 表示是否已加载的全局均值和方差。 |
### 功能差异
#### 输入格式
***PyTorch***:只支持`NCDHW`的输入。
***PaddlePaddle***:支持`NCDHW``NDHWC`两种格式的输入(通过`data_format`设置)。
#### 反射变换设置
当PyTorch的反射变换设置为`False`,表示weight和bias不进行更新,由于PaddlePaddle不具备这一功能,可使用如下代码组合实现该API。
```python
class BatchNorm3D(paddle.nn.BatchNorm3D):
def __init__(self,
num_features,
eps=1e-05,
momentum=0.1,
affine=True,
track_running_stats=True):
momentum = 1 - momentum
weight_attr = None
bias_attr = None
if not affine:
weight_attr = paddle.ParamAttr(learning_rate=0.0)
bias_attr = paddle.ParamAttr(learning_rate=0.0)
super().__init__(
num_features,
momentum=momentum,
epsilon=eps,
weight_attr=weight_attr,
bias_attr=bias_attr,
use_global_stats=track_running_stats)
```
## torch.nn.ConstantPad1d
### [torch.nn.ConstantPad1d](https://pytorch.org/docs/stable/generated/torch.nn.ConstantPad1d.html?highlight=pad#torch.nn.ConstantPad1d)
```python
torch.nn.ConstantPad1d(padding, value)
```
### [paddle.nn.Pad1D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Pad1D_cn.html#pad1d)
```python
paddle.nn.Pad1D(padding, mode='constant', value=0.0, data_format='NCL', name=None)
```
### 功能差异
#### 使用方式
***PyTorch***:只支持`constant`方式的Pad方式。
***PaddlePaddle***:支持`constant``reflect``replicate``circular`四种格式的输入(通过`mode`设置)。
#### 输入格式
***PyTorch***:只支持`NCL`的输入。
***PaddlePaddle***:支持`NCL``NLC`两种格式的输入(通过`data_format`设置)。
#### padding的设置
***PyTorch***:padding参数的类型只能为int或tuple。
***PaddlePaddle***:padding参数的类型只能为Tensor或list。
### 代码示例
``` python
# PyTorch示例:
import torch
import torch.nn as nn
import numpy as np
input_shape = (1, 2, 3)
pad = 1
data = torch.arange(np.prod(input_shape), dtype=torch.float32).reshape(input_shape) + 1
my_pad = nn.ConstantPad1d(padding=pad, value=0)
result = my_pad(data)
# 输出
# tensor([[[0., 1., 2., 3., 0.],
# [0., 4., 5., 6., 0.]]])
```
``` python
# PaddlePaddle示例:
import paddle
import paddle.nn as nn
import numpy as np
input_shape = (1, 2, 3)
pad = [1, 1]
mode = "constant"
data = paddle.arange(np.prod(input_shape), dtype="float32").reshape(input_shape) + 1
my_pad = nn.Pad1D(padding=pad, value=0, mode=mode)
result = my_pad(data)
# 输出
# Tensor(shape=[1, 2, 5], dtype=float32, place=CPUPlace, stop_gradient=True,
# [[[0., 1., 2., 3., 0.],
# [0., 4., 5., 6., 0.]]])
```
## torch.nn.ConstantPad2d
### [torch.nn.ConstantPad2d](https://pytorch.org/docs/stable/generated/torch.nn.ConstantPad2d.html?highlight=pad#torch.nn.ConstantPad2d)
```python
torch.nn.ConstantPad2d(padding, value)
```
### [paddle.nn.Pad2D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Pad2D_cn.html#pad2d)
```python
paddle.nn.Pad2D(padding, mode='constant', value=0.0, data_format='NCHW', name=None)
```
### 功能差异
#### 使用方式
***PyTorch***:只支持`constant`方式的Pad方式。
***PaddlePaddle***:支持`constant``reflect``replicate``circular`四种格式的输入(通过`mode`设置)。
#### 输入格式
***PyTorch***:只支持`NCHW`的输入。
***PaddlePaddle***:支持`NCHW``NHWC`两种格式的输入(通过`data_format`设置)。
#### padding的设置
***PyTorch***:padding参数的类型只能为int或tuple。
***PaddlePaddle***:padding参数的类型只能为Tensor或list。
### 代码示例
``` python
# PyTorch示例:
import torch
import torch.nn as nn
import numpy as np
input_shape = (1, 1, 2, 3)
pad = [1, 0, 1, 2]
data = torch.arange(np.prod(input_shape), dtype=torch.float32).reshape(input_shape) + 1
my_pad = nn.ConstantPad2d(padding=pad, value=0)
result = my_pad(data)
# 输出
# tensor([[[[0., 0., 0., 0.],
# [0., 1., 2., 3.],
# [0., 4., 5., 6.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.]]]])
```
``` python
# PaddlePaddle示例:
import paddle
import paddle.nn as nn
import numpy as np
input_shape = (1, 1, 2, 3)
pad = [1, 0, 1, 2]
mode = "constant"
data = paddle.arange(np.prod(input_shape), dtype="float32").reshape(input_shape) + 1
my_pad = nn.Pad2D(padding=pad, mode=mode)
result = my_pad(data)
# 输出
# Tensor(shape=[1, 1, 5, 4], dtype=float32, place=CPUPlace, stop_gradient=True,
# [[[[0., 0., 0., 0.],
# [0., 1., 2., 3.],
# [0., 4., 5., 6.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.]]]])
```
## torch.nn.ConstantPad3d
### [torch.nn.ConstantPad3d](https://pytorch.org/docs/stable/generated/torch.nn.ConstantPad3d.html?highlight=pad#torch.nn.ConstantPad3d)
```python
torch.nn.ConstantPad3d(padding, value)
```
### [paddle.nn.Pad3D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Pad3D_cn.html#pad3d)
```python
paddle.nn.Pad3D(padding, mode='constant', value=0.0, data_format='NCDHW', name=None)
```
### 功能差异
#### 使用方式
***PyTorch***:只支持`constant`方式的Pad方式。
***PaddlePaddle***:支持`constant``reflect``replicate``circular`四种格式的输入(通过`mode`设置)。
#### 输入格式
***PyTorch***:只支持`NCDHW`的输入。
***PaddlePaddle***:支持`NCDHW``NCDHW`两种格式的输入(通过`data_format`设置)。
#### padding的设置
***PyTorch***:padding参数的类型只能为int或tuple。
***PaddlePaddle***:padding参数的类型只能为Tensor或list。
### 代码示例
``` python
# PyTorch示例:
import torch
import torch.nn as nn
import numpy as np
input_shape = (1, 1, 1, 2, 3)
pad = [1, 0, 1, 2, 0, 0]
data = torch.arange(np.prod(input_shape), dtype=torch.float32).reshape(input_shape) + 1
my_pad = nn.ConstantPad3d(padding=pad, value=0)
result = my_pad(data)
# 输出
# tensor([[[[[0., 0., 0., 0.],
# [0., 1., 2., 3.],
# [0., 4., 5., 6.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.]]]]])
```
``` python
# PaddlePaddle示例:
import paddle
import paddle.nn as nn
import numpy as np
input_shape = (1, 1, 1, 2, 3)
pad = [1, 0, 1, 2, 0, 0]
mode = "constant"
data = paddle.arange(np.prod(input_shape), dtype="float32").reshape(input_shape) + 1
my_pad = nn.Pad3D(padding=pad, mode=mode)
result = my_pad(data)
# 输出
# Tensor(shape=[1, 1, 1, 5, 4], dtype=float32, place=CPUPlace, stop_gradient=True,
# [[[[[0., 0., 0., 0.],
# [0., 1., 2., 3.],
# [0., 4., 5., 6.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.]]]]])
```
# torch.nn.Conv1d
### [torch.nn.Conv1d](https://pytorch.org/docs/stable/generated/torch.nn.Conv1d.html?highlight=conv1d#torch.nn.Conv1d)
```python
torch.nn.Conv1d(in_channels,
out_channels,
kernel_size,
stride=1,
padding=0,
dilation=1,
groups=1,
bias=True,
padding_mode='zeros')
```
### [paddle.nn.Conv1D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/conv/Conv1D_cn.html#conv1d)
```python
paddle.nn.Conv1D(in_channels,
out_channels,
kernel_size,
stride=1,
padding=0,
dilation=1,
groups=1,
padding_mode='zeros',
weight_attr=None,
bias_attr=None,
data_format='NCL')
```
### 功能差异
#### 输入格式
***PyTorch***:只支持`NCL`的输入。
***PaddlePaddle***:支持`NCL``NLC`两种格式的输入(通过`data_format`设置)。
#### 更新参数设置
***PyTorch***`bias`默认为True,表示使用可更新的偏置参数。
***PaddlePaddle***`weight_attr`/`bias_attr`默认使用默认的权重/偏置参数属性,否则为指定的权重/偏置参数属性,具体用法参见[ParamAttr](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/param_attr/ParamAttr_cn.html#cn-api-fluid-paramattr);当`bias_attr`设置为bool类型与PyTorch的作用一致。
#### padding的设置
***PyTorch***`padding`只能支持list或tuple类型。
***PaddlePaddle***`padding`支持list或tuple类型或str类型。
# torch.nn.Conv2d
### [torch.nn.Conv2d](https://pytorch.org/docs/stable/generated/torch.nn.Conv2d.html?highlight=conv2d#torch.nn.Conv2d)
```python
torch.nn.Conv2d(in_channels,
out_channels,
kernel_size,
stride=1,
padding=0,
dilation=1,
groups=1,
bias=True,
padding_mode='zeros')
```
### [paddle.nn.Conv2D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/conv/Conv2D_cn.html#conv2d)
```python
paddle.nn.Conv2D(in_channels,
out_channels,
kernel_size,
stride=1,
padding=0,
dilation=1,
groups=1,
padding_mode='zeros',
weight_attr=None,
bias_attr=None,
data_format='NCHW')
```
### 功能差异
#### 输入格式
***PyTorch***:只支持`NCHW`的输入。
***PaddlePaddle***:支持`NCHW``NHWC`两种格式的输入(通过`data_format`设置)。
#### 更新参数设置
***PyTorch***`bias`默认为True,表示使用可更新的偏置参数。
***PaddlePaddle***`weight_attr`/`bias_attr`默认使用默认的权重/偏置参数属性,否则为指定的权重/偏置参数属性,具体用法参见[ParamAttr](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/param_attr/ParamAttr_cn.html#cn-api-fluid-paramattr);当`bias_attr`设置为bool类型与PyTorch的作用一致。
#### padding的设置
***PyTorch***`padding`只能支持list或tuple类型。它可以有3种格式:
(1)包含4个二元组:\[\[0,0\], \[0,0\], \[padding_height_top, padding_height_bottom\], \[padding_width_left, padding_width_right\]\],其中每个元组都可使用整数值替换,代表元组中的2个值相等;
(2)包含2个二元组:\[\[padding_height_top, padding_height_bottom\], \[padding_width_left, padding_width_right\]\],其中每个元组都可使用整数值替换,代表元组中的2个值相等;
(3)包含一个整数值,padding_height = padding_width = padding。
***PaddlePaddle***`padding`支持list或tuple类型或str类型。如果它是一个list或tuple,它可以有4种格式:
(1)包含4个二元组:当 data_format 为"NCHW"时为 \[\[0,0\], \[0,0\], \[padding_height_top, padding_height_bottom\], \[padding_width_left, padding_width_right\]\],当 data_format 为"NHWC"时为\[\[0,0\], \[padding_height_top, padding_height_bottom\], \[padding_width_left, padding_width_right\], \[0,0\]\]
(2)包含4个整数值:\[padding_height_top, padding_height_bottom, padding_width_left, padding_width_right\]
(3)包含2个整数值:\[padding_height, padding_width\],此时padding_height_top = padding_height_bottom = padding_height, padding_width_left = padding_width_right = padding_width;
(4)包含一个整数值,padding_height = padding_width = padding。如果它为一个字符串时,可以是"VALID"或者"SAME",表示填充算法。
# torch.nn.Conv3d
### [torch.nn.Conv3d](https://pytorch.org/docs/stable/generated/torch.nn.Conv3d.html?highlight=conv3d#torch.nn.Conv3d)
```python
torch.nn.Conv3d(in_channels,
out_channels,
kernel_size,
stride=1,
padding=0,
dilation=1,
groups=1,
bias=True,
padding_mode='zeros')
```
### [paddle.nn.Conv3D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/conv/Conv3D_cn.html#conv3d)
```python
paddle.nn.Conv3D(in_channels,
out_channels,
kernel_size,
stride=1,
padding=0,
dilation=1,
groups=1,
padding_mode='zeros',
weight_attr=None,
bias_attr=None,
data_format='NCDHW')
```
### 功能差异
#### 输入格式
***PyTorch***:只支持`NCHW`的输入。
***PaddlePaddle***:支持`NCDHW``NDHWC`两种格式的输入(通过`data_format`设置)。
#### 更新参数设置
***PyTorch***`bias`默认为True,表示使用可更新的偏置参数。
***PaddlePaddle***`weight_attr`/`bias_attr`默认使用默认的权重/偏置参数属性,否则为指定的权重/偏置参数属性,具体用法参见[ParamAttr](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/param_attr/ParamAttr_cn.html#cn-api-fluid-paramattr);当`bias_attr`设置为bool类型与PyTorch的作用一致。
#### padding的设置
***PyTorch***`padding`只能支持list或tuple类型。它可以有3种格式:
(1)包含4个二元组:\[\[0,0\], \[0,0\], \[padding_depth_front, padding_depth_back\], \[padding_height_top, padding_height_bottom\], \[padding_width_left, padding_width_right\]\],其中每个元组都可使用整数值替换,代表元组中的2个值相等;
(2)包含3个二元组:\[\[padding_depth_front, padding_depth_back\], \[padding_height_top, padding_height_bottom\], \[padding_width_left, padding_width_right\]\],其中每个元组都可使用整数值替换,代表元组中的2个值相等;
(3)包含一个整数值,padding_height = padding_width = padding。
***PaddlePaddle***`padding`支持list或tuple类型或str类型。如果它是一个list或tuple,它可以有4种格式:
(1)包含5个二元组:当 data_format 为"NCDHW"时为 \[\[0,0], \[0,0\], \[padding_depth_front, padding_depth_back\], \[padding_height_top, padding_height_bottom\], \[padding_width_left, padding_width_right\]\],当 data_format 为"NDHWC"时为\[\[0,0\], \[padding_depth_front, padding_depth_back\], \[padding_height_top, padding_height_bottom\], \[padding_width_left, padding_width_right\], \[0,0\]\]
(2)包含6个整数值:\[padding_depth_front, padding_depth_back, padding_height_top, padding_height_bottom, padding_width_left, padding_width_right\]
(3)包含3个整数值:\[padding_depth, padding_height, padding_width\],此时 padding_depth_front = padding_depth_back = padding_depth, padding_height_top = padding_height_bottom = padding_height, padding_width_left = padding_width_right = padding_width;
(4)包含一个整数值,padding_height = padding_width = padding。如果它为一个字符串时,可以是"VALID"或者"SAME",表示填充算法。
## torch.nn.ConvTranspose1d
### [torch.nn.ConvTranspose1d](https://pytorch.org/docs/stable/generated/torch.nn.ConvTranspose1d.html?highlight=torch%20nn%20convtranspose1d#torch.nn.ConvTranspose1d)
```python
torch.nn.ConvTranspose1d(in_channels,
out_channels,
kernel_size,
stride=1,
padding=0,
output_padding=0,
groups=1,
bias=True,
dilation=1,
padding_mode='zeros')
```
### [paddle.nn.Conv1DTranspose](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/conv/Conv1DTranspose_cn.html#conv1dtranspose)
```python
paddle.nn.Conv1DTranspose(in_channels,
out_channels,
kernel_size,
stride=1,
padding=0,
output_padding=0,
groups=1,
dilation=1,
weight_attr=None,
bias_attr=None,
data_format='NCL')
```
### 功能差异
#### 输入格式
***PyTorch***:只支持`NCL`的输入。
***PaddlePaddle***:支持`NCL``NLC`两种格式的输入(通过`data_format`设置)。
#### 更新参数设置
***PyTorch***`bias`默认为True,表示使用可更新的偏置参数。
***PaddlePaddle***`weight_attr`/`bias_attr`默认使用默认的权重/偏置参数属性,否则为指定的权重/偏置参数属性,具体用法参见[ParamAttr](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/param_attr/ParamAttr_cn.html#cn-api-fluid-paramattr);当`bias_attr`设置为bool类型与PyTorch的作用一致。
#### padding大小的设置
***PyTorch***`padding`只能支持list或tuple类型。
***PaddlePaddle***`padding`支持list或tuple类型或str类型。
#### padding值的设置
***PyTorch***:通过设置`padding_mode`确定padding的值。
***PaddlePaddle***:PaddlePaddle无此参数。
## torch.nn.ConvTranspose2d
### [torch.nn.ConvTranspose2d](https://pytorch.org/docs/stable/generated/torch.nn.ConvTranspose2d.html?highlight=convtranspose2d#torch.nn.ConvTranspose2d)
```python
torch.nn.ConvTranspose1d(in_channels,
out_channels,
kernel_size,
stride=1,
padding=0,
output_padding=0,
groups=1,
bias=True,
dilation=1,
padding_mode='zeros')
```
### [paddle.nn.Conv2DTranspose](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/conv/Conv2DTranspose_cn.html#conv2dtranspose)
```python
paddle.nn.Conv2DTranspose(in_channels,
out_channels,
kernel_size,
stride=1,
padding=0,
output_padding=0,
groups=1,
dilation=1,
weight_attr=None,
bias_attr=None,
data_format='NCHW')
```
### 功能差异
#### 输入格式
***PyTorch***:只支持`NCHW`的输入。
***PaddlePaddle***:支持`NCHW``NHWC`两种格式的输入(通过`data_format`设置)。
#### 更新参数设置
***PyTorch***`bias`默认为True,表示使用可更新的偏置参数。
***PaddlePaddle***`weight_attr`/`bias_attr`默认使用默认的权重/偏置参数属性,否则为指定的权重/偏置参数属性,具体用法参见[ParamAttr](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/param_attr/ParamAttr_cn.html#cn-api-fluid-paramattr);当`bias_attr`设置为bool类型与PyTorch的作用一致。
#### padding大小的设置
***PyTorch***`padding`只能支持list或tuple类型。
***PaddlePaddle***`padding`支持list或tuple类型或str类型。
#### padding值的设置
***PyTorch***:通过设置`padding_mode`确定padding的值。
***PaddlePaddle***:PaddlePaddle无此参数。
## torch.nn.ConvTranspose3d
### [torch.nn.ConvTranspose3d](https://pytorch.org/docs/stable/generated/torch.nn.ConvTranspose3d.html?highlight=convtranspose3d#torch.nn.ConvTranspose3d)
```python
torch.nn.ConvTranspose1d(in_channels,
out_channels,
kernel_size,
stride=1,
padding=0,
output_padding=0,
groups=1,
bias=True,
dilation=1,
padding_mode='zeros')
```
### [paddle.nn.Conv3DTranspose](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/conv/Conv3DTranspose_cn.html#conv3dtranspose)
```python
paddle.nn.Conv2DTranspose(in_channels,
out_channels,
kernel_size,
stride=1,
padding=0,
output_padding=0,
groups=1,
dilation=1,
weight_attr=None,
bias_attr=None,
data_format='NCDHW')
```
### 功能差异
#### 输入格式
***PyTorch***:只支持`NCDHW`的输入。
***PaddlePaddle***:支持`NCDHW``NDHWC`两种格式的输入(通过`data_format`设置)。
#### 更新参数设置
***PyTorch***`bias`默认为True,表示使用可更新的偏置参数。
***PaddlePaddle***`weight_attr`/`bias_attr`默认使用默认的权重/偏置参数属性,否则为指定的权重/偏置参数属性,具体用法参见[ParamAttr](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/param_attr/ParamAttr_cn.html#cn-api-fluid-paramattr);当`bias_attr`设置为bool类型与PyTorch的作用一致。
#### padding大小的设置
***PyTorch***`padding`只能支持list或tuple类型。
***PaddlePaddle***`padding`支持list或tuple类型或str类型。
#### padding值的设置
***PyTorch***:通过设置`padding_mode`确定padding的值。
***PaddlePaddle***:PaddlePaddle无此参数。
## torch.nn.Dropout
### [torch.nn.Dropout](https://pytorch.org/docs/stable/generated/torch.nn.Dropout.html?highlight=dropout#torch.nn.Dropout)
```python
torch.nn.Dropout(p=0.5, inplace=False)
```
### [paddle.nn.Dropout](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Dropout_cn.html#dropout)
```python
paddle.nn.Dropout(p=0.5, axis=None, mode="upscale_in_train”, name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| inplace | - | 表示在不更改变量的内存地址的情况下,直接修改变量的值,PaddlePaddle无此参数。 |
| - | axis | 指定对输入Tensor进行Dropout操作的轴,PyTorch无此参数。 |
| - | mode | 表示丢弃单元的方式,PyTorch无此参数。|
### 功能差异
#### 丢弃方式
***PyTorch***:只支持`upscale_in_train`的丢弃方式。
***PaddlePaddle***:支持`upscale_in_train``downscale_in_infer`两种丢弃方式(通过`mode`设置),计算方法可参考[文档](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Dropout_cn.html#dropout)
## torch.nn.Dropout2d
### [torch.nn.Dropout2d](https://pytorch.org/docs/stable/generated/torch.nn.Dropout2d.html?highlight=dropout2d#torch.nn.Dropout2d)
```python
torch.nn.Dropout2d(p=0.5, inplace=False)
```
### [paddle.nn.Dropout2D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Dropout2D_cn.html#dropout2d)
```python
paddle.nn.Dropout2D(p=0.5, data_format='NCHW', name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| inplace | - | 表示在不更改变量的内存地址的情况下,直接修改变量的值,PaddlePaddle无此参数。 |
| - | data_format | 指定对输入的数据格式,PyTorch无此参数。 |
### 功能差异
#### 输入格式
***PyTorch***:只支持`NCHW`的输入。
***PaddlePaddle***:支持`NCHW``NHWC`两种格式的输入(通过`data_format`设置)。
## torch.nn.Dropout3d
### [torch.nn.Dropout3d](https://pytorch.org/docs/stable/generated/torch.nn.Dropout3d.html?highlight=dropout3d#torch.nn.Dropout3d)
```python
torch.nn.Dropout3d(p=0.5, inplace=False)
```
### [paddle.nn.Dropout3D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Dropout3D_cn.html#dropout3d)
```python
paddle.nn.Dropout3D(p=0.5, data_format='NCDHW', name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| inplace | - | 表示在不更改变量的内存地址的情况下,直接修改变量的值,PaddlePaddle无此参数。 |
| - | data_format | 指定对输入的数据格式,PyTorch无此参数。 |
### 功能差异
#### 输入格式
***PyTorch***:只支持`NCDHW`的输入。
***PaddlePaddle***:支持`NCDHW``NDHWC`两种格式的输入(通过`data_format`设置)。
## torch.nn.Embedding
### [torch.nn.Embedding](https://pytorch.org/docs/stable/generated/torch.nn.Embedding.html?highlight=embedding#torch.nn.Embedding)
```python
torch.nn.Embedding(num_embeddings,
embedding_dim,
padding_idx=None,
max_norm=None,
norm_type=2.0,
scale_grad_by_freq=False,
sparse=False)
```
### [paddle.nn.Embedding](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Embedding_cn.html#embedding)
```python
paddle.nn.Embedding(num_embeddings,
embedding_dim,
padding_idx=None,
sparse=False,
weight_attr=None,
name=None)
```
### 功能差异
#### 归一化设置
***PyTorch***:当max_norm不为`None`时,如果Embeddding向量的范数(范数的计算方式由norm_type决定)超过了max_norm这个界限,就要再进行归一化。
***PaddlePaddle***:PaddlePaddle无此要求,因此不需要归一化。
#### 梯度缩放设置
***PyTorch***:若scale_grad_by_freq设置为`True`,会根据单词在mini-batch中出现的频率,对梯度进行放缩。
***PaddlePaddle***:PaddlePaddle无此功能。
## torch.nn.GRU
### [torch.nn.GRU](https://pytorch.org/docs/stable/generated/torch.nn.GRU.html?highlight=torch%20nn%20gru#torch.nn.GRU)
```python
torch.nn.GRU(input_size,
hidden_size,
num_layers=1,
bias=True,
batch_first=False,
dropout=0,
bidirectional=False)
```
### [paddle.nn.GRU](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/rnn/GRU_cn.html#gru)
```python
paddle.nn.GRU(input_size,
hidden_size,
num_layers=1,
direction='forward',
dropout=0.,
time_major=False,
weight_ih_attr=None,
weight_hh_attr=None,
bias_ih_attr=None,
bias_hh_attr=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| batch_first | time_major | PyTorch表示batch size是否为第一维,PaddlePaddle表示time steps是否为第一位,它们的意义相反。 |
| bidirectional | direction | PyTorch表示是否进行双向LSTM,PyTorch使用字符串表示是双向LSTM(`bidirectional`)还是单向LSTM(`forward`)。 |
### 功能差异
#### 更新参数设置
***PyTorch***`bias`默认为True,表示使用可更新的偏置参数。
***PaddlePaddle***`weight_ih_attr`/`weight_hh_attr`/`bias_ih_attr`/`bias_hh_attr`默认使用默认的权重/偏置参数属性,否则为指定的权重/偏置参数属性,具体用法参见[ParamAttr](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/param_attr/ParamAttr_cn.html#cn-api-fluid-paramattr);当`bias_ih_attr`/`bias_hh_attr`设置为bool类型与PyTorch的作用一致。
## torch.nn.LSTM
### [torch.nn.LSTM](https://pytorch.org/docs/stable/generated/torch.nn.LSTM.html?highlight=lstm#torch.nn.LSTM)
```python
torch.nn.LSTM(input_size,
hidden_size,
num_layers=1,
bias=True,
batch_first=False,
dropout=0,
bidirectional=False,
proj_size=0)
```
### [paddle.nn.LSTM](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/rnn/LSTM_cn.html#lstm)
```python
paddle.nn.LSTM(input_size,
hidden_size,
num_layers=1,
direction='forward',
dropout=0.,
time_major=False,
weight_ih_attr=None,
weight_hh_attr=None,
bias_ih_attr=None,
bias_hh_attr=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| batch_first | time_major | PyTorch表示batch size是否为第一维,PaddlePaddle表示time steps是否为第一位,它们的意义相反。 |
| bidirectional | direction | PyTorch表示是否进行双向LSTM,PyTorch使用字符串表示是双向LSTM(`bidirectional`)还是单向LSTM(`forward`)。 |
| proj_size | - | 表示LSTM后将映射到对应的大小,PaddlePaddle无此功能。 |
### 功能差异
#### 映射大小的设置
***PyTorch***:支持将LSTM的结果映射到到对应大小,其具体方式可参见[论文](https://arxiv.org/abs/1402.1128)
***PaddlePaddle***:无此功能。
#### 更新参数设置
***PyTorch***`bias`默认为True,表示使用可更新的偏置参数。
***PaddlePaddle***`weight_ih_attr`/`weight_hh_attr`/`bias_ih_attr`/`bias_hh_attr`默认使用默认的权重/偏置参数属性,否则为指定的权重/偏置参数属性,具体用法参见[ParamAttr](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/param_attr/ParamAttr_cn.html#cn-api-fluid-paramattr);当`bias_ih_attr`/`bias_hh_attr`设置为bool类型与PyTorch的作用一致。
## torch.nn.Linear
### [torch.nn.Linear](https://pytorch.org/docs/stable/generated/torch.nn.Linear.html?highlight=linear#torch.nn.Linear)
```python
torch.nn.Linear(in_features, out_features, bias=True)
```
### [paddle.nn.Linear](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Linear_cn.html#linear)
```python
paddle.nn.Linear(in_features, out_features, weight_attr=None, bias_attr=None, name=None)
```
### 功能差异
#### 更新参数设置
***PyTorch***`bias`默认为True,表示使用可更新的偏置参数。
***PaddlePaddle***`weight_attr`/`bias_attr`默认使用默认的权重/偏置参数属性,否则为指定的权重/偏置参数属性,具体用法参见[ParamAttr](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/param_attr/ParamAttr_cn.html#cn-api-fluid-paramattr);当`bias_attr`设置为bool类型与PyTorch的作用一致。
## torch.nn.MaxPool1d
### [torch.nn.MaxPool1d](https://pytorch.org/docs/stable/generated/torch.nn.MaxPool1d.html?highlight=maxpool1d#torch.nn.MaxPool1d)
```python
torch.nn.MaxPool1d(kernel_size,
stride=None,
padding=0,
dilation=1,
return_indices=False,
ceil_mode=False)
```
### [paddle.nn.MaxPool1D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/pooling/MaxPool1D_cn.html#maxpool1d)
```python
paddle.nn.MaxPool1D(kernel_size,
stride=None,
padding=0,
return_mask=False,
ceil_mode=False,
name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| dilation | - | 设置空洞池化的大小,PaddlePaddle无此参数。 |
### 功能差异
#### 池化方式
***PyTorch***:可以使用空洞池化。
***PaddlePaddle***:无此池化方式。
## torch.nn.MaxPool2d
### [torch.nn.MaxPool2d](https://pytorch.org/docs/stable/generated/torch.nn.MaxPool2d.html?highlight=maxpool2d#torch.nn.MaxPool2d)
```python
torch.nn.MaxPool2d(kernel_size,
stride=None,
padding=0,
dilation=1,
return_indices=False,
ceil_mode=False)
```
### [paddle.nn.MaxPool2D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/pooling/MaxPool2D_cn.html#maxpool2d)
```python
paddle.nn.MaxPool2D(kernel_size,
stride=None,
padding=0,
return_mask=False,
ceil_mode=False,
name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| dilation | - | 设置空洞池化的大小,PaddlePaddle无此参数。 |
### 功能差异
#### 池化方式
***PyTorch***:可以使用空洞池化。
***PaddlePaddle***:无此池化方式。
## torch.nn.MaxPool3d
### [torch.nn.MaxPool3d](https://pytorch.org/docs/stable/generated/torch.nn.MaxPool3d.html?highlight=maxpool3d#torch.nn.MaxPool3d)
```python
torch.nn.MaxPool3d(kernel_size,
stride=None,
padding=0,
dilation=1,
return_indices=False,
ceil_mode=False)
```
### [paddle.nn.MaxPool3D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/pooling/MaxPool3D_cn.html#maxpool3d)
```python
paddle.nn.MaxPool3D(kernel_size,
stride=None,
padding=0,
ceil_mode=False,
return_mask=False,
data_format='NCDHW',
name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| dilation | - | 设置空洞池化的大小,PaddlePaddle无此参数。 |
### 功能差异
#### 池化方式
***PyTorch***:可以使用空洞池化。
***PaddlePaddle***:无此池化方式。
## torch.nn.MaxUnpool1d
### [torch.nn.MaxUnpool1d](https://pytorch.org/docs/stable/generated/torch.nn.MaxUnpool1d.html?highlight=unpool#torch.nn.MaxUnpool1d)
```python
torch.nn.MaxUnpool1d(kernel_size, stride=None, padding=0)
```
### 功能介绍
用于实现一维反池化,PaddlePaddle目前无对应API,可使用如下代码组合实现该API。
```python
import paddle
import paddle.nn as nn
TYPE_MAPPER = {"fp16": "float16", "fp32": "float32", "fp64": "float64"}
# 定义MaxUnpool1D
class MaxUnpool1D(paddle.nn.Layer):
def __init__(self, kernel_size, stride=None, padding=0):
super().__init__()
if isinstance(stride, int):
self.kernel_size = [kernel_size]
else:
self.kernel_size = kernel_size
if stride is None:
self.stride = self.kernel_size
else:
if isinstance(stride, int):
self.stride = [stride]
else:
self.stride = stride
if isinstance(padding, int):
self.padding = [padding]
else:
self.padding = padding
def forward(self, input, indices, output_size=None):
if output_size is None:
n, c, l = input.shape
out_l = (l - 1) * self.stride[0] - 2 * self.padding[0] + self.kernel_size[0]
output_size = (n, c, out_l)
else:
if len(output_size) == len(self.kernel_size) + 2:
output_size = output_size[2:]
t = str(input.dtype).lower().strip().split(".")[-1]
t = TYPE_MAPPER[t]
out = paddle.zeros(output_size, dtype=t)
flatten_out = paddle.flatten(out)
for i in range(indices.shape[0]):
for j in range(indices.shape[1]):
for k in range(indices.shape[2]):
indices[i, j, k] = (out.shape[1] * out.shape[2]) * i + out.shape[2] * j + indices[i, j, k]
flatten_indices = paddle.flatten(indices)
flatten_input = paddle.flatten(input)
for i in range(flatten_indices.shape[0]):
flatten_out[flatten_indices[i].tolist()] = flatten_input[i].tolist()
out = paddle.reshape(flatten_out, out.shape)
return out
# 组网
pool = nn.MaxPool1D(2, stride=2, return_mask=True)
unpool = MaxUnpool1D(2, stride=2)
# 构造输入
input = paddle.to_tensor([[[ 1., 2, 3, 4]]])
# 进行池化
pool_res, indices = pool(input)
# pool_res:
# Tensor(shape=[1, 1, 2], dtype=float32, place=CPUPlace, stop_gradient=True,
# [[[2., 4.]]])
# indices:
# Tensor(shape=[1, 1, 2], dtype=int32, place=CPUPlace, stop_gradient=True,
# [[[1, 3]]])
# 进行反池化
res = unpool(pool_res, indices)
# res:
# Tensor(shape=[1, 1, 4], dtype=float32, place=CPUPlace, stop_gradient=True,
# [[[0., 2., 0., 4.]]])
```
## torch.nn.MaxUnpool2d
### [torch.nn.MaxUnpool2d](https://pytorch.org/docs/stable/generated/torch.nn.MaxUnpool2d.html?highlight=maxunpool2d#torch.nn.MaxUnpool2d)
```python
torch.nn.MaxUnpool2d(kernel_size, stride=None, padding=0)
```
### 功能介绍
用于实现一维反池化,PaddlePaddle目前无对应API,可使用如下代码组合实现该API。
```python
import paddle
import paddle.nn as nn
TYPE_MAPPER = {"fp16": "float16", "fp32": "float32", "fp64": "float64"}
# 定义MaxUnpool2D
class MaxUnpool2D(paddle.nn.Layer):
def __init__(self, kernel_size, stride=None, padding=0):
super().__init__()
if isinstance(stride, int):
self.kernel_size = (kernel_size, kernel_size)
else:
self.kernel_size = kernel_size
if stride is None:
self.stride = self.kernel_size
else:
if isinstance(stride, int):
self.stride = (stride, stride)
else:
self.stride = stride
if isinstance(padding, int):
self.padding = (padding, padding)
else:
self.padding = padding
def forward(self, input, indices, output_size=None):
if output_size is None:
n, c, h, w = input.shape
out_h = (h - 1) * self.stride[0] - 2 * self.padding[0] + self.kernel_size[0]
out_w = (w - 1) * self.stride[1] - 2 * self.padding[1] + self.kernel_size[1]
output_size = (n, c, out_h, out_w)
else:
if len(output_size) == len(self.kernel_size) + 2:
output_size = output_size[2:]
t = str(input.dtype).lower().strip().split(".")[-1]
t = TYPE_MAPPER[t]
out = paddle.zeros(output_size, dtype=t)
flatten_out = paddle.flatten(out)
for i in range(indices.shape[0]):
for j in range(indices.shape[1]):
for k in range(indices.shape[2]):
for m in range(indices.shape[3]):
indices[i, j, k, m] = (out.shape[1] * out.shape[2] * out.shape[3]) * i + \
(out.shape[2] * out.shape[3]) * j + indices[i, j, k, m]
flatten_indices = paddle.flatten(indices)
flatten_input = paddle.flatten(input)
for i in range(flatten_indices.shape[0]):
flatten_out[flatten_indices[i].tolist()] = flatten_input[i].tolist()
out = paddle.reshape(flatten_out, out.shape)
return out
# 组网
pool = nn.MaxPool2D(2, stride=2, return_mask=True)
unpool = MaxUnpool2D(2, stride=2)
# 构造输入
input = paddle.to_tensor([[[[ 1., 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12],
[13, 14, 15, 16]]]])
# 进行池化
pool_res, indices = pool(input)
# pool_res:
# Tensor(shape=[1, 1, 2, 2], dtype=float32, place=CPUPlace, stop_gradient=True,
# [[[[6. , 8. ],
# [14., 16.]]]])
# indices:
# Tensor(shape=[1, 1, 2, 2], dtype=int32, place=CPUPlace, stop_gradient=True,
# [[[[5 , 7 ],
# [13, 15]]]])
# 进行反池化
res = unpool(pool_res, indices)
# res:
# Tensor(shape=[1, 1, 4, 4], dtype=float32, place=CPUPlace, stop_gradient=True,
# [[[[0. , 0. , 0. , 0. ],
# [0. , 6. , 0. , 8. ],
# [0. , 0. , 0. , 0. ],
# [0. , 14., 0. , 16.]]]])
```
## torch.nn.MaxUnpool3d
### [torch.nn.MaxUnpool3d](https://pytorch.org/docs/stable/generated/torch.nn.MaxUnpool3d.html?highlight=maxunpool3d#torch.nn.MaxUnpool3d)
```python
torch.nn.MaxUnpool3d(kernel_size, stride=None, padding=0)
```
### 功能介绍
用于实现一维反池化,PaddlePaddle目前无对应API,可使用如下代码组合实现该API。
```python
import paddle
import paddle.nn as nn
TYPE_MAPPER = {"fp16": "float16", "fp32": "float32", "fp64": "float64"}
# 定义MaxUnpool3D
class MaxUnpool3D(paddle.nn.Layer):
def __init__(self, kernel_size, stride=None, padding=0):
super().__init__()
if isinstance(stride, int):
self.kernel_size = (kernel_size, kernel_size, kernel_size)
else:
self.kernel_size = kernel_size
if stride is None:
self.stride = self.kernel_size
else:
if isinstance(stride, int):
self.stride = (stride, stride, stride)
else:
self.stride = stride
if isinstance(padding, int):
self.padding = (padding, padding, padding)
else:
self.padding = padding
def forward(self, input, indices, output_size=None):
if output_size is None:
n, c, d, h, w = input.shape
out_d = (d - 1) * self.stride[0] - 2 * self.padding[0] + self.kernel_size[0]
out_h = (h - 1) * self.stride[1] - 2 * self.padding[1] + self.kernel_size[1]
out_w = (w - 1) * self.stride[2] - 2 * self.padding[2] + self.kernel_size[2]
output_size = (n, c, out_d, out_h, out_w)
else:
if len(output_size) == len(self.kernel_size) + 2:
output_size = output_size[2:]
t = str(input.dtype).lower().strip().split(".")[-1]
t = TYPE_MAPPER[t]
out = paddle.zeros(output_size, dtype=t)
flatten_out = paddle.flatten(out)
for i in range(indices.shape[0]):
for j in range(indices.shape[1]):
for k in range(indices.shape[2]):
for m in range(indices.shape[3]):
for n in range(indices.shape[4]):
indices[i, j, k, m, n] = (out.shape[1] * out.shape[2] * out.shape[3] * out.shape[4]) * i + \
(out.shape[2] * out.shape[3] * out.shape[4]) * j + \
indices[i, j, k, m, n]
flatten_indices = paddle.flatten(indices)
flatten_input = paddle.flatten(input)
for i in range(flatten_indices.shape[0]):
flatten_out[flatten_indices[i].tolist()] = flatten_input[i].tolist()
out = paddle.reshape(flatten_out, out.shape)
return out
# 组网
pool = nn.MaxPool3D(2, stride=2, padding=0, return_mask=True)
unpool = MaxUnpool3D(2, stride=2, padding=0)
# 构造输入
input = paddle.to_tensor([[[[[ 1., 2, 3, 4],
[ 5, 6, 7, 8]],
[[ 1., 2, 3, 4],
[ 5, 6, 7, 8]]]]])
# 进行池化
pool_res, indices = pool(input)
# pool_res:
# Tensor(shape=[1, 1, 1, 1, 2], dtype=float32, place=CPUPlace, stop_gradient=True,
# [[[[[6., 8.]]]]])
# indices
# Tensor(shape=[1, 1, 1, 1, 2], dtype=int32, place=CPUPlace, stop_gradient=True,
# [[[[[5, 7]]]]])
# 进行反池化
res = unpool(pool_res, indices)
# res:
# Tensor(shape=[1, 1, 2, 2, 4], dtype=float32, place=CPUPlace, stop_gradient=True,
# [[[[[0., 0., 0., 0.],
# [0., 6., 0., 8.]],
# [[0., 0., 0., 0.],
# [0., 0., 0., 0.]]]]])
```
## torch.nn.ReflectionPad1d
### [torch.nn.ReflectionPad1d](https://pytorch.org/docs/stable/generated/torch.nn.ReflectionPad1d.html?highlight=pad#torch.nn.ReflectionPad1d)
```python
torch.nn.ReflectionPad1d(padding)
```
### [paddle.nn.Pad1D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Pad1D_cn.html#pad1d)
```python
paddle.nn.Pad1D(padding, mode='constant', value=0.0, data_format='NCL', name=None)
```
### 功能差异
#### 使用方式
***PyTorch***:只支持`reflect`方式的Pad方式。
***PaddlePaddle***:支持`constant``reflect``replicate``circular`四种格式的输入(通过`mode`设置)。
#### 输入格式
***PyTorch***:只支持`NCL`的输入。
***PaddlePaddle***:支持`NCL``NLC`两种格式的输入(通过`data_format`设置)。
#### padding的设置
***PyTorch***:padding参数的类型只能为int或tuple。
***PaddlePaddle***:padding参数的类型只能为Tensor或list。
### 代码示例
``` python
# PyTorch示例:
import torch
import torch.nn as nn
import numpy as np
input_shape = (1, 2, 3)
pad = 2
data = torch.arange(np.prod(input_shape), dtype=torch.float32).reshape(input_shape) + 1
my_pad = nn.ReflectionPad1d(padding=pad)
result = my_pad(data)
# 输出
# tensor([[[3., 2., 1., 2., 3., 2., 1.],
# [6., 5., 4., 5., 6., 5., 4.]]])
```
``` python
# PaddlePaddle示例:
import paddle
import paddle.nn as nn
import numpy as np
input_shape = (1, 2, 3)
pad = [2, 2]
mode = "reflect"
data = paddle.arange(np.prod(input_shape), dtype="float32").reshape(input_shape) + 1
my_pad = nn.Pad1D(padding=pad, mode=mode)
result = my_pad(data)
# 输出
# Tensor(shape=[1, 2, 7], dtype=float32, place=CPUPlace, stop_gradient=True,
# [[[3., 2., 1., 2., 3., 2., 1.],
# [6., 5., 4., 5., 6., 5., 4.]]])
```
## torch.nn.ReflectionPad2d
### [torch.nn.ReflectionPad2d](https://pytorch.org/docs/stable/generated/torch.nn.ReflectionPad2d.html?highlight=pad#torch.nn.ReflectionPad2d)
```python
torch.nn.ReflectionPad2d(padding)
```
### [paddle.nn.Pad2D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Pad2D_cn.html#pad2d)
```python
paddle.nn.Pad2D(padding, mode='constant', value=0.0, data_format='NCHW', name=None)
```
### 功能差异
#### 使用方式
***PyTorch***:只支持`reflect`方式的Pad方式。
***PaddlePaddle***:支持`constant``reflect``replicate``circular`四种格式的输入(通过`mode`设置)。
#### 输入格式
***PyTorch***:只支持`NCHW`的输入。
***PaddlePaddle***:支持`NCHW``NHWC`两种格式的输入(通过`data_format`设置)。
#### padding的设置
***PyTorch***:padding参数的类型只能为int或tuple。
***PaddlePaddle***:padding参数的类型只能为Tensor或list。
### 代码示例
``` python
# PyTorch示例:
import torch
import torch.nn as nn
import numpy as np
input_shape = (1, 1, 2, 3)
pad = [1, 0, 1, 0]
data = torch.arange(np.prod(input_shape), dtype=torch.float32).reshape(input_shape) + 1
my_pad = nn.ReflectionPad2d(padding=pad)
result = my_pad(data)
# 输出
# tensor([[[[5., 4., 5., 6.],
# [2., 1., 2., 3.],
# [5., 4., 5., 6.]]]])
```
``` python
# PaddlePaddle示例:
import paddle
import paddle.nn as nn
import numpy as np
input_shape = (1, 1, 2, 3)
pad = [1, 0, 1, 0]
mode = "reflect"
data = paddle.arange(np.prod(input_shape), dtype="float32").reshape(input_shape) + 1
my_pad = nn.Pad2D(padding=pad, mode=mode)
result = my_pad(data)
# 输出
# Tensor(shape=[1, 1, 3, 4], dtype=float32, place=CPUPlace, stop_gradient=True,
# [[[[5., 4., 5., 6.],
# [2., 1., 2., 3.],
# [5., 4., 5., 6.]]]])
```
## torch.nn.ReplicationPad1d
### [torch.nn.ReplicationPad1d](https://pytorch.org/docs/stable/generated/torch.nn.ReplicationPad1d.html?highlight=pad#torch.nn.ReplicationPad1d)
```python
torch.nn.ReplicationPad1d(padding)
```
### [paddle.nn.Pad1D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Pad1D_cn.html#pad1d)
```python
paddle.nn.Pad1D(padding, mode='constant', value=0.0, data_format='NCL', name=None)
```
### 功能差异
#### 使用方式
***PyTorch***:只支持`replicate`方式的Pad方式。
***PaddlePaddle***:支持`constant``reflect``replicate``circular`四种格式的输入(通过`mode`设置)。
#### 输入格式
***PyTorch***:只支持`NCL`的输入。
***PaddlePaddle***:支持`NCL``NLC`两种格式的输入(通过`data_format`设置)。
#### padding的设置
***PyTorch***:padding参数的类型只能为int或tuple。
***PaddlePaddle***:padding参数的类型只能为Tensor或list。
### 代码示例
``` python
# PyTorch示例:
import torch
import torch.nn as nn
import numpy as np
input_shape = (1, 2, 3)
pad = 2
data = torch.arange(np.prod(input_shape), dtype=torch.float32).reshape(input_shape) + 1
my_pad = nn.ReplicationPad1d(padding=pad)
result = my_pad(data)
# 输出
# tensor([[[1., 1., 1., 2., 3., 3., 3.],
# [4., 4., 4., 5., 6., 6., 6.]]])
```
``` python
# PaddlePaddle示例:
import paddle
import paddle.nn as nn
import numpy as np
input_shape = (1, 2, 3)
pad = [2, 2]
mode = "replicate"
data = paddle.arange(np.prod(input_shape), dtype="float32").reshape(input_shape) + 1
my_pad = nn.Pad1D(padding=pad, mode=mode)
result = my_pad(data)
# 输出
# Tensor(shape=[1, 2, 7], dtype=float32, place=CPUPlace, stop_gradient=True,
# [[[1., 1., 1., 2., 3., 3., 3.],
# [4., 4., 4., 5., 6., 6., 6.]]])
```
## torch.nn.ReplicationPad2d
### [torch.nn.ReplicationPad2d](https://pytorch.org/docs/stable/generated/torch.nn.ReplicationPad2d.html?highlight=pad#torch.nn.ReplicationPad2d)
```python
torch.nn.ReplicationPad2d(padding)
```
### [paddle.nn.Pad2D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Pad2D_cn.html#pad2d)
```python
paddle.nn.Pad2D(padding, mode='constant', value=0.0, data_format='NCHW', name=None)
```
### 功能差异
#### 使用方式
***PyTorch***:只支持`replicate`方式的Pad方式。
***PaddlePaddle***:支持`constant``reflect``replicate``circular`四种格式的输入(通过`mode`设置)。
#### 输入格式
***PyTorch***:只支持`NCHW`的输入。
***PaddlePaddle***:支持`NCHW``NHWC`两种格式的输入(通过`data_format`设置)。
#### padding的设置
***PyTorch***:padding参数的类型只能为int或tuple。
***PaddlePaddle***:padding参数的类型只能为Tensor或list。
### 代码示例
``` python
# PyTorch示例:
import torch
import torch.nn as nn
import numpy as np
input_shape = (1, 1, 2, 3)
pad = [1, 0, 1, 0]
data = torch.arange(np.prod(input_shape), dtype=torch.float32).reshape(input_shape) + 1
my_pad = nn.ReplicationPad2d(padding=pad)
result = my_pad(data)
# 输出
# tensor([[[[1., 1., 2., 3.],
# [1., 1., 2., 3.],
# [4., 4., 5., 6.]]]])
```
``` python
# PaddlePaddle示例:
import paddle
import paddle.nn as nn
import numpy as np
input_shape = (1, 1, 2, 3)
pad = [1, 0, 1, 0]
mode = "replicate"
data = paddle.arange(np.prod(input_shape), dtype="float32").reshape(input_shape) + 1
my_pad = nn.Pad2D(padding=pad, mode=mode)
result = my_pad(data)
# 输出
# Tensor(shape=[1, 1, 3, 4], dtype=float32, place=CPUPlace, stop_gradient=True,
# [[[[1., 1., 2., 3.],
# [1., 1., 2., 3.],
# [4., 4., 5., 6.]]]])
```
## torch.nn.ReplicationPad3d
### [torch.nn.ReplicationPad3d](https://pytorch.org/docs/stable/generated/torch.nn.ReplicationPad3d.html?highlight=pad#torch.nn.ReplicationPad3d)
```python
torch.nn.ReplicationPad3d(padding)
```
### [paddle.nn.Pad3D](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Pad3D_cn.html#pad3d)
```python
paddle.nn.Pad3D(padding, mode='constant', value=0.0, data_format='NCDHW', name=None)
```
### 功能差异
#### 使用方式
***PyTorch***:只支持`replicate`方式的Pad方式。
***PaddlePaddle***:支持`constant``reflect``replicate``circular`四种格式的输入(通过`mode`设置)。
#### 输入格式
***PyTorch***:只支持`NCDHW`的输入。
***PaddlePaddle***:支持`NCDHW``NCDHW`两种格式的输入(通过`data_format`设置)。
#### padding的设置
***PyTorch***:padding参数的类型只能为int或tuple。
***PaddlePaddle***:padding参数的类型只能为Tensor或list。
### 代码示例
``` python
# PyTorch示例:
import paddle
import paddle.nn as nn
import numpy as np
input_shape = (1, 1, 1, 2, 3)
pad = [1, 0, 1, 2, 0, 0]
mode = "constant"
data = paddle.arange(np.prod(input_shape), dtype="float32").reshape(input_shape) + 1
my_pad = nn.Pad3D(padding=pad, mode=mode)
result = my_pad(data)
# 输出
# tensor([[[[[1., 1., 2., 3.],
# [1., 1., 2., 3.],
# [4., 4., 5., 6.],
# [4., 4., 5., 6.],
# [4., 4., 5., 6.]]]]])
```
``` python
# PaddlePaddle示例:
import paddle
import paddle.nn as nn
import numpy as np
input_shape = (1, 1, 1, 2, 3)
pad = [1, 0, 1, 2, 0, 0]
mode = "constant"
data = paddle.arange(np.prod(input_shape), dtype="float32").reshape(input_shape) + 1
my_pad = nn.Pad3D(padding=pad, mode=mode)
result = my_pad(data)
# 输出
# Tensor(shape=[1, 1, 1, 5, 4], dtype=float32, place=CPUPlace, stop_gradient=True,
# [[[[[1., 1., 2., 3.],
# [1., 1., 2., 3.],
# [4., 4., 5., 6.],
# [4., 4., 5., 6.],
# [4., 4., 5., 6.]]]]])
```
## torch.nn.Upsample
### [torch.nn.Upsample](https://pytorch.org/docs/stable/generated/torch.nn.Upsample.html?highlight=upsample#torch.nn.Upsample)
```python
torch.nn.Upsample(size=None,
scale_factor=None,
mode='nearest',
align_corners=False)
```
### [paddle.nn.Upsample](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Upsample_cn.html#upsample)
```python
paddle.nn.Upsample(size=None,
scale_factor=None,
mode='nearest',
align_corners=False,
align_mode=0,
data_format='NCHW',
name=None)
```
### 功能差异
#### 输入格式
***PyTorch***:只支持`NCHW`的输入。
***PaddlePaddle***:支持`NCHW``NHWC`两种格式的输入(通过`data_format`设置)。
#### 计算方式
***PyTorch***:在mode为`bilinear``trilinear`时,只支持align_mode为0的上采样。
***PaddlePaddle***:在mode为`bilinear``trilinear`时,支持align_mode为0和1的上采样。
【注意】align_mode为0或1时的上采样方式可参见[文档](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/layer/common/Upsample_cn.html#upsample)
## PyTorch-PaddlePaddle 基础操作类API对应表
| 序号 | PyTorch API | PaddlePaddle API | 备注 |
| ---- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
| 1 | [torch.set\_default\_dtype](https://pytorch.org/docs/stable/generated/torch.set_default_dtype.html) | [paddle.set\_default\_dtype](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/framework/set_default_dtype_cn.html) | 功能一致 |
| 2 | [torch.get\_default\_dtype](https://pytorch.org/docs/stable/generated/torch.get_default_dtype.html) | [paddle.get\_default\_dtype](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/framework/get_default_dtype_cn.html#get-default-dtype) | 功能一致 |
| 3 | [torch.numel](https://pytorch.org/docs/stable/generated/torch.numel.html) | [paddle.numel](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/stat/numel_cn.html#numel) | 功能一致,参数名不一致 |
| 4 | [torch.tensor](https://pytorch.org/docs/stable/generated/torch.tensor.html?highlight=tensor#torch.tensor) | [paddle.to\_tensor](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/creation/to_tensor_cn.html#to-tensor) | [差异对比](torch.tensor.md) |
| 5 | [torch.from\_numpy](https://pytorch.org/docs/stable/generated/torch.from_numpy.html?highlight=from_numpy#torch.from_numpy) | [paddle.to\_tensor](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/creation/to_tensor_cn.html#to-tensor) | [差异对比](torch.from_numpy.md) |
| 6 | [torch.zeros](https://pytorch.org/docs/stable/generated/torch.zeros.html?highlight=zeros#torch.zeros) | [paddle.zeros](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/creation/zeros_cn.html#zeros) | [差异对比](torch.zeros.md) |
| 7 | [torch.zeros_like](https://pytorch.org/docs/stable/generated/torch.zeros_like.html?highlight=zeros_like#torch.zeros_like) | [paddle.zeros_like](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/creation/zeros_like_cn.html#zeros-like) | [差异对比](torch.zeros_like.md) |
| 8 | [torch.ones](https://pytorch.org/docs/stable/generated/torch.ones.html?highlight=ones#torch.ones) | [paddle.ones](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/creation/ones_cn.html#ones) | [差异对比](torch.ones.md) |
| 9 | [torch.ones_like](https://pytorch.org/docs/stable/generated/torch.zeros_like.html?highlight=zeros_like#torch.zeros_like) | [paddle.ones_like](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/creation/zeros_like_cn.html#zeros-like) | [差异对比](torch.ones_like.md) |
| 10 | [torch.empty](https://pytorch.org/docs/stable/generated/torch.empty.html?highlight=empty#torch.empty) | [paddle.empty](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/creation/empty_cn.html#empty) | [差异对比](torch.empty.md) |
| 11 | [torch.empty_like](https://pytorch.org/docs/stable/generated/torch.empty_like.html?highlight=empty_like#torch.empty_like) | [paddle.empty_like](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/creation/empty_like_cn.html#empty-like) | [差异对比](torch.empty_like.md) |
| 12 | [torch.full](https://pytorch.org/docs/stable/generated/torch.full.html?highlight=full#torch.full) | [paddle.full](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/creation/full_cn.html#full) | 功能一致,[参数不一致](torch.full.md) |
| 13 | [torch.full_like](https://pytorch.org/docs/stable/generated/torch.full_like.html?highlight=full_like#torch.full_like) | [paddle.full_like](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/creation/full_like_cn.html#full-like) | [差异对比](torch.full_like.md) |
| 14 | [torch.arange](https://pytorch.org/docs/stable/generated/torch.arange.html?highlight=arange#torch.arange) | [paddle.arange](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/creation/arange_cn.html#arange) | 功能一致,[参数不一致](torch.arange.md) |
| 15 | [torch.range](https://pytorch.org/docs/stable/generated/torch.range.html?highlight=range#torch.range) | [paddle.arange](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/creation/arange_cn.html#arange) | 功能一致,[参数不一致](torch.range.md) |
| 16 | [torch.linspace](https://pytorch.org/docs/stable/generated/torch.linspace.html?highlight=linspace#torch.linspace) | [paddle.linspace](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/linspace_cn.html#linspace) | 功能一致,[参数不一致](torch.linspace.md) |
| 17 | [torch.eye](https://pytorch.org/docs/stable/generated/torch.eye.html?highlight=eye#torch.eye) | [paddle.eye](https://pytorch.org/docs/stable/generated/torch.eye.html?highlight=eye#torch.eye) | 功能一致,[参数不一致](torch.eye.md) |
| 18 | [torch.cat](https://pytorch.org/docs/stable/generated/torch.cat.html?highlight=torch%20cat#torch.cat) | [paddle.concat](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/manipulation/concat_cn.html#concat) | 功能一致,参数名不一致 |
| 19 | [torch.chunk](https://pytorch.org/docs/stable/generated/torch.chunk.html?highlight=chunk#torch.chunk) | [paddle.chunk](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/manipulation/chunk_cn.html#chunk) | 功能一致,参数名不一致 |
| 20 | [torch.gather](https://pytorch.org/docs/stable/generated/torch.gather.html?highlight=gather#torch.gather) | [paddle.gather](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/manipulation/gather_cn.html#gather) | [差异对比](torch.gather.md) |
| 21 | [torch.index\_select](https://pytorch.org/docs/stable/generated/torch.index_select.html?highlight=index_select#torch.index_select) | [paddle.index\_select](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/search/index_select_cn.html#index-select) | 功能一致,参数名不一致 |
| 22 | [torch.masked\_select](https://pytorch.org/docs/stable/generated/torch.masked_select.html?highlight=masked_sel#torch.masked_select) | [paddle.masked\_select](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/search/masked_select_cn.html#masked-select) | 功能一致,参数名不一致 |
| 23 | [torch.narrow](https://pytorch.org/docs/stable/generated/torch.narrow.html?highlight=narrow#torch.narrow) | [paddle.slice](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/slice_cn.html#slice) | [差异对比](torch.narrow.md) |
| 24 | [torch.nonzero](https://pytorch.org/docs/stable/generated/torch.nonzero.html?highlight=nonzero#torch.nonzero) | [paddle.nonzero](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/search/nonzero_cn.html#nonzero) | 功能一致,参数名不一致 |
| 25 | [torch.reshape](https://pytorch.org/docs/stable/generated/torch.reshape.html?highlight=reshape#torch.reshape) | [paddle.reshape](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/manipulation/reshape_cn.html#reshape) | 功能一致,参数名不一致 |
| 26 | [torch.split](https://pytorch.org/docs/stable/generated/torch.split.html?highlight=split#torch.split) | [paddle.split](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/manipulation/split_cn.html#split) | 功能一致,参数名不一致 |
| 27 | [torch.squeeze](https://pytorch.org/docs/stable/generated/torch.squeeze.html?highlight=squeeze#torch.squeeze) | [paddle.squeeze](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/manipulation/squeeze_cn.html#squeeze) | 功能一致,参数名不一致 |
| 28 | [torch.stack](https://pytorch.org/docs/stable/generated/torch.stack.html?highlight=stack#torch.stack) | [paddle.stack](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/manipulation/stack_cn.html#stack) | 功能一致,参数名不一致 |
| 29 | [torch.t](https://pytorch.org/docs/stable/generated/torch.t.html) | [paddle.t](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/linalg/t_cn.html#t) | 功能一致,参数名不一致 |
| 30 | [torch.transpose](https://pytorch.org/docs/stable/generated/torch.transpose.html?highlight=transpose#torch.transpose) | [paddle.transpose](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/transpose_cn.html#transpose) | [差异对比](torch.transpose.md) |
| 31 | [torch.unbind](https://pytorch.org/docs/stable/generated/torch.unbind.html?highlight=unbind#torch.unbind) | [paddle.unbind](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/manipulation/unbind_cn.html#unbind) | 功能一致,参数名不一致 |
| 32 | [torch.unsqueeze](https://pytorch.org/docs/stable/generated/torch.unsqueeze.html?highlight=unsqueeze#torch.unsqueeze) | [paddle.unsqueeze](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/manipulation/unsqueeze_cn.html#unsqueeze) | 功能一致,参数名不一致 |
| 33 | [torch.where](https://pytorch.org/docs/stable/generated/torch.where.html?highlight=where#torch.where) | [paddle.where](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/search/where_cn.html#where) | 功能一致 |
| 34 | [torch.bernoulli](https://pytorch.org/docs/stable/generated/torch.bernoulli.html?highlight=bernoulli#torch.bernoulli) | [paddle.bernoulli](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/random/bernoulli_cn.html#bernoulli) | 功能一致,[参数不一致](torch.bernoulli.md) |
| 35 | [torch.multinomial](https://pytorch.org/docs/stable/generated/torch.multinomial.html?highlight=multinomial#torch.multinomial) | [paddle.multinomial](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/random/multinomial_cn.html#multinomial) | 功能一致,[参数不一致](torch.multinomial.md) |
| 36 | [torch.normal](https://pytorch.org/docs/stable/generated/torch.normal.html?highlight=normal#torch.normal) | [paddle.normal](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/random/normal_cn.html#normal) | [差异对比](torch.normal.md) |
| 37 | [torch.rand](https://pytorch.org/docs/stable/generated/torch.rand.html?highlight=rand#torch.rand) | [paddle.rand](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/random/rand_cn.html#rand) | [差异对比](torch.rand.md) |
| 38 | [torch.randint](https://pytorch.org/docs/stable/generated/torch.randint.html?highlight=randint#torch.randint) | [paddle.randint](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/random/randint_cn.html#randint) | 功能一致,[参数不一致](torch.randint.md) |
| 39 | [torch.randn](https://pytorch.org/docs/stable/generated/torch.randn.html?highlight=ran%20dn#torch.randn) | [paddle.randn](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/random/randn_cn.html#randn) | [差异对比](torch.randn.md) |
| 40 | [torch.randperm](https://pytorch.org/docs/stable/generated/torch.randperm.html?highlight=randperm#torch.randperm) | [paddle.randperm](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/random/randperm_cn.html#randperm) | 功能一致,[参数不一致](torch.randperm.md) |
| 41 | [torch.save](https://pytorch.org/docs/stable/generated/torch.save.html?highlight=save#torch.save) | [paddle.save](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/framework/io/save_cn.html#save) | [差异对比](torch.save.md) |
| 42 | [torch.load](https://pytorch.org/docs/stable/generated/torch.load.html?highlight=load#torch.load) | [paddle.load](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/framework/io/load_cn.html#load) | [差异对比](torch.load.md) |
| 43 | [torch.abs](https://pytorch.org/docs/stable/generated/torch.abs.html?highlight=abs#torch.abs) | [paddle.abs](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/abs_cn.html#abs) | 功能一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 44 | [torch.absolute](https://pytorch.org/docs/stable/generated/torch.absolute.html?highlight=absolute#torch.absolute) | [paddle.abs](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/abs_cn.html#abs) | 功能一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 45 | [torch.acos](https://pytorch.org/docs/stable/generated/torch.acos.html?highlight=torch%20acos#torch.acos) | [paddle.acos](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/acos_cn.html#acos) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 46 | [torch.arccos](https://pytorch.org/docs/stable/generated/torch.arccos.html?highlight=arccos#torch.arccos) | [paddle.acos](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/acos_cn.html#acos) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 47 | [torch.add](https://pytorch.org/docs/stable/generated/torch.add.html?highlight=add#torch.add) | [padle.add](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/math/add_cn.html#add) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 48 | [torch.asin](https://pytorch.org/docs/stable/generated/torch.asin.html?highlight=asin#torch.asin) | [paddle.asin](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/asin_cn.html#asin) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 49 | [torch.arcsin](https://pytorch.org/docs/stable/generated/torch.arcsin.html?highlight=arcsin#torch.arcsin) | [paddle.asin](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/asin_cn.html#asin) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 50 | [torch.atan](https://pytorch.org/docs/stable/generated/torch.atan.html?highlight=atan#torch.atan) | [paddle.atan](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/atan_cn.html#atan) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 51 | [torch.arctan](https://pytorch.org/docs/stable/generated/torch.arctan.html?highlight=arctan#torch.arctan) | [paddle.atan](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/atan_cn.html#atan) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 52 | [torch.ceil](https://pytorch.org/docs/stable/generated/torch.ceil.html?highlight=ceil#torch.ceil) | [paddle.ceil](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/ceil_cn.html#ceil) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 53 | [torch.clamp](https://pytorch.org/docs/stable/generated/torch.clamp.html#torch.clamp) | [paddle.clip](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/math/clip_cn.html#clip) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 54 | [torch.conj](https://pytorch.org/docs/stable/generated/torch.conj.html?highlight=conj#torch.conj) | [paddle.conj](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/math/conj_cn.html#conj) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 55 | [torch.cos](https://pytorch.org/docs/stable/generated/torch.cos.html?highlight=cos#torch.cos) | [paddle.cos](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/cos_cn.html#cos) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 56 | [torch.cosh](https://pytorch.org/docs/stable/generated/torch.cosh.html?highlight=cosh#torch.cosh) | [paddle.cosh](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/cosh_cn.html#cosh) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 57 | [torch.div](https://pytorch.org/docs/stable/generated/torch.div.html?highlight=div#torch.div) | [paddle.divide](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/math/divide_cn.html#divide) | [差异对比](torch.div.md) |
| 58 | [torch.divide](https://pytorch.org/docs/stable/generated/torch.divide.html?highlight=divide#torch.divide) | [paddle.divide](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/math/divide_cn.html#divide) | [差异对比](torch.divide.md) |
| 59 | [torch.erf](https://pytorch.org/docs/stable/generated/torch.erf.html?highlight=erf#torch.erf) | [paddle.erf](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/erf_cn.html#erf) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 60 | [torch.exp](https://pytorch.org/docs/stable/generated/torch.exp.html?highlight=exp#torch.exp) | [paddle.exp](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/exp_cn.html#exp) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 61 | [torch.floor](https://pytorch.org/docs/stable/generated/torch.floor.html?highlight=floor#torch.floor) | [paddle.floor](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/floor_cn.html#floor) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 62 | [torch.floor_divide](https://pytorch.org/docs/stable/generated/torch.floor_divide.html?highlight=floor_divide#torch.floor_divide) | [paddle.floor_divide](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/math/floor_divide_cn.html#floor-divide) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 63 | [torch.fmod](https://pytorch.org/docs/stable/generated/torch.fmod.html?highlight=fmod#torch.fmod) | [paddle.mod](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/math/remainder_cn.html#mod) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 64 | [torch.log](https://pytorch.org/docs/stable/generated/torch.log.html?highlight=log#torch.log) | [paddle.log](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/log_cn.html#log) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 65 | [torch.log10](https://pytorch.org/docs/stable/generated/torch.log10.html?highlight=log10#torch.log10) | [paddle.log10](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/math/log10_cn.html#log10) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 66 | [torch.log1p](https://pytorch.org/docs/stable/generated/torch.log1p.html?highlight=log1p#torch.log1p) | [paddle.log1p](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/math/log1p_cn.html#log1p) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 67 | [torch.log2](https://pytorch.org/docs/stable/generated/torch.log2.html?highlight=log2#torch.log2) | [paddle.log2](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/math/log2_cn.html#log2) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 68 | [torch.logical_and](https://pytorch.org/docs/stable/generated/torch.logical_and.html?highlight=logical_and#torch.logical_and) | [paddle.logical_and](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/logical_and_cn.html#logical-and) | 功能一致,参数名不一致 |
| 69 | [torch.logical_not](https://pytorch.org/docs/stable/generated/torch.logical_not.html?highlight=logical_not#torch.logical_not) | [paddle.logical_not](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/logical_not_cn.html#logical-not) | 功能一致,参数名不一致 |
| 70 | [torch.logical_or](https://pytorch.org/docs/stable/generated/torch.logical_or.html?highlight=logical_or#torch.logical_or) | [paddle.logical_or](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/logical_or_cn.html#logical-or) | 功能一致,参数名不一致 |
| 71 | [torch.logical_xor](https://pytorch.org/docs/stable/generated/torch.logical_xor.html?highlight=logical_xor#torch.logical_xor) | [paddle.logical_xor](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/logical_xor_cn.html#logical-xor) | 功能一致,参数名不一致 |
| 72 | [torch.mul](https://pytorch.org/docs/stable/generated/torch.mul.html?highlight=torch%20mul#torch.mul) | [paddle.multiply](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/math/multiply_cn.html#multiply) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 73 | [torch.multiply](https://pytorch.org/docs/stable/generated/torch.multiply.html?highlight=multiply#torch.multiply) | [paddle.multiply](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/math/multiply_cn.html#multiply) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 74 | [torch.pow](https://pytorch.org/docs/stable/generated/torch.pow.html?highlight=pow#torch.pow) | [paddle.pow](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/math/pow_cn.html#pow) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 75 | [torch.real](https://pytorch.org/docs/stable/generated/torch.real.html?highlight=real#torch.real) | [paddle.real](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/attribute/real_cn.html#real) | 功能一致,参数名不一致 |
| 76 | [torch.reciprocal](https://pytorch.org/docs/stable/generated/torch.reciprocal.html?highlight=reciprocal#torch.reciprocal) | [paddle.reciprocal](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/reciprocal_cn.html#reciprocal) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 77 | [torch.remainder](https://pytorch.org/docs/stable/generated/torch.remainder.html?highlight=remainder#torch.remainder) | [paddle.mod](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/math/remainder_cn.html#cn-api-tensor-remainder) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 78 | [torch.round](https://pytorch.org/docs/stable/generated/torch.round.html?highlight=round#torch.round) | [paddle.round](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/round_cn.html#round) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 79 | [torch.rsqrt](https://pytorch.org/docs/stable/generated/torch.rsqrt.html?highlight=rsqrt#torch.rsqrt) | [paddle.rsqrt](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/rsqrt_cn.html#rsqrt) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 80 | [torch.sign](https://pytorch.org/docs/stable/generated/torch.sign.html?highlight=sign#torch.sign) | [paddle.sign](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/math/sign_cn.html#sign) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 81 | [torch.sin](https://pytorch.org/docs/stable/generated/torch.sin.html?highlight=sin#torch.sin) | [paddle.sin](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/sin_cn.html#sin) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 82 | [torch.sinh](https://pytorch.org/docs/stable/generated/torch.sinh.html?highlight=sinh#torch.sinh) | [paddle.sinh](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/sinh_cn.html#sinh) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 83 | [torch.sqrt](https://pytorch.org/docs/stable/generated/torch.sqrt.html?highlight=sqrt#torch.sqrt) | [paddle.sqrt](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/sqrt_cn.html#sqrt) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 84 | [torch.argmax](https://pytorch.org/docs/stable/generated/torch.argmax.html?highlight=argmax#torch.argmax) | [paddle.argmax](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/search/argmax_cn.html#argmax) | 功能一致,参数名不一致 |
| 85 | [torch.argmin](https://pytorch.org/docs/stable/generated/torch.argmin.html?highlight=argmin#torch.argmin) | [paddle.argmin](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/search/argmin_cn.html#argmin) | 功能一致,参数名不一致 |
| 86 | [torch.max](https://pytorch.org/docs/stable/generated/torch.max.html?highlight=max#torch.max) | [paddle.max](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/math/max_cn.html#max) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
| 87 | [torch.min](https://pytorch.org/docs/stable/generated/torch.min.html?highlight=min#torch.min) | [paddle.min](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/math/min_cn.html#min) | 功能一致,参数名不一致,PaddlePaddle未定义`out`参数代表输出Tensor |
***持续更新...***
## torch.arange
### [torch.arange](https://pytorch.org/docs/stable/generated/torch.arange.html?highlight=arange#torch.arange)
```python
torch.arange(start=0,
end,
step=1,
*,
out=None,
dtype=None,
layout=torch.strided,
device=None,
requires_grad=False)
```
### [paddle.arange](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/creation/arange_cn.html#arange)
```python
paddle.arange(start=0,
end=None,
step=1,
dtype=None,
name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| out | - | 表示输出的Tensor,PaddlePaddle无此参数。 |
| layout | - | 表示布局方式,PaddlePaddle无此参数。 |
| device | - | 表示Tensor存放位置,PaddlePaddle无此参数。 |
| requires_grad | - | 表示是否不阻断梯度传导,PaddlePaddle无此参数。 |
## torch.bernoulli
### [torch.bernoulli](https://pytorch.org/docs/stable/generated/torch.bernoulli.html?highlight=bernoulli#torch.bernoulli)
```python
torch.bernoulli(input, *, generator=None, out=None)
```
### [paddle.bernoulli](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/random/bernoulli_cn.html#bernoulli)
```python
paddle.bernoulli(x, name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| input | x | 表示输入Tensor。 |
| generator | - | 用于采样的伪随机数生成器,PaddlePaddle无此参数。 |
| out | - | 表示输出的Tensor,PaddlePaddle无此参数。 |
***【注意】*** 这类生成器的用法如下:
```python
G = torch.Generator()
G.manual_seed(1)
# 生成指定分布Tensor
torch.randperm(5, generator=G)
```
## torch.div
### [torch.div](https://pytorch.org/docs/stable/generated/torch.div.html?highlight=div#torch.div)
```python
torch.div(input, other, *, rounding_mode=None, out=None)
```
### [paddle.divide](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/math/divide_cn.html#divide)
```python
paddle.divide(x, y, name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| rounding_mode | - | 表示舍入模式,PaddlePaddle无此参数。 |
| out | - | 表示输出的Tensor,PaddlePaddle无此参数。 |
### 功能差异
#### 舍入模式设置
***PyTorch***:可以通过`rounding_mode`设置舍入模式,`"trunc"`表示向0取整,`"floor"`表示向下取整,默认值为`None`表示不进行任何舍入操作。
***PaddlePaddle***:PaddlePaddle无此功能,需要组合实现。
### 代码示例
``` python
# PyTorch示例:
import torch
a = torch.tensor([ 0.3810, 1.2774, -0.3719, 0.4637])
b = torch.tensor([ 1.8032, 0.2930, 0.5091, -0.1392])
out = torch.div(a, b, rounding_mode='trunc')
# 输出
# tensor([ 0., 4., -0., -3.])
```
``` python
# PaddlePaddle示例:
import paddle
a = paddle.to_tensor([0.3810, 1.2774, -0.3719, 0.4637], dtype="float32")
b = paddle.to_tensor([1.8032, 0.2930, 0.5091, -0.1392], dtype="float32")
ipt = paddle.divide(a, b)
sign_ipt = paddle.sign(ipt)
abs_ipt = paddle.abs(ipt)
abs_ipt = paddle.floor(abs_ipt)
out = paddle.multiply(sign_ipt, abs_ipt)
# 输出
# Tensor(shape=[4], dtype=float32, place=CPUPlace, stop_gradient=True,
# [ 0., 4., -0., -3.])
```
## torch.divide
### [torch.divide](https://pytorch.org/docs/stable/generated/torch.divide.html?highlight=divide#torch.divide)
```python
torch.divide(input, other, *, rounding_mode=None, out=None)
```
### [paddle.divide](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/math/divide_cn.html#divide)
```python
paddle.divide(x, y, name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| rounding_mode | - | 表示舍入模式,PaddlePaddle无此参数。 |
| out | - | 表示输出的Tensor,PaddlePaddle无此参数。 |
### 功能差异
#### 舍入模式设置
***PyTorch***:可以通过`rounding_mode`设置舍入模式,`"trunc"`表示向0取整,`"floor"`表示向下取整,默认值为`None`表示不进行任何舍入操作。
***PaddlePaddle***:PaddlePaddle无此功能,需要组合实现。
### 代码示例
``` python
# PyTorch示例:
import torch
a = torch.tensor([ 0.3810, 1.2774, -0.3719, 0.4637])
b = torch.tensor([ 1.8032, 0.2930, 0.5091, -0.1392])
out = torch.divide(a, b, rounding_mode='trunc')
# 输出
# tensor([ 0., 4., -0., -3.])
```
``` python
# PaddlePaddle示例:
import paddle
a = paddle.to_tensor([0.3810, 1.2774, -0.3719, 0.4637], dtype="float32")
b = paddle.to_tensor([1.8032, 0.2930, 0.5091, -0.1392], dtype="float32")
ipt = paddle.divide(a, b)
sign_ipt = paddle.sign(ipt)
abs_ipt = paddle.abs(ipt)
abs_ipt = paddle.floor(abs_ipt)
out = paddle.multiply(sign_ipt, abs_ipt)
# 输出
# Tensor(shape=[4], dtype=float32, place=CPUPlace, stop_gradient=True,
# [ 0., 4., -0., -3.])
```
## torch.empty
### [torch.empty](https://pytorch.org/docs/stable/generated/torch.empty.html?highlight=empty#torch.empty)
```python
torch.empty(*size,
*,
out=None,
dtype=None,
layout=torch.strided,
device=None,
requires_grad=False,
pin_memory=False)
```
### [paddle.empty](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/creation/empty_cn.html#empty)
```python
paddle.empty(shape,
dtype=None,
name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| size | shape | 表示输出形状大小。 |
| out | - | 表示输出的Tensor,PaddlePaddle无此参数。 |
| layout | - | 表示布局方式,PaddlePaddle无此参数。 |
| device | - | 表示Tensor存放位置,PaddlePaddle无此参数。 |
| requires_grad | - | 表示是否不阻断梯度传导,PaddlePaddle无此参数。 |
| pin_memeory | - | 表示是否使用锁页内存,PaddlePaddle无此参数。 |
### 功能差异
#### 使用方式
***PyTorch***:生成Tensor的形状大小以可变参数的方式传入。
***PaddlePaddle***:生成Tensor的形状大小以list的方式传入。
### 代码示例
``` python
# PyTorch示例:
torch.empty(2, 3)
# 输出
# tensor([[9.1835e-41, 0.0000e+00, 0.0000e+00],
# [0.0000e+00, 0.0000e+00, 0.0000e+00]])
```
``` python
# PaddlePaddle示例:
paddle.empty([2, 3])
# 输出
# Tensor(shape=[2, 3], dtype=float32, place=CPUPlace, stop_gradient=True,
# [[0., 0., 0.],
# [0., 0., 0.]])
```
## torch.empty_like
### [torch.empty_like](https://pytorch.org/docs/stable/generated/torch.empty_like.html?highlight=empty_like#torch.empty_like)
```python
torch.empty_like(input,
*,
dtype=None,
layout=None,
device=None,
requires_grad=False,
memory_format=torch.preserve_format)
```
### [paddle.empty_like](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/creation/empty_like_cn.html#empty-like)
```python
paddle.empty_like(x, dtype=None, name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| input | x | 表示输入Tensor。 |
| layout | - | 表示布局方式,PaddlePaddle无此参数。 |
| device | - | 表示Tensor存放位置,PaddlePaddle无此参数。 |
| requires_grad | - | 表示是否不阻断梯度传导,PaddlePaddle无此参数。 |
| pin_memeory | - | 表示是否使用锁页内存,PaddlePaddle无此参数。 |
## torch.eye
### [torch.eye](https://pytorch.org/docs/stable/generated/torch.eye.html?highlight=eye#torch.eye)
```python
torch.eye(n,
m=None,
*,
out=None,
dtype=None,
layout=torch.strided,
device=None,
requires_grad=False)
```
### [paddle.eye](https://pytorch.org/docs/stable/generated/torch.eye.html?highlight=eye#torch.eye)
```python
paddle.eye(num_rows,
num_columns=None,
dtype=None,
name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| n | num_rows | 生成2-D Tensor的行数。 |
| m | num_columns | 生成2-D Tensor的列数。 |
| out | - | 表示输出的Tensor,PaddlePaddle无此参数。 |
| layout | - | 表示布局方式,PaddlePaddle无此参数。 |
| device | - | 表示Tensor存放位置,PaddlePaddle无此参数。 |
| requires_grad | - | 表示是否不阻断梯度传导,PaddlePaddle无此参数。 |
## torch.tensor
### [torch.from_numpy](https://pytorch.org/docs/stable/generated/torch.from_numpy.html?highlight=from_numpy#torch.from_numpy)
```python
torch.from_numpy(ndarray)
```
### [paddle.to_tensor](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/creation/to_tensor_cn.html#to-tensor)
```python
paddle.to_tensor(data,
dtype=None,
place=None,
stop_gradient=True)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| ndarray | data | 表示需要转换的数据。 |
| - | dtype | 表示数据类型,PyTorch无此参数。 |
| - | place | 表示Tensor存放位置,PyTorch无此参数。 |
| - | stop_gradient | 表示是否阻断梯度传导,PyTorch无此参数。 |
### 功能差异
#### 使用方式
***PyTorch***:只能传入一个numpy.ndarray。
***PaddlePaddle***:可以传入scalar、list、tuple、numpy.ndarray、paddle.Tensor。
## torch.full
### [torch.full](https://pytorch.org/docs/stable/generated/torch.full.html?highlight=full#torch.full)
```python
torch.full(size,
fill_value,
*,
out=None,
dtype=None,
layout=torch.strided,
device=None,
requires_grad=False)
```
### [paddle.full](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/creation/full_cn.html#full)
```python
paddle.full(shape,
fill_value,
dtype=None,
name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| size | shape | 表示输出形状大小。 |
| out | - | 表示输出的Tensor,PaddlePaddle无此参数。 |
| layout | - | 表示布局方式,PaddlePaddle无此参数。 |
| device | - | 表示Tensor存放位置,PaddlePaddle无此参数。 |
| requires_grad | - | 表示是否不阻断梯度传导,PaddlePaddle无此参数。 |
## torch.full_like
### [torch.full_like](https://pytorch.org/docs/stable/generated/torch.full_like.html?highlight=full_like#torch.full_like)
```python
torch.full_like(input,
fill_value,
*,
dtype=None,
layout=torch.strided,
device=None,
requires_grad=False,
memory_format=torch.preserve_format)
```
### [paddle.full_like](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/creation/full_like_cn.html#full-like)
```python
paddle.full_like(x, fill_value, dtype=None, name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| input | x | 表示输入Tensor。 |
| layout | - | 表示布局方式,PaddlePaddle无此参数。 |
| device | - | 表示Tensor存放位置,PaddlePaddle无此参数。 |
| requires_grad | - | 表示是否阻断梯度传导,PaddlePaddle无此参数。 |
| memory_format | - | 表示是内存格式,PaddlePaddle无此参数。 |
## torch.gather
### [torch.gather](https://pytorch.org/docs/stable/generated/torch.gather.html?highlight=gather#torch.gather)
```python
torch.gather(input, dim, index, *, sparse_grad=False, out=None)
```
### [paddle.gather](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/manipulation/gather_cn.html#gather)
```python
paddle.gather(x, index, axis=None, name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| input | x | 表示输入Tensor。 |
| dim | axis | 用于指定index获取输入的维度,PyTorch中类型仅能为int,PaddlePaddle中类型可以为int32/int64/Tensor。 |
| sparse_grad | - | 表示是否对梯度稀疏化,PaddlePaddle无此参数。 |
| out | - | 表示目标Tensor,PaddlePaddle无此参数。 |
### 功能差异
#### 使用方式
***PyTorch***:索引(index)的维度数和输入(input)的维度数一致,索引(index)的形状大小要小于等于输入(input)的形状大小。
***PaddlePaddle***:索引(index)的秩有且只能等于1。
#### 计算方式
***PyTorch***:沿指定的轴(dim)收集值。以2-D Tensor输入为例,其输出结果如下:
```
if dim == 0:
out[i][j] = input[index[i][j]][j]
if dim == 1:
out[i][j] = input[i][index[i][j]]
```
***PaddlePaddle***:根据索引(index)获取输入(x)的指定维度(axis)的条目,并将它们拼接在一起。以2-D Tensor输入为例,其输出结果如下:
```
if axis == 0:
tensor_list = list()
for i in index:
tensor_list.append(index[i, :])
将tensor_list中的tensor沿axis轴拼接
if axis == 1:
tensor_list = list()
for i in index:
tensor_list.append(index[:, i])
将tensor_list中的tensor沿axis轴拼接
```
### 代码示例
``` python
# PyTorch示例:
t = torch.tensor([[1, 2], [3, 4]])
torch.gather(t, 1, torch.tensor([[0, 0], [1, 0]]))
# 输出
# tensor([[ 1, 1],
# [ 4, 3]])
```
``` python
# PaddlePaddle示例:
t = paddle.to_tensor([[1, 2], [3, 4]])
paddle.gather(t, paddle.to_tensor([1, 0]), 1)
# 输出
# Tensor(shape=[2, 2], dtype=int64, place=CPUPlace, stop_gradient=True,
# [[2, 1],
# [4, 3]])
```
## torch.linspace
### [torch.linspace](https://pytorch.org/docs/stable/generated/torch.linspace.html?highlight=linspace#torch.linspace)
```python
torch.linspace(start,
end,
steps,
*,
out=None,
dtype=None,
layout=torch.strided,
device=None,
requires_grad=False)
```
### [paddle.linspace](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/linspace_cn.html#linspace)
```python
paddle.linspace(start,
stop,
num,
dtype=None,
name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| out | - | 表示输出的Tensor,PaddlePaddle无此参数。 |
| layout | - | 表示布局方式,PaddlePaddle无此参数。 |
| device | - | 表示Tensor存放位置,PaddlePaddle无此参数。 |
| requires_grad | - | 表示是否不阻断梯度传导,PaddlePaddle无此参数。 |
## torch.load
### [torch.load](https://pytorch.org/docs/stable/generated/torch.load.html?highlight=load#torch.load)
```python
torch.load(f,
map_location=None,
pickle_module=pickle,
**pickle_load_args)
```
### [paddle.load](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/framework/io/load_cn.html#load)
```python
paddle.load(path, **configs)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| pickle_module | - | 表示用于unpickling元数据和对象的模块,PaddlePaddle无此参数。 |
| map_location | - | 表示加载模型的位置,PaddlePaddle无此参数。 |
### 功能差异
#### 加载类型
***PyTorch***:可从文件或者内存中的读缓冲区(例如`io.BytesIO``io.StringIO`)中加载。
***PaddlePaddle***:只能从文件中加载。
#### 加载内容
***PyTorch***:可以加载`torch.Tensor``torch.nn.Module`、优化器等多个类型的数据。
***PaddlePaddle***:只能加载`paddle.nn.Layer`、优化器这两个类型的数据。
### 代码示例
``` python
# PyTorch示例:
torch.load('tensors.pt', map_location=torch.device('cpu'))
```
``` python
# PaddlePaddle示例:
load_layer_state_dict = paddle.load("emb.pdparams")
```
## torch.multinomial
### [torch.multinomial](https://pytorch.org/docs/stable/generated/torch.multinomial.html?highlight=multinomial#torch.multinomial)
```python
torch.multinomial(input, num_samples, replacement=False, *, generator=None, out=None)
```
### [paddle.multinomial](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/random/multinomial_cn.html#multinomial)
```python
paddle.multinomial(x, num_samples=1, replacement=False, name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| input | x | 表示输入Tensor。 |
| generator | - | 用于采样的伪随机数生成器,PaddlePaddle无此参数。 |
| out | - | 表示输出的Tensor,PaddlePaddle无此参数。 |
***【注意】*** 这类生成器的用法如下:
```python
G = torch.Generator()
G.manual_seed(1)
# 生成指定分布Tensor
torch.randperm(5, generator=G)
```
## torch.narrow
### [torch.narrow](https://pytorch.org/docs/stable/generated/torch.narrow.html?highlight=narrow#torch.narrow)
```python
torch.narrow(input, dim, start, length)
```
### [paddle.slice](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/slice_cn.html#slice)
```python
paddle.slice(input, axes, starts, ends)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| dim | axes | 表示切片的轴。 |
| start | starts | 表示起始位置。 |
### 功能差异
#### 使用方式
***PyTorch***:只能在一个维度上进行切割,`dim``start``length`传入的值均只能为int型;使用该维度输出长度(`length`)来定位结束位置。
***PaddlePaddle***:可以在多个维度进行切割,`axes``starts``ends`传入的值为list/tuple(`starts``ends`传入的值可以为tensor);直接使用结束位置(`end`)来定位结束位置。
### 代码示例
``` python
# PyTorch示例:
x = torch.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
torch.narrow(x, 0, 0, 2)
# 输出
# tensor([[ 1, 2, 3],
# [ 4, 5, 6]])
```
``` python
# PaddlePaddle示例:
x = paddle.to_tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
paddle.slice(x, [0], [0], [2])
# 输出
# Tensor(shape=[2, 3], dtype=int64, place=CPUPlace, stop_gradient=True,
# [[1, 2, 3],
# [4, 5, 6]])
```
## torch.normal
### [torch.normal](https://pytorch.org/docs/stable/generated/torch.normal.html?highlight=normal#torch.normal)
```python
torch.normal(mean, std, *, generator=None, out=None)
```
### [paddle.normal](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/random/normal_cn.html#normal)
```python
paddle.normal(mean=0.0, std=1.0, shape=None, name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| - | shape | 表示输出Tensor的形状。 |
| generator | - | 用于采样的伪随机数生成器,PaddlePaddle无此参数。 |
| out | - | 表示输出的Tensor,PaddlePaddle无此参数。 |
***【注意】*** 这类生成器的用法如下:
```python
G = torch.Generator()
G.manual_seed(1)
# 生成指定分布Tensor
torch.randperm(5, generator=G)
```
### 功能差异
#### 使用方式
***PyTorch***: `mean``std`只能是Tensor,表示输出Tensor中每个元素的正态分布的均值和标准差。
***PaddlePaddle***: `mean``std`既能是Tensor,也能是float,当为float时,则表示输出Tensor中所有元素的正态分布的均值和标准差,同时需要设置`shape`,表示生成的随机Tensor的形状。
## torch.ones
### [torch.ones](https://pytorch.org/docs/stable/generated/torch.ones.html?highlight=ones#torch.ones)
```python
torch.ones(*size,
*,
out=None,
dtype=None,
layout=torch.strided,
device=None,
requires_grad=False)
```
### [paddle.ones](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/creation/ones_cn.html#ones)
```python
paddle.ones(shape,
dtype=None,
name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| size | shape | 表示输出形状大小。 |
| out | - | 表示输出的Tensor,PaddlePaddle无此参数。 |
| layout | - | 表示布局方式,PaddlePaddle无此参数。 |
| device | - | 表示Tensor存放位置,PaddlePaddle无此参数。 |
| requires_grad | - | 表示是否不阻断梯度传导,PaddlePaddle无此参数。 |
### 功能差异
#### 使用方式
***PyTorch***:生成Tensor的形状大小以可变参数的方式传入。
***PaddlePaddle***:生成Tensor的形状大小以list或tuple的方式传入。
### 代码示例
``` python
# PyTorch示例:
torch.ones(2, 3)
# 输出
# tensor([[ 1., 1., 1.],
# [ 1., 1., 1.]])
```
``` python
# PaddlePaddle示例:
paddle.ones([2, 3])
# 输出
# Tensor(shape=[2, 3], dtype=float32, place=CPUPlace, stop_gradient=True,
# [[1., 1., 1.],
# [1., 1., 1.]])
```
## torch.ones_like
### [torch.ones_like](https://pytorch.org/docs/stable/generated/torch.ones_like.html?highlight=ones_like#torch.ones_like)
```python
torch.ones_like(input,
*,
dtype=None,
layout=None,
device=None,
requires_grad=False,
memory_format=torch.preserve_format)
```
### [paddle.ones_like](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/creation/ones_like_cn.html#ones-like)
```python
paddle.ones_like(x, dtype=None, name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| input | x | 表示输入Tensor。 |
| layout | - | 表示布局方式,PaddlePaddle无此参数。 |
| device | - | 表示Tensor存放位置,PaddlePaddle无此参数。 |
| requires_grad | - | 表示是否不阻断梯度传导,PaddlePaddle无此参数。 |
| memory_format | - | 表示内存格式,PaddlePaddle无此参数。 |
### [torch.rand](https://pytorch.org/docs/stable/generated/torch.rand.html?highlight=rand#torch.rand)
```python
torch.rand(*size,
*,
out=None,
dtype=None,
layout=torch.strided,
device=None,
requires_grad=False)
```
### [paddle.rand](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/creation/rand_cn.html#rand)
```python
paddle.rand(shape,
dtype=None,
name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| size | shape | 表示输出形状大小。 |
| out | - | 表示输出的Tensor,PaddlePaddle无此参数。 |
| layout | - | 表示布局方式,PaddlePaddle无此参数。 |
| device | - | 表示Tensor存放位置,PaddlePaddle无此参数。 |
| requires_grad | - | 表示是否不阻断梯度传导,PaddlePaddle无此参数。 |
### 功能差异
#### 使用方式
***PyTorch***:生成Tensor的形状大小以可变参数的方式传入。
***PaddlePaddle***:生成Tensor的形状大小以list或tuple的方式传入。
### 代码示例
``` python
# PyTorch示例:
torch.rand(2, 3)
# 输出
# tensor([[0.0860, 0.2757, 0.3211],
# [0.5872, 0.5267, 0.4184]])
```
``` python
# PaddlePaddle示例:
paddle.rand([2, 3])
# 输出
# Tensor(shape=[2, 3], dtype=float32, place=CPUPlace, stop_gradient=True,
# [[0.18905126, 0.56219709, 0.00808361],
# [0.78120756, 0.32112977, 0.90572405]])
```
## torch.randint
### [torch.randint](https://pytorch.org/docs/stable/generated/torch.randint.html?highlight=randint#torch.randint)
```python
torch.randint(low=0,
high,
size,
*,
generator=None,
out=None,
dtype=None,
layout=torch.strided,
device=None,
requires_grad=False)
```
### [paddle.randint](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/random/randint_cn.html#randint)
```python
paddle.randint(low=0,
high=None,
shape=[1],
dtype=None,
name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| size | shape | 表示输出形状大小。 |
| generator | - | 用于采样的伪随机数生成器,PaddlePaddle无此参数。 |
| out | - | 表示输出的Tensor,PaddlePaddle无此参数。 |
| layout | - | 表示布局方式,PaddlePaddle无此参数。 |
| device | - | 表示Tensor存放位置,PaddlePaddle无此参数。 |
| requires_grad | - | 表示是否不阻断梯度传导,PaddlePaddle无此参数。 |
***【注意】*** 这类生成器的用法如下:
```python
G = torch.Generator()
G.manual_seed(1)
# 生成指定分布Tensor
torch.randperm(5, generator=G)
```
### [torch.randn](https://pytorch.org/docs/stable/generated/torch.randn.html?highlight=randn#torch.randn)
```python
torch.randn(*size,
*,
out=None,
dtype=None,
layout=torch.strided,
device=None,
requires_grad=False)
```
### [paddle.randn](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/creation/randn_cn.html#randn)
```python
paddle.randn(shape,
dtype=None,
name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| size | shape | 表示输出形状大小。 |
| out | - | 表示输出的Tensor,PaddlePaddle无此参数。 |
| layout | - | 表示布局方式,PaddlePaddle无此参数。 |
| device | - | 表示Tensor存放位置,PaddlePaddle无此参数。 |
| requires_grad | - | 表示是否不阻断梯度传导,PaddlePaddle无此参数。 |
### 功能差异
#### 使用方式
***PyTorch***:生成Tensor的形状大小以可变参数的方式传入。
***PaddlePaddle***:生成Tensor的形状大小以list或tuple的方式传入。
### 代码示例
``` python
# PyTorch示例:
torch.randn(2, 3)
# 输出
# tensor([[ 1.3290, 1.4679, -1.2373],
# [-0.2354, -0.9818, 0.0877]])
```
``` python
# PaddlePaddle示例:
paddle.randn([2, 3])
# 输出
# Tensor(shape=[2, 3], dtype=float32, place=CPUPlace, stop_gradient=True,
# [[-1.74181163, -0.50677234, -0.14707172],
# [ 1.18375409, 1.52477348, -0.73248941]])
```
## torch.randperm
### [torch.randperm](https://pytorch.org/docs/stable/generated/torch.randperm.html?highlight=randperm#torch.randperm)
```python
torch.randperm(n,
*,
generator=None,
out=None,
dtype=torch.int64,
layout=torch.strided,
device=None,
requires_grad=False,
pin_memory=False)
```
### [paddle.randperm](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/random/randperm_cn.html#randperm)
```python
paddle.randperm(n, dtype='int64', name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| generator | - | 用于采样的伪随机数生成器,PaddlePaddle无此参数。 |
| out | - | 表示输出的Tensor,PaddlePaddle无此参数。 |
| layout | - | 表示布局方式,PaddlePaddle无此参数。 |
| device | - | 表示Tensor存放位置,PaddlePaddle无此参数。 |
| requires_grad | - | 表示是否不阻断梯度传导,PaddlePaddle无此参数。 |
| pin_memeory | - | 表示是否使用锁页内存,PaddlePaddle无此参数。 |
***【注意】*** 这类生成器的用法如下:
```python
G = torch.Generator()
G.manual_seed(1)
# 生成指定分布Tensor
torch.randperm(5, generator=G)
```
## torch.range
### [torch.range](https://pytorch.org/docs/stable/generated/torch.arange.html?highlight=arange#torch.range)
```python
torch.range(start=0,
end,
step=1,
*,
out=None,
dtype=None,
layout=torch.strided,
device=None,
requires_grad=False)
```
### [paddle.arange](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/creation/arange_cn.html#arange)
```python
paddle.arange(start=0,
end=None,
step=1,
dtype=None,
name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| out | - | 表示输出的Tensor,PaddlePaddle无此参数。 |
| layout | - | 表示布局方式,PaddlePaddle无此参数。 |
| device | - | 表示Tensor存放位置,PaddlePaddle无此参数。 |
| requires_grad | - | 表示是否不阻断梯度传导,PaddlePaddle无此参数。 |
## torch.save
### [torch.save](https://pytorch.org/docs/stable/generated/torch.save.html?highlight=save#torch.save)
```python
torch.save(obj,
f,
pickle_module=pickle,
pickle_protocol=2)
```
### [paddle.save](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/framework/io/save_cn.html#save)
```python
paddle.save(obj, path, pickle_protocol=2)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| f | path | 表示存储的路径。 |
| pickle_module | - | 表示用于pickling元数据和对象的模块,PaddlePaddle无此参数。 |
### 功能差异
#### 存储类型
***PyTorch***:可存储到文件或者内存中的写缓冲区(例如`io.BytesIO``io.StringIO`)。
***PaddlePaddle***:只能存储到文件中。
#### 存储内容
***PyTorch***:可以存储`torch.Tensor``torch.nn.Module`、优化器等多个类型的数据。
***PaddlePaddle***:只能存储`paddle.nn.Layer`、优化器这两个类型的数据。
### 代码示例
``` python
# PyTorch示例:
x = torch.tensor([0, 1, 2, 3, 4])
buffer = io.BytesIO()
torch.save(x, buffer)
```
``` python
# PaddlePaddle示例:
x = paddle.to_tensor([0, 1, 2, 3, 4])
padle.save(x, "tensor.pdiparams")
# 报错:
# NotImplementedError: Now only supports save state_dict of Layer or Optimizer, expect dict, but received <class 'paddle.VarBase'>.
emb = paddle.nn.Embedding(10, 10)
layer_state_dict = emb.state_dict()
paddle.save(layer_state_dict, "emb.pdparams")
# 正常保存
```
## torch.tensor
### [torch.tensor](https://pytorch.org/docs/stable/generated/torch.tensor.html?highlight=tensor#torch.tensor)
```python
torch.tensor(data,
dtype=None,
device=None,
requires_grad=False,
pin_memory=False)
```
### [paddle.to_tensor](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/creation/to_tensor_cn.html#to-tensor)
```python
paddle.to_tensor(data,
dtype=None,
place=None,
stop_gradient=True)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| device | place | 表示Tensor存放位置。 |
| requires_grad | stop_gradient | PyTorch表示是否不阻断梯度传导,PaddlePaddle表示是否阻断梯度传导。 |
| pin_memeory | - | 表示是否使用锁页内存,PaddlePaddle无此参数。 |
## torch.transpose
### [torch.transpose](https://pytorch.org/docs/stable/generated/torch.transpose.html?highlight=transpose#torch.transpose)
```python
torch.transpose(input, dim0, dim1)
```
### [paddle.transpose](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/transpose_cn.html#transpose)
```python
paddle.transpose(x, perm, name=None)
```
### 功能差异
#### 使用方式
***PyTorch***:需要设置2个维度值(`dim0``dim1`)表示需要交换的维度。
***PaddlePaddle***:需要设置一个重排顺序(`perm`),类型为list或者tuple。
### 代码示例
``` python
# PyTorch示例:
x = torch.ones((10,20,30))
out = torch.transpose(x, 0, 2)
out.shape
# 输出
# torch.Size([30, 20, 10])
```
``` python
# PaddlePaddle示例:
x = paddle.ones((10,20,30))
out = paddle.transpose(x, (2, 1, 0))
out.shape
# 输出
# [30, 20, 10]
```
## torch.zeros
### [torch.zeros](https://pytorch.org/docs/stable/generated/torch.zeros.html?highlight=zeros#torch.zeros)
```python
torch.zeros(*size,
*,
out=None,
dtype=None,
layout=torch.strided,
device=None,
requires_grad=False)
```
### [paddle.zeros](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/creation/zeros_cn.html#zeros)
```python
paddle.zeros(shape,
dtype=None,
name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| size | shape | 表示输出形状大小。 |
| out | - | 表示输出的Tensor,PaddlePaddle无此参数。 |
| layout | - | 表示布局方式,PaddlePaddle无此参数。 |
| device | - | 表示Tensor存放位置,PaddlePaddle无此参数。 |
| requires_grad | - | 表示是否不阻断梯度传导,PaddlePaddle无此参数。 |
### 功能差异
#### 使用方式
***PyTorch***:生成Tensor的形状大小以可变参数的方式传入。
***PaddlePaddle***:生成Tensor的形状大小以list的方式传入。
### 代码示例
``` python
# PyTorch示例:
torch.zeros(2, 3)
# 输出
# tensor([[ 0., 0., 0.],
# [ 0., 0., 0.]])
```
``` python
# PaddlePaddle示例:
paddle.zeros([2, 3])
# 输出
# Tensor(shape=[2, 3], dtype=float32, place=CPUPlace, stop_gradient=True,
# [[0., 0., 0.],
# [0., 0., 0.]])
```
## torch.zeros_like
### [torch.zeros_like](https://pytorch.org/docs/stable/generated/torch.zeros_like.html?highlight=zeros_like#torch.zeros_like)
```python
torch.zeros_like(input,
*,
dtype=None,
layout=None,
device=None,
requires_grad=False,
memory_format=torch.preserve_format)
```
### [paddle.zeros_like](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/tensor/creation/zeros_like_cn.html#zeros-like)
```python
paddle.zeros_like(x, dtype=None, name=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| input | x | 表示输入Tensor。 |
| layout | - | 表示布局方式,PaddlePaddle无此参数。 |
| device | - | 表示Tensor存放位置,PaddlePaddle无此参数。 |
| requires_grad | - | 表示是否不阻断梯度传导,PaddlePaddle无此参数。 |
| memory_format | - | 表示内存格式,PaddlePaddle无此参数。 |
## 工具类
| 序号 | PyTorch API | PaddlePaddle API | 备注 |
| ---- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
| 1 | [torch.nn.DataParallel](https://pytorch.org/docs/stable/generated/torch.nn.DataParallel.html?highlight=dataparallel#torch.nn.DataParallel) | [paddle.DataParallel](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/dygraph/parallel/DataParallel_cn.html#dataparallel) | [差异对比](torch.nn.DataParallel.md) |
| 2 | [torch.nn.parameter.Parameter](https://pytorch.org/docs/stable/generated/torch.nn.parameter.Parameter.html?highlight=torch%20nn%20parameter#torch.nn.parameter.Parameter) | [paddle.create_parameter](https://github.com/PaddlePaddle/Paddle/blob/ce2bdb0afdc2a09a127e8d9aa394c8b00a877364/python/paddle/fluid/layers/tensor.py#L77) | [差异对比](torch.nn.parameter.Parameter.md) |
| 3 | [torch.nn.utils.clip_grad_value_](https://pytorch.org/docs/stable/generated/torch.nn.utils.clip_grad_value_.html?highlight=clip_grad_value_#torch.nn.utils.clip_grad_value_) | 无对应实现 | [组合实现](torch.nn.utils.clip_grad_value_.md) |
| 4 | [torch.utils.data.DataLoader](https://pytorch.org/docs/stable/data.html?highlight=dataloader#torch.utils.data.DataLoader) | [paddle.io.DataLoader](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/reader/DataLoader_cn.html#dataloader) | [差异对比](torch.utils.data.DataLoader.md) |
| 5 | [torch.utils.data.random_split](https://pytorch.org/docs/stable/data.html?highlight=random_split#torch.utils.data.random_split) | 无对应实现 | [组合实现](torch.utils.data.random_split.md) |
| 6 | [torch.utils.data.distributed.DistributedSampler](https://pytorch.org/docs/stable/data.html?highlight=distributedsampler#torch.utils.data.distributed.DistributedSampler) | 无对应实现 | [组合实现](torch.utils.data.distributed.DistributedSampler.md) |
| 7 | [torch.utils.data.Dataset](https://pytorch.org/docs/stable/data.html?highlight=torch%20utils%20data%20dataset#torch.utils.data.Dataset) | [paddle.io.Dataset](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/dataloader/dataset/Dataset_cn.html#dataset) | 功能一致 |
| 8 | [torch.utils.data.BatchSampler](https://pytorch.org/docs/stable/data.html?highlight=batchsampler#torch.utils.data.BatchSampler) | [paddle.io.BatchSampler](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/dataloader/batch_sampler/BatchSampler_cn.html#batchsampler) | [差异对比](torch.utils.data.BatchSampler.md) |
| 9 | [torch.utils.data.Sampler](https://pytorch.org/docs/stable/data.html?highlight=sampler#torch.utils.data.Sampler) | [paddle.io.Sampler](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/dataloader/sampler/Sampler_cn.html#sampler) | 功能一致 |
***持续更新...***
## torch.nn.DataParallel
### [torch.nn.DataParallel](https://pytorch.org/docs/stable/generated/torch.nn.DataParallel.html?highlight=dataparallel#torch.nn.DataParallel)
```python
torch.nn.DataParallel(module, device_ids=None, output_device=None, dim=0)
```
### [paddle.DataParallel](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/dygraph/parallel/DataParallel_cn.html#dataparallel)
```python
paddle.DataParallel(layers, strategy=None, comm_buffer_size=25, last_comm_buffer_size=1)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| module | layers | 需要通过数据并行方式执行的模型。 |
| device_ids | - | 表示训练在哪几块GPU上,PaddlePaddle无此参数。 |
| output_device | - | 表示结果输出在哪一块GPU上,PaddlePaddle无此参数。 |
| dim | - | 表示哪一维度上的数据进行划分,PaddlePaddle无此参数。 |
| - | strategy | PaddlePaddle即将废弃参数。 |
| - | comm_buffer_size | 它是通信调用(如NCCLAllReduce)时,参数梯度聚合为一组的内存大小(MB),PyTorch无此参数。 |
| - | last_comm_buffer_size | 它限制通信调用中最后一个缓冲区的内存大小(MB),PyTorch无此参数。 |
### 功能差异
#### 使用差异
***PyTorch***:在API中即可通过设置参数使用的GPU id。
***PaddlePaddle***:只能在启动代码时设置GPU id,设置方式如下:
> python -m paddle.distributed.launch –selected_gpus=0,1 demo.py
> 其中 demo.py 脚本的代码可以是下面的示例代码。
## torch.nn.parameter.Parameter
### [torch.nn.parameter.Parameter](https://pytorch.org/docs/stable/generated/torch.nn.parameter.Parameter.html?highlight=torch%20nn%20parameter#torch.nn.parameter.Parameter)
```python
torch.nn.parameter.Parameter(data, requires_grad=True)
```
## [paddle.create_parameter](https://github.com/PaddlePaddle/Paddle/blob/ce2bdb0afdc2a09a127e8d9aa394c8b00a877364/python/paddle/fluid/layers/tensor.py#L77)
```python
paddle.create_parameter(shape,
dtype,
name=None,
attr=None,
is_bias=False,
default_initializer=None)
```
### 功能差异
#### 使用方式
***PyTorch***:通过设置`data`将Tensor赋给Parameter。
***PaddlePaddle***:有2种方式创建Parameter。方式一:通过设置`attr`将ParamAttr赋给Parameter;方式二:通过设置`shape`(大小)、`dtype`(类型)、`default_initializer`(初始化方式)设置Parameter。
#### 梯度设置
***PyTorch***:通过设置`requires_grad`确定是否进行梯度反传。
***PaddlePaddle***:PaddlePaddle无此功能。
### 代码示例
``` python
# PyTorch示例:
import torch
x = torch.zeros(2, 3)
param = torch.nn.parameter.Parameter(x, requires_grad=False)
# 输出
# Parameter containing:
# tensor([[0., 0., 0.],
# [0., 0., 0.]])
```
``` python
# PaddlePaddle示例:
import paddle
x = paddle.zeros([2, 3], dtype="float32")
param = paddle.create_parameter(shape=x.shape,
dtype=str(x.numpy().dtype),
default_initializer=paddle.nn.initializer.Assign(x))
param.stop_gradient = True
# 输出
# Parameter containing:
# Tensor(shape=[2, 3], dtype=float32, place=CPUPlace, stop_gradient=True,
# [[0., 0., 0.],
# [0., 0., 0.]])
```
## torch.nn.utils.clip_grad_value_
### [torch.nn.utils.clip_grad_value_](https://pytorch.org/docs/stable/generated/torch.nn.utils.clip_grad_value_.html?highlight=clip_grad_value_#torch.nn.utils.clip_grad_value_)
```python
torch.nn.utils.clip_grad_value_(parameters, clip_value)
```
### 功能介绍
用于梯度裁剪,PaddlePaddle目前无对应API,可使用如下代码组合实现该API。
```python
def clip_grad_value_(parameters, clip_value):
if isinstance(parameters, paddle.Tensor):
parameters = [parameters]
clip_value = float(clip_value)
for p in filter(lambda p: p.grad is not None, parameters):
paddle.clip(p.grad, min=-clip_value, max=clip_value)
```
## torch.utils.data.BatchSampler
### [torch.utils.data.BatchSampler](https://pytorch.org/docs/stable/data.html?highlight=batchsampler#torch.utils.data.BatchSampler)
```python
torch.utils.data.BatchSampler(sampler, batch_size, drop_last)
```
### [paddle.io.BatchSampler](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/dataloader/batch_sampler/BatchSampler_cn.html#batchsampler)
```python
paddle.io.BatchSampler(dataset=None, sampler=None, shuffle=Fasle, batch_size=1, drop_last=False)
```
### 功能差异
#### 使用方式
***PyTorch***:只能使用`sampler`来构建BatchSampler。
***PaddlePaddle***:能使用`sampler``dataset`来构建BatchSampler。
## torch.utils.data.DataLoader
### [torch.utils.data.DataLoader](https://pytorch.org/docs/stable/data.html?highlight=dataloader#torch.utils.data.DataLoader)
```python
torch.utils.data.DataLoader(dataset,
batch_size=1,
shuffle=False,
sampler=None,
batch_sampler=None,
num_workers=0,
collate_fn=None,
pin_memory=False,
drop_last=False,
timeout=0,
worker_init_fn=None,
multiprocessing_context=None,
generator=None,
prefetch_factor=2,
persistent_workers=False)
```
### [paddle.io.DataLoader](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/reader/DataLoader_cn.html#dataloader)
```python
paddle.io.DataLoader(dataset,
feed_list=None,
places=None,
return_list=False,
batch_sampler=None,
batch_size=1,
shuffle=False,
drop_last=False,
collate_fn=None,
num_workers=0,
use_buffer_reader=True,
use_shared_memory=False,
timeout=0,
worker_init_fn=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| sampler | - | 表示数据集采集器,PaddlePaddle无此参数。 |
| prefetch_factor | - | 表示每个worker预先加载的数据数量,PaddlePaddle无此参数。 |
| persistent_workers | - | 表示数据集使用一次后,数据加载器将会不会关闭工作进程,PaddlePaddle无此参数。 |
| generator | - | 用于采样的伪随机数生成器,PaddlePaddle无此参数。 |
| pin_memory | - | 表示数据最开始是属于锁页内存,PaddlePaddle无此参数。 |
| - | feed_list | 表示feed变量列表,PyTorch无此参数。 |
| - | use_buffer_reader | 表示是否使用缓存读取器,PyTorch无此参数。 |
| - | use_shared_memory | 表示是否使用共享内存来提升子进程将数据放入进程间队列的速度,PyTorch无此参数。 |
### 功能差异
#### 自定义数据采集器
***PyTorch***:可通过设置`sampler`自定义数据采集器。
***PaddlePaddle***:PaddlePaddle无此功能,可使用如下代码自定义一个DataLoader实现该功能。
```python
class DataLoader(paddle.io.DataLoader):
def __init__(self,
dataset,
batch_size=1,
shuffle=False,
sampler=None,
batch_sampler=None,
num_workers=0,
collate_fn=None,
pin_memory=False,
drop_last=False,
timeout=0,
worker_init_fn=None,
multiprocessing_context=None,
generator=None):
if isinstance(dataset[0], (tuple, list)):
return_list = True
else:
return_list = False
return_list = True
super().__init__(
dataset,
feed_list=None,
places=None,
return_list=return_list,
batch_sampler=batch_sampler,
batch_size=batch_size,
shuffle=shuffle,
drop_last=drop_last,
collate_fn=collate_fn,
num_workers=num_workers,
use_buffer_reader=True,
use_shared_memory=False,
timeout=timeout,
worker_init_fn=worker_init_fn)
if sampler is not None:
seld.batch_sampler.sampler = sampler
```
## torch.utils.data.distributed.DistributedSampler
### [torch.utils.data.distributed.DistributedSampler](https://pytorch.org/docs/stable/data.html?highlight=distributedsampler#torch.utils.data.distributed.DistributedSampler)
```python
torch.utils.data.distributed.DistributedSampler(dataset,
num_replicas=None,
rank=None,
shuffle=True,
seed=0,
drop_last=False)
```
### 功能介绍
用于实现分布式数据采集器,PaddlePaddle目前无对应API,可使用如下代码组合实现该API。
```python
import paddle
class DistributedSampler(paddle.io.DistributedBatchSampler):
def __init__(self,
dataset,
num_replicas=None,
rank=None,
shuffle=True,
seed=0,
drop_last=False):
super().__init__(
dataset=dataset,
batch_size=1,
num_replicas=num_replicas,
rank=rank,
shuffle=shuffle,
drop_last=drop_last)
```
## torch.utils.data.random_split
### [torch.utils.data.random_split](https://pytorch.org/docs/stable/data.html?highlight=random_split#torch.utils.data.random_split)
```python
torch.utils.data.random_split(dataset, lengths, generator=<torch._C.Generator object>)
```
### 功能介绍
用于实现数据集划分,PaddlePaddle目前无对应API,可使用如下代码组合实现该API。
```python
import paddle
from paddle.io import Dataset
def _accumulate(iterable, fn=lambda x, y: x + y):
it = iter(iterable)
try:
total = next(it)
except StopIteration:
return
yield total
for element in it:
total = fn(total, element)
yield total
class Subset(Dataset):
def __init__(self, dataset, indices):
self.dataset = dataset
self.indices = indices
def __getitem__(self, idx):
return self.dataset[self.indices[idx]]
def __len__(self):
return len(self.indices)
def random_split(dataset, lengths, generator=None):
if sum(lengths) != len(dataset):
raise ValueError(
"Sum of input lengths does not equal the length of the input dataset!"
)
indices = paddle.randperm(sum(lengths))
return [
Subset(dataset, indices[offset - length: offset])
for offset, length in zip(_accumulate(lengths), lengths)
]
```
## 视觉类
| 序号 | PyTorch API | PaddlePaddle API | 备注 |
| ---- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------- |
| 1 | [torchvision.transforms.Compose](https://pytorch.org/vision/stable/transforms.html?highlight=compose#torchvision.transforms.Compose) | [paddle.vision.transforms.Compose](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/vision/transforms/transforms/Compose_cn.html#compose) | 功能一致 |
| 2 | [torchvision.transforms.ToPILImage](https://pytorch.org/vision/stable/transforms.html?highlight=topilimage#torchvision.transforms.ToPILImage) | 无对应实现 | [组合实现](torchvision.transforms.ToPILImage.md) |
| 3 | [torchvision.transforms.Resize](https://pytorch.org/vision/stable/transforms.html?highlight=resize#torchvision.transforms.Resize) | [paddle.vision.transforms.Resize](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/vision/transforms/transforms/Resize_cn.html#resize) | 功能一致 |
| 4 | [torchvision.transforms.ToTensor](https://pytorch.org/vision/stable/transforms.html?highlight=totensor#torchvision.transforms.ToTensor) | [paddle.vision.transforms.ToTensor](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/vision/transforms/transforms/ToTensor_cn.html#totensor) | 功能一致 |
| 5 | [torchvision.transforms.RandomHorizontalFlip](https://pytorch.org/vision/stable/transforms.html?highlight=randomhorizontalflip#torchvision.transforms.RandomHorizontalFlip) | [paddle.vision.transforms.RandomHorizontalFlip](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/vision/transforms/transforms/RandomHorizontalFlip_cn.html#randomhorizontalflip) | 功能一致 |
| 6 | [torchvision.transforms.CenterCrop](https://pytorch.org/vision/stable/transforms.html?highlight=centercrop#torchvision.transforms.CenterCrop) | [paddle.vision.transforms.CenterCrop](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/vision/transforms/transforms/CenterCrop_cn.html#centercrop) | 功能一致 |
| 7 | [torchvision.transforms.ColorJitter](https://pytorch.org/vision/stable/transforms.html?highlight=colorjitter#torchvision.transforms.ColorJitter) | [paddle.vision.transforms.ColorJitter](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/vision/transforms/transforms/ColorJitter_cn.html#colorjitter) | 功能一致 |
| 8 | [torchvision.transforms.Grayscale](https://pytorch.org/vision/stable/transforms.html?highlight=grayscale#torchvision.transforms.Grayscale) | [paddle.vision.transforms.Grayscale](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/vision/transforms/transforms/Grayscale_cn.html#grayscale) | 功能一致 |
| 9 | [torchvision.transforms.Normalize](https://pytorch.org/vision/stable/transforms.html?highlight=normalize#torchvision.transforms.Normalize) | [paddle.vision.transforms.Normalize](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/vision/transforms/transforms/Normalize_cn.html#normalize) | [差异对比](torchvision.transforms.Normalize.md) |
| 10 | [torchvision.transforms.RandomResizedCrop](https://pytorch.org/vision/stable/transforms.html?highlight=randomresizedcrop#torchvision.transforms.RandomResizedCrop) | [paddle.vision.transforms.RandomResizedCrop](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/vision/transforms/transforms/RandomResizedCrop_cn.html#randomresizedcrop) | 功能一致 |
| 11 | [torchvision.transforms.Pad](https://pytorch.org/vision/stable/transforms.html?highlight=pad#torchvision.transforms.Pad) | [paddle.vision.transforms.Pad](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/vision/transforms/transforms/Pad_cn.html#pad) | 功能一致 |
| 12 | [torchvision.transforms.RandomCrop](https://pytorch.org/vision/stable/transforms.html?highlight=randomcrop#torchvision.transforms.RandomCrop) | [paddle.vision.transforms.RandomCrop](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/vision/transforms/transforms/RandomCrop_cn.html#randomcrop) | 功能一致 |
| 13 | [torchvision.transforms.RandomRotation](https://pytorch.org/vision/stable/transforms.html?highlight=randomrotation#torchvision.transforms.RandomRotation) | [paddle.vision.transforms.RandomRotation](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/vision/transforms/transforms/RandomRotation_cn.html#daimashili) | 功能一致 |
| 14 | [torchvision.transforms.RandomVerticalFlip](https://pytorch.org/vision/stable/transforms.html?highlight=randomverticalflip#torchvision.transforms.RandomVerticalFlip) | [paddle.vision.transforms.RandomVerticalFlip](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/vision/transforms/transforms/RandomVerticalFlip_cn.html#randomverticalflip) | 功能一致 |
| 15 | [torchvision.transforms.Lambda](https://pytorch.org/vision/stable/transforms.html?highlight=lambda#torchvision.transforms.Lambda) | 无对应实现 | [组合实现](torchvision.transforms.Lambda.md) |
| 17 | [torchvision.utils.save_image](https://pytorch.org/vision/stable/utils.html?highlight=save_image#torchvision.utils.save_image) | 无对应实现 | [组合实现](torchvision.utils.save_image.md) |
| 18 | [torchvision.models 系列模型](https://pytorch.org/vision/stable/models.html?highlight=torchvision%20models) | X2Paddle提供 | [使用方式](torchvision.models.md) |
***持续更新...***
## [torchvision.models](https://pytorch.org/vision/stable/models.html?highlight=torchvision%20models)
目前PaddlePaddle官方提供的模型参数与PyTorch不一致,为此X2Paddle提供了一套与torchvision模型参数一致且使用方式一致的模型库,以resnet18为例,具体使用方式如下:
```python
from x2paddle import models
# 构造权重随机初始化的模型:
resnet18 = models.resnet18_pth()
x = paddle.rand([1, 3, 224, 224])
out = model(x)
# 构造预训练模型:
resnet18 = models.resnet18_pth(pretrained=True)
x = paddle.rand([1, 3, 224, 224])
out = model(x)
```
目前支持的模型为:
| PyTorch模型 | Paddle模型 |
| ------------------------------------------------------------ | -------------------------------- |
| [torchvision.models.resnet18](https://pytorch.org/vision/stable/models.html#torchvision.models.resnet18) | x2paddle.models.resnet18_pth |
| [torchvision.models.resnet34](https://pytorch.org/vision/stable/models.html#torchvision.models.resnet34) | x2paddle.models.resnet34_pth |
| [torchvision.models.resnet50](https://pytorch.org/vision/stable/models.html#torchvision.models.resnet50) | x2paddle.models.resnet50_pth |
| [torchvision.models.resnet101](https://pytorch.org/vision/stable/models.html#torchvision.models.resnet101) | x2paddle.models.resnet101_pth |
| [torchvision.models.resnet152](https://pytorch.org/vision/stable/models.html#torchvision.models.resnet152) | x2paddle.models.resnet152_pth |
| [torchvision.models.resnext50_32x4d](https://pytorch.org/vision/stable/models.html#torchvision.models.resnext50_32x4d) | x2paddle.models.resnext50_32x4d_pth |
| [torchvision.models.resnext101_32x8d](https://pytorch.org/vision/stable/models.html#torchvision.models.resnext101_32x8d) | x2paddle.resnext101_32x8d_pth |
| [torchvision.models.wide_resnet50_2](https://pytorch.org/vision/stable/models.html#torchvision.models.wide_resnet50_2) | x2paddle.models.wide_resnet50_2_pth |
| [torchvision.models.wide_resnet101_2](https://pytorch.org/vision/stable/models.html#torchvision.models.wide_resnet101_2) | x2paddle.models.wide_resnet101_2_pth |
| [torchvision.models.vgg11](https://pytorch.org/vision/stable/models.html#torchvision.models.vgg11) | x2paddle.models.vgg11_pth |
| [torchvision.models.vgg11_bn](https://pytorch.org/vision/stable/models.html#torchvision.models.vgg11_bn) | x2paddle.models.vgg11_bn_pth |
| [torchvision.models.vgg13](https://pytorch.org/vision/stable/models.html#torchvision.models.vgg13) | x2paddle.models.vgg13_pth |
| [torchvision.models.vgg13_bn](https://pytorch.org/vision/stable/models.html#torchvision.models.vgg13_bn) | x2paddle.models.vgg13_bn_pth |
| [torchvision.models.vgg16](https://pytorch.org/vision/stable/models.html#torchvision.models.vgg16) | x2paddle.models.vgg16_pth |
| [torchvision.models.vgg16_bn](https://pytorch.org/vision/stable/models.html#torchvision.models.vgg16_bn) | x2paddle.models.vgg16_bn_pth |
| [torchvision.models.vgg19](https://pytorch.org/vision/stable/models.html#torchvision.models.vgg19) | x2paddle.models.vgg19_pth |
| [torchvision.models.vgg19_bn](https://pytorch.org/vision/stable/models.html#torchvision.models.vgg19_bn) | x2paddle.models.vgg19_bn_pth |
## torchvision.transforms.Lambda
### [torchvision.transforms.Lambda](https://pytorch.org/vision/stable/transforms.html?highlight=lambda#torchvision.transforms.Lambda)
```python
torchvision.transforms.Lambda(lambd)
```
### 功能介绍
用于使用lamda定义的函数对数据进行预处理,PaddlePaddle目前无对应API,可使用如下代码组合实现该API。
```python
import paddle
from paddle.vision.transforms import BaseTransform
class Lambda(BaseTransform):
def __init__(self, lambd):
if not callable(lambd):
raise TypeError("Argument lambd should be callable, got {}".format(repr(type(lambd).__name__)))
self.lambd = lambd
def _apply_image(self, img):
return self.lambd(img)
```
## torchvision.transforms.Normalize
### [torchvision.transforms.Normalize](https://pytorch.org/vision/stable/transforms.html?highlight=normalize#torchvision.transforms.Normalize)
```python
torchvision.transforms.Normalize(mean, std, inplace=False)
```
### [paddle.vision.transforms.Normalize](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/vision/transforms/transforms/Normalize_cn.html#normalize)
```python
paddle.vision.transforms.Normalize(mean=0.0, std=1.0, data_format='CHW', to_rgb=False, keys=None)
```
### 参数差异
| PyTorch | PaddlePaddle | 备注 |
| ------------- | ------------ | ------------------------------------------------------ |
| inplace | - | 表示表示在不更改变量的内存地址的情况下,直接修改变量,PaddlePaddle无此参数。 |
| - | data_format | 表示数据的格式,PyTorch无此参数。 |
| - | to_rgb | 表示是否是否转换为rgb的格式,PyTorch无此参数。 |
### 功能差异
#### 使用方式
***PyTorch***:只支持`CHW`的输入数据,同时不支持转换为`rgb`
***PaddlePaddle***:支持`CHW``HWC`的输入数据,同时支持转换为`rgb`
## torchvision.transforms.ToPILImage
### [torchvision.transforms.ToPILImage](https://pytorch.org/vision/stable/transforms.html?highlight=topilimage#torchvision.transforms.ToPILImage)
```python
torchvision.transforms.ToPILImage(mode=None)
```
### 功能介绍
用于根据`mode`返回PIL类型的图像,PaddlePaddle目前无对应API,可使用如下代码组合实现该API。
```python
import paddle
import PIL
import numbers
import numpy as np
from PIL import Image
from paddle.vision.transforms import BaseTransform
from paddle.vision.transforms import functional as F
class ToPILImage(BaseTransform):
def __init__(self, mode=None, keys=None):
super(ToTensor, self).__init__(keys)
self.data_format = data_format
def _apply_image(self, pic):
"""
Args:
pic (Tensor|np.ndarray): Image to be converted to PIL Image.
Returns:
PIL: Converted image.
"""
if not (isinstance(pic, paddle.Tensor) or isinstance(pic, np.ndarray)):
raise TypeError('pic should be Tensor or ndarray. Got {}.'.format(
type(pic)))
elif isinstance(pic, paddle.Tensor):
if pic.ndimension() not in {2, 3}:
raise ValueError(
'pic should be 2/3 dimensional. Got {} dimensions.'.format(
pic.ndimension()))
elif pic.ndimension() == 2:
# if 2D image, add channel dimension (CHW)
pic = pic.unsqueeze(0)
elif isinstance(pic, np.ndarray):
if pic.ndim not in {2, 3}:
raise ValueError(
'pic should be 2/3 dimensional. Got {} dimensions.'.format(
pic.ndim))
elif pic.ndim == 2:
# if 2D image, add channel dimension (HWC)
pic = np.expand_dims(pic, 2)
npimg = pic
if isinstance(pic, paddle.Tensor) and "float" in str(pic.numpy(
).dtype) and mode != 'F':
pic = pic.mul(255).byte()
if isinstance(pic, paddle.Tensor):
npimg = np.transpose(pic.numpy(), (1, 2, 0))
if not isinstance(npimg, np.ndarray):
raise TypeError(
'Input pic must be a paddle.Tensor or NumPy ndarray, ' +
'not {}'.format(type(npimg)))
if npimg.shape[2] == 1:
expected_mode = None
npimg = npimg[:, :, 0]
if npimg.dtype == np.uint8:
expected_mode = 'L'
elif npimg.dtype == np.int16:
expected_mode = 'I;16'
elif npimg.dtype == np.int32:
expected_mode = 'I'
elif npimg.dtype == np.float32:
expected_mode = 'F'
if mode is not None and mode != expected_mode:
raise ValueError(
"Incorrect mode ({}) supplied for input type {}. Should be {}"
.format(mode, np.dtype, expected_mode))
mode = expected_mode
elif npimg.shape[2] == 2:
permitted_2_channel_modes = ['LA']
if mode is not None and mode not in permitted_2_channel_modes:
raise ValueError("Only modes {} are supported for 2D inputs".
format(permitted_2_channel_modes))
if mode is None and npimg.dtype == np.uint8:
mode = 'LA'
elif npimg.shape[2] == 4:
permitted_4_channel_modes = ['RGBA', 'CMYK', 'RGBX']
if mode is not None and mode not in permitted_4_channel_modes:
raise ValueError("Only modes {} are supported for 4D inputs".
format(permitted_4_channel_modes))
if mode is None and npimg.dtype == np.uint8:
mode = 'RGBA'
else:
permitted_3_channel_modes = ['RGB', 'YCbCr', 'HSV']
if mode is not None and mode not in permitted_3_channel_modes:
raise ValueError("Only modes {} are supported for 3D inputs".
format(permitted_3_channel_modes))
if mode is None and npimg.dtype == np.uint8:
mode = 'RGB'
if mode is None:
raise TypeError('Input type {} is not supported'.format(
npimg.dtype))
return Image.fromarray(npimg, mode=mode)
```
## torchvision.utils.save_image
### [torchvision.utils.save_image](https://pytorch.org/vision/stable/utils.html?highlight=save_image#torchvision.utils.save_image)
```python
torchvision.utils.save_image(tensor: Union[torch.Tensor, List[torch.Tensor]],
fp: Union[str, pathlib.Path, BinaryIO],
format: Union[str, NoneType] = None,
**kwargs)
```
### 功能介绍
用于将Tensor保存至图像中,PaddlePaddle目前无对应API,可使用如下代码组合实现该API。
```python
import pathlib
import paddle
import warnings
import math
import numpy as np
from PIL import Image
from typing import Union, Optional, List, Tuple, Text, BinaryIO
@paddle.no_grad()
def make_grid(tensor: Union[paddle.Tensor, List[paddle.Tensor]],
nrow: int=8,
padding: int=2,
normalize: bool=False,
value_range: Optional[Tuple[int, int]]=None,
scale_each: bool=False,
pad_value: int=0,
**kwargs) -> paddle.Tensor:
if not (isinstance(tensor, paddle.Tensor) or
(isinstance(tensor, list) and all(
isinstance(t, paddle.Tensor) for t in tensor))):
raise TypeError(
f'tensor or list of tensors expected, got {type(tensor)}')
if "range" in kwargs.keys():
warning = "range will be deprecated, please use value_range instead."
warnings.warn(warning)
value_range = kwargs["range"]
# if list of tensors, convert to a 4D mini-batch Tensor
if isinstance(tensor, list):
tensor = paddle.stack(tensor, axis=0)
if tensor.dim() == 2: # single image H x W
tensor = tensor.unsqueeze(0)
if tensor.dim() == 3: # single image
if tensor.size(0) == 1: # if single-channel, convert to 3-channel
tensor = paddle.concat((tensor, tensor, tensor), 0)
tensor = tensor.unsqueeze(0)
if tensor.dim() == 4 and tensor.size(1) == 1: # single-channel images
tensor = paddle.concat((tensor, tensor, tensor), 1)
if normalize is True:
if value_range is not None:
assert isinstance(value_range, tuple), \
"value_range has to be a tuple (min, max) if specified. min and max are numbers"
def norm_ip(img, low, high):
img.clip(min=low, max=high)
img = img - low
img = img / max(high - low, 1e-5)
def norm_range(t, value_range):
if value_range is not None:
norm_ip(t, value_range[0], value_range[1])
else:
norm_ip(t, float(t.min()), float(t.max()))
if scale_each is True:
for t in tensor: # loop over mini-batch dimension
norm_range(t, value_range)
else:
norm_range(tensor, value_range)
if tensor.size(0) == 1:
return tensor.squeeze(0)
# make the mini-batch of images into a grid
nmaps = tensor.size(0)
xmaps = min(nrow, nmaps)
ymaps = int(math.ceil(float(nmaps) / xmaps))
height, width = int(tensor.shape[2] + padding), int(tensor.shape[3] +
padding)
num_channels = tensor.shape[1]
grid = paddle.full((num_channels, height * ymaps + padding,
width * xmaps + padding), pad_value)
k = 0
for y in range(ymaps):
for x in range(xmaps):
if k >= nmaps:
break
grid[:, y * height + padding:(y + 1) * height, x * width + padding:(
x + 1) * width] = tensor[k]
k = k + 1
return grid
@paddle.no_grad()
def save_image(tensor: Union[paddle.Tensor, List[paddle.Tensor]],
fp: Union[Text, pathlib.Path, BinaryIO],
format: Optional[str]=None,
**kwargs) -> None:
grid = make_grid(tensor, **kwargs)
ndarr = paddle.clip(grid * 255 + 0.5, 0, 255).transpose(
[1, 2, 0]).cast("uint8").numpy()
im = Image.fromarray(ndarr)
im.save(fp, format=format)
```
## 常见问题
1.出现如下提示如何处理?
> The no support Api are: [torchvision.transforms.RandomErasing, torchvision.transforms.functional, torchvision.transforms.RandomCrop.get_params, torch.all, torch.as_tensor].
A:这一提示说明仍有API未支持转换,用户可自行添加相应API的支持,具体添加流程参照[添加示例](./add_api.md),或及时提issue与我们联系。
2.运行时,出现如下2种错误,如何处理?
> AttributeError: 'Tensor' object has no attribute 'XX'
> AttributeError: 'Layer' object has no attribute 'XX'
A:这一提示说明`paddle.nn.Tensor``paddle.nn.Layer`仍有attribute未支持转换,用户可自行添加相应API的支持,具体添加流程参照[添加示例](./add_api.md),或及时提issue与我们联系。
3.运行时,出现DataLoader的报错异常,如何查找原因?
A:
步骤一:查看对应自定义Dataset中\_\_getiem\_\_的返回值是否为numpy;
步骤二:如若当前的设备为GPU,是否未将`num_workers`设置为0;
步骤三:查看图像预处理的transform中是否有使用出错。
4.当前是否支持torch.jit的转换?
A:不支持。
5.如何查看PyTorch与PaddlePaddle API的差异?
A:我们提供了[PyTorch-PaddlePaddle API对应表](./API_docs/README.md),您可从中获取对应关系。
# PyTorch训练项目转换
支持将PyTorch代码及预训练模型转换为PaddlePaddle代码及预训练模型。
## 使用方法
### 第一步:转换前代码预处理
由于部分PyTorch操作是目前PaddlePaddle暂不支持的操作(例如:不支持TensorBoard、自动下载模型等),因此我们需要手动将这部分操作去除或者修改,具体可参见[转换前代码预处理](./before_convert.md)
### 第二步:转换
``` shell
x2paddle --convert_torch_project --project_dir=torch_project --save_dir=paddle_project --pretrain_model=model.pth
```
| 参数 | |
|----------|--------------|
|--convert_torch_project | 当前方式为对PyTorch Project进行转换 |
|--project_dir | PyTorch的项目路径 |
|--save_dir | 指定转换后项目的保存路径 |
|--pretrain_model | **[可选]**需要转换的预训练模型的路径(文件后缀名为“.pth”、“.pt”、“.ckpt”)或者包含预训练模型的文件夹路径,转换后的模型将将保在当前路径,后缀名为“.pdiparams” |
### 第三步:转换后代码后处理
PaddlePaddle在使用上有部分限制(例如:自定义Dataset必须继承自`paddle.io.Dataset`、部分情况下DataLoader的num_worker只能为0等),用户需要手动修改代码,使代码运行,具体可参见[转换后代码后处理](./after_convert.md)
***[注意]*** 转换前后相应操作可以参考[转换示例](./demo.md)
# 添加API映射方式
在3种情况下需要添加的API映射,本文档将对添加方式逐一进行介绍,3种情况如下表所示:
| | 对应情况 |
| -------------------- | ------------------------------------------------------------ |
| [情况1](#situation1) | 在运行代码时出现错误:`AttributeError: 'Tensor' object has no attribute 'XX'`。 |
| [情况2](#situation2) | 在运行代码时出现错误:`AttributeError: 'Layer' object has no attribute 'XX'`。 |
| [情况3](#situation3) | 在转换代码时出现提示:`Can not convert the file XX.py. The unsupported packages or operators are: [torch.nn.Tanh, torch.nn.utils.spectral_norm].`<br/>[3.1](#situation3.1) PaddlePaddle存在对应API,功能完全一致,参数一致。 <br/>[3.2](#situation3.2) PaddlePaddle存在对应API,功能基本一致,参数不一致。 <br/>[3.3](#situation3.3) PaddlePaddle不存在对应API。 |
需要修改的文件在[x2paddle/project_convertor/pytorch](../../x2paddle/project_convertor/pytorch)中,具体文件如下所示:
> .
> |── api_mapper # 存放映射处理相关操作
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|── \_\_init\_\_.py
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|── learning_rate_scheduler.py # 学习率类API映射操作
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|── nn.py # 组网、损失相关类API映射操作
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|── ops.py # paddle.Tensor处理类API映射操作
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|── torchvision.py # 图像处理相关的API映射操作
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└── utils.py # 基础操作
> |── mapper.py # 存放映射关系
> └── torch2paddle # 存放需要重新封装实现的API
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|──\_\_init\_\_.py
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|── device.py # 实现设备相关的操作
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|── io.py # 实现数据相关的操作
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|── layer.py # 实现paddle.nn.Layer类内方法/属性的操作
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|── nn_functional.py # 实现组网OP的操作
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|── nn_utils.py # 实现组网参数相关的操作
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|── ops.py # 实现Tensor处理OP的操作
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|── optimizer.py # 实现优化相关的操作
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|── tensor.py # 实现paddle.Tensor类内方法/属性操作
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|── varbase.py # 实现paddle.Tensor取值的操作
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|── vision_transforms.py # 实现视觉transform的操作
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└── vision_utils.py # 实现视觉基础的操作
***[注意]*** 添加完映射后,需要重新安装X2Paddle:
```
cd X2Paddle
rm -rf bulid dist x2paddle.egg-info
pip uninstall x2paddle
python setup.py install
```
### <span id="situation1">情况1</span>
该情况出现的原因为paddle.Tensor缺乏类内方法/属性,因此需要将torch.Tensor的类内方法/属性注册为paddle.Tensor的类内方法/属性,在[x2paddle/project_convertor/pytorch/torch2paddle/tensor.py](../../x2paddle/project_convertor/pytorch/torch2paddle/tensor.py)添加相应代码。以item类内方法为例,PyTorch中item方法的作用是提取Scalar中的数值,以避免耗费内存和计算量,因此需要添加如下代码:
```python
# 添加注册装饰器
@add_tensor_function
def item(self):
# 实现item方法的对应功能
return self.numpy()[0]
```
当torch.Tensor的类内方法/属性与paddle.Tensor的内置方法/属性命名一致,但实现功能不一致,也需要重新实现该类内方法/属性。以reshape类内方法为例,PyTorch传入的为可变参数,而PaddlePaddle出入的参数为一个list,因此需要添加的代码如下:
```python
# 对原始的reshape进行重命名,此处添加"_tmp",防止与其他类内函数重名
reshape_tmp = partial(paddle.Tensor.reshape)
# 添加注册装饰器
@add_tensor_function
def reshape(self, *shape):
# 实现reshape方法的对应功能
return reshape_tmp(self, shape)
```
### <span id="situation2">情况2</span>
该情况出现的原因为paddle.nn.Layer缺乏类内方法/属性,因此需要将torch.nn.Module的类内方法/属性注册为paddle.nn.Layer的类内方法/属性,在[x2paddle/project_convertor/pytorch/torch2paddle/layer.py](../../x2paddle/project_convertor/pytorch/torch2paddle/layer.py)添加相应代码。以cuda类内方法为例,PyTorch的网络可以设置运行的的设备为cuda,而PaddlePaddle则不需要此操作,因此需要添加如下代码返回原网络即可:
```python
# 添加注册装饰器
@add_layer_function
def cuda(self):
return self
```
当torch.nn.Module的类内方法/属性与paddle.nn.Layer的内置方法/属性命名一致,但实现功能不一致,也需要重新实现该类内方法/属性。以train类内方法为例,PyTorch可以设置train的模式是train还是eval,PaddlePaddle则需要组合实现,因此需要添加的代码如下:
```python
# 对原始的train进行重命名,此处添加"_tmp",防止与其他类内函数重名
train_tmp = partial(paddle.nn.Layer.train)
# 添加注册装饰器
@add_layer_function
def train(self, mode=True):
# 实现train方法的对应功能
if mode:
return train_tmp(self)
else:
return paddle.nn.Layer.eval(self)
```
### <span id="situation3">情况3</span>
### <span id="situation3.1">3.1</span> PaddlePaddle存在对应API,功能完全一致,参数一致
该情况直接在[x2paddle/project_convertor/pytorch/mapper.py](../../x2paddle/project_convertor/pytorch/mapper.py)中对应的MAPPER中添加PyTorch API的字符串以及Paddle API的字符串,无需添加进行参数映射所需调用的类,具体实现如下:
```python
# key为PyTorch API字符串;
# value为列表,由Paddle API字符串和None组合而成。
...
NN_MAPPER = {
...
"torch.nn.Sequential":
["paddle.nn.Sequential", None],
"torch.nn.utils":
["paddle.nn.utils", None],
...
}
...
```
### <span id="situation3.2">3.2</span> PaddlePaddle存在对应API,功能基本一致,参数不一致
该情况需要完成以下几个步骤:
***步骤1***[x2paddle/project_convertor/pytorch/mapper.py](.../../x2paddle/project_convertor/pytorch/mapper.py)中对应的MAPPER中添加PyTorch API的字符串以及Paddle API的字符串、映射处理类,具体实现如下:
```python
# key为PyTorch API字符串;
# value为列表,由Paddle API字符串和参映射处理类组合而成。
...
NN_MAPPER = {
...
"torch.nn.Conv2d":
["paddle.nn.Conv2D", ClassConv2D],
...
"torch.nn.functional.relu":
["paddle.nn.functional.relu", FuncRelu],
...
}
...
# 类名以Class或Func开始,Class代表Paddle API为一个类,Func代表Paddle API为一个方法。
```
***步骤2***[x2paddle/project_convertor/pytorch/api_mapper/](../../x2paddle/project_convertor/pytorch/api_mapper)文件夹中找到对应的文件并在其中添加映射处理类,类型中用户需要重写process_attrs、delete_attrs、check_attrs以及run这三个函数,其中run只需要修改对应的x2paddle封装的API命名即可。以`torch.matmul``paddle.matmul`的映射为例,二者的参数名不一致,因此需要添加的代码如下所示:
```python
class FuncMatmul(Mapper):
def __init__(self, func_name, pytorch_api_name, args, kwargs, target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
""" 更新参数。
"""
rename_key(self.kwargs, "input", "x")
rename_key(self.kwargs, "other", "y")
def delete_attrs(self):
""" 删除参数。
"""
delete_key(self.kwargs, "out")
def check_attrs(self):
""" 确认参数的值。
"""
pass
def run(self):
if self.rename_func_name("x2paddle.torch2paddle.matmul"):
# 作用:当出现可变参数或关键字参数,无法对参数进行处理;
# 需要根据x2paddle封装的对应API命名生成代码(x2paddle封装的对应API相关代码在步骤3中实现)
return [], generate_api_code(self.func_name, self.args, self.kwargs), []
else:
# 作用:将paddle与pytorch不同的可变参数替换成字典参数,并生成相应代码
self.convert_args2kwargs()
return self.convert_to_paddle()
```
其中,使用到的几个方法介绍如下:
| 方法 | 参数 | 作用 |
| ------------------------------------ | ------------------------------------------------------------ | ----------------------------------------------- |
| rename_key(kwargs, old_key, new_key) | kwargs:PyTorch API的关键字参数; old_key:PyTorch API的关键字参数的key; new_key:Paddle API的关键字参数的key。 | 若old_key存在于kwargs,将old_key替换为new_key。 |
| delete_key(kwargs, old_key) | kwargs:PyTorch API的关键字参数;old_key:PyTorch API的关键字参数的key。 | 删除kwargs中的old_key。 |
***步骤3*** 当PyTorch API传入的是可变参数或关键字参数,映射处理类无法对参数进行处理,此时只能调用x2paddle封装的API,所以需要在[x2paddle/project_convertor/pytorch/torch2paddle/](../../x2paddle/project_convertor/pytorch/torch2paddle)文件夹中找到对应的文件并在其中添加x2paddle API实现,其函数名或类名与步骤2中的`torch2paddle_func_name`命名一致,同样以`torch.matmul``paddle.matmul`的映射为例,其实现代码如下:
```python
def matmul(input, other, *, out=None):
return paddle.matmul(input, other)
```
### <span id="situation3.3">3.3</span> PaddlePaddle不存在对应API
### 3.3.1 API代码为必要代码
当前API在代码中必须存在,需要添加转换,因此要完成以下2个步骤:
***步骤1***[x2paddle/project_convertor/pytorch/mapper.py](../../x2paddle/project_convertor/pytorch/mapper.py)中对应的MAPPER中添加PyTorch API的字符串以及Paddle API的字符串,具体实现如下:
```python
# key为PyTorch API字符串;
# value为列表,由x2paddle自行实现API字符串和None组合而成。
...
UTILS_MAPPER = {
...
"torch.utils.data.random_split":
["x2paddle.torch2paddle.random_split", None],
...
"torch.utils.data.ConcatDataset":
["x2paddle.torch2paddle.ConcatDataset", None]
...
}
...
```
***步骤2***[x2paddle/project_convertor/pytorch/torch2paddle/](../../x2paddle/project_convertor/pytorch/torch2paddle)文件夹中找到对应的文件并在其中添加x2paddle API实现,其函数名或类名与步骤1中字典 value值中list的第一个值一致,以`torch.utils.data.random_split`的实现为例,其作用为划分数据集,因此需要添加的代码如下所示:
```python
def random_split(dataset, lengths, generator=None):
if sum(lengths) != len(dataset):
raise ValueError("Sum of input lengths does not equal the length of the input dataset!")
indices = paddle.randperm(sum(lengths))
return [Subset(dataset, indices[offset - length : offset]) for offset, length in zip(_accumulate(lengths), lengths)]
setattr(paddle.io, "random_split", random_split)
```
### 3.3.2 API代码为不必要代码
当前API为PaddlePaddle不需要的代码,应进行删除,因此需要在[x2paddle/project_convertor/pytorch/mapper.py](../../x2paddle/project_convertor/pytorch/mapper.py)中REMOVE_API中添加需要去除的PyTorch API,具体实现如下:
```python
REMOVE_API =["torch.backends.cudnn",
"torch.backends.cudnn.benchmark"]
```
### 3.3.3 API代码为可替换代码
若当前API可用其他PyTorch API`torch.YY``torch.YY`[已支持映射列表](./supported_API.md)中)代替且替换后精度影响不大,可在原PyTorch代码中将当前API替换为`torch.YY`,再进行转换。
# 转换后代码后处理
1. 若需要使用GPU,且预处理中使用了Tensor,`x2paddle.torch2paddle.DataLoader`中的`num_workers`必须设置为0。
2. 修改自定义Dataset(继承自`paddle.io.Dataset`)中的`__getitem__`的返回值,若返回值中存在Tensor,需添加相应代码将Tensor修改为numpy。
```
# 原始代码
class VocDataset(paddle.io.Dataset):
...
def __getitem__(self):
...
return out1, out2
...
# 替换后代码
class VocDataset(paddle.io.Dataset):
...
def __getitem__(self):
...
if isinstance(out1, paddle.Tensor):
out1 = out1.numpy()
if isinstance(out2, paddle.Tensor):
out2 = out2.numpy()
return out1, out2
...
```
3. 若存在Tensor对比操作(包含==、!=、<、<=、>、>=操作符),在对比操作符前添加对Tensor类型的判断,如果为bool型强转为int型,并在对比后转换回bool型。
```
# 原始代码(其中c_trg是Tensor)
c_trg = c_trg == 0
# 替换后代码
is_bool = False
if str(c_trg.dtype) == "VarType.BOOL":
c_trg = c_trg.cast("int32")
is_bool = True
c_trg = c_trg == 0
if is_bool:
c_trg = c_trg.cast("bool")
```
4. 如若转换后的运行代码的入口为sh脚本文件,且其中有预训练模型路径,应将其中的预训练模型的路径字符串中的“.pth”、“.pt”、“.ckpt”替换为“.pdiparams”。
# 转换前代码预处理
1. 去除TensorBoard相关的操作。
2. 将PyTorch中Tensor逐位逻辑与、或、异或运算操作符替换为对应的API的操作:
> | 替换为 torch.bitwise_or
> & 替换为 torch.bitwise_and
> ^ 替换为 torch.bitwise_xor
``` python
# 原始代码:
pos_mask | neg_mask
# 替换后代码
torch.bitwise_or(pos_mask, neg_mask)
```
3. 若自定义的`DataSet`(用于加载数据模块,作为`torch.utils.data.DataLoader`的参数)未继承`torch.utils.data.Dataset`,则需要添加该继承关系。
```
# 原始代码
class VocDataset:
# 替换后代码
import torch
class VocDataset(torch.utils.data.Dataset):
```
4. 若预训练模型需要下载,去除下载预训练模型相关代码,在转换前将预训练模型下载至本地,并修改加载预训练模型参数相关代码的路径为预训练模型本地保存路径。
5. 若在数据预处理中出现Tensor与float型/int型对比大小,则需要将float型/int型修改为Tensor,例如下面代码为一段未数据预处理中一段代码,修改如下:
``` python
# 原始代码:
mask = best_target_per_prior < 0.5
# 替换后代码
threshold_tensor = torch.full_like(best_target_per_prior, 0.5)
mask = best_target_per_prior < threshold_tensor
```
# PyTorch项目转换示例
## [StarGAN](https://github.com/yunjey/stargan)
### 准备工作
``` shell
# 下载项目
git clone https://github.com/yunjey/stargan.git
git checkout 30867d6f85a3bb99c38ae075de651004747c42d4
# 下载预训练模型
cd stargan
bash download.sh pretrained-celeba-128x128
# 下载数据集
bash download.sh celeba
```
### 第一步:转换前代码预处理
1. 规避使用TensorBoard,在[config处](https://github.com/yunjey/stargan/blob/master/main.py#L109)设置不使用tensorboard,具体添加代码如下:
``` python
...
parser.add_argument('--lr_update_step', type=int, default=1000)
config = parser.parse_args()
# 第5行为添加不使用tensorboard的相关代码
config.use_tensorboard = False
print(config)
main(config)
```
### 第二步:转换
``` shell
cd ../
x2paddle --convert_torch_project --project_dir=stargan --save_dir=paddle_project --pretrain_model=stargan/stargan_celeba_128/models/
```
【注意】此示例中的`pretrain_model`是训练后的PyTorch模型,转换后则为PaddlePaddle训练后的模型,用户可修改转换后代码将其作为预训练模型,也可直接用于预测。
### 第三步:转换后代码后处理
**需要修改的文件位于paddle_project文件夹中,其中文件命名与原始stargan文件夹中文件命名一致。**
1. DataLoader的`num_workers`设置为0,在[config处](https://github.com/SunAhong1993/stargan/blob/paddle/main.py#L116)设置强制设置`num_workers`,具体添加代码如下:
``` python
...
parser.add_argument('--lr_update_step', type=int, default=1000)
config = parser.parse_args()
config.use_tensorboard = False
# 第6行添加设置num_workers为0
config.num_workers = 0
print(config)
main(config)
```
2. 修改自定义Dataset中的[\_\_getitem\_\_的返回值](https://github.com/SunAhong1993/stargan/blob/paddle/data_loader.py#L63),将Tensor修改为numpy,修改代码如下:
``` python
...
class CelebA(data.Dataset):
...
def __getitem__(self, index):
"""Return one image and its corresponding attribute label."""
dataset = (self.train_dataset if self.mode == 'train' else self.
test_dataset)
filename, label = dataset[index]
image = Image.open(os.path.join(self.image_dir, filename))
# return self.transform(image), torch2paddle.create_float32_tensor(label)
# 将原来的return替换为如下12-17行
out1 = self.transform(image)
if isinstance(out1, paddle.Tensor):
out1 = out1.numpy()
out2 = torch2paddle.create_float32_tensor(label)
if isinstance(out2, paddle.Tensor):
out2 = out2.numpy()
return out1, out2
...
```
3.[Tensor对比操作](https://github.com/SunAhong1993/stargan/blob/paddle/solver.py#L156)中对Tensor进行判断,判断是否为bool型,如果为bool类型需要强制转换,修改代码如下:
``` python
...
class Solver(object):
...
def create_labels(self, c_org, c_dim=5, dataset='CelebA', selected_attrs=None):
...
for i in range(c_dim):
if dataset == 'CelebA':
c_trg = c_org.clone()
if i in hair_color_indices:
c_trg[:, i] = 1
for j in hair_color_indices:
if j != i:
c_trg[:, j] = 0
else:
# 如果为bool型,需要强转为int32,
# 在17-20行实现
is_bool = False
if str(c_trg.dtype) == "VarType.BOOL":
c_trg = c_trg.cast("int32")
is_bool = True
c_trg[:, i] = (c_trg[:, i] == 0)
# 如果为bool类型转换为原类型
# 在23-24行实现
if is_bool:
c_trg = c_trg.cast("bool")
...
...
...
...
```
### 运行训练代码
``` shell
cd paddle_project/stargan
python main.py --mode train --dataset CelebA --image_size 128 --c_dim 5 --sample_dir stargan_celeba/samples --log_dir stargan_celeba/logs --model_save_dir stargan_celeba/models --result_dir stargan_celeba/results --selected_attrs Black_Hair Blond_Hair Brown_Hair Male Young --celeba_image_dir ./data/celeba/images --attr_path ./data/celeba/list_attr_celeba.txt
```
***转换后的代码可在[这里](https://github.com/SunAhong1993/stargan/tree/paddle)进行查看。***
## [Ultra-Light-Fast-Generic-Face-Detector](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB)
### 准备工作
1. 下载项目
``` shell
# 下载项目
git clone https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB.git
git checkout 492a02471671b49c56be8d90cda54c94749d2980
```
2. 根据Generate VOC format training data set and training process的README.md所示下载数据集,并存放于Ultra-Light-Fast-Generic-Face-Detector-1MB/data/文件夹下。
### 第一步:转换前代码预处理
1. 将代码中的[或操作符](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/blob/master/vision/utils/box_utils.py#L153)替换为如下代码:
``` python
...
def hard_negative_mining(loss, labels, neg_pos_ratio):
...
# return pos_mask | neg_mask
return torch.bitwise_or(pos_mask, neg_mask)
...
```
2. 使自定义的[`DataSet`](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/blob/master/vision/datasets/voc_dataset.py#L10)继承`torch.utils.data.Dataset`,同时由于代码未导入torch,要添加相关导入的包,修改为如下代码:
``` python
...
# 导入torch
import torch
...
# class VOCDataset
class VOCDataset(torch.utils.data.Dataset):
...
...
```
3.[数据预处理](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/blob/master/vision/utils/box_utils.py#L126)Tensor与int型对比,修改为Tensor与Tensor对比,修改如下:
``` python
...
def assign_priors(gt_boxes, gt_labels, corner_form_priors,
iou_threshold):
...
# labels[best_target_per_prior < iou_threshold] = 0 # the backgournd id
# 将原来的赋值修改为7-8行
iou_threshold_tensor = torch.full_like(best_target_per_prior, iou_threshold)
labels[best_target_per_prior < iou_threshold_tensor] = 0
boxes = gt_boxes[best_target_per_prior_index]
return boxes, labels
...
```
### 第二步:转换
```shell
x2paddle --convert_torch_project --project_dir=Ultra-Light-Fast-Generic-Face-Detector-1MB --save_dir=paddle_project
```
### 第三步:转换后代码后处理
**需要修改的文件位于paddle_project文件夹中,其中文件命名与原始Ultra-Light-Fast-Generic-Face-Detector-1MB文件夹中文件命名一致。**
1. DataLoader的`num_workers`设置为0,在转换后的[train-version-RFB.sh处](https://github.com/SunAhong1993/Ultra-Light-Fast-Generic-Face-Detector-1MB/blob/paddle/train-version-RFB.sh#L27)设置强制设置`num_workers`,具体添加代码如下:
```shell
...
--num_workers \
#4 \
0 \
...
```
2.修改自定义Dataset中的[\_\_getitem\_\_的返回值](https://github.com/SunAhong1993/Ultra-Light-Fast-Generic-Face-Detector-1MB/blob/paddle/vision/datasets/voc_dataset.py#L56),将Tensor修改为numpy,修改代码如下:
``` python
...
class VOCDataset(data.Dataset):
...
def __getitem__(self, index):
image_id = self.ids[index]
boxes, labels, is_difficult = self._get_annotation(image_id)
if not self.keep_difficult:
boxes = boxes[is_difficult == 0]
labels = labels[is_difficult == 0]
image = self._read_image(image_id)
if self.transform:
image, boxes, labels = self.transform(image, boxes, labels)
if self.target_transform:
boxes, labels = self.target_transform(boxes, labels)
# return image, boxes, labels
# 将原来的return替换为如下17行
return image.numpy(), boxes.numpy(), labels.numpy()
...
```
### 运行训练代码
``` shell
cd paddle_project/Ultra-Light-Fast-Generic-Face-Detector-1MB
sh train-version-RFB.sh
```
***转换后的代码可在[这里](https://github.com/SunAhong1993/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/paddle)进行查看。***
# PyTorch训练项目转换支持API列表
> 目前PyTorch训练项目转换支持6个优化器相关API,40+的NN类API,5个Utils类API,2个Autograd类API,40+的基础操作API以及10+Torchvision API,我们在如下列表中给出了目前的全部API。
## 优化器相关API
| 序号 | API | 序号 | API |
| ---- | ------------------------------------------ | ---- | ------------------------------------------ |
| 1 | torch.optim | 2 | torch.optim.lr_scheduler.ReduceLROnPlateau |
| 3 | torch.optim.lr_scheduler.CosineAnnealingLR | 4 | torch.optim.lr_scheduler.MultiStepLR |
| 5 | torch.optim.Adam | 6 | torch.optim.SGD |
## NN类API
| 序号 | API | 序号 | API |
| ---- | ---------------------------------------------------- | ---- | --------------------------------- |
| 1 | torch.nn | 2 | torch.nn.Module |
| 3 | torch.nn.ModuleList | 4 | torch.nn.Sequential |
| 5 | torch.nn.utils | 6 | torch.nn.utils.clip_grad_value_ |
| 7 | torch.nn.Parameter | 8 | torch.nn.DataParallel |
| 9 | torch.nn.functional | 10 | torch.nn.BatchNorm1d |
| 11 | torch.nn.BatchNorm2d | 12 | torch.nn.BatchNorm3d |
| 13 | torch.nn.Conv1d | 14 | torch.nn.Conv2d |
| 15 | torch.nn.Conv3d | 16 | torch.nn.ConvTranspose2d |
| 17 | torch.nn.Dropout | 18 | torch.nn.Embedding |
| 19 | torch.nn.InstanceNorm2d | 20 | torch.nn.LeakyReLU |
| 21 | torch.nn.Linear | 22 | torch.nn.MaxPool1d |
| 23 | torch.nn.MaxPool2d | 24 | torch.nn.MaxPool3d |
| 25 | torch.nn.ReLU | 26 | torch.nn.Sigmoid |
| 27 | torch.nn.Softmax | 28 | torch.nn.Tanh |
| 29 | torch.nn.Upsample | 30 | torch.nn.CrossEntropyLoss |
| 31 | torch.nn.BCEWithLogitsLoss | 32 | torch.nn.BCELoss |
| 33 | torch.nn.functional.avg_pool1d | 34 | torch.nn.functional.avg_pool2d |
| 35 | torch.nn.functional.avg_pool3d | 36 | torch.nn.functional.dropout |
| 37 | torch.nn.functional.log_softmax | 38 | torch.nn.functional.pad |
| 39 | torch.sigmoid | 40 | torch.nn.functional.sigmoid |
| 41 | torch.nn.functional.softmax | 42 | torch.nn.init.xavier_uniform_ |
| 43 | torch.nn.functional.binary_cross_entropy_with_logits | 44 | torch.nn.functional.cross_entropy |
| 45 | torch.nn.functional.dropout | 46 | torch.nn.functional.relu |
| 47 | torch.nn.functional.smooth_l1_loss | | |
## Utils类API
| 序号 | API | 序号 | API |
| ---- | ------------------------------ | ---- | --------------------------- |
| 1 | torch.utils.data | 2 | torch.utils.data.DataLoader |
| 3 | torch.utils.data.random_split | 4 | torch.utils.data.Dataset |
| 5 | torch.utils.data.ConcatDataset | | |
## Autograd类API
| 序号 | API | 序号 | API |
| ---- | ----------------------- | ---- | ------------------- |
| 1 | torch.autograd.Variable | 2 | torch.autograd.grad |
## 基础操作API
| 序号 | API | 序号 | API |
| ---- | ----------------------- | ---- | ----------------------- |
| 1 | torch | 2 | torch.Tensor |
| 3 | torch.FloatTensor | 4 | torch.load |
| 5 | torch.save | 6 | torch.device |
| 7 | torch.cat | 8 | torch.cuda.is_available |
| 9 | torch.no_grad | 10 | torch.from_numpy |
| 11 | torch.cuda.device_count | 12 | torch.manual_seed |
| 13 | torch.unsqueeze | 14 | torch.squeeze |
| 15 | torch.sum | 16 | torch.mean |
| 17 | torch.full | 18 | torch.full_like |
| 19 | torch.ones | 20 | torch.ones_like |
| 21 | torch.zeros | 22 | torch.zeros_like |
| 23 | torch.sqrt | 24 | torch.arange |
| 25 | torch.matmul | 26 | torch.set_grad_enabled |
| 27 | torch.tensor | 28 | torch.clamp |
| 29 | torch.exp | 30 | torch.max |
| 31 | torch.min | 32 | torch.argmax |
| 33 | torch.argmin | 34 | torch.stack |
| 35 | torch.log | 36 | torch.randperm |
| 37 | torch.rand | 38 | torch.abs |
| 39 | torch.bitwise_or | 40 | torch.bitwise_xor |
| 41 | torch.bitwise_and | 42 | torch.bitwise_not |
## Torchvision API
| 序号 | API | 序号 | API |
| ---- | --------------------------------- | ---- | ------------------------------------------- |
| 1 | torchvision.transforms | 2 | torchvision.transforms.Compose |
| 3 | torchvision.transforms.ToPILImage | 4 | torchvision.transforms.Resize |
| 5 | torchvision.transforms.ToTensor | 6 | torchvision.transforms.RandomHorizontalFlip |
| 7 | torchvision.transforms.CenterCrop | 8 | torchvision.transforms.Normalize |
| 9 | torchvision.utils.save_image | 10 | torchvision.datasets.ImageFolder |
***持续更新...***
### 一、PaddleLite部署
使用X2Paddle转换后的模型均可以使用Paddle Fluid进行预测。但对于PaddleLite上的部署,则需要检查模型中的OP是否都在PaddleLite中支持。使用`check_for_lite.py`可以进行检查。
```
python tools/check_for_lite.py paddle_model/inference_model/__model__
```
> 附:check_for_lite工具并不能完全判断模型是否被支持,PaddleLite详细支持的算子请参考[PaddleLite支持算子集](https://github.com/PaddlePaddle/Paddle-Lite/blob/develop/docs/introduction/support_operation_list.md)
### 二、模型参数合并
X2Paddle转换后产出的路径下包括两个目录,
1. `model_with_code`: 包含保存的参数文件和模型python代码文件,供用户debug
2. `inference_model`: 参数文件和序列化的模型结构文件,供用户预测部署
其中在`inference_model`中,X2Paddle将每个参数独立保存在不同的文件中(文件名和参数名一致),用户可使用`merge_params.py`将参数文件合并成一个文件使用
```
python tools/merge_params.py paddle_model/inference_model new_model_dir
```
合并参数后的模型保存在`new_model_dir`
#!/bin/bash
function abort(){
echo "Your change doesn't follow X2Paddle's code style." 1>&2
echo "Please use pre-commit to check what is wrong." 1>&2
exit 1
}
trap 'abort' 0
set -e
cd $TRAVIS_BUILD_DIR
export PATH=/usr/bin:$PATH
pre-commit install
if ! pre-commit run -a ; then
git diff
exit 1
fi
trap : 0
from six.moves import urllib
import sys
from paddle.fluid.framework import Program
ops_h = "https://raw.githubusercontent.com/PaddlePaddle/Paddle-Lite/develop/lite/api/_paddle_use_ops.h"
try:
fetch = urllib.urlretrieve(ops_h, "./_paddle_use_ops.h")
except:
fetch = urllib.request.urlretrieve(ops_h, "./_paddle_use_ops.h")
ops = list()
with open("./_paddle_use_ops.h") as f:
for line in f:
if "USE_LITE_OP" in line:
op = line.strip().split('(')[1].split(')')[0]
ops.append(op)
model_file = sys.argv[1]
with open(model_file, 'rb') as f:
program = Program.parse_from_string(f.read())
unsupported_ops = set()
for op in program.blocks[0].ops:
if op.type not in ops:
unsupported_ops.add(op.type)
nums = len(unsupported_ops)
if len(unsupported_ops) > 0:
print("========= {} OPs are not supported in Paddle-Lite=========".format(
nums))
for op in unsupported_ops:
print("========= {} ========".format(op))
else:
print("\n========== Good News! ========")
print("Good! All ops in this model are supported in Paddle-Lite!\n")
#!/bin/bash
#function:
# script used to generate caffe_pb2.py from caffe.proto using protoc
#
PROTOC=`which protoc`
if [[ -z $PROTOC ]];then
echo "not found protoc, you should first install it following this[https://github.com/google/protobuf/releases]"
exit 1
fi
WORK_ROOT=$1
PY_NAME="$WORK_ROOT/caffe_pb2.py"
$PROTOC --proto_path=$WORK_ROOT --python_out=$WORK_ROOT $WORK_ROOT/caffe.proto
ret=$?
if [ -e "$PY_NAME" ];then
echo "succeed to generate [$PY_NAME]"
exit 0
else
echo "failed to generate [$PY_NAME]"
fi
exit $ret
import paddle
import paddle.fluid as fluid
import sys
model_dir = sys.argv[1]
new_model_dir = sys.argv[2]
paddle.enable_static()
exe = paddle.static.Executor(paddle.CPUPlace())
[inference_program, feed_target_names,
fetch_targets] = paddle.static.load_inference_model(
dirname=model_dir, executor=exe)
print(feed_target_names)
paddle.static.save_inference_model(
dirname=new_model_dir,
feeded_var_names=feed_target_names,
target_vars=fetch_targets,
executor=exe,
main_program=inference_program,
params_filename="__params__")
__version__ = "1.1.0" __version__ = "1.2.0"
from .core.program import PaddleGraph from .core.program import PaddleGraph
......
...@@ -47,8 +47,10 @@ def arg_parser(): ...@@ -47,8 +47,10 @@ def arg_parser():
parser.add_argument( parser.add_argument(
"--framework", "--framework",
"-f", "-f",
choices=['tensorflow', 'caffe', 'onnx'], type=_text_type,
help="define which deeplearning framework(tensorflow/caffe/onnx)") default=None,
help="define which deeplearning framework(tensorflow/caffe/onnx/paddle2onnx)"
)
parser.add_argument( parser.add_argument(
"--caffe_proto", "--caffe_proto",
"-c", "-c",
...@@ -71,9 +73,26 @@ def arg_parser(): ...@@ -71,9 +73,26 @@ def arg_parser():
parser.add_argument( parser.add_argument(
"--paddle_type", "--paddle_type",
"-pt", "-pt",
choices=['dygraph', 'static'], type=_text_type,
default="dygraph", default="dygraph",
help="define the paddle model type after converting(dygraph/static)") help="define the paddle model type after converting(dygraph/static)")
parser.add_argument(
"--convert_torch_project",
"-tp",
action='store_true',
help="Convert the PyTorch Project.")
parser.add_argument(
"--project_dir",
"-pd",
type=_text_type,
default=None,
help="define project folder path for pytorch")
parser.add_argument(
"--pretrain_model",
"-pm",
type=_text_type,
default=None,
help="pretrain model file of pytorch model")
return parser return parser
...@@ -220,7 +239,11 @@ def main(): ...@@ -220,7 +239,11 @@ def main():
x2paddle.__version__)) x2paddle.__version__))
return return
if not args.convert_torch_project:
assert args.framework is not None, "--framework is not defined(support tensorflow/caffe/onnx)"
assert args.save_dir is not None, "--save_dir is not defined" assert args.save_dir is not None, "--save_dir is not defined"
assert args.paddle_type in ["dygraph", "static"
], "--paddle_type must be 'dygraph' or 'static'"
try: try:
import platform import platform
...@@ -241,6 +264,11 @@ def main(): ...@@ -241,6 +264,11 @@ def main():
"[ERROR] paddlepaddle not installed, use \"pip install paddlepaddle\"" "[ERROR] paddlepaddle not installed, use \"pip install paddlepaddle\""
) )
if args.convert_torch_project:
assert args.project_dir is not None, "--project_dir should be defined while translating pytorch project"
from x2paddle.project_convertor.pytorch.convert import main as convert_torch
convert_torch(args)
else:
if args.framework == "tensorflow": if args.framework == "tensorflow":
assert args.model is not None, "--model should be defined while translating tensorflow model" assert args.model is not None, "--model should be defined while translating tensorflow model"
define_input_shape = False define_input_shape = False
...@@ -262,7 +290,8 @@ def main(): ...@@ -262,7 +290,8 @@ def main():
) )
else: else:
raise Exception("--framework only support tensorflow/caffe/onnx now") raise Exception(
"--framework only support tensorflow/caffe/onnx now")
if __name__ == "__main__": if __name__ == "__main__":
......
...@@ -313,7 +313,8 @@ def shape_reshape(layer, input_shape): ...@@ -313,7 +313,8 @@ def shape_reshape(layer, input_shape):
assert input_count % explicit_count == 0, "[Reshape]botom count[%d] "\ assert input_count % explicit_count == 0, "[Reshape]botom count[%d] "\
"must be divisible by product of the specified dimensions[%d] "\ "must be divisible by product of the specified dimensions[%d] "\
% (input_count, explicit_count) % (input_count, explicit_count)
output_shape[start_axis + inferred_axis] = int(input_count / explicit_count) output_shape[start_axis + inferred_axis] = int(input_count /
explicit_count)
output_count = count(output_shape) output_count = count(output_shape)
assert output_count == input_count, "[Reshape]output count[%d] must match input count[%d]" % ( assert output_count == input_count, "[Reshape]output count[%d] must match input count[%d]" % (
...@@ -381,7 +382,8 @@ def shape_reduction(layer, input_shape): ...@@ -381,7 +382,8 @@ def shape_reduction(layer, input_shape):
assert axis <= len(input_shape[0]), 'invalid axis[%d] error' % (axis) assert axis <= len(input_shape[0]), 'invalid axis[%d] error' % (axis)
return [input_shape[0:axis]] return [input_shape[0:axis]]
def shape_axpy(layer, input_shape):
def shape_axpy(layer, input_shapes):
assert len(input_shapes) == 3, "not valid input shape for axpy layer" assert len(input_shapes) == 3, "not valid input shape for axpy layer"
assert len(input_shapes[0]) == len(input_shapes[1]), 'should have same dims' assert len(input_shapes[0]) == len(input_shapes[1]), 'should have same dims'
output_shape = input_shapes[1] output_shape = input_shapes[1]
...@@ -390,12 +392,15 @@ def shape_axpy(layer, input_shape): ...@@ -390,12 +392,15 @@ def shape_axpy(layer, input_shape):
% (str(output_shape), str(input_shapes[2])) % (str(output_shape), str(input_shapes[2]))
return [output_shape] return [output_shape]
def shape_detectionoutput(layer, input_shape): def shape_detectionoutput(layer, input_shape):
return [[-1, 6]] return [[-1, 6]]
def shape_normalize(layer, input_shape): def shape_normalize(layer, input_shape):
return input_shape return input_shape
def shape_permute(layer, input_shape): def shape_permute(layer, input_shape):
order = layer.permute_param.order order = layer.permute_param.order
inshape = input_shape[0] inshape = input_shape[0]
...@@ -406,6 +411,7 @@ def shape_permute(layer, input_shape): ...@@ -406,6 +411,7 @@ def shape_permute(layer, input_shape):
output_shape.append(inshape[ii]) output_shape.append(inshape[ii])
return [output_shape] return [output_shape]
def shape_priorbox(layer, input_shape): def shape_priorbox(layer, input_shape):
max_size = layer.prior_box_param.max_size max_size = layer.prior_box_param.max_size
aspect_ratio = layer.prior_box_param.aspect_ratio aspect_ratio = layer.prior_box_param.aspect_ratio
...@@ -419,10 +425,12 @@ def shape_priorbox(layer, input_shape): ...@@ -419,10 +425,12 @@ def shape_priorbox(layer, input_shape):
output_shape = [1, 2, 4 * N_bbx] output_shape = [1, 2, 4 * N_bbx]
return [output_shape] return [output_shape]
def shape_relu6(layer, input_shape): def shape_relu6(layer, input_shape):
return input_shape return input_shape
def shape_roipooling(layer, input_shape):
def shape_roipooling(layer, input_shapes):
pooled_w = layer.roi_pooling_param.pooled_w pooled_w = layer.roi_pooling_param.pooled_w
pooled_h = layer.roi_pooling_param.pooled_h pooled_h = layer.roi_pooling_param.pooled_h
base_fea_shape = input_shapes[0] base_fea_shape = input_shapes[0]
...@@ -433,10 +441,12 @@ def shape_roipooling(layer, input_shape): ...@@ -433,10 +441,12 @@ def shape_roipooling(layer, input_shape):
output_shape[3] = pooled_w output_shape[3] = pooled_w
return [output_shape] return [output_shape]
def shape_shufflechannel(layer, input_shape): def shape_shufflechannel(layer, input_shape):
return input_shape return input_shape
def shape_upsample(layer, input_shape):
def shape_upsample(layer, input_shapes):
scale = layer.upsample_param.scale scale = layer.upsample_param.scale
assert len(input_shapes) == 1, "not valid input shape for upsample layer" assert len(input_shapes) == 1, "not valid input shape for upsample layer"
assert type(scale) is int assert type(scale) is int
...@@ -447,7 +457,8 @@ def shape_upsample(layer, input_shape): ...@@ -447,7 +457,8 @@ def shape_upsample(layer, input_shape):
output_shape = [input_shape[0], input_shape[1], new_h, new_w] output_shape = [input_shape[0], input_shape[1], new_h, new_w]
return [output_shape] return [output_shape]
def shape_select(layer, input_shape):
def shape_select(layer, input_shapes):
slice_point = layer.select_param.slice_point slice_point = layer.select_param.slice_point
axis = layer.select_param.axis axis = layer.select_param.axis
input_shape = input_shapes[0] input_shape = input_shapes[0]
...@@ -461,4 +472,3 @@ def shape_select(layer, input_shape): ...@@ -461,4 +472,3 @@ def shape_select(layer, input_shape):
output_shape = input_shape output_shape = input_shape
output_shape[axis] = end - start output_shape[axis] = end - start
return [output_shape] return [output_shape]
from x2paddle.project_convertor.pytorch import models
resnet_pth_urls = models.resnet.model_urls
resnet18_pth = models.resnet18
resnet34_pth = models.resnet34
resnet50_pth = models.resnet50
resnet101_pth = models.resnet101
resnet152_pth = models.resnet152
resnext50_32x4d_pth = models.resnext50_32x4d
resnext101_32x8d_pth = models.resnext101_32x8d
wide_resnet50_2_pth = models.wide_resnet50_2
wide_resnet101_2_pth = models.wide_resnet101_2
vgg_pth_urls = models.vgg.model_urls
vgg11_pth = models.vgg11
vgg11_bn_pth = models.vgg11_bn
vgg13_pth = models.vgg13
vgg13_bn_pth = models.vgg13_bn
vgg16_pth = models.vgg16
vgg16_bn_pth = models.vgg16_bn
vgg19_pth = models.vgg19
vgg19_bn_pth = models.vgg19_bn
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from .learning_rate_scheduler import *
from .nn import *
from .ops import *
from .torchvision import *
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from .utils import *
class LRScheculerMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
self.useful_attrs = dict()
def process_attrs(self):
self.kwargs["learning_rate"] = 0.01
def delete_attrs(self):
self.useful_attrs["optimizer"] = self.kwargs.pop("optimizer")
def run(self):
if self.pytorch_api_name == "torch.optim.lr_scheduler.ReduceLROnPlateau" and \
self.rename_func_name("x2paddle.torch2paddle.ReduceOnPlateau"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
elif self.pytorch_api_name == "torch.optim.lr_scheduler.CosineAnnealingLR" and \
self.rename_func_name("x2paddle.torch2paddle.CosineAnnealingDecay"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
elif self.pytorch_api_name == "torch.optim.lr_scheduler.MultiStepLR" and \
self.rename_func_name("x2paddle.torch2paddle.MultiStepDecay"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
self.convert_args2kwargs()
self.check_attrs()
self.process_attrs()
self.delete_attrs()
insert_code = "{}._learning_rate = {}".format(
self.useful_attrs["optimizer"], self.target_name)
return [], generate_api_code(self.func_name, self.args,
self.kwargs), [insert_code]
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from .utils import *
from x2paddle.utils import *
class AvgPoolModuleMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
if "count_include_pad" in self.kwargs:
if isinstance(self.kwargs["count_include_pad"], bool):
self.kwargs["exclusive"] = not self.kwargs["count_include_pad"]
else:
self.kwargs["exclusive"] = "not {}".format(self.kwargs[
"count_include_pad"])
if len(self.args) > 4:
if isinstance(self.args[4], bool):
self.args[4] = not self.args[4]
else:
self.args[4] = "not {}".format(self.args[4])
def delete_attrs(self):
delete_key(self.kwargs, "count_include_pad")
def run(self):
if self.pytorch_api_name == "torch.nn.AvgPool1d" and self.rename_func_name(
"x2paddle.torch2paddle.AvgPool1D"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
elif self.pytorch_api_name == "torch.nn.AvgPool2d" and self.rename_func_name(
"x2paddle.torch2paddle.AvgPool2D"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
elif self.pytorch_api_name == "torch.nn.AvgPool3d" and self.rename_func_name(
"x2paddle.torch2paddle.AvgPool3d"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
return self.convert_to_paddle()
class BatchNormModuleMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
rename_key(self.kwargs, "num_channels", "num_features")
rename_key(self.kwargs, "eps", "epsilon")
rename_key(self.kwargs, "track_running_stats", "use_global_stats")
if "momentum" in self.kwargs:
if isinstance(self.kwargs["momentum"], float):
self.kwargs["momentum"] = 1 - self.kwargs["momentum"]
else:
self.kwargs["momentum"] = "1 - {}".format(self.kwargs[
"momentum"])
if "affine" in self.kwargs and not self.kwargs["affine"]:
for key in ["weight_attr", "bias_attr"]:
self.kwargs[key] = "paddle.ParamAttr(learning_rate=0.0)"
def delete_attrs(self):
delete_key(self.kwargs, "affine")
delete_key(self.kwargs, "process_group")
def run(self):
if self.pytorch_api_name == "torch.nn.InstanceNorm2d":
delete_key(self.kwargs, "track_running_stats")
if self.pytorch_api_name == "torch.nn.BatchNorm1d" and self.rename_func_name(
"x2paddle.torch2paddle.BatchNorm1D"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
elif self.pytorch_api_name == "torch.nn.BatchNorm2d" and self.rename_func_name(
"x2paddle.torch2paddle.BatchNorm2D"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
elif self.pytorch_api_name == "torch.nn.BatchNorm3d" and self.rename_func_name(
"x2paddle.torch2paddle.BatchNorm3D"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
elif self.pytorch_api_name == "torch.nn.SyncBatchNorm" and self.rename_func_name(
"x2paddle.torch2paddle.SyncBatchNorm"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
elif self.pytorch_api_name == "torch.nn.InstanceNorm2d" and self.rename_func_name(
"x2paddle.torch2paddle.InstanceNorm2D"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
self.convert_args2kwargs(1)
if "affine" in self.kwargs and not (isinstance(self.kwargs["affine"], bool) \
or (isinstance(self.kwargs["affine"], str) and self.kwargs["affine"].strip() in ["True", "False"])):
print(self.kwargs["affine"], self.func_name)
if self.pytorch_api_name == "torch.nn.BatchNorm1D":
self.func_name = "x2paddle.torch2paddle.BatchNorm1D"
elif self.pytorch_api_name == "torch.nn.BatchNorm2D":
self.func_name = "x2paddle.torch2paddle.BatchNorm2D"
elif self.pytorch_api_name == "torch.nn.BatchNorm3D":
self.func_name = "x2paddle.torch2paddle.BatchNorm3D"
elif self.pytorch_api_name == "torch.nn.SyncBatchNorm":
self.func_name = "x2paddle.torch2paddle.SyncBatchNorm"
elif self.pytorch_api_name == "torch.nn.InstanceNorm2D":
self.func_name = "x2paddle.torch2paddle.InstanceNorm2D"
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
return self.convert_to_paddle()
class ConvModuleMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
rename_key(self.kwargs, "bias", "bias_attr")
def run(self):
if self.pytorch_api_name == "torch.nn.Conv1d" and self.rename_func_name(
"x2paddle.torch2paddle.Conv1D"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
elif self.pytorch_api_name == "torch.nn.Conv2d" and self.rename_func_name(
"x2paddle.torch2paddle.Conv2D"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
elif self.pytorch_api_name == "torch.nn.Conv3d" and self.rename_func_name(
"x2paddle.torch2paddle.Conv3D"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
self.convert_args2kwargs(7)
return self.convert_to_paddle()
class DropoutModuleMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def delete_attrs(self):
delete_key(self.kwargs, "inplace")
class EmbeddingModuleMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def delete_attrs(self):
delete_key(self.kwargs, "max_norm")
delete_key(self.kwargs, "norm_type")
delete_key(self.kwargs, "scale_grad_by_freq")
def check_attrs(self):
assert "max_norm" not in self.kwargs or self.kwargs[
"max_norm"] is None, "The max_norm is not supported yet in Embedding!"
assert "scale_grad_by_freq" not in self.kwargs or not self.kwargs[
"scale_grad_by_freq"], "The scale_grad_by_freq must be False in Embedding!"
def run(self):
if self.rename_func_name("x2paddle.torch2paddle.Embedding"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
self.convert_args2kwargs(3)
return self.convert_to_paddle()
class GroupNormModuleMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
rename_key(self.kwargs, "eps", "epsilon")
if "affine" in self.kwargs and not self.kwargs["affine"]:
for key in ["weight_attr", "bias_attr"]:
self.kwargs[key] = False
def delete_attrs(self):
delete_key(self.kwargs, "affine")
def run(self):
if self.rename_func_name("x2paddle.torch2paddle.GroupNorm"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
self.convert_args2kwargs(2)
return self.convert_to_paddle()
class LayerNormModuleMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
rename_key(self.kwargs, "eps", "epsilon")
if "elementwise_affine" in self.kwargs and not self.kwargs[
"elementwise_affine"]:
for key in ["weight_attr", "bias_attr"]:
self.kwargs[key] = False
def delete_attrs(self):
delete_key(self.kwargs, "elementwise_affine")
def run(self):
if self.rename_func_name("x2paddle.torch2paddle.LayerNorm"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
self.convert_args2kwargs(1)
return self.convert_to_paddle()
class LinearModuleMapper(ConvModuleMapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def run(self):
if self.rename_func_name("x2paddle.torch2paddle.Linear"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
self.convert_args2kwargs(2)
return self.convert_to_paddle()
class LossModuleMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def delete_attrs(self):
delete_key(self.kwargs, "size_average")
delete_key(self.kwargs, "reduce")
def run(self):
if self.pytorch_api_name == "torch.nn.CrossEntropyLoss" and \
self.rename_func_name("x2paddle.torch2paddle.CrossEntropyLoss"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
elif self.pytorch_api_name == "torch.nn.BCEWithLogitsLoss" and \
self.rename_func_name("x2paddle.torch2paddle.BCEWithLogitsLoss"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
elif self.pytorch_api_name == "torch.nn.L1Loss" and \
self.rename_func_name("x2paddle.torch2paddle.L1Loss"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
return self.convert_to_paddle()
class MaxPoolModuleMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
rename_key(self.kwargs, "return_indices", "return_mask")
def check_attrs(self):
assert "dilation" not in self.kwargs, "The dilation is not supported yet in MaxPool!"
def run(self):
if self.pytorch_api_name == "torch.nn.MaxPool1d" and self.rename_func_name(
"x2paddle.torch2paddle.MaxPool1D"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
elif self.pytorch_api_name == "torch.nn.MaxPool2d" and self.rename_func_name(
"x2paddle.torch2paddle.MaxPool12D"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
elif self.pytorch_api_name == "torch.nn.MaxPool3d" and self.rename_func_name(
"x2paddle.torch2paddle.MaxPool13D"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
self.convert_args2kwargs(3)
return self.convert_to_paddle()
class PadModuleMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
if self.pytorch_api_name == "torch.nn.ReflectionPad2d":
self.kwargs["mode"] = "reflect"
elif self.pytorch_api_name in [
"torch.nn.ConstantPad2d", "torch.nn.ZeroPad2d"
]:
self.kwargs["mode"] = "constant"
elif self.pytorch_api_name == "torch.nn.ReplicationPad2d":
self.kwargs["mode"] = "replicate"
def run(self):
if self.pytorch_api_name == "torch.nn.ReflectionPad2d" and self.rename_func_name(
"x2paddle.torch2paddle.ReflectionPad2D"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
elif self.pytorch_api_name == "torch.nn.ConstantPad2d" and self.rename_func_name(
"x2paddle.torch2paddle.ConstantPad2D"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
elif self.pytorch_api_name == "torch.nn.ReplicationPad2d" and self.rename_func_name(
"x2paddle.torch2paddle.ReplicationPad2D"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
elif self.pytorch_api_name == "torch.nn.ZeroPad2d" and self.rename_func_name(
"x2paddle.torch2paddle.ZeroPad2D"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
self.convert_args2kwargs(1)
return self.convert_to_paddle()
class ReLUModuleMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def delete_attrs(self):
delete_key(self.kwargs, "inplace")
if len(self.args) > 0:
self.args.clear()
class SoftmaxModuleMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
rename_key(self.kwargs, "dim", "axis")
class AvgPoolFuncMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
rename_key(self.kwargs, "input", "x")
if "count_include_pad" in self.kwargs:
if isinstance(self.kwargs["count_include_pad"], bool):
self.kwargs["exclusive"] = not self.kwargs["count_include_pad"]
else:
self.kwargs["exclusive"] = "not {}".format(self.kwargs[
"count_include_pad"])
def delete_attrs(self):
delete_key(self.kwargs, "count_include_pad")
def run(self):
if self.pytorch_api_name == "torch.nn.functional.avg_pool1d" and self.rename_func_name(
"x2paddle.torch2paddle.avg_pool1d"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
elif self.pytorch_api_name == "torch.nn.functional.avg_pool2d" and self.rename_func_name(
"x2paddle.torch2paddle.avg_pool2d"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
elif self.pytorch_api_name == "torch.nn.functional.avg_pool3d" and self.rename_func_name(
"x2paddle.torch2paddle.avg_pool3d"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
self.convert_args2kwargs(4)
return self.convert_to_paddle()
class CrossEntropyFuncMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
rename_key(self.kwargs, "target", "label")
class DropoutFuncMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
rename_key(self.kwargs, "input", "x")
def delete_attrs(self):
delete_key(self.kwargs, "inplace")
def run(self):
if self.rename_func_name("x2paddle.torch2paddle.dropout"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
self.convert_args2kwargs(2)
return self.convert_to_paddle()
class InterpolateFuncMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
rename_key(self.kwargs, "input", "x")
def check_attrs(self):
assert "recompute_scale_factor" not in self.kwargs or self.kwargs[
"recompute_scale_factor"] is None or len(
self.args
) > 5, "The recompute_scale_factor is not supported yet in interpolate!"
def run(self):
if self.rename_func_name("x2paddle.torch2paddle.interpolate"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
return self.convert_to_paddle()
class LeaklyReluFuncMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
rename_key(self.kwargs, "input", "x")
def delete_attrs(self):
delete_key(self.kwargs, "inplace")
def run(self):
if self.rename_func_name("x2paddle.torch2paddle.leaky_relu"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
return self.convert_to_paddle()
class LogSoftmaxFuncMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
rename_key(self.kwargs, "dim", "axis")
rename_key(self.kwargs, "input", "x")
def run(self):
if self.rename_func_name("x2paddle.torch2paddle.log_softmax"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
self.convert_args2kwargs(2)
return self.convert_to_paddle()
class PadFuncMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
rename_key(self.kwargs, "input", "x")
class ReluFuncMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
rename_key(self.kwargs, "input", "x")
def delete_attrs(self):
delete_key(self.kwargs, "inplace")
def run(self):
if self.rename_func_name("x2paddle.torch2paddle.relu"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
self.convert_args2kwargs(1)
return self.convert_to_paddle()
class SigmoidFuncMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
rename_key(self.kwargs, "input", "x")
class LossFuncMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
rename_key(self.kwargs, "beta", "delta")
rename_key(self.kwargs, "target", "label")
def delete_attrs(self):
delete_key(self.kwargs, "size_average")
delete_key(self.kwargs, "reduce")
def run(self):
if self.pytorch_api_name == "torch.nn.functional.smooth_l1_loss" and self.rename_func_name(
"x2paddle.torch2paddle.smooth_l1_loss"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
elif self.pytorch_api_name == "torch.nn.functional.mse_loss" and self.rename_func_name(
"x2paddle.torch2paddle.mse_loss"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
self.convert_args2kwargs(2)
return self.convert_to_paddle()
class SoftmaxFuncMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
rename_key(self.kwargs, "input", "x")
rename_key(self.kwargs, "dim", "axis")
def delete_attrs(self):
delete_key(self.kwargs, "_stacklevel")
def run(self):
if self.rename_func_name("x2paddle.torch2paddle.softmax"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
self.convert_args2kwargs(2)
return self.convert_to_paddle()
from .utils import *
from x2paddle.utils import *
class SaveMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def delete_attrs(self):
delete_key(self.kwargs, "pickle_module")
def run(self):
if self.rename_func_name("x2paddle.torch2paddle.save"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
self.convert_args2kwargs(2)
return self.convert_to_paddle()
class LoadMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def delete_attrs(self):
delete_key(self.kwargs, "pickle_module")
delete_key(self.kwargs, "map_location")
def run(self):
if self.rename_func_name("x2paddle.torch2paddle.load"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
self.convert_args2kwargs(2)
return self.convert_to_paddle()
class HubLoadMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
if len(self.args) == 1:
self.kwargs.clear()
elif len(self.args) == 0:
self.args.append(list(self.kwargs.values())[0])
self.kwargs.clear()
else:
self.args = self.args[:1]
def run(self):
if self.pytorch_api_name == "torch.hub.load_state_dict_from_url":
if self.rename_func_name(
"x2paddle.torch2paddle.load_state_dict_from_url"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
if self.pytorch_api_name == "torch.utils.model_zoo.load_url":
if self.rename_func_name("x2paddle.torch2paddle.load_url"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
return self.convert_to_paddle()
class SetDeviceMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
self.useful_attrs = dict()
def process_attrs(self):
self.useful_attrs["device"] = self.args[0]
self.args[0] = self.target_name
def run(self):
self.process_attrs()
insert_codes = list()
insert_codes.append("{} = {}".format(self.target_name,
self.useful_attrs["device"]))
insert_codes.append("{} = {}.replace('cuda', 'gpu')".format(
self.target_name, self.target_name))
return insert_codes, generate_api_code(self.func_name, self.args,
self.kwargs), []
class DataParallelModuleMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def delete_attrs(self):
delete_key(self.kwargs, "device_ids")
delete_key(self.kwargs, "output_device")
delete_key(self.kwargs, "dim")
def run(self):
if self.rename_func_name("x2paddle.torch2paddle.DataParallel"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
return self.convert_to_paddle()
class UnSqueezeMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
rename_key(self.kwargs, "input", "x")
rename_key(self.kwargs, "dim", "axis")
def run(self):
if self.rename_func_name("x2paddle.torch2paddle.unsqueeze"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
self.convert_args2kwargs(2)
return self.convert_to_paddle()
class OneMathMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
rename_key(self.kwargs, "input", "x")
def delete_attrs(self):
delete_key(self.kwargs, "out")
def run(self):
if self.pytorch_api_name == "torch.sqrt":
if self.rename_func_name("x2paddle.torch2paddle.sqrt"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
if self.pytorch_api_name == "torch.abs":
if self.rename_func_name("x2paddle.torch2paddle.abs"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
if self.pytorch_api_name == "torch.log":
if self.rename_func_name("x2paddle.torch2paddle.log"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
if self.pytorch_api_name == "torch.exp":
if self.rename_func_name("x2paddle.torch2paddle.exp"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
if self.pytorch_api_name == "torch.clip":
if self.rename_func_name("x2paddle.torch2paddle.clip"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
return self.convert_to_paddle()
class ArangeMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
self.useful_attrs = dict()
def process_attrs(self):
self.useful_attrs["requires_grad"] = self.kwargs[
"requires_grad"] if "requires_grad" in self.kwargs else False
def delete_attrs(self):
delete_key(self.kwargs, "out")
delete_key(self.kwargs, "layout")
delete_key(self.kwargs, "device")
delete_key(self.kwargs, "requires_grad")
def run(self):
if self.rename_func_name("x2paddle.torch2paddle.arange"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
self.convert_args2kwargs(3)
out1, out2, out3 = self.convert_to_paddle()
if isinstance(self.useful_attrs["requires_grad"],
str) or not self.useful_attrs["requires_grad"]:
out2 = "{}.requires_grad_({})".format(
out2, self.useful_attrs["requires_grad"])
return out1, out2, out3
class TwoMathMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
rename_key(self.kwargs, "input", "x")
rename_key(self.kwargs, "other", "y")
def delete_attrs(self):
delete_key(self.kwargs, "out")
def run(self):
if self.pytorch_api_name == "torch.matmul":
if self.rename_func_name("x2paddle.torch2paddle.matmul"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
if self.pytorch_api_name == "torch.add":
if self.rename_func_name("x2paddle.torch2paddle.add"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
if self.pytorch_api_name == "torch.mul":
if self.rename_func_name("x2paddle.torch2paddle.mul"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
return self.convert_to_paddle()
class CreateParamModuleMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
rename_key(self.kwargs, "data", "value")
def delete_attrs(self):
delete_key(self.kwargs, "requires_grad")
def check_attrs(self):
assert "requires_grad" not in self.kwargs or self.kwargs[
"requires_grad"], "The requires_grad must be True in Parameter!"
def run(self):
if self.rename_func_name(self.func_name):
if "*" in self.args[0] and "**" not in self.args[0]:
param_name = self.args[0][1:]
elif "**" in self.args[0]:
param_name = "{}['data']".format(self.args[0][2:])
elif "*" not in self.args[0] and "**" in self.args[1]:
param_name = self.args[0]
else:
self.check_attrs()
self.process_attrs()
self.delete_attrs()
if len(self.args) == 1:
param_name = self.args[0]
else:
param_name = self.kwargs["value"]
code = "paddle.create_parameter(shape={}.shape, dtype=str({}.numpy().dtype), default_initializer = paddle.nn.initializer.Assign({}))".format(
param_name, param_name, param_name)
return [], code, ["{}.stop_gradient = False".format(self.target_name)]
class NoGradMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def delete_attrs(self):
self.args.clear()
self.kwargs.clear()
class LogicalMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
rename_key(self.kwargs, "input", "x")
rename_key(self.kwargs, "other", "y")
def run(self):
if self.pytorch_api_name == "torch.bitwise_or":
if self.rename_func_name("x2paddle.torch2paddle.logical_or"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
if self.pytorch_api_name == "torch.bitwise_and":
if self.rename_func_name("x2paddle.torch2paddle.logical_and"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
if self.pytorch_api_name == "torch.bitwise_xor":
if self.rename_func_name("x2paddle.torch2paddle.logical_xor"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
if self.pytorch_api_name == "torch.bitwise_not":
if self.rename_func_name("x2paddle.torch2paddle.logical_not"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
return self.convert_to_paddle()
class StackMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
rename_key(self.kwargs, "tensors", "x")
rename_key(self.kwargs, "dim", "axis")
def delete_attrs(self):
delete_key(self.kwargs, "out")
def run(self):
if self.rename_func_name("x2paddle.torch2paddle.stack"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
return self.convert_to_paddle()
class RandpermMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def delete_attrs(self):
delete_key(self.kwargs, "out")
delete_key(self.kwargs, "layout")
delete_key(self.kwargs, "device")
delete_key(self.kwargs, "requires_grad")
delete_key(self.kwargs, "pin_memory")
def run(self):
if self.rename_func_name("x2paddle.torch2paddle.randperm"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
return self.convert_to_paddle()
class TensorBuilderMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
self.useful_attrs = dict()
def process_attrs(self):
if self.pytorch_api_name in ["torch.ones", "torch.zeros"]:
if len(self.args) > 1:
new_args = list()
for arg in self.args:
if isinstance(arg, int):
new_args.append(str(arg))
else:
new_args.append(arg)
shape = ", ".join(new_args)
shape = "[{}]".format(shape)
self.args.clear()
self.args.append(shape)
rename_key(self.kwargs, "size", "shape")
self.useful_attrs["requires_grad"] = self.kwargs[
"requires_grad"] if "requires_grad" in self.kwargs else False
def delete_attrs(self):
delete_key(self.kwargs, "out")
delete_key(self.kwargs, "layout")
delete_key(self.kwargs, "device")
delete_key(self.kwargs, "requires_grad")
def run(self):
if self.pytorch_api_name == "torch.full":
if self.rename_func_name("x2paddle.torch2paddle.full"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
if self.pytorch_api_name == "torch.zeros":
if self.rename_func_name("x2paddle.torch2paddle.zeros"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
if self.pytorch_api_name == "torch.ones":
if self.rename_func_name("x2paddle.torch2paddle.ones"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
out1, out2, out3 = self.convert_to_paddle()
if isinstance(self.useful_attrs["requires_grad"],
str) or not self.useful_attrs["requires_grad"]:
out2 = "{}.requires_grad_({})".format(
out2, self.useful_attrs["requires_grad"])
return out1, out2, out3
class TensorLikeMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
self.useful_attrs = dict()
def process_attrs(self):
rename_key(self.kwargs, "input", "x")
self.useful_attrs["requires_grad"] = self.kwargs[
"requires_grad"] if "requires_grad" in self.kwargs else False
def delete_attrs(self):
delete_key(self.kwargs, "out")
delete_key(self.kwargs, "layout")
delete_key(self.kwargs, "device")
delete_key(self.kwargs, "requires_grad")
def run(self):
if self.pytorch_api_name == "torch.full_like":
if self.rename_func_name("x2paddle.torch2paddle.full_like"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
if self.pytorch_api_name == "torch.zeros_like":
if self.rename_func_name("x2paddle.torch2paddle.zeros_like"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
if self.pytorch_api_name == "torch.ones_like":
if self.rename_func_name("x2paddle.torch2paddle.ones_like"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
out1, out2, out3 = self.convert_to_paddle()
if isinstance(self.useful_attrs["requires_grad"],
str) or not self.useful_attrs["requires_grad"]:
out2 = "{}.requires_grad_({})".format(
out2, self.useful_attrs["requires_grad"])
return out1, out2, out3
class SplitMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def process_attrs(self):
rename_key(self.kwargs, "tensor", "x")
rename_key(self.kwargs, "split_size_or_sections", "num_or_sections")
rename_key(self.kwargs, "dim", "axis")
def run(self):
if self.rename_func_name("x2paddle.torch2paddle.split"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
self.convert_args2kwargs(3)
return self.convert_to_paddle()
class LinspaceMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
self.useful_attrs = dict()
def process_attrs(self):
rename_key(self.kwargs, "end", "stop")
rename_key(self.kwargs, "steps", "num")
self.useful_attrs["requires_grad"] = self.kwargs[
"requires_grad"] if "requires_grad" in self.kwargs else False
def delete_attrs(self):
delete_key(self.kwargs, "out")
delete_key(self.kwargs, "layout")
delete_key(self.kwargs, "device")
delete_key(self.kwargs, "requires_grad")
def run(self):
if self.rename_func_name("x2paddle.torch2paddle.linspace"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
self.convert_args2kwargs(1)
out1, out2, out3 = self.convert_to_paddle()
if isinstance(self.useful_attrs["requires_grad"],
str) or not self.useful_attrs["requires_grad"]:
out2 = "{}.requires_grad_({})".format(
out2, self.useful_attrs["requires_grad"])
return out1, out2, out3
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from .utils import *
class ImageFolderMapper(Mapper):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
super().__init__(func_name, pytorch_api_name, args, kwargs, target_name)
def check_attrs(self):
assert "target_transform" not in self.kwargs, "The target_transform is not supported yet in ImageFolder!"
def run(self):
if self.pytorch_api_name == "torchvision.datasets.ImageFolder" and \
self.rename_func_name("x2paddle.torch2paddle.ImageFolder"):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
self.convert_args2kwargs(1)
return self.convert_to_paddle()
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import inspect
def api_args2kwargs(pytorch_api_name, args, first_same_attr_count):
""" 将每个OP的args转为kwargs。
Args:
pytorch_api_name (str): OP的类型名字。
args (list): 参数列表。
first_same_attr_count (int): PyTorch与Paddle前first_same_attr_count个完全相同的参数。
"""
def get_default_args(obj):
if inspect.isbuiltin(obj):
demp_str = obj.__doc__.split("->")[0].strip()[:-1]
demp_str = demp_str.split("(")[-1]
demp_str_seg = demp_str.split(",")
default_args = list()
for seg in demp_str_seg:
seg = seg.strip().replace("*", "")
if seg == "":
continue
if "=" in seg:
seg = seg.split("=")[0]
default_args.append(seg)
return default_args
else:
signature = inspect.signature(obj)
return [k for k, v in signature.parameters.items()]
if pytorch_api_name.startswith("torchvision"):
import torchvision
obj = torchvision
else:
import torch
obj = torch
for i, part in enumerate(pytorch_api_name.split(".")):
if i == 0:
continue
obj = getattr(obj, part)
default_args = get_default_args(obj)
new_kwargs = dict()
for i, default_k in enumerate(default_args):
if i >= first_same_attr_count and i < len(args):
new_kwargs[default_k] = args[i]
return new_kwargs
def rename_key(kwargs, old_key, new_key):
if old_key in kwargs:
v = kwargs.pop(old_key)
kwargs[new_key] = v
def delete_key(kwargs, old_key):
if old_key in kwargs:
kwargs.pop(old_key)
def generate_api_code(func_name, args, kwargs):
for i, arg in enumerate(args):
if not isinstance(args[i], str):
args[i] = str(args[i])
args_str = ", ".join(args)
kwargs_str_list = list()
for k, v in kwargs.items():
kwargs_str_list.append("{}={}".format(k, v))
kwargs_str = ", ".join(kwargs_str_list)
if len(args_str) > 0:
code = "{}({}, {})".format(func_name, args_str, kwargs_str)
else:
code = "{}({})".format(func_name, kwargs_str)
return code
class Mapper(object):
def __init__(self,
func_name,
pytorch_api_name,
args,
kwargs,
target_name=None):
self.func_name = func_name
self.pytorch_api_name = pytorch_api_name
self.args = args
self.kwargs = kwargs
self.target_name = target_name
def process_attrs(self):
""" 更新参数。
"""
pass
def delete_attrs(self):
""" 删除参数。
"""
pass
def check_attrs(self):
""" 确认参数的值。
"""
pass
def rename_func_name(self, torch2paddle_func_name=None):
""" 判断是否为可变参数或者关键字参数,
若为可变参数或者关键字参数,则替换参数名。
"""
if torch2paddle_func_name is not None and \
(len(self.args) > 0 and isinstance(self.args[0], str) and self.args[0].startswith("*")) or \
(len(self.args) > 1 and isinstance(self.args[-1], str) and self.args[-1].startswith("**")):
self.func_name = torch2paddle_func_name
return True
else:
return False
def convert_to_paddle(self):
""" 1. 通过执行check、process、delete转换为paddle的参数;
2. 生成paddle相关代码。
"""
self.check_attrs()
self.process_attrs()
self.delete_attrs()
return [], generate_api_code(self.func_name, self.args, self.kwargs), []
def convert_args2kwargs(self, first_same_attr_count=0):
""" 将args转换为kwargs。
"""
if len(self.args) > first_same_attr_count:
new_kwargs = api_args2kwargs(self.pytorch_api_name, self.args,
first_same_attr_count)
self.kwargs.update(new_kwargs)
self.args = self.args[:first_same_attr_count]
def run(self, torch2paddle_func_name=None):
""" 如果存在可变参数或者关键字参数,直接替换函数名为x2paddle的API;
反之,调用convert_to_paddle。
"""
if self.rename_func_name(torch2paddle_func_name):
return [], generate_api_code(self.func_name, self.args,
self.kwargs), []
else:
return self.convert_to_paddle()
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import ast
import astor
import sys
from x2paddle.project_convertor.pytorch.mapper import *
import copy
import os.path as osp
from .utils import get_dep_file_path
class DepInfo:
"""
依赖包信息。
PT_FROM代表pytorch from信息的字符串,例如:torch;
PD_FROM代表paddle from信息的字符串,例如:paddle;
PT_IMPORT代表pytorch import信息系的字符串,例如:nn.functional;
PD_IMPORT代表paddle import信息系的字符串,例如:nn.functional;
AS代表as信息的字符串,例如:F;
PT_DEPENDENCY代表由PT_FROM、PT_IMPORT、AS三者组成的字符串,例如:from torch import nn.functional as F。
PD_DEPENDENCY代表由PD_FROM、PD_IMPORT、AS三者组成的字符串,例如:from paddle import nn.functional as F。
"""
PT_FROM = None
PD_FROM = None
PT_IMPORT = None
PD_IMPORT = None
AS = None
PT_DEPENDENCY = None
PD_DEPENDENCY = None
class AstUpdater(ast.NodeVisitor):
""" 更新ast树,将ast树中PyTorch相关的节点转为Paddle相关的节点。
Args:
py_file_path (str): python文件的绝对值路径。
file_dependencies (dict): 当前已经统计的依赖信息,key为python文件的绝对值路径,
value为key文件所对应的依赖信息组成的list。
"""
def __init__(self, py_file_path, file_dependencies):
self.py_file_path = py_file_path
self.root = ast.parse(open(py_file_path, "rb").read())
self.file_dependencies = file_dependencies
self.scopes_and_dependencies = list() # 作用域和依赖组成的stack
self.nodes = list() # ast节点组成的stack
self.no_support_apis = list() # 不支持的API列表
self.is_import_torch2paddle = False # 是否添加import torch2paddle
self.is_import_paddle = True # 是否添加import padddle
self.is_import_x2paddle = False # 是否添加import x2paddle
def _get_scope_node(self):
""" 获取当前节点的作用域。
"""
scope_node = None
for i in range(len(self.scopes_and_dependencies)):
i = -(i + 1)
sd = self.scopes_and_dependencies[i]
if not isinstance(sd, DepInfo) and not isinstance(sd, ast.Assign):
scope_node = sd
break
return scope_node
def _get_current_index(self, scope_node, node):
""" 获取当前节点在其作用域中的索引序号。
"""
current_id = 0
for i, n in enumerate(scope_node.body):
if node == n:
current_id = i
break
return current_id
def _get_father_node(self):
""" 获取父节点。
"""
return self.nodes[-2]
def _get_complete_api(self, api_part_name):
""" 根据部分api名字获取PyTorch的api全名。
情况1:依赖是DepInfo,但其PD_IMPORT为None(非PyTorch的依赖),则pytorch_api为None。
情况2:依赖是DepInfo,且DepInfo的部分PyTorch属性以“torch”开头,则pytorch_api为完整api。
情况3:依赖是ast.Assign节点,则pytorch_api为None。
"""
pytorch_api = None
dep_info = None
if api_part_name is None:
return pytorch_api, dep_info
for i in range(len(self.scopes_and_dependencies)):
i = -(i + 1)
dep_info = self.scopes_and_dependencies[i]
if isinstance(dep_info, DepInfo):
if dep_info.PT_IMPORT is None:
continue
if (dep_info.PT_FROM is not None and "torch" in dep_info.PT_FROM) or \
(dep_info.PT_IMPORT is not None and "torch" in dep_info.PT_IMPORT):
replace_str = None
if dep_info.AS is not None and api_part_name.startswith(
dep_info.AS + "."):
replace_str = dep_info.AS
elif dep_info.AS is None and api_part_name.startswith(
dep_info.PT_IMPORT):
replace_str = dep_info.PT_IMPORT
if replace_str is not None:
pytorch_api = api_part_name.replace(
replace_str, dep_info.PT_DEPENDENCY, 1)
if "torch2paddle" in pytorch_api:
# 说明当前节点是插入的已经替换过的node
pytorch_api = None
break
elif isinstance(dep_info, ast.Assign):
is_customized = False
for s in astor.to_source(dep_info.targets[0]).split(","):
if api_part_name.split(".")[0] == s.strip():
is_customized = True
break
if is_customized:
break
return pytorch_api, dep_info
def _rename(self, name, dep_info, pytorch_api, paddle_api):
""" 对函数名进行重命名。
例如:将nn.Conv2d替换为nn.Conv2D。
"""
pytorch_api_seg = pytorch_api.split(dep_info.PT_IMPORT)
if ".models." in paddle_api:
self.is_import_x2paddle = True
if paddle_api.startswith(dep_info.PD_IMPORT + ".") or \
paddle_api.endswith("." + dep_info.PD_IMPORT) or \
"." + dep_info.PD_IMPORT + "." in paddle_api:
paddle_api_seg = paddle_api.split(dep_info.PD_IMPORT)
if dep_info.AS is None:
name = name.replace(dep_info.PT_IMPORT + pytorch_api_seg[-1],
dep_info.PD_IMPORT + paddle_api_seg[-1])
else:
name = name.replace(pytorch_api_seg[-1], paddle_api_seg[-1])
elif "torch2paddle." in paddle_api:
name = "torch2paddle." + paddle_api.split("torch2paddle.")[-1]
self.is_import_torch2paddle = True
else:
name = paddle_api
return name
def run(self):
self.scopes_and_dependencies.append(self.root)
self.visit(self.root)
for i, node in enumerate(self.root.body):
if isinstance(node, ast.Import) or isinstance(node, ast.ImportFrom):
if self.is_import_torch2paddle:
self.root.body.insert(
i,
ast.parse("from x2paddle import torch2paddle").body[0])
if self.is_import_x2paddle:
self.root.body.insert(i,
ast.parse("import x2paddle").body[0])
if self.is_import_paddle:
self.root.body.insert(i, ast.parse("import paddle").body[0])
break
def visit(self, node):
self.nodes.append(node)
out = super(AstUpdater, self).visit(node)
self.nodes.pop()
if out is not None:
return out
else:
# 出现字符串或者if等节点需要返回字符串
try:
return astor.to_source(node)
except Exception:
return None
def visit_ImportFrom(self, node):
""" 1. 遍历子节点。
2. 将当前from依赖中的多个import拆分成多个import。
例如:from torch import nn, utils 这个node
拆分为:node1:from torch import nn
node2:from torch import utils
拆分原因:
在paddle中父依赖包可能不一致。
"""
scope_node = self._get_scope_node()
current_id = self._get_current_index(scope_node, node)
scope_node.body.pop(current_id)
son_nodes = node.names
for i, son_node in enumerate(son_nodes):
copy_node = copy.deepcopy(node)
copy_node.names = [son_node]
if i == 0:
is_remove = self.visit_alias(son_node, copy_node, node.module,
node.level)
if not is_remove:
scope_node.body.insert(current_id, copy_node)
else:
scope_node.body.insert(current_id + i, copy_node)
def visit_Import(self, node):
""" 遍历子节点。
"""
son_nodes = getattr(node, "names")
for son_node in son_nodes:
self.visit_alias(son_node, node)
def visit_alias(self,
node,
father_node=None,
from_name=None,
from_level=None):
""" 构建DepInfo并将其放入scopes_and_dependencies。
如果import字符串为“*”,获取依赖包所在文件的依赖信息并转换为DepInfo加入当前的scopes_and_dependencies;
反之,直接在scopes_and_dependencies中加入DepInfo。
"""
is_remove = False
dep_info = DepInfo()
dep_info.PT_FROM = from_name
dep_info.PT_IMPORT = getattr(node, "name")
dep_info.AS = getattr(node, "asname", None)
if dep_info.PT_IMPORT == "*":
import_file_path = get_dep_file_path(self.py_file_path, from_level,
from_name)
pytorch_dependencies = self.file_dependencies[import_file_path]
for pytorch_dep_info in pytorch_dependencies:
current_dep_info = DepInfo()
if not isinstance(pytorch_dep_info, str):
current_dep_info.PT_FROM = pytorch_dep_info.FROM
current_dep_info.PT_IMPORT = pytorch_dep_info.IMPORT
current_dep_info.AS = pytorch_dep_info.AS
current_dep_info.PT_DEPENDENCY = pytorch_dep_info.DEPENDENCY
if "torch" in current_dep_info.PT_DEPENDENCY:
if current_dep_info.PT_DEPENDENCY in API_MAPPER:
current_dep_info.PD_DEPENDENCY = \
API_MAPPER[current_dep_info.PT_DEPENDENCY][0]
if current_dep_info.PT_DEPENDENCY == "torch" and \
isinstance(self._get_scope_node(), ast.Module):
self.is_import_paddle = False
if current_dep_info.PT_FROM is not None:
seg = current_dep_info.PD_DEPENDENCY.split(".")
current_dep_info.PD_IMPORT = seg[-1]
current_dep_info.PD_FROM = \
current_dep_info.PD_DEPENDENCY.replace("." + seg[-1], "")
else:
current_dep_info.PD_IMPORT = \
current_dep_info.PD_DEPENDENCY
elif current_dep_info.PT_DEPENDENCY in REMOVE_API:
scope_node = self._get_scope_node()
for i, n in enumerate(scope_node.body):
if father_node == n:
scope_node.body[i] = ast.parse("\n").body
is_remove = True
else:
self.no_support_apis.append(
current_dep_info.PT_DEPENDENCY)
else:
current_dep_info.PD_DEPENDENCY = pytorch_dep_info
self.scopes_and_dependencies.append(current_dep_info)
return is_remove
dependency_str_list = list()
if dep_info.PT_FROM is None and from_level is not None:
dependency_str_list.append("." * from_level)
elif dep_info.PT_FROM is not None:
dependency_str_list.append(dep_info.PT_FROM)
dependency_str_list.append(dep_info.PT_IMPORT)
dep_info.PT_DEPENDENCY = ".".join(dependency_str_list)
if dep_info.PT_DEPENDENCY.startswith("torch"):
if dep_info.PT_DEPENDENCY in API_MAPPER:
dep_info.PD_DEPENDENCY = API_MAPPER[dep_info.PT_DEPENDENCY][0]
if dep_info.PT_DEPENDENCY == "torch":
self.is_import_paddle = False
if dep_info.PT_FROM is not None:
seg = dep_info.PD_DEPENDENCY.split(".")
setattr(node, "name", seg[-1])
setattr(father_node, "module",
dep_info.PD_DEPENDENCY.replace("." + seg[-1], ""))
dep_info.PD_IMPORT = seg[-1]
dep_info.PD_FROM = dep_info.PD_DEPENDENCY.replace(
"." + seg[-1], "")
else:
setattr(node, "name", dep_info.PD_DEPENDENCY)
dep_info.PD_IMPORT = dep_info.PD_DEPENDENCY
elif dep_info.PT_DEPENDENCY in REMOVE_API:
scope_node = self._get_scope_node()
for i, n in enumerate(scope_node.body):
if father_node == n:
scope_node.body[i] = ast.parse("\n").body
is_remove = True
elif dep_info.PT_DEPENDENCY.startswith("torch"):
self.no_support_apis.append(dep_info.PT_DEPENDENCY)
else:
dep_info.PD_DEPENDENCY = dep_info.PT_DEPENDENCY
self.scopes_and_dependencies.append(dep_info)
return is_remove
def visit_Name(self, node):
""" 获取字符串名字。
"""
pytorch_api, dep_info = self._get_complete_api(getattr(node, "id"))
father_node = self._get_father_node()
if pytorch_api in API_MAPPER:
paddle_api = API_MAPPER[pytorch_api][0]
if isinstance(father_node, ast.Call) and getattr(
father_node.func, "id", None) in ("getattr", "setattr",
"hasattr"):
paddle_api = self._rename(paddle_api, dep_info, pytorch_api,
paddle_api)
for i, arg_node in enumerate(father_node.args):
if astor.to_source(arg_node).strip() == getattr(node, "id"):
father_node.args[i] = ast.parse(paddle_api).body[
0].value
return getattr(node, "id")
def visit_Attribute(self, node):
""" 对属性字符串满足以下4种情况时进行替换:
情况1 —— Class A(nn.Module):将nn.Module替换为nn.Layer;
情况2 —— a = (1, 2, nn.Module):将nn.Module替换为nn.Layer;
情况3 —— def a() -> torch.Tensor:将torch.Tensor替换为paddle.Tensor;
情况4 —— def a(x: torch.Tensor):将torch.Tensor替换为paddle.Tensor;
情况5 —— isinstance(a, nn.Module):将nn.Module替换为nn.Layer;
情况6 —— torch.float32:将torch.float32替换为"float32";
"""
value_node = node.value
attr = node.attr
name = self.visit(value_node)
attr_str = name + "." + attr
pytorch_api, dep_info = self._get_complete_api(attr_str)
father_node = self._get_father_node()
if pytorch_api in API_MAPPER:
paddle_api = API_MAPPER[pytorch_api][0]
if isinstance(father_node, ast.ClassDef):
attr_str = self._rename(attr_str, dep_info, pytorch_api,
paddle_api)
if node in father_node.bases:
father_node.bases[0] = ast.parse(attr_str).body[0].value
return attr_str
elif isinstance(father_node, ast.arguments):
attr_str = self._rename(attr_str, dep_info, pytorch_api,
paddle_api)
for i, default_n in enumerate(father_node.defaults):
if default_n == node:
father_node.defaults[i] = ast.parse(attr_str).body[
0].value
return attr_str
elif isinstance(father_node, ast.Tuple):
paddle_api = self._rename(paddle_api, dep_info, pytorch_api,
paddle_api)
for i, elts_node in enumerate(father_node.elts):
if astor.to_source(elts_node).strip() == attr_str:
father_node.elts[i] = ast.parse(paddle_api).body[
0].value
return paddle_api
elif isinstance(father_node, ast.FunctionDef):
paddle_api = self._rename(paddle_api, dep_info, pytorch_api,
paddle_api)
father_node.returns = ast.parse(paddle_api).body[0].value
return paddle_api
elif isinstance(father_node, ast.arg):
attr_str = self._rename(attr_str, dep_info, pytorch_api,
paddle_api)
father_node.annotation = ast.parse(attr_str).body[0].value
return attr_str
elif isinstance(father_node, ast.Call) and getattr(
father_node.func, "id", None) == "isinstance":
paddle_api = self._rename(paddle_api, dep_info, pytorch_api,
paddle_api)
for i, arg_node in enumerate(father_node.args):
if astor.to_source(arg_node).strip() == attr_str:
father_node.args[i] = ast.parse(paddle_api).body[
0].value
return paddle_api
elif not isinstance(father_node, ast.Call):
# 对torch.float32的处理
for k, v in father_node.__dict__.items():
if v == node:
father_node.k = ast.parse(paddle_api).body[0].value
break
return attr_str
elif pytorch_api in REMOVE_API:
if isinstance(
father_node,
(ast.Assign, ast.If, ast.FunctionDef, ast.ClassDef, ast.Call)):
scope_node = self._get_scope_node()
for i, n in enumerate(scope_node.body):
if father_node == n:
scope_node.body.pop(i)
return None
elif isinstance(father_node, ast.BoolOp):
for i, n in enumerate(father_node.values):
if node == n:
father_node.values[i] = ast.parse("False").body[0].value
return None
else:
if isinstance(pytorch_api, str) and pytorch_api.startswith(
"torch"
) and "(" not in pytorch_api and "[" not in pytorch_api:
if not isinstance(father_node, ast.Attribute):
self.no_support_apis.append(pytorch_api)
return attr_str
def visit_Num(self, node):
""" 返回数值。
"""
return getattr(node, "n")
def visit_keyword(self, node):
""" 返回键值对。
【注意】当value是API_MAPPER中的key时,需要替换为API_MAPPER中对应的Paddle API。
"""
key = getattr(node, "arg")
value_node = getattr(node, "value")
value = self.visit(value_node)
if value in API_MAPPER:
value = API_MAPPER[value][0]
elif isinstance(value, str) and value.startswith(
"torch") and "(" not in value and "[" not in value:
self.no_support_apis.append(value)
return {key: value}
def visit_Tuple(self, node):
""" 返回tuple。
"""
elts_nodes = getattr(node, "elts")
elts = list()
for elts_node in elts_nodes:
elts.append(self.visit(elts_node))
elts = tuple(elts)
return elts
def visit_Assign(self, node):
""" 1. 将Assign节点加入scopes_and_dependencies;
2. 遍历Assign节点的子节点。
"""
self.scopes_and_dependencies.append(node)
self.generic_visit(node)
def visit_Call(self, node):
""" 1. 获取原始函数名并更新为新的函数名。
2. 获取args和kwargs。
3. 根据API_MAPPER映射需要更新的操作,对参数进行处理。
4. 如果有前缀代码和后缀代码,则需要添加相应节点。
"""
# 获取函数名
func_node = node.func
if isinstance(func_node, ast.Attribute) and isinstance(func_node.value,
ast.Call):
func_name = None
else:
func_name = self.visit(func_node)
pytorch_api, dep_info = self._get_complete_api(func_name)
if pytorch_api is None:
self.generic_visit(node)
return
if pytorch_api not in API_MAPPER:
if pytorch_api.startswith(
"torch"
) and "[" not in pytorch_api and "(" not in pytorch_api:
self.no_support_apis.append(pytorch_api)
return
paddle_api = API_MAPPER[pytorch_api][0]
func_name = self._rename(func_name, dep_info, pytorch_api, paddle_api)
setattr(node, "func", ast.parse(func_name).body[0].value)
# 获取args
args_nodes = getattr(node, "args")
args_list = list()
for args_node in args_nodes:
args_list.append(self.visit(args_node))
# 获取keywords
keywords_nodes = getattr(node, "keywords")
kw_dict = dict()
for keywords_node in keywords_nodes:
if list(self.visit(keywords_node).keys())[0] is None:
args_list.append("**{}".format(
list(self.visit(keywords_node).values())[0]))
else:
kw_dict.update(self.visit(keywords_node))
if API_MAPPER[pytorch_api][1] is None:
return
target_name = None
father_node = self._get_father_node()
if isinstance(father_node, ast.Assign):
target_node = father_node.targets[0]
target_name = self.visit(target_node)
mapper = API_MAPPER[pytorch_api][1](func_name, pytorch_api, args_list,
kw_dict, target_name)
prefix_insert_codes, new_code, suffix_insert_codes = mapper.run()
scope_node = self._get_scope_node()
if isinstance(ast.parse(new_code).body[0], ast.Assign):
node_index = self._get_current_index(scope_node, node)
scope_node.body[node_index] = ast.parse(
new_code.replace("\n", "")).body[0]
else:
new_call_node = ast.parse(new_code).body[0].value
setattr(node, "func", new_call_node.func) # 修改了fun_name
setattr(node, "args", new_call_node.args)
setattr(node, "keywords", new_call_node.keywords)
for i, n in enumerate(scope_node.body):
if father_node == n:
for code in prefix_insert_codes:
scope_node.body.insert(
i, ast.parse(code.replace("\n", "")).body[0])
i += 1
break
for i, n in enumerate(scope_node.body):
if father_node == n:
j = i + 1
for code in suffix_insert_codes:
scope_node.body.insert(
j, ast.parse(code.replace("\n", "")).body[0])
j += 1
break
def visit_Subscript(self, node):
value_node = node.value
value_name = self.visit(value_node)
pytorch_api, dep_info = self._get_complete_api(value_name)
if pytorch_api in API_MAPPER:
paddle_api = API_MAPPER[pytorch_api][0]
value_name = self._rename(value_name, dep_info, pytorch_api,
paddle_api)
node.value = ast.parse(value_name).body[0]
else:
if isinstance(pytorch_api, str) and pytorch_api.startswith(
"torch") and "(" not in pytorch_api:
self.no_support_apis.append(pytorch_api)
self.visit(node.slice)
self.visit(node.ctx)
def visit_FunctionDef(self, node):
""" 1. 将FunctionDef节点加入scopes_and_dependencies;
2. 遍历FunctionDef节点的子节点;
3. 去除scopes_and_dependencies中FunctionDef节点以及之后的节点。
"""
self.scopes_and_dependencies.append(node)
self.generic_visit(node)
last_node = self.scopes_and_dependencies.pop(-1)
while not isinstance(last_node, ast.FunctionDef):
last_node = self.scopes_and_dependencies.pop(-1)
def visit_ClassDef(self, node):
""" 1. 将ClassDef节点加入scopes_and_dependencies;
2. 遍历ClassDef节点的子节点;
3. 去除scopes_and_dependencies中ClassDef节点以及之后的节点。
"""
self.scopes_and_dependencies.append(node)
self.generic_visit(node)
last_node = self.scopes_and_dependencies.pop(-1)
while not isinstance(last_node, ast.ClassDef):
last_node = self.scopes_and_dependencies.pop(-1)
def visit_If(self, node):
""" 1. 将If节点加入scopes_and_dependencies;
2. 遍历If节点的子节点;
3. 去除scopes_and_dependencies中If节点以及之后的节点。
"""
self.scopes_and_dependencies.append(node)
self.generic_visit(node)
last_node = self.scopes_and_dependencies.pop(-1)
while not isinstance(last_node, ast.If):
last_node = self.scopes_and_dependencies.pop(-1)
def visit_While(self, node):
""" 1. 将While节点加入scopes_and_dependencies;
2. 遍历Try节点的子节点;
3. 去除scopes_and_dependencies中Try节点以及之后的节点。
"""
self.scopes_and_dependencies.append(node)
self.generic_visit(node)
last_node = self.scopes_and_dependencies.pop(-1)
while not isinstance(last_node, ast.While):
last_node = self.scopes_and_dependencies.pop(-1)
def visit_Try(self, node):
""" 1. 将Try节点加入scopes_and_dependencies;
2. 遍历Try节点的子节点;
3. 去除scopes_and_dependencies中Try节点以及之后的节点。
"""
self.scopes_and_dependencies.append(node)
self.generic_visit(node)
last_node = self.scopes_and_dependencies.pop(-1)
while not isinstance(last_node, ast.Try):
last_node = self.scopes_and_dependencies.pop(-1)
def visit_ExtSlice(self, node):
""" 将Index节点替换替换为Num。
"""
dim_nodes = node.dims
for i, dim_node in enumerate(dim_nodes):
if isinstance(dim_node, ast.Index):
dim_nodes[i] = dim_node.value
else:
self.visit(dim_node)
def visit_Str(self, node):
""" 修改模型参数的后缀名。
"""
setattr(node, "s",
node.s.replace(".pth", ".pdiparams").replace(
".pt", ".pdiparams").replace(".ckpt", ".pdiparams"))
def update(py_file_path, file_dependencies):
updater = AstUpdater(py_file_path, file_dependencies)
updater.run()
if len(updater.no_support_apis) > 0:
print("Can not convert the file {}.".format(py_file_path))
print("The unsupported packages or operators are: [{}].".format(
", ".join(set(updater.no_support_apis))))
return None
else:
return updater.root
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import ast
import astor
import os
import os.path as osp
import shutil
import argparse
from six import text_type as _text_type
from .dependency_analyzer import analyze
from .ast_update import update
from .utils import *
def write_file(path, tree):
code = astor.to_source(tree)
code = code.replace("(...)", "...")
code = add_line_continuation_symbol(code)
f = open(path, "w")
f.write(code)
f.close()
def generate_dependencies(folder_path, file_dependencies):
for name in os.listdir(folder_path):
current_path = osp.join(folder_path, name)
if osp.isfile(current_path) and current_path.endswith(".py"):
if current_path in file_dependencies:
continue
analyze(current_path, file_dependencies)
elif osp.isdir(current_path):
generate_dependencies(current_path, file_dependencies)
def convert_code(folder_path, new_folder_path, file_dependencies):
for name in os.listdir(folder_path):
current_path = osp.join(folder_path, name)
new_current_path = osp.join(new_folder_path, name)
if osp.isfile(current_path) and current_path.endswith(".py"):
print(current_path)
root = update(current_path, file_dependencies)
if root is not None:
write_file(new_current_path, root)
elif osp.isdir(current_path):
if not osp.exists(new_current_path):
os.makedirs(new_current_path)
convert_code(current_path, new_current_path, file_dependencies)
elif osp.isfile(current_path) and osp.splitext(current_path)[
-1] in [".pth", ".pt", ".ckpt"]:
continue
elif osp.isfile(current_path) and current_path.endswith(".pyc"):
continue
elif osp.isdir(current_path) and current_path == "__pycache__":
continue
elif osp.isdir(current_path) and current_path == ".ipynb_checkpoints":
continue
else:
shutil.copyfile(current_path, new_current_path)
def convert_params(params_path):
import torch
import paddle
params = torch.load(params_path, map_location=torch.device('cpu'))
new_params = dict()
bn_w_name_list = list()
for k, v in params.items():
if k.endswith(".running_mean"):
new_params[k.replace(".running_mean", "._mean")] = v.detach().numpy(
)
elif k.endswith(".running_var"):
new_params[k.replace(".running_var", "._variance")] = v.detach(
).numpy()
bn_w_name_list.append(k.replace(".running_var", ".weight"))
else:
new_params[k] = v.detach().numpy()
for k, v in new_params.items():
if len(v.shape) == 2 and k.endswith(
".weight") and k not in bn_w_name_list:
new_params[k] = v.T
paddle.save(new_params,
params_path.replace(".pth", ".pdiparams").replace(
".pt", ".pdiparams").replace(".ckpt", ".pdiparams"))
def main(args):
project_path = args.project_dir
save_path = args.save_dir
params_path = args.pretrain_model
if params_path is not None:
params_path = osp.abspath(params_path)
if osp.isdir(params_path):
for file in os.listdir(params_path):
if osp.splitext(file)[-1] in [".pth", ".pt", ".ckpt"]:
convert_params(osp.join(params_path, file))
else:
convert_params(params_path)
project_path = osp.abspath(project_path)
file_dependencies = dict()
sys.path.append(project_path)
generate_dependencies(project_path, file_dependencies)
if not osp.exists(save_path):
os.makedirs(save_path)
convert_code(project_path, save_path, file_dependencies)
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import sys
import os.path as osp
import ast
import astor
from x2paddle.project_convertor.pytorch.mapper import *
import copy
from .utils import get_dep_file_path
class PtDepInfo:
"""
PyTorch依赖包信息。
FROM代表from信息的字符串,例如:torch;
IMPORT代表import信息系的字符串,例如:nn.functional;
AS代表as信息的字符串,例如:F;
DEPENDENCY代表由FROM、IMPORT、AS三者组成的字符串,例如:from torch import nn.functional as F。
"""
FROM = None
IMPORT = None
AS = None
DEPENDENCY = None
class DependencyAnalyzer(ast.NodeVisitor):
""" 获取python文件的依赖信息。
依赖信息由4部分组成:(1)import相关的依赖;(2)赋值;(3)函数;(4)类。
Args:
py_file_path (str): python文件的绝对值路径。
file_dependencies (dict): 当前已经统计的依赖信息,key为python文件的绝对值路径,
value为key文件所对应的依赖信息组成的list。
"""
def __init__(self, py_file_path, file_dependencies):
self.py_file_path = py_file_path
self.file_dependencies = file_dependencies
self.root = ast.parse(open(py_file_path, "rb").read())
self.scopes_and_dependencies = list() # 作用域和依赖组成的stack
self.file_dependencies[self.py_file_path] = list()
def _get_scope_node(self):
""" 获取当前节点的作用域。
"""
scope_node = None
for i in range(len(self.scopes_and_dependencies)):
i = -(i + 1)
sd = self.scopes_and_dependencies[i]
if not isinstance(sd, PtDepInfo) and not isinstance(sd, ast.Assign):
scope_node = sd
break
return scope_node
def run(self):
self.scopes_and_dependencies.append(self.root)
self.visit(self.root)
def visit(self, node):
out = super(DependencyAnalyzer, self).visit(node)
def visit_ImportFrom(self, node):
""" 遍历子节点。
"""
son_nodes = node.names
for son_node in son_nodes:
self.visit_alias(son_node, node.module, node.level)
def visit_Import(self, node):
""" 遍历子节点。
"""
son_nodes = getattr(node, "names")
for son_node in son_nodes:
self.visit_alias(son_node)
def visit_alias(self, node, from_name=None, from_level=None):
""" 构建PtDepInfo并将当前的PtDepInfo放入scopes_and_dependencies。
如果import字符串为“*”,获取依赖包所在文件的依赖信息加入当前的dependencies;
反之,直接在dependencies中加入PtDepInfo。
"""
dep_info = PtDepInfo()
dep_info.FROM = from_name
dep_info.IMPORT = getattr(node, "name")
dep_info.AS = getattr(node, "asname", None)
if dep_info.IMPORT == "*":
import_file_path = get_dep_file_path(self.py_file_path, from_level,
dep_info.FROM)
if import_file_path not in self.file_dependencies:
analyzer = DependencyAnalyzer(import_file_path,
self.file_dependencies)
analyzer.run()
self.file_dependencies[self.py_file_path].extend(
self.file_dependencies[import_file_path])
else:
dependency_str_list = list()
if dep_info.FROM is None and from_level is not None:
dependency_str_list.append("." * from_level)
elif dep_info.FROM is not None:
dependency_str_list.append(dep_info.FROM)
dependency_str_list.append(dep_info.IMPORT)
dep_info.DEPENDENCY = ".".join(dependency_str_list)
self.file_dependencies[self.py_file_path].append(dep_info)
self.scopes_and_dependencies.append(dep_info)
def visit_FunctionDef(self, node):
""" 当作用域为ast的根节点时,把函数名放入dependencies。
"""
if isinstance(self._get_scope_node(), ast.Module):
self.scopes_and_dependencies.append(node)
self.file_dependencies[self.py_file_path].append(node.name)
def visit_ClassDef(self, node):
""" 当作用域为ast的根节点时,把类名放入dependencies。
"""
if isinstance(self._get_scope_node(), ast.Module):
self.scopes_and_dependencies.append(node)
self.file_dependencies[self.py_file_path].append(node.name)
def visit_Assign(self, node):
""" 当作用域为ast的根节点时,把赋值名放入dependencies。
"""
if isinstance(self._get_scope_node(), ast.Module):
self.scopes_and_dependencies.append(node)
for target in node.targets:
if isinstance(target, ast.Tuple):
for ele in target.elts:
self.file_dependencies[self.py_file_path].append(ele.id)
elif isinstance(target, ast.Name):
self.file_dependencies[self.py_file_path].append(target.id)
def analyze(py_file_path, file_dependencies):
analyzer = DependencyAnalyzer(py_file_path, file_dependencies)
analyzer.run()
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from x2paddle.project_convertor.pytorch.api_mapper import *
from x2paddle.utils import *
OPTIMIZER_MAPPER = {
"torch.optim": ["paddle.optimizer", None],
"torch.optim.lr_scheduler.ReduceLROnPlateau":
["paddle.optimizer.lr.ReduceOnPlateau", LRScheculerMapper],
"torch.optim.lr_scheduler.CosineAnnealingLR":
["paddle.optimizer.lr.CosineAnnealingDecay", LRScheculerMapper],
"torch.optim.lr_scheduler.MultiStepLR":
["paddle.optimizer.lr.MultiStepDecay", LRScheculerMapper],
"torch.optim.Adam": ["x2paddle.torch2paddle.Adam", None],
"torch.optim.SGD": ["x2paddle.torch2paddle.Momentum", None]
}
NN_MAPPER = {
# basic
"torch.nn": ["paddle.nn", None],
"torch.nn.Module": ["paddle.nn.Layer", None],
"torch.nn.ModuleList": ["paddle.nn.LayerList", None],
"torch.nn.Sequential": ["paddle.nn.Sequential", None],
"torch.nn.utils": ["paddle.nn.utils", None],
"torch.nn.utils.clip_grad_value_":
["x2paddle.torch2paddle.clip_grad_value_", None],
"torch.nn.utils.spectral_norm":
["x2paddle.torch2paddle.spectral_norm", None],
"torch.nn.Parameter": ["paddle.create_parameter", CreateParamModuleMapper],
"torch.nn.parallel": ["paddle", None],
"torch.nn.DataParallel": ["paddle.DataParallel", DataParallelModuleMapper],
"torch.nn.parallel.DistributedDataParallel":
["paddle.DataParallel", DataParallelModuleMapper],
"torch.nn.functional": ["paddle.nn.functional", None],
# nn_net
"torch.nn.AdaptiveAvgPool1d": ["paddle.nn.AdaptiveAvgPool1D", None],
"torch.nn.AdaptiveAvgPool2d": ["paddle.nn.AdaptiveAvgPool2D", None],
"torch.nn.AdaptiveAvgPool3d": ["paddle.nn.AdaptiveAvgPool3D", None],
"torch.nn.AvgPool1d": ["paddle.nn.AvgPool1D", AvgPoolModuleMapper],
"torch.nn.AvgPool2d": ["paddle.nn.AvgPool2D", AvgPoolModuleMapper],
"torch.nn.AvgPool3d": ["paddle.nn.AvgPool3D", AvgPoolModuleMapper],
"torch.nn.BatchNorm1d": ["paddle.nn.BatchNorm1D", BatchNormModuleMapper],
"torch.nn.BatchNorm2d": ["paddle.nn.BatchNorm2D", BatchNormModuleMapper],
"torch.nn.BatchNorm3d": ["paddle.nn.BatchNorm3D", BatchNormModuleMapper],
"torch.nn.ConstantPad2d": ["paddle.nn.Pad2D", PadModuleMapper],
"torch.nn.Conv1d": ["paddle.nn.Conv1D", ConvModuleMapper],
"torch.nn.Conv2d": ["paddle.nn.Conv2D", ConvModuleMapper],
"torch.nn.Conv3d": ["paddle.nn.Conv3D", ConvModuleMapper],
"torch.nn.ConvTranspose2d":
["x2paddle.torch2paddle.Conv2DTranspose", None],
"torch.nn.Dropout": ["paddle.nn.Dropout", DropoutModuleMapper],
"torch.nn.Dropout2d": ["paddle.nn.Dropout", DropoutModuleMapper],
"torch.nn.Embedding": ["paddle.nn.Embedding", EmbeddingModuleMapper],
"torch.nn.GELU": ["paddle.nn.GELU", None],
"torch.nn.GroupNorm": ["paddle.nn.GroupNorm", None],
"torch.nn.Identity": ["x2paddle.torch2paddle.Identity", None],
"torch.nn.InstanceNorm2d":
["paddle.nn.InstanceNorm2D", BatchNormModuleMapper],
"torch.nn.LeakyReLU": ["paddle.nn.LeakyReLU", None],
"torch.nn.LayerNorm": ["paddle.nn.LayerNorm", BatchNormModuleMapper],
"torch.nn.Linear": ["paddle.nn.Linear", LinearModuleMapper],
"torch.nn.MaxPool1d": ["paddle.nn.MaxPool1D", MaxPoolModuleMapper],
"torch.nn.MaxPool2d": ["paddle.nn.MaxPool2D", MaxPoolModuleMapper],
"torch.nn.MaxPool3d": ["paddle.nn.MaxPool3D", MaxPoolModuleMapper],
"torch.nn.MaxUnpool2d": ["x2paddle.torch2paddle.MaxUnpool2d", None],
"torch.nn.ReflectionPad2d": ["paddle.nn.Pad2D", PadModuleMapper],
"torch.nn.ReplicationPad2d": ["paddle.nn.Pad2D", PadModuleMapper],
"torch.nn.PReLU": ["paddle.nn.PReLU", None],
"torch.nn.ReLU": ["paddle.nn.ReLU", ReLUModuleMapper],
"torch.nn.ReLU6": ["paddle.nn.ReLU6", ReLUModuleMapper],
"torch.nn.Sigmoid": ["paddle.nn.Sigmoid", None],
"torch.nn.Softmax": ["paddle.nn.Softmax", SoftmaxModuleMapper],
"torch.nn.SyncBatchNorm":
["paddle.nn.SyncBatchNorm", BatchNormModuleMapper],
"torch.nn.Tanh": ["paddle.nn.Tanh", None],
"torch.nn.Upsample": ["paddle.nn.Upsample", None],
"torch.nn.ZeroPad2d": ["paddle.nn.Pad2D", PadModuleMapper],
# nn_loss
"torch.nn.CrossEntropyLoss":
["paddle.nn.CrossEntropyLoss", LossModuleMapper],
"torch.nn.BCEWithLogitsLoss":
["paddle.nn.BCEWithLogitsLoss", LossModuleMapper],
"torch.nn.BCELoss": ["paddle.nn.BCELoss", None],
"torch.nn.KLDivLoss": ["x2paddle.torch2paddle.KLDivLoss", None],
"torch.nn.L1Loss": ["paddle.nn.loss.L1Loss", LossModuleMapper],
# functional_net
"torch.nn.functional.avg_pool1d":
["paddle.nn.functional.avg_pool1d", AvgPoolFuncMapper],
"torch.nn.functional.avg_pool2d":
["paddle.nn.functional.avg_pool2d", AvgPoolFuncMapper],
"torch.nn.functional.avg_pool3d":
["paddle.nn.functional.avg_pool3d", AvgPoolFuncMapper],
"torch.nn.functional.dropout":
["paddle.nn.functional.dropout", DropoutFuncMapper],
"torch.nn.functional.interpolate":
["paddle.nn.functional.interpolate", InterpolateFuncMapper],
"torch.nn.functional.leaky_relu":
["paddle.nn.functional.leaky_relu", LeaklyReluFuncMapper],
"torch.nn.functional.log_softmax":
["paddle.nn.functional.log_softmax", LogSoftmaxFuncMapper],
"torch.nn.functional.pad": ["paddle.nn.functional.pad", PadFuncMapper],
"torch.nn.functional.relu": ["paddle.nn.functional.relu", ReluFuncMapper],
"torch.sigmoid": ["paddle.nn.functional.sigmoid", SigmoidFuncMapper],
"torch.nn.functional.sigmoid":
["paddle.nn.functional.sigmoid", SigmoidFuncMapper],
"torch.nn.functional.softmax":
["paddle.nn.functional.softmax", SoftmaxFuncMapper],
"torch.nn.functional.tanh": ["paddle.tanh", None],
# init
"torch.nn.init": ["x2paddle.torch2paddle", None],
"torch.nn.init.kaiming_normal_":
["x2paddle.torch2paddle.kaiming_normal_", None],
"torch.nn.init.kaiming_normal":
["x2paddle.torch2paddle.kaiming_normal_", None],
"torch.nn.init.xavier_uniform_":
["x2paddle.torch2paddle.xavier_normal_", None],
"torch.nn.init.xavier_normal_":
["x2paddle.torch2paddle.xavier_uniform_", None],
"torch.nn.init.constant_": ["x2paddle.torch2paddle.constant_init_", None],
"torch.nn.init.normal_": ["x2paddle.torch2paddle.normal_init_", None],
"torch.nn.init.ones_": ["x2paddle.torch2paddle.ones_init_", None],
"torch.nn.init.zeros_": ["x2paddle.torch2paddle.zeros_init_", None],
"torch.nn.init.orthogonal_":
["x2paddle.torch2paddle.normal_init_", None], # syf(TODO)
# functional_loss
"torch.nn.functional.binary_cross_entropy_with_logits":
["x2paddle.torch2paddle.binary_cross_entropy_with_logits", None],
"torch.nn.functional.cross_entropy":
["paddle.nn.functional.cross_entropy", CrossEntropyFuncMapper],
"torch.nn.functional.mse_loss":
["paddle.nn.functional.mse_loss", LossFuncMapper],
"torch.nn.functional.smooth_l1_loss":
["paddle.nn.functional.smooth_l1_loss", LossFuncMapper],
}
UTILS_MAPPER = {
"torch.utils.data": ["paddle.io", None],
"torch.utils.data.DataLoader": ["x2paddle.torch2paddle.DataLoader", None],
"torch.utils.data.random_split":
["x2paddle.torch2paddle.random_split", None],
"torch.utils.data.Dataset": ["paddle.io.Dataset", None],
"torch.utils.data.ConcatDataset":
["x2paddle.torch2paddle.ConcatDataset", None],
"torch.utils.data.distributed": ["x2paddle.torch2paddle", None],
"torch.utils.data.distributed.DistributedSampler":
["x2paddle.torch2paddle.DistributedSampler", None],
"torch.utils.model_zoo": ["paddle", None],
"torch.utils.model_zoo.load_url": ["paddle.load", HubLoadMapper],
}
DIST_MAPPER = {
"torch.multiprocessing": ["paddle.distributed", None],
"torch.multiprocessing.spawn": ["paddle.distributed.spawn", None],
"torch.distributed": ["x2paddle.torch2paddle", None],
"torch.distributed.init_process_group":
["x2paddle.torch2paddle.init_process_group", None]
}
DTYPE_MAPPER = {
"torch.float32": [string("float32"), None],
"torch.long": [string("int64"), None],
"torch.bool": [string("bool"), None]
}
TORCHVISION_MAPPER = {
"torchvision": ["paddle.vision", None],
# transforms
"torchvision.transforms": ["paddle.vision.transforms", None],
"torchvision.transforms.Compose":
["paddle.vision.transforms.Compose", None],
"torchvision.transforms.ToPILImage":
["x2paddle.torch2paddle.ToPILImage", None],
"torchvision.transforms.Resize": ["paddle.vision.transforms.Resize", None],
"torchvision.transforms.ToTensor":
["x2paddle.torch2paddle.ToTensor", None],
"torchvision.transforms.RandomHorizontalFlip":
["paddle.vision.transforms.RandomHorizontalFlip", None],
"torchvision.transforms.CenterCrop":
["paddle.vision.transforms.CenterCrop", None],
"torchvision.transforms.Normalize":
["x2paddle.torch2paddle.Normalize", None],
"torchvision.transforms.RandomResizedCrop":
["paddle.vision.transforms.RandomResizedCrop", None],
"torchvision.transforms.Lambda": ["x2paddle.torch2paddle.Lambda", None],
# utils
"torchvision.utils": ["x2paddle.torch2paddle", None],
"torchvision.utils.save_image": ["x2paddle.torch2paddle.save_image", None],
# datasets
"torchvision.datasets": ["paddle.vision.datasets", None],
"torchvision.datasets.ImageFolder":
["x2paddle.torch2paddle.ImageFolder", None],
# models
"torchvision.models": ["x2paddle.models", None],
"torchvision.models.vgg.model_urls":
["x2paddle.models.vgg_pth_urls", None],
"torchvision.models.vgg11": ["x2paddle.models.vgg11_pth", None],
"torchvision.models.vgg13": ["x2paddle.models.vgg13_pth", None],
"torchvision.models.vgg16": ["x2paddle.models.vgg16_pth", None],
"torchvision.models.vgg19": ["x2paddle.models.vgg19_pth", None],
"torchvision.models.vgg11_bn": ["x2paddle.models.vgg11_bn_pth", None],
"torchvision.models.vgg13_bn": ["x2paddle.models.vgg13_bn_pth", None],
"torchvision.models.vgg16_bn": ["x2paddle.models.vgg16_bn_pth", None],
"torchvision.models.vgg19_bn": ["x2paddle.models.vgg19_bn_pth", None],
"torchvision.models.resnet.model_urls":
["x2paddle.models.resnet_pth_urls", None],
"torchvision.models.resnet18": ["x2paddle.models.resnet18_pth", None],
"torchvision.models.resnet34": ["x2paddle.models.resnet34_pth", None],
"torchvision.models.resnet50": ["x2paddle.models.resnet50_pth", None],
"torchvision.models.resnet101": ["x2paddle.models.resnet101_pth", None],
"torchvision.models.resnet152": ["x2paddle.models.resnet152_pth", None],
"torchvision.models.resnext50_32x4d":
["x2paddle.models.resnext50_32x4d_pth", None],
"torchvision.models.resnext101_32x8d":
["x2paddle.models.resnext101_32x8d_pth", None],
"torchvision.models.wide_resnet50_2":
["x2paddle.models.wide_resnet50_2_pth", None],
"torchvision.models.wide_resnet101_2":
["x2paddle.models.wide_resnet101_2_pth", None],
}
AUTOGRAD_MAPPER = {
"torch.autograd.Variable": ["paddle.to_tensor", None], # TODO(syf): 确认是否一致
"torch.autograd.grad": ["paddle.grad", None],
}
API_MAPPER = {
"torch": ["paddle", None],
"torch.Tensor": ["x2paddle.torch2paddle.create_tensor", None],
"torch.FloatTensor": ["x2paddle.torch2paddle.create_float32_tensor", None],
"torch.cuda.FloatTensor":
["x2paddle.torch2paddle.create_float32_tensor", None],
"torch.ByteTensor": ["x2paddle.torch2paddle.create_uint8_tensor", None],
"torch.cuda.ByteTensor":
["x2paddle.torch2paddle.create_uint8_tensor", None],
"torch.load": ["paddle.load", LoadMapper],
"torch.save": ["paddle.save", SaveMapper],
"torch.device": ["paddle.set_device", SetDeviceMapper],
"torch.cat": ["x2paddle.torch2paddle.concat", None],
"torch.cuda.is_available": ["paddle.is_compiled_with_cuda", None],
"torch.cuda.set_device": ["x2paddle.torch2paddle.set_cuda_device", None],
"torch.no_grad": ["paddle.no_grad", None],
"torch.from_numpy": ["paddle.to_tensor", None],
"torch.cuda.device_count": ["x2paddle.torch2paddle.device_count", None],
"torch.manual_seed": ["paddle.seed", None],
"torch.unsqueeze": ["paddle.unsqueeze", UnSqueezeMapper],
"torch.squeeze": ["paddle.squeeze", UnSqueezeMapper],
"torch.sum": ["x2paddle.torch2paddle.sum", None],
"torch.mean": ["x2paddle.torch2paddle.mean", None],
"torch.full": ["paddle.full", TensorBuilderMapper],
"torch.full_like": ["paddle.full_like", TensorLikeMapper],
"torch.ones": ["paddle.ones", TensorBuilderMapper],
"torch.ones_like": ["paddle.full_like", TensorLikeMapper],
"torch.zeros": ["paddle.zeros", TensorBuilderMapper],
"torch.zeros_like": ["paddle.full_like", TensorLikeMapper],
"torch.sqrt": ["paddle.sqrt", OneMathMapper],
"torch.arange": ["paddle.arange", ArangeMapper],
"torch.matmul": ["paddle.matmul", TwoMathMapper],
"torch.set_grad_enabled": ["paddle.no_grad", NoGradMapper],
"torch.tensor": ["paddle.to_tensor", None],
"torch.clamp": ["paddle.clip", OneMathMapper],
"torch.exp": ["paddle.exp", OneMathMapper],
"torch.max": ["x2paddle.torch2paddle.max", None],
"torch.min": ["x2paddle.torch2paddle.min", None],
"torch.argmax": ["paddle.argmax", OneMathMapper],
"torch.argmin": ["paddle.argmin", OneMathMapper],
"torch.stack": ["paddle.stacks", StackMapper],
"torch.log": ["paddle.log", OneMathMapper],
"torch.randperm": ["paddle.randperm", RandpermMapper],
"torch.rand": ["x2paddle.torch2paddle.rand", None],
"torch.randn_like": ["x2paddle.torch2paddle.randn_like", None],
"torch.abs": ["paddle.abs", OneMathMapper],
"torch.bitwise_or": ["paddle.logical_or", LogicalMapper],
"torch.bitwise_xor": ["paddle.logical_xor", LogicalMapper],
"torch.bitwise_and": ["paddle.logical_and", LogicalMapper],
"torch.bitwise_not": ["paddle.logical_not", LogicalMapper],
"torch.split": ["paddle.split", SplitMapper],
"torch.hub.load_state_dict_from_url": ["paddle.load", HubLoadMapper],
"torch.randn": ["x2paddle.torch2paddle.randn", None],
"torch.add": ["paddle.add", TwoMathMapper],
"torch.mul": ["paddle.multiply", TwoMathMapper],
"torch.einsum": ["paddlenlp.ops.einsum ", None],
"torch.linspace": ["paddle.linspace", LinspaceMapper],
}
INVALID_API = {
"torch.channels_last": ["None", None],
"torch.cuda.empty_cache": ["x2paddle.torch2paddle.invalid", None],
}
API_MAPPER.update(OPTIMIZER_MAPPER)
API_MAPPER.update(NN_MAPPER)
API_MAPPER.update(UTILS_MAPPER)
API_MAPPER.update(DTYPE_MAPPER)
API_MAPPER.update(DIST_MAPPER)
API_MAPPER.update(TORCHVISION_MAPPER)
API_MAPPER.update(AUTOGRAD_MAPPER)
API_MAPPER.update(INVALID_API)
REMOVE_API = [
"torch.backends.cudnn",
"torch.backends.cudnn.benchmark",
"torch.backends.cudnn.enabled",
"torch.backends.cudnn.deterministic",
]
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from . import vgg
from . import resnet
from .vgg import *
from .resnet import *
__all__ = vgg.__all__
__all__.extend(resnet.__all__)
import paddle
import paddle.nn as nn
from paddle import Tensor
from paddle.utils.download import get_weights_path_from_url
from typing import Type, Any, Callable, Union, List, Optional
from x2paddle import torch2paddle
__all__ = [
'ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', 'resnet152',
'resnext50_32x4d', 'resnext101_32x8d', 'wide_resnet50_2', 'wide_resnet101_2'
]
model_urls = {
'resnet18':
'https://x2paddle.bj.bcebos.com/vision/models/resnet18-pt.pdparams',
'resnet34':
'https://x2paddle.bj.bcebos.com/vision/models/resnet34-pt.pdparams',
'resnet50':
'https://x2paddle.bj.bcebos.com/vision/models/resnet50-pt.pdparams',
'resnet101':
'https://x2paddle.bj.bcebos.com/vision/models/resnet101-pt.pdparams',
'resnet152':
'https://x2paddle.bj.bcebos.com/vision/models/resnet152-pt.pdparams',
'resnext50_32x4d':
'https://x2paddle.bj.bcebos.com/vision/models/resnext50_32x4d-pt.pdparams',
'resnext101_32x8d':
'https://x2paddle.bj.bcebos.com/vision/models/resnext101_32x8d-pt.pdparams',
'wide_resnet50_2':
'https://x2paddle.bj.bcebos.com/vision/models/wide_resnet50_2-pt.pdparams',
'wide_resnet101_2':
'https://x2paddle.bj.bcebos.com/vision/models/wide_resnet101_2-pt.pdparams',
}
def conv3x3(in_planes: int,
out_planes: int,
stride: int=1,
groups: int=1,
dilation: int=1) -> nn.Conv2D:
"""3x3 convolution with padding"""
return nn.Conv2D(
in_planes,
out_planes,
kernel_size=3,
stride=stride,
padding=dilation,
groups=groups,
bias_attr=False,
dilation=dilation)
def conv1x1(in_planes: int, out_planes: int, stride: int=1) -> nn.Conv2D:
"""1x1 convolution"""
return nn.Conv2D(
in_planes, out_planes, kernel_size=1, stride=stride, bias_attr=False)
class BasicBlock(nn.Layer):
expansion: int = 1
def __init__(self,
inplanes: int,
planes: int,
stride: int=1,
downsample: Optional[nn.Layer]=None,
groups: int=1,
base_width: int=64,
dilation: int=1,
norm_layer: Optional[Callable[..., nn.Layer]]=None) -> None:
super(BasicBlock, self).__init__()
if norm_layer is None:
norm_layer = nn.BatchNorm2d
if groups != 1 or base_width != 64:
raise ValueError(
'BasicBlock only supports groups=1 and base_width=64')
if dilation > 1:
raise NotImplementedError(
"Dilation > 1 not supported in BasicBlock")
# Both self.conv1 and self.downsample layers downsample the input when stride != 1
self.conv1 = conv3x3(inplanes, planes, stride)
self.bn1 = norm_layer(planes)
self.relu = nn.ReLU()
self.conv2 = conv3x3(planes, planes)
self.bn2 = norm_layer(planes)
self.downsample = downsample
self.stride = stride
def forward(self, x: Tensor) -> Tensor:
identity = x
out = self.conv1(x)
out = self.bn1(out)
out = self.relu(out)
out = self.conv2(out)
out = self.bn2(out)
if self.downsample is not None:
identity = self.downsample(x)
out += identity
out = self.relu(out)
return out
class Bottleneck(nn.Layer):
# Bottleneck in torchvision places the stride for downsampling at 3x3 convolution(self.conv2)
# while original implementation places the stride at the first 1x1 convolution(self.conv1)
# according to "Deep residual learning for image recognition"https://arxiv.org/abs/1512.03385.
# This variant is also known as ResNet V1.5 and improves accuracy according to
# https://ngc.nvidia.com/catalog/model-scripts/nvidia:resnet_50_v1_5_for_pytorch.
expansion: int = 4
def __init__(self,
inplanes: int,
planes: int,
stride: int=1,
downsample: Optional[nn.Layer]=None,
groups: int=1,
base_width: int=64,
dilation: int=1,
norm_layer: Optional[Callable[..., nn.Layer]]=None) -> None:
super(Bottleneck, self).__init__()
if norm_layer is None:
norm_layer = nn.BatchNorm2D
width = int(planes * (base_width / 64.)) * groups
# Both self.conv2 and self.downsample layers downsample the input when stride != 1
self.conv1 = conv1x1(inplanes, width)
self.bn1 = norm_layer(width)
self.conv2 = conv3x3(width, width, stride, groups, dilation)
self.bn2 = norm_layer(width)
self.conv3 = conv1x1(width, planes * self.expansion)
self.bn3 = norm_layer(planes * self.expansion)
self.relu = nn.ReLU()
self.downsample = downsample
self.stride = stride
def forward(self, x: Tensor) -> Tensor:
identity = x
out = self.conv1(x)
out = self.bn1(out)
out = self.relu(out)
out = self.conv2(out)
out = self.bn2(out)
out = self.relu(out)
out = self.conv3(out)
out = self.bn3(out)
if self.downsample is not None:
identity = self.downsample(x)
out += identity
out = self.relu(out)
return out
class ResNet(nn.Layer):
def __init__(self,
block: Type[Union[BasicBlock, Bottleneck]],
layers: List[int],
num_classes: int=1000,
zero_init_residual: bool=False,
groups: int=1,
width_per_group: int=64,
replace_stride_with_dilation: Optional[List[bool]]=None,
norm_layer: Optional[Callable[..., nn.Layer]]=None) -> None:
super(ResNet, self).__init__()
if norm_layer is None:
norm_layer = nn.BatchNorm2D
self._norm_layer = norm_layer
self.inplanes = 64
self.dilation = 1
if replace_stride_with_dilation is None:
# each element in the tuple indicates if we should replace
# the 2x2 stride with a dilated convolution instead
replace_stride_with_dilation = [False, False, False]
if len(replace_stride_with_dilation) != 3:
raise ValueError("replace_stride_with_dilation should be None "
"or a 3-element tuple, got {}".format(
replace_stride_with_dilation))
self.groups = groups
self.base_width = width_per_group
self.conv1 = nn.Conv2D(
3,
self.inplanes,
kernel_size=7,
stride=2,
padding=3,
bias_attr=False)
self.bn1 = norm_layer(self.inplanes)
self.relu = nn.ReLU()
self.maxpool = nn.MaxPool2D(kernel_size=3, stride=2, padding=1)
self.layer1 = self._make_layer(block, 64, layers[0])
self.layer2 = self._make_layer(
block,
128,
layers[1],
stride=2,
dilate=replace_stride_with_dilation[0])
self.layer3 = self._make_layer(
block,
256,
layers[2],
stride=2,
dilate=replace_stride_with_dilation[1])
self.layer4 = self._make_layer(
block,
512,
layers[3],
stride=2,
dilate=replace_stride_with_dilation[2])
self.avgpool = nn.AdaptiveAvgPool2D((1, 1))
self.fc = nn.Linear(512 * block.expansion, num_classes)
for m in self.sublayers():
if isinstance(m, nn.Conv2D):
torch2paddle.kaiming_normal_(
m.weight, mode='fan_out', nonlinearity='relu')
elif isinstance(m, (nn.BatchNorm2D, nn.GroupNorm)):
torch2paddle.constant_init_(m.weight, 1)
torch2paddle.constant_init_(m.bias, 0)
# Zero-initialize the last BN in each residual branch,
# so that the residual branch starts with zeros, and each residual block behaves like an identity.
# This improves the model by 0.2~0.3% according to https://arxiv.org/abs/1706.02677
if zero_init_residual:
for m in self.sublayers():
if isinstance(m, Bottleneck):
torch2paddle.constant_init_(m.bn3.weight,
0) # type: ignore[arg-type]
elif isinstance(m, BasicBlock):
torch2paddle.constant_init_(m.bn2.weight,
0) # type: ignore[arg-type]
def _make_layer(self,
block: Type[Union[BasicBlock, Bottleneck]],
planes: int,
blocks: int,
stride: int=1,
dilate: bool=False) -> nn.Sequential:
norm_layer = self._norm_layer
downsample = None
previous_dilation = self.dilation
if dilate:
self.dilation *= stride
stride = 1
if stride != 1 or self.inplanes != planes * block.expansion:
downsample = nn.Sequential(
conv1x1(self.inplanes, planes * block.expansion, stride),
norm_layer(planes * block.expansion), )
layers = []
layers.append(
block(self.inplanes, planes, stride, downsample, self.groups,
self.base_width, previous_dilation, norm_layer))
self.inplanes = planes * block.expansion
for _ in range(1, blocks):
layers.append(
block(
self.inplanes,
planes,
groups=self.groups,
base_width=self.base_width,
dilation=self.dilation,
norm_layer=norm_layer))
return nn.Sequential(*layers)
def _forward_impl(self, x: Tensor) -> Tensor:
# See note [TorchScript super()]
x = self.conv1(x)
x = self.bn1(x)
x = self.relu(x)
x = self.maxpool(x)
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
x = self.layer4(x)
x = self.avgpool(x)
x = paddle.flatten(x, 1)
x = self.fc(x)
return x
def forward(self, x: Tensor) -> Tensor:
return self._forward_impl(x)
def _resnet(arch: str,
block: Type[Union[BasicBlock, Bottleneck]],
layers: List[int],
pretrained: bool,
**kwargs: Any) -> ResNet:
model = ResNet(block, layers, **kwargs)
if pretrained:
state_dict = get_weights_path_from_url(model_urls[arch])
model.load_dict(state_dict)
return model
def resnet18(pretrained: bool=False, progress: bool=True,
**kwargs: Any) -> ResNet:
r"""ResNet-18 model from
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_.
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
return _resnet('resnet18', BasicBlock, [2, 2, 2, 2], pretrained, **kwargs)
def resnet34(pretrained: bool=False, progress: bool=True,
**kwargs: Any) -> ResNet:
r"""ResNet-34 model from
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_.
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
return _resnet('resnet34', BasicBlock, [3, 4, 6, 3], pretrained, **kwargs)
def resnet50(pretrained: bool=False, progress: bool=True,
**kwargs: Any) -> ResNet:
r"""ResNet-50 model from
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_.
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
return _resnet('resnet50', Bottleneck, [3, 4, 6, 3], pretrained, **kwargs)
def resnet101(pretrained: bool=False, progress: bool=True,
**kwargs: Any) -> ResNet:
r"""ResNet-101 model from
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_.
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
return _resnet('resnet101', Bottleneck, [3, 4, 23, 3], pretrained, **kwargs)
def resnet152(pretrained: bool=False, progress: bool=True,
**kwargs: Any) -> ResNet:
r"""ResNet-152 model from
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_.
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
return _resnet('resnet152', Bottleneck, [3, 8, 36, 3], pretrained, **kwargs)
def resnext50_32x4d(pretrained: bool=False, progress: bool=True,
**kwargs: Any) -> ResNet:
r"""ResNeXt-50 32x4d model from
`"Aggregated Residual Transformation for Deep Neural Networks" <https://arxiv.org/pdf/1611.05431.pdf>`_.
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
kwargs['groups'] = 32
kwargs['width_per_group'] = 4
return _resnet('resnext50_32x4d', Bottleneck, [3, 4, 6, 3], pretrained,
**kwargs)
def resnext101_32x8d(pretrained: bool=False, progress: bool=True,
**kwargs: Any) -> ResNet:
r"""ResNeXt-101 32x8d model from
`"Aggregated Residual Transformation for Deep Neural Networks" <https://arxiv.org/pdf/1611.05431.pdf>`_.
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
kwargs['groups'] = 32
kwargs['width_per_group'] = 8
return _resnet('resnext101_32x8d', Bottleneck, [3, 4, 23, 3], pretrained,
**kwargs)
def wide_resnet50_2(pretrained: bool=False, progress: bool=True,
**kwargs: Any) -> ResNet:
r"""Wide ResNet-50-2 model from
`"Wide Residual Networks" <https://arxiv.org/pdf/1605.07146.pdf>`_.
The model is the same as ResNet except for the bottleneck number of channels
which is twice larger in every block. The number of channels in outer 1x1
convolutions is the same, e.g. last block in ResNet-50 has 2048-512-2048
channels, and in Wide ResNet-50-2 has 2048-1024-2048.
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
kwargs['width_per_group'] = 64 * 2
return _resnet('wide_resnet50_2', Bottleneck, [3, 4, 6, 3], pretrained,
**kwargs)
def wide_resnet101_2(pretrained: bool=False, progress: bool=True,
**kwargs: Any) -> ResNet:
r"""Wide ResNet-101-2 model from
`"Wide Residual Networks" <https://arxiv.org/pdf/1605.07146.pdf>`_.
The model is the same as ResNet except for the bottleneck number of channels
which is twice larger in every block. The number of channels in outer 1x1
convolutions is the same, e.g. last block in ResNet-50 has 2048-512-2048
channels, and in Wide ResNet-50-2 has 2048-1024-2048.
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
kwargs['width_per_group'] = 64 * 2
return _resnet('wide_resnet101_2', Bottleneck, [3, 4, 23, 3], pretrained,
**kwargs)
import paddle
import paddle.nn as nn
from paddle.utils.download import get_weights_path_from_url
from typing import Union, List, Dict, Any, cast
from x2paddle import torch2paddle
__all__ = [
'VGG',
'vgg11',
'vgg11_bn',
'vgg13',
'vgg13_bn',
'vgg16',
'vgg16_bn',
'vgg19_bn',
'vgg19',
]
model_urls = {
'vgg11': 'https://x2paddle.bj.bcebos.com/vision/models/vgg11-pt.pdparams',
'vgg13': 'https://x2paddle.bj.bcebos.com/vision/models/vgg13-pt.pdparams',
'vgg16': 'https://x2paddle.bj.bcebos.com/vision/models/vgg16-pt.pdparams',
'vgg19': 'https://x2paddle.bj.bcebos.com/vision/models/vgg19-pt.pdparams',
'vgg11_bn':
'https://x2paddle.bj.bcebos.com/vision/models/vgg11_bn-pt.pdparams',
'vgg13_bn':
'https://x2paddle.bj.bcebos.com/vision/models/vgg13_bn-pt.pdparams',
'vgg16_bn':
'https://x2paddle.bj.bcebos.com/vision/models/vgg16_bn-pt.pdparams',
'vgg19_bn':
'https://x2paddle.bj.bcebos.com/vision/models/vgg19_bn-pt.pdparams',
}
class VGG(nn.Layer):
def __init__(self, features, num_classes=1000, init_weights=True):
super(VGG, self).__init__()
self.features = features
self.avgpool = nn.AdaptiveAvgPool2D((7, 7))
self.classifier = nn.Sequential(
nn.Linear(512 * 7 * 7, 4096),
nn.ReLU(),
nn.Dropout(),
nn.Linear(4096, 4096),
nn.ReLU(),
nn.Dropout(),
nn.Linear(4096, num_classes), )
if init_weights:
self._initialize_weights()
def forward(self, x):
x = self.features(x)
x = self.avgpool(x)
x = paddle.flatten(x, 1)
x = self.classifier(x)
return x
def _initialize_weights(self):
for m in self.modules():
if isinstance(m, nn.Conv2D):
torch2paddle.kaiming_normal_(
m.weight, mode='fan_out', nonlinearity='relu')
if m.bias is not None:
torch2paddle.constant_init_(m.bias, 0)
elif isinstance(m, nn.BatchNorm2D):
torch2paddle.constant_init_(m.weight, 1)
torch2paddle.constant_init_(m.bias, 0)
elif isinstance(m, nn.Linear):
torch2paddle.normal_init_(m.weight, 0, 0.01)
torch2paddle.constant_init_(m.bias, 0)
def make_layers(cfg: List[Union[str, int]],
batch_norm: bool=False) -> nn.Sequential:
layers: List[nn.Layer] = []
in_channels = 3
for v in cfg:
if v == 'M':
layers += [nn.MaxPool2D(kernel_size=2, stride=2)]
else:
v = cast(int, v)
conv2d = nn.Conv2D(in_channels, v, kernel_size=3, padding=1)
if batch_norm:
layers += [conv2d, nn.BatchNorm2D(v), nn.ReLU()]
else:
layers += [conv2d, nn.ReLU()]
in_channels = v
return nn.Sequential(*layers)
cfgs: Dict[str, List[Union[str, int]]] = {
'A': [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
'B':
[64, 64, 'M', 128, 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
'D': [
64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512,
512, 512, 'M'
],
'E': [
64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512, 512,
'M', 512, 512, 512, 512, 'M'
],
}
def _vgg(arch: str, cfg: str, batch_norm: bool, pretrained: bool,
**kwargs: Any) -> VGG:
if pretrained:
kwargs['init_weights'] = False
model = VGG(make_layers(cfgs[cfg], batch_norm=batch_norm), **kwargs)
if pretrained:
state_dict = get_weights_path_from_url(model_urls[arch])
model.load_dict(state_dict)
return model
def vgg11(pretrained: bool=False, progress: bool=True, **kwargs: Any) -> VGG:
r"""VGG 11-layer model (configuration "A") from
`"Very Deep Convolutional Networks For Large-Scale Image Recognition" <https://arxiv.org/pdf/1409.1556.pdf>`._
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
return _vgg('vgg11', 'A', False, pretrained, **kwargs)
def vgg11_bn(pretrained: bool=False, progress: bool=True, **kwargs: Any) -> VGG:
r"""VGG 11-layer model (configuration "A") with batch normalization
`"Very Deep Convolutional Networks For Large-Scale Image Recognition" <https://arxiv.org/pdf/1409.1556.pdf>`._
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
return _vgg('vgg11_bn', 'A', True, pretrained, **kwargs)
def vgg13(pretrained: bool=False, progress: bool=True, **kwargs: Any) -> VGG:
r"""VGG 13-layer model (configuration "B")
`"Very Deep Convolutional Networks For Large-Scale Image Recognition" <https://arxiv.org/pdf/1409.1556.pdf>`._
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
return _vgg('vgg13', 'B', False, pretrained, **kwargs)
def vgg13_bn(pretrained: bool=False, progress: bool=True, **kwargs: Any) -> VGG:
r"""VGG 13-layer model (configuration "B") with batch normalization
`"Very Deep Convolutional Networks For Large-Scale Image Recognition" <https://arxiv.org/pdf/1409.1556.pdf>`._
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
return _vgg('vgg13_bn', 'B', True, pretrained, **kwargs)
def vgg16(pretrained: bool=False, progress: bool=True, **kwargs: Any) -> VGG:
r"""VGG 16-layer model (configuration "D")
`"Very Deep Convolutional Networks For Large-Scale Image Recognition" <https://arxiv.org/pdf/1409.1556.pdf>`._
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
return _vgg('vgg16', 'D', False, pretrained, **kwargs)
def vgg16_bn(pretrained: bool=False, progress: bool=True, **kwargs: Any) -> VGG:
r"""VGG 16-layer model (configuration "D") with batch normalization
`"Very Deep Convolutional Networks For Large-Scale Image Recognition" <https://arxiv.org/pdf/1409.1556.pdf>`._
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
return _vgg('vgg16_bn', 'D', True, pretrained, **kwargs)
def vgg19(pretrained: bool=False, progress: bool=True, **kwargs: Any) -> VGG:
r"""VGG 19-layer model (configuration "E")
`"Very Deep Convolutional Networks For Large-Scale Image Recognition" <https://arxiv.org/pdf/1409.1556.pdf>`._
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
return _vgg('vgg19', 'E', False, pretrained, **kwargs)
def vgg19_bn(pretrained: bool=False, progress: bool=True, **kwargs: Any) -> VGG:
r"""VGG 19-layer model (configuration 'E') with batch normalization
`"Very Deep Convolutional Networks For Large-Scale Image Recognition" <https://arxiv.org/pdf/1409.1556.pdf>`._
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
return _vgg('vgg19_bn', 'E', True, pretrained, **kwargs)
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from .io import *
from .layer import *
from .tensor import *
from .optimizer import *
from .nn import *
from .nn_utils import *
from .nn_functional import *
from .nn_init import *
from .varbase import *
from .vision_transforms import *
from .device import *
from .vision_utils import *
from .vision_datasets import *
from .ops import *
from .learning_rate_scheduler import *
from .parambase import *
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import paddle
def device_count():
gpu_useful = paddle.get_device().startswith("gpu")
if gpu_useful:
device_str = os.environ["CUDA_VISIBLE_DEVICES"]
seg = device_str.split(",")
return len(seg)
else:
return 0
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import paddle
def init_process_group(backend,
init_method=None,
timeout=datetime.timedelta(0, 1800),
world_size=-1,
rank=-1,
store=None,
group_name=''):
paddle.distributed.init_parallel_env()
os.environ['PADDLE_TRAINERS_NUM'] = world_size if world_size > 0 else 1
os.environ['PADDLE_TRAINER_ID'] = rank if rank > 0 else 1
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from paddle.io import Dataset, IterableDataset
import paddle
import warnings
import bisect
class ConcatDataset(Dataset):
r"""Dataset as a concatenation of multiple datasets.
This class is useful to assemble different existing datasets.
Arguments:
datasets (sequence): List of datasets to be concatenated
"""
@staticmethod
def cumsum(sequence):
r, s = [], 0
for e in sequence:
l = len(e)
r.append(l + s)
s += l
return r
def __init__(self, datasets):
super(ConcatDataset, self).__init__()
assert len(datasets) > 0, 'datasets should not be an empty iterable'
self.datasets = list(datasets)
for d in self.datasets:
assert not isinstance(
d, IterableDataset
), "ConcatDataset does not support IterableDataset"
self.cumulative_sizes = self.cumsum(self.datasets)
def __len__(self):
return self.cumulative_sizes[-1]
def __getitem__(self, idx):
if idx < 0:
if -idx > len(self):
raise ValueError(
"absolute value of index should not exceed dataset length")
idx = len(self) + idx
dataset_idx = bisect.bisect_right(self.cumulative_sizes, idx)
if dataset_idx == 0:
sample_idx = idx
else:
sample_idx = idx - self.cumulative_sizes[dataset_idx - 1]
return self.datasets[dataset_idx][sample_idx]
@property
def cummulative_sizes(self):
warnings.warn(
"cummulative_sizes attribute is renamed to "
"cumulative_sizes",
DeprecationWarning,
stacklevel=2)
return self.cumulative_sizes
def _accumulate(iterable, fn=lambda x, y: x + y):
# _accumulate([1,2,3,4,5]) --> 1 3 6 10 15
# _accumulate([1,2,3,4,5], operator.mul) --> 1 2 6 24 120
it = iter(iterable)
try:
total = next(it)
except StopIteration:
return
yield total
for element in it:
total = fn(total, element)
yield total
class Subset(Dataset):
r"""
Subset of a dataset at specified indices.
Arguments:
dataset (Dataset): The whole Dataset
indices (sequence): Indices in the whole set selected for subset
"""
def __init__(self, dataset, indices):
self.dataset = dataset
self.indices = indices
def __getitem__(self, idx):
return self.dataset[self.indices[idx]]
def __len__(self):
return len(self.indices)
def random_split(dataset, lengths, generator=None):
r"""
Randomly split a dataset into non-overlapping new datasets of given lengths.
Optionally fix the generator for reproducible results, e.g.:
>>> random_split(range(10), [3, 7], generator=torch.Generator().manual_seed(42))
Arguments:
dataset (Dataset): Dataset to be split
lengths (sequence): lengths of splits to be produced
generator (Generator): from torch import default_generator, which is not use in paddle.
"""
if sum(lengths) != len(dataset):
raise ValueError(
"Sum of input lengths does not equal the length of the input dataset!"
)
indices = paddle.randperm(sum(lengths))
return [
Subset(dataset, indices[offset - length:offset])
for offset, length in zip(_accumulate(lengths), lengths)
]
setattr(paddle.io, "random_split", random_split)
class DataLoader(paddle.io.DataLoader):
def __init__(self,
dataset,
batch_size=1,
shuffle=False,
sampler=None,
batch_sampler=None,
num_workers=0,
collate_fn=None,
pin_memory=False,
drop_last=False,
timeout=0,
worker_init_fn=None,
multiprocessing_context=None,
generator=None):
if isinstance(dataset[0], (tuple, list)):
return_list = True
else:
return_list = False
return_list = True
super().__init__(
dataset,
feed_list=None,
places=None,
return_list=return_list,
batch_sampler=batch_sampler,
batch_size=batch_size,
shuffle=shuffle,
drop_last=drop_last,
collate_fn=collate_fn,
num_workers=num_workers,
use_buffer_reader=True,
use_shared_memory=False,
timeout=timeout,
worker_init_fn=worker_init_fn)
if sampler is not None:
seld.batch_sampler.sampler = sampler
class DistributedSampler(paddle.io.DistributedBatchSampler):
def __init__(self,
dataset,
num_replicas=None,
rank=None,
shuffle=True,
seed=0,
drop_last=False):
super().__init__(
dataset=dataset,
batch_size=1,
num_replicas=num_replicas,
rank=rank,
shuffle=shuffle,
drop_last=drop_last)
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import paddle
from functools import partial
def add_layer_function(func):
setattr(paddle.nn.Layer, func.__name__, func)
@property
def module(self):
if hasattr(self, "_layers"):
return self._layers
else:
return self
setattr(paddle.nn.Layer, "module", module)
@add_layer_function
def load_state_dict(self, state_dict, strict=True):
for key, param in self.state_dict().items():
state = state_dict.get(key, None)
if state is None:
if key.endswith(".scale"):
state_dict[key] = state_dict.pop(key[0:-5] + "weight")
self.set_state_dict(state_dict)
@add_layer_function
def to(self, *args, **kwargs):
# TODO(syf): for dtype
return self
@add_layer_function
def cuda(self):
return self
@add_layer_function
def apply(self, func):
func(self)
@add_layer_function
def modules(self):
return [self] + self.sublayers()
@add_layer_function
def add_module(self, name, module):
self.add_sublayer(name, module)
pd_cuda = partial(paddle.nn.Layer.cuda)
@add_layer_function
def cuda(self, device=None):
return self
pd_train = partial(paddle.nn.Layer.train)
@add_layer_function
def train(self, mode=True):
if mode:
return pd_train(self)
else:
return paddle.nn.Layer.eval(self)
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import paddle
class ReduceOnPlateau(paddle.optimizer.lr.ReduceOnPlateau):
def __init__(self,
optimizer,
mode='min',
factor=0.1,
patience=10,
threshold=0.0001,
threshold_mode='rel',
cooldown=0,
min_lr=0,
eps=1e-08,
verbose=False):
super().__init__(
learning_rate=0.01,
mode=mode,
factor=factor,
patience=patience,
threshold=threshold,
threshold_mode=threshold_mode,
cooldown=cooldown,
min_lr=min_lr,
epsilon=eps,
verbose=verbose)
optimizer._learning_rate = self
class CosineAnnealingDecay(paddle.optimizer.lr.CosineAnnealingDecay):
def __init__(self,
optimizer,
T_max,
eta_min=0,
last_epoch=-1,
verbose=False):
super().__init__(0.01, T_max, eta_min, last_epoch, verbose)
optimizer._learning_rate = self
class MultiStepDecay(paddle.optimizer.lr.MultiStepDecay):
def __init__(self,
optimizer,
milestones,
gamma=0.1,
last_epoch=-1,
verbose=False):
super().__init__(0.01, milestones, gamma, last_epoch1, verbose)
optimizer._learning_rate = self
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import paddle
from .utils import *
class AvgPool1D(paddle.nn.AvgPool1D):
def __init__(self,
kernel_size,
stride=None,
padding=0,
ceil_mode=False,
count_include_pad=True,
divisor_override=None):
super().__init__(
kernel_size=kernel_size,
stride=stride,
padding=padding,
ceil_mode=padding,
exclusive=count_include_pad,
divisor_override=divisor_override)
class AvgPool2D(paddle.nn.AvgPool2D):
def __init__(self,
kernel_size,
stride=None,
padding=0,
ceil_mode=False,
count_include_pad=True,
divisor_override=None):
super().__init__(
kernel_size=kernel_size,
stride=stride,
padding=padding,
ceil_mode=padding,
exclusive=count_include_pad,
divisor_override=divisor_override)
class AvgPool3D(paddle.nn.AvgPool3D):
def __init__(self,
kernel_size,
stride=None,
padding=0,
ceil_mode=False,
count_include_pad=True,
divisor_override=None):
super().__init__(
kernel_size=kernel_size,
stride=stride,
padding=padding,
ceil_mode=padding,
exclusive=count_include_pad,
divisor_override=divisor_override)
class BatchNorm1D(paddle.nn.BatchNorm1D):
def __init__(self,
num_features,
eps=1e-05,
momentum=0.1,
affine=True,
track_running_stats=True):
momentum = 1 - momentum
weight_attr = None
bias_attr = None
if not affine:
weight_attr = paddle.ParamAttr(learning_rate=0.0)
bias_attr = paddle.ParamAttr(learning_rate=0.0)
super().__init__(
num_features,
momentum=momentum,
epsilon=eps,
weight_attr=weight_attr,
bias_attr=bias_attr,
use_global_stats=track_running_stats)
class BatchNorm2D(paddle.nn.BatchNorm2D):
def __init__(self,
num_features,
eps=1e-05,
momentum=0.1,
affine=True,
track_running_stats=True):
momentum = 1 - momentum
weight_attr = None
bias_attr = None
if not affine:
weight_attr = paddle.ParamAttr(learning_rate=0.0)
bias_attr = paddle.ParamAttr(learning_rate=0.0)
super().__init__(
num_features,
momentum=momentum,
epsilon=eps,
weight_attr=weight_attr,
bias_attr=bias_attr,
use_global_stats=track_running_stats)
class BatchNorm3D(paddle.nn.BatchNorm3D):
def __init__(self,
num_features,
eps=1e-05,
momentum=0.1,
affine=True,
track_running_stats=True):
momentum = 1 - momentum
weight_attr = None
bias_attr = None
if not affine:
weight_attr = paddle.ParamAttr(learning_rate=0.0)
bias_attr = paddle.ParamAttr(learning_rate=0.0)
super().__init__(
num_features,
momentum=momentum,
epsilon=eps,
weight_attr=weight_attr,
bias_attr=bias_attr,
use_global_stats=track_running_stats)
class BCEWithLogitsLoss(paddle.nn.BCEWithLogitsLoss):
def __init__(self,
weight=None,
size_average=None,
reduce=None,
reduction='mean',
pos_weight=None):
super().__init__(weight, reduction=reduction, pos_weight=pos_weight)
@property
def in_channels(self):
return self._in_channels
setattr(paddle.nn.layer.conv._ConvNd, "in_channels", in_channels)
@property
def out_channels(self):
return self._out_channels
setattr(paddle.nn.layer.conv._ConvNd, "out_channels", out_channels)
@property
def kernel_size(self):
return self._kernel_size
setattr(paddle.nn.layer.conv._ConvNd, "kernel_size", kernel_size)
@property
def stride(self):
return self._stride
setattr(paddle.nn.layer.conv._ConvNd, "stride", stride)
@property
def padding(self):
return self._padding
setattr(paddle.nn.layer.conv._ConvNd, "padding", padding)
@property
def dilation(self):
return self._dilation
setattr(paddle.nn.layer.conv._ConvNd, "dilation", dilation)
@property
def groups(self):
return self._groups
setattr(paddle.nn.layer.conv._ConvNd, "groups", groups)
class ConstantPad2D(paddle.nn.Pad2D):
def __init__(self, padding, value):
super().__init__(padding, value=value)
class Conv1D(paddle.nn.Conv1D):
def __init__(self,
in_channels,
out_channels,
kernel_size,
stride=1,
padding=0,
dilation=1,
groups=1,
bias=True,
padding_mode='zeros'):
super().__init__(
in_channels,
out_channels,
kernel_size,
stride=stride,
padding=padding,
dilation=dilation,
groups=groups,
padding_mode=padding_mode,
bias_attr=bias if not bias else None)
class Conv2D(paddle.nn.Conv2D):
def __init__(self,
in_channels,
out_channels,
kernel_size,
stride=1,
padding=0,
dilation=1,
groups=1,
bias=True,
padding_mode='zeros'):
super().__init__(
in_channels,
out_channels,
kernel_size,
stride=stride,
padding=padding,
dilation=dilation,
groups=groups,
padding_mode=padding_mode,
bias_attr=bias if not bias else None)
class Conv3D(paddle.nn.Conv3D):
def __init__(self,
in_channels,
out_channels,
kernel_size,
stride=1,
padding=0,
dilation=1,
groups=1,
bias=True,
padding_mode='zeros'):
super().__init__(
in_channels,
out_channels,
kernel_size,
stride=stride,
padding=padding,
dilation=dilation,
groups=groups,
padding_mode=padding_mode,
bias_attr=bias if not bias else None)
class Conv2DTranspose(paddle.nn.Conv2DTranspose):
def __init__(self,
in_channels,
out_channels,
kernel_size,
stride=1,
padding=0,
output_padding=0,
groups=1,
bias=True,
dilation=1,
padding_mode='zeros'):
super().__init__(
in_channels,
out_channels,
kernel_size,
stride=stride,
padding=padding,
output_padding=output_padding,
groups=groups,
dilation=dilation,
bias_attr=bias if not bias else None)
assert padding_mode == 'zeros', "The padding_mode must be zero in Conv2DTranspose."
class CrossEntropyLoss(paddle.nn.CrossEntropyLoss):
def __init__(self,
weight=None,
size_average=None,
ignore_index=-100,
reduce=None,
reduction='mean'):
super().__init__(weight, reduction=reduction, ignore_index=ignore_index)
class Dropout(paddle.nn.Dropout):
def __init__(self, p=0.5, inplace=False):
super().__init__(p)
class Embedding(paddle.nn.Embedding):
def __init__(self,
num_embeddings,
embedding_dim,
padding_idx=None,
max_norm=None,
norm_type=2.0,
scale_grad_by_freq=False,
sparse=False,
_weight=None):
super().__init__(
num_embeddings,
embedding_dim,
padding_idx=padding_idx,
sparse=sparse)
assert max_norm is None, "The max_norm must be None in Embedding!"
assert not scale_grad_by_freq, "The scale_grad_by_freq must False None in Embedding!"
class Identity(paddle.nn.Layer):
def __init__(self, *args, **kwargs):
super().__init__()
def forward(self, input):
return input
class GroupNorm(paddle.nn.GroupNorm):
def __init__(num_groups, num_channels, eps=1e-05, affine=True):
if not affine:
weight_attr = False
bias_attr = False
else:
weight_attr = None
bias_attr = None
super().__init__(num_groups, num_channels, eps, weight_attr, bias_attr)
class InstanceNorm2D(paddle.nn.InstanceNorm2D):
def __init__(self,
num_features,
eps=1e-05,
momentum=0.1,
affine=False,
track_running_stats=False):
momentum = 1 - momentum
weight_attr = None
bias_attr = None
if not affine:
weight_attr = paddle.ParamAttr(learning_rate=0.0)
bias_attr = paddle.ParamAttr(learning_rate=0.0)
super().__init__(
num_features,
momentum=momentum,
epsilon=eps,
weight_attr=weight_attr,
bias_attr=bias_attr)
class KLDivLoss(paddle.nn.Layer):
def __init__(self,
size_average=None,
reduce=None,
reduction='mean',
log_target=False):
super().__init__()
self.reduction = reduction
self.log_target = log_target
def forward(self, input, target):
if self.log_target:
out = paddle.exp(target) * (target - input)
else:
out_pos = target * (paddle.log(target) - input)
zeros = paddle.zeros_like(out_pos)
out = paddle.where(target > 0, out_pos, zeros)
out_sum = paddle.sum(out)
if self.reduction == "sum":
return out_sum
elif self.reduction == "batchmean":
n = input.shape[0]
return out_sum / n
elif self.reduction == "mean":
return paddle.mean(out)
else:
return out
class LayerNorm(paddle.nn.LayerNorm):
def __init__(self, normalized_shape, eps=1e-05, elementwise_affine=True):
if not elementwise_affine:
weight_attr = False
bias_attr = False
else:
weight_attr = None
bias_attr = None
super().__init__(normalized_shape, eps, weight_attr, bias_attr)
class Linear(paddle.nn.Linear):
def __init__(self, in_features, out_features, bias=True):
super().__init__(
in_features, out_features, bias_attr=bias if not bias else None)
class L1Loss(paddle.nn.L1Loss):
def __init__(self, size_average=None, reduce=None, reduction='mean'):
super().__init__(reduction=reduction)
class MaxPool1D(paddle.nn.MaxPool1D):
def __init__(self,
kernel_size,
stride=None,
padding=0,
dilation=1,
return_indices=False,
ceil_mode=False):
super().__init__(
kernel_size,
stride=stride,
padding=padding,
ceil_mode=ceil_mode,
return_mask=return_indices)
assert dilation == 1, "The dilation must be 1 in MaxPool1D."
class MaxPool2D(paddle.nn.MaxPool2D):
def __init__(self,
kernel_size,
stride=None,
padding=0,
dilation=1,
return_indices=False,
ceil_mode=False):
super().__init__(
kernel_size,
stride=stride,
padding=padding,
ceil_mode=ceil_mode,
return_mask=return_indices)
assert dilation == 1, "The dilation must be 1 in MaxPool2D."
class MaxPool3D(paddle.nn.MaxPool3D):
def __init__(self,
kernel_size,
stride=None,
padding=0,
dilation=1,
return_indices=False,
ceil_mode=False):
super().__init__(
kernel_size,
stride=stride,
padding=padding,
ceil_mode=ceil_mode,
return_mask=return_indices)
assert dilation == 1, "The dilation must be 1 in MaxPool3D."
import paddle
import paddle.nn as nn
TYPE_MAPPER = {"fp16": "float16", "fp32": "float32", "fp64": "float64"}
class MaxUnpool2D(paddle.nn.Layer):
def __init__(self, kernel_size, stride=None, padding=0):
super().__init__()
if isinstance(stride, int):
self.kernel_size = (kernel_size, kernel_size)
else:
self.kernel_size = kernel_size
if stride is None:
self.stride = self.kernel_size
else:
if isinstance(stride, int):
self.stride = (stride, stride)
else:
self.stride = stride
if isinstance(padding, int):
self.padding = (padding, padding)
else:
self.padding = padding
def forward(self, input, indices, output_size=None):
if output_size is None:
n, c, h, w = input.shape
out_h = (
h - 1
) * self.stride[0] - 2 * self.padding[0] + self.kernel_size[0]
out_w = (
w - 1
) * self.stride[1] - 2 * self.padding[1] + self.kernel_size[1]
output_size = (n, c, out_h, out_w)
else:
if len(output_size) == len(self.kernel_size) + 2:
output_size = output_size[2:]
t = str(input.dtype).lower().strip().split(".")[-1]
t = TYPE_MAPPER[t]
out = paddle.zeros(output_size, dtype=t)
flatten_out = paddle.flatten(out)
for i in range(indices.shape[0]):
for j in range(indices.shape[1]):
for k in range(indices.shape[2]):
for m in range(indices.shape[3]):
indices[i, j, k, m] = (out.shape[1] * out.shape[2] * out.shape[3]) * i + \
(out.shape[2] * out.shape[3]) * j + indices[i, j, k, m]
flatten_indices = paddle.flatten(indices)
flatten_input = paddle.flatten(input)
for i in range(flatten_indices.shape[0]):
flatten_out[flatten_indices[i].tolist()] = flatten_input[i].tolist()
out = paddle.reshape(flatten_out, out.shape)
return out
class ReflectionPad2D(paddle.nn.Pad2D):
def __init__(self, padding):
super().__init__(padding, mode="reflect")
class ReplicationPad2D(paddle.nn.Pad2D):
def __init__(self, padding):
super().__init__(padding, mode="replicate")
class Softmax(paddle.nn.Softmax):
def __init__(self, dim=None):
super().__init__(axis=dim)
class SyncBatchNorm(paddle.nn.SyncBatchNorm):
def __init__(self,
num_features,
eps=1e-05,
momentum=0.1,
affine=True,
track_running_stats=True,
process_group=None):
momentum = 1 - momentum
weight_attr = None
bias_attr = None
if not affine:
weight_attr = paddle.ParamAttr(learning_rate=0.0)
bias_attr = paddle.ParamAttr(learning_rate=0.0)
super().__init__(
num_features,
momentum=momentum,
epsilon=eps,
weight_attr=weight_attr,
bias_attr=bias_attr,
use_global_stats=track_running_stats)
class ZeroPad2D(paddle.nn.Pad2D):
def __init__(self, padding):
super().__init__(padding)
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import paddle
import copy
from .utils import *
def binary_cross_entropy_with_logits(input,
target,
weight=None,
size_average=None,
reduce=None,
reduction='mean',
pos_weight=None):
if not reduce or not size_average:
reduction = "sum"
input_t = str(input.dtype).lower().strip().split(".")[-1]
if input_t in TYPE_MAPPER:
input_t = TYPE_MAPPER[input_t]
input_index = TYPE_ORDER.index(input_t)
target_t = str(target.dtype).lower().strip().split(".")[-1]
if target_t in TYPE_MAPPER:
target_t = TYPE_MAPPER[target_t]
target_index = TYPE_ORDER.index(target_t)
if input_index < target_index:
real_type = TYPE_ORDER[target_index]
input = input.cast(real_type)
else:
real_type = TYPE_ORDER[input_index]
target = target.cast(real_type)
return paddle.nn.functional.binary_cross_entropy_with_logits(
input, target, weight, reduction, pos_weight)
def avg_pool1d(input,
kernel_size,
stride=None,
padding=0,
ceil_mode=False,
count_include_pad=True):
return paddle.nn.functional.avg_pool1d(
input,
kernel_size,
stride=stride,
padding=padding,
ceil_mode=ceil_mode,
exclusive=not count_include_pad)
def avg_pool2d(input,
kernel_size,
stride=None,
padding=0,
ceil_mode=False,
count_include_pad=True,
divisor_override=None):
return paddle.nn.functional.avg_pool2d(
input,
kernel_size,
stride=stride,
padding=padding,
ceil_mode=ceil_mode,
exclusive=not count_include_pad,
divisor_override=divisor_override)
def avg_pool3d(input,
kernel_size,
stride=None,
padding=0,
ceil_mode=False,
count_include_pad=True,
divisor_override=None):
return paddle.nn.functional.avg_pool3d(
input,
kernel_size,
stride=stride,
padding=padding,
ceil_mode=ceil_mode,
exclusive=not count_include_pad,
divisor_override=divisor_override)
def dropout(input, p=0.5, training=True, inplace=False):
return paddle.nn.functional.dropout(input, p=p, training=training)
def interpolate(input,
size=None,
scale_factor=None,
mode='nearest',
align_corners=None,
recompute_scale_factor=None):
return paddle.nn.functional.interpolate(
input,
size=size,
scale_factor=scale_factor,
mode=mode,
align_corners=align_corners)
def leaky_relu(input, negative_slope=0.01, inplace=False):
return paddle.nn.functional.leaky_relu(input, negative_slope=negative_slope)
def log_softmax(input, dim=None, _stacklevel=3, dtype=None):
return paddle.nn.functional.log_softmax(input, axis=dim, dtype=None)
def mse_loss(input, target, size_average=None, reduce=None, reduction='mean'):
paddle.nn.functional.mse_loss(input, target, reduction=reduction)
def relu(input, inplace=False):
return paddle.nn.functional.relu(input)
def smooth_l1_loss(input,
target,
size_average=None,
reduce=None,
reduction='mean',
beta=1.0):
paddle.nn.functional.smooth_l1_loss(
input, target, reduction=reduction, delta=beta)
def softmax(input, dim=None, _stacklevel=3, dtype=None):
return paddle.nn.functional.softmax(input, axis=dim, dtype=dtype)
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import math
from functools import reduce
import paddle
from paddle.fluid import framework
from paddle.fluid.core import VarDesc
from paddle.fluid.initializer import XavierInitializer, MSRAInitializer
from paddle.fluid.data_feeder import check_variable_and_dtype
def _calculate_fan_in_and_fan_out(var):
dimensions = var.dim()
if dimensions < 2:
raise ValueError(
"Fan in and fan out can not be computed for var with fewer than 2 dimensions"
)
num_input_fmaps = var.shape[0]
num_output_fmaps = var.shape[1]
receptive_field_size = 1
if var.dim() > 2:
receptive_field_size = reduce(lambda x, y: x * y, var.shape[2:])
fan_in = num_input_fmaps * receptive_field_size
fan_out = num_output_fmaps * receptive_field_size
return fan_in, fan_out
def _calculate_correct_fan(var, mode):
mode = mode.lower()
valid_modes = ['fan_in', 'fan_out']
if mode not in valid_modes:
raise ValueError("Mode {} not supported, please use one of {}".format(
mode, valid_modes))
fan_in, fan_out = _calculate_fan_in_and_fan_out(var)
return fan_in if mode == 'fan_in' else fan_out
def _calculate_gain(nonlinearity, param=None):
linear_fns = [
'linear', 'conv1d', 'conv2d', 'conv3d', 'conv_transpose1d',
'conv_transpose2d', 'conv_transpose3d'
]
if nonlinearity in linear_fns or nonlinearity == 'sigmoid':
return 1
elif nonlinearity == 'tanh':
return 5.0 / 3
elif nonlinearity == 'relu':
return math.sqrt(2.0)
elif nonlinearity == 'leaky_relu':
if param is None:
negative_slope = 0.01
elif not isinstance(param, bool) and isinstance(
param, int) or isinstance(param, float):
# True/False are instances of int, hence check above
negative_slope = param
else:
raise ValueError("negative_slope {} not a valid number".format(
param))
return math.sqrt(2.0 / (1 + negative_slope**2))
elif nonlinearity == 'selu':
return 3.0 / 4 # Value found empirically (https://github.com/pytorch/pytorch/pull/50664)
else:
raise ValueError("Unsupported nonlinearity {}".format(nonlinearity))
class KaimingNormal(MSRAInitializer):
def __init__(self, a=0, mode='fan_in', nonlinearity='leaky_relu'):
super(KaimingNormal, self).__init__(uniform=False, fan_in=None, seed=0)
self.a = a
self.mode = mode
self.nonlinearity = nonlinearity
def __call__(self, var, block=None):
"""Initialize the input tensor with MSRA initialization.
Args:
var(Tensor): Tensor that needs to be initialized.
block(Block, optional): The block in which initialization ops
should be added. Used in static graph only, default None.
Returns:
The initialization op
"""
block = self._check_block(block)
assert isinstance(var, framework.Variable)
assert isinstance(block, framework.Block)
f_in, f_out = self._compute_fans(var)
if self._seed == 0:
self._seed = block.program.random_seed
# to be compatible of fp16 initalizers
if var.dtype == VarDesc.VarType.FP16:
out_dtype = VarDesc.VarType.FP32
out_var = block.create_var(
name=unique_name.generate(".".join(
['masra_init', var.name, 'tmp'])),
shape=var.shape,
dtype=out_dtype,
type=VarDesc.VarType.LOD_TENSOR,
persistable=False)
else:
out_dtype = var.dtype
out_var = var
fan = _calculate_correct_fan(var, self.mode)
gain = _calculate_gain(self.nonlinearity, self.a)
std = gain / math.sqrt(fan)
op = block._prepend_op(
type="gaussian_random",
outputs={"Out": out_var},
attrs={
"shape": out_var.shape,
"dtype": int(out_dtype),
"mean": 0.0,
"std": std,
"seed": self._seed
},
stop_gradient=True)
if var.dtype == VarDesc.VarType.FP16:
block.append_op(
type="cast",
inputs={"X": out_var},
outputs={"Out": var},
attrs={"in_dtype": out_var.dtype,
"out_dtype": var.dtype})
if not framework.in_dygraph_mode():
var.op = op
return op
def kaiming_normal_(param, a=0, mode='fan_in', nonlinearity='leaky_relu'):
replaced_param = paddle.create_parameter(
shape=param.shape,
dtype=param.dtype,
default_initializer=KaimingNormal(
a=a, mode=mode, nonlinearity=nonlinearity))
paddle.assign(param, replaced_param)
class XavierNormal(XavierInitializer):
def __init__(self, gain=1.0):
super(XavierNormal, self).__init__(
uniform=True, fan_in=None, fan_out=None, seed=0)
self._gain = gain
def __call__(self, var, block=None):
block = self._check_block(block)
assert isinstance(block, framework.Block)
check_variable_and_dtype(var, "Out", ["float16", "float32", "float64"],
"xavier_init")
fan_in, fan_out = _calculate_fan_in_and_fan_out(var)
if self._seed == 0:
self._seed = block.program.random_seed
# to be compatible of fp16 initalizers
if var.dtype == VarDesc.VarType.FP16:
out_dtype = VarDesc.VarType.FP32
out_var = block.create_var(
name=unique_name.generate(".".join(
['xavier_init', var.name, 'tmp'])),
shape=var.shape,
dtype=out_dtype,
type=VarDesc.VarType.LOD_TENSOR,
persistable=False)
else:
out_dtype = var.dtype
out_var = var
std = self._gain * math.sqrt(2.0 / float(fan_in + fan_out))
op = block._prepend_op(
type="uniform_random",
inputs={},
outputs={"Out": out_var},
attrs={
"shape": out_var.shape,
"dtype": out_dtype,
"min": 0,
"max": std,
"seed": self._seed
},
stop_gradient=True)
if var.dtype == VarDesc.VarType.FP16:
block.append_op(
type="cast",
inputs={"X": out_var},
outputs={"Out": var},
attrs={"in_dtype": out_var.dtype,
"out_dtype": var.dtype})
if not framework.in_dygraph_mode():
var.op = op
return op
def xavier_normal_(param, gain=1.0):
replaced_param = paddle.create_parameter(
shape=param.shape,
dtype=param.dtype,
default_initializer=XavierNormal(gain=gain))
paddle.assign(param, replaced_param)
class XavierUniform(XavierInitializer):
def __init__(self, gain=1.0):
super(XavierUniform, self).__init__(
uniform=True, fan_in=None, fan_out=None, seed=0)
self._gain = gain
def __call__(self, var, block=None):
block = self._check_block(block)
assert isinstance(block, framework.Block)
check_variable_and_dtype(var, "Out", ["float16", "float32", "float64"],
"xavier_init")
fan_in, fan_out = _calculate_fan_in_and_fan_out(var)
if self._seed == 0:
self._seed = block.program.random_seed
# to be compatible of fp16 initalizers
if var.dtype == VarDesc.VarType.FP16:
out_dtype = VarDesc.VarType.FP32
out_var = block.create_var(
name=unique_name.generate(".".join(
['xavier_init', var.name, 'tmp'])),
shape=var.shape,
dtype=out_dtype,
type=VarDesc.VarType.LOD_TENSOR,
persistable=False)
else:
out_dtype = var.dtype
out_var = var
std = self._gain * math.sqrt(2.0 / float(fan_in + fan_out))
limit = math.sqrt(3.0) * std
op = block._prepend_op(
type="uniform_random",
inputs={},
outputs={"Out": out_var},
attrs={
"shape": out_var.shape,
"dtype": out_dtype,
"min": -limit,
"max": limit,
"seed": self._seed
},
stop_gradient=True)
if var.dtype == VarDesc.VarType.FP16:
block.append_op(
type="cast",
inputs={"X": out_var},
outputs={"Out": var},
attrs={"in_dtype": out_var.dtype,
"out_dtype": var.dtype})
if not framework.in_dygraph_mode():
var.op = op
return op
def xavier_uniform_(param, gain=1.0):
replaced_param = paddle.create_parameter(
shape=param.shape,
dtype=param.dtype,
default_initializer=XavierUniform(gain=gain))
paddle.assign(param, replaced_param)
def constant_init_(param, val):
replaced_param = paddle.create_parameter(
shape=param.shape,
dtype=param.dtype,
default_initializer=paddle.nn.initializer.Assign(
paddle.full(param.shape, val, param.dtype)))
paddle.assign(param, replaced_param)
def normal_init_(param, mean=0.0, std=1.0):
replaced_param = paddle.create_parameter(
shape=param.shape,
dtype=param.dtype,
default_initializer=paddle.nn.initializer.Assign(
paddle.normal(
mean=mean, std=std, shape=param.shape)))
paddle.assign(param, replaced_param)
def ones_init_(param):
replaced_param = paddle.create_parameter(
shape=param.shape,
dtype=param.dtype,
default_initializer=paddle.nn.initializer.Assign(
paddle.ones(param.shape, param.dtype)))
paddle.assign(param, replaced_param)
def zeros_init_(param):
replaced_param = paddle.create_parameter(
shape=param.shape,
dtype=param.dtype,
default_initializer=paddle.nn.initializer.Assign(
paddle.zeros(param.shape, param.dtype)))
paddle.assign(param, replaced_param)
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import paddle
from .utils import *
def clip_grad_value_(parameters, clip_value):
r"""Clips gradient of an iterable of parameters at specified value.
Gradients are modified in-place.
Arguments:
parameters (Iterable[Tensor] or Tensor): an iterable of Tensors or a
single Tensor that will have gradients normalized
clip_value (float or int): maximum allowed value of the gradients.
The gradients are clipped in the range
:math:`\left[\text{-clip\_value}, \text{clip\_value}\right]`
"""
if isinstance(parameters, paddle.Tensor):
parameters = [parameters]
clip_value = float(clip_value)
for p in filter(lambda p: p.grad is not None, parameters):
paddle.clip(p.grad, min=-clip_value, max=clip_value)
def spectral_norm(module,
name='weight',
n_power_iterations=1,
eps=1e-12,
dim=None):
input = getattr(module, name)
if dim is None:
if isinstance(module,
(paddle.nn.Conv1DTranspose, pdddle.nn.Conv2DTranspose,
paddle.nn.Conv3DTranspose)):
dim = 1
else:
dim = 0
t = str(input.dtype).lower().strip().split(".")[-1]
t = TYPE_MAPPER[t]
spectral_norm = paddle.nn.SpectralNorm(
input.shape, dim=dim, power_iters=n_power_iterations, eps=eps, dtype=t)
out = spectral_norm(input)
return out
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import paddle
import copy
import warnings
from .utils import *
def abs(input, *, out=None):
return paddle.abs(input)
def add(input, other, *, out=None):
return paddle.add(input, other)
def arange(start,
end,
step=1,
*,
out=None,
dtype=None,
layout=None,
device=None,
requires_grad=False):
if requires_grad:
return paddle.arange(start, end, step, dtype).requires_grad_(True)
else:
return paddle.arange(start, end, step, dtype)
def clip(input, min, max, *, out=None):
return paddle.clip(input, min, max)
def concat(tensors, dim=0):
x = tensors
last_index = -1
for ele in x:
t = str(ele.dtype).lower().strip().split(".")[-1]
if t in TYPE_MAPPER:
t = TYPE_MAPPER[t]
index = TYPE_ORDER.index(t)
if last_index < index:
last_index = index
real_type = TYPE_ORDER[last_index]
x = list(x)
for i in range(len(x)):
x[i] = x[i].cast(real_type)
return paddle.concat(x, dim)
def create_tensor(*size):
if len(size) > 1:
return paddle.zeros(size, dtype="float32")
else:
return paddle.to_tensor(size[0])
def create_float32_tensor(*size):
if len(size) > 1:
return paddle.zeros(size, dtype="float32")
else:
out = paddle.to_tensor(size[0])
out = paddle.cast(out, "float32")
return out
def create_uint8_tensor(*size):
if len(size) > 1:
return paddle.zeros(size, dtype="uint8")
else:
out = paddle.to_tensor(size[0])
out = paddle.cast(out, "uint8")
return out
def exp(input, *, out=None):
return paddle.exp(input)
def full(size,
fill_value,
*,
out=None,
dtype=None,
layout=None,
device=None,
requires_grad=False):
if requires_grad:
return paddle.full(size, fill_value, dtype).requires_grad_(True)
else:
return paddle.full(size, fill_value, dtype)
def full_like(input,
fill_value,
*,
dtype=None,
layout=None,
device=None,
requires_grad=False,
memory_format=None):
if requires_grad:
return paddle.full_like(input, fill_value, dtype).requires_grad_(True)
else:
return paddle.full_like(input, fill_value, dtype)
def linspace(start,
end,
steps,
out=None,
dtype=None,
layout=None,
device=None,
requires_grad=False):
if requires_grad:
return paddle.linspace(start, end, step, dtype).requires_grad_(True)
else:
return paddle.linspace(start, end, step, dtype)
def load(f, map_location=None, pickle_module=None, **pickle_load_args):
return paddle.load(f)
def load_state_dict_from_url(url,
model_dir=None,
map_location=None,
progress=True,
check_hash=False,
file_name=None):
return paddle.load(url)
def load_url(url,
model_dir=None,
map_location=None,
progress=True,
check_hash=False,
file_name=None):
return paddle.load(url)
def log(input, *, out=None):
return paddle.log(input)
def logical_and(input, other, *, out=None):
return paddle.logical_and(input, other, out)
def logical_not(input, *, out=None):
return paddle.logical_not(input, out)
def logical_or(input, other, *, out=None):
return paddle.logical_or(input, other, out)
def logical_xor(input, other, *, out=None):
return paddle.logical_xor(input, other, out)
def matmul(input, other, *, out=None):
return paddle.matmul(input, other)
def mul(input, other, *, out=None):
return paddle.multiply(input, other)
def max(input, dim_other=None, keepdim=False, *, out=None):
if dim_other is None:
return paddle.max(input)
elif isinstance(dim_other, paddle.Tensor):
return paddle.maximum(input, dim_other)
else:
return paddle.max(input, axis=dim_other, keepdim=keepdim)
def mean(input, dim=None, keepdim=False, *, out=None):
if dim is None:
warnings.warn('The output of paddle.mean is not scalar!')
return paddle.mean(input)
else:
return paddle.mean(input, axis=dim, keepdim=keepdim)
def min(input, dim_other=None, keepdim=False, *, out=None):
if dim_other is None:
return paddle.min(input)
elif isinstance(dim_other, paddle.Tensor):
return paddle.minimum(input, dim_other)
else:
return paddle.min(input, axis=dim_other, keepdim=keepdim)
def ones(*size,
out=None,
dtype=None,
layout=None,
device=None,
requires_grad=False):
if len(size) == 1 and isinstance(size[0], (tuple, list)):
shape = size[0]
else:
shape = size
if requires_grad:
return paddle.ones(shape, dtype).requires_grad_(True)
else:
return paddle.ones(shape, dtype)
def ones_like(input,
*,
dtype=None,
layout=None,
device=None,
requires_grad=False,
memory_format=None):
if requires_grad:
return paddle.ones_like(input, dtype).requires_grad_(True)
else:
return paddle.ones_like(input, dtype)
def set_cuda_device(device):
if isinstance(device, int):
return paddle.set_device("gpu:{}".format(device))
else:
return paddle.set_device("gpu")
def rand(*size,
out=None,
dtype=None,
layout=None,
device=None,
requires_grad=False):
if len(size) == 1 and isinstance(size[0], (tuple, list)):
shape = size[0]
else:
shape = size
if requires_grad:
return paddle.rand(shape, dtype).requires_grad_(True)
else:
return paddle.rand(shape, dtype)
def randn(*size,
out=None,
dtype=None,
layout=None,
device=None,
requires_grad=False):
if len(size) == 1 and isinstance(size[0], (tuple, list)):
shape = size[0]
else:
shape = size
if requires_grad:
return paddle.randn(shape, dtype).requires_grad_(True)
else:
return paddle.randn(shape, dtype)
def randn_like(input,
dtype=None,
layout=None,
device=None,
requires_grad=False,
memory_format=None):
shape = input.shape
if requires_grad:
return paddle.randn(shape, dtype).requires_grad_(True)
else:
return paddle.randn(shape, dtype)
def randperm(n,
*,
generator=None,
out=None,
dtype="int64",
layout=None,
device=None,
requires_grad=False,
pin_memory=False):
if requires_grad:
return paddle.randperm(n, dtype).requires_grad_(True)
else:
return paddle.randperm(n, dtype)
def save(obj, f, pickle_module=None, pickle_protocol=2):
return paddle.save(obj, f, pickle_protocol=pickle_protocol)
def split(tensor, split_size_or_sections, dim=0):
return paddle.split(tensor, split_size_or_sections, dim)
def sqrt(input, *, out=None):
return paddle.sqrt(input)
def stack(tensors, dim=0, *, out=None):
return paddle.stack(tensors, dim)
def sum(input, dim=None, keepdim=False, *, out=None):
if dim is None:
warnings.warn('The output of paddle.sum is not scalar!')
return paddle.sum(input)
else:
return paddle.sum(input, axis=dim, keepdim=keepdim)
def unsqueeze(input, dim):
return paddle.squeeze(input, dim)
def zeros(*size,
out=None,
dtype=None,
layout=None,
device=None,
requires_grad=False):
if len(size) == 1 and isinstance(size[0], (tuple, list)):
shape = size[0]
else:
shape = size
if requires_grad:
return paddle.zeros(shape, dtype).requires_grad_(True)
else:
return paddle.zeros(shape, dtype)
def zeros_like(input,
*,
dtype=None,
layout=None,
device=None,
requires_grad=False,
memory_format=None):
if requires_grad:
return paddle.zeros_like(input, dtype).requires_grad_(True)
else:
return paddle.zeros_like(input, dtype)
class DataParallel(paddle.DataParallel):
def __init__(self, module, device_ids=None, output_device=None, dim=0):
super().__init__(module)
def invalid(*args, **kwargs):
return None
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from collections import defaultdict
import warnings
import paddle
from paddle.regularizer import L2Decay
class _RequiredParameter(object):
"""Singleton class representing a required parameter for an Optimizer."""
def __repr__(self):
return "<required parameter>"
required = _RequiredParameter()
def update_parameters(parameters, lr, weight_decay):
parameters_list = list()
if parameters is not None:
for items in parameters:
if isinstance(items, dict):
params = items["params"]
if "lr" in items:
for p in params:
p.optimize_attr["learning_rate"] = items[
"lr"] / lr * p.optimize_attr["learning_rate"]
if "weight_decay" in items:
for p in params:
if isinstance(items["weight_decay"], (float, int)):
p.regularizer = L2Decay(items["weight_decay"])
else:
p.regularizer = weight_decay
for p in params:
print(p.regularizer)
parameters_list.extend(params)
else:
parameters_list.append(items)
return parameters_list
class Momentum(paddle.optimizer.Momentum):
def __init__(self,
params,
lr=0.001,
momentum=0.0,
dampening=0,
weight_decay=0.0,
nesterov=False):
assert dampening == 0, "The dampening must be 0 in Momentum!"
parameters_list = update_parameters(params, lr, weight_decay)
super().__init__(
learning_rate=lr,
momentum=momentum,
parameters=parameters_list,
use_nesterov=nesterov,
weight_decay=weight_decay,
grad_clip=None,
name=None)
defaults = dict(
lr=lr,
momentum=momentum,
dampening=dampening,
weight_decay=weight_decay,
nesterov=nesterov)
self.defaults = defaults
self.state = defaultdict(dict)
self.param_groups = []
param_groups = list(params)
if len(param_groups) == 0:
raise ValueError("optimizer got an empty parameter list")
if not isinstance(param_groups[0], dict):
param_groups = [{'params': param_groups}]
for param_group in param_groups:
self.add_param_group(param_group)
def add_param_group(self, param_group):
assert isinstance(param_group, dict), "param group must be a dict"
params = param_group['params']
if isinstance(params, paddle.Tensor):
param_group['params'] = [params]
elif isinstance(params, set):
raise TypeError(
'optimizer parameters need to be organized in ordered collections, but '
'the ordering of tensors in sets will change between runs. Please use a list instead.'
)
else:
param_group['params'] = list(params)
for param in param_group['params']:
if not isinstance(param, paddle.Tensor):
raise TypeError("optimizer can only optimize Tensors.")
if not param.is_leaf:
raise ValueError("can't optimize a non-leaf Tensor")
for name, default in self.defaults.items():
if default is required and name not in param_group:
raise ValueError(
"parameter group didn't specify a value of required optimization parameter "
+ name)
else:
param_group.setdefault(name, default)
params = param_group['params']
if len(params) != len(set(params)):
warnings.warn(
"optimizer contains a parameter group with duplicate parameters; "
"in future, this will cause an error; ",
stacklevel=3)
param_set = set()
for group in self.param_groups:
param_set.update(set(group['params']))
if not param_set.isdisjoint(set(param_group['params'])):
raise ValueError(
"some parameters appear in more than one parameter group")
self.param_groups.append(param_group)
def zero_grad(self):
return self.clear_grad()
class Adam(paddle.optimizer.Adam):
def __init__(self,
params,
lr=0.001,
betas=(0.9, 0.999),
eps=1e-08,
weight_decay=0,
amsgrad=False):
parameters_list = update_parameters(params, lr, weight_decay)
if weight_decay == 0:
weight_decay = None
super().__init__(
learning_rate=lr,
beta1=betas[0],
beta2=betas[1],
epsilon=eps,
parameters=parameters_list,
weight_decay=weight_decay,
grad_clip=None,
name=None,
lazy_mode=False)
defaults = dict(
lr=lr,
betas=betas,
eps=eps,
weight_decay=weight_decay,
amsgrad=amsgrad)
self.defaults = defaults
self.state = defaultdict(dict)
self.param_groups = []
param_groups = list(parameters_list)
if len(param_groups) == 0:
print(param_groups)
raise ValueError("optimizer got an empty parameter list")
if not isinstance(param_groups[0], dict):
param_groups = [{'params': param_groups}]
for param_group in param_groups:
self.add_param_group(param_group)
def add_param_group(self, param_group):
assert isinstance(param_group, dict), "param group must be a dict"
params = param_group['params']
if isinstance(params, paddle.Tensor):
param_group['params'] = [params]
elif isinstance(params, set):
raise TypeError(
'optimizer parameters need to be organized in ordered collections, but '
'the ordering of tensors in sets will change between runs. Please use a list instead.'
)
else:
param_group['params'] = list(params)
for param in param_group['params']:
if not isinstance(param, paddle.Tensor):
raise TypeError("optimizer can only optimize Tensors.")
if not param.is_leaf:
raise ValueError("can't optimize a non-leaf Tensor")
for name, default in self.defaults.items():
if default is required and name not in param_group:
raise ValueError(
"parameter group didn't specify a value of required optimization parameter "
+ name)
else:
param_group.setdefault(name, default)
params = param_group['params']
if len(params) != len(set(params)):
warnings.warn(
"optimizer contains a parameter group with duplicate parameters; "
"in future, this will cause an error; ",
stacklevel=3)
param_set = set()
for group in self.param_groups:
param_set.update(set(group['params']))
if not param_set.isdisjoint(set(param_group['params'])):
raise ValueError(
"some parameters appear in more than one parameter group")
self.param_groups.append(param_group)
def zero_grad(self):
return self.clear_grad()
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import paddle
from functools import partial
def add_parambase_function(func):
setattr(paddle.fluid.framework.ParamBase, func.__name__, func)
@add_parambase_function
def normal_(self, mean=0.0, std=1.0):
replaced_param = paddle.create_parameter(
shape=self.shape,
dtype=self.dtype,
default_initializer=paddle.nn.initializer.Normal(
mean=mean, std=std))
paddle.assign(self, replaced_param)
@add_parambase_function
def zero_(self):
replaced_param = paddle.create_parameter(
shape=self.shape,
dtype=self.dtype,
default_initializer=paddle.nn.initializer.Assign(
paddle.zeros(self.shape, self.dtype)))
paddle.assign(self, replaced_param)
@add_parambase_function
def fill_(self, value):
replaced_param = paddle.create_parameter(
shape=self.shape,
dtype=self.dtype,
default_initializer=paddle.nn.initializer.Assign(
paddle.full(self.shape, value, self.dtype)))
paddle.assign(self, replaced_param)
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import paddle
import copy
from functools import reduce
from functools import partial
def add_tensor_function(func):
setattr(paddle.Tensor, func.__name__, func)
@property
def data(self):
return self
setattr(paddle.Tensor, "data", data)
@property
def requires_grad(self):
return not self.stop_gradient
setattr(paddle.Tensor, "requires_grad", requires_grad)
@add_tensor_function
def requires_grad_(self, requires_grad=True):
self.stop_gradient = not requires_grad
return self
@add_tensor_function
def item(self):
return self.numpy()[0]
@add_tensor_function
def permute(self, *dims):
return self.transpose(dims)
@add_tensor_function
def clamp_(self, min, max):
return self.clip(min, max)
@add_tensor_function
def contiguous(self):
return self
@add_tensor_function
def view(self, *shape):
return self.reshape(*shape)
@add_tensor_function
def repeat(self, *sizes):
return self.tile(sizes)
@add_tensor_function
def dim(self):
return self.ndim
@add_tensor_function
def long(self, memory_format=None):
return paddle.cast(self, dtype="int64")
@add_tensor_function
def float(self, memory_format=None):
return paddle.cast(self, dtype="float32")
@add_tensor_function
def size(self, dim=None):
if dim is not None:
return self.shape[dim]
else:
return self.shape
@add_tensor_function
def to(self, *args, **kwargs):
if len(args) == 1 and "dtype" not in kwargs:
try:
return paddle.cast(self, dtype=args[0])
except Exception:
return self
else:
if len(kwargs) > 0:
if "dtype" in kwargs:
return paddle.cast(self, dtype=kwargs["dtype"])
else:
return self
else:
return self
@add_tensor_function
def index_fill_(self, dim, index, val):
x_shape = self.shape
index_shape = index.shape
if dim != 0:
perm_list = list(range(len(x_shape)))
while dim < 0:
dim += len(x_shape)
perm_list.pop(dim)
perm_list = [dim] + perm_list
self = paddle.transpose(self, perm=perm_list)
s = x_shape.pop(dim)
x_shape = [s] + x_shape
updates_shape = index_shape + x_shape[1:]
updates = paddle.full(updates_shape, fill_value=val, dtype=self.dtype)
out = paddle.scatter(self, index, updates)
if dim != 0:
perm_list = list(range(len(x_shape)))
perm_list.pop(0)
perm_list.insert(dim, 0)
out = paddle.transpose(out, perm=perm_list)
paddle.assign(out, output=self)
@add_tensor_function
def fill_(self, value):
paddle.assign(
paddle.full_like(
self, value, dtype="float32").cast(self.dtype),
output=self)
pd_sum = partial(paddle.Tensor.sum)
@add_tensor_function
def sum(self, dim, keepdim=False, dtype=None):
return pd_sum(self, axis=dim, dtype=dtype, keepdim=keepdim)
pd_sort = partial(paddle.Tensor.sort)
@add_tensor_function
def sort(self, dim=-1, descending=False, out=None):
return pd_sort(
self, axis=dim, descending=descending), paddle.argsort(
self, axis=dim, descending=descending)
pd_reshape = partial(paddle.Tensor.reshape)
@add_tensor_function
def reshape(self, *shape):
return pd_reshape(self, shape)
pd_transpose = partial(paddle.Tensor.transpose)
@add_tensor_function
def transpose(self, dim0, dim1=None):
if dim1 is None:
return pd_transpose(self, dim0)
else:
shape = self.shape
perm = list(range(len(shape)))
dim0 = (dim0 + len(shape)) if dim0 < 0 else dim0
dim1 = (dim1 + len(shape)) if dim1 < 0 else dim1
perm[dim0] = dim1
perm[dim1] = dim0
return pd_transpose(self, perm)
pd_max = partial(paddle.Tensor.max)
@add_tensor_function
def max(self, dim, keepdim=None):
return pd_max(self, dim, keepdim), paddle.argmax(self, dim, keepdim)
pd_min = partial(paddle.Tensor.min)
@add_tensor_function
def min(self, dim, keepdim=None):
return pd_min(self, dim, keepdim), paddle.argmin(self, dim, keepdim)
pd_expand = partial(paddle.Tensor.expand)
@add_tensor_function
def expand(self, *sizes):
return pd_expand(self, sizes)
@add_tensor_function
def div(self, value):
return self / value
@add_tensor_function
def eq(self, other):
return self.equal(other)
@add_tensor_function
def eq_(self, other):
return self.equal(other)
@add_tensor_function
def mul(self, value):
return self * value
@add_tensor_function
def mul_(self, value):
return self * value
pd_cuda = partial(paddle.Tensor.cuda)
@add_tensor_function
def cuda(self, device=None, non_blocking=False, memory_format=None):
return self
@add_tensor_function
def copy_(self, src, non_blocking=False):
src = paddle.expand(src, self.shape)
paddle.assign(src, self)
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
TYPE_ORDER = ["bool", "int32", "int64", "float16", "float32", "float64"]
TYPE_MAPPER = {"fp16": "float16", "fp32": "float32", "fp64": "float64"}
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import paddle
from paddle.fluid.core import VarBase
def is_condition_one(idx):
"""
a = paddle.to_tensor(np.array([[1,2,3], [4,5,6]]).astype("float32"))
mask = paddle.to_tensor(np.array([True, False]).astype("bool"))
a[mask, :]
a[mask, ...]
"""
if not (isinstance(idx[0], paddle.Tensor) and
str(idx[0].dtype) == "VarType.BOOL"):
return False
if len(idx) == 1:
return False
if len(idx) > 1:
if idx[1] is Ellipsis:
return True
for ele in idx[1:]:
if isinstance(
ele, slice
) and ele.start is None and ele.start is None and ele.step is None:
continue
else:
return False
return True
def is_condition_two(idx):
"""
a = paddle.to_tensor(np.random.rand(1, 2, 3).astype("float32"))
a[..., :2]
"""
if idx[0] is Ellipsis and (isinstance(idx[1], slice) or isinstance(idx[1],
int)):
return True
return False
VarBase.tmp = VarBase.__getitem__
def __getitem__(self, idx):
is_bool = False
if str(self.dtype) == "VarType.BOOL":
self = self.cast("int32")
is_bool = True
if isinstance(idx, paddle.Tensor) and len(idx.shape) == 1:
out = paddle.gather(self, idx)
return out.cast("bool") if is_bool else out
elif isinstance(idx, paddle.Tensor) and str(idx.dtype) == "VarType.BOOL":
idx = paddle.cast(idx, "int32")
idx = paddle.nonzero(idx)
out = paddle.gather_nd(self, idx)
return out.cast("bool") if is_bool else out
elif isinstance(idx, tuple):
if is_condition_one(idx):
first_idx = idx[0]
first_idx = paddle.cast(first_idx, "int32")
first_idx = paddle.nonzero(first_idx)
out = paddle.gather_nd(self, first_idx)
return out.cast("bool") if is_bool else out
elif is_condition_two(idx):
new_idx = list()
for i in range(len(self.shape) - 1):
new_idx.append(slice(None, None, None))
new_idx.append(list(idx)[-1])
out = self.tmp(tuple(new_idx))
return out.cast("bool") if is_bool else out
else:
out = self.tmp(idx)
return out.cast("bool") if is_bool else out
# TODO(syf): 出来为(slice(None, None, None), slice(None, None, None), 0)
else:
out = self.tmp(idx)
if out.shape == [1]:
return out.numpy()[0]
else:
return out
VarBase.__getitem__ = __getitem__
VarBase.setitem_tmp = VarBase.__setitem__
def __setitem__(self, idx, value):
if isinstance(idx, paddle.Tensor) and str(idx.dtype) == "VarType.BOOL":
"""
a = paddle.to_tensor(np.array([1,2,3]).astype("float32"))
mask = paddle.to_tensor(np.array([True, False, True]).astype("bool"))
a[mask] = 1
"""
value_tensor = paddle.full(self.shape, value, self.dtype)
paddle.assign(paddle.where(idx, value_tensor, self), self)
else:
return self.setitem_tmp(idx, value)
VarBase.__setitem__ = __setitem__
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import paddle
from PIL import Image
import os
import os.path
from typing import Any, Callable, cast, Dict, List, Optional, Tuple
IMG_EXTENSIONS = ('.jpg', '.jpeg', '.png', '.ppm', '.bmp', '.pgm', '.tif',
'.tiff', '.webp')
def has_file_allowed_extension(filename: str,
extensions: Tuple[str, ...]) -> bool:
return filename.lower().endswith(extensions)
def make_dataset(
directory: str,
class_to_idx: Dict[str, int],
extensions: Optional[Tuple[str, ...]]=None,
is_valid_file: Optional[Callable[[str], bool]]=None, ) -> List[Tuple[
str, int]]:
instances = []
directory = os.path.expanduser(directory)
both_none = extensions is None and is_valid_file is None
both_something = extensions is not None and is_valid_file is not None
if both_none or both_something:
raise ValueError(
"Both extensions and is_valid_file cannot be None or not None at the same time"
)
if extensions is not None:
def is_valid_file(x: str) -> bool:
return has_file_allowed_extension(x,
cast(Tuple[str, ...], extensions))
is_valid_file = cast(Callable[[str], bool], is_valid_file)
for target_class in sorted(class_to_idx.keys()):
class_index = class_to_idx[target_class]
target_dir = os.path.join(directory, target_class)
if not os.path.isdir(target_dir):
continue
for root, _, fnames in sorted(os.walk(target_dir, followlinks=True)):
for fname in sorted(fnames):
path = os.path.join(root, fname)
if is_valid_file(path):
item = path, class_index
instances.append(item)
return instances
class ImageFolder(paddle.vision.datasets.ImageFolder):
def __init__(self,
root,
transform=None,
target_transform=None,
loader=None,
is_valid_file=None):
super().__init__(
root,
loader=loader,
transform=transform,
is_valid_file=is_valid_file)
self.target_transform = target_transform
classes, class_to_idx = self._find_classes(root)
self.samples = self.make_dataset(self.root, class_to_idx, IMG_EXTENSIONS
if is_valid_file is None else None,
is_valid_file)
def _find_classes(self, dir: str) -> Tuple[List[str], Dict[str, int]]:
classes = [d.name for d in os.scandir(dir) if d.is_dir()]
classes.sort()
class_to_idx = {cls_name: i for i, cls_name in enumerate(classes)}
return classes, class_to_idx
@staticmethod
def make_dataset(
directory: str,
class_to_idx: Dict[str, int],
extensions: Optional[Tuple[str, ...]]=None,
is_valid_file: Optional[Callable[[str], bool]]=None, ) -> List[
Tuple[str, int]]:
return make_dataset(
directory,
class_to_idx,
extensions=extensions,
is_valid_file=is_valid_file)
def __getitem__(self, index):
path, target = self.samples[index]
sample = self.loader(path)
if self.transform is not None:
sample = self.transform(sample)
if self.target_transform is not None:
target = self.target_transform(target)
return [sample, target]
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import paddle
import PIL
import numbers
import numpy as np
from PIL import Image
from paddle.vision.transforms import BaseTransform
from paddle.vision.transforms import functional as F
class ToPILImage(BaseTransform):
def __init__(self, mode=None, keys=None):
super(ToTensor, self).__init__(keys)
self.data_format = data_format
def _apply_image(self, pic):
"""
Args:
pic (Tensor|np.ndarray): Image to be converted to PIL Image.
Returns:
PIL: Converted image.
"""
if not (isinstance(pic, paddle.Tensor) or isinstance(pic, np.ndarray)):
raise TypeError('pic should be Tensor or ndarray. Got {}.'.format(
type(pic)))
elif isinstance(pic, paddle.Tensor):
if pic.ndimension() not in {2, 3}:
raise ValueError(
'pic should be 2/3 dimensional. Got {} dimensions.'.format(
pic.ndimension()))
elif pic.ndimension() == 2:
# if 2D image, add channel dimension (CHW)
pic = pic.unsqueeze(0)
elif isinstance(pic, np.ndarray):
if pic.ndim not in {2, 3}:
raise ValueError(
'pic should be 2/3 dimensional. Got {} dimensions.'.format(
pic.ndim))
elif pic.ndim == 2:
# if 2D image, add channel dimension (HWC)
pic = np.expand_dims(pic, 2)
npimg = pic
if isinstance(pic, paddle.Tensor) and "float" in str(pic.numpy(
).dtype) and mode != 'F':
pic = pic.mul(255).byte()
if isinstance(pic, paddle.Tensor):
npimg = np.transpose(pic.numpy(), (1, 2, 0))
if not isinstance(npimg, np.ndarray):
raise TypeError(
'Input pic must be a paddle.Tensor or NumPy ndarray, ' +
'not {}'.format(type(npimg)))
if npimg.shape[2] == 1:
expected_mode = None
npimg = npimg[:, :, 0]
if npimg.dtype == np.uint8:
expected_mode = 'L'
elif npimg.dtype == np.int16:
expected_mode = 'I;16'
elif npimg.dtype == np.int32:
expected_mode = 'I'
elif npimg.dtype == np.float32:
expected_mode = 'F'
if mode is not None and mode != expected_mode:
raise ValueError(
"Incorrect mode ({}) supplied for input type {}. Should be {}"
.format(mode, np.dtype, expected_mode))
mode = expected_mode
elif npimg.shape[2] == 2:
permitted_2_channel_modes = ['LA']
if mode is not None and mode not in permitted_2_channel_modes:
raise ValueError("Only modes {} are supported for 2D inputs".
format(permitted_2_channel_modes))
if mode is None and npimg.dtype == np.uint8:
mode = 'LA'
elif npimg.shape[2] == 4:
permitted_4_channel_modes = ['RGBA', 'CMYK', 'RGBX']
if mode is not None and mode not in permitted_4_channel_modes:
raise ValueError("Only modes {} are supported for 4D inputs".
format(permitted_4_channel_modes))
if mode is None and npimg.dtype == np.uint8:
mode = 'RGBA'
else:
permitted_3_channel_modes = ['RGB', 'YCbCr', 'HSV']
if mode is not None and mode not in permitted_3_channel_modes:
raise ValueError("Only modes {} are supported for 3D inputs".
format(permitted_3_channel_modes))
if mode is None and npimg.dtype == np.uint8:
mode = 'RGB'
if mode is None:
raise TypeError('Input type {} is not supported'.format(
npimg.dtype))
return Image.fromarray(npimg, mode=mode)
class ToTensor(BaseTransform):
"""Convert a ``PIL.Image`` or ``numpy.ndarray`` to ``numpy.ndarray`` with shapr (C x H x W).
Args:
data_format (str, optional): Data format of output tensor, should be 'HWC' or
'CHW'. Default: 'CHW'.
keys (list[str]|tuple[str], optional): Same as ``BaseTransform``. Default: None.
"""
def __init__(self, data_format='CHW', keys=None):
super(ToTensor, self).__init__(keys)
self.data_format = data_format
def _apply_image(self, img):
"""
Args:
img (PIL.Image|np.ndarray): Image to be converted to tensor.
Returns:
np.ndarray: Converted image.
"""
if isinstance(img, PIL.JpegImagePlugin.JpegImageFile) or isinstance(
img, PIL.Image.Image):
img = np.array(img)
img = img / 255.0
img = img.transpose((2, 0, 1)).astype("float32")
img = paddle.to_tensor(img)
return img
class Normalize(BaseTransform):
"""Normalize the input data with mean and standard deviation.
Given mean: ``(M1,...,Mn)`` and std: ``(S1,..,Sn)`` for ``n`` channels,
this transform will normalize each channel of the input data.
``output[channel] = (input[channel] - mean[channel]) / std[channel]``
Args:
mean (int|float|list): Sequence of means for each channel.
std (int|float|list): Sequence of standard deviations for each channel.
"""
def __init__(self, mean=0.0, std=1.0, inplace=False):
key = None
super(Normalize, self).__init__(key)
if isinstance(mean, numbers.Number):
mean = [mean, mean, mean]
if isinstance(std, numbers.Number):
std = [std, std, std]
self.mean = mean
self.std = std
def _apply_image(self, img):
if isinstance(img, paddle.Tensor):
img = img.numpy()
return F.normalize(img, self.mean, self.std, 'CHW', False)
class Lambda(BaseTransform):
"""Apply a user-defined lambda as a transform. This transform does not support torchscript.
Args:
lambd (function): Lambda/function to be used for transform.
"""
def __init__(self, lambd):
if not callable(lambd):
raise TypeError("Argument lambd should be callable, got {}".format(
repr(type(lambd).__name__)))
self.lambd = lambd
def _apply_image(self, img):
return self.lambd(img)
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import pathlib
import paddle
import warnings
import math
import numpy as np
from PIL import Image
from typing import Union, Optional, List, Tuple, Text, BinaryIO
@paddle.no_grad()
def make_grid(tensor: Union[paddle.Tensor, List[paddle.Tensor]],
nrow: int=8,
padding: int=2,
normalize: bool=False,
value_range: Optional[Tuple[int, int]]=None,
scale_each: bool=False,
pad_value: int=0,
**kwargs) -> paddle.Tensor:
"""Make a grid of images.
Args:
tensor (Tensor or list): 4D mini-batch Tensor of shape (B x C x H x W)
or a list of images all of the same size.
nrow (int, optional): Number of images displayed in each row of the grid.
The final grid size is ``(B / nrow, nrow)``. Default: ``8``.
padding (int, optional): amount of padding. Default: ``2``.
normalize (bool, optional): If True, shift the image to the range (0, 1),
by the min and max values specified by :attr:`range`. Default: ``False``.
value_range (tuple, optional): tuple (min, max) where min and max are numbers,
then these numbers are used to normalize the image. By default, min and max
are computed from the tensor.
scale_each (bool, optional): If ``True``, scale each image in the batch of
images separately rather than the (min, max) over all images. Default: ``False``.
pad_value (float, optional): Value for the padded pixels. Default: ``0``.
Example:
See this notebook `here <https://gist.github.com/anonymous/bf16430f7750c023141c562f3e9f2a91>`_
"""
if not (isinstance(tensor, paddle.Tensor) or
(isinstance(tensor, list) and all(
isinstance(t, paddle.Tensor) for t in tensor))):
raise TypeError(
f'tensor or list of tensors expected, got {type(tensor)}')
if "range" in kwargs.keys():
warning = "range will be deprecated, please use value_range instead."
warnings.warn(warning)
value_range = kwargs["range"]
# if list of tensors, convert to a 4D mini-batch Tensor
if isinstance(tensor, list):
tensor = paddle.stack(tensor, axis=0)
if tensor.dim() == 2: # single image H x W
tensor = tensor.unsqueeze(0)
if tensor.dim() == 3: # single image
if tensor.size(0) == 1: # if single-channel, convert to 3-channel
tensor = paddle.concat((tensor, tensor, tensor), 0)
tensor = tensor.unsqueeze(0)
if tensor.dim() == 4 and tensor.size(1) == 1: # single-channel images
tensor = paddle.concat((tensor, tensor, tensor), 1)
if normalize is True:
if value_range is not None:
assert isinstance(value_range, tuple), \
"value_range has to be a tuple (min, max) if specified. min and max are numbers"
def norm_ip(img, low, high):
img.clip(min=low, max=high)
img = img - low
img = img / max(high - low, 1e-5)
def norm_range(t, value_range):
if value_range is not None:
norm_ip(t, value_range[0], value_range[1])
else:
norm_ip(t, float(t.min()), float(t.max()))
if scale_each is True:
for t in tensor: # loop over mini-batch dimension
norm_range(t, value_range)
else:
norm_range(tensor, value_range)
if tensor.size(0) == 1:
return tensor.squeeze(0)
# make the mini-batch of images into a grid
nmaps = tensor.size(0)
xmaps = min(nrow, nmaps)
ymaps = int(math.ceil(float(nmaps) / xmaps))
height, width = int(tensor.shape[2] + padding), int(tensor.shape[3] +
padding)
num_channels = tensor.shape[1]
grid = paddle.full((num_channels, height * ymaps + padding,
width * xmaps + padding), pad_value)
k = 0
for y in range(ymaps):
for x in range(xmaps):
if k >= nmaps:
break
grid[:, y * height + padding:(y + 1) * height, x * width + padding:(
x + 1) * width] = tensor[k]
k = k + 1
return grid
@paddle.no_grad()
def save_image(tensor: Union[paddle.Tensor, List[paddle.Tensor]],
fp: Union[Text, pathlib.Path, BinaryIO],
format: Optional[str]=None,
**kwargs) -> None:
"""Save a given Tensor into an image file.
Args:
tensor (Tensor or list): Image to be saved. If given a mini-batch tensor,
saves the tensor as a grid of images by calling ``make_grid``.
fp (string or file object): A filename or a file object
format(Optional): If omitted, the format to use is determined from the filename extension.
If a file object was used instead of a filename, this parameter should always be used.
**kwargs: Other arguments are documented in ``make_grid``.
"""
grid = make_grid(tensor, **kwargs)
# Add 0.5 after unnormalizing to [0, 255] to round to nearest integer
ndarr = paddle.clip(grid * 255 + 0.5, 0, 255).transpose(
[1, 2, 0]).cast("uint8").numpy()
im = Image.fromarray(ndarr)
im.save(fp, format=format)
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os.path as osp
import sys
def get_dep_file_path(current_file_path, from_level, from_str):
""" 根据from信息获取依赖包所在文件。如果from字符串中存在相对路径(出现"."),
则根据相对路径找到相应的文件;反之,执行import语句找到相应依赖的文件。
Args:
current_file_path (str): from信息所在文件的路径。
from_level (int): from信息中父目录级别数。
from_str (str): from信息中依赖包名字。
"""
if from_level > 0:
while from_level > 0:
current_file_path, folder_or_file = osp.split(current_file_path)
from_level -= 1
if from_str is None:
import_file_path = osp.join(current_file_path, "__init__.py")
else:
current_file_path = osp.join(current_file_path,
osp.join(*from_str.split(".")))
if osp.exists(current_file_path + ".py"):
import_file_path = current_file_path + ".py"
else:
import_file_path = osp.join(current_file_path, "__init__.py")
else:
current_abs_path = osp.dirname(current_file_path)
sys.path.append(current_abs_path)
if len(from_str.split(".")) == 1:
key_str = from_str
exec("import {}".format(key_str))
else:
from_seg = from_str.split(".")
from_str = ".".join(from_seg[0:-1])
key_str = from_seg[-1]
exec("from {} import {}".format(from_str, key_str))
sys.path.pop(-1)
import_file_path = locals()[key_str].__file__
return import_file_path
def add_line_continuation_symbol(code):
code_list = code.split("\n")
for i, line in enumerate(code_list):
if line.strip().endswith("="):
code_list[i] = line + "\\"
return "\n".join(code_list)
from x2paddle.project_convertor.pytorch.torch2paddle import *
# -*- coding:UTF-8 -*-
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
def string(param):
""" 生成字符串。
"""
return "\'{}\'".format(param)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册