【发布时间】:2017-03-16 08:07:34
【问题描述】:
我有一些矩阵运算,主要处理诸如遍历矩阵的所有行和列并执行乘法运算a*mat[i,j]*mat[ii,j]:
public double[] MaxSumFunction()
{
var maxSum= new double[vector.GetLength(1)];
for (int j = 0; j < matrix.GetLength(1); j++)
{
for (int i = 0; i < matrix.GetLength(0); i++)
{
for (int ii = 0; ii < matrix.GetLength(0); ii++)
{
double wi= Math.Sqrt(vector[i]);
double wii= Math.Sqrt(vector[ii]);
maxSum[j] += SomePowerFunctions(wi, wii) * matrix[i, j]*matrix[ii, j];
}
}
}
}
private double SomePowerFunctions(double wi, double wj)
{
var betaij = wi/ wj;
var numerator = 8 * Math.Sqrt(wi* wj) * Math.Pow(betaij, 3.0 / 2)
* (wi+ betaij * wj);
var dominator = Math.Pow(1 - betaij * betaij, 2) +
4 * wi* wj* betaij * (1 + Math.Pow(betaij, 2)) +
4 * (wi* wi+ wj* wj) * Math.Pow(betaij, 2);
if (wi== 0 && wj== 0)
{
if (Math.Abs(betaij - 1) < 1.0e-8)
return 1;
else
return 0;
}
return numerator / dominator;
}
如果矩阵很大,我发现这样的循环会特别慢。
我希望速度快。所以我正在考虑使用 Eigen 库重新实现这些算法。
我的矩阵不是对称的,不是稀疏的,并且不包含任何求解器都可以可靠利用的规律性。
我读到 Eigen solver can be fast 是因为:
- 编译器优化
- 矢量化
- Multi-thread support
但我想知道考虑到我的矩阵特性,这些优势是否真的适用?
注意:我可以运行一两个样本来找出答案,但我相信在这里提出问题并将其记录在 Internet 上也会对其他人有所帮助。
【问题讨论】:
-
我不明白......如果你只需要性能,你为什么不使用一些低级别的东西,比如 OpenBLAS?为什么你需要重新发明人们花了几十年时间优化的矩阵乘法?您在那里标记的操作:
mat[i,j]*mat[ii,j],只是矩阵乘法与转置mat[j,ii]。任何 BLAS 接口库都可以为您做到这一点。顺便说一句,像这样循环是最慢的方法。如果您可以使用std::transform执行此操作,您仍然可以获得更好的性能,这将为您启用矢量化。 -
@TheQuantumPhysicist, 1)
mat[i,j]*mat[ii,j]这不是转置操作 2),我正在使用 C#,所以std::transform没有帮助 3) 我认为没有理由更喜欢 OpenBlas 而不是 Eigen,我很了解 Eigen,但 OpenBlas 不是这样。 -
我从没说过它是转置运算,我说它是与
mat[ii,j]的转置相乘,所以它是mat[i,j]*Tr(mat[j,ii]),它意味着这个操作可以简化为矩阵乘法,并且由于矩阵乘法是本书中最古老的问题,你应该考虑使用 BLAS,因为它是线性代数的库。如果它是专门的 OpenBLAS(这是 BLAS 的一种实现)并不重要,但是,同样,你会在那里重新发明轮子。我遇到了大小超过 10000x10000 的矩阵乘法的量子力学问题,所以看看 BLAS。 -
@TheQuantumPhysicist,很好的解释。让我看看
-
@TheQuantumPhysicist,我不认为这可以直接转换为矩阵-矩阵乘积,因为求和不适用于公共索引
j。另一方面,如果您将f(wi,wii)视为一个矩阵,那么您可以做一些事情......此外,Eigen 提供了与其他优化的 BLAS 实现相似的性能量级,它还公开了一个 BLAS 兼容的 API,并且可以使用另一个 BLAS 实现....