提交 65156e1b 编写于 作者: M Macrobull

Merge remote-tracking branch 'upstream/master'

......@@ -5,13 +5,17 @@
X2Paddle支持将Caffe和TensorFlow模型转至PaddlePaddle模型
# 用法
**[caffe2fluid](caffe2fluid)**: Caffe model to PaddlePaddle,支持将Caffe模型转至PaddlePaddle fluid可加载预测模型
## [caffe2fluid](caffe2fluid)
1. 支持将Caffe模型转至PaddlePaddle fluid可加载预测模型
2. 提供Caffe-PaddlePaddle常用API的对比文档[[doc](caffe2fluid/doc)]
## [tensorflow2fluid](tensorflow2fluid)
1. 支持将TensorFlow模型转至PaddlePaddle fluid可加载预测模型
2. 提供TensorFlow-PaddlePaddle常用API的对比文档[[doc](tensorflow2fluid/doc)]
**[tensorflow2fluid](tensorflow2fluid)**: TensorFlow model to PaddlePaddle,支持将Tensorflow模型转至PaddlePaddle fluid可加载预测模型
**[onnx2fluid](onnx2fluid)**: ONNX model to PaddlePaddle,支持将ONNX模型转至PaddlePaddle fluid可加载预测模型。对于Pytorch模型,用户可以将模型导出来ONNX格式模型,再使用onnx2fluid,将模型转为PaddlePaddle模型
## [onnx2fluid](onnx2fluid)
1. 支持将ONNX模型转至PaddlePaddle fluid可加载预测模型
2. Pytorch支持导出为ONNX模型,因此也可通过onnx2fluid支持PyTorch模型的转换
# 贡献代码
clone代码至本地后,先运行`X2Paddle/commit-prepare.sh`配置代码提交环境
# caffe2fluid
[![License](https://img.shields.io/badge/license-Apache%202-blue.svg)](LICENSE)
caffe2fluid用于将Caffe模型转换为PaddlePaddle模型
caffe2fluid用于将Caffe模型转换为PaddlePaddle模型,此外在[[doc](doc/接口速查表.md)]目录中整理了Caffe-PaddlePaddle的常用API对比分析。
## 环境依赖
......@@ -46,16 +46,16 @@ python alexnet.py --npy_path alexnet.npy --model-param-path ./fluid --need-layer
模型转换后,可通过如下方式,逐层对比转换后的模型与原模型的计算结果差异(**运行环境依赖caffe和paddlepaddle**
```
# alexnet : caffe配置文件(.prototxt)中“name”的值
# ./models/alexnet.prototxt : caffe配置文件路径
# ./models/alexnet.caffemodel : caffe模型文件路径
# ./models/alexnet.py : 转换后模型代码保存路径
# ./models/alexnet.npy : 转换后模型参数保存路径
# ../../alexnet.prototxt : caffe配置文件路径
# ../../alexnet.caffemodel : caffe模型文件路径
# ../../alexnet.py : 转换后模型代码保存路径
# ../../alexnet.npy : 转换后模型参数保存路径
# ./data/65.jpeg : 需要测试的图像数据
cd examples/imagenet
bash tools/diff.sh alexnet ./models/alexnet.prototxt \
./models/alexnet.caffemodel \
./models/alexnet.py \
./models/alexnet.npy \
bash tools/diff.sh alexnet ../../alexnet.prototxt \
../../alexnet.caffemodel \
../../alexnet.py \
../../alexnet.npy \
./data/65.jpeg
```
......
......@@ -28,8 +28,8 @@ paddle.fluid.layers.accuracy(
```
### 功能差异
#### 计算机制的差异
Caffe:只能计算每个类别中top1中正确预测的个数
#### 计算机制
Caffe:只能计算每个类别中top1中正确预测的个数
PaddlePaddle:可以通过设置`k`来计算每个类别中top k 中正确预测的个数。
......
......@@ -26,6 +26,6 @@ paddle.fluid.layers.argmax(
```
### 功能差异
#### 输出的差异
Caffe:可以通过设置设置`top_k`使输出为前k大的索引,同时可以设置`out_max_val`为true来使输出为前k大的数值。
PaddlePaddle:只能输出最大值的索引
#### 计算机制
Caffe:可通过`top_k``out_max_val`参数设置得到前`k`的索引或数值;
PaddlePaddle:只能输出最大值的索引
......@@ -39,19 +39,6 @@ paddle.fluid.layers.batch_norm(
```
### 功能差异
#### 输出结果的差异
Caffe:输出只是单纯的使用均值和方差进行归一化计算,没有缩放变换这一过程,若要完成后面这一过程需要搭配Scale层进行使用。
PaddlePaddle:完成了归一化和缩放变换两个过程,是完整的一个Batch Normalization过程。
#### 输入参数的差异
Caffe:共需要3个输入参数:均值向量、方差向量、滑动系数。
PaddlePaddle:共需要4个输入参数:均值向量、方差向量、缩放变量`param_attr`和缩放变量`bias_attr`
#### 计算方式的差异
Caffe:输入的均值和方差都需要与滑动系数进行计算得出新均值和方差,再进行归一化处理。
PaddlePaddle:直接使用输入的均值和方差进行归一化处理。
#### 其他差异
Caffe:激活函数需要由另外一层完成。
PaddlePaddle:可以通过设置`act``fuse_with_relu`看是否在进行Batch Normalization后进行激活函数的操作。
#### 计算机制
Caffe:`BatchNorm`仅做了归一化计算,需结合`Scale`层进行缩放变换;
PaddlePaddle:包括归一化计算和缩放变换,`param_attr``bias_attr`即为缩放变换的设置参数。
......@@ -57,9 +57,20 @@ paddle.fluid.layers.conv2d(
```
### 功能差异
#### 参数初始化的差异
Caffe:第一个`param`负责设置卷积核的局部学习率和权值衰减因子,第二个`param`则负责设置偏置项的局部学习率和权值衰减因子;而卷积核和偏置项的在`convolution_param`中进行设置;是否使用偏置项可以使用`bias_term`进行设置。
PaddlePaddle:卷积核和偏置项的多处设置均分别在一个参数——`param_attr`/`bias_attr`中完成所有操作。二者的默认值为None,而ParamAttr是一个初始化结果,其可以通过`paddle.fluid.ParamAttr(name=None, initializer=None, learning_rate=1.0, regularizer=None, trainable=True, gradient_clip=None, do_model_average=False)`获得;bias_attr同时可以是设置为布尔型,用来表示是否使用偏置项。
#### 空洞卷积的使用
Caffe:无法使用空洞卷积。
PaddlePaddle:使用`dilation`来设置空洞卷积。
#### 参数初始化
Caffe:Layer定义中共有两个结构体`param`用于设置局部学习率和权值衰减因子,其中第一个用于设置卷积核,第二个则用于设置偏值项;卷积核和偏置项的初始化参数在`convolution_param`中进行设置;是否使用偏置项可以使用`bias_term`进行设置;
PaddlePaddle:卷积核和偏置项的参数分别使用`param_attr``bias_attr`进行配置,配置参数如下所示,此外将`bias_attr`直接设为`False`表示不使用偏置项。
```
paddle.fluid.ParamAttr(
name=None,
initializer=None,
learning_rate=1.0,
regularizer=None,
trainable=True,
gradient_clip=None,
do_model_average=False
)
```
#### 空洞卷积
Caffe:无法使用空洞卷积;
PaddlePaddle:使用`dilation`参数来设置空洞卷积。
......@@ -29,17 +29,18 @@ paddle.fluid.layers.crop(
```
### 功能差异
#### 裁剪参考输入的差异
Caffe:裁剪参考输入只能是Variable的格式。
PaddlePaddle:剪裁参考输入可以是Variable,也可以是一个list或者tuple,其中放入每一个维度的维度数。
#### 裁剪偏移量输入的差异
#### 输出大小
Caffe:输入为`data1`,裁剪的输出大小与`data2`(Variable类型)一致;
PaddlePaddle:`shape`参数支持python list的方式传入输出大小,同时也支持`Variable`类型的输入。当`shape``Variable`类型时,用法与Caffe类似,裁剪输出大小与`shape`参数的大小一致。
#### 裁剪偏移量
Caffe:只需要设置需要裁剪的维度的偏移量。
PaddlePaddle:每一个维度需要设置偏移量。
### 代码示例
```
# Caffe示例:
# data1输入shape:(20,3,128,128)
# data2输入shape:(20,2,64,64)
# data1 shape:(20,3,128,128)
# data2 shape:(20,2,64,64)
layer {
name: "crop"
type: "Crop"
......@@ -58,9 +59,7 @@ layer {
```python
# PaddlePaddle示例:
# inputs1输入shape:(20,3,128,128)
# inputs2输入shape:(20,2,64,64)
output1 = fluid.layers.crop(x = inputs1, shape=inputs2, offsets=[0,0,25,25])
# 输出shape:(20,2,64,64)
output = fluid.layers.crop(x = inputs1, shape=[20,2,64,64], offsets=[0,0,25,25])
# 输出shape:(20,2,64,64),其与output1输出结果一致
```
......@@ -57,10 +57,20 @@ paddle.fluid.layers.conv2d_transpose(
```
### 功能差异
#### 参数初始化的差异
Caffe:第一个`param`负责设置卷积核的局部学习率和权值衰减因子,第二个`param`则负责设置偏置项的局部学习率和权值衰减因子;而卷积核和偏置项的在`convolution_param`中进行设置;是否使用偏置项可以使用`bias_term`进行设置。
PaddlePaddle:卷积核和偏置项的多处设置均分别在一个参数——`param_attr`/`bias_attr`中完成所有操作。二者的默认值为None,而ParamAttr是一个初始化结果,其可以通过`paddle.fluid.ParamAttr(name=None, initializer=None, learning_rate=1.0, regularizer=None, trainable=True, gradient_clip=None, do_model_average=False)`获得;bias_attr同时可以是设置为布尔型,用来表示是否使用偏置项。
#### 空洞卷积的使用
Caffe:无法使用空洞卷积。
PaddlePaddle:使用`dilation`来设置空洞卷积。
#### 参数初始化
Caffe:Layer定义中共有两个结构体`param`用于设置局部学习率和权值衰减因子,其中第一个用于设置卷积核,第二个则用于设置偏值项;卷积核和偏置项的初始化参数在`convolution_param`中进行设置;是否使用偏置项可以使用`bias_term`进行设置;
PaddlePaddle:卷积核和偏置项的参数分别使用`param_attr``bias_attr`进行配置,配置参数如下所示,此外将`bias_attr`直接设为`False`表示不使用偏置项。
```
paddle.fluid.ParamAttr(
name=None,
initializer=None,
learning_rate=1.0,
regularizer=None,
trainable=True,
gradient_clip=None,
do_model_average=False
)
```
#### 空洞卷积
Caffe:无法使用空洞卷积;
PaddlePaddle:使用`dilation`参数来设置空洞卷积。
......@@ -28,6 +28,14 @@ paddle.fluid.layers.dropout(
```
### 功能差异
#### 输入参数的差异
Caffe:输出的是PaddlePaddle中`dropout_implementation`设置为`upscale_in_train`的结果。
PaddlePaddle:相对于Caffe,多使用了`seed``dropout_implementation``is_test`几个参数。
#### 实现方式
Caffe:采用`upscale_in_train`方式实现;
PaddlePaddle:实现方式支持`downgrade_in_infer``upscale_in_infer`两种方式。
```
1. downgrade_in_infer实现方式
训练时: out = input * mask
预测时: out = input * dropout_prob
2. upscale_in_infer实现方式
训练时: out = input * mask / (1.0 - dropout_prob)
预测时: out = input
```
......@@ -19,7 +19,9 @@ layer {
```
### [paddle.fluid.layers.elementwise_sum](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#permalink-61-elementwise_add)、[paddle.fluid.layers.elementwise_max](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#permalink-63-elementwise_max)、[paddle.fluid.layers.elementwise_mul](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#permalink-65-elementwise_mul)
### [paddle.fluid.layers.elementwise_sum](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#permalink-61-elementwise_add)
### [paddle.fluid.layers.elementwise_max](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#permalink-63-elementwise_max)
### [paddle.fluid.layers.elementwise_mul](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#permalink-65-elementwise_mul)
```python
paddle.fluid.layers.elementwise_sum(
x,
......@@ -46,44 +48,18 @@ paddle.fluid.layers.elementwise_mul(
```
### 功能差异
#### 输入数据的差异
假设逐元素操作的两个输入分别是`X``Y`
Caffe:`X``Y``shape`必须按相同,否则会出错。
#### 输入数据
Caffe:`num1``num2``shape`必须按相同;
PaddlePaddle:`Y``shape`可以是`X``shape`可以的一个连续子序列,并通过设置`axis`表示从哪一个维度开始对应。
#### 加法操作的差异
Caffe:可以通过设置`coeff`参数为加法的每个输入添加一个权重,所以实际上其可以完成剪发操作。
Caffe:可以通过设置`coeff`参数为加法的每个输入添加一个权重
PaddlePaddle:无权重设置功能。
#### 乘法操作的差异
Caffe:可以通过设置`stable_prod_grad`参数来选择是否渐进较慢的梯度计算方法。
#### 乘法操作
Caffe:可以通过设置`stable_prod_grad`参数来选择是否渐进较慢的梯度计算方法;
PaddlePaddle:无设置`stable_prod_grad`参数的功能。
#### 其他差异
Caffe:激活函数需要由另外一层完成。
PaddlePaddle:可以通过设置`act`对逐元素操作后的tensor变量执行非线性激活。
### 代码示例
```
# Caffe示例:
# 输入num1的shape:(2,3,4,5)
# 输入num2的shape:(2,3,4,5)
layer {
name: "eltwise"
type: "Eltwise"
bottom: "num1"
bottom: "num2"
top: "sum"
eltwise_param{
operation: SUM
coeff: 1
coeff: 1
}
}
# 输出shape:(2,3,4,5)
```
```python
# PaddlePaddle示例:
# 输入num1的shape:(2,3,4,5)
# 输入num2的shape:(3,4)
output = paddle.fluid.layers.elementwise_sum(x = num1, y = num2, axis = 1)
# 输出shape:(2,3,4,5)
```
#### 其他
Caffe:激活函数需要由另外一层完成;
PaddlePaddle:可以通过设置`act`对逐元素操作后的tensor变量执行非线性激活。
......@@ -22,15 +22,26 @@ paddle.fluid.layers.square_error_cost(
```
### 功能差异
#### 计算机制的差异
Caffe:计算的是整个输入的欧氏距离除以两倍的样本个数,最终获得的是一个值。
#### 实现方式
Caffe:对整个输入的欧氏距离进行取和后除以两倍的样本个数,最终获得一个标量数值。
PaddlePaddle:使用elemenwise方式,计算`input``label`对应元素的欧式距离,最终获得一个array(输入和输出`shape`一致):
PaddlePaddle:计算的是`input``label`中每个值对应的L2距离,输出的大小和输入大小一致。若要通过PaddlePaddle实现Caffe的这一操作可以通过下面示例完成:
### 代码示例
```python
inputs = paddle.fluid.layers.data(name = 'data1', shape = [2,3,227,227], append_batch_size = False, dtype = 'float32')
labels = paddle.fluid.layers.data(name = 'data1', shape = [2,3,227,227], append_batch_size = False, dtype = 'float32')
loss = paddle.fluid.layers.square_error_cost(input = inputs, label = labels)
sum = paddle.fluid.layers.sum(x = loss)
res = sum/(2*inputs.shape[0])
# 利用PaddlePaddle实现Caffe的EuclideanLoss
def EuclideanLoss(inputs, label):
elw_eud = fluid.layers.square_error_cost(data, label)
eud = fluid.layers.reduce_mean(elw_eud)
eud = fluid.layers.scale(eud, scale=0.5)
return eud
# 调用函数计算欧氏路离
# inputs: [1, 2, 4, 5, 6]
# labels: [6, 5, 4, 3, 2]
# eud: 5.4
inputs = fluid.layers.data(dtype='float32', shape=[5], name='data')
labels = fluid.layers.data(dtype='float32', shape=[5], name='label')
eud = EulideanLoss(inputs, labels)
```
......@@ -26,7 +26,7 @@ paddle.fluid.layers.exp(
```
### 功能差异
#### 计算机制的差异
#### 计算机制
Caffe:有三个关于计算的参数,其计算公式为:
$$
y=\begin{cases}
......
......@@ -16,52 +16,24 @@ layer {
```
### [paddle.fluid.layers.flatten](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#permalink-72-flatten)
### [paddle.fluid.layers.reshape](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#permalink-72-reshape)
```python
paddle.fluid.layers.flatten(
paddle.fluid.layers.reshape(
x,
axis = 1,
name = None
shape,
actual_shape=None,
act=None,
inplace=False,
name=None
)
```
### 功能差异
#### 转换机制的差异
Caffe:有两个参数,`axis`代表转换起始点,`end_axis`代表转换终止点,假设输入数据的维度为n,则`axis``end_axis`的取值范围都是[-n,n-1](其中当i是一个大于等于-n的负值时,可以将其等同于i+n)。它有两种用法:当`axis<=end_axis`时,代表将第`axis+1`维数据至第`end_axis+1`维数据压缩至同一纬度的数据;当`axis`是一个大于等于-n的负值或者0且`end_axis=axis+n-1`时,代表在第`end_axis+1`个维度插入一个维度,且该维度大小为1,其余维度后移。
PaddlePaddle:只有一个参数`axis`,其取值范围为[0,n],小于等于`axis`的维度压缩成一个维度,剩下的压缩成另一个维度,当某一边维度数为0时,则添入一个维度大小为1的维度。
### 代码示例
```
# Caffe代码示例:
# 输入shape:(10,3,5,5)
layer {
name: "flatten"
type: "Flatten"
bottom: "data"
top: "flatten"
flatten_param{
axis: 1
end_axis: -2
}
}
# 输出shape:(10,15,10)
layer {
name: "flatten"
type: "Flatten"
bottom: "data"
top: "flatten"
flatten_param{
axis: 1
end_axis: -2
}
}
# 输出shape:(10,3,5,1,5)
#### 输入参数
Caffe:分别使用参数`axis``end_axis`表示起始轴和结束轴,[axis, end_axis]轴上的数据将被压缩至一维,
但如若`axis-end_axis==1`时,则会在`axis`轴之后插入一维;
> 输入数据shape[2, 3, 4, 5]
> axis=1, end_axis=3:输出shape[2, 60]
> axis=3, end_axis=2:输出shape[2, 3, 4, 1, 5]
```
```python
# PaddlePaddle示例:
# 输入shape:(10,3,5,5)
output1 = paddle.fluid.layers.flatten(x = inputs , axis = 2)
# 输出shape:(30,15)
output2 = paddle.fluid.layers.flatten(x = inputs , axis = 4)
# 输出shape:(450,1)
```
PaddlePaddle:通过在`shape`参数设置具体的输出shape。
......@@ -47,18 +47,25 @@ paddle.fluid.layers.fc(
```
### 功能差异
#### 参数初始化的差异
Caffe:第一个`param`负责设置卷积核的局部学习率和权值衰减因子,第二个`param`则负责设置偏置项的局部学习率和权值衰减因子;而卷积核和偏置项的在`convolution_param`中进行设置;是否使用偏置项可以使用`bias_term`进行设置。
PaddlePaddle:Caffe中的卷积核和偏置项的多处设置均分别在一个参数——`param_attr`/`bias_attr`中完成所有操作。二者的默认值为None,而ParamAttr是一个初始化结果,其可以通过`paddle.fluid.ParamAttr(name=None, initializer=None, learning_rate=1.0, regularizer=None, trainable=True, gradient_clip=None, do_model_average=False)`获得;bias_attr同时可以是设置为布尔型,用来表示是否使用偏置项。
#### 参数格式的差异
Caffe:输入参数的数据格式是`(filter_num, channel*height*width)`
PaddlePaddle:在`num_flatten_dims=1`且维度为4的情况下,其输入参数的输入数据格式则是`(channel*height*width, filter_num)`,而其他不管什么情况PaddlePaddle的filter_num都始终应该放在第二维。
#### 输入数据扁平化的差异
Caffe:将输入数据的第一维默认为batch size,其他剩余的几个维度扁平化压缩成一个向量进行全连接的计算。
PaddlePaddle:通过设置`num_flatten_dims`的值,确认后`rank(input)-num_flatten_dim`个维度扁平化压缩成一个向量进行全连接计算。
#### 参数初始化
Caffe:Layer定义中共有两个结构体`param`用于设置局部学习率和权值衰减因子,其中第一个用于设置权重,第二个则用于设置偏值项;权重和偏置项的初始化参数在`InnerProduct`中进行设置;是否使用偏置项可以使用`bias_term`进行设置;
PaddlePaddle:权重和偏置项的参数分别使用`param_attr``bias_attr`进行配置,配置参数如下所示,此外将`bias_attr`直接设为`False`表示不使用偏置项。
```
paddle.fluid.ParamAttr(
name=None,
initializer=None,
learning_rate=1.0,
regularizer=None,
trainable=True,
gradient_clip=None,
do_model_average=False
)
```
#### 多维输入
Caffe:将输入数据的第一维默认为batch size,其余维度压缩至一维后,得到新的二维输入进行全连接计算;
PaddlePaddle:`[0, num_flatten_dims)``[num_flattens_dim, )`维上的数据分别被压缩至一维,得到新的二维输入进行全连接计算。
#### 其他差异
#### 其他
Caffe:需要在另一个层中定义激活函数。
PaddlePaddle:可以通过设置`act`这一参数来确定输出的激活函数。
......@@ -63,8 +63,10 @@ layer{
``` python
# PaddlePaddle示例:
inputs1 = paddle.fluid.layers.data(name = 'data1', shape = [10,3,227,227], dtype = 'float32', append_batch_size = False)
# 数据shape为[10,3,227,227]
inputs2 = paddle.fluid.layers.data(name = 'data2', shape = [3,227,227], dtype = 'float32')
inputs1 = paddle.fluid.layers.data(name='data1', shape=[10,3,227,227],
dtype='float32', append_batch_size=False)
# 数据shape为[-1,3,227,227]
inputs2 = paddle.fluid.layers.data(name='data2', shape=[3,227,227], dtype='float32')
```
......@@ -31,20 +31,16 @@ paddle.fluid.layers.lrn(
```
### 功能差异
#### 计算机制的差异
Caffe:
计算机制:
$$output(i,x,y)=input(i,x,y)/(1+\frac{\alpha}{n}\sum_{j=max(0,i-\frac{n}{2})}{min(C,i+\frac{n}{2}}{input(j,x,y)^2})^\beta$$
位移数只能是1,同时在计算缩放参数时还除以累加通道数。
#### 参数差异
Caffe:参数`norm_region`支持`ACROSS_CHANNELS``WITHIN_CHANNEL`两种模式;
PaddlePaddle:默认且仅支持`ACROSS_CHANNELS`模式。
#### 计算机制
Caffe:在`ACROSS_CHANNELS`模式下,计算公式如下,
$$output(i,x,y)=input(i,x,y)/(1+\frac{\alpha}{n}\sum_{j=max(0,i-\frac{n}{2})}^{min(C,i+\frac{n}{2})}{input(j,x,y)^2})^\beta$$
位移值固定为1,计算缩放参数的同时除以通道数目
PaddlePaddle:
计算机制:
$$output(i,x,y)=input(i,x,y)/(k+\alpha\sum_{j=max(0,i-\frac{n}{2})}{min(C,i+\frac{n}{2}}{input(j,x,y)^2})^\beta$$
PaddlePaddle:计算公式如下,
$$output(i,x,y)=input(i,x,y)/(k+\alpha\sum_{j=max(0,i-\frac{n}{2})}^{min(C,i+\frac{n}{2})}{input(j,x,y)^2})^\beta$$
能通过设置k来定义位移数。
#### 其他差异
Caffe:可以通过设置`norm_region`参数来制定规范化方式,分别为通道间规范化(`ACROSS_CHANNELS`)和通道内规范化(`WITHIN_CHANNEL`)。
PaddlePaddle:默认只能使用通道间规范化。
......@@ -26,14 +26,15 @@ paddle.fluid.layers.log(
```
### 功能差异
#### 计算机制的差异
#### 计算机制
Caffe:有三个关于计算的参数,其计算公式为:
Caffe:计算公式如下,
$$
y=\begin{cases}
ln(shift+scale \times x),\quad base\leq 0 \\\\
log_base(shift+scale \times x),\quad base>0
log_{base}(shift+scale \times x),\quad base>0
\end{cases}
$$
PaddlePaddle:计算公式为:$$y=ln(x)$$
PaddlePaddle:计算公式如下,
$$y=ln(x)$$
......@@ -32,31 +32,27 @@ paddle.fluid.layers.pool2d(
```
### 功能差异
#### 计算输出高度和宽度的差异
计算池化的输出高度和宽度有两种方式,分别为向上取整(ceil)和向下取整(floor),其计算方式如下列所示:
**向上取整:**
`H_out = (H_in-ksize[0]+2*padding[0])/strides[0]+1`
`W_out = (W_in-ksize[1]+2*padding[1])/strides[1]+1`
**向下取整:**
`H_out = (H_in-ksize[0]+2*padding[0]+strides[0]-1)/strides[0]+1`
`W_out = (W_in-ksize[1]+2*padding[1]+strides[1]-1)/strides[1]+1`
Caffe:只能使用向上取整的方式来计算输入输出的大小。
PaddlePaddle:可以使用`ceil_mode`参数来定义使用何种计算方式,当`ceil_mode=False`(默认值)时使用向下取整的方式来计算,反之为`True`时则使用向上取整的方式进行计算。
#### 池化方式的差异
Caffe:提供了三种池化方式——最大池化、均值池化和随机池化(随机池化通过对像素点按照数值大小赋予概率,再按照概率进行亚采样)。
PaddlePaddle:提供了两种池化方式——最大池化和均值池化。
#### 输出大小
Caffe:输出大小计算方式如下所示,
```
H_out = (H_in-ksize[0]+2*padding[0])/strides[0]+1
W_out = (W_in-ksize[1]+2*padding[1])/strides[1]+1
```
PaddlePaddle:`ceil_mode``Ture`时,输出大小计算方式与Caffe一致;当`ceil_mode``False`时,输出大小计算方式如下所示,
```
# ceil_model为False时,计算公式
H_out = (H_in-ksize[0]+2*padding[0]+strides[0]-1)/strides[0]+1
W_out = (W_in-ksize[1]+2*padding[1]+strides[1]-1)/strides[1]+1
```
#### 池化方式
Caffe:通过`pool`参数设置,支持`MAX`, `AVE``STOCHASTIC`三种池化方式;
PaddlePaddle:通过`pool_type`参数设置,支持`max``avg`两种池化方式。
#### 其他差异
Caffe:无`exclusive`参数
PaddlePaddle:使用了一个`exclusive`参数,其代表在进行平均池化时是否忽略填充值。
#### 其他
Caffe:无`exclusive`参数
PaddlePaddle:`exclusive`参数为`True`的情况下,`avg`平均池化过程中会忽略填充值。
### 代码示例
......
......@@ -27,6 +27,8 @@ paddle.fluid.layers.power(
```
### 功能差异
#### 计算机制的差异
Caffe:有三个关于计算的参数,其计算公式为:$$y=(shift+scale \times x)^2$$
PaddlePaddle:只有一个关于计算的参数`factor`,其计算公式为:$$y=x^factor$$
#### 计算机制
Caffe:计算公式如下所示,
$$y=(shift+scale \times x)^2$$
PaddlePaddle:计算公式如下所示,
$$y=x^{factor}$$
......@@ -21,7 +21,7 @@
| 12 | [ELU](http://caffe.berkeleyvision.org/tutorial/layers/elu.html) | [paddle.layers.fluid.elu](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#permalink-68-elu) | 接口对应 |
| 13 | [EuclideanLoss](http://caffe.berkeleyvision.org/tutorial/layers/euclideanloss.html) | [paddle.fluid.layers.square_error_cost](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#permalink-167-square_error_cost) | [差异对比](EuclideanLoss.md) |
| 14 | [Exp](http://caffe.berkeleyvision.org/tutorial/layers/exp.html) | [paddle.fluid.layers.exp](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#permalink-186-exp) | [差异对比](Exp.md) |
| 15 | [Flatten](http://caffe.berkeleyvision.org/tutorial/layers/flatten.html) | [paddle.fluid.layer.flatten](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#permalink-72-flatten) | [差异对比](Flatten.md) |
| 15 | [Flatten](http://caffe.berkeleyvision.org/tutorial/layers/flatten.html) | [paddle.fluid.layer.reshape](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#permalink-72-reshape) | [差异对比](Flatten.md) |
| 16 | [InnerProduct](http://caffe.berkeleyvision.org/tutorial/layers/innerproduct.html) | [paddle.fluid.layers.fc](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#permalink-71-fc) | [差异对比](InnerProduct.md) |
| 17 | [Input](http://caffe.berkeleyvision.org/tutorial/layers/input.html) | [paddle.fluid.layers.data](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#permalink-20-data) | [差异对比](Input.md) |
| 18 | [Log](http://caffe.berkeleyvision.org/tutorial/layers/log.html) | [paddle.fluid.layers.log](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#permalink-93-log) | [差异对比](Log.md) |
......
......@@ -17,7 +17,8 @@ layer {
```
### [paddle.fluid.layers.reduce_sum](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#permalink-127-reduce_sum)、[paddle.fluid.layers.reduce_mean](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#permalink-124-reduce_mean)
### [paddle.fluid.layers.reduce_sum](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#permalink-127-reduce_sum)
### [paddle.fluid.layers.reduce_mean](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#permalink-124-reduce_mean)
```python
paddle.fluid.layers.reduce_sum(
input,
......@@ -25,7 +26,8 @@ paddle.fluid.layers.reduce_sum(
keep_dim=False,
name=None
)
```
```
paddle.fluid.layers.reduce_mean(
input,
dim=None,
......@@ -35,13 +37,14 @@ paddle.fluid.layers.reduce_mean(
```
### 功能差异
#### 输入参数的差异
Caffe:一个层里面可以是`SUM``ASUM``SUMSQ`或者`MEAN`这四种操作。
PaddlePaddle:只能完成里面的两种操作。同时Caffe可以设置`coeff`来将每个值乘以一个系数。
#### 操作类型
Caffe:通过`operation`参数支持`SUM``ASUM``SUMSQ``MEAN`四种操作;
PaddlePaddle:`reduce_sum``reduce_mean`分别对应Caffe的`SUM``MEAN`操作,另外两种无对应。
#### 计算方式
Caffe:`axis``int`型参数,该维及其后维度,均会被降维,且不保留对应部分的维度,如shape为`(30, 3, 6, 8)``axis`为2的情况下,得到的输出shape为`(30, 3)`
PaddlePaddle:`dim`参数为`list`型参数,其指定的维度才会被降维,且当`keep_dim``True`时,降维的维度仍会以`1`的形式保留下来,如shape为`(30, 3, 6, 8)``dim``[2, 3]``keep_dim``True`的情况下,得到的输出shape为`(30, 3, 1, 1)`
#### 输出的差异
Caffe:`axis`往后的每个维度都会缩减为一个维度。
PaddlePaddle:只会缩减`dim`中list定义的维度,并根据`keep_dim`确定是否在输出Tensor中保留减小的维度。
### 代码示例
```
# Caffe示例:
......
## Scale
### [Scale](http://caffe.berkeleyvision.org/tutorial/layers/scale.html)
```
layer {
name: "scale"
type: "Scale"
bottom: "data"
top: "scale"
scale_param{
axis: 1
num_axes: 1
filter{
type: "constant"
value: 2
}
bias_term: true
bias_filter{
type: "constant"
value: 0.5
}
}
}
```
### [paddle.fluid.layers.scale](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#permalink-137-scale)
```python
paddle.fluid.layers.scale(
x,
scale=1.0,
bias=0.0,
bias_after_scale=True,
act=None,
name=None
)
```
### 功能差异
#### 输入参数的差异
Caffe:设置了`filter``bias_filter`,它们在训练阶段被用来初始化,在测试阶段`filter``bias_filter`的值都将被忽略。输入参数的维度由`axis`来定义,以大小为`100*3*40*60`的输入为例,其输入参数维度如下所示:
| axis值 | 可能维度1 | 可能维度2 | 可能维度3 | 可能维度4 |
| :---------: | :-------: | :-------: | :-------: | :---------: |
| axis==0==-4 | $$100$$ | $$100\times3$$ | $$100\times3\times40$$ | $$100\times3\times40\times60$$ |
| axis==1==-3 | $$3$$ | $$3\times40$$ | $$3\times40\times60$$ | |
| axis==2==-2 | $$40$$ | $$40\times60$$ | | |
| axis==3==-1 | $$60$$ | | | |
PaddlePaddle:不存在输入参数的维度问题,它的`scale``bias`在定义中设置了。
#### 计算方式的差异
Caffe:只能在缩放之后添加bias。
PaddlePaddle:可以通过设置`bias_after_scale`设置是在缩放之后还是之前添加bias。
#### 其他差异
Caffe:激活函数需要由另外一层完成。
PaddlePaddle:可以通过设置`act`看是否在进行Scale后进行激活函数的操作。
......@@ -25,12 +25,13 @@ paddle.fluid.layers.sigmoid_cross_entropy_with_logits(
```
### 功能差异
#### 输入的差异
Caffe:输入的数据维度最大是4维(`N*C*H*W`)。
PaddlePaddle:输入只能是2维(`N*H`)。
#### 输出的差异
Caffe:输出的数据大小是`1*1*1*1`,即将所有位置上的loss取均值。
#### 输入格式
Caffe:输入的数据维度最大是4维`N*C*H*W`
PaddlePaddle:输入只能是2维`N*H`
#### 输出格式
Caffe:输出的数据大小是`1*1*1*1`,即将所有位置上的loss取均值;
PaddlePaddle:输出和输入大小一致,即`N*H`
#### 其他差异
#### 其他
PaddlePaddle:可以通过设定`ignore_index`来确定忽略的目标值,同时它有一个`normalize`参数可以输出除以除去`ignore_index`对应目标外的目标数所得的结果。
......@@ -31,15 +31,10 @@ paddle.fluid.layers.slice(
```
### 功能差异
#### 输入参数的差异
Caffe:输入的`axis``alice_point`等参数都是数值。
PaddlePaddle:输入的`axes``starts``ends`等输入参数都是list类型。
#### slice机制的差异
Caffe:只能在一个维度上截取,但可以截取多个切片。
PaddlePaddle:可以在多个维度上截取,但只能截取到一个切片。
#### 其他差异
Caffe:可以使用`slice_dim`代替`axis`,但是其只能使用正值。
PaddlePaddle:如果传递给`starts``end`的值大于n(此维度中的元素数目),则表示n。
#### slice机制
Caffe:`axis``alice_point`参数为数值,只能在一个维度上截取,但可以截取多个切片;
PaddlePaddle:`axes``start``ends`参数为`list`类型,可以在多个维度上截取,但只能截取一个切片。
### 代码示例
```
# Caffe示例:
......
......@@ -22,6 +22,6 @@ paddle.fluid.layers.softmax(
```
### 功能差异
#### 计算机制的差异
Caffe:计算softmax之前,对每个样本中的每个值减去该样本中的最大值
#### 计算机制
Caffe:计算softmax之前,对每个样本中的每个值减去该样本中的最大值;
PaddlePaddle:省略了这一操作直接计算softmax。
......@@ -31,18 +31,18 @@ paddle.fluid.layers.softmax_with_cross_entropy(
```
### 功能差异
#### 计算机制的差异
计算softmax的loss时,根据每个样本是否被分配至多个类别中可以分为两类——硬标签和软标签,具体如下:
#### 计算机制
**硬标签:** 即one-hot label,每个样本仅分到一个类别中。在硬标签中,根据是否对未初始化的log概率进行预处理,又可以分为两类,预处理主要是完成对每个样本中的每个log概率减去该样本中的最大的log概率。
Caffe:只可以使用硬标签的输入,同时进行预处理操作。
PaddlePaddle:可以使用`soft_label`来设置是使用软标签(True)还是硬标签(False);将`numeric_stable_mode`设为True,同时在GPU环境下运行,可是在使用硬标签之前先进行预处理。此外,软标签和硬标签的label输入略有不同,当log概率的输入大小为`N*K`时(`N`代表batch size,`K`代表类别数量),软标签的输入大小为`N*K`,其重的数值数据类型为`float`或者`double`,每一个batch中的值都是0或者1(1代表属于这个类别,0则代表不属于);硬标签的输入大小为`N*1`,其重的数值数据类型为`int`,每一个batch中的值都是大于等于0且小于K(代表属于某一个类别)。在Caffe中,则只可以使用硬标签的输入,同时进行预处理操作。
**软标签:** 每个样本至少被分配到一个类别中。
> 计算softmax的loss时,根据每个样本是否被分配至多个类别中可以分为两类——硬标签和软标签,具体如下:
> **硬标签:** 即one-hot label,每个样本仅分到一个类别中。在硬标签中,根据是否对未初始化的log概率进行预处理,又可以分为两类,预处理主要是完成对每个样本中的每个log概率减去该样本中的最大的log概率。
Caffe:只可以使用硬标签的输入,同时进行预处理操作。
PaddlePaddle:可以使用`soft_label`来设置是使用软标签(True)还是硬标签(False);将`numeric_stable_mode`设为True,同时在GPU环境下运行,可是在使用硬标签之前先进行预处理。此外,软标签和硬标签的label输入略有不同,当log概率的输入大小为`N*K`时(`N`代表batch size,`K`代表类别数量),软标签的输入大小为`N*K`,其重的数值数据类型为`float`或者`double`,每一个batch中的值都是0或者1(1代表属于这个类别,0则代表不属于);硬标签的输入大小为`N*1`,其重的数值数据类型为`int`,每一个batch中的值都是大于等于0且小于K(代表属于某一个类别)。在Caffe中,则只可以使用硬标签的输入,同时进行预处理操作。
> **软标签:** 每个样本至少被分配到一个类别中。
#### 输出的差异
#### 输出结果
Caffe:输出是对所有样本的loss进行归一化后的结果,同时根据`normalize``normalization`的设置,归一化形式略有不同,当`normalization`是FULL或0时整个loss取和后除以batch的大小,当`normalization`是VALID或1时整个loss取和后除以除`ignore_label`以外的样本数,为NONE时则取和;当`normalization`未设置时,采用`normalize`的值进行判断,若`normalize==1`则归一化方式是VALID,若`normalize==0`则归一化方式是FULL。
PaddlePaddle:输出是每个样本的loss所组成的一个向量,同时如果将参数`return_softmax`设为True,则输出的是loss向量和softmax值组成的一个元组。
......
......@@ -26,6 +26,6 @@ paddle.fluid.layers.concat(
```
### 功能差异
#### 输入参数的差异
#### 输入参数
Caffe:只能在一个维度上进行复制。
PaddlePaddle:`expand_times`为一个list或tuple,它存放的是每个维度复制的倍数。
......@@ -8,7 +8,7 @@ onnx2fluid支持将onnx模型转换为PaddlePaddle模型,并用于预测,用
工具开发过程中,我们在如下环境配置中测试模型转换:
* python3.5+ (python2 working in progress)
* python3.5+
* onnx == 1.4.0
* paddlepaddle == 1.3.0
......@@ -20,38 +20,41 @@ onnx2fluid支持将onnx模型转换为PaddlePaddle模型,并用于预测,用
conda install -c conda-forge onnx
```
## Get started
Test with pretrained models from ONNX repositories:
``` shell
## 使用说明
```shell
# 安装
git clone https://github.com/PaddlePaddle/X2Paddle.git
cd X2Paddle/onnx2fluid
python setup.py install
cd examples
sh onnx_model_zoo.sh
```
Try exporting from PyTorch to Paddle fluid:
``` shell
python setup.py install
cd examples
python gen_some_samples.py
onnx2fluid sample_1.onnx -t sample_1.npz
# 模型转换
python -m onnx2fluid -o /path/to/export_dir/ /path/of/onnx/model.onnx
```
**示例:VGG19模型**
```shell
wget https://s3.amazonaws.com/download.onnx/models/opset_9/vgg19.tar.gz
tar xzvf vgg19.tar.gz
## 使用说明
python -m onnx2fluid -o paddle_model vgg19/model.onnx
```
转换后的PaddlePaddle模型加载可参考文档[加载预测模型](http://www.paddlepaddle.org/documentation/docs/zh/1.3/api_guides/low_level/inference.html#id4)
## 模型测试
目录[examples](examples)中集成了部分ONNX预训练模型的转换测试
```shell
onnx2fluid [-dexy] -o /path/to/export_dir/ /path/of/onnx/model.onnx
optional arguments:
--embed_params, -e try to embed parameters for trainable Paddle fluid layers
--no-pedantic, -x process non-standard ONNX ops
--skip-version-conversion, -y
skip ONNX op version conversion, workaround for
RumtimeErrors
--archive [ARCHIVE], -z [ARCHIVE]
compress outputs to ZIP file if conversion successed
cd examples
# 测试和验证各onnx模型的转换
sh onnx_model_zoo.sh
```
转换后的PaddlePaddle模型加载可参考文档[加载预测模型](http://www.paddlepaddle.org/documentation/docs/zh/1.3/api_guides/low_level/inference.html#id4)
目前测试脚本中已包含的测试模型如下,
1. [bvlc_alexnet](https://s3.amazonaws.com/download.onnx/models/opset_9/bvlc_alexnet.tar.gz)
2. [bvlc_googlenet](https://s3.amazonaws.com/download.onnx/models/opset_9/bvlc_googlenet.tar.gz)
3. [bvlc_reference_caffenet](https://s3.amazonaws.com/download.onnx/models/opset_9/bvlc_reference_caffenet.tar.gz)
4. [bvlc_reference_rcnn_ilsvrc13](https://s3.amazonaws.com/download.onnx/models/opset_9/bvlc_reference_rcnn_ilsvrc13.tar.gz)
5. [inception_v1](https://s3.amazonaws.com/download.onnx/models/opset_9/inception_v1.tar.gz)
6. [inception_v2](https://s3.amazonaws.com/download.onnx/models/opset_9/inception_v2.tar.gz)
7. [resnet50](https://s3.amazonaws.com/download.onnx/models/opset_9/resnet50.tar.gz)
8. [shufflenet](https://s3.amazonaws.com/download.onnx/models/opset_9/shufflenet.tar.gz)
9. [squeezenet](https://s3.amazonaws.com/download.onnx/models/opset_9/squeezenet.tar.gz)
10. [vgg19](https://s3.amazonaws.com/download.onnx/models/opset_9/vgg19.tar.gz)
11. [zfnet512](https://s3.amazonaws.com/download.onnx/models/opset_9/zfnet512.tar.gz)
# onnx2fluid
[![License](https://img.shields.io/badge/license-Apache%202-blue.svg)](LICENSE)
onnx2fluid supports converting ONNX model to PaddlePaddle Model for prediction.
## Running Environment
* python3.5+ (python2 working in progress)
* onnx == 1.4.0
* paddlepaddle == 1.3.0
## Get started
Test with pretrained models from ONNX repositories:
``` shell
python setup.py install
cd examples
sh onnx_model_zoo.sh
```
Try exporting from PyTorch to Paddle fluid:
``` shell
python setup.py install
cd examples
python gen_some_samples.py
onnx2fluid sample_1.onnx -t sample_1.npz
```
## Usage
```shell
onnx2fluid [-dexy] -o /path/to/export_dir/ /path/of/onnx/model.onnx
optional arguments:
--embed_params, -e try to embed parameters for trainable Paddle fluid layers
--no-pedantic, -x process non-standard ONNX ops
--skip-version-conversion, -y
skip ONNX op version conversion, workaround for
RumtimeErrors
--archive [ARCHIVE], -z [ARCHIVE]
compress outputs to ZIP file if conversion successed
```
......@@ -3,6 +3,8 @@
tensorflow2fluid支持将训练好的TensorFlow模型转换为PaddlePaddle模型,包括基于PaddlePaddle实现的模型前向计算网络python代码,以及PaddlePaddle可加载的模型参数文件。
此外在[[doc](doc)]目录中整理了TensorFlow-PaddlePaddle的常用API对比分析。
[环境安装](#环境安装)&nbsp;&nbsp;[使用方法](#使用方法)&nbsp;&nbsp;[验证模型](#验证模型)&nbsp;&nbsp;[常见问题](#常见问题)
## 环境安装
......@@ -91,7 +93,7 @@ ref_name.info|my_model.py中各tensor与原TensorFlow模型中的tensor对应关
const_\*/params_\*|转换后的模型参数文件
save_var.list|模型载入过程中的变量list
## 支持模型
## 验证模型
tensorflow2fluid在如下tensorflow模型上测试了模型转换前后的diff
| 模型类别 | 模型 | Code | 最大diff |
......@@ -105,6 +107,26 @@ tensorflow2fluid在如下tensorflow模型上测试了模型转换前后的diff
| | YOLO-V3 | [code](https://github.com/mystic123/tensorflow-yolo-v3) | 6.20E-04 |
| 语义分割 | Unet | [code](https://github.com/jakeret/tf_unet) | 4.17E-07 |
## 常见问题
1. 转换参数`input_format`的设定?
> TensorFlow中的CV模型,大多采用`NHWC`的输入格式,但同时也可以支持`NCHW`的格式输入;而在PaddlePaddle中,支持的是`NCHW`的格式。因此需要在转换模型时,指定TensorFlow模型的输入格式,转换过程中会根据输入格式,对输入数据,参数进行变换。
2. 转换参数`input_shape`的设定?
> 在模型转换时,需设定输入数据的具体`shape`。因为转换过程中,涉及到较多参数的转换,因此模型转换完成应用到预测时,输入数据的`shape`也须与之前指定的一致,否则可能会出错。
3. 转换参数`use_cuda`的设定?
> 受限于PaddlePaddle与TensorFlow部分OP上的实现差异,部分tensor参数(在TensorFlow中,这部分参数类型是tensor类型,但值保持不变)需要通过infer得到。因此模型转换过程中,同时也会加载tensorflow模型进行预测,消耗计算资源。在有GPU资源的的前提下,将`use_cuda`设为`True`有助于提升转换速度。
4. 模型转换前后diff对比?
> tensorflow2fluid仍在不断完善和测试中,用户转换完模型后,注意对比模型在转换前后的输出diff是否在可接受范围内。此外转换后的模型结构`mymodel.py`如存在构建失败的问题,可能是由于部分参数在特殊情况下未被考虑到导致,用户可以直接通过修改`mymodel.py`来解决。
5. 模型转换失败,提示"Unsupported OP: XXX"?
> 目前tf2fluid支持50个左右常见OP的转换,仍然在不断补充中,当出现如上提示时,即表示模型存在暂未支持的OP,用户可以直接在[tf2fluid/paddle_emitter.py](tf2fluid/paddle_emitter.py)中仿照`emit_xxx`函数添加转换代码支持,或者也欢迎通过提ISSUE的方式让我们知道你的需求!
## Link
本目录下部分代码参考了MMdnn-Tensorflow,对此表示感谢!
......
此差异已折叠。
## 比较函数
在PaddlePaddle中使用运算符来对tensor之间进行`element-wise`方式的对比。其与TensorFlow相应接口关系如下表所示,
| TensorFlow接口 | PaddlePaddle接口 |
|--------------------------|-------------------------------------------------|
|[tf.math.less_equal](https://www.tensorflow.org/api_docs/python/tf/math/less_equal)|运算符`<=`|
|[tf.math.greater](https://www.tensorflow.org/api_docs/python/tf/math/greater)|运算符`>`|
|[tf.math.greater_equal](https://www.tensorflow.org/api_docs/python/tf/math/greater_equal)|运算符`>=`|
|[tf.math.equal](https://www.tensorflow.org/api_docs/python/tf/math/equal)|运算符`==`[paddle.fluid.layers.equal](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#permalink-7-equal) |
|[tf.math.less](https://www.tensorflow.org/api_docs/python/tf/math/less)|运算符`<`[paddle.fluid.layers.less_than](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#permalink-11-less_than) |
## tf.case
### [tf.case](https://www.tensorflow.org/api_docs/python/tf/case)
```python
tf.case(
pred_fn_pairs,
default=None,
exclusive=False,
strict=False,
name='case'
)
```
### [paddle.fluid.layers.While](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#while)
```python
class paddle.fluid.layers.Switch(
name=None
)
```
### 功能差异
#### 使用方式
TensorFlow:用户采用定义`条件-函数对`的方式,创建一个`case`操作;
PaddlePaddle:用户通过在`switch`代码块中,定义`case`分支方式,实现`switch`操作。与TensorFlow对比,在使用形式上更类似于传统的c/c++代码。
### 代码示例
```
# 如下代码展示进行学习率的调度,当global_step超过某个数值时,学习率减小
# 定义学习率tensor
lr = fluid.layers.tensor.create_global_var(
shape=[1],
value=0.0,
dtype='float32',
persistable=True,
name="learning_rate")
# 定义学习率常量
lr_0 = tensor.fill_constant(
shape=[1], dtype='float32', value=1.0)
lr_1 = tensor.fill_constant(
shape=[1], dtype='float32', value=0.1)
# 当global_step超过10000时,采用lr_1,否则采用lr_0
with fluid.layers.control_flow.Switch() as switch:
with switch.case(global_step > 10000):
fluid.layers.tensor.assign(input=lr_1, output=lr)
with switch.default():
fluid.layers.tensor.assign(input=lr_0, output=lr)
```
## tf.contrib.rnn.GRUCell
### [tf.contrib.rnn.GRUCell](https://www.tensorflow.org/api_docs/python/tf/nn/rnn_cell/GRUCell)
```python
tf.contrib.rnn.GRUCell(
num_units,
activation=None,
reuse=None,
kernel_initializer=None,
bias_initializer=None,
name=None,
dtype=None,
**kwargs
)
```
### [paddle.fluid.layers.gru_unit](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#gru-unit)
```python
paddle.fluid.layers.gru_unit(
input,
hidden,
size,
param_attr=None,
bias_attr=None,
activation='tanh',
gate_activation='sigmoid',
origin_mode=False
)
```
### 功能差异
#### 实现方式
TensorFlow:GRU的实现方式见论文[Learning Phrase Representations using RNN Encoder-Decoder for Statistical Machine Translation](http://arxiv.org/abs/1406.1078)
PaddlePaddle:GRU有两种实现方式,当设置`origin_mode=False`时,与TensorFlow实现方式一致;当设置`origin_mode=True`时,实现方式则参考论文[Empirical Evaluation of
Gated Recurrent Neural Networks
on Sequence Modeling](https://arxiv.org/pdf/1412.3555.pdf)
#### 使用方式
TensorFlow:首先定义`GRUCell`对象,定义对象时只需要指定单元数`num_units`;由于`GRUCell`内部定义了`__call__`方法,因而其对象是可调用对象,直接使用`step_output, cur_state = cell(step_input, last_state)`的形式,可以计算得到当前步的输出与状态;
PaddlePaddle:提供op形式的调用接口,通常与[paddle.fluid.layers.DynamicRNN](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#dynamicrnn)配合使用,以获取序列中的单步输入。**注意,为了提高`gru_unit`的计算效率,用户在使用该接口时需要遵从如下约定:假设要指定的GRU单元数为`num_units`,则`size`以及`input.shape[-1]`必须为`3*num_units`,`hidden.shape[-1]`为`num_units`,见如下代码示例小节。**
#### 返回值
TensorFlow:返回一个二元组,分别是当前时刻的输出值与隐藏状态,实际上输出值与隐藏状态为相同的tensor;
PaddlePaddle:返回一个三元组,即`(hidden_value, reset_hidden_value, gate_value)`。后面两个元素为内部使用,用户可以只关注第一个元素。
### 代码示例
```
emb_size = 32
emb_vocab = 10000
num_unit_0 = 10
data = fluid.layers.data(name='input', shape=[1], dtype='int64', lod_level=1)
embedding = fluid.layers.embedding(input=data, size=[emb_vocab, emb_size],
is_sparse=False)
# 为了调用gru_unit,输入最后的维度必须为实际单元数的3倍
emb_fc = layers.fc(embedding, num_unit_0 * 3)
drnn = fluid.layers.DynamicRNN()
with drnn.block():
word = drnn.step_input(emb_fc)
# 指定上一时刻的隐状态,单元数为num_unit_0
prev_hid0 = drnn.memory(shape=[num_unit_0])
# 执行gru_unit计算,num_unit_0 为实际的单元数
cur_hid0, _, _ = layers.gru_unit(word, prev_hid0, num_unit_0 * 3)
# 更新隐状态
drnn.update_memory(prev_hid0, cur_hid0)
drnn.output(cur_hid0)
out = drnn()
last = fluid.layers.sequence_last_step(out)
```
## tf.expand_dims
### [tf.expand_dims](https://www.tensorflow.org/api_docs/python/tf/expand_dims)
``` python
tf.expand_dims(
input,
axis=None,
name=None,
dim=None
)
```
### [paddle.fluid.layers.unsqueeze](http://paddlepaddle.org/documentation/docs/zh/1.2/api_cn/layers_cn.html#unsqueeze)
``` python
paddle.fluid.layers.unsqueeze(
input,
axes,
name=None)
```
### 功能差异
#### 参数类型
TensorFlow:`axis``int`类型或`0-D`tensor, 使用`axis`指定要增加维度的位置,支持负数进行索引;
PaddlePaddle:`axes``list`类型,表示要增加维度的位置列表,支持在多个位置同时增加维度,也支持负数进行索引。
### 代码示例
```python
# 输入 tensor t 的 shape 为[3, 4]
# 输出 tensor out 的 shape 为[1, 3, 4]
out = fluid.layers.unsqueeze(t, [0])
# 输出 tensor out 的 shape 为[3, 4, 1]
out = fluid.layers.unsqueeze(t, [-1])
# 输出 tensor out 的 shape 为[1, 1,3, 4]
out = fluid.layers.unsqueeze(t, [0, 1])
```
## tf.image.non_max_suppression
### [tf.image.non_max_suppression](https://www.tensorflow.org/api_docs/python/tf/image/non_max_suppression)
``` python
tf.image.non_max_suppression(
boxes,
scores,
max_output_size,
iou_threshold=0.5,
score_threshold=float('-inf'),
name=None
)
```
### [paddle.fluid.layers.multiclass_nms](http://paddlepaddle.org/documentation/docs/en/1.3/api/layers.html#permalink-245-multiclass_nms)
``` python
paddle.fluid.layers.multiclass_nms(
bboxes,
scores,
score_threshold,
nms_top_k,
keep_top_k,
nms_threshold=0.3,
normalized=True,
nms_eta=1.0,
background_label=0,
name=None)
```
### 功能差异
#### 输入格式
TensorFlow:`boxes`的shape为`[num_boxes, 4]``scores`的shape为`[num_boxes]`
PaddlePaddle:相对比Tensorflow,还支持batch和多类别,`bboxes`的shape为`[batch, num_boxes, 4]``scores`的shape为`[batch, num_classes, num_boxes]`
#### 输出格式
TensorFlow: 返回shape为`[N]`的tensor,表示为`boxes`中选取的index集合,长度为`N`
PaddlePaddle: 返回`[N, 6]`[LodTensor](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/fluid_cn.html#lodtensor),其中每行内容为`[lable, confidence, xmin, ymin, xmax, ymax]`
#### 参数差异
TensorFlow: 在所有boxes中,根据其它参数条件,最终选出的boxes数量不超过`max_output_size`
PaddlePaddle: 在`nms_top_k`个boxes中,根据其它参数条件,最终选出的boxes数量不超过`keep_top_k`
### 代码示例
```python
clip_boxes = fluid.layers.data(dtype='float32', shape=[5000, 4], name='boxes')
scores = fluid.layers.data(dtype='float32', shape=[1, 5000], name='scores')
# nms_top_k=-1,表示在输入的所有boxes中选取
selected_boxes = fluid.layers.multiclass_nms(
clip_boxes,
scores,
scrore_threshold=0.5,
nms_top_k=-1,
keep_top_k=300,
nms_threshold=0.7)
```
## tf.image.resize_images
### [tf.image.resize_images](https://www.tensorflow.org/api_docs/python/tf/image/resize_images)
``` python
tf.image.resize_images(
images,
size,
method=ResizeMethod.BILINEAR,
align_corners=False,
preserve_aspect_ratio=False
)
```
### [paddle.fluid.layers.image_resize](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#paddle.fluid.layers.image_resize)
``` python
paddle.fluid.layers.image_resize(
input,
out_shape=None,
scale=None,
name=None,
resample='BILINEAR',
actual_shape=None,
align_corners=True,
align_mode=1
)
```
### 功能差异
#### 参数种类
TensorFlow:支持`BILINEAR`,`NEAREST`,`BICUBIC`, `AREA`四种方式;
PaddlePaddle:支持`BILINEAR``NEAREST`两种方式, `align_mode``BILINEAR`的可选项,当为1的时候,与TensorFlow功能一致。
### 代码示例
```python
# 输入图像数据shape为[None, 3, 300, 300]
inputs = fluid.layers.data(dtype='float32', shape=[3, 300, 300], name='inputs')
# 输出shape为[3, 400, 500]
outputs = fluid.layers.image_reisze(inputs, [400, 500])
```
## tf.layers.conv2d
### [tf.layers.conv2d](https://www.tensorflow.org/api_docs/python/tf/layers/conv2d)
``` python
tf.layers.conv2d(
inputs,
filters,
kernel_size,
strides=(1, 1),
padding='valid',
data_format='channels_last',
dilation_rate=(1, 1),
activation=None,
use_bias=True,
kernel_initializer=None,
bias_initializer=tf.zeros_initializer(),
kernel_regularizer=None,
bias_regularizer=None,
activity_regularizer=None,
kernel_constraint=None,
bias_constraint=None,
trainable=True,
name=None,
reuse=None
)
```
### [paddle.fluid.layers.conv2d](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#paddle.fluid.layers.conv2d)
``` python
paddle.fluid.layers.conv2d(
input,
num_filters,
filter_size,
stride=1,
padding=0,
dilation=1,
groups=None,
param_attr=None,
bias_attr=None,
use_cudnn=True,
act=None,
name=None)
```
### 功能差异
#### 数据格式
TensorFlow: 默认输入数据格式为`NHWC`,表示`(batch,height, width, in_channels)`, 同时也将`data_format`参数设为`channels_first`,支持`NCHW`格式的数据输入。其中输入、输出、卷积核对应关系如下表所示,
| 输入 | 卷积核 | 输出 |
|--------------------|-------------------|------------------|
|NHWC | (kernel_h, kernel_w, filters_num, in_channels)| (batch, out_h, out_w, filters_num)|
|NDHW | (kernel_h, kernel_w, filters_num, in_channels) | (batch, filters_num, out_h, out_w)|
PaddlePaddle:只支持输入数据格式为`NCHW`,且**卷积核格式**与TensorFlow不同,其中输入、输出、卷积核对应关系如下表所示,
| 输入 | 卷积核 | 输出 |
|--------------------|-------------------|------------------|
|NCHW | (in_channels, filters_num, kernel_h, kernel_w) | (batch, filters_num, out_h, out_w)|
#### Padding机制
TensorFlow: `SAME``VALID`两种选项。当为`SAME`时,padding的计算方式如下所示,
```python
# 计算在width上的padding size
# height上的padding计算方式同理
ceil_size = ceil(input_width / stride_width)
pad_size = (ceil_size - 1) * stride_width + filter_width - input_width
pad_left = ceil(pad_size / 2)
pad_right = pad_size - pad_left
```
PaddlePaddle:`padding`参数表示在输入图像四周padding的size大小。
#### 参数差异
TensorFlow:深度可分离卷积使用[tf.layers.separable_conv2d](https://www.tensorflow.org/api_docs/python/tf/layers/separable_conv2d)接口;
PaddlePaddle: 使用`paddle.fluid.layers.conv2d`,可参考
[PaddlePaddle对卷积的说明文档](http://paddlepaddle.org/documentation/docs/zh/1.3/api_guides/low_level/layers/conv.html), 同时也可参考[tf.nn.separable_conv2d](tf.nn.separable_conv2d.md)中的代码示例。
### 代码示例
```python
# 结合pad2d,实现SAME方式的padding
# 输入Shape:(None, 3, 200, 200)
# 输出Shape:(None, 5, 67, 67)
# 卷积核Shape: (5, 3, 4, 4)
inputs = paddle.fluid.layers.data(dtype='float32', shape=[3, 200, 200], name='inputs)
pad_inputs = paddle.fluid.layers.pad2d(inputs, paddings=[1, 2, 1, 2])
outputs = paddle.fluid.layers.conv2d(pad_inputs, 5, [4, 4], (1, 1))
## tf.layers.dense
### [tf.layers.dense](https://www.tensorflow.org/api_docs/python/tf/layers/dense)
``` python
tf.layers.dense(
inputs,
units,
activation=None,
use_bias=True,
kernel_initializer=None,
bias_initializer=tf.zeros_initializer(),
kernel_regularizer=None,
bias_regularizer=None,
activity_regularizer=None,
kernel_constraint=None,
bias_constraint=None,
trainable=True,
name=None,
reuse=None
)
```
### [paddle.fluid.layers.fc](http://paddlepaddle.org/documentation/docs/zh/1.2/api_cn/layers_cn.html#fc)
``` python
paddle.fluid.layers.fc(
input,
size,
num_flatten_dims=1,
param_attr=None,
bias_attr=None,
act=None,
is_test=False,
name=None
)
```
### 功能差异
#### 输入类型
TensorFlow:`inputs`为一个tensor;
PaddlePaddle:允许`input`是一个tensor或者是一个tensor 列表,如果是tensor列表的情况,该layer会声明多个kernel,个数与列表长度相同,在将列表中各个tensor与对应kernel做矩阵乘法之后,将各个结果相加。
#### kernel、bias初始化
TensorFlow:通过`kernel_initializer``bias_initializer``kernel``bias`进行初始化;
PaddlePaddle:通过设置`param_attr``bias_attr`为某种Attribute的方式,进行`kernel``bias`初始化。
#### 高维tensor处理
TensorFlow:对于rank大于2的输入tensor,将其看做是最内两个维度所组成矩阵的堆叠,dense操作将改变最后一个维度;
PaddlePaddle:对于rank大于2的输入tensor,可以从第`num_flatten_dims`维开始(维度下标从0开始,`num_flatten_dims`最小为1),将各维度拍平,例如`shape`为(2,3,4,5),当`num_flatten_dims`为2时,输入tensor将被reshape成(2,3,20)的tensor,输出tensor的shape为(2,3,size)。
### 代码示例
```python
# 输入 tensor t 的shape为[2, 3, 4, 5]
# size=6, 输出tensor 的shape为[2,6]
out = fluid.layers.fc(t, size=6)
# size=6, 设置kernel为均匀分布
out = fluid.layers.fc(t, size=6, \
param_attr=fluid.ParamAttr(initializer=fluid.initializer.Uniform(low=-0.5, high=0.5)))
# size=6, num_flatten_dims=2,输出tensor的shape为[2, 3, 6]
out = fluid.layers.fc(t, size=6, num_flatten_dims=2)
```
## tf.losses.sigmoid_cross_entropy
### [tf.losses.sigmoid_cross_entropy](https://www.tensorflow.org/api_docs/python/tf/losses/sigmoid_cross_entropy)
```python
tf.losses.sigmoid_cross_entropy(
multi_class_labels,
logits,
weights=1.0,
label_smoothing=0,
scope=None,
loss_collection=tf.GraphKeys.LOSSES,
reduction=Reduction.SUM_BY_NONZERO_WEIGHTS
)
```
### [paddle.fluid.layers.sigmoid_cross_entropy_with_logit](http://paddlepaddle.org/documentation/docs/zh/1.2/api_cn/layers_cn.html#sigmoid_cross_entropy_with_logits)
```python
paddle.fluid.layers.sigmoid_cross_entropy_with_logits(
x,
label,
name=None
)
```
### 功能差异
#### 返回值类型
Tensorflow:通过控制`reduction`参数,返回结果可以是rank为0的tensor,也可以是shape与`logits`相同的tensor;
PaddlePaddle:固定返回shape与`x`相同的tensor,表示每个样本在每个标签上的损失。
#### 其他
Tensorflow:通过`weights`,可以设置不同样本、不同label的权重;通过`label_smoothing`,可以控制对label进行平滑;
PaddlePaddle:不支持调权与平滑功能。
### 代码示例
```
# x与label均是shape为[3,5]的tensor,表示三个样本,每个样本有5个类别
# out是shape为[3,5]的tensor,表示每个样本在每个类别上的loss
out = fluid.layers.sigmoid_cross_entropy_with_logits(x, label)
```
## tf.math.is_finite
### [tf.math.is_finite](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/math/is_finite)
``` python
tf.math.is_finite(
x,
name=None
)
```
### [paddle.fluid.layers.isfinite](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#paddle.fluid.layers.isfinite)
``` python
paddle.fluid.layers.isfinite(x)
```
### 功能差异
#### 输出格式
TensorFlow: 返回elementwise检查的结果,即输出与输入shape一致;
PaddlePaddle: 返回结果仅包含一个boolean值,若输入数据中均为`infinite`,则返回True,否则返回False。
### 代码示例
```python
# TensorFlow示例
# 输入[2.1, 3.2, 4.5]
# 输出[True, True, True]
result = tf.is_finite(inputs)
# PaddlePaddle示例
# 输入[2.1, 3.2, 4.5]
# 输出True
result = fluid.layers.isfinite(inputs)
```
## tf.math.rsqrt
### [tf.math.rsqrt](https://www.tensorflow.org/api_docs/python/tf/math/rsqrt)
``` python
tf.math.rsqrt(
x,
name=None
)
```
### PaddlePaddle实现
PaddlePaddle中目前无对应接口,可使用如下代码实现
``` python
def rsqrt(x):
net_0 = fluid.layers.sqrt(x)
net_1 = fluid.layers.pow(net_0, factor=-1.0)
return net_1
```
### 代码示例
``` python
inputs = fluid.layers.data(dtype='float32', shape=[1000], name='inputs')
# 调用上述自定义函数
result = rsqrt(inputs)
```
## tf.matmul
### [tf.matmul](https://www.tensorflow.org/api_docs/python/tf/linalg/matmul)
``` python
tf.matmul(
a,
b,
transpose_a=False,
transpose_b=False,
adjoint_a=False,
adjoint_b=False,
a_is_sparse=False,
b_is_sparse=False,
name=None
)
```
### [paddle.fluid.layers.matmul](http://paddlepaddle.org/documentation/docs/zh/1.2/api_cn/layers_cn.html#matmul)
``` python
paddle.fluid.layers.matmul(
x,
y,
transpose_x=False,
transpose_y=False,
alpha=1.0,
name=None
)
```
### 功能差异
#### 输入格式
TensorFlow:要求op的两个操作数具有相同的rank;
PaddlePaddle:允许两者具有不同的rank,具体说就是当任一操作数的rank大于2时,将其看做最里面两维度矩阵的堆叠,paddlepaddle将进行broadcast操作。
#### 其他
TensorFlow:使用`adjoint`参数可以实现快速的共轭操作;paddlepaddle中并不支持;
PaddlePaddle:额外支持对输出进行数乘操作。
### 代码示例
```python
# x: [M, K], y: [K, N]
fluid.layers.matmul(x, y) # out: [M, N]
# x: [B, ..., M, K], y: [B, ..., K, N]
fluid.layers.matmul(x, y) # out: [B, ..., M, N]
# x: [B, M, K], y: [B, K, N]
fluid.layers.matmul(x, y) # out: [B, M, N]
# x: [B, M, K], y: [K, N]
fluid.layers.matmul(x, y) # out: [B, M, N]
# x: [B, M, K], y: [K]
fluid.layers.matmul(x, y) # out: [B, M]
# x: [K], y: [K]
fluid.layers.matmul(x, y) # out: [1]
# x: [M], y: [N]
fluid.layers.matmul(x, y, True, True) # out: [M, N]
```
## tf.nn.avg_pool
### [tf.nn.avg_pool](https://www.tensorflow.org/versions/r1.10/api_docs/python/tf/nn/avg_pool)
``` python
tf.nn.avg_pool(
value,
ksize,
strides,
padding,
data_format='NHWC',
name=None
)
```
### [paddle.fluid.layers.pool2d](http://paddlepaddle.org/documentation/docs/en/1.3/api/layers.html#permalink-116-pool2d)
``` python
paddle.fluid.layers.pool2d(
input,
pool_size=-1,
pool_type='max',
pool_stride=1,
pool_padding=0,
global_pooling=False,
use_cudnn=True,
ceil_mode=False,
name=None,
exclusive=True)
```
### 功能差异
#### 输入格式
TensorFlow: 默认为`NHWC`的数据输入格式,同时也可通过修改`data_format`参数,支持`NCHW`的输入;
PaddlePaddle:只支持`NCHW`的数据输入格式。
#### Padding机制
Tensorflow: 存在`SAME``VALID`两种padding方式。当为`SAME`时,padding的size计算方式如下伪代码所示,需要注意的是,当计算得到的`pad_size`为奇数时,右侧与下方相对比左侧和上方会多1个size;
``` python
# 计算在width上的padding size
# height上的padding计算方式同理
ceil_size = ceil(input_width / stride_width)
pad_size = (ceil_size - 1) * stride_width + filter_width - input_width
pad_left = ceil(pad_size / 2)
pad_right = pad_size - pad_left
```
PaddlePaddle:在输入的上、下、左、右分别padding,size大小为`pool_padding`
### 代码示例
```
inputs = fluid.layers.data(dtype='float32', shape=[3, 300, 300], name='inputs')
# 计算得到输入的长、宽对应padding size为1
# 当Tensorflow中padding为SAME时,可能会两侧padding的size不同,可调用pad2d对齐
pad_res = fluid.layers.pad2d(inputs, paddings=[0, 1, 0, 1])
conv_res = fluid.layers.pool2d(pad_res, pool_size=3, pool_type='avg', padding=[1, 1], pool_stride=2)
```
## tf.nn.bidirectional_dynamic_rnn
### [tf.nn.bidirectional_dynamic_rnn](https://www.tensorflow.org/api_docs/python/tf/nn/bidirectional_dynamic_rnn)
```python
tf.nn.bidirectional_dynamic_rnn(
cell_fw,
cell_bw,
inputs,
sequence_length=None,
initial_state_fw=None,
initial_state_bw=None,
dtype=None,
parallel_iterations=None,
swap_memory=False,
time_major=False,
scope=None
)
```
### 功能差异
#### 使用方式
TensorFlow:用户通过定义正向与反向`cell`,可以实现一个双向RNN网络的功能;
PaddlePaddle:并没有提供一个对应的接口,用户可以使用`DynamicRNN`组合实现得到,详见如下代码示例。
### 代码示例
```
# 如下代码片段实现双向lstm网络,lstm单元数为16
num_unit_0 = 16
# 定义LoD输入
data = fluid.layers.data(name='input', shape=[1], dtype='int64', lod_level=1)
# 获得正向与反向embedding
embedding = fluid.layers.embedding(input=data, size=[emb_vocab, emb_size],
is_sparse=False)
rev_embedding = fluid.layers.sequence_reverse(embedding)
# 定义lstm网络
def rnn(in_tensor):
drnn = fluid.layers.DynamicRNN()
with drnn.block():
word = drnn.step_input(in_tensor)
prev_hid0 = drnn.memory(shape=[num_unit_0])
prev_cell0 = drnn.memory(shape=[num_unit_0])
cur_hid0, cur_cell0 = layers.lstm_unit(word, prev_hid0, prev_cell0)
drnn.update_memory(prev_hid0, cur_hid0)
drnn.update_memory(prev_cell0, cur_cell0)
drnn.output(cur_hid0)
out = drnn()
return out
# 计算正向lstm网络的输出
out = rnn(embedding)
# 计算反向lstm网络的输出
rev_out = rnn(rev_embedding)
# 再次反转使得rev_out每个时刻所处理的数据与out对应
rev_rev_out = fluid.layers.sequence_reverse(rev_out)
# 合并得到最后的输出,其shape为(-1, 32)
concat_out = layers.concat([out, rev_rev_out], axis=1)
```
## tf.nn.conv2d
### [tf.nn.conv2d](https://www.tensorflow.org/api_docs/python/tf/nn/conv2d)
```python
tf.nn.conv2d(
input,
filter,
strides,
padding,
use_cudnn_on_gpu=True,
data_format='NHWC',
dilations=[1, 1, 1, 1],
name=None
)
```
### [paddle.fluid.layers.conv2d](http://www.paddlepaddle.org/documentation/docs/zh/1.2/api_cn/layers_cn.html#paddle.fluid.layers.conv2d)
```python
paddle.fluid.layers.conv2d(
input,
num_filters,
filter_size,
stride=1,
padding=0,
dilation=1,
groups=None,
param_attr=None,
bias_attr=None,
use_cudnn=True,
act=None,
name=None
)
```
### 功能差异
`tf.nn.conv2d`中的参数`filter`为具体的tensor,而`paddle.fluid.layers.conv2d`参数中则声明卷积核的`size`,函数内部创建卷积核tensor。也可通过如下代码示例,自行创建并复用卷积核
需要注意的是PaddlePaddle中的输入、输出以及卷积核的格式与tensorflow存在部分差异,可参考[tf.layers.conv2d](tf.layers.conv2d.md)
### 代码示例
```python
# 输入为NCHW格式
inputs = fluid.layers.data(dtype='float32', shape=[-1, 3, 300, 300], name='inputs')
create_kernel = fluid.layers.create_parameters(shape=[5, 3, 2, 2], dtype='float32', name='kernel')
# PaddlePaddle中可通过相同的参数命名引用同一个参数变量
# 通过指定卷积核参数名(param_attr)为'kernel',引用了create_kernel
result = fluid.layers.conv2d(inputs, 5, [2, 2], param_attr='kernel')
```
## tf.nn.conv2d_transpose
### [tf.nn.conv2d_transpose](https://www.tensorflow.org/api_docs/python/tf/nn/conv2d_transpose)
``` python
tf.nn.conv2d_transpose(
value,
filter,
output_shape,
strides,
padding='SAME',
data_format='NHWC',
name=None
)
```
### [paddle.fluid.layers.conv2d_transpose](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#paddle.fluid.layers.conv2d_transpose)
``` python
paddle.fluid.layers.conv2d_transpose(
input,
num_filters,
output_size=None,
filter_size=None,
padding=0,
stride=1,
dilation=1,
groups=None,
param_attr=None,
bias_attr=None,
use_cudnn=True,
act=None,
name=None
)
```
### 功能差异
#### 数据格式
TensorFlow: 默认输入数据格式为`NHWC`,表示`(batch,height, width, in_channels)`, 同时也将`data_format`参数设为`channels_first`,支持`NCHW`格式的数据输入。其中输入、输出、卷积核对应关系如下表所示,
| 输入 | 卷积核 | 输出 |
|--------------------|-------------------|------------------|
|NHWC | (kernel_h, kernel_w, filters_num, in_channels)| (batch, out_h, out_w, filters_num)|
|NDHW | (kernel_h, kernel_w, filters_num, in_channels) | (batch, filters_num, out_h, out_w)|
PaddlePaddle:只支持输入数据格式为`NCHW`,且**卷积核格式**与TensorFlow不同,其中输入、输出、卷积核对应关系如下表所示,
| 输入 | 卷积核 | 输出 |
|--------------------|-------------------|------------------|
|NCHW | (in_channels, filters_num, kernel_h, kernel_w) | (batch, filters_num, out_h, out_w)|
#### Padding机制
TensorFlow: `SAME``VALID`两种选项。当为`SAME`时,padding的计算方式如下所示
```python
# 计算在width上的padding size
# height上的padding计算方式同理
ceil_size = ceil(input_width / stride_width)
pad_size = (ceil_size - 1) * stride_width + filter_width - input_width
pad_left = ceil(pad_size / 2)
pad_right = pad_size - pad_left
```
PaddlePaddle:`padding`参数表示在输入图像四周padding的size大小
#### 输出大小
TensorFlow:当padding为`SAME``VALID`两种情况下,输出大小计算方式如下所示
```python
if padding == 'SAME':
output_size = input_size * stride
elif padding == 'VALID':
output_size = input_size * stride + max(kernel_size - stride, 0)
```
PaddlePaddle: 输出大小计算公式如下,差异主要由于TensorFlow在`conv2d_transpose`的最后还存在**裁剪**步骤,因此可参考示例代码,调用`crop`解决
```python
output_size = (input_size - 1) * stride - 2 * padding + dilation * (kernel - 1) + 1
```
### 代码示例
```python
# TensorFlow使用conv2d_transpose
# 输入shape: [-1, 20, 20, 3]
inputs = tf.placeholder(dtype=tf.float32, shape=[None, 20, 20, 3])
filter = tf.random_uniform(shape=[5, 5, 3, 3], 0.0 1.0)
batch = tf.shape(inputs)[0]
# conv2d_transpose输出shape: [-1, 40, 40, 3]
result = tf.nn.conv2d_transpose(inputs, filter, output_shape=[batch, 40, 40, 3],
strides=[1, 2, 2, 1], padding='SAME')
#PaddlePaddle中使用conv2d_transpose
# 输入Shape:(None, 3, 20, 20)
inputs = fluid.layers.data(dtype='float32', shape=[3, 20, 20], name='inputs)
# conv2d_transpose输出shape:[-1, 3, 41, 41]
outputs = fluid.layers.conv2d_transpose(pad_inputs, 3, filter_size=[5, 5],
padding=[1, 1], stride=[2, 2], bias_attr=False)
# 裁剪后结果即为与TensorFlow一致
outputs = fluid.layers.crop(outputs, shape=[-1, 3, 40, 40])
## tf.nn.conv3d_transpose
### [tf.nn.conv3d_transpose](https://www.tensorflow.org/api_docs/python/tf/nn/conv3d_transpose)
``` python
tf.nn.conv3d_transpose(
value,
filter,
output_shape,
strides,
padding='SAME',
data_format='NDHWC',
name=None
)
```
### [paddle.fluid.layers.conv3d_transpose](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#permalink-48-conv3d_transpose)
``` python
paddle.fluid.layers.conv3d_transpose(
input,
num_filters,
output_size=None,
filter_size=None,
padding=0,
stride=1,
dilation=1,
groups=None,
param_attr=None,
bias_attr=None,
use_cudnn=True,
act=None,
name=None
)
```
### 功能差异
#### 数据格式
TensorFlow: 默认输入数据格式为`NDHWC`,表示`(batch,depth, height, width, in_channels)`, 同时也将`data_format`参数设为`channels_first`,支持`NCDHW`格式的数据输入。其中输入、输出、卷积核对应关系如下表所示,
| 输入 | 卷积核 | 输出 |
|--------------------|-------------------|------------------|
|NDHWC | (kernel_d, kernel_h, kernel_w, filters_num, in_channels)| (batch, out_d, out_h, out_w, filters_num)|
|NCDHW | (kernel_d, kernel_h, kernel_w, filters_num, in_channels) | (batch, filters_num, out_d, out_h, out_w)|
PaddlePaddle: 只支持输入数据格式为`NCDHW`,且**卷积核格式**与TensorFlow不同,其中输入、输出、卷积核对应关系如下表所示,
| 输入 | 卷积核 | 输出 |
|--------------------|-------------------|------------------|
|NCDHW | (in_channels, filters_num, kernel_d, kernel_h, kernel_w) | (batch, filters_num, out_d, out_h, out_w)|
#### Padding机制
TensorFlow: `SAME``VALID`两种选项。当为`SAME`时,padding的计算方式如下所示
```python
# 计算在width上的padding size
# height上的padding计算方式同理
ceil_size = ceil(input_width / stride_width)
pad_size = (ceil_size - 1) * stride_width + filter_width - input_width
pad_left = ceil(pad_size / 2)
pad_right = pad_size - pad_left
```
PaddlePaddle:`padding`参数表示在输入图像四周padding的size大小
#### 输出大小
TensorFlow:当padding为`SAME``VALID`两种情况下,输出大小计算方式如下所示
```python
if padding == 'SAME':
output_size = input_size * stride
elif padding == 'VALID':
output_size = input_size * stride + max(kernel_size - stride, 0)
```
PaddlePaddle: 输出大小计算公式如下,差异主要由于TensorFlow在`conv2d_transpose`的最后还存在**裁剪**步骤,因此可参考示例代码,调用`crop`解决
```python
output_size = (input_size - 1) * stride - 2 * padding + dilation * (kernel - 1) + 1
```
### 代码示例
```python
# TensorFlow使用conv3d_transpose
# 输入shape: [-1, 5, 20, 40, 3]
inputs = tf.placeholder(dtype=tf.float32, shape=[None, 5 20, 40, 3])
filter = tf.random_uniform(shape=[2, 4, 5, 7 3], 0.0 1.0)
batch = tf.shape(inputs)[0]
# conv2d_transpose输出shape: [-1, 5, 40, 80, 7]
result = tf.nn.conv2d_transpose(inputs, filter, output_shape=[batch, 5, 40, 80 7],
strides=(1, 2, 2), padding='SAME')
#PaddlePaddle中使用conv3d_transpose
# 输入Shape:(None, 3, 5, 20, 40)
inputs = fluid.layers.data(dtype='float32', shape=[3, 5, 20, 40], name='inputs)
# conv3d_transpose输出shape:[-1, 7, 6, 40, 81]
outputs = fluid.layers.conv3d(inputs, 7, filter_size=(2, 4, 5), stride=(1, 2, 2),
padding=(0, 1, 1), bias_attr=False)
# 裁剪后结果即为与TensorFlow一致
outputs = fluid.layers.crop(outputs, shape=[-1, 7, 5, 40, 80])
## tf.nn.depthwise_conv2d
### [tf.nn.depthwise_conv2d](https://www.tensorflow.org/api_docs/python/tf/nn/depthwise_conv2d)
```python
tf.nn.depthwise_conv2d(
input,
filter,
strides,
padding,
rate=None,
name=None,
data_format=None
)
```
### [paddle.fluid.layers.conv2d](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#paddle.fluid.layers.conv2d)
```python
paddle.fluid.layers.conv2d(
input,
num_filters,
filter_size,
stride=1,
padding=0,
dilation=1,
groups=None,
param_attr=None,
bias_attr=None,
use_cudnn=True,
act=None,
name=None
)
```
### 功能差异
#### 数据格式
TensorFlow:默认输入数据格式为`NHWC`,表示`(batch, height, width, in_channels)`, 同时也将`data_format`参数设为`channels_first`,支持`NCHW`格式的数据输入。其中输入、输出、卷积核对应关系如下表所示,
| 输入 | 卷积核 | 输出 |
|--------------------|-------------------|------------------|
|NHWC | (kernel_h, kernel_w, in_channels, channel_multiplier)| (batch, out_h, out_w, in_channel*channel_multiplier)|
|NCHW | (kernel_h, kernel_w, in_channels, channel_multiplier) | (batch, in_channel*channel_multiplier, out_h, out_w)|
PaddlePaddle: 只支持输入数据格式为`NCHW`,且**卷积核格式**与TensorFlow不同,其中输入、输出、卷积核对应关系如下表所示,可以看到,需要设置`num_filters`参数与`in_channels`一致
| 输入 | 卷积核 | 输出 |
|--------------------|-------------------|------------------|
|NCHW | (num_filters, in_channels/groups, kernel_h, kernel_w) | (batch, num_filters, out_h, out_w)|
#### Padding机制
TensorFlow: `SAME``VALID`两种选项。当为`SAME`时,padding的计算方式如下所示
```python
# 计算在width上的padding size
# height上的padding计算方式同理
ceil_size = ceil(input_width / stride_width)
pad_size = (ceil_size - 1) * stride_width + filter_width - input_width
pad_left = ceil(pad_size / 2)
pad_right = pad_size - pad_left
```
PaddlePaddle:`padding`参数表示在输入图像四周padding的size大小
#### 参数差异
Tensorflow:普通2维卷积使用`tf.layers.conv2d`
PaddlePaddle:仍使用本接口,可参考在文档[tf.layers.conv2d](https://github.com/PaddlePaddle/X2Paddle/blob/doc/tensorflow2fluid/doc/tf.layers.conv2d.md)
### 代码示例
```python
# TensorFlow中使用depthwise_conv2d
# 输入shape: [-1, 20, 20, 3]
inputs = tf.placeholder(dtype=tf.float32, shape=[None, 20, 20, 3])
filter = tf.random_uniform(shape=[4, 4, 3, 1], 0.0 1.0)
# 输出shape: [-1, 20, 20, 3]
result = tf.nn.depthwise_conv2d(inputs, filter, strides=[1, 1, 1, 1], padding='SAME')
# PaddlePaddle中使用conv2d实现depthwise_conv2d
# 输入shape: [-1, 3, 20, 20]
inputs = fluid.layers.data(dtype='float32', shape=[3, 20, 20], name='inputs')
# 使用pad2d对齐TensorFlow的padding参数:SAME
inputs = fluid.layers.pad2d(inputs, paddings=[1, 2, 1, 2])
#输出shape:[-1, 3, 20, 20]
result = fluid.layers.conv2d(inputs, 3, filter_size=[4, 4], groups=3, bias_attr=False)
```
## tf.dropout
### [tf.nn.dropout](https://www.tensorflow.org/api_docs/python/tf/nn/dropout)
``` python
tf.nn.dropout(
x,
keep_prob=None,
noise_shape=None,
seed=None,
name=None,
rate=None
)
```
### [paddle.fluid.layers.dropout](http://paddlepaddle.org/documentation/docs/zh/1.2/api_cn/layers_cn.html#cn-api-fluid-layers-dropout)
``` python
paddle.fluid.layers.dropout(
x,
dropout_prob,
is_test=False,
seed=None,
name=None,
dropout_implementation='downgrade_in_infer'
)
```
### 功能差异
#### 丢弃概率
TensorFlow:使用`keep_prob`表示保留单元输出的概率,等价于`1-rate`
PaddlePaddle:使用`dropout_prob`表示将单元输出设置为0的概率,即其丢弃概率;
#### dropout独立性
TensorFlow:通过设置一个可以广播到x的`noise_shape`,可以控制dropout的独立性;
PaddlePaddle:暂无此设置。
#### 实现方式
TensorFlow:在训练时,被保留的单元输出要乘上`1/keep_prob`的系数,而在测试时,直接关闭dropout。
PaddlePaddle:通过设置`dropout_implementation`有不同的实现。当设置为`downgrade_in_infer`时,在训练时,保留单元直接被输出,而测试时所有单元乘以`1-dropout_prob`的系数;当设置为`upgrade_in_train`时,则与tensorflow的实现一致。
### 代码示例
```python
# 输入 tensor t 为[[1,2],[3,4]]
# 第0维前面padding长度为0,后面padding长度为1;第1维前面padding长度为1,后面padding长度为2
out = fluid.layers.dropout(t, dropout_prob=0.2, dropout_implementation="upscale_in_train")
# inference 时关闭dropout
inference_program = fluid.default_main_program().clone(for_test=True)
```
## tf.nn.dynamic_rnn
### [tf.nn.dynamic_rnn](https://www.tensorflow.org/api_docs/python/tf/nn/dynamic_rnn)
``` python
tf.nn.dynamic_rnn(
cell,
inputs,
sequence_length=None,
initial_state=None,
dtype=None,
parallel_iterations=None,
swap_memory=False,
time_major=False,
scope=None
)
```
### [paddle.fluid.layers.DynamicRNN](http://www.paddlepaddle.org/documentation/docs/zh/1.2/api_cn/api_guides/low_level/layers/control_flow.html#dynamicrnn)
``` python
paddle.fluid.layers.DynamicRNN(name=None)
```
### 功能差异
#### 调用机制
Tensorflow: `tf.nn.dynamic_rnn`通常与`tf.nn.rnn_cell.LSTMCell``tf.nn.rnn_cell.GRUCell`等Cell结合使用
PaddlePaddle: 使用`paddle.fluid.layers.DynamicRNN`类实现类似功能 ,通过DynamicRNN提供的类方法,用户可以在`with block`中方便地自定义每个时间步的处理过程。
#### 输入格式
TensorFlow: `tf.nn.dynamic_rnn`输入为序列数据,批输入中的每个序列需要填充到相同的长度
PaddlePaddle: 使用
[LoDTensor](http://www.paddlepaddle.org/documentation/docs/zh/1.2/user_guides/howto/basic_concept/lod_tensor.html)表示一个批输入,用户在使用时不需要进行填充操作。
### 代码示例
```
# TensorFlow代码示例
# 创建 BasicRNNCell
rnn_cell = tf.nn.rnn_cell.BasicRNNCell(hidden_size)
# 定义初始隐状态
initial_state = rnn_cell.zero_state(batch_size, dtype=tf.float32)
# 输出shape为(batch_size, max_time, cell_state_size)
# 最后时刻隐状态shape为(batch_size, cell_state_size)
outputs, state = tf.nn.dynamic_rnn(rnn_cell, input_data,
initial_state=initial_state,
dtype=tf.float32)
# PaddlePaddle代码示例
# 创建一个DynamicRNN对象
drnn = fluid.layers.DynamicRNN()
# 定义一个类似BasicRNNCell的处理过程
with drnn.block():
# 设置drnn的序列输入,并取得当前步的输入
cur_input = drnn.step_input(input_data)
# 设置memory变量,并取得上一时刻(或初始)隐状态
last_hidden_state = drnn.memory(shape=[hidden_size], value=0.0)
# 计算当前时刻隐状态
cur_hidden_state = fluid.layers.fc(input=[cur_input, last_hidden_state], size=hidden_size, act='relu')
# 更新隐状态
drnn.update_memory(last_hidden_state, cur_hidden_state)
# 记录本时刻的输出(BasicRNNCell中当前时刻的输出与当前时刻隐状态一致)
drnn.output(hidden)
# 获取输出LoDTensor,其shape为(-1, hidden_size)
outputs = drnn()
# 获取各序列最后时刻的隐状态,其shape为(batch_size, hidden_size)
state = fluid.layers.sequence_last_step(outputs)
```
### 其他
为了简化用户定义动态RNN的过程,paddle有如下op可供选择:
- [paddle.fluid.layers.dynamic_lstm](http://www.paddlepaddle.org/documentation/docs/zh/1.2/api_cn/layers_cn.html#dynamic-lstm):相当于 `tf.nn.dynamic_rnn`结合`tf.nn.rnn_cell.LSTMCell`
- [paddle.fluid.layers.dynamic_gru](http://www.paddlepaddle.org/documentation/docs/zh/1.2/api_cn/layers_cn.html#dynamic-gru):相当于`tf.nn.dynamic_rnn`结合`tf.nn.rnn_cell.GRUCell`
## tf.nn.l2_normalize
### [tf.nn.l2_normalize](https://www.tensorflow.org/api_docs/python/tf/math/l2_normalize)
```python
tf.math.l2_normalize(
x,
axis=None,
epsilon=1e-12,
name=None,
dim=None
)
```
### [paddle.fluid.layers.l2_normalize](http://paddlepaddle.org/documentation/docs/zh/1.2/api_cn/layers_cn.html#l2-normalize)
```python
paddle.fluid.layers.l2_normalize(
x,
axis,
epsilon=1e-12,
name=None
)
```
### 功能差异
#### 计算方式
TensorFlow:计算方式为`output = x / sqrt(max(sum(x^2), epsilon))`;
PaddlePaddle:计算方式为`output = x / sqrt(sum(x^2) + epsilon))`
### 代码示例
```
# x是shape为[3,2]的张量
# out同样是shape[3,2]的张量,axis设置为1,表示将x中每个行向量做归一化
out = fluid.layers.l2_normalize(x, axis=1)
```
## tf.nn.max_pool
### [tf.nn.max_pool](https://www.tensorflow.org/api_docs/python/tf/nn/max_pool)
``` python
tf.nn.max_pool(
value,
ksize,
strides,
padding,
data_format='NHWC',
name=None
)
```
### [paddle.fluid.layers.pool2d](http://paddlepaddle.org/documentation/docs/en/1.3/api/layers.html#permalink-116-pool2d)
``` python
paddle.fluid.layers.pool2d(
input,
pool_size=-1,
pool_type='max',
pool_stride=1,
pool_padding=0,
global_pooling=False,
use_cudnn=True,
ceil_mode=False,
name=None,
exclusive=True)
```
### 功能差异
#### 输入格式
TensorFlow: 默认为`NHWC`的数据输入格式,同时也可通过修改`data_format`参数,支持`NCHW`的输入;
PaddlePaddle:只支持`NCHW`的数据输入格式。
#### Padding机制
Tensorflow: 存在`SAME``VALID`两种padding方式。当为`SAME`时,padding的size计算方式如下,仅在最右和最下进行padding;
```
ceil_size = ceil(input_size / stride)
pad_size = (ceil_size - 1) * stride + filter_size - input_size
```
PaddlePaddle:在输入的上、下、左、右分别padding,size大小为`pool_padding`,通过示例代码,可实现与Tensorflow中`max_pool``SAME`方式。
### 代码示例
```
inputs = fluid.layers.data(dtype='float32', shape=[3, 300, 300], name='inputs')
# 计算得到输入的长、宽对应padding size为1
# 在最右、最下进行padding
pad_res = fluid.layers.pad2d(inputs, padding=[0, 1, 0, 1])
conv_res = fluid.layers.pool2d(pad_res, pool_size=3, pool_type='max', pool_stride=2)
```
## tf.math.reduce_logsumexp
### [tf.math.reduce_logsumexp](https://www.tensorflow.org/api_docs/python/tf/math/reduce_logsumexp)
``` python
tf.math.log_softmax(
logits,
axis=None,
name=None,
dim=None
)
```
### PaddlePaddle实现
PaddlePaddle中目前无对应接口,可使用如下代码实现
``` python
def reduce_logsumexp(inputs, axis=None, keepdims=None):
net_0 = fluid.layers.exp(inputs)
net_1 = fluid.layers.reduce_sum(net_0, dim=axis, keep_dim=keepdims)
net_2 = fluid.layers.log(net_1)
return net_2
```
### 代码示例
``` python
inputs = fluid.layers.data(dtype='float32', shape=[1000], name='inputs')
# 调用上述自定义函数
result = reduce_logsumexp(inputs)
```
## tf.nn.rnn_cell.LSTMCell
### [tf.nn.rnn_cell.LSTMCell](https://www.tensorflow.org/api_docs/python/tf/nn/rnn_cell/LSTMCell)
```python
tf.nn.rnn_cell.LSTMCell(
num_units,
use_peepholes=False,
cell_clip=None,
initializer=None,
num_proj=None,
proj_clip=None,
num_unit_shards=None,
num_proj_shards=None,
forget_bias=1.0,
state_is_tuple=True,
activation=None,
reuse=None,
name=None,
dtype=None,
**kwargs
)
```
### [paddle.fluid.layers.lstm_unit](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#lstm-unit)
```python
paddle.fluid.layers.lstm_unit(
x_t,
hidden_t_prev,
cell_t_prev,
forget_bias=0.0,
param_attr=None,
bias_attr=None,
name=None
)
```
### 功能差异
#### 使用方式
TensorFlow:首先定义`LSTMCell`对象,定义对象时只需要指定单元数`num_units`;由于`LSTMCell`内部定义了`__call__`方法,因而其对象是可调用对象,直接使用`step_output, cur_state = cell(step_input, last_state)`的形式,可以计算得到当前步的输出与状态;
PaddlePaddle:提供op形式的调用接口,通常与[paddle.fluid.layers.DynamicRNN](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#dynamicrnn)配合使用,以获取序列中的单步输入。**注意,`lstm_unit`通过`cell_t_prev`最后一个维度来确定lstm的单元数,同时要求`hidden_t_prev`与`cell_t_prev`最后的维度相同。**
#### 窥孔连接
TensorFlow:通过设置`use_peepholes`选择LSTM的实现是否进行窥孔连接;
PaddlePaddle:只提供非窥孔连接的LSTM实现。
#### 输出变换
TensorFlow:第一个返回值为`step_output`。当`num_proj`非空时,由`hidden_state`经过`fc`变换后得到`step_output`;而当`num_proj`为空时,则直接返回`hidden_step`作为`step_output`
PaddlePaddle:第一个返回值为`hidden_state`,不涉及输出变换。
#### cell_state
TensorFlow:第二个返回值为`cell_state``cell_state`由真实的`cell_state``hidden_state`一起构成:当`state_id_tuple``True`时,返回真实的`cell_state``hidden_state`组成的`tuple`;反之,则返回`concat([cell_state, hidden_state], axis=1)`
PaddlePaddle:第二个返回值为真实的`cell_state`
### 代码示例
```
# embedding 是一个rank为2,lod_level为1的LoDTensor
num_unit_0 = 32
drnn = fluid.layers.DynamicRNN()
with drnn.block():
word = drnn.step_input(embedding)
# 记录hidden_state与cell_state,初始状态使用零向量
prev_hid0 = drnn.memory(shape=[num_unit_0])
prev_cell0 = drnn.memory(shape=[num_unit_0])
# 执行lstm计算
cur_hid0, cur_cell0 = layers.lstm_unit(word, prev_hid0, prev_cell0)
# 更新hidden_state与cell_state
drnn.update_memory(prev_hid0, cur_hid0)
drnn.update_memory(prev_cell0, cur_cell0)
# 输出每个时刻的hidden_state
drnn.output(cur_hid0)
# 获取每个时刻的输出
out = drnn()
# 获取最后时刻的输出
last = fluid.layers.sequence_last(out)
```
## tf.nn.rnn_cell.MultiRNNCell
### [tf.nn.rnn_cell.MultiRNNCell](https://www.tensorflow.org/api_docs/python/tf/nn/rnn_cell/MultiRNNCell)
```python
tf.nn.rnn_cell.MultiRNNCell(
cells,
state_is_tuple=True
)
```
### PaddlePaddle实现
在Tensorflow中,用户通过定义多个单独的`RNNCell`生成一个`cell`列表,进而调用`MultiRNNCell`,可以实现一个多层RNN网络的功能。PaddlePaddle并没有提供一个对应的接口,用户可以在`DynamicRNN`的block中,通过组合多个RNN相关的`unit`实现类似的功能,可参考代码示例。
### 代码示例
```
# 如下代码片段实现两层lstm网络,第一层单元数为32,第二层单元数为16
num_unit_0 = 32
num_unit_1 = 16
emb_size = 12
emb_vocab = 10000
data = fluid.layers.data(name='input', shape=[1], dtype='int64', lod_level=1)
embedding = fluid.layers.embedding(input=data, size=[emb_vocab, emb_size])
drnn = fluid.layers.DynamicRNN()
with drnn.block():
# 定义单步输入
word = drnn.step_input(embedding)
# 定义第一层lstm的hidden_state, cell_state
prev_hid0 = drnn.memory(shape=[num_unit_0])
prev_cell0 = drnn.memory(shape=[num_unit_0])
# 定义第二层lstm的hidden_state, cell_state
prev_hid1 = drnn.memory(shape=[num_unit_1])
prev_cell1 = drnn.memory(shape=[num_unit_1])
# 执行两层lstm运算
cur_hid0, cur_cell0 = layers.lstm_unit(word, prev_hid0, prev_cell0)
cur_hid1, cur_cell1 = layers.lstm_unit(cur_hid0, prev_hid1, prev_cell1)
# 更新第一层lstm的hidden_state, cell_state
drnn.update_memory(prev_hid0, cur_hid0)
drnn.update_memory(prev_cell0, cur_cell0)
# 更新第二层lstm的hidden_state, cell_state
drnn.update_memory(prev_hid1, cur_hid1)
drnn.update_memory(prev_cell1, cur_cell1)
drnn.output(cur_hid1)
out = drnn()
last = fluid.layers.sequence_last_step(out)
```
## tf.nn.separable_conv2d
### [tf.nn.separable_conv2d](https://www.tensorflow.org/api_docs/python/tf/nn/separable_conv2d)
``` python
tf.nn.separable_conv2d(
input,
depthwise_filter,
pointwise_filter,
strides,
padding,
rate=None,
name=None,
data_format=None
)
```
### PaddlePaddle实现
PaddlePaddle中目前无对应接口,可使用如下代码实现,在如下代码中只考虑了基本的`strides`参数,其它参数如`padding`在PaddlePaddle中使用机制
以及输入输出和卷积核格式与TensorFlow存在差异,可参考文档[tf.layers.conv2d](tf.layers.conv2d.md)[tf.nn.depthwise_conv2d](tf.nn.depthwise_conv2d.md)中的说明。
``` python
# TensorFlow中separable_conv2d的使用
depthwise_filter = tf.random_uniform([4, 4, 3, 1], 0.0, 1.0)
pointwise_filter = tf.random_uniform([1, 1, 3, 5], 0.0, 1.0)
result = tf.nn.separable_conv2d(input, depthwise_filter, pointwise_filter,
strides=[1, 1, 1, 1], padding='VALID')
# PaddlePaddle中对应如上代码实现separable_conv2d
depthwise_result = fluid.layers.conv2d(input, 3, filter_size=[4, 4],
stride=[1, 1], groups=3, bias_attr=False)
pointwise_result = fluid.layers.conv2d(depthwise_result, filter_size=[1, 1],
stride=[1, 1], bias_attr=False)
```
## tf.nn.softmax_cross_entropy_with_logits
### [tf.nn.rnn_cell.MultiRNNCell](https://www.tensorflow.org/api_docs/python/tf/nn/softmax_cross_entropy_with_logits)
```python
tf.nn.softmax_cross_entropy_with_logits(
_sentinel=None,
labels=None,
logits=None,
dim=-1,
name=None
)
```
### [paddle.fluid.layers.softmax_with_cross_entropy](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#softmax-with-cross-entropy)
```python
paddle.fluid.layers.softmax_with_cross_entropy(
logits,
label,
soft_label=False,
ignore_index=-100,
numeric_stable_mode=False,
return_softmax=False
)
```
### 功能差异
#### 标签类型
TensorFlow:`labels`只能使用软标签,其`shape``[batch, num_classes]`,表示样本在各个类别上的概率分布;
PaddlePaddle:通过设置`soft_label`,可以选择软标签或者硬标签。当使用硬标签时,`label``shape``[batch, 1]``dtype``int64`;当使用软标签时,其`shape``[batch, num_classes]``dtype``int64`
#### 返回值
TensorFlow:返回`batch`中各个样本的log loss;
PaddlePaddle:当`return_softmax``False`时,返回`batch`中各个样本的log loss;当`return_softmax``True`时,再额外返回`logtis`的归一化值。
### 代码示例
```
# logits的shape为[32, 10], dtype为float32; label的shape为[32, 1], dtype为int64
# loss的shape为[32, 1], dtype为float32
loss = fluid.layers.softmax_with_cross_entropy(logits, label, soft_label=False)
```
## tf.nn.top_k
### [tf.nn.top_k](https://www.tensorflow.org/api_docs/python/tf/nn/top_k)
``` python
tf.math.top_k(
input,
k=1,
sorted=True,
name=None
)
```
### [paddle.fluid.layers.topk](http://paddlepaddle.org/documentation/docs/zh/1.2/api_cn/layers_cn.html#topk)
``` python
paddle.fluid.layers.topk(
input,
k,
name=None
)
```
### 功能差异
#### 参数差异
TensorFlow: 通过设置`sorted`参数,对返回的值与下标设置是否进行降序排序;`k`默认为1。
PaddlePaddle: 对返回的`top-k` tensor进行降序排序;`k`没有默认值,必须设置。
### 代码示例
```python
# 输入 tensor t 为[[2,6,3],[3,0,8]]
# 当k=2时,输出 tensor out 为[[6,3], [8,3]],index为[[1,2],[2,0]]
out, index = fluid.layers.topk(t, k=1)
```
## tf.one_hot
### [tf.one_hot](https://www.tensorflow.org/api_docs/python/tf/one_hot)
``` python
tf.one_hot(
indices,
depth,
on_value=None,
off_value=None,
axis=None,
dtype=None,
name=None
)
```
### [paddle.fluid.layers.one_hot](http://paddlepaddle.org/documentation/docs/zh/1.2/api_cn/layers_cn.html#one-hot)
``` python
layers.one_hot(;
input,
depth
)
```
### 功能差异
#### 输入格式
TensorFlow:indices shape 没有限定;支持设置on与off的值;
PaddlePaddle:input限定为2-D tensor,shape为(batch, 1)。
#### 参数种类
TensorFlow:可以配置`on_value``off_value`,默认为`1``0`
PaddlePaddle:无对应配置选项,即为默认的`1``0`
### 代码示例
```python
# 输入 tensor t 为[[1],[2]]
# depth 为3时,输出 tensor out 为[[0, 1, 0], [0, 0, 1]]
out = fluid.layers.one_hot(t, 3)
```
## tf.pad
### [tf.pad](https://www.tensorflow.org/api_docs/python/tf/pad)
``` python
tf.pad(
tensor,
paddings,
mode='CONSTANT',
name=None,
constant_values=0
)
```
### [paddle.fluid.layers.pad](http://paddlepaddle.org/documentation/docs/zh/1.2/api_cn/layers_cn.html#cn-api-fluid-layers-pad)
``` python
paddle.fluid.layers.pad(
x,
paddings,
pad_value=0.0,
name=None
)
```
### 功能差异
#### padding方式
TensorFlow:支持采用三种模式进行padding,不同padding模式决定pad的值是什么,包括constant、symmetric和reflect。padding的shape为(rank, 2),表示每一维前后padding的长度
PaddlePaddle:目前仅支持采用常量进行padding;指定padding长度时,采用一个一维列表表示,其长度为输入rank的两倍,连续的两个值表示某维度上前、后进行padding的长度
### 代码示例
```python
# 输入 tensor t 为[[1,2],[3,4]]
# 第0维前面padding长度为0,后面padding长度为1;第1维前面padding长度为1,后面padding长度为2
out = fluid.layers.pad(t, paddings=[0,1,1,2])
```
## tf.placeholder
### [tf.placeholder](https://www.tensorflow.org/api_docs/python/tf/placeholder)
``` python
tf.placeholder(
dtype,
shape=None,
name=None
)
```
### [paddle.fluid.layers.data](http://paddlepaddle.org/documentation/docs/zh/1.2/api_cn/layers_cn.html#cn-api-fluid-layers-data)
``` python
paddle.fluid.layers.data(
name,
shape,
append_batch_size=True,
dtype='float32',
lod_level=0,
type=VarType.LOD_TENSOR,
stop_gradient=True)
```
### 功能差异
#### Batch维度处理
TensorFlow: 对于shape中的batch维度,需要用户使用`None`指定;
PaddlePaddle: 将第1维设置为`-1`表示batch维度;如若第1维为正数,则会默认在最前面插入batch维度,如若要避免batch维,可将参数`append_batch_size`设为`False`
### 代码示例
```python
# 创建输入型tensor out,其shape为[-1, 3, 4], 数据类型为float32
out = fluid.layers.data('out', shape=[3, 4], dtype='float32')
# 创建输入型tensor out,其shape为[3, -1, 4], 数据类型为float32
out = fluid.layers.data('out', shape=[3, -1, 4], append_batch_size=False, dtype='float32')
```
## tf.print
### [tf.print](https://www.tensorflow.org/api_docs/python/tf/print)
```python
tf.print(
*inputs,
**kwargs
)
```
### [paddle.fluid.layers.Print](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#print)
```python
paddle.fluid.layers.Print(
input,
first_n=-1,
message=None,
summarize=-1,
print_tensor_name=True,
print_tensor_type=True,
print_tensor_shape=True,
print_tensor_lod=True,
print_phase='both'
)
```
### 功能差异
#### 使用方式
TensorFlow:在`graph`模式下,该op的运行决定于是否直接被运行,或者作为直接运行的其他op的依赖;在`eager`模式下,该op在被调用后会自动运行;
PaddlePaddle:在被调用后,该op被添加到代码块,之后执行到代码块时将自动运行。
#### input类型
TensorFlow:可以是python primitives,也可以是tensor或其与python primitives的组合;
PaddlePaddle:只可以是tensor。
#### 梯度打印
TensorFlow:不支持;
PaddlePaddle:通过设置`print_phase`,可以控制是否打印`input`的梯度。
### 代码示例
```
# input 是任意paddle tensor
# 打印input的内容,如果有梯度的话也将打印梯度
print(input, message="content of input")
```
## tf.reshape
### [tf.reshape](https://www.tensorflow.org/api_docs/python/tf/reshape)
``` python
tf.reshape(
tensor,
shape,
name=None
)
```
### [paddle.fluid.layers.reshape](http://paddlepaddle.org/documentation/docs/zh/1.2/api_cn/layers_cn.html#cn-api-fluid-layers-reshape)
``` python
paddle.fluid.layers.reshape(
x,
shape,
actual_shape=None,
act=None,
inplace=False,
name=None)
```
### 功能差异:
#### shape标记差别
TensorFlow: shape 中可以使用单独一个-1,表示待推断的维度;
PaddlePaddle: shape 中除了可以使用单独一个-1表示待推断维度外,还能使用0,表示在输入tensor原来的shape中对应位置的维度。注意,0的下标不能超过原来tensor的rank。
## 代码示例
```python
# 输入 tensor t 的 shape 为[3, 4]
# 输出 tensor out 的 shape 为[2,6]
out = fluid.layers.reshape(t, [-1, 6])
# 输出 tensor out 的 shape 为[3, 2, 2]
out = fluid.layers.reshape(t, [0, 2, 2])
```
## tf.reverse_sequence
### [tf.reverse_sequence](https://www.tensorflow.org/api_docs/python/tf/reverse_sequence)
```python
tf.reverse_sequence(
input,
seq_lengths,
seq_axis=None,
batch_axis=None,
name=None,
seq_dim=None,
batch_dim=None
)
```
### [paddle.fluid.layers.sequence_reverse](http://paddlepaddle.org/documentation/docs/zh/1.2/api_cn/layers_cn.html#sequence_reverse)
```python
paddle.fluid.layers.sequence_reverse(
x,
name=None
)
```
### 功能差异
#### 输入格式
Tensorflow:`reverse_sequence`中,`input`是一个带padding的tensor,每个序列都会被填充到相同长度;
PaddlePaddle:`sequence_reverse`中,`x`是一个[LoDTensor](http://paddlepaddle.org/documentation/docs/zh/1.2/api_cn/fluid_cn.html#lodtensor)
不需要进行填充;
#### 参数类型
Tensorflow:通过`seq_axis``batch_axis`指定序列维度与batch维度;同时使用`seq_lengths`来表示每个序列的长度,属于序列的部分会被翻转,padding部分则被保留;
PaddlePaddle:由于`LoDTensor`本身已经携带序列信息,因而不需要用户提供除了输入tensor外的额外参数;
### 代码示例
```
# x是shape为[5, 6]的LoDTensor,其LoD信息为{0, 2, 5},表示两个序列,长度分别是2和3
# out同样也是shape为[5, 6]的LoDTensor,LoD信息为{0, 2, 5},表示两个序列
# out[0:2, 6] = x[2:0:-1, 6]
# out[2:5, 6] = x[5:2:-1, 6]
out = fluid.layers.sequence_reverse(x)
```
## tf.scatter_update
### [tf.scatter_update](https://www.tensorflow.org/api_docs/python/tf/scatter_update)
```python
tf.scatter_update(
ref,
indices,
updates,
use_locking=True,
name=None
)
```
### [paddle.fluid.layers.scatter](http://paddlepaddle.org/documentation/docs/zh/1.2/api_cn/layers_cn.html#scatter)
```python
paddle.fluid.layers.scatter(
input,
index,
updates,
name=None
)
```
### 功能差异
#### 参数类型
Tensorflow:`indices`支持任意维度,可以是变量,也可以是常量;
PaddlePaddle:`index`只支持1-d Variable。
#### 其他
Tensorflow:`updates`支持numpy-style broadcasting;
PaddlePaddle:`updates`要求其rank与`input`相同,同时`updates.shape[0]`等于`index.shape[0]`
### 代码示例
```
# x是dtype为float32, shape为[3,9,5]的张量
# 将x[1:,:,:]置为1,并返回更新后的张量
out = layers.scatter(x,
index=layers.assign(np.array([1,2], dtype='int32')),
updates=layers.assign(np.ones((2,9,5), dtype='float32')))
```
## tf.slice
### [tf.slice](https://www.tensorflow.org/api_docs/python/tf/slice)
``` python
tf.slice(
input_,
begin,
size,
name=None
)
```
### [paddle.fluid.layers.slice](http://paddlepaddle.org/documentation/docs/zh/1.2/api_cn/layers_cn.html#cn-api-fluid-layers-slice)
``` python
paddle.fluid.layers.slice(
input,
axes,
starts,
ends
)
```
### 功能差异
#### 参数类型
TensorFlow:`begin/size`可以是python list,也可以是变量类型;
PaddlePaddle:`axes/starts/ends`只能是python list。
#### 参数种类
TensorFlow:使用`begin`指定要开始截取tensor的位置,使用`size`指定截取长度,必须描述所有的轴;
PaddlePaddle:采用`axes`指定要操作的轴,未指定的轴默认全部截取,使用`starts``ends`分别指定截取tensor的开始与结束位置,注意采用的是先闭后开[start, end)的写法。
### 代码示例
```python
# 输入 tensor t 为[[0,1,2,3],[4,5,6,7],[8,9,10,11]]
# 输出 tensor out 为[[1,2],[5,6]]
out = fluid.layers.slice(t, axes=[0,1], starts=[0,1], ends=[2,3])
# 输出 tensor out 为[[1,2],[5,6],[9,10]]
out = fluid.layers.slice(t, axes=[1], starts=[1], ends=[3])
```
## tf.split
### [tf.split](https://www.tensorflow.org/api_docs/python/tf/split)
```python
tf.split(
value,
num_or_size_splits,
axis=0,
num=None,
name='split'
)
```
### [paddle.fluid.layers.split](http://paddlepaddle.org/documentation/docs/zh/1.2/api_cn/layers_cn.html#split)
```python
paddle.fluid.layers.split(
input,
num_or_sections,
dim=-1,
name=None
)
```
### 功能差异
#### 返回值类型
TensorFlow:`split`函数返回的结果均保存在一个tensor类型的值中;
PaddlePaddle:`split`返回`list`类型结果,长度为`num_or_sections`
### 代码示例
```
# x是shape为[3,9,5]的张量:
x0, x1, x2 = fluid.layers.split(x, num_or_sections=3, dim=1)
x0.shape # [3, 3, 5]
x1.shape # [3, 3, 5]
x2.shape # [3, 3, 5]
```
## tf.squared_difference
### [tf.squared_diffenrece](https://www.tensorflow.org/api_docs/python/tf/math/squared_difference)
``` python
tf.math.squared_difference(
x,
y,
name=None
)
```
### PaddlePaddle实现
PaddlePaddle中目前无对应接口,可使用如下代码实现
``` python
def squared_difference(x, y):
net_0 = fluid.layers.elementwise_sub(x, y)
net_1 = fluid.layers.elementwise_mul(net_0, net_0)
return net_1
```
### 代码示例
``` python
input_x = fluid.layers.data(dtype='float32', shape=[1000], name='input_x')
input_y = fluid.layers.data(dtype='float32', shape=[1000], name='input_y')
# 调用上述自定义函数
result = squared_difference(input_x, input_y)
```
## tf.stop_gradient
### [tf.stop_gradient](https://www.tensorflow.org/api_docs/python/tf/stop_gradient)
``` python
tf.stop_gradient(
input,
name=None
)
```
### PaddlePaddle实现
TensorFlow中,使用`stop_gradient`表示该tensor不需要进行bp。而在PaddlePaddle中,每个tensor具有`stop_gradient`的属性,用户可以将该属性直接设置成`True`/`False`
## 代码示例
```python
# 将tensor t设置成不需要bp
t.stop_gradient = True
## tf.while_loop
### [tf.while_loop](https://www.tensorflow.org/api_docs/python/tf/while_loop)
```python
tf.while_loop(
cond,
body,
loop_vars,
shape_invariants=None,
parallel_iterations=10,
back_prop=True,
swap_memory=False,
name=None,
maximum_iterations=None,
return_same_structure=False
)
```
### [paddle.fluid.layers.While](http://paddlepaddle.org/documentation/docs/zh/1.3/api_cn/layers_cn.html#while)
```python
paddle.fluid.layers.While(
cond,
is_test=False,
name=None
)
```
### 功能差异
#### 使用方式
TensorFlow:用户通过函数的方式定义`cond``body`,在循环体中操纵的是循环变量`loop_vars`,返回值为`tensor`或其`list`;
PaddlePaddle:用户通过op的方式定义`cond`,然后在`block`中实现循环体。*注意,在循环体中用户需要更新`cond`,具体可参数代码示例*
#### 其他
TensorFlow:支持设置最大迭代次数`maximum_iterations`及并行迭代`parallel_iterations`;
PaddlePaddle:不涉及最大迭代次数及并行。
### 代码示例
```
# 如下代码片段实现从0到5循环叠加i
i = fluid.layers.fill_constant(shape=[1], dtype='int64', value=0)
limit = fluid.layers.fill_constant(shape=[1], dtype='int64', value=5)
# 定义条件
cond = layers.less_than(x=i, y=limit)
while_op = layers.While(cond=cond)
# 定义循环体
with while_op.block():
# 更新i
i = layers.increment(x=i, in_place=True)
# 更新条件状态
layers.less_than(x=i, y=limit, cond=cond)
```
......@@ -179,18 +179,7 @@ class PaddleEmitter(object):
desc_size = tensor_desc.ByteSize()
filew.write(struct.pack('i', desc_size))
filew.write(tensor_desc.SerializeToString())
if len(shape) == 0:
if weight.size == 1:
tensor_size = 1
weight = numpy.array([weight])
else:
tensor_size = 0
else:
tensor_size = reduce(lambda x, y: x * y, shape)
weight = weight.flatten()
for i in range(0, tensor_size):
filew.write(
struct.pack(struct_write_format[str(weight.dtype)], weight[i]))
weight.tofile(filew)
filew.close()
@property
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册