之所以使用Eigen的Tensor,主要是因为Tensorflow
中的一个C++项目中,需要对graph
中得到的Tensor
进行数据后处理。而tensorflow
的C++API中用到了Eigen这个矩阵运算库中的Tensor,所做了些笔记。该笔记主要参考Eigen-unsupport
这个官方的文档(英文),并以此为基础记录一些与numpy对应的函数与技巧。
中文方面可以参考以下三篇文章:
Eigen Tensor详解一
Eigen Tensor详解二
Eigen Tensor详解三
Eigen中的Tensor中重载了*
并用于实现点对点相乘和与标量相乘。关于点对点相乘,需要注意的是两个tensor的shape必须相同才能相乘,如果需要像numpy那样实现大小矩阵相乘(广播机制),需要自己设置广播,如下:
#include
Eigen::Tensor a(3, 2);
Eigen::Tensor b(1, 2);
a.setConstant(2.0);
b.setConstant(3.0);
Eigen::array bcast = { 3, 1 };//第一维复制3倍
auto ab = a*b.broadcast(bcast);
cout<
如果是要实现Tensor的内积,则需要使用tensor的contract
函数,可以实现高维的矩阵内积,如下:
Eigen::Tensor a(2, 3);
a.setValues({{1, 2, 3}, {6, 5, 4}});
Eigen::Tensor b(3, 2);
b.setValues({{1, 2}, {4, 5}, {5, 6}});
Eigen::array, 1> product_dims = { Eigen::IndexPair(1, 0) };
Eigen::Tensor AB = a.contract(b, product_dims);
cout<
Tensor中的reshape靠TensorMap
这种数据类型实现。
float nums[12] = { 0, 100, 200 , 300, 400, 500,600, 700, 800,900, 1000, 1100 };
Eigen::TensorMap> a(nums, 4, 3);
Eigen::TensorMap> b(a.data(), 2, 6);
----------------------
a
0 100 200
300 400 500
600 700 800
900 1000 1100
b
0 100 200 300 400 500
600 700 800 900 1000 1100
Tensor的堆叠,如两个(2,2)的tensor堆叠为(2,2,2),也可以实现拼接(4,2),(2,4)。
Eigen::Tensor a(2, 2);
Eigen::Tensor b(2, 2);
a.setConstant(1,0);
b.setConstant(2.0);
auto ab = a.concatenate(b,0); //(4,2)
auto ab1 = a.concatenate(b,1); //(2,4)
Eigen::DSizes three_dim(3,2,1);
Eigen::Tensor ab2 = a.reshape(three_dim).concatenate(b.reshape(three_dim), 2) //(2,2,2)
Tensor中没有matlab中的find
或者python中numpy里的where
,用于寻找满足条件的元素的下标。这里用到的思路是首先通过比较(><
的符号Eigen已经重载),考虑到tensor的内存是连续存储的,通过遍历每个元素,计算满足的元素的下标。由于下面的代码中已经设置了Tensor为行优先存储,下标计算如下所示。
class getthree_index
{
public:
vector* fir_dim;
vector* sec_dim;
vector* thi_dim;
int fir, sec, thi;
int idx = 0;
getthree_index(vector* f, vector* s, vector* t, int fn, int sn, int tn)
{
fir_dim = f; sec_dim = s; thi_dim = t; fir = fn; sec = sn; thi = tn;
};
void operator()(bool i);
};
float nums[12] = { 0, 100, 200 , 300, 400, 500,600, 700, 800,900, 1000, 1100 };
Eigen::TensorMap> a(nums, 2, 3, 2);
auto threshold = a.constant(400);
Eigen::Tensor res = a>threshold.eval();
vector fir_dim;
vector sec_dim;
vector thi_dim;
auto shape = a.dimensions();
for_each(res.data(), res.data() + res.size(), getthree_index(&fir_dim, &sec_dim, &thi_dim,
int(shape[0]), int(shape[1]), int(shape[2])));
暂时这么多,后面再来补充。