# LoDTensor¶

## 变长序列的解决方案¶

System Message: WARNING/2 (/home/work/paddledoc/FluidDoc/doc/fluid/beginners_guide/basic_concept/lod_tensor.rst, line 12)

Title underline too short.

```变长序列的解决方案
================
```

## LoD 索引¶

```3       1   2
| | |   |   | |
```

```3            1 2
3   2  4     1 2  3
||| || ||||  | || |||
```

```[[3，1，2]/*level=0*/，[3，2，4，1，2，3]/*level=1*/]
```

```3     1  2

```

```1 1 1 1     1

```

```口口口口 ... 口
```

## LoDTensor的偏移表示¶

```3 2 4 1 2 3
```

```0  3  5   9   10  12   15
=  =   =   =   =    =
3  2+3 4+5 1+9 2+10 3+12
```

```3 1 2
```

```0 3 4   6
= =   =
3 3+1 4+2
```

```0       3    4      6
3 5 9   10   12 15
```

## 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] ]。

recursive_seq_lens 是一个双层嵌套列表，也就是列表的列表，最外层列表的size表示嵌套的层数，也就是lod-level的大小；内部的每个列表，对应表示每个lod-level下，每个元素的大小。

• 创建 LoD-Tensor

```#创建lod-tensor
import numpy as np

a = fluid.create_lod_tensor(np.array([[1],[1],[1],
[1],[1],
[1],[1],[1],[1],
[1],
[1],[1],
[1],[1],[1]]).astype('int64') ,
[[3,1,2] , [3,2,4,1,2,3]],
fluid.CPUPlace())

#查看lod-tensor嵌套层数
print (len(a.recursive_sequence_lengths()))
# output：2

#查看最基础元素个数
print (sum(a.recursive_sequence_lengths()[-1]))
# output:15 (3+2+4+1+2+3=15)
```
• LoD-Tensor 转 Tensor

```import paddle.fluid as fluid
import numpy as np

# 创建一个 LoD-Tensor
a = fluid.create_lod_tensor(np.array([[1.1], [2.2],[3.3],[4.4]]).astype('float32'), [[1,3]], fluid.CPUPlace())

def LodTensor_to_Tensor(lod_tensor):
# 获取 LoD-Tensor 的 lod 信息
lod = lod_tensor.lod()
# 转换成 array
array = np.array(lod_tensor)
new_array = []
# 依照原LoD-Tensor的层级信息，转换成Tensor
for i in range(len(lod[0]) - 1):
new_array.append(array[lod[0][i]:lod[0][i + 1]])
return new_array

new_array = LodTensor_to_Tensor(a)

# 输出结果
print(new_array)
```
• Tensor 转 LoD-Tensor

```import paddle.fluid as fluid
import numpy as np

def to_lodtensor(data, place):
# 存储Tensor的长度作为LoD信息
seq_lens = [len(seq) for seq in data]
cur_len = 0
lod = [cur_len]
for l in seq_lens:
cur_len += l
lod.append(cur_len)
# 对待转换的 Tensor 降维
flattened_data = np.concatenate(data, axis=0).astype("float32")
flattened_data = flattened_data.reshape([len(flattened_data), 1])
# 为 Tensor 数据添加lod信息
res = fluid.LoDTensor()
res.set(flattened_data, place)
res.set_lod([lod])
return res

# new_array 为上段代码中转换的Tensor
lod_tensor = to_lodtensor(new_array,fluid.CPUPlace())

# 输出 LoD 信息
print("The LoD of the result: {}.".format(lod_tensor.lod()))

# 检验与原Tensor数据是否一致
print("The array : {}.".format(np.array(lod_tensor)))
```

## 代码示例¶

• 直观理解Fluid中 `fluid.layers.sequence_expand` 的实现过程

• 掌握如何在Fluid中创建LoD-Tensor

• 学习如何打印LoDTensor内容

layers.sequence_expand通过获取 y 的 lod 值对 x 的数据进行扩充，关于 `fluid.layers.sequence_expand` 的功能说明，请先阅读 cn_api_fluid_layers_sequence_expand

```x = fluid.layers.data(name='x', shape=[1], dtype='float32', lod_level=1)
y = fluid.layers.data(name='y', shape=[1], dtype='float32', lod_level=2)
out = fluid.layers.sequence_expand(x=x, y=y, ref_level=0)
```

```place = fluid.CPUPlace()
exe = fluid.Executor(place)
exe.run(fluid.default_startup_program())
```

`fluid.create_lod_tensor()` 的使用说明请参考 cn_api_fluid_create_lod_tensor

```x_d = fluid.create_lod_tensor(np.array([[1.1],[2.2],[3.3],[4.4]]).astype('float32'), [[1,3]], place)
y_d = fluid.create_lod_tensor(np.array([[1.1],[1.1],[1.1],[1.1],[1.1],[1.1]]).astype('float32'), [[1,3], [2,1,2,1]],place)
```

```results = exe.run(fluid.default_main_program(),
feed={'x':x_d, 'y': y_d },
fetch_list=[out],return_numpy=False)
```

```np.array(results[0])
```

```array([[1.1],[2.2],[3.3],[4.4],[2.2],[3.3],[4.4],[2.2],[3.3],[4.4]])
```

```results[0].recursive_sequence_lengths()
```

```[[1L, 3L, 3L, 3L]]
```

```#加载库
import numpy as np
#定义前向计算
x = fluid.layers.data(name='x', shape=[1], dtype='float32', lod_level=1)
y = fluid.layers.data(name='y', shape=[1], dtype='float32', lod_level=2)
out = fluid.layers.sequence_expand(x=x, y=y, ref_level=0)
#定义运算场所
place = fluid.CPUPlace()
#创建执行器
exe = fluid.Executor(place)
exe.run(fluid.default_startup_program())
#创建LoDTensor
x_d = fluid.create_lod_tensor(np.array([[1.1], [2.2],[3.3],[4.4]]).astype('float32'), [[1,3]], place)
y_d = fluid.create_lod_tensor(np.array([[1.1],[1.1],[1.1],[1.1],[1.1],[1.1]]).astype('float32'), [[1,3], [1,2,1,2]], place)
#开始计算
results = exe.run(fluid.default_main_program(),
feed={'x':x_d, 'y': y_d },
fetch_list=[out],return_numpy=False)
#输出执行结果
print("The data of the result: {}.".format(np.array(results[0])))
#输出 result 的序列长度
print("The recursive sequence lengths of the result: {}.".format(results[0].recursive_sequence_lengths()))
#输出 result 的 LoD
print("The LoD of the result: {}.".format(results[0].lod()))
```

## FAQ：¶

1. 可以使用 executor.run 将你需要查看的 variable fetch 出来，然后打印其 lod 信息，注意运行时设置 executor.run 方法的 return_numpy 参数为 False

```results = exe.run(fluid.default_main_program(),
feed={'x':x_d, 'y': y_d },
fetch_list=[out],return_numpy=False)
lod_tensor = results[0]
print (lod_tensor.lod())
```
1. 可以使用fluid.layers.Print()

```y = fluid.layers.data(name='y', shape=[1], dtype='float32', lod_level=2)

fluid.layers.Print(y)
```