【问题标题】:Optimizing a program by vectorized notation通过向量化符号优化程序
【发布时间】:2014-03-25 05:41:21
【问题描述】:

大家好,我正在从事图像处理工作,并在 MATLAB 中编写了一小段代码。代码很慢。

我在这里给出我的代码 sn-p

for i=1:10
    //find c1,c2,c3
    //c1 c2 and c3 change at each iteration

    u = (1./((abs(P-c1))^m) + 1./((abs(P-c2))^m) + 1./((abs(P-c3))^m));
    u1 = 1./((abs(P-c1))^m)./u;
    u2 = 1./((abs(P-c2))^m)./u;    
    u3 = 1./((abs(P-c3))^m)./u;
end

让我在这里解释一下变量:

P,u,u1,u2 and u3 are all matrices of size 512x512
c1,c2 and c3 are constants of dimension 1x1
m is a constant with value = 2

我想在循环中重复此操作(比如 10 次)。但是我的代码很慢。

分析器的结果如下:

程序的总运行时间为 4.6 秒。然而,上面列出的四个步骤本身需要大约 80% 的时间。

所以我想让我的代码运行更快我的第一次编辑

我修改后的代码sn-p

for i=1:10

    //find c1 and c2
    //c1 and c2 changes at each iteration

    a=((abs(P-c1))^m); 
    b=((abs(P-c2))^m); 
    c=((abs(P-c3))^m);

    x=1./a; y=1./b; z=1./c;
    u = (x + y + z);
    u1 = x./u;
    u2 = y./u;    
    u3 = z./u;
end

现在程序计算上述步骤的计算时间为 2.47 秒:

所以这比我的第一种方法快得多。

第二次修改 对于 i=1:10 //找到c1,c2,c3 //c1 c2 和 c3 在每次迭代时改变

    a=(P-c1).*(P-c1); 
    b=(P-c2).*(P-c2); 
    c=(P-c3).*(P-c3);

    x=1./a; y=1./b; z=1./c;
    u = (x + y + z);
    u1 = x./u;
    u2 = y./u;    
    u3 = z./u;
end

现在程序计算时间为 0.808 秒。

上面描述的四个步骤计算上面的速度非常快。

我相信它可以做得更快。你们能帮我进一步优化 我的代码。 这对于大于 512 的矩阵(例如 1024 、 2048 等)非常有用。

提前致谢。

【问题讨论】:

  • 为什么要使用图像处理标签?性能标签更有意义。
  • 对,但是如果在帖子中,则没有图像处理相关的问题。最好不要提及。这有助于让更多人参与该领域。
  • @roni 你说你在一个循环中运行了四行 10 次。那么这 10 个 for 循环中发生了什么变化。所有的矩阵,即P,u,u1,u2 and u3 都在变化吗?我的第二个问题是,你有这 10 个矩阵吗?如果您可以发布整个 for 循环会更好。
  • @roni 我不能对这么多信息发表太多评论。原因如下: 1、如果找到c1, c2, c3的过程是不可向量化的,那么目前也做不了多少。 2. 如果可以向量化,那么实际上我们可以使用c1,c2,c3 作为10x1 数组并同时计算所有10 个值的u,u1,u2,u3。 3. 我能给你的最后一个建议是,尝试将其转换为parfor 循环,看看是否有什么不同。
  • 您的优化不等同于您的原始代码。 A^m 是矩阵幂。 A^2 是 AA,就像在矩阵乘法中一样。但是,您的新代码编写的是 A.*A,它是逐个元素的乘法,速度要快得多。那你想要哪个?每个元素平方(A.^2 或 A.*A),还是矩阵平方(A^2 或 AA)?

标签: performance matlab optimization performance-testing


【解决方案1】:

您当前的代码是:

a=((abs(P-c1))^m); 
b=((abs(P-c2))^m); 
c=((abs(P-c3))^m);

x=1./a; y=1./b; z=1./c;
u = (x + y + z);
u1 = x./u;
u2 = y./u;    
u3 = z./u;

首先,认识到绝对值函数是乘法的。所以|AB| = |A|x|B|。现在,abs(P-C1)^m 等价于 abs( (P-C1)^m )

初步看一眼就表明瓶颈中的一些计算可以重用。具体来说,由于c1c2c3 是常量,因此如果您尝试重用它们(以增加内存为代价),计算速度会稍微加快。

temp_P2 = P*P;
temp_PCA = P*ones(size(P));
temp_PCB = ones(size(P))*P;

a = abs(temp_P2 - c1*temp_PCA - c1*temp_PCB + c1^2 * length(P))

temp_PCAtemp_PCB 的计算也可以避免,因为乘以常数矩阵总是等于构造具有常数行或列的秩 1 矩阵。

我并不声称这些修改中的任何一个都会加快您的代码速度,但它们绝对值得一试。

【讨论】:

  • 您能否详细说明您的步骤。我无法理解您计算矩阵的方式。你只是扩展了方程吗?
  • 你好。我试过你的建议。不幸的是,它增加了计算时间。看起来 (P-c1).*(P-c1) 的计算速度比您编辑的看起来要快。无论如何感谢您的帮助。我会非常高兴听到更多消息。
  • @roni。是的,我只是扩展了矩阵方程。另外,请注意,如果m=2,您仍然需要abs 符号。 (NKN 和我认为这是多余的,但我能够找到一个反例)。
  • @roni abs 在 MATLAB 中采用每个元素的绝对值。如果您有一个矩阵AA^2 不一定使每个元素都为正。考虑A = [1 -2; -2 1]A*A = [5 -4; -4 5]。但是,abs(A*A) = [5 4 ; 4 5].
  • @roni 你把元素平方和矩阵平方混淆了。
【解决方案2】:

第一个建议是:

如果 m = 2 并且它没有改变,为什么不尝试这些替代方案:

A*A

如果 m = 2 那么你真的需要 abs 吗?

你正在做的这部分

1./a

a.^(-1)

所以我在这部分没有看到更好的选择。

您可以尝试的另一件事是这个。而不是:

x=1./a; y=1./b; z=1./c;
    u = (x + y + z);
    u1 = x./u;
    u2 = y./u;    
    u3 = z./u;

你可以有这个:

    u = (x + y + z);
    u1 = 1./(a.*u);
    u2 = 1./(b.*u);    
    u3 = 1./(c.*u);

这样我想通过删除 3 个变量会快一点。但是代码变得不那么可读了。

【讨论】:

  • 使用了您的有用建议!请看结果。您想提出任何进一步的修改建议吗?
  • 抱歉,您能否重新检查您编辑的部分。我相信这是错误的。例如:u1 = x./u = 1./u./x 而不是 1./(a.*u)
  • 例如 x=1./a 和 u1=x./u;然后我们可以将第二个公式中的 x 替换为 1./a。结果是 u1=1./(a./u);那么,1./(a.*u) 是正确的(在 MATLAB 中也检查过)为什么会出错?
猜你喜欢
  • 2021-02-05
  • 1970-01-01
  • 2021-04-01
  • 2011-01-11
  • 2012-10-15
  • 2021-06-27
  • 2012-10-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多