Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
PaddlePaddle
FluidDoc
提交
830bd9e8
F
FluidDoc
项目概览
PaddlePaddle
/
FluidDoc
通知
5
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
23
列表
看板
标记
里程碑
合并请求
111
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
F
FluidDoc
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
23
Issue
23
列表
看板
标记
里程碑
合并请求
111
合并请求
111
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
未验证
提交
830bd9e8
编写于
10月 24, 2018
作者:
T
Tink_Y
提交者:
GitHub
10月 24, 2018
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #169 from PaddlePaddle/tink2123-patch-2
Create LoD-Tensor.md
上级
464b6c86
2d5ff206
变更
1
显示空白变更内容
内联
并排
Showing
1 changed file
with
238 addition
and
0 deletion
+238
-0
doc/fluid/user_guides/design_idea/lod_tensor.md
doc/fluid/user_guides/design_idea/lod_tensor.md
+238
-0
未找到文件。
doc/fluid/user_guides/design_idea/lod_tensor.md
0 → 100644
浏览文件 @
830bd9e8
# LoD-Tensor
LoD(Level-of-Detail) Tensor是Fluid中特有的概念,它在Tensor基础上附加了序列信息。Fluid中可传输的数据包括:输入、输出、网络中的可学习参数,全部统一使用LoD-Tensor表示。
阅读本文档将帮助您了解 Fluid 中的 LoD-Tensor 设计思想,以便您更灵活的使用这一数据类型。
## 变长序列的挑战
大多数的深度学习框架使用Tensor表示一个mini-batch。
例如一个mini-batch中有10张图片,每幅图片大小为32x32,则这个mini-batch是一个10x32x32的 Tensor。
或者在处理NLP任务中,一个mini-batch包含N个句子,每个字都用一个D维的one-hot向量表示,假设所有句子都用相同的长度L,那这个mini-batch可以被表示为NxLxD的Tensor。
上述两个例子中序列元素都具有相同大小,但是在许多情况下,训练数据是变长序列。基于这一场景,大部分框架采取的方法是确定一个固定长度,对小于这一长度的序列数据以0填充。
在Fluid中,由于LoD-Tensor的存在,我们不要求每个mini-batch中的序列数据必须保持长度一致,因此您不需要执行填充操作,也可以满足处理NLP等具有序列要求的任务需求。
Fluid引入了一个索引数据结构(LoD)来将张量分割成序列。
## LoD 索引
为了更好的理解LoD的概念,本节提供了几个例子供您参考:
**句子组成的 mini-batch**
假设一个mini-batch中有3个句子,每个句子中分别包含3个、1个和2个单词。我们可以用(3+1+2)xD维Tensor 加上一些索引信息来表示这个mini-batch:
```
3 1 2
| | | | | |
```
上述表示中,每一个
`|`
代表一个D维的词向量,数字3,1,2构成了 1-level LoD。
**递归序列**
让我们来看另一个2-level LoD-Tensor的例子:假设存在一个mini-batch中包含3个句子、1个句子和2个句子的文章,每个句子都由不同数量的单词组成,则这个mini-batch的样式可以看作:
```
3 1 2
3 2 4 1 2 3
||| || |||| | || |||
```
表示的LoD信息为:
```
[[3,1,2]/*level=0*/,[3,2,4,1,2,3]/*level=1*/]
```
**视频的mini-batch**
在视觉任务中,时常需要处理视频和图像这些元素是高维的对象,假设现存的一个nimi-batch包含3个视频,分别有3个,1个和2个帧,每个帧都具有相同大小:640x480,则这个mini-batch可以被表示为:
```
3 1 2
口口口 口 口口
```
最底层tensor大小为(3+1+2)x640x480,每一个
`口`
表示一个640x480的图像
**图像的mini-batch**
在传统的情况下,比如有N个固定大小的图像的mini-batch,LoD-Tensor表示为:
```
1 1 1 1 1
口口口口 ... 口
```
在这种情况下,我们不会因为索引值都为1而忽略信息,仅仅把LoD-Tensor看作是一个普通的张量:
```
口口口口 ... 口
```
**模型参数**
模型参数只是一个普通的张量,在Fluid中它们被表示为一个0-level LoD-Tensor。
## LoDTensor的偏移表示
为了快速访问基本序列,Fluid提供了一种偏移表示的方法——保存序列的开始和结束元素,而不是保存长度。
在上述例子中,您可以计算基本元素的长度:
```
3 2 4 1 2 3
```
将其转换为偏移表示:
```
0 3 5 9 10 12 15
= = = = = =
3 2+3 4+5 1+9 2+10 3+12
```
所以我们知道第一个句子是从单词0到单词3,第二个句子是从单词3到单词5。
类似的,LoD的顶层长度
```
3 1 2
```
可以被转化成偏移形式:
```
0 3 4 6
= = =
3 3+1 4+2
```
因此该LoD-Tensor的偏移表示为:
```
0 3 4 6
3 5 9 10 12 15
```
## LoD-Tensor
一个LoD-Tensor可以被看作是一个树的结构,树叶是基本的序列元素,树枝作为基本元素的标识。
在 Fluid 中 LoD-Tensor 的序列信息有两种表述形式:原始长度和偏移量。在 Paddle 内部采用偏移量的形式表述 LoD-Tensor,以获得更快的序列访问速度;在 python API中采用原始长度的形式表述 LoD-Tensor 方便用户理解和计算,并将原始长度称为:
`recursive_sequence_lengths`
。
以上文提到的一个2-level LoD-Tensor为例:
```
3 1 2
3 2 4 1 2 3
||| || |||| | || |||
```
-
以偏移量表示此 LoD-Tensor:[ [0,3,4,6] , [0,3,5,9,10,12,15] ],
-
以原始长度表达此 Lod-Tensor:recursive_sequence_lengths=[ [3-0 , 4-3 , 6-4] , [3-0 , 5-3 , 9-5 , 10-9 , 12-10 , 15-12] ]。
以文字序列为例: [3,1,2] 可以表示这个mini-batch中有3篇文章,每篇文章分别有3、2、1个句子,[3,2,4,1,2,3] 表示每个句子中分别含有3、2、4、1、2、3个字。
recursive_seq_lens 是一个双层嵌套列表,也就是列表的列表,最外层列表的size表示嵌套的层数,也就是lod-level的大小;内部的每个列表,对应表示每个lod-level下,每个元素的大小。
```
python
#查看lod-tensor嵌套层数
print
len
(
recursive_seq_lengths
)
# output:2
#查看最基础元素个数
print
sum
(
recursive_seq_lengths
[
-
1
])
# output:15 (3+2+4+1+2+3=15)
```
## 代码示例
本节代码将根据指定的级别y-lod,扩充输入变量x。本例综合了LoD-Tensor的多个重要概念,跟随代码实现,您将:
-
直观理解Fluid中
`fluid.layers.sequence_expand`
的实现过程
-
掌握如何在Fluid中创建LoD-Tensor
-
学习如何打印LoDTensor内容
**创建LoD-Tensor**
Fluid中可以通过
`fluid.create_lod_tensor()`
创建一个LoD-Tensor,使用说明请参考
[
API reference
](
http://paddlepaddle.org/documentation/api/zh/develop/fluid.html#create-lod-tensor
)
。需要注意的是,这个API只能支持int64的数据,如果您希望处理float32的数据,推荐您使用下述方式创建lod_tensor:
使用fluid.LoDTensor()创建一个LoD-Tensor,并为其指定数据、运算场所和LoD值:
```
python
import
paddle.fluid
as
fluid
import
numpy
as
np
def
create_lod_tensor
(
data
,
lod
,
place
):
res
=
fluid
.
LoDTensor
()
res
.
set
(
data
,
place
)
res
.
set_lod
(
lod
)
return
res
```
**定义计算过程**
layers.sequence_expand通过获取 y 的 lod 值对 x 的数据进行扩充,关于
`fluid.layers.sequence_expand`
的功能说明,请先阅读
[
API reference
](
http://www.paddlepaddle.org/documentation/api/zh/0.15.0/layers.html#sequence-expand
)
。
序列扩充代码实现:
```
python
x
=
fluid
.
layers
.
data
(
name
=
'x'
,
shape
=
[
1
],
dtype
=
'float32'
,
lod_level
=
0
)
y
=
fluid
.
layers
.
data
(
name
=
'y'
,
shape
=
[
1
],
dtype
=
'float32'
,
lod_level
=
1
)
out
=
fluid
.
layers
.
sequence_expand
(
x
=
x
,
y
=
y
,
ref_level
=
0
)
```
*说明*
:输出LoD-Tensor的维度仅与传入的真实数据维度有关,在定义网络结构阶段为x、y设置的shape值,仅作为占位,并不影响结果。
**创建Executor**
```
python
place
=
fluid
.
CPUPlace
()
exe
=
fluid
.
Executor
(
place
)
exe
.
run
(
fluid
.
default_startup_program
())
```
**准备数据**
这里我们使用
[
偏移量
](
#LoDTensor的偏移表示
)
的方法表示Tensor的LoD索引:
假使x_d 为一个LoDTensor:
```
x.lod = [[0,1,4]]
x.data = [[1],[2],[3],[4]]
x.dims = [4,1]
```
y_d 也为一个LoDTensor:
```
y.lod = [[0, 1, 4],
[0, 2, 3, 5, 6]]
```
其中,输出值只与 y 的LoD值有关,y_d 的 data 值在这里并不参与计算,维度上与LoD[-1]一致即可。
预期输出结果为:
```
#预期输出lod的原始长度
out.lod = [ [1, 3, 3, 3]]
#预期输出结果
out.data = [ [1],[2],[3],[4],[2],[3],[4],[2],[3],[4]]
```
实现代码如下:
```
python
x_d
=
create_lod_tensor
(
np
.
array
([[
1
],
[
2
],[
3
],[
4
]]),
[[
0
,
1
,
4
]],
place
)
y_d
=
create_lod_tensor
(
np
.
array
([[
1
],[
1
],[
1
],[
1
],[
1
],[
1
]]),
[[
0
,
1
,
4
],
[
0
,
2
,
3
,
5
,
6
]],
place
)
```
**执行运算**
在Fluid中,LoD>1的Tensor与其他类型数据一样,使用feed定义数据传入顺序。此外,由于输出results是带有LoD信息的Tensor,需在exe.run( )中添加
`return_numpy=False`
参数,获得LoD-Tensor的输出结果。
```
python
feeder
=
fluid
.
DataFeeder
(
place
=
place
,
feed_list
=
[
x
,
y
])
results
=
exe
.
run
(
fluid
.
default_main_program
(),
feed
=
{
'x'
:
x_d
,
'y'
:
y_d
},
fetch_list
=
[
out
],
return_numpy
=
False
)
```
**查看LodTensor结果**
由于LoDTensor的特殊属性,无法直接print查看内容,常用操作时将LoD-Tensor作为网络的输出fetch出来,然后执行 numpy.array(lod_tensor), 就能转成numpy array:
```
python
np
.
array
(
results
[
0
])
```
输出结果为:
```
array([[1],[2],[3],[4],[2],[3],[4],[2],[3],[4]])
```
可以看到与
[
准备数据
](
#准备数据
)
一节中的预期结果一致。
## 总结
至此,相信您已经基本掌握了LoD-Tensor的概念,尝试修改上述代码中的 x_d 与 y_d,观察输出结果,有助于您更好的理解这一灵活的结构。
更多LoDTensor的模型应用,可以参考新手入门中的
[
词向量
](
../../../beginners_guide/basics/word2vec/index.html
)
、
[
个性化推荐
](
../../../beginners_guide/basics/recommender_system/index.html
)
、
[
情感分析
](
../../../beginners_guide/basics/understand_sentiment/index.html
)
等指导教程。
更高阶的应用案例,请参考
[
模型库
](
../../../user_guides/models/index.html
)
中的相关内容。
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录