8

我需要f(x)=exp(A*x)反复计算一个微小的可变列向量x和一个巨大的常量矩阵A(多行,几列)。换句话说,x很少,但A*x很多。我的问题维度是这样的,它A*x需要与 exp() 部分一样多的运行时间。

除了泰勒展开和预先计算一系列值exp(y)(假设已知 的y值范围A*x),相对于 MATLAB 自己所做的事情,我还没有设法显着加快(同时保持准确性),我是考虑分析重述问题,以便能够预先计算一些值。

例如,我发现exp(A*x)_i = exp(\sum_j A_ij x_j) = \prod_j exp(A_ij x_j) = \prod_j exp(A_ij)^x_j

这将允许我预先计算exp(A)一次,但循环中所需的求幂与原始函数调用一样昂贵exp(),并且必须另外执行乘法 (\prod)。

有没有我可以遵循的其他想法,或者我可能错过的 MATLAB 中的解决方案?

编辑:更多细节

A是 26873856 x 81 的大小(是的,它是那么大),所以x是 81 x 1。 nnz(A) / numel(A)0.0012nnz(A*x) / numel(A*x)0.0075。我已经使用稀疏矩阵来表示A,但是,稀疏矩阵的 exp() 不再是稀疏的。所以事实上,我存储xnon-sparse 并且我计算exp(full(A*x))结果是快/慢full(exp(A*x))(我认为A*x无论如何都是非稀疏的,因为 x 是非稀疏的。)exp(full(A*sparse(x)))是一种拥有 sparse 的方法A*x,但速度较慢. 甚至更慢的变体是exp(A*sparse(x))(对于稀疏类型的非稀疏矩阵具有双倍的内存影响)和full(exp(A*sparse(x))(这再次产生非稀疏结果)。

sx = sparse(x);
tic, for i = 1 : 10, exp(full(A*x)); end, toc
tic, for i = 1 : 10, full(exp(A*x)); end, toc
tic, for i = 1 : 10, exp(full(A*sx)); end, toc
tic, for i = 1 : 10, exp(A*sx); end, toc
tic, for i = 1 : 10, full(exp(A*sx)); end, toc

Elapsed time is 1.485935 seconds.
Elapsed time is 1.511304 seconds.
Elapsed time is 2.060104 seconds.
Elapsed time is 3.194711 seconds.
Elapsed time is 4.534749 seconds.

是的,我确实计算了元素 exp,我更新了上面的等式以反映这一点。

另一个编辑:我试图变得聪明,但收效甚微:

tic, for i = 1 : 10, B = exp(A*x); end, toc
tic, for i = 1 : 10, C = 1 + full(spfun(@(x) exp(x) - 1, A * sx)); end, toc
tic, for i = 1 : 10, D = 1 + full(spfun(@(x) exp(x) - 1, A * x)); end, toc
tic, for i = 1 : 10, E = 1 + full(spfun(@(x) exp(x) - 1, sparse(A * x))); end, toc
tic, for i = 1 : 10, F = 1 + spfun(@(x) exp(x) - 1, A * sx); end, toc
tic, for i = 1 : 10, G = 1 + spfun(@(x) exp(x) - 1, A * x); end, toc
tic, for i = 1 : 10, H = 1 + spfun(@(x) exp(x) - 1, sparse(A * x)); end, toc

Elapsed time is 1.490776 seconds.
Elapsed time is 2.031305 seconds.
Elapsed time is 2.743365 seconds.
Elapsed time is 2.818630 seconds.
Elapsed time is 2.176082 seconds.
Elapsed time is 2.779800 seconds.
Elapsed time is 2.900107 seconds.
4

1 回答 1

2

计算机并没有真正做指数。你会认为他们这样做,但他们所做的是高精度多项式逼近。

参考:

最后一个参考看起来很不错。也许它应该是第一个。

由于您正在处理图像,因此您可能具有离散数量的强度级别(通常为 255)。这可以减少采样或查找,具体取决于“A”的性质。检查这一点的一种方法是对具有足够代表性的“x”值组执行以下操作:

y=Ax
cdfplot(y(:))

如果您能够将图像预分割为“更有趣”和“不那么有趣” - 就像您正在看 X 光片,能够修剪出所有“人体外部”位置并将它们夹在零来预先稀疏您的数据,这可能会减少您的唯一值数量。对于数据中的每个唯一“模式”,您可能会考虑前一个。

我的方法包括:

  • 查看精度较低但速度较高的 exp(x) 的替代公式
  • 如果您的“x”级别足够少,请考虑查找表
  • 如果您有“稍微太多”的级别来进行表查找,请考虑插值和表查找的组合
  • 考虑基于分段模式的单个查找(或替代公式)。如果您知道它是一根骨头并且正在寻找一根静脉,那么也许它应该应用较少的高成本数据处理。

现在我不得不问自己,为什么你会生活在如此多的 exp(A*x)*x 迭代中,我认为你可能会在频率/波数域和时间/空间域之间来回切换。您还可能正在使用 exp(x) 作为基础来处理概率,并做一些贝叶斯的乐趣。我不知道 exp(x) 是一个很好的先验共轭,所以我将使用傅立叶材料。

其他选项: - 考虑使用 fft、fft2 或 fftn 给定您的矩阵 - 它们速度很快,可能会满足您的需求。

我确信以下内容存在更前沿的域变化:

您也许可以使用woodbury 矩阵将查找与计算混合。不过,我必须考虑一些才能确定。(链接) 在某一时刻,我知道所有重要的事情(CFD、FEA、FFT)都是关于矩阵求逆的,但我已经忘记了具体的细节。

现在,如果您住在 MatLab 中,那么您可以考虑使用“coder”,它将 MatLab 代码转换为 c 代码。无论解释器多么有趣,一个好的 c 编译器都可以快得多。我使用的助记符(希望不要太雄心勃勃)如下所示:链接开始于 13:49 左右。这真的很简单,但它显示了规范解释语言(python)和相同的编译版本(cython/c)之间的区别。

我敢肯定,如果我有一些更具体的信息并被要求提供,那么我可以更积极地参与更具体的相关答案。

您可能没有在传统硬件上执行此操作的好方法,购买您可能会考虑使用 GPGPU 之类的东西。CUDA 及其同行具有大规模并行操作,可以以少量视频卡的成本大幅加速。您可以有数千个“核心”(过分夸大的管道)来完成一些 ALU 的工作,如果该工作可以适当地并行化(看起来像这样),那么它可以更快地完成。

编辑:

我在想Eureqa。如果我有一些“大铁”用于开发而不是生产,我会考虑的一个选择是使用他们的 Eureqa 产品来提出足够快、足够准确的近似值。

如果您对“A”矩阵执行“快速”奇异值分解,您会发现主要性能由 81 个特征向量控制。我会查看特征值,看看这 81 个特征向量中是否只有少数几个提供了大部分信息。如果是这种情况,那么您可以将其他的钳位为零,并构造一个简单的变换。

现在,如果是我,我想从指数中得到“A”。我想知道您是否可以查看 81x81 特征向量矩阵和“x”并考虑一下线性代数,以及您将向量投影到什么空间。有什么方法可以制作如下所示的函数:

f(x) = B2 * exp( B1 * x )

使得

B1 * x

比你现在的排名小很多

斧头。

于 2014-05-05T14:03:04.773 回答