Commit 969b7054 by linye

删除 manual.md

parent 1d44c72a
# NiuTrans.Tensor张量计算库
## NiuTrans.Tensor
NiuTrans.Tensor是小牛开源项目所开发的一个工具包,提供了完整的张量定义及计算功能,可以被用于深度学习相关研究及工业系统的开发。NiuTrans.Tensor具有以下特点:
* 简单小巧,易于修改
* c语言编写,代码高度优化
* 同时支持CPU和GPU设备
* 丰富的张量计算接口
* 支持C/C++、Python等调用方式
## 安装NiuTrans.Tensor
## 什么是张量
在计算机科学中,张量(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}12 & 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}12 & 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
<pre><code>#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;
}
</code></pre>
下一步,编译以上源程序,这个过程需要指定XTensor.h头文件所在目录。比如,使用g++编译sample.cpp(如果你使用的是visual studio,请看这里???)
<pre><code>g++ sample.cpp -I~/NTS/source -o sample</code></pre>
在sample.cpp中使用了XTensor,它是NiuTrans.Tensor里的一个类,这个类定义了张量所需的数据结构。我们可以使用这个类完成对张量的计算、拷贝等各种操作。XTensor类型的变量被声明后,这个变量需要被初始化,或者说被真正指定为一个张量,比如,指定张量各个维度的大小、张量中每个单元的数据类型、给张量分配内存空间等。InitTensor2D()就是一个张量初始化函数,它把张量初始化为一个矩阵,有四个参数:指向被初始化的张量的指针,矩阵的列数,矩阵的行数,数据单元的类型。这里X_FLOAT,是NiuTrans.Tensor自定义的枚举类型,它表示单精度浮点数。我们也可以使用X_INT或者X_DOUBLE,将数据类型指定为32bit整数或者双精度浮点数。
NiuTrans.Tensor也提供了其它方式定义张量。比如可以直接调用一个函数完成张量的创建,而且可以显性释放张量。下面是一段示例代码(sample2.cpp):
<pre><code>#inlucde "XTensor.h" // 引用XTensor定义的头文件
using namepsace nt; // 使用XTensor所在的命名空间nt
int main(int argc, const char ** argv)
{
// 构建一个单精度浮点类型张量,它是一个50列*100行的矩阵
XTensor * tensor = NewTensor2D(&tensor, 50, 100, X_FLOAT);
// 之后可以使用张量tensor了
// 释放这个张量
DelTensor(tensor);
return 0;
}
</code></pre>
sample2.cpp中使用的NewTensor2D和DelTensor是一组函数,前者生成张量并返回指向这个张量的指针,后者释放指针所指向张量的内容。这种方法比较适合C语言风格的开发。
> 注意,在NiuTrans.Tensor中所有张量默认都是“稠密”张量,也就是张量中所有的单元都会被分配空间,而且这些空间是连续的。有些情况下,张量里的单元仅有少数为非零单元,对于这类张量,可以使用“稀疏"的表示方法,这样可以有效的节省存储空间。
如果要定义稀疏张量,需要在原有的参数基础上额外指定一个参数 - 稠密度。所谓稠密度是指非零单元的比例,他是介于0和1之间的一个实数,0表示所有单元全为零,1表示全为非零单元。默认所有张量的稠密度都是1。下面是不同类型张量的定义方法示例(sample3.cpp)
<pre><code>#inlucde "XTensor.h" // 引用XTensor定义的头文件
using namepsace nt; // 使用XTensor所在的命名空间nt
int main(int argc, const char ** argv)
{
// 构建一个单精度浮点类型张量,它是一个50列*100行的矩阵
// 这个张量是稠密的
XTensor * tensor0 = NewTensor2D(&tensor, 50, 100, X_FLOAT);
// 构建一个单精度浮点类型张量,它是一个50列*100行的矩阵
// 这个张量是稠密的
XTensor * tensor1 = NewTensor2D(&tensor, 50, 100, X_FLOAT, 1.0F);
// 构建一个单精度浮点类型张量,它是一个50列*100行的矩阵
// 这个张量是稀疏的,有10%的单元非零
XTensor * tensor2 = NewTensor2D(&tensor, 50, 100, X_FLOAT, 0.1F);
// 之后可以使用张量tensor0,tensor1和tensor2了
// 释放这些张量
DelTensor(tensor0);
DelTensor(tensor1);
DelTensor(tensor2);
return 0;
}
</code></pre>
以下是关于张量定义的基础函数:
功能 | 函数 | 参数
-: | - | -
初始化张量 | void InitTensor(<br>XTensor * tensor, 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> <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 - 张量所使用的内存池
其它问题??
* 程序编译,是直接引用源文件还是引用库
* 是否需要改变环境变量
* 命名空间是nt还是ntts,还是nts
## 设备及内存池
## 访问张量中的内容
## 张量计算
### 加法(Sum)
### 缩放和偏移(Scale and Shift)
## 高级技巧
## 实例1:矩阵乘法
## 实例2:前馈神经网络
## 实例3:循环神经网络
## 致谢
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论