organization_of_the_inputs.md 10.0 KB
Newer Older
Y
ying 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
## 输入/输出数据组织

这篇文档介绍在使用 PaddlePaddle C-API 时如何组织输入数据,以及如何解析神经网络前向计算的输出数据。

### 输入/输出数据类型
在C-API中,按照基本数据类型在PaddlePaddle内部的定义和实现,输入数据可分为:
1. 一维整型数组
2. 二维浮点型矩阵
    - 稠密矩阵
    - 稀疏矩阵

  - 说明:
    1. 一维数组**仅支持整型值**
        - 常用于自然语言处理任务,例如:表示词语在词典中的序号;
        - 分类任务中类别标签;
    1. 逻辑上高于二维的数据(例如含有多个通道的图片,视频等)在程序实现中都会转化为二维矩阵,转化方法在相应的领域都有通用解决方案,需要使用者自己了解相关的转化表示方法;
    1. 二维矩阵可以表示行向量和列向量,任何时候,如果需要浮点型数组(向量)时,都应使用C-API中的矩阵来表示,而不是C-API中的一维数组。

不论是一维整型数组还是二维浮点数矩阵,**为它们附加上序列信息,将变成序列输入。PaddlePaddle 会通过判数据是否附带有序列信息来判断一个向量/矩阵是否是一个序列**。关于什么是“序列信息”,下文会进行详细地介绍。

PaddlePaddle 支持两种序列类型:
1. 单层序列
    - 序列中的每一个元素是非序列,是进行计算的基本单位,不可再进行拆分。
    - 例如:自然语言中的句子是一个序列,序列中的元素是词语;
1. 双层序列
    - 序列中的每一个元素又是一个序列。
    - 例如:自然语言中的段落是一个双层序列;段落是有句子构成的序列;句子是由词语构成的序列。
    - 双层序列在处理长序列的任务或是构建层级模型时会发挥作用。

### 基本使用概念

- 在PaddlePaddle内部,神经网络中一个计算层的输入/输出被组织为一个 `Argument` 结构体,如果神经网络有多个输入或者多个输入,每一个输入/输入都会对应有自己的`Argument`
- `Argument` 并不真正“存储”数据,而是将输入/输出信息有机地组织在一起。
-`Argument`内部由`IVector`(对应着上文提到的一维整型数组)和`Matrix`(对应着上文提到的二维浮点型矩阵)来实际存储数据;由 `sequence start position` (下文详细解释) 来记录输入/输出的序列信息。

**注意:这篇文档之后部分将会统一使用`argument`来特指PaddlePaddle中神经网络计算层一个输入/输出数据;使用`ivector`来特指PaddlePaddle中的一维整型数组;使用`matrix`来特指PaddlePaddle中的二维浮点型矩阵;使用`sequence_start_position`来特指PaddlePaddle中的序列信息。**

于是,在组织神经网络输入时,需要思考完成以下工作:
1. 为每一个输入/输出创建`argument`
    - C-API 中操作`argument`的接口请查看[argument.h](https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/capi/arguments.h)
1. 为每一个`argument`创建`matrix`或者`ivector`来存储数据。
    - C-API 中操作`ivector`的接口请查看 [vector.h](https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/capi/vector.h)
    - C-API 中操作`matrix`的接口请查看[matrix.h](https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/capi/matrix.h)
1. 如果输入是序列数据,需要创建并填写`sequence_start_position`信息。
    - 通过调用 [`paddle_arguments_set_sequence_start_pos`](https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/capi/arguments.h#L137) 来为一个`argument`添加序列信息;
    - 通过调用 [`paddle_arguments_get_sequence_start_pos`](https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/capi/arguments.h#L150) 来读取一个`argument`添加序列信息;
    - 接口说明请查看 [argument.h](https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/capi/arguments.h) 文件。

### 组织非序列数据
- 一维整型数组

    概念上可以将`paddle_ivector`理解为一个一维的整型数组,通常用于表示离散的类别标签,或是在自然语言处理任务中表示词语在字典中的序号。下面的代码片段创建了含有三个元素`1`、`2`、`3`的`paddle_ivector`。
    ```cpp
    int ids[] = {1, 2, 3};
     paddle_ivector ids_array =
         paddle_ivector_create(ids, sizeof(ids) / sizeof(int), false, false);
     CHECK(paddle_arguments_set_ids(in_args, 0, ids_array));
    ```
- **稠密矩阵**
    - 一个$m×n$的稠密矩阵是一个由$m$行$n$列元素排列成的矩形阵列,矩阵里的元素是浮点数。对神经网络来说,矩阵的高度$m$是一次预测接受的样本数目,宽度$n$是神经网络定义时,`paddle.layer.data``size`
    - 下面的代码片段创建了一个高度为1,宽度为`layer_size`的稠密矩阵,矩阵中每个元素的值随机生成。

    ```cpp
    paddle_matrix mat =
        paddle_matrix_create(/* height = batch size */ 1,
                             /* width = dimensionality of the data layer */ layer_size,
                             /* whether to use GPU */ false);

    paddle_real* array;
    // Get the pointer pointing to the start address of the first row of the
    // created matrix.
    CHECK(paddle_matrix_get_row(mat, 0, &array));

    // Fill the matrix with a randomly generated test sample.
    srand(time(0));
    for (int i = 0; i < layer_size; ++i) {
      array[i] = rand() / ((float)RAND_MAX);
    }

    // Assign the matrix to the argument.
    CHECK(paddle_arguments_set_value(in_args, 0, mat));
    ```

- **稀疏矩阵**

  PaddlePaddle C-API 中 稀疏矩阵使用[CSR(Compressed Sparse Row Format)](https://en.wikipedia.org/wiki/Sparse_matrix#Compressed_sparse_row_(CSR,_CRS_or_Yale_format))格式存储。下图是CSR存储稀疏矩阵的示意图,在CSR表示方式中,通过(1)行偏移;(2)列号;(3)值;来决定矩阵的内容。

  <p align="center">
  <img src="images/csr.png" width=75%></br>图1. CSR存储示意图.
  </p>

  在PaddlePaddle C-API中通过以下接口创建稀疏矩阵:
  ```cpp
  PD_API paddle_matrix paddle_matrix_create_sparse(
    uint64_t height, uint64_t width, uint64_t nnz, bool isBinary, bool useGpu);
  ```
  1. 创建稀疏矩阵时需要显示地指定矩阵的(1)高度(`height`,在神经网络中等于一次预测处理的样本数)(2)宽度(`width``paddle.layer.data``size`)以及(3)非零元个数(`nnz`)。
  1. 当上述接口第4个参数`isBinary`指定为`true`时,**只需要设置行偏移(`row_offset`)和列号(`colum indices`),不需要提供元素值(`values`)**,这时行偏移和列号指定的元素默认其值为1。

  - 下面的代码片段创建了一个CPU上的二值稀疏矩阵:

      ```cpp
      paddle_matrix mat = paddle_matrix_create_sparse(1, layer_size, nnz, true, false);
      int colIndices[] = {9, 93, 109};  // layer_size here is greater than 109.
      int rowOffset[] = {0, sizeof(colIndices) / sizeof(int)};

      CHECK(paddle_matrix_sparse_copy_from(mat,
                                           rowOffset,
                                           sizeof(rowOffset) / sizeof(int),
                                           colIndices,
                                           sizeof(colIndices) / sizeof(int),
                                           NULL /*values array is NULL.*/,
                                           0 /*size of the value arrary is 0.*/));
      CHECK(paddle_arguments_set_value(in_args, 0, mat));
      ```
   - 下面的代码片段在创建了一个CPU上的带元素值的稀疏矩阵:
      ```cpp
      paddle_matrix mat = paddle_matrix_create_sparse(1, layer_size, nnz, false, false);
      int colIndices[] = {9, 93, 109};  // layer_size here is greater than 109.
      int rowOffset[] = {0, sizeof(colIndices) / sizeof(int)};
      float values[] = {0.5, 0.5, 0.5};

      CHECK(paddle_matrix_sparse_copy_from(mat,
                                           rowOffset,
                                           sizeof(rowOffset) / sizeof(int),
                                           colIndices,
                                           sizeof(colIndices) / sizeof(int),
                                           values,
                                           sizeof(values) / sizeof(float)));
      ```

### 组织序列数据



### Python 端数据类型说明

下表列出了Python端训练接口暴露的数据类型(`paddle.layer.data`函数`type`字段的取值)对应于调用C-API时需要创建的数据类型:


Python 端数据类型  | C-API 输入数据类型|
:-------------: | :-------------:
`paddle.data_type.integer_value` |一维整型数组,无需附加序列信息|
`paddle.data_type.dense_vector` |二维浮点型稠密矩阵,无需附加序列信息|
`paddle.data_type.sparse_binary_vector` |二维浮点型稀疏矩阵,无需提供非零元的值,默认为1,无需附加序列信息|
`paddle.data_type.sparse_vector` |二维浮点型稀疏矩阵,需提供非零元的值,无需附加序列信息|
`paddle.data_type.integer_value_sequence` |一维整型数组,需附加序列信息|
`paddle.data_type.dense_vector_sequence` |二维浮点型稠密矩阵,需附加序列信息|
`paddle.data_type.sparse_binary_vector_sequence` |二维浮点型稀疏矩阵,无需提供非零元的值,默认为1,需附加序列信息|
`paddle.data_type.sparse_vector_sequence` |二维浮点型稀疏矩阵,需提供非零元的值,需附加序列信息|
`paddle.data_type.integer_value_sub_sequence` |一维整型数组,需附加双层序列信息|
`paddle.data_type.dense_vector_sub_sequence` |二维浮点型稠密矩阵,需附加双层序列信息|
`paddle.data_type.sparse_binary_vector_sub_sequence` |二维浮点型稀疏矩阵,无需提供非零元的值,默认为1,需附加双层序列信息|
`paddle.data_type.sparse_vector_sub_sequence` |二维浮点型稀疏矩阵,需提供非零元的值,需附加双层序列信息|