目录
本文还会对比与python numpy的相同操作的区别
项目引入
VS2019环境下
- 点击<项目>
- 管理NuGet程序包
- 搜索Eigen3,安装即可
在项目源代码添加头文件
#include <unsupported/Eigen/CXX11/Tensor>
获取Tensor的shape
// 定义一个tensor
Eigen::Tensor<int, 3> input(1, 4, 2);
// 输出各个维度
cout << input.dimensions()[0] << endl; // output: 1
cout << input.dimensions()[1] << endl; // output: 4
cout << input.dimensions()[2] << endl; // output: 2
类型转换
C++ 数组转Eigen::Tensor(包含reshape操作)
例如从float数组转到储存类型为float的Tensor
- float数组转Eigen::TensorMap
- Eigen::TensorMap类型转换回Eigen::Tensor
#include <iostream>
#include <unsupported/Eigen/CXX11/Tensor>
int main()
{
// 定义一个一维数组,在下面将其转换为2x2的tensor
float arr[] = { 0.1, 0.2, 0.3, 0.4 };
// 定义转换的Eigen::TensorMap,同时做了一个reshape操作
// 如果arr是个vector, 则使用arr.data()
auto mapped_t = Eigen::TensorMap<Eigen::Tensor<float, 2>>(arr, 2, 2);
std::cout << typeid(mapped_t).name() << std::endl;
// 强制转换为Tensor
auto result = Eigen::Tensor<float, 2>(mapped_t);
std::cout << typeid(result).name() << std::endl;
std::cout << result << std::endl;
}
输出
class Eigen::TensorMap<class Eigen::Tensor<float,2,0,__int64>,0,struct Eigen::MakePointer>
class Eigen::Tensor<float,2,0,__int64>
0.1 0.3
0.2 0.4
Tensor操作
concatenate
#include <iostream>
#include <unsupported/Eigen/CXX11/Tensor>
int main()
{
// 创建一个2维,2x2的tensor
Eigen::Tensor<float, 2, 1> a(2, 2);
Eigen::Tensor<float, 2, 1> b(2, 2);
// 给tensor设置默认值
a.setConstant(1.0);
b.setConstant(2.0);
// 从维度0进行拼接
auto res = a.concatenate(b, 0);
std::cout << res << std::endl;
}
输出结果:
1 1
1 1
2 2
2 2
transpose
#include <iostream>
#include <unsupported/Eigen/CXX11/Tensor>
using namespace std;
int main()
{
Eigen::Tensor<int, 3> m(2, 3, 3);
m.setValues(
{
{{1, 2, 3},
{4, 5, 6},
{7, 8, 9}},
{{10, 11, 12},
{13, 14, 15},
{16, 17, 18}}
});
Eigen::array<int, 3> shuffling({ 2, 1, 0});
Eigen::Tensor<int, 3> transposed = m.shuffle(shuffling);
cout << transposed(0, 0, 0) << ',' << transposed(0, 0, 1) << endl;
cout << transposed(0, 1, 0) << ',' << transposed(0, 1, 1) << endl;
cout << transposed(0, 2, 0) << ',' << transposed(0, 2, 1) << endl;
cout << transposed(1, 0, 0) << ',' << transposed(1, 0, 1) << endl;
cout << transposed(1, 1, 0) << ',' << transposed(1, 1, 1) << endl;
cout << transposed(1, 2, 0) << ',' << transposed(1, 2, 1) << endl;
cout << transposed(2, 0, 0) << ',' << transposed(2, 0, 1) << endl;
cout << transposed(2, 1, 0) << ',' << transposed(2, 1, 1) << endl;
cout << transposed(2, 2, 0) << ',' << transposed(2, 2, 1) << endl;
}
输出
1,10
4,13
7,16
2,11
5,14
8,17
3,12
6,15
9,18
该操作与python的numpy库的ndarray.transpose一致
import numpy as np
mat = [
[[1, 2, 3],
[4, 5, 6],
[7, 8, 9]],
[[10, 11, 12],
[13, 14, 15],
[16, 17, 18]]
]
mat = np.array(mat)
mat = mat.transpose(2, 1, 0)
print(mat[0][0][0], mat[0][0][1])
print(mat[0][1][0], mat[0][1][1])
print(mat[0][2][0], mat[0][2][1])
print(mat[1][0][0], mat[1][0][1])
print(mat[1][1][0], mat[1][1][1])
print(mat[1][2][0], mat[1][2][1])
print(mat[2][0][0], mat[2][0][1])
print(mat[2][1][0], mat[2][1][1])
print(mat[2][2][0], mat[2][2][1])
输出
1 10
4 13
7 16
2 11
5 14
8 17
3 12
6 15
9 18
reshape
#include <iostream>
#include <unsupported/Eigen/CXX11/Tensor>
using namespace std;
int main()
{
// 定义一个2x2x2的Tensor
Eigen::Tensor<int, 3> input(2, 2, 2);
// 设置默认值
input.setValues(
{
{{1,2}, {3, 4}},
{{5,6}, {7, 8}}
}
);
const auto output = Eigen::Tensor<int, 3>(input.reshape(Eigen::array<int, 3>({ 1, 4, 2 })));
cout << output(0, 0, 0) << ',' << output(0, 0, 1) << endl;
cout << output(0, 1, 0) << ',' << output(0, 1, 1) << endl;
cout << output(0, 2, 0) << ',' << output(0, 2, 1) << endl;
cout << output(0, 3, 0) << ',' << output(0, 3, 1) << endl;
}
输出
1,2
5,6
3,4
7,8
该操作与python numpy的reshape输出是不一致
import numpy as np
res = [
[
[1, 2],
[3, 4]
],
[
[5, 6],
[7, 8]
],
]
res = np.array(res)
res = res.reshape(1, 4, 2)
print(res)
输出
[[[1 2]
[3 4]
[5 6]
[7 8]]]
如果想要得到跟numpy一样的输出可进行以下操作, 先展平再重新构建
Eigen::Tensor<float, 3> reshape(Eigen::Tensor<int, 3> input , int channel, int height, int width)
{
Eigen::Tensor<float, 3> res;
vector<float> one_dim_array;
int index = 0;
for (int i = 0; i < input.dimensions()[0]; i++)
{
for (int i2 = 0; i2 < input.dimensions()[1]; i2++)
{
for (int i3 = 0; i3 < input.dimensions()[2]; i3++)
{
one_dim_array.push_back(input(i, i2, i3));
}
}
}
res = Eigen::Tensor<float, 3>(Eigen::TensorMap<Eigen::Tensor<float, 3>>(one_dim_array.data(), channel, height, width));
return res;
}
辅助操作
打印Tensor的shape
template<typename type>
void printDims(type tensor)
{
for (int i = 0; i < tensor.NumDimensions; i++) {
cout << tensor.dimension(i);
if(i != (tensor.NumDimensions - 1 )){
cout << ',';
}
}
cout << endl;
}