/* NiuTrans.Tensor - an open-source tensor library * Copyright (C) 2017, Natural Language Processing Lab, Northestern University. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * * the tensor class * * $Created by: XIAO Tong (xiaotong@mail.neu.edu.cn) 2017-07-31 * I'm working while most of the students are enjoying their holidays :( * $Updated by: LI Yinqiao (li.yin.qiao.2012@hotmail.com) 2017-11-18 bug fixes * */ #ifndef __XTENSOR_H__ #define __XTENSOR_H__ #include <math.h> #include "XGlobal.h" #include "XPRunner.h" #include "XStream.h" #include "XHeap.h" #include "XList.h" #include "XDataType.h" #include "XMem.h" #include "XLink.h" #include "XCall.h" /* the nts (NiuTrans.Tensor) namespace */ namespace nts{ /* cross reference */ struct XLink; /* define the maximum number of dimensions in a tensor */ #define MAX_TENSOR_DIM_NUM 8 #define USE_BATCHED_STRIDED_MAT_MUL #define MIN_TENSOR_SPLIT_NUM 0 #define MIN_TENSOR_SPLIT_LIST_NUM 1024 #define MIN_TENSOR_MERGE_NUM 0 #define MIN_TENSOR_MERGE_LIST_NUM 1024 #define MIN_TENSOR_CAT_NUM 8 #define MAX_TENSOR_NAME_SIZE 32 /* computation flags */ #define UNSAFE_BUT_FAST_MEM #define FAST_MATRIX /* XTensor is a class to do everything a tensor can do :) */ struct XTensor { public: /* name */ char name[MAX_TENSOR_NAME_SIZE]; /* id */ int id; /* memory pool */ XMem * mem; /* signature of the memory pool */ MTYPE signature; /* data array to keep the elements */ void * data; /* copy of data on the host memory. It is only activated when the tensor is operated on GPUs */ void * dataHost; /* a pointer to data (i.e., a pointer to the address of "data". This is for reset "data" when XTensor is used as a const variable. */ void ** dataP; /* device id <0: CPU memory >=0: GPU device ID */ int devID; /* order of the tensor. e.g., a matrix (a 2-dimensional array) is a 2nd-order tensor */ int order; /* size of each dimension */ int dimSize[MAX_TENSOR_DIM_NUM]; /* data unit - data type for every cell */ TENSOR_DATA_TYPE dataType; /* size of tensor unit, e.g., sizeof(int) */ int unitSize; /* number of units */ int unitNum; /* if it is a sparse matrix dense matrix: there are n * m entries - i.e., the size of "data" is n * m sparse matrix: number of entries depends on how many entries are non-zero */ bool isSparse; /* nubmer of non-zero items in a sparse matrix */ int unitNumNonZero; /* denseRatio - how dense the matrix is denseRatio = 1: a dense matrix denseRatio < 1: how often an element has a non-zero value */ float denseRatio; /* indicates whether the data array is shared with other tensors */ bool isShared; /* indicates whether the date type used in this tensor is in default type (i.e., DTYPE) */ bool isDefaultDType; /* indicates whether the data is allocated in the global memory rather than a memory pool */ bool isInGlobalMem; /* indicates whether the SPARSE tensor has non-zero values for all entries alone each dimension */ bool isAllValued[MAX_TENSOR_DIM_NUM]; /* indicates whether the tensor is initialized or not */ bool isInit; /* indicates whether the tensor is created temporarily */ bool isTmp; /* indicates whether the tensor keeps the gradient when used as model parameters */ bool isGrad; /* indicates whether the gradient of the tensor should be computed */ bool enableGrad; /* indicates whether the tensor is used as paramters (or variables) */ bool isVar; /* mark for traversing the gragh */ unsigned int visitMark; /* gradient (for back-propagation) */ XTensor * grad; /* the link used to form networks. Note that when we compute on tensors, we actually create a network where nodes are tensors and edges the connections among them. Each connection is a hyperedge whose head is the output tensor and tails are input tensors. E.g, c = a + b represents a network with three nodes (a, b and c) and a hyperedge that links a and b (tails) to c (head). Here "income" keeps which nodes (tensors) are used to form the current node (tensor). */ XLink income; /* It keeps which nodes (tensors) we go to from the current node (tensor). */ XLink outgo; /******************** XTensor untilities ********************/ /* constructor */ XTensor(); /* constructor */ XTensor(const XTensor * reference); /* constructor */ XTensor(const int myOrder, int myDevID, XMem * myMem); /* constructor */ XTensor(const int myOrder, const int * myDimSize, const TENSOR_DATA_TYPE myDataType, const float myDenseRatio, int myDevID, XMem * myMem); /* copy constructor */ XTensor(const XTensor &reference); /* copy constructor (with right value reference) */ XTensor(const XTensor &&reference); /* de-constructor */ ~XTensor(); /* set the name of the tensor */ void SetName(const char * myName); /* initialize member variables */ void Init(); /* delete data arrays */ void DestroyData(); /* shallow copy of tensor */ void ShallowCopy(const XTensor &tensor); /* overloading of the equal-sign */ XTensor& operator= (const XTensor &tensor); /* overloading of the equal-sign (with right value reference) */ XTensor& operator= (const XTensor &&tensor); /* overloading of the plus-sign */ XTensor operator+ (const XTensor &tensor) const; /* overloading of the plus-sign */ XTensor operator+ (const DTYPE shift) const; /* overloading of the multiply-sign */ XTensor operator* (const XTensor &tensor) const; /* overloading of the multiply-sign */ XTensor operator* (const DTYPE scale) const; /* overloading of the minus-sign */ XTensor operator- (const XTensor &tensor) const; /* overloading of the minus-sign */ XTensor operator- (const DTYPE shift) const; /* overloading of the minus-sign */ XTensor operator- () const; /* overloading of the division-sign */ XTensor operator/ (const XTensor &tensor) const; /* overloading of the division-sign */ XTensor operator/ (const DTYPE scale) const; /* linear transformation */ XTensor Lin(DTYPE scale, DTYPE shift = 0) const; /* relocate the data on the target device */ void SetDevice(int myDevId, XMem * myMem = NULL); /* judge whether b is the reduced shape of a ?? */ static bool IsReduceShaped(const XTensor * a, const XTensor * b, int dim); /* set the size of each dimension */ void SetDim(int * myDimSize); /* get the size of a given dimension */ int GetDim(const int dim) const; /* reshape the tensor */ void Reshape(const int order, const int * myDimSize); /* reshape the tensor to a vector */ void Reshape(const int num); /* reshape the tensor to a matrix */ void Reshape(const int rowNum, const int colNum); /* reshape the tensor by merging two consecutive dimensions */ void ReshapeMerged(const int i, const int j = -1); /* return a tensor that datatype is same as the special tensor */ XTensor TypeAs(const XTensor input); /* get the number of items in the data array */ int GetSize() const; /* get size of the memory used */ int GetDataSizeInChar() const; /* get unit size in terms of "dataType" */ int GetUnitSize(TENSOR_DATA_TYPE myDataType) const; /* get offset (2D) */ MTYPE GetOffset2D(int row, int col) const; /* get offset (3D) */ MTYPE GetOffset3D(int d0, int d1, int d2) const; /* a tensor with all entries of 0 */ void SetZeroAll(XStream * stream = NULL); /* set the tensor with an data array */ void SetData(const void * d, int num, int beg = 0); /* generate data items with a uniform distribution in [0, 1] */ void Rand(int rNum, int cNum); /* generate data items with a range by start, end and the step */ void Range(DTYPE lower, DTYPE upper, DTYPE step); /* set tensor items by a uniform distribution */ void SetDataRand(DTYPE lower = 0.0F, DTYPE upper = 1.0F); /* set tensor items by a normal distribution */ void SetDataRandn(DTYPE mean, DTYPE standardDeviation); /* set tensor items with an array of offsets */ void SetDataBatched(MTYPE * offsets, DTYPE value, int num); /* set tensor items with an array of values */ void SetDataBatchedWithValues(MTYPE * offsets, void * values, int num); /* set the pointer to "data" */ void SetDataPointer(); /* get the value of a cell with the index */ DTYPE Get(int index[], int size = -1) const; /* get the value of a cell with the offset */ DTYPE Get(int offset) const; /* get the pointer to a cell */ void * GetCell(int index[], int size = -1) const; /* get the default type value of a cell in a 0d tensor */ DTYPE Get0D() const; /* get the default type value of a cell in a 1d tensor */ DTYPE Get1D(int i) const; /* get the default type value of a cell in a 2d tensor */ DTYPE Get2D(int ni, int mi) const; /* get the default type value of a cell in a 3d tensor */ DTYPE Get3D(int d0, int d1, int d2) const; /* get the int value of a cell by its offset */ int GetInt(int offset) const; /* get the int value of a cell in a 0d tensor */ int Get0DInt() const; /* get the int value of a cell in a 1d tensor */ int Get1DInt(int i) const; /* get the int value of a cell in a 2d tensor */ int Get2DInt(int ni, int mi) const; /* get the int value of a cell in a 3d tensor */ int Get3DInt(int d0, int d1, int d2) const; /* get the value of a cell in a sparse tensor */ DTYPE GetInSparse(int i) const; /* get the key value of a tuple in a sparse tensor */ int GetKeyInSparse(int i) const; /* set the value of a cell */ bool Set(DTYPE value, int index[], int size = -1); /* set the value of a cell with its offset in the array */ bool Set(DTYPE value, int offset); /* set the value of a cell in a 0d tensor */ bool Set0D(DTYPE value); /* set the value of a cell in a 1d tensor */ bool Set1D(DTYPE value, int i); /* set the value of a cell in a 2d tensor */ bool Set2D(DTYPE value, int ni, int mi); /* set the value of a cell in a 3d tensor */ bool Set3D(DTYPE value, int d0, int d1, int d2); /* set the integer value of a cell by its offset */ bool SetInt(int value, int offset); /* set the integer value of a cell */ bool SetInt(int value, int index[], int size = -1); /* set the integer value of a cell in a 0d tensor */ bool Set0DInt(int value); /* set the integer value of a cell in a 1d tensor */ bool Set1DInt(int value, int i); /* set the integer value of a cell in a 2d tensor */ bool Set2DInt(int value, int ni, int mi); /* set the integer value of a cell in a 3d tensor */ bool Set3DInt(int value, int d0, int d1, int d2); /* increase the value of a cell in a 2d */ bool Add2D(DTYPE value, int ni, int mi); /* get the number of non-zero elements (in a sparse tensor) */ int GetNonzeroSize() const; /* set the tensor as "temporary" */ void SetTMPFlag(bool myIsTmp = true); /* set the tensor as "keep-gradient" */ void SetGradFlag(bool myIsGrad = true); /* set the tensor as "variable" */ void SetVarFlag(bool myIsVar = true); /* resize a tensor with a specified tensor size */ bool Resize(const int myOrder, const int * myDimSize, const TENSOR_DATA_TYPE myDataType = DEFAULT_DTYPE, const float myDenseRatio = 1.0F); /* resize a tensor by another one */ bool Resize(const XTensor * myTensor); /* binary search to find an element in a sparse matrix*/ bool BinarySearch(int key, DTYPE &value, void * &position) const; /* dump data to a file */ void Dump(FILE * file, const char * label = NULL, const int n = -1, const int beg = 0, const int verbose = 0); /* dump data to a file */ static void Dump(const XTensor * tensor, FILE * file, const char * label = NULL, const int n = -1, const int beg = 0, const int verbose = 0); /* dump data to a binary file */ void BinaryDump(FILE * file); /* read data from a file */ void Read(FILE * file, const char * label = NULL); /* read data from a binary file */ void BinaryRead(FILE * file, size_t offset); /* flush the data to the target device */ void FlushToMem(XMem * targetMem); /* allocate the memory space of the tensor (in the global memory) */ static void AllocateData(XTensor * tensor, XMem * myMem = NULL, bool useBuf = false); /* free the memory space of the tensor (in the global memory) */ static void FreeData(XTensor * tensor, XMem * myMem = NULL, bool useBuf = false); }; /* we make a unique id for every tensor */ extern int tensorIDGlobal; extern MUTEX_HANDLE tensorMutex; extern XTensor NULLTensor; extern int MakeTensorID(); /* overloading of the plus-sign */ XTensor operator+ (const DTYPE shift, const XTensor &tensor); /* overloading of the minus-sign */ XTensor operator- (const DTYPE shift, const XTensor &tensor); /* overloading of the multiply-sign */ XTensor operator* (const DTYPE scale, const XTensor &tensor); /* overloading of the division-sign */ XTensor operator/ (const DTYPE scale, const XTensor &tensor); } /* end of the nts (NiuTrans.Tensor) namespace */ #endif