C++ Eigen3库Tensor操作整理(持续更新)

本文详细介绍如何在C++中使用Eigen库进行Tensor操作,包括获取shape、类型转换(如C++数组转Tensor)、concatenate、transpose和reshape,同时对比了与Python numpy的异同。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文还会对比与python numpy的相同操作的区别

项目引入

VS2019环境下

  1. 点击<项目>
  2. 管理NuGet程序包
  3. 搜索Eigen3,安装即可
    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

  1. float数组转Eigen::TensorMap
  2. 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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Alex-Leung

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值