我想用一个三维特征::Tensor来替换代码中的一系列矩阵。考虑到这一点,我尝试比较Tensor和矩阵的性能。
下面的函数“tensorContractTest”将(n,n,n)秩为3的Tensor与大小为n(n = 500)的秩为1的Tensor进行收缩,该收缩计算n**2个点积,因此就运算次数而言,它等效于两个(n,n)矩阵的乘法(下面的函数“matrixProductTest”)。
当在Visual Studio 2013上运行时,函数“TensorContractTest”的运行速度比“MatrixProductTest”慢40倍。可能是我漏掉了什么。请提供帮助。
#include <unsupported/Eigen/CXX11/Tensor>
using namespace Eigen;
// Contracts 3-dimensional (n x n x n) tensor with 1-dimensional (n) tensor.
// By the number of operations, it's equivalent to multiplication of
// two (n, n) matrices (matrixProdTest).
Tensor<double, 2> tensorContractTest(int n)
{
Tensor<double, 3> a(n, n, n); a.setConstant(1.);
Tensor<double, 1> b(n); b.setConstant(1.);
auto indexPair = array<IndexPair<int>, 1>{IndexPair<int>(2,0)};
Tensor<double, 2> result = a.contract(b, indexPair);
return result;
}
MatrixXd matrixProductTest(int n)
{
MatrixXd a = MatrixXd::Ones(n, n), result = a * a;
return result;
}
3条答案
按热度按时间cpjpxq1n1#
虽然浮点运算的次数是相同的,但存取模式却完全不同,因此两者的运算根本无法比较,一般而言,矩阵对矩阵的运算总是比较快(就FLOPS而言)比矩阵-向量或向量-向量运算更有效,因为前者可以更好地利用高速缓存,从而使CPU的ALU得到近乎最佳的利用。在您的情况下,一方面,你必须读取一个n^3Tensor和两个n^2矩阵,所以内存占用根本不可比。
在内部,
Tensor::contract
在可能的情况下回退到Eigen的矩阵乘积内核,因此性能应该成对。klsxnrf12#
因为Tensor收缩和矩阵乘法不一样。
存在矩阵乘法的专用算法,如斯特拉森算法,减少了运算总数。此外,矩阵库多年来已得到高度优化,因此它们通常专用于使用矢量化指令(SIMD或AVX),具体取决于平台(Intel、AMD、ARM)。对于小尺寸或稀疏模式的矩阵,与非专用代码相比,速度增益巨大。
相比之下,Tensor库往往没有那么优化,所以如果你能把你的Tensor数学转换成矩阵代数,速度有很多机会会提高。
4uqofj5v3#
我可以用谷歌的基准测试程序重现这种缓慢的速度,正如我测试的那样,如果数据量很小,特征矩阵乘法比特征Tensor收缩更快,但结果是一样的。
所以我不确定后备计划
在内部,Tensor::合同在可能的情况下回退到特征矩阵乘积内核,因此性能应该成对。
@ggael在这里提到。
下面是我的测试代码:
,其中I、J和K
用相同的数字填充,范围从1到8。
我用Bazel编译,编译命令是
build --cxxopt=-std=c++17 --cxxopt=-march=native --cxxopt=-O3 --cxxopt=-DNDEBUG
,Eigen的版本是3.4.0。