Commit b5d217dc by linye

Upload New File

parent ffb1db81
# NiuTrans.Tensor张量计算库
## NiuTrans.Tensor
NiuTrans.Tensor是小牛开源项目所开发的一个工具包,提供了完整的张量定义及计算功能,可以被用于深度学习相关研究及工业系统的开发。NiuTrans.Tensor具有以下特点:
* 简单小巧,易于修改
* c语言编写,代码高度优化
* 同时支持CPU和GPU设备
* 丰富的张量计算接口
* 支持C/C++、Python等调用方式
## 安装NiuTrans.Tensor
在开始创建您的项目并使用NiuTrans.Tensor工具包时,需要注意的是:
* 所创建项目如在CPU上运行,我们的系统支持高性能的数学运算库,推荐安装[Intel® MKL](https://software.intel.com/en-us/mkl)[OpenBLAS](http://www.openblas.net/)
* 所创建项目如需在GPU上运行,需安装 [NVIDIA®CUDA®Toolkit](https://developer.nvidia.com/cuda-downloads),CUDA版本需求为9.0及以上,CUDA工具为创建高性能GPU加速应用程序提供了开发环境。
在使用小牛开源项目所开发的NiuTrans.Tensor工具包时:
* 首先需要将NiuTrans.Tensor代码包含在所创建的项目中
* 需要引用XTensor.h、core里的CHeader.h和function里的FHeader.h这三个头文件:
* 通过XTensor.h可以获取我们需要操作的XTensor类
* 通过core里的CHeader.h可以对Tensor进行一些张量运算
* 通过function里的FHeader.h可以调用一些激活函数
* 在所创建项目中使用命名空间nts
## 什么是张量
在计算机科学中,张量(Tensor)通常被定义为\\(n\\)维空间中的一种量,它具有\\(n\\)个分量,这种张量本质上是一个多维数组( multidimensional array)。张量的阶或秩是这个多维数组的维度,或者简单理解为索引张量里的每个元素所需要的索引个数。通常来说,0阶张量被定义为标量(Scalar),1阶张量被定义为向量(vector),而2阶张量被定义为矩阵(matrix)。比如,在一个三维空间中,1阶张量就是空间中点所表示的向量\\((x,y,z)\\),其中\\(x\\)、\\(y\\)、\\(z\\)分别表示这个点在三个轴上的坐标。
张量是一种高效的数学建模工具,它可以将复杂的问题通过统一、简洁的方式进行表达。比如,姜英俊同学做饭需要2斤牛肉、5斤土豆,市场上牛肉每斤32元、土豆每斤2元,那么购买这些食物总共花费\\(2 \times 32 + 5 \times 2 = 74\\)元。如果用张量来描述,我们可以用一个1阶张量\\(a=(2,5)\\)表示所需不同食物的重量。然后用另一个1阶张量\\(b=(32,2)\\)表示不同食物的价格。最后,我们用一个0阶张量\\(c\\)表示购买这些食物的总价,计算如下
$$
\begin{aligned}
c & = a \times b^T \\\\
& = \left(\begin{matrix}2 & 5\end{matrix}\right) \times \left(\begin{matrix}32 \\\\ 2\end{matrix}\right) \\\\
& = 2 \times 32 + 5 \times 2 \\\\
& = 74
\end{aligned}
$$
其中\\(b^T\\)表示行向量\\(b\\)的转置 - 列向量,\\(\times\\)表示向量的乘法。第二天,姜英俊同学换了一个市场,这里牛肉每斤35元、土豆每斤1元。如果要知道在两个市场分别购物的总价,可以把\\(b\\)重新定义为一个2阶张量\\(\left(\begin{matrix}32 & 2 \\\\ 35 & 1\end{matrix}\right)\\),总价\\(c\\)定义为一个2阶张量。同样有
$$
\begin{aligned}
c & = a \times b^T \\\\
& = \left(\begin{matrix}2 & 5\end{matrix}\right) \times \left(\begin{matrix}32 & 35 \\\\ 2 & 1\end{matrix}\right) \\\\
& = \left(\begin{matrix}74 & 75\end{matrix}\right)
\end{aligned}
$$
即,在两个市场分别花费74元和75元。可以看出,利用张量可以对多样、复杂的问题进行建模,比如,可以进一步扩展上述问题中\\(a\\)、\\(b\\)、\\(c\\)的定义,把它们定义成更高阶的张量,处理不同时间、不同市场、不同菜谱的情况,但是不论情况如何变化,都可以用同一个公式\\(c = a \times b^T\\)来描述问题。
许多现实世界的问题都可以被描述为张量表达式(expression),也就是把张量的组合、计算描述为算数表达式。这种建模方式也构成了现代神经网络模型及深度学习方法的基础。在许多机器学习工具中,张量计算已经成为了神经网络前向、反向传播等过程的基本单元,应用十分广泛。
## 如何定义张量
如果你是一名C/C++或者Python的使用者,那么在程序中使用NiuTrans.Tensor定义张量将非常简单。首先,下载NiuTrans.Tensor的工具包(source???),并解压到任意目录,比如~/NTS目录。我们会在NTS这个目录中找到source子目录,它是存放源代码的目录。对于source子目录的结构,信息如下:
* ~/NTS/source/XTensor.h - 定义了张量结构XTensor,以及构建和销毁XTensor的接口
* ~/NTS/source/core - 存放张量计算的函数声明及函数体实现的源文件
* ~/NTS/source/function - 存放各种激活函数的源文件
* ~/NTS/source/test - 存放单元测试的源文件
* ~/NTS/source/*.h(cpp) - 与张量定义不相关,后文介绍 :)
以C/C++为例,仅需要在源程序中引用XTensor.h头文件就可以完成张量的定义。下面是一个简单的示例程序sample.cpp
```
#inlucde "XTensor.h" // 引用XTensor定义的头文件
using namepsace nt; // 使用XTensor所在的命名空间nt
int main(int argc, const char ** argv)
{
// 声明一个变量tensor,它的类型是XTensor
XTensor tensor;
// 初始化这个变量为50列*100行的矩阵(2阶张量)
InitTensor2D(&tensor, 50, 100, X_FLOAT);
// 之后可以使用张量tensor了
return 0;
}
```
下一步,编译以上源程序,这个过程需要指定XTensor.h头文件所在目录。比如,使用g++编译sample.cpp(如果你使用的是visual studio,请看这里???)
```
g++ sample.cpp -I~/NTS/source -o sample
```
在sample.cpp中使用了XTensor,它是NiuTrans.Tensor里的一个类,这个类定义了张量所需的数据结构。我们可以使用这个类完成对张量的计算、拷贝等各种操作。XTensor类型的变量被声明后,这个变量需要被初始化,或者说被真正指定为一个张量,比如,指定张量各个维度的大小、张量中每个单元的数据类型、给张量分配内存空间等。InitTensor2D()就是一个张量初始化函数,它把张量初始化为一个矩阵,有四个参数:指向被初始化的张量的指针,矩阵的列数,矩阵的行数,数据单元的类型。这里X_FLOAT,是NiuTrans.Tensor自定义的枚举类型,它表示单精度浮点数。我们也可以使用X_INT或者X_DOUBLE,将数据类型指定为32bit整数或者双精度浮点数。
NiuTrans.Tensor也提供了其它方式定义张量。比如可以直接调用一个函数完成张量的创建,而且可以显性释放张量。下面是一段示例代码(sample2.cpp):
```
#inlucde "XTensor.h" // 引用XTensor定义的头文件
using namepsace nt; // 使用XTensor所在的命名空间nt
int main(int argc, const char ** argv)
{
// 构建一个单精度浮点类型张量,它是一个50列*100行的矩阵
XTensor * tensor = NewTensor2D(50, 100, X_FLOAT);
// 之后可以使用张量tensor了
// 释放这个张量
DelTensor(tensor);
return 0;
}
```
sample2.cpp中使用的NewTensor2D和DelTensor是一组函数,前者生成张量并返回指向这个张量的指针,后者释放指针所指向张量的内容。这种方法比较适合C/C++风格的开发。
> 注意,在NiuTrans.Tensor中所有张量默认都是“稠密”张量,也就是张量中所有的单元都会被分配空间,而且这些空间是连续的。有些情况下,张量里的单元仅有少数为非零单元,对于这类张量,可以使用“稀疏"的表示方法,这样可以有效的节省存储空间。
如果要定义稀疏张量,需要在原有的参数基础上额外指定一个参数 - 稠密度。所谓稠密度是指非零单元的比例,他是介于0和1之间的一个实数,0表示所有单元全为零,1表示全为非零单元。默认所有张量的稠密度都是1。下面是不同类型张量的定义方法示例(sample3.cpp)
```
#inlucde "XTensor.h" // 引用XTensor定义的头文件
using namepsace nt; // 使用XTensor所在的命名空间nt
int main(int argc, const char ** argv)
{
// 构建一个单精度浮点类型张量,它是一个50列*100行的矩阵
// 这个张量是稠密的
XTensor * tensor0 = NewTensor2D(50, 100, X_FLOAT);
// 构建一个单精度浮点类型张量,它是一个50列*100行的矩阵
// 这个张量是稠密的
XTensor * tensor1 = NewTensor2D(50, 100, X_FLOAT, 1.0F);
// 构建一个单精度浮点类型张量,它是一个50列*100行的矩阵
// 这个张量是稀疏的,有10%的单元非零
XTensor * tensor2 = NewTensor2D(50, 100, X_FLOAT, 0.1F);
// 之后可以使用张量tensor0,tensor1和tensor2了
// 释放这些张量
DelTensor(tensor0);
DelTensor(tensor1);
DelTensor(tensor2);
return 0;
}
```
以下是关于张量定义的基础函数:
| 功能 | 函数| 参数 |
| -: | - | - |
| 初始化张量 | void InitTensor(<br>XTensor * tensor, const int myOrder, <br> const int * myDimSize, <br> const TENSOR_DATA_TYPE myDataType = X_FLOAT, <br> const float myDenseRatio, <br>const int myDevID = -1, XMem * myMem = NULL) <br> <br> <br> | tensor - 指向被初始化张量的指针 <br> myOrder - 张量的维度 <br> myDimSize - 张量每一维的大小,索引0表示第一维 <br> myDenseRatio - 张量的稠密度,1表示稠密张量 <br> myDataType - 张量的数据类型 <br> myDevID - 张量所在的设备ID <br> myMem - 张量所使用的内存池 |
| 初始化稠密张量 | void InitTensor(<br>XTensor * tensor, const int myOrder, <br> const int * myDimSize, <br> const TENSOR_DATA_TYPE myDataType = X_FLOAT, <br>const int myDevID = -1, XMem * myMem = NULL) <br> <br> | tensor - 指向被初始化张量的指针 <br> myOrder - 张量的维度 <br> myDimSize - 张量每一维的大小,索引0表示第一维 <br> myDataType - 张量的数据类型 <br> myDevID - 张量所在的设备ID <br> myMem - 张量所使用的内存池 |
| 创建空张量 | XTensor * NewTensor() | N/A |
| 创建张量 | XTensor * NewTensor(<br>const int myOrder, <br> const int * myDimSize, const float myDenseRatio, <br> const TENSOR_DATA_TYPE myDataType = X_FLOAT, <br>const int myDevID = -1, XMem * myMem = NULL) <br> <br> | myOrder - 张量的维度 <br> myDimSize - 张量每一维的大小,索引0表示第一维 <br> myDenseRatio - 张量的稠密度,1表示稠密张量 <br> myDataType - 张量的数据类型 <br> myDevID - 张量所在的设备ID <br> myMem - 张量所使用的内存池 |
| 创建稠密张量 | XTensor * NewTensor(<br>const int myOrder, <br> const int * myDimSize, <br> const TENSOR_DATA_TYPE myDataType = X_FLOAT, <br>const int myDevID = -1, XMem * myMem = NULL) <br> | myOrder - 张量的维度 <br> myDimSize - 张量每一维的大小,索引0表示第一维 <br> myDataType - 张量的数据类型 <br> myDevID - 张量所在的设备ID <br> myMem - 张量所使用的内存池 |
| 销毁张量 | void DelTensor(const XTensor * tensor) | tensor - 指向要被销毁的张量的指针 |
上述函数中需要说明的是
* 设备ID是指张量所申请的空间所在CPU或者GPU设备的编号,-1表示CPU
* XMem是NiuTrans.Tensor中的一个内存/显存池类,它负责内存(或显存)的统一管理。关于设备ID和XMem的进一步说明,请参见下一节内容。
* TENSOR_DATA_TYPE定义了张量的数据类型,包括:
| 类型 | 说明 |
| - | - |
| X_INT | 32bit整数 |
| X_FLOAT | 32bit浮点数 |
| X_DOUBLE | 64bit浮点数 |
| X_INT8 | 8bit整数(计划支持)|
| X_FLOAT16 | 16bit浮点数(计划支持) |
此外,NiuTrans.Tensor也提供了更多种类的张量初始化和创建方法:
| 功能 | 函数 | 参数 |
| -: | - | - |
| 初始化为稠密向量 | void InitTensor1D(<br>XTensor * tensor, const int num, <br> const TENSOR_DATA_TYPE myDataType = X_FLOAT, <br>const int myDevID = -1, XMem * myMem = NULL) <br> <br> | tensor - 指向被初始化张量的指针 <br> num - 向量维度大小 <br> myDataType - 张量的数据类型 <br> myDevID - 张量所在的设备ID <br> myMem - 张量所使用的内存池 |
| 初始化为稠密矩阵 | void InitTensor2D(<br>XTensor * tensor, const int colNum, const int rowNum, <br> const TENSOR_DATA_TYPE myDataType = X_FLOAT, <br>const int myDevID = -1, XMem * myMem = NULL) <br> <br> <br> | tensor - 指向被初始化张量的指针 <br> colNum - 矩阵列数 <br> rowNum - 矩阵行数 <br> myDataType - 张量的数据类型 <br> myDevID - 张量所在的设备ID <br> myMem - 张量所使用的内存池 |
| 初始化为3维稠密张量 | void InitTensor3D(<br>XTensor * tensor, <br> const int d0, const int d1, const int d2, <br> const TENSOR_DATA_TYPE myDataType = X_FLOAT, <br>const int myDevID = -1, XMem * myMem = NULL) <br> <br> <br> | tensor - 指向被初始化张量的指针 <br> d0 - 张量第一维大小 <br> d1 - 张量第二维大小 <br> d2 - 张量第三维大小 <br> myDataType - 张量的数据类型 <br> myDevID - 张量所在的设备ID <br> myMem - 张量所使用的内存池 |
| 初始化为4维稠密张量 | void InitTensor4D(<br>XTensor * tensor, <br> const int d0, const int d1, const int d2, const int d3, <br> const TENSOR_DATA_TYPE myDataType = X_FLOAT, <br>const int myDevID = -1, XMem * myMem = NULL) <br> <br> <br> <br> | tensor - 指向被初始化张量的指针 <br> d0 - 张量第一维大小 <br> d1 - 张量第二维大小 <br> d2 - 张量第三维大小 <br> d3 - 张量第四维大小 <br> myDataType - 张量的数据类型 <br> myDevID - 张量所在的设备ID <br> myMem - 张量所使用的内存池 |
| 初始化为5维稠密张量 | void InitTensor5D(<br>XTensor * tensor, <br> const int d0, const int d1, const int d2, <br> const int d3, const int d4, <br> const TENSOR_DATA_TYPE myDataType = X_FLOAT, <br>const int myDevID = -1, XMem * myMem = NULL) <br> <br> <br> <br> | tensor - 指向被初始化张量的指针 <br> d0 - 张量第一维大小 <br> d1 - 张量第二维大小 <br> d2 - 张量第三维大小 <br> d3 - 张量第四维大小 <br> d4 - 张量第五维大小 <br> myDataType - 张量的数据类型 <br> myDevID - 张量所在的设备ID <br> myMem - 张量所使用的内存池 |
| 创建稠密向量 | XTensor * NewTensor1D(<br>const int num, <br> const TENSOR_DATA_TYPE myDataType = X_FLOAT, <br>const int myDevID = -1, XMem * myMem = NULL) <br> | num - 向量维度大小 <br> myDataType - 张量的数据类型 <br> myDevID - 张量所在的设备ID <br> myMem - 张量所使用的内存池 |
| 创建稠密矩阵 | XTensor * NewTensor2D(<br>const int colNum, const int rowNum, <br> const TENSOR_DATA_TYPE myDataType = X_FLOAT, <br>const int myDevID = -1, XMem * myMem = NULL) <br> <br> | colNum - 矩阵列数 <br> rowNum - 矩阵行数 <br> myDataType - 张量的数据类型 <br> myDevID - 张量所在的设备ID <br> myMem - 张量所使用的内存池 |
| 创建3维稠密张量 | XTensor * NewTensor3D(<br> const int d0, const int d1, const int d2, <br> const TENSOR_DATA_TYPE myDataType = X_FLOAT, <br>const int myDevID = -1, XMem * myMem = NULL) <br> <br> <br> | d0 - 张量第一维大小 <br> d1 - 张量第二维大小 <br> d2 - 张量第三维大小 <br> myDataType - 张量的数据类型 <br> myDevID - 张量所在的设备ID <br> myMem - 张量所使用的内存池 |
| 创建4维稠密张量 | XTensor * NewTensor4D(<br>const int d0, const int d1, const int d2, const int d3, <br> const TENSOR_DATA_TYPE myDataType = X_FLOAT, <br>const int myDevID = -1, XMem * myMem = NULL) <br> <br> <br> <br> | d0 - 张量第一维大小 <br> d1 - 张量第二维大小 <br> d2 - 张量第三维大小 <br> d3 - 张量第四维大小 <br> myDataType - 张量的数据类型 <br> myDevID - 张量所在的设备ID <br> myMem - 张量所使用的内存池 |
| 创建5维稠密张量 | XTensor * NewTensor5D(<br>const int d0, const int d1, const int d2, <br> const int d3, const int d4, <br> const TENSOR_DATA_TYPE myDataType = X_FLOAT, <br>const int myDevID = -1, XMem * myMem = NULL) <br> <br> <br> <br> | d0 - 张量第一维大小 <br> d1 - 张量第二维大小 <br> d2 - 张量第三维大小 <br> d3 - 张量第四维大小 <br> d4 - 张量第五维大小 <br> myDataType - 张量的数据类型 <br> myDevID - 张量所在的设备ID <br> myMem - 张量所使用的内存池 |
## 设备
## 访问张量中的内容
在C/C++中,我们通过XTensor.h访问张量中的内容,并且仅需要在源程序中引用XTensor.h头文件就可以完成张量的定义。
在XTensor.h头文件中定义的成员变量说明:
| 成员变量 | 功能 |
| -: | - |
| XMem * mem | 张量所使用的内存池 |
| void * data | 保存元素的数据数组 |
| void * dataHost | 主机内存上的数据副本,只在GPU上运行时被激活 |
| int devID | 设备ID,指张量所申请的空间所在CPU或者GPU设备的编号,-1表示CPU |
| int order | 张量的维度,例如:一个矩阵(维度为2)是一个二维张量 |
| int dimSize<br> [MAX_TENSOR_DIM_NUM] | 张量中每一维度的大小,索引0表示第1维 |
| int dimSizeRDI<br> [MAX_TENSOR_DIM_NUM] | 转置模式下张量中每一维度的大小,索引0表示第1维 |
| TENSOR_DATA_TYPE dataType | 每个数据单元的数据类型 |
| int unitSize | 数据单元的大小,类似于sizeof() |
| int unitNum | 数据单元的数量 |
| bool isSparse | 是否稠密,一个n * m稠密矩阵的数据量大小为n * m,而稀疏(非稠密)矩阵的数据量大小则取决于矩阵中非零元素个数。|
| int unitNumNonZero | 稀疏矩阵中非零元素个数 |
| float denseRatio | 稠密度,指非零单元的比例,是介于0和1之间的一个实数,0表示所有单元全为零,1表示全为非零单元。|
| bool isShared | 标志数据数组是否被其他张量所共享 |
| bool isInGlobalMem | 标志数据是否在全局内存而不是内存池中 |
| bool isAllValued<br> [MAX_TENSOR_DIM_NUM] | 标志稀疏矩阵中是否每个维度都具有非零元素 |
在XTensor.h头文件中定义的方法说明:
| 功能 | 函数 | 参数 |
| -: | - | - |
| 判断两个张量数据类型和大小是否相同 | static bool IsIdentical(<br> XTensor * a, XTensor * b) | a - 进行比较的第一个张量 <br> b - 进行比较的第二个张量 |
| 判断三个张量数据类型和大小是否相同 | static bool IsIdentical(<br> XTensor * a, XTensor * b, XTensor * c) | a - 进行比较的第一个张量 <br> b - 进行比较的第二个张量 <br> c - 进行比较的第三个张量 |
| 设置张量每一维度的大小 | void SetDim(int * myDimSize) |myDimSize - 张量每一维度的大小 |
| 得到张量中给定的维度大小 | int GetDim(const int dim) | dim - 张量的维度 |
| 重新调整矩阵维度 | void Reshape(<br> const int order, const int * myDimSize) | order - 张量的维度 <br> myDimSize - 张量每一维的大小 |
| 得到张量中元素数量 | int GetSize() | N/A |
| 得到内存使用大小 | int GetDataSizeInChar() | N/A |
| 得到所给数据类型的数据<br> 单元大小 | int GetUnitSize(<br> TENSOR_DATA_TYPE myDataType) | myDataType - 所给数据类型 |
| 张量中所有元素设置为0 | void SetZeroAll(XStream * stream = NULL) | stream - ???流|
| 用数组赋值张量 | void SetData(<br> const void * d, int num, int beg = 0) | d - 赋值数组 <br> num - 数组大小 <br> beg - 赋值时从张量的第几位开始 |
| 设置张量服从均匀分布 | void SetDataRand(<br> DTYPE lower, DTYPE upper) | lower - 最小值 <br> upper - 最大值 |
| 设置张量服从正态分布 | void SetDataRandn(<br> DTYPE mean, DTYPE standardDeviation) | mean - 均值 <br> standardDeviation - 标准差 |
| 检查张量中元素是否相同 | bool CheckData(<br> const void * answer, int num, int beg = 0) | answer - 给定数组 <br> num - 数组大小 <br> beg - 赋值时从张量的第几位开始 |
| 将给定维度中元素<br> 设置为升序 | void SetAscendingOrder(int dim) | dim - 给定维度 |
| 获取张量中元素指针 | void * GetCell(int * index, int size) | index - 元素位置 <br> size-矩阵大小 |
| 获取二维张量中元素指针 | void * GetCell2D(int ni, int mi = 0) | ni - 行值 <br> mi - 列值 |
| 获取二维张量的值 |
| 获取稀疏张量的值 | DTYPE GetInSparse(int i) | i - 稀疏矩阵中非0元素位置 |
| 获取稀疏张量中<br> 元组的键值 | int GetKeyInSparse(int i) | i - 稀疏矩阵中非0元素位置 |
| 设置二维张量中<br> 的单元值 | bool Set2D(DTYPE value, int ni, int mi = 0) | value - 单元值 <br> ni - 行值 <br> mi - 列值 |
| 增加二维张量中<br> 的单元值 | bool Add2D(DTYPE value, int ni, int mi = 0) | value - 单元值 <br> ni - 行值 <br> mi - 列值 |
| 获取稀疏矩阵中<br> 非零元素数量 | int GetNonzeroSize() | N/A |
| 将矩阵重置为特定大小 | bool Resize(<br> const int myOrder, <br> const int * myDimSize, <br> const TENSOR_DATA_TYPE myDataType = DEFAULT_DTYPE, <br> const float myDenseRatio = 1.0F) | myOrder - 张量的维度 <br> myDimSize - 张量每一维的大小,索引0表示第一维 <br> myDataType - 张量的数据类型 <br> myDenseRatio - 张量的稠密度,1表示稠密张量 |
| 将矩阵重置为特定大小并不申请新空间 | bool ResizeWithNoData(<br> const int myOrder, <br> const int * myDimSize, <br> const TENSOR_DATA_TYPE myDataType = DEFAULT_DTYPE, <br> const float myDenseRatio = 1.0F) | myOrder - 张量的维度 <br> myDimSize - 张量每一维的大小,索引0表示第一维 <br> myDataType - 张量的数据类型 <br> myDenseRatio - 张量的稠密度,1表示稠密张量 |
| 将矩阵重置为<br> 另一矩阵大小 | bool Resize(<br> const XTensor * myTensor) | myTensor - 重置矩阵大小的参考矩阵 |
| 用二值搜索方法<br> 找到稀疏矩阵中元素 | bool BinarySearch(<br> int key, DTYPE &value, void * &position) | key - 稀疏矩阵中元素位置 <br> value - 元素值 <br> position - 元素坐标位置 |
| 将数据刷新到<br> 目标设备中 | void FlushToMem(XMem * targetMem) | targetMem - 目标设备 |
| 在全局内存中<br> 申请矩阵的内存空间 | static void AllocateData(<br> XTensor * matrix, <br> XMem * myMem = NULL, <br> bool useBuf = false) | matrix - 申请内存空间的矩阵 <br> myMem - 是否在内存池中申请空间 <br> useBuf - 是否使用缓冲区 |
| 在全局内存中<br> 释放矩阵的内存空间 | static void FreeData(<br> XTensor * matrix, <br> XMem * myMem = NULL, <br> bool useBuf = false) | matrix - 申请内存空间的矩阵 <br> myMem - 是否在内存池中申请空间 <br> useBuf - 是否使用缓冲区 |
| 在缓冲区创建张量 | XTensor * NewTensorBuf( <br> const int myOrder, <br> const int * myDimSize, XMem * myMem, <br> const TENSOR_DATA_TYPE myDataType = <br> X_FLOAT, const float myDenseRatio = 1.0F) | myOrder - 张量的维度 <br> myDimSize - 张量每一维的大小,索引0表示第一维 <br> myMem - 张量所使用的内存池 <br> myDataType - 张量的数据类型 <br> myDenseRatio - 张量的稠密度,1表示稠密张量 |
| 依据给定张量<br>复制一个新的张量 | XTensor * NewTensor(<br>XTensor * a, bool isFilledData = true) | a - 给定张量 <br> isFilledData - 是否申请张量中的数据空间 |
| 依据给定张量<br>释放数据空间 | void DelTensor(<br>const XTensor * tensor) | tensor - 给定张量 |
| 依据给定张量<br>在缓存中释放数据空间 | void DelTensorBuf(<br>const XTensor * tensor) | tensor - 给定张量 |
## 张量计算
NiuTrans.Tensor提供关于张量计算的函数功能,主要包括一些基本的张量运算以及激活函数,在本节中,主要对这些函数及其用法用例进行介绍。
### 加法(Sum)
#### 什么是张量加法?
张量加法的目的是将n个张量相加得到一个新的结果张量,结果张量某一位置的元素数值为进行操作的张量在该位置上元素的求和,在张量加法的计算过程中进行操作的张量与结果张量的维度相同,两个维度为\\(2\times 3\\)的张量相加过程如下所示:
$$
\left(\begin{matrix}0.0 & 1.0 & 2.0 \\\\ 3.0 & 4.0 & 5.0\end{matrix}\right) +
\left(\begin{matrix}0.5 & 1.5 & 2.5 \\\\ 3.5 & 4.5 & 5.5\end{matrix}\right) ->
\left(\begin{matrix}0.5 & 2.5 & 4.5 \\\\ 6.5 & 8.5 & 10.5\end{matrix}\right)
$$
#### 张量加法的调用
NiuTrans.Tensor提供了张量加法的计算操作,在NiuTrans.Tensor/Tensor/core中定义,该操作用来进行张量之间的按元素位置相加,并得到相加的结果张量,张量加法的调用方法为:Sum(XTensor * a, XTensor * b, XTensor * c, DTYPE beta),其中a和b为输入张量,c为结果张量,若c为NULL则将相加结果存入a中,beta为一个缩放参数,缩放公式为:c = a + b * beta,beta默认为1.0,NiuTrans.Tensor中张量加法的调用方式以及参数说明如下表所示:
| 功能 | 函数 | 参数 |
| -: | - | - |
| 张量加法 | void Sum(<br>XTensor * a, XTensor * b, XTensor * c, DTYPE beta) | a - 操作张量1 <br> b - 操作张量2 <br> c - 结果张量,如果c为空则将结果存入a <br> beta - 缩放参数 |
#### 张量加法片段示例
调用Sum进行张量间的求和操作如下所示:
```
/* call sum function */
Sum(a, b);
```
详细代码示例见NiuTrans.Tensor/Tensor/test/TSum.cpp
### 矩阵乘法(MatrixMul)
#### 什么是张量间矩阵乘法?
利用矩阵乘法可以将矩阵想乘并得到一个新的结果矩阵,两个维度分别为\\(2 \times 3\\)和\\(3 \times 2\\)的矩阵相乘过程如下所示,结果矩阵的维度为\\(2 \times 2\\):
$$
\left(\begin{matrix}1.0 & 2.0 & 3.0\\\\-4.0 & 5.0 & 6.0\end{matrix}\right) ×
\left(\begin{matrix}0.0 & -1.0\\\\1.0 & 2.0\\\\2.0 & 1.0\end{matrix}\right) ->
\left(\begin{matrix}8.0 & 6.0\\\\17.0 & 20.0\end{matrix}\right)
$$
#### 矩阵乘法的调用
NiuTrans.Tensor提供了矩阵乘法的计算操作,在NiuTrans.Tensor/Tensor/core中定义,矩阵乘法的调用方式以及参数说明如下表所示:
| 功能 | 函数 | 参数 |
| -: | - | - |
| 乘法 | void MatrixMul(<br>XTensor * a, MATRIX_TRANS_TYPE transposedA,<br>XTensor * b, MATRIX_TRANS_TYPE transposedB,<br>XTensor * c, DTYPE alpha, DTYPE beta,<br>XPRunner * parallelRunner) | a - 操作张量1 <br> transposedA - 操作张量1是否进行转置 <br> b - 操作张量2 <br> transposedB - 操作张量2是否进行转置 <br> c - 操作张量3 <br> alpha - 系数 <br> beta - 系数 <br> parallelRunner - 并行处理模块 |
#### 矩阵乘法片段示例
我们以最基本的二维矩阵乘法为例,用MatrixMul进行矩阵乘法操作的示例代码为:
```
/* call MatrixMul function */
MatrixMul(s1, X_NOTRANS, s2, X_NOTRANS, t);
```
有关矩阵乘法的详细代码示例见NiuTrans.Tensor/Tensor/test/TMatrixMul.cpp、NiuTrans.Tensor/Tensor/test/TMatrixMul2D.cpp、NiuTrans.Tensor/Tensor/test/TMatrixMulBatchedCPU.cpp
### 点乘(MultiplyElementWise)
#### 什么是张量点乘?
利用张量间的点乘操作可以进行张量间元素的按位置依次相乘,两个维度分别为\\(2 \times 2\\)的张量点乘过程如下所示:
$$
\left(\begin{matrix}0.0 & 1.0\\\\2.0 & 3.0\end{matrix}\right) ·
\left(\begin{matrix}0.0 & 1.0\\\\2.0 & 3.0\end{matrix}\right) ->
\left(\begin{matrix}0.0 & 1.0\\\\4.0 & 9.0\end{matrix}\right)
$$
#### 张量点乘的调用
NiuTrans.Tensor提供了张量点乘的计算操作,用来计算张量中元素点乘结果,该函数在NiuTrans.Tensor/Tensor/core中定义,张量点乘的调用方式以及参数说明如下表所示:
| 功能 | 函数 | 参数 |
| -: | - | - |
| 点乘 | MultiplyElementWise(<br>XTensor * a, XTensor * b, <br>XTensor * c, int leadingDim, DTYPE alpha) | a - 操作张量1 <br> b - 操作张量2 <br> c - 结果张量 <br> leadingDim - ??? <br>alpha - 系数 |
#### 张量点乘片段示例
用MultiplyElementWise进行s1和s2张量间的点乘操作的调用示例如下所示,计算结果存入t中:
```
/* call multiplyelementwise function */
MultiplyElementWise(s1, s2, t, 0);
```
有关矩阵乘法的详细代码示例见NiuTrans.Tensor/Tensor/test/TMultiplyElementWise.cpp
### 取负(Negate)
#### 什么是张量的取负操作?
在进行张量的取负操作时,张量中每一元素都进行取负得到新的元素,所有新元素的组合得到新的结果张量,一个维度为\\(3 \times 2\\)的张量取负操作过程如下所示:
$$
\left(\begin{matrix}1.0 & -2.0\\\\-3.0 & 4.0\\\\5.0 & -6.0\end{matrix}\right) ->
\left(\begin{matrix}-1.0 & 2.0\\\\3.0 & -4.0\\\\-5.0 & 6.0\end{matrix}\right)
$$
#### 张量取负的调用
NiuTrans.Tensor提供了张量取负的计算操作,进行张量的按元素位置进行取负操作,该函数在NiuTrans.Tensor/Tensor/core中定义,调用方法为:Negate(XTensor * a),张量取负的调用方式以及参数说明如下表所示:
| 功能 | 函数 | 参数 |
| -: | - | - |
| 取负 | void Negate(<br>XTensor * a) | a - 操作张量 |
#### 张量点乘片段示例
用Negate进行张量取负操作的调用示例如下所示,其中a为我们要进行处理的张量:
```
/* call negate function */
Negate(a);
```
有关张量取负的详细代码示例见NiuTrans.Tensor/Tensor/test/TNegate.cpp
### 幂运算(Power)
#### 什么是张量的幂运算操作?
幂运算是一种关于幂的数学运算,张量的幂运算是将张量中的每个元素都进行幂运算从而得到新的张量,一个维度为\\(3 \times 2\\)的幂为2.0的张量幂运算过程如下所示:
$$
\left(\begin{matrix}1.0 & 2.0\\\\3.0 & 4.0\\\\5.0 & 6.0\end{matrix}\right) ->
\left(\begin{matrix}1.0 & 4.0\\\\9.0 & 16.0\\\\25.0 & 36.0\end{matrix}\right)
$$
#### 张量幂运算的调用
NiuTrans.Tensor提供了张量幂运算的操作,用来进行张量的按元素位置进行幂运算的操作,调用方法为:Power(XTensor * a, DTYPE p),其中a为进行操作的张量,p为次方数,张量幂运算的调用方式以及参数说明如下表所示:
| 功能 | 函数 | 参数 |
| -: | - | - |
| 幂运算 | void Power(<br>XTensor * a, DTYPE p) | a - 操作张量 <br> p - 次方数 |
#### 张量幂运算片段示例
下面是调用Power进行a的幂为2.0的幂运算操作的一段示例代码:
```
/* call power function */
Power(a, 2.0);
```
有关张量幂运算的详细代码示例见NiuTrans.Tensor/Tensor/test/TPower.cpp
### 级联(Concatenate)
#### 什么是张量的级联操作?
张量间的级联操作是沿着张量的某一维度,将一系列张量或是一个列表中的所有张量连接在一起组成一个更大的张量,将维度分别为\\(2 \times 1\\)和\\(2 \times 2\\)的两个张量进行级联过程如下所示:
$$
\left(\begin{matrix}0.0\\\\1.0\end{matrix}\right) +
\left(\begin{matrix}2.0 & 3.0\\\\4.0 & 5.0\end{matrix}\right) ->
\left(\begin{matrix}0.0 & 2.0 & 3.0\\\\1.0 & 4.0 & 5.0\end{matrix}\right)
$$
#### 张量级联的调用
NiuTrans.Tensor提供了张量间的级联操作,调用方法为:
Concatenate(XList * smalls, XTensor * big, int dim)和Concatenate(XTensor * smallA, XTensor * smallB, XTensor * big, int dim)。
第一种调用方法中的操作对象是列表,将进行级联操作的张量存入列表smalls中,级联结果存入张量big中;第二种方法操作对象不再是列表中的张量而是直接对一系列张量进行级联操作,两种张量级联的调用方式以及参数说明如下表所示:
| 功能 | 函数 | 参数 |
| -: | - | - |
| 级联 | void Concatenate(<br>XList * smalls, XTensor * big, int dim) | smalls - 进行级联张量的列表 <br> big - 结果张量 <br> dim - 在指定维度进行级联 |
| 级联 | void Concatenate(<br>XTensor * smallA, XTensor * smallB, <br> XTensor * big, int dim) | smallA - 操作张量1 <br> smallB - 操作张量2 <br> big - 结果张量 <br> dim - 进行级联的维度 |
#### 张量级联片段示例
通过操作张量列表进行张量的级联操作片段示例如下所示,sList为存放进行级联张量的列表,t为结果张量:
```
/* call concatenate function */
Concatenate(&sList, t, 1);
```
直接通过操作一系列张量进行张量的级联操作片段示例如下所示,s1、s2为需要进行级联的张量,t为结果张量:
```
/* call concatenate function */
Concatenate(s1, s2, t, 1);
```
有关张量级联的详细代码示例见NiuTrans.Tensor/Tensor/test/TConcatenate.cpp
### 切分(Split)
#### 什么是张量的切分操作?
张量间的切分操作是沿着张量的某一维度,可以将一个张量切分成另一张量,也可以将一个大的张量切分成n个小的张量集合的列表。
第一种情况下将维度为\\(4 \times 3\\)张量沿着维度0进行切分,切分份数为2,得到维度为\\(2 \times 2 \times 3\\)的张量的过程如下所示:
$$
\left(\begin{matrix}0.0 & 1.0 & 2.0\\\\3.0 & 4.0 & 5.0\\\\0.1 & 1.1 & 2.1\\\\3.1 & 4.1 & 5.1\end{matrix}\right) ->
\begin{aligned}
\Biggl( & \left(
\begin{matrix}0.0 & 1.0 & 2.0\\\\3.0 & 4.0 & 5.0\end{matrix}\right),
\\\\ & \left(
\begin{matrix}0.1 & 1.1 & 2.1\\\\3.1 & 4.1 & 5.1\end{matrix}
\right) \Biggr)
\end{aligned}
$$
在第二种情况下将维度为\\(4 \times 3\\)张量沿着维度0进行切分,切分份数为2,得到两个维度均为\\(2 \times 3\\)的张量的过程如下所示:
$$
\left(\begin{matrix}0.0 & 1.0 & 2.0\\\\3.0 & 4.0 & 5.0\\\\0.1 & 1.1 & 2.1\\\\3.1 & 4.1 & 5.1\end{matrix}\right) ->
\left(\begin{matrix}0.0 & 2.0 & 3.0\\\\1.0 & 4.0 & 5.0\end{matrix}\right) + \left(\begin{matrix}0.1 & 1.1 & 2.1\\\\3.1 & 4.1 & 5.1\end{matrix}\right)
$$
#### 张量切分的调用
NiuTrans.Tensor提供了两种张量切分操作,调用方法为:
Split(XTensor * s, XTensor * t, int whereToSplit, int splitNum)和Split(XTensor * big, XList * smalls, int whereToSplit, int splitNum)
在第一种调用方法中是将源张量中的某一维度进行Split操作,Split结果为张量t,whereToSplit为在哪一维度进行split操作,splitNum表示分成多少份,例如:(N, M) -> (N/3, M, 3)
在第二种调用方法中是将所操作张量big按某一维度whereToSplit进行Split操作,操作结果为包含若干更小维度张量的列表smalls,splitNum表示分成多少份,例如:(N, M) -> 2 * (N/2, M)
两种张量级联的调用方式以及参数说明如下表所示:
| 功能 | 函数 | 参数 |
| -: | - | - |
| 切分 | void Split(<br>XTensor * s, XTensor * t, <br>int whereToSplit, int splitNum) | s - 操作张量 <br> t - 结果张量 <br> whereToSplit - 在指定维度进行split操作 <br> splitNum - 分成多少份 |
| 切分 | void Split(<br>XTensor * big, XList * smalls, <br>int whereToSplit, int splitNum) | big - 操作张量 <br> smalls - 存放切分出张量的列表 <br> whereToSplit - 在指定维度进行split操作 <br> splitNum - 分成多少份 |
#### 张量切分片段示例
上述第一种张量切分片段示例如下所示,s为进行切分的张量,t为结果张量,0表示沿着第0维进行切分操作,2表示切分份数为2:
```
/* call split function */
Split(s, t, 0, 2);
```
上述第二种张量切分片段示例如下所示,s为进行切分的张量,tList为存放结果张量的列表,1表示沿着第1维进行切分操作,2表示切分份数为2:
```
/* call split function */
Split(s, &tList, 1, 2);
```
有关张量切分的详细代码示例见NiuTrans.Tensor/Tensor/test/TSplit.cpp
### 合并(Merge)
#### 什么是张量的合并操作?
张量间的合并操作与级联有些类似,是沿着张量的某一维度,可以将一个张量合并为另一个维度不同的张量,也可以将一个列表中的所有张量合并在一起组成一个更大的张量。
在第一种情况下将维度为\\(2 \times 2 \times 3\\)的张量在维度1进行合并,进行合并的维度为0,得到维度为\\(4 \times 3\\)的张量的过程如下所示:
$$
\begin{aligned}
\Biggl( & \left(
\begin{matrix}0.0 & 1.0 & 2.0\\\\3.0 & 4.0 & 5.0\end{matrix}\right),
\\\\ & \left(
\begin{matrix}0.1 & 1.1 & 2.1\\\\3.1 & 4.1 & 5.1\end{matrix}
\right) \Biggr)
\end{aligned} ->
\left(\begin{matrix}0.0 & 1.0 & 2.0\\\\3.0 & 4.0 & 5.0\\\\0.1 & 1.1 & 2.1\\\\3.1 & 4.1 & 5.1\end{matrix}\right)
$$
在第二种情况下将两个维度均为\\(2 \times 3\\)的张量沿着第0维合并为维度为\\(4 \times 3\\)的张量的过程如下所示:
$$
\left(\begin{matrix}0.0 & 2.0 & 3.0\\\\1.0 & 4.0 & 5.0\end{matrix}\right) + \left(\begin{matrix}0.1 & 1.1 & 2.1\\\\3.1 & 4.1 & 5.1\end{matrix}\right) ->
\left(\begin{matrix}0.0 & 1.0 & 2.0\\\\3.0 & 4.0 & 5.0\\\\0.1 & 1.1 & 2.1\\\\3.1 & 4.1 & 5.1\end{matrix}\right)
$$
#### 张量合并操作的调用
NiuTrans.Tensor提供了张量的合并操作,调用方法为:
Merge(XTensor * s, XTensor * t, int whereToMerge, int leadingDim)和Merge(XList * smalls, XTensor * big, int whereToMerge)
在第一种调用方法中是将源张量中的某一维度进行Merge操作,Merge结果为张量t,whereToMerge为指定进行Merge操作的维度,leadingDim为指定将哪一维度Merge,例如:(N/2, 2, M) -> (N, M)
在第二种调用方法中是将所操作张量存入列表smalls中,操作结果为张量big,whereToMerge为指定进行Merge操作的维度,例如:2 * (N/2, M) -> (N, M)。
两种张量合并操作的调用方式以及参数说明如下表所示:
| 功能 | 函数 | 参数 |
| -: | - | - |
| 合并 | void Merge(<br>XTensor * s, XTensor * t, <br>int whereToMerge, int leadingDim) | s - 操作张量 <br> t - 结果张量 <br> whereToMerge - 沿着指定维度进行Merge操作 <br> leadingDim - 把指定维度进行Merge操作 |
| 合并 | void Merge(<br>XList * smalls, XTensor * big, <br>int whereToMerge) | smalls - 存放进行合并张量的列表 <br> big - 结果张量 <br> whereToMerge - 沿着指定维度进行Merge操作 |
#### 张量合并片段示例
上述第一种张量合并片段示例如下所示,s为进行合并的张量,t为结果张量,1表示在第1维进行合并操作,0表示将第0维进行合并操作:
```
/* call merge function */
Merge(s, t, 1, 0);
```
上述第二种张量合并片段示例如下所示,sList为要进行合并的张量列表,t为结果张量,0表示沿着第0维进行合并操作:
```
/* call merge function */
Merge(&sList, t, 0);
```
有关张量合并的详细代码示例见NiuTrans.Tensor/Tensor/test/TMerge.cpp
### 归约取最大值(ReduceMax)
#### 什么是张量的归约取最大值?
张量的归约取最大值操作是沿着张量的某一维度,取得该向量在该维度中的最大值,一个\\(2 \times 4\\)的张量在第0维和第1维进行取最大值操作的过程分别如下所示:
$$
\left(\begin{matrix}0.0 & 1.0 & 2.0 & 3.0\\\\4.0 & 5.0 & 6.0 & 7.0\end{matrix}\right) ->
\left(\begin{matrix}4.0 & 5.0 & 6.0 & 7.0\end{matrix}\right)
$$
$$
\left(\begin{matrix}0.0 & 1.0 & 2.0 & 3.0\\\\4.0 & 5.0 & 6.0 & 7.0\end{matrix}\right) ->
\left(\begin{matrix}3.0\\\\7.0\end{matrix}\right)
$$
#### 张量归约取最大值操作的调用
NiuTrans.Tensor提供了张量的ReduceMax操作,用来获得张量中沿指定维度取得的最大值,张量归约取最大值操作的调用方式以及参数说明如下表所示:
| 功能 | 函数 | 参数 |
| -: | - | - |
| 归约取最大值 | void ReduceMax(<br>XTensor * input, <br>XTensor * output, int dim) | input - 输入张量 <br> output - 输出张量 <br> dim - 沿着指定维度进行取最大值操作 |
#### 张量归约取最大值片段示例
调用ReduceMax进行张量归约取最大值操作的示例代码如下所示,代码中两行分别表示沿着第0维和第1维进行取值:
```
/* call reduce max function */
ReduceMax(a, reduce_a, 0);
ReduceMax(b, reduce_b, 1);
```
有关张量归约取最大值的详细代码示例见NiuTrans.Tensor/Tensor/test/TReduceMax.cpp
### 归约求和(ReduceSum)
#### 什么是张量的归约求和操作?
张量的归约求和操作是沿着张量的某一维度,计算该张量在该维度的和,一个\\(2 \times 4\\)的张量在第0维和第1维进行求和操作的过程分别如下所示:
$$
\left(\begin{matrix}0.0 & 1.0 & 2.0 & 3.0\\\\4.0 & 5.0 & 6.0 & 7.0\end{matrix}\right) ->
\left(\begin{matrix}4.0 & 6.0 & 8.0 & 10.0\end{matrix}\right)
$$
$$
\left(\begin{matrix}0.0 & 1.0 & 2.0 & 3.0\\\\4.0 & 5.0 & 6.0 & 7.0\end{matrix}\right) ->
\left(\begin{matrix}6.0\\\\22.0\end{matrix}\right)
$$
#### 张量归约求和操作的调用
NiuTrans.Tensor提供了张量的ReduceSum操作,调用方法为:ReduceSum(XTensor * input, XTensor * output, int dim, XTensor * shift, DTYPE power, bool isExp),shift默认为NULL,power默认为1.0F,isExp默认为false,张量归约求和操作的调用方式以及参数说明如下表所示:
| 功能 | 函数 | 参数 |
| -: | - | - |
| 归约求和 | void ReduceSum(<br>XTensor * input, XTensor * output, <br>int dim, XTensor * shift, DTYPE power, bool isExp) | input - 输入张量 <br> output - 输出张量 <br> dim - 沿着指定维度进行取最大值操作 <br> shift - 输入的偏移,默认为NULL <br> power - 元素的幂,默认为1.0F <br> isExp - 是否取指,默认为false |
#### 张量归约求和片段示例
调用ReduceSum进行张量归约求和操作的示例代码如下所示,代码中两行分别表示沿着第0维和第1维进行取值:
```
/* call reduce sum function */
ReduceSum(a, reduce_a, 0);
ReduceSum(b, reduce_b, 1);
```
有关张量归约求和的详细代码示例见NiuTrans.Tensor/Tensor/test/TReduceSum.cpp
### 归约取均值(ReduceMean)
#### 什么是张量的归约取均值操作?
张量的归约取均值操作是沿着张量的某一维度,计算该张量在该维度的均值,一个\\(2 \times 4\\)的张量在第0维和第1维进行取均值操作的过程分别如下所示:
$$
\left(\begin{matrix}0.0 & 1.0 & 2.0 & 3.0\\\\4.0 & 5.0 & 6.0 & 7.0\end{matrix}\right) ->
\left(\begin{matrix}2.0 & 3.0 & 4.0 & 5.0\end{matrix}\right)
$$
$$
\left(\begin{matrix}1.0 & 1.0 & 3.0 & 3.0\\\\4.0 & 4.0 & 6.0 & 6.0\end{matrix}\right) ->
\left(\begin{matrix}2.0\\\\5.0\end{matrix}\right)
$$
#### 张量归约取均值操作的调用
NiuTrans.Tensor提供了张量的ReduceMean操作,调用方法为:ReduceMean(XTensor * input, XTensor * output, int dim),用来获得张量中沿指定维度取得的数值均值,张量归约取均值操作的调用方式以及参数说明如下表所示:
| 功能 | 函数 | 参数 |
| -: | - | - |
| 归约取均值 | void ReduceMean(<br>XTensor * input, XTensor * output, int dim) | input - 输入张量 <br> output - 输出张量 <br> dim - 沿着指定维度进行取平均值操作 |
#### 张量归约取均值片段示例
调用ReduceMean进行张量归约取均值操作的示例代码如下所示,代码中两行分别表示沿着第0维和第1维进行取值:
```
/* call reduce mean function */
ReduceMean(a, reduce_a, 0);
ReduceMean(b, reduce_b, 1);
```
有关张量归约取均值的详细代码示例见NiuTrans.Tensor/Tensor/test/TReduceMean.cpp
### 归约取方差(ReduceSumSquared)
#### 什么是张量的归约取方差操作?
张量的归约取方差操作是沿着张量的某一维度,计算该张量在该维度的方差,一个\\(2 \times 4\\)的张量在第0维进行取方差操作的过程如下所示:
$$
\left(\begin{matrix}0.0 & 1.0 & 2.0 & 3.0\\\\4.0 & 5.0 & 6.0 & 7.0\end{matrix}\right) ->
\left(\begin{matrix}8.0 & 8.0 & 8.0 & 8.0\end{matrix}\right)
$$
#### 张量归约取方差操作的调用
NiuTrans.Tensor提供了张量的ReduceSumSquared操作,调用方法为:ReduceSumSquared(XTensor * input, XTensor * output, int dim, XTensor * shift),用来计算张量的沿着某一维度元素的方差,张量归约取方差操作的调用方式以及参数说明如下表所示:
| 功能 | 函数 | 参数 |
| -: | - | - |
| 归约取方差 | void ReduceSumSquared(<br>XTensor * input, XTensor * output, <br>int dim, XTensor * shift) | input - 输入张量 <br> output - 输出张量 <br> dim - 沿着指定维度进行取平均值操作 <br> shift - 输入的偏移 |
#### 张量归约取方差片段示例
调用ReduceSumSquared进行张量归约取方差操作的示例代码如下所示:
```
/* call reduce sum squared function */
ReduceSumSquared(input, output, 0, shift);
```
有关张量归约取方差的详细代码示例见NiuTrans.Tensor/Tensor/test/TReduceSumSquared.cpp
### 归约取标准差(ReduceVariance)
#### 什么是张量的归约取标准差操作?
张量的归约取标准差操作是沿着张量的某一维度,计算该张量在该维度的标准差,一个\\(2 \times 4\\)的张量在第0维进行取标准差操作的过程如下所示:
$$
\left(\begin{matrix}0.0 & 1.0 & 2.0 & 3.0\\\\4.0 & 5.0 & 6.0 & 7.0\end{matrix}\right) ->
\left(\begin{matrix}4.0 & 4.0 & 4.0 & 4.0\end{matrix}\right)
$$
#### 张量归约取标准差操作的调用
NiuTrans.Tensor提供了张量的ReduceVariance操作,调用方法为:ReduceVariance(XTensor * input, XTensor * output, int dim, XTensor * mean),用来计算张量的沿着某一维度元素的标准差,张量归约取标准差操作的调用方式以及参数说明如下表所示:
| 功能 | 函数 | 参数 |
| -: | - | - |
| 归约取标准差 | void ReduceVariance(<br>XTensor * input, XTensor * output, <br>int dim, XTensor * mean) | input - 输入张量 <br> output - 输出张量 <br> dim - 沿着指定维度进行取标准差操作 <br> mean - 均值 |
#### 张量归约取标准差片段示例
调用ReduceVariance进行张量归约取标准差操作的示例代码如下所示:
```
/* call reduce variance function */
ReduceVariance(input, output, 0, mean);
```
有关张量归约取标准差的详细代码示例见NiuTrans.Tensor/Tensor/test/TReduceVariance.cpp
### 缩放和偏移(Scale and Shift)
#### 什么是张量的缩放和偏移?
张量的缩放和偏移计算公式为:p = p * scale + shift,其中scale和shift分别为张量缩放和偏移的参数,一个\\(2 \times 4\\)的张量进行缩放和偏移的过程如下所示,缩放参数取2.0,偏移参数取0.5:
$$
\left(\begin{matrix}0.0 & 1.0 & 2.0 & 3.0\\\\4.0 & 5.0 & 6.0 & 7.0\end{matrix}\right) ->
\left(\begin{matrix}0.5 & 2.5 & 4.5 & 6.5\\\\8.5 & 10.5 & 12.5 & 14.5\end{matrix}\right)
$$
#### 张量缩放和偏移的调用
NiuTrans.Tensor提供了张量的缩放和偏移操作,调用方法为:ScaleAndShift(XTensor * a, DTYPE scale, DTYPE shift),操作结果为:p = p * scale + shift,其中scale和shift分别为张量的缩放和偏移参数,张量缩放和偏移操作的调用方式以及参数说明如下表所示:
| 功能 | 函数 | 参数 |
| -: | - | - |
| 缩放和偏移 | void ScaleAndShift(<br>XTensor * a, DTYPE scale, DTYPE shift) | a - 输入张量 <br> scale - 缩放参数 <br> shift - 偏移参数 |
#### 张量缩放和偏移片段示例
张量缩放和偏移示例代码如下,input为输入的待操作张量,scaleFactor为缩放参数,shiftFactor为偏移参数:
```
/* call ScaleAndShift function */
ScaleAndShift(input, scaleFactor, shiftFactor);
```
有关张量缩放和偏移的详细代码示例见NiuTrans.Tensor/Tensor/test/TScaleAndShift.cpp
### TopK
#### 什么是TopK?
TopK操作是通过对张量中元素进行排序,得到最大或最小的k个元素值及其对应的索引值,在张量中,可以沿着某一维度进行TopK操作,一个\\(2 \times 4\\)的张量沿着第0维进行Top-2操作过程如下所示:
$$
\left(\begin{matrix}5.0 & 1.0 & 2.0 & 8.0\\\\4.0 & 3.0 & 7.0 & 6.0\end{matrix}\right) ->
\begin{aligned}
outputAnswer: & \left(
\begin{matrix}0.5 & 2.5 & 4.5 & 6.5\\\\8.5 & 10.5 & 12.5 & 14.5\end{matrix}\right)\\\\ +
\\\\ indexAnswer: & \left(
\begin{matrix}0 & 1 & 1 & 0\\\\1 & 0 & 0 & 1\end{matrix}\right)
\end{aligned}
$$
#### TopK的调用
NiuTrans.Tensor提供了张量的TopK操作,调用方法为:TopK(XTensor * a, XTensor * b, XTensor * index, int dim, int k),参数说明如下表所示:
| 功能 | 函数 | 参数 |
| -: | - | - |
| TopK | void TopK(<br>XTensor * a, XTensor * b, <br>XTensor * index, int dim, int k) | a - 输入张量 <br> b - 输出结果张量 <br> index - 输出结果索引 <br> dim - 沿着指定维度进行TopK操作 <br> k - TopK中k代表取最大的k个值 |
#### TopK片段示例
TopK示例代码如下,input为输入的待操作张量,output输出结果张量,index为输出结果索引,本例中沿着第0维取Top-2:
```
/* call TopK function */
int dim = 0;
int k = inputDimSize[dim];
TopK(input, outputA, indexA, dim, k);
```
有关TopK的详细代码示例见 NiuTrans.Tensor/Tensor/test/TTopK.cpp
### 赋值(CopyValues)
#### 什么是张量的赋值操作?
赋值,即将一个张量的值赋给另一个张量,也就是对张量进行拷贝操作,一个\\(2 \times 4\\)的张量赋值过程如下所示:
$$
\left(\begin{matrix}5.0 & 1.0 & 2.0 & 8.0\\\\4.0 & 3.0 & 7.0 & 6.0\end{matrix}\right) ->
\left(
\begin{matrix}5.0 & 1.0 & 2.0 & 8.0\\\\4.0 & 3.0 & 7.0 & 6.0\end{matrix}\right)
$$
#### 张量赋值操作的调用
NiuTrans.Tensor提供了张量的赋值操作,调用方法为:CopyValues(XTensor * s, XTensor * t, XStream * stream),参数说明如下表所示:
| 功能 | 函数 | 参数 |
| -: | - | - |
| 赋值 | bool CopyValues(<br>XTensor * s, XTensor * t, XStream * stream) | s - 输入张量 <br> t - 输出结果张量 <br> stream - 啥流??? |
#### 张量赋值片段示例
张量赋值示例代码如下,其中input为输入的待操作张量,output输出结果张量:
```
/* call CopyValues function */
CopyValues(input, output);
```
有关张量赋值的详细代码示例见 NiuTrans.Tensor/Tensor/test/TCopyValues.cpp、NiuTrans.Tensor/Tensor/test/TCopyInGrid.cpp、NiuTrans.Tensor/Tensor/test/TCopyIndexed.cpp、NiuTrans.Tensor/Tensor/test/TCopyData2D.cpp、NiuTrans.Tensor/Tensor/test/TCopyBlocksOnSite.cpp、NiuTrans.Tensor/Tensor/test/TCopyBlocksInGrid.cpp、NiuTrans.Tensor/Tensor/test/TCopyBlocks.cpp
### Unsqueeze
#### 什么是Unsqueeze?
Unsqueeze的作用是通过对张量进行操作,返回一个新的在指定维度插入新维度的张量,这个返回的张量与源张量共享相同的基础数据,一个\\(2 \times 3\\)的张量在维度1和2分别进行Unsqueeze的操作如下所示,插入新的维度大小均为2:
$$
\left(\begin{matrix}0.0 & 1.0 & 2.0\\\\3.0 & 4.0 & 5.0\end{matrix}\right) ->
\begin{aligned}
\Biggl( & \left(
\begin{matrix}0.0 & 1.0 & 2.0\\\\0.0 & 1.0 & 2.0\end{matrix}\right),
\\\\ & \left(
\begin{matrix}3.0 & 4.0 & 5.0\\\\3.0 & 4.0 & 5.0\end{matrix}
\right) \Biggr)
\end{aligned}
$$
$$
\left(\begin{matrix}0.0 & 1.0 & 2.0\\\\3.0 & 4.0 & 5.0\end{matrix}\right) ->
\begin{aligned}
\Biggl( & \left(
\begin{matrix}0.0 & 0.0\\\\1.0 & 1.0\\\\2.0 & 2.0\end{matrix}\right),
\\\\ & \left(
\begin{matrix}3.0 & 3.0\\\\4.0 & 4.0\\\\5.0 & 5.0\end{matrix}
\right) \Biggr)
\end{aligned}
$$
#### Unsqueeze的调用
NiuTrans.Tensor提供了张量的Unsqueeze操作,调用方法为:Unsqueeze(XTensor * a, XTensor * b, int dim, int dSize),参数说明如下表所示:
| 功能 | 函数 | 参数 |
| -: | - | - |
| Unsqueeze | void Unsqueeze(<br>XTensor * a, XTensor * b, <br>int dim, int dSize) | a - 输入张量 <br> b - 输出结果张量 <br> dim - 在指定维度进行Unsqueeze操作 <br> dSize - 插入维度的大小 |
#### Unsqueeze片段示例
Unsqueeze示例代码如下,其中s为输入的待操作张量,t1、t2代表输出结果张量,以下两行分别表示在维度1和维度2上插入的维度大小为2:
```
/* call Unsqueeze function */
Unsqueeze(s, t1, 1, 2);
Unsqueeze(s, t2, 2, 2);
```
有关张量赋值的详细代码示例见 NiuTrans.Tensor/Tensor/test/TUnsqueeze.cpp、
## 高级技巧
### 内存池
## 实例1:矩阵乘法
## 实例2:前馈神经网络
## 实例3:循环神经网络
## 致谢
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论