Eigen库学习笔记(四)Eigen用于三维张量

  • 1、示例:
  • 2、3维张量
  • 3、固定大小矩阵TensorFixedSize
  • 4、常用函数API
  • 5、矩阵乘法与广播机制
    • Tensor的矩阵乘法操作
    • Tensor的reshape操作
    • Tensor的堆叠(stack)操作

平常中我们使用Eigen::MatrixXd二维矩阵。
Eigen的三维张量正处于开发中,在unsupported文件夹下,还没有放到正式代码中。
Eigen::Tensor来定义
IMPORTANT NOTE: The current developement version of Eigen (post-3.2) supports Tensors. This support is experimental and a moving target.
包含头文件:

#include <unsupported/Eigen/CXX11/Tensor>

1、示例:

Eigen::Tensor<double, 3> epsilon(3,3,3);
epsilon.setZero();
epsilon(0,1,2) = 1;
epsilon(1,2,0) = 1;
epsilon(2,0,1) = 1;
epsilon(1,0,2) = -1;
epsilon(2,1,0) = -1;
epsilon(0,2,1) = -1;
Eigen::Tensor<double, 4> grassmannIdentity(3,3,3,3);
grassmannIdentity.setZero();
// this is not the most efficient way to write such a product,
// but is the only way possible with the current feature set
for (int i = 0; i < 3; i++) {for (int j = 0; j < 3; j++) {for (int k = 0; k < 3; k++) {for (int l = 0; l < 3; l++) {for (int m = 0; m < 3; m++) {grassmannIdentity(i,j,l,m) += epsilon(i,j,k) * epsilon(k,l,m);}}}}
}// verify
for (int i = 0; i < 3; i++) {for (int j = 0; j < 3; j++) {for (int l = 0; l < 3; l++) {for (int m = 0; m < 3; m++) {assert(grassmannIdentity(i,j,l,m) == (int(i == l) * int(j == m) - int(i == m) * int(j == l)));}}}
}// dimensionalities
assert(epsilon.dimension(0) == 3);
assert(epsilon.dimension(1) == 3);
assert(epsilon.dimension(2) == 3);
auto dims = epsilon.dimensions();
assert(dims[0] == 3);
assert(dims[1] == 3);
assert(dims[2] == 3);

参考:官方文档Tensor support

2、3维张量

  // 定义一个2x3x4大小的矩阵Eigen::Tensor<float, 3> a(2, 3, 4);// 初始化为0a.setZero();// 访问元素a(0, 1, 0) = 12.0f;for (int i = 0; i < 2; i++) {for (int j = 0; j < 3; j++) {for (int k = 0; k < 4; k++) {std::cout << a(i, j, k) << " ";}std::cout << std::endl;}std::cout << std::endl << std::endl;}// 输出维度std::cout<<a.dimension(0)<<" "<<a.dimension(1)<<" "<<a.dimension(2)<<std::endl;

输出结果:

0 0 0 0
12 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0
0 0 0 02 3 4

3、固定大小矩阵TensorFixedSize

参考官方解释

The fixed sized equivalent of Eigen::Tensor<float, 3> t(3, 5, 7); is Eigen::TensorFixedSize<float, Size<3,5,7>> t;
  // 固定 大小的Size 2x3x4Eigen::TensorFixedSize<float, Eigen::Sizes<2, 3, 4>> b;// 每个元素都设置固定值b.setConstant(3.f);for (int i = 0; i < 2; i++) {for (int j = 0; j < 3; j++) {for (int k = 0; k < 4; k++) {std::cout << b(i, j, k) << " ";}std::cout << std::endl;}std::cout << std::endl << std::endl;}

输出:

3 3 3 3
3 3 3 3
3 3 3 3 3 3 3 3
3 3 3 3
3 3 3 3

4、常用函数API

1.维度

  Eigen::Tensor<float, 2> a(3, 4);std::cout << "Dims " << a.NumDimensions;//=> Dims 2
  Eigen::Tensor<float, 2> a(3, 4);int dim1 = a.dimension(1);std::cout << "Dim 1: " << dim1;//=> Dim 1: 4

2.形状

  Eigen::Tensor<float, 2> a(3, 4);const Eigen::Tensor<float, 2>::Dimensions& d = a.dimensions();std::cout << "Dim size: " << d.size << ", dim 0: " << d[0]<< ", dim 1: " << d[1];//=> Dim size: 2, dim 0: 3, dim 1: 4

3.矩阵元素个数

  Eigen::Tensor<float, 2> a(3, 4);std::cout << "Size: " << a.size();//=> Size: 12

4.初始化

  /// 1.// setConstant(const Scalar& val),用于把一个矩阵的所有元素设置成一个指定的常数。Eigen::Tensor<string, 2> a(2, 3);a.setConstant("yolo");std::cout << "String tensor: " << endl << a << endl << endl;//=>// String tensor:// yolo yolo yolo// yolo yolo yolo/// 2.// setZero() 全部置零a.setZero();/// 3.// setRandom() 随机初始化a.setRandom();std::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/// 4.// setValues({..initializer_list}) 从列表、数据初始化Eigen::Tensor<float, 2> a(2, 3);a.setValues({{0.0f, 1.0f, 2.0f}, {3.0f, 4.0f, 5.0f}});std::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}});std::cout << "a" << endl << a << endl << endl;//=>// a// 10   20   30// 1000 1000 1000

参考: Eigen::Tensor使用,定义高维矩阵

参考:官方 张量说明 Eigen-unsupported 3.4.0 (git rev e3e74001f7c4bf95f0dde572e8a08c5b2918a3ab)

5、矩阵乘法与广播机制

使用Eigen的Tensor缘由
之所以使用Eigen的Tensor,主要是因为Tensorflow中的一个C++项目中,需要对graph中得到的Tensor进行数据后处理。而tensorflow的C++API中用到了Eigen这个矩阵运算库中的Tensor,所做了些笔记。该笔记主要参考[Eigen-unsupport这个官方的文档(英文),并以此为基础记录一些与numpy对应的函数与技巧。

Tensor的矩阵乘法操作

Eigen中的Tensor中重载了*并用于实现点对点相乘和与标量相乘。关于点对点相乘,需要注意的是两个tensor的shape必须相同才能相乘,如果需要像numpy那样实现大小矩阵相乘(广播机制),需要自己设置广播,如下:

#include <Eigen/Dense>
Eigen::Tensor<float, 2, 1> a(3, 2);
Eigen::Tensor<float, 2, 1> b(1, 2);
a.setConstant(2.0);
b.setConstant(3.0);
Eigen::array<int, 2> bcast = { 3, 1 };//第一维复制3倍
auto ab = a*b.broadcast(bcast);
cout<<ab<<endl;
-----------------------
6 6
6 6
6 6

如果是要实现Tensor的内积,则需要使用tensor的contract函数,可以实现高维的矩阵内积,如下:

Eigen::Tensor<int, 2> a(2, 3);
a.setValues({{1, 2, 3}, {6, 5, 4}});
Eigen::Tensor<int, 2> b(3, 2);
b.setValues({{1, 2}, {4, 5}, {5, 6}});
Eigen::array<Eigen::IndexPair<int>, 1> product_dims = { Eigen::IndexPair<int>(1, 0) };
Eigen::Tensor<int, 2> AB = a.contract(b, product_dims);
cout<<a<<endl<<b<<endl<<AB<<endl;
----------------------------------
1 2 3
6 5 4
1 2
4 5
5 6
24 30
46 61

Tensor的reshape操作

Tensor中的reshape靠TensorMap这种数据类型实现。

float nums[12] = { 0, 100, 200 , 300, 400, 500,600, 700, 800,900, 1000, 1100 };
Eigen::TensorMap<Eigen::Tensor<float, 2, 1>> a(nums, 4, 3);
Eigen::TensorMap<Eigen::Tensor<float, 2, 1>> b(a.data(), 2, 6);
----------------------
a0  100  200300  400  500600  700  800900 1000 1100
b0  100  200  300  400  500600  700  800  900 1000 1100

Tensor的堆叠(stack)操作

Tensor的堆叠,如两个(2,2)的tensor堆叠为(2,2,2),也可以实现拼接(4,2),(2,4)。

Eigen::Tensor<float, 2, 1> a(2, 2);
Eigen::Tensor<float, 2, 1> 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<Eigen::DenseIndex, 3> three_dim(3,2,1);
Eigen::Tensor<float, 3, 1> ab2 = a.reshape(three_dim).concatenate(b.reshape(three_dim), 2)  //(2,2,2)

Tensor的find(where)操作
Tensor中没有matlab中的find或者python中numpy里的where,用于寻找满足条件的元素的下标。这里用到的思路是首先通过比较(><的符号Eigen已经重载),考虑到tensor的内存是连续存储的,通过遍历每个元素,计算满足的元素的下标。由于下面的代码中已经设置了Tensor为行优先存储,下标计算如下所示。

class getthree_index
{public:vector<int>* fir_dim;vector<int>* sec_dim;vector<int>* thi_dim;int fir, sec, thi;int idx = 0;getthree_index(vector<int>* f, vector<int>* s, vector<int>* 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<Eigen::Tensor<float, 3, 1>> a(nums, 2, 3, 2);
auto threshold = a.constant(400);
Eigen::Tensor<bool, 3, 1> res = a>threshold.eval();
vector<int> fir_dim;
vector<int> sec_dim;
vector<int> 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])));

参考:Eigen中Tensor的使用技巧

Eigen库学习笔记(四)Eigen用于三维张量相关推荐

  1. Eigen库学习笔记(五)张量计算

    Eigen库学习笔记(五)张量计算 1.规约操作 2.最值与索引 3.按索引取值 Array of indices 4.类似 where的功能,生成mask 5.reshape 改变形状元素个数不变 ...

  2. Eigen库学习笔记(十三)Eigen实现softmax

    Eigen库学习笔记(十三)Eigen实现softmax 1.pytorch中的softmax 2.Eigen实现softmax 1.pytorch中的softmax 示例: import torch ...

  3. eigen库学习笔记(2)

    这里主要整理矩阵运算相关内容.其中备注了与Matlab的命令对比. eigen库的矩阵运算 Eigen 矩阵定义 Eigen 基础使用 Eigen 特殊矩阵生成 Eigen 矩阵分块 Eigen 矩阵 ...

  4. eigen库学习笔记

    #简介 Eigen是有关线性代数(矩阵.向量等)的c++模板库.支持SSE2/3/4, ARM NEON (32-bit and 64-bit), PowerPC AltiVec/VSX (32-bi ...

  5. STM32 HAL库学习笔记4-SPI

    STM32 HAL库学习笔记4-SPI 前言 一.SPI协议简介 SPI物理层 SPI协议层 1.基本通讯过程 2. 通讯的起始和停止信号 3. 数据有效性 4. CPOL/CPHA 及通讯模式 二. ...

  6. STM32F103学习笔记四 时钟系统

    STM32F103学习笔记四 时钟系统 本文简述了自己学习时钟系统的一些框架,参照风水月 1. 单片机中时钟系统的理解 1.1 概述 时钟是单片机的脉搏,是单片机的驱动源 用任何一个外设都必须打开相应 ...

  7. 华清远见fs4412开发板学习笔记(四)

    fs4412开发板学习笔记(四) 今天的课程安排 1.复习 1.1 VIM 编辑器 [1] vim + filename 打开 [2] 工作模式 命令模式 编辑模式 底行模式 [3] 模式切换 命令- ...

  8. 【http学习笔记四】安全篇

    [http学习笔记四]安全篇 文章目录 [http学习笔记四]安全篇 一.HTTPS 与 SSL/TLS ① 什么是安全? 机密性 完整性 身份认证 不可否认 ② 什么是HTTPS? ③ SSL/TL ...

  9. Python pillow库学习笔记

    Python pillow库学习笔记 PIL( Python Imaging Library)是 Python 的第三方图像处理库,由于其功能丰富,API 简洁易用,因此深受好评. 自 2011 年以 ...

最新文章

  1. c语言 10以内加法,求助 给小学生出题,自己选加减乘除 做10题 10以内的数 然后统计分...
  2. 快速打开unity manual的方式
  3. 网站安全狗”响应内容保护“网页错误返回页面优化功能介绍
  4. Knative 多容器支持介绍
  5. 如何打开设计思路,避免不断改稿?只需提前做好这一步
  6. 排序算法 —— 选择排序
  7. 太牛了!芯片级拆解世界第一颗FPGA芯片!
  8. 从零开始用好 Maven : 从 Hello World 到日常使用
  9. JAVA生成pdf文件
  10. 音频信号频率测试软件,音频信号发生器软件(MyToneTest)
  11. Au入门系列之五:轨道与轨道控制​
  12. 研究生论文写作心得体会
  13. 转 波束成形 Beamforming 简述
  14. Python 中拼音库 PyPinyin 的使用
  15. mysql where in and_mysql中 where in 用法详解
  16. spring 容器启动执行重置定时任务
  17. 调试输出信息OutPutDebugString
  18. VS插件--Resharper
  19. STM32玩转物联网实战篇:01.网络通信前准备
  20. libjpeg库的简单使用,rgb565与rgb888互转,以及色块的寻找

热门文章

  1. 手写Web服务器(三)
  2. 一款数据挖掘软件——WEKA
  3. 【Vue路由】多级路由、路由传参、命名路由、params使用
  4. RuntimeError: CUDA out of memory. Tried to allocate 20.00 MiB解决方案
  5. 纳皮尔筹——老外是如何「运筹帷幄」的
  6. http 415 unsupported media type的一种解决办法
  7. matplotlib绘制sin函数图像
  8. 如何在csdn关掉百度广告
  9. hihocoder 1505
  10. C++ 编写一个不可复制的类