Eigen unsupport mudule: Tensor
Class Tensor<data_type, rank>
- data_type:数据类型
int, float
- rank: 数据的维度,比如矩阵 rank = 2
tensor 支持不同大小的tensor的赋值
|
|
tensor的初始化
|
|
TensorFixedSize<data_type, Sizes<size0, size1, ...>>
固定大小的Tensor
|
|
TensorMap<Tensor<data_type, rank>>
TensorMap可以从用户提供的已分配内存的空间中构造出tensor,但是TensorMap的大小是不可改变的因为这部分内存空间并不属于它。
TensorMap 的构造函数TensorMap<Tensor<data_type, rank>>(data, size0, size1, ...)
|
|
Tensor的基本操作
获取元素和赋值
|
|
操作
Tensor库包含了大量的操作,这些操作都作为Tensor类的方法,可以直接使用。
|
|
对于表达式值的获取有以下三种方式:
- 赋值给
Tensor
,TensorFixedSize
, 或者TensorMap
- 使用
eval()
方法 - 赋值诶
TensorRef
在下面的实例中auto
得到的是立即值Operations
而不是Tensor
,并且auto
并不会让表达式进行计算,而是直到赋值给Tensor
计算才会执行。
|
|
使用eval()
方法,需要注意调用eval()
的返回值是一个Operation
。eval()
可以让计算更先进行,类似于()
的作用提高了优先级。
|
|
当你并不需要整个表达式计算的所有的值,而是只会用到计算所的的其中某些值(比如我们只会用到计算所得矩阵的第一行),可以选择赋值给RensorRef
|
|
控制表达式如何计算
在Tensor库中对于不同的环境进行了优化比如:CPU单进程,CPU多进程,或者在单个GPU上使用cuda。
目前默认的是实现已经针对Intel CPUs进行了优化,未来将针对ARM CPUs进行优化。
普通的单线程CPU实现:
|
|
使用不同的实现需要使用device()
方法, 目前支持三种不同的devices
类型: DefaultDevice
,ThreadPoolDevice
和 GPUDevice
.
|
|
API
数据类型
<Tensor-Type>::Dimensions
使用来表示Tensor
的数据维度<Tensor-Type>::Index
用来索引<Tensor-Type>::Scalar
用来表示Tensor
的数据类型比如:float
内置方法
这些内置的方法并不会像Operations
一样提供"惰性"计算,而是立刻进行计算得到结果。这些方法适用于所有的tensor类: Tensor
,TensorFixedSize
和TensorMap
。
Shape 相关
-
int NumDimensions
1 2 3
Eigen::Tensor<float, 2> a(3, 4); cout << "Dims " << a.NumDimensions; => Dims 2
-
Dimensions dimensions()
1 2 3 4 5 6 7 8
// Returns an array-like object representing the dimensions of the tensor. Eigen::Tensor<float, 2> a(3, 4); const Eigen::Tensor<float, 2>::Dimensions& d = a.dimensions(); // or use auto to simplify the code in C+11 // const auto& d = a.dimensions(); cout << "Dim size: " << d.size << ", dim 0: " << d[0] << ", dim 1: " << d[1]; => Dim size: 2, dim 0: 3, dim 1: 4
-
Index dimension(Index n)
1 2 3 4
Eigen::Tensor<float, 2> a(3, 4); int dim1 = a.dimension(1); cout << "Dim 1: " << dim1; => Dim 1: 4
-
Index size()
1 2 3
Eigen::Tensor<float, 2> a(3, 4); cout << "Size: " << a.size(); => Size: 12
赋值相关
-
<Tensor-Type> setConstant(const Scalar& val)
1 2 3 4 5 6 7
a.setConstant(12.3f); cout << "Constant: " << endl << a << endl << endl; => Constant: 12.3 12.3 12.3 12.3 12.3 12.3 12.3 12.3 12.3 12.3 12.3 12.3
-
<Tensor-Type> setZero()
1 2 3 4 5 6 7
a.setZero(); cout << "Zeros: " << endl << a << endl << endl; => Zeros: 0 0 0 0 0 0 0 0 0 0 0 0
-
<Tensor-Type> setValues({..initializer_list})
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Eigen::Tensor<float, 2> a(2, 3); a.setValues({{0.0f, 1.0f, 2.0f}, {3.0f, 4.0f, 5.0f}}); cout << "a" << endl << a << endl << endl; => a 0 1 2 3 4 5 Eigen::Tensor<int, 2> a(2, 3); a.setConstant(1000); a.setValues({{10, 20, 30}}); cout << "a" << endl << a << endl << endl; => a 10 20 30 1000 1000 1000
-
<Tensor-Type> setRandom()
1 2 3 4 5 6 7
a.setRandom(); cout << "Random: " << endl << a << endl << endl; => Random: 0.680375 0.59688 -0.329554 0.10794 -0.211234 0.823295 0.536459 -0.0452059 0.566198 -0.604897 -0.444451 0.257742
可以使用自定义的
number generator
,示例如下1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
// Custom number generator for use with setRandom(). struct MyRandomGenerator { // Default and copy constructors. Both are needed MyRandomGenerator() { } MyRandomGenerator(const MyRandomGenerator& ) { } // Return a random value to be used. "element_location" is the // location of the entry to set in the tensor, it can typically // be ignored. Scalar operator()(Eigen::DenseIndex element_location, Eigen::DenseIndex /*unused*/ = 0) const { return <randomly generated value of type T>; } // Same as above but generates several numbers at a time. typename internal::packet_traits<Scalar>::type packetOp( Eigen::DenseIndex packet_location, Eigen::DenseIndex /*unused*/ = 0) const { return <a packet of randomly generated values>; } };
然后使用
a.setRandom<MyRandomGenerator>();
便可以了,其中Eigen内置了两个generator
:UniformRandomGenerator
,NormalRandomGenerator
.
数据获取
-
Scalar* data()
返回指向tensor内存的指针。其中内存存储方法取决于tensor的存储方式是`RowMajor`还是`ColMajor`. ```c++ Eigen::Tensor<float, 2> a(3, 4); float* a_data = a.data(); a_data[0] = 123.45f; cout << "a(0, 0): " << a(0, 0); => a(0, 0): 123.45 ```
Tensor 操作
本小节内的操作都将会返回一个没有计算值的`tensor Operations`, 这些操作可以组合在一起使用。需要注意的是,这些操作执行的是“惰性”计算。
Unary Element wise operations
-
<Operation> constant(const Scalar& val)
返回一个和原tensor一样的tensor.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Eigen::Tensor<float, 2> a(2, 3); a.setConstant(1.0f); Eigen::Tensor<float, 2> b = a + a.constant(2.0f); Eigen::Tensor<float, 2> c = b * b.constant(0.2f); cout << "a" << endl << a << endl << endl; cout << "b" << endl << b << endl << endl; cout << "c" << endl << c << endl << endl; => a 1 1 1 1 1 1 b 3 3 3 3 3 3 c 0.6 0.6 0.6 0.6 0.6 0.6
-
<Operation> random()
返回一个shape和原tensor一样,但是里面的元素值为随机值
1 2 3 4 5 6 7 8 9 10 11 12 13
Eigen::Tensor<float, 2> a(2, 3); a.setConstant(1.0f); Eigen::Tensor<float, 2> b = a + a.random(); cout << "a" << endl << a << endl << endl; cout << "b" << endl << b << endl << endl; => a 1 1 1 1 1 1 b 1.68038 1.5662 1.82329 0.788766 1.59688 0.395103
-
<Operation> operator-()
所有元素取反
1 2 3 4 5 6 7 8 9 10 11 12 13
Eigen::Tensor<float, 2> a(2, 3); a.setConstant(1.0f); Eigen::Tensor<float, 2> b = -a; cout << "a" << endl << a << endl << endl; cout << "b" << endl << b << endl << endl; => a 1 1 1 1 1 1 b -1 -1 -1 -1 -1 -1
-
<Operation> sqrt()
-
<Operation> rsqrt()
-
Operation> square()
-
<Operation> inverse()
-
<Operation> exp()
-
<Operation> log()
-
<Operation> abs()
-
<Operation> pow(Scalar exponent)
1 2 3 4 5 6 7 8 9 10 11 12 13
Eigen::Tensor<int, 2> a(2, 3); a.setValues({{0, 1, 8}, {27, 64, 125}}); Eigen::Tensor<double, 2> b = a.cast<double>().pow(1.0 / 3.0); cout << "a" << endl << a << endl << endl; cout << "b" << endl << b << endl << endl; => a 0 1 8 27 64 125 b 0 1 2 3 4 5
-
<Operation> operator * (Scalar scale)
Binary Element wise operation
提供两个tensor,进行基于相应元素的计算操作。
-
<Operation> operator+(const OtherDerived& other)
-
<Operation> operator-(const OtherDerived& other)
-
<Operation> operator*(const OtherDerived& other)
-
<Operation> operator/(const OtherDerived& other)
-
<Operation> cwiseMax(const OtherDerived& other)
返回两个tensor每个元素大的值组成的新tensor =
max {t1_i, t2_i}
-
Operation> cwiseMin(const OtherDerived& other)
-
<Operation> Logical operators
- operator&&(const OtherDerived& other)
- operator||(const OtherDerived& other)
- operator<(const OtherDerived& other)
- operator<=(const OtherDerived& other)
- operator>(const OtherDerived& other)
- operator>=(const OtherDerived& other)
- operator==(const OtherDerived& other)
- operator!=(const OtherDerived& other) 返回的是一个包含bool 值的tensor
Contraction
Tensor contractions是将矩阵相乘的操作推广到多维上。
|
|
Reduction operations
维度缩减至1维:
|
|
维度缩减至2维:
|
|
维度缩减至一个数值:
|
|
<Operation> sum(const Dimensions& new_dims)
<Operation> sum()
<Operation> mean(const Dimensions& new_dims)
<Operation> mean()
<Operation> maximum(const Dimensions& new_dims)
<Operation> maximum()
<Operation> minimum(const Dimensions& new_dims)
<Operation> minimum()
<Operation> prod(const Dimensions& new_dims)
<Operation> prod()
<Operation> all(const Dimensions& new_dims)
<Operation> all()
返回bool值,检验所有的元素是否都为true<Operation> any(const Dimensions& new_dims)
<Operation> any()
返回bool值,检验是否存在元素为true<Operation> reduce(const Dimensions& new_dims, const Reducer& reducer)
用于支持用户自定义的reduce
操作
Scan operations
该操作返回的tensor的shape将会与原tensor一样
|
|
<Operation> cumsum(const Index& axis)
<Operation> cumprod(const Index& axis)
Convolutions
-
<Operation> convolve(const Kernel& kernel, const Dimensions& dims)
对使用卷积核(kernel)对tensor进行卷积操作(执行的是无padding的计算
output_dim_size = input_dim_size - kernel_dim_size + 1
)1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Tensor<float, 4, DataLayout> input(3, 3, 7, 11); Tensor<float, 2, DataLayout> kernel(2, 2); Tensor<float, 4, DataLayout> output(3, 2, 6, 11); input.setRandom(); kernel.setRandom(); Eigen::array<ptrdiff_t, 2> dims({1, 2}); // Specify second and third dimension for convolution. output = input.convolve(kernel, dims); for (int i = 0; i < 3; ++i) { for (int j = 0; j < 2; ++j) { for (int k = 0; k < 6; ++k) { for (int l = 0; l < 11; ++l) { const float result = output(i,j,k,l); const float expected = input(i,j+0,k+0,l) * kernel(0,0) + input(i,j+1,k+0,l) * kernel(1,0) + input(i,j+0,k+1,l) * kernel(0,1) + input(i,j+1,k+1,l) * kernel(1,1); VERIFY_IS_APPROX(result, expected); } } } }
Geometrical operations
包含切分和增添数据的操作
-
<Operation> reshape(const Dimensions& new_dims)
1 2 3 4 5 6 7 8 9
// Increase the rank of the input tensor by introducing a new dimension // of size 1. Tensor<float, 2> input(7, 11); array<int, 3> three_dims{{7, 11, 1}}; Tensor<float, 3> result = input.reshape(three_dims); // Decrease the rank of the input tensor by merging 2 dimensions; array<int, 1> one_dim{{7 * 11}}; Tensor<float, 1> result = input.reshape(one_dim);
当原tensor的存储分布为
ColMajor
时1 2 3 4 5 6 7 8 9 10 11 12 13
Eigen::Tensor<float, 2, Eigen::ColMajor> a(2, 3); a.setValues({{0.0f, 100.0f, 200.0f}, {300.0f, 400.0f, 500.0f}}); Eigen::array<Eigen::DenseIndex, 1> one_dim({3 * 2}); Eigen::Tensor<float, 1, Eigen::ColMajor> b = a.reshape(one_dim); cout << "b" << endl << b << endl; => b 0 300 100 400 200 500
当原tensor的存储分布为
RowMajor
时1 2 3 4 5 6 7 8 9 10 11 12 13
Eigen::Tensor<float, 2, Eigen::RowMajor> a(2, 3); a.setValues({{0.0f, 100.0f, 200.0f}, {300.0f, 400.0f, 500.0f}}); Eigen::array<Eigen::DenseIndex, 1> one_dim({3 * 2}); Eigen::Tensor<float, 1, Eigen::RowMajor> b = a.reshape(one_dim); cout << "b" << endl << b << endl; => b 0 100 200 300 400 500
-
<Operation> shuffle(const Shuffle& shuffle)
返回原tensor的副本,但是其维度被打乱了,比如原先维度为{2, 3}
变成{3, 2}
1 2 3 4 5 6 7 8
// Shuffle all dimensions to the left by 1. Tensor<float, 3> input(20, 30, 50); // ... set some values in input. Tensor<float, 3> output = input.shuffle({1, 2, 0}) eigen_assert(output.dimension(0) == 30); eigen_assert(output.dimension(1) == 50); eigen_assert(output.dimension(2) == 20);
-
<Operation> stride(const Strides& strides)
1 2 3 4 5 6 7 8 9
Eigen::Tensor<int, 2> a(4, 3); a.setValues({{0, 100, 200}, {300, 400, 500}, {600, 700, 800}, {900, 1000, 1100}}); Eigen::array<Eigen::DenseIndex, 2> strides({3, 2}); Eigen::Tensor<int, 2> b = a.stride(strides); cout << "b" << endl << b << endl; => b 0 200 900 1100
-
<Operation> slice(const StartIndices& offsets, const Sizes& extents)
|
|
<Operation> chip(const Index offset, const Index dim)
返回一个比原tensor少一个维度的tensor
|
|
<Operation> reverse(const ReverseDimensions& reverse)
|
|
<Operation> broadcast(const Broadcast& broadcast)
|
|
-
<Operation> pad(const PaddingDimensions& padding)
padding with zeros.
|
|
Special operations
<Operation> cast<T>()
类型转换1 2
Eigen::Tensor<float, 2> a(2, 3); Eigen::Tensor<int, 2> b = a.cast<int>();
特殊问题
- Tensor 默认存储方式是“column-major”