模糊矩阵乘法matlab,性能-通过空矩阵乘法初始化数组的更快方法? (Matlab)

结果可能会产生误导。 当您将两个空矩阵相乘时,生成的矩阵不会立即“分配”和“初始化”,而是会推迟到您第一次使用它时(有点像惰性计算)。

当索引超出范围以增长变量时,情况也是如此,在数字数组的情况下,该变量用零填充所有缺失的条目(我将在后面讨论非数字的情况)。 当然,以这种方式生长矩阵不会覆盖现有元素。

因此,虽然看起来更快,但是您只是在延迟分配时间,直到您真正开始使用矩阵。 最后,您将拥有与开始时一样的分配时间。

与其他几种选择相比,展示此行为的示例:

N = 1000;

clear z

tic, z = zeros(N,N); toc

tic, z = z + 1; toc

assert(isequal(z,ones(N)))

clear z

tic, z = zeros(N,0)*zeros(0,N); toc

tic, z = z + 1; toc

assert(isequal(z,ones(N)))

clear z

tic, z(N,N) = 0; toc

tic, z = z + 1; toc

assert(isequal(z,ones(N)))

clear z

tic, z = full(spalloc(N,N,0)); toc

tic, z = z + 1; toc

assert(isequal(z,ones(N)))

clear z

tic, z(1:N,1:N) = 0; toc

tic, z = z + 1; toc

assert(isequal(z,ones(N)))

clear z

val = 0;

tic, z = val(ones(N)); toc

tic, z = z + 1; toc

assert(isequal(z,ones(N)))

clear z

tic, z = repmat(0, [N N]); toc

tic, z = z + 1; toc

assert(isequal(z,ones(N)))

结果显示,如果对两种情况下的两条指令的经过时间进行求和,最终将得到相似的总计时:

// zeros(N,N)

Elapsed time is 0.004525 seconds.

Elapsed time is 0.000792 seconds.

// zeros(N,0)*zeros(0,N)

Elapsed time is 0.000052 seconds.

Elapsed time is 0.004365 seconds.

// z(N,N) = 0

Elapsed time is 0.000053 seconds.

Elapsed time is 0.004119 seconds.

其他时间是:

// full(spalloc(N,N,0))

Elapsed time is 0.001463 seconds.

Elapsed time is 0.003751 seconds.

// z(1:N,1:N) = 0

Elapsed time is 0.006820 seconds.

Elapsed time is 0.000647 seconds.

// val(ones(N))

Elapsed time is 0.034880 seconds.

Elapsed time is 0.000911 seconds.

// repmat(0, [N N])

Elapsed time is 0.001320 seconds.

Elapsed time is 0.003749 seconds.

这些测量值在毫秒内太小,可能不太准确,因此您可能想循环运行这些命令数千次并取平均值。 另外有时运行保存的M函数比运行脚本或在命令提示符下运行更快,因为某些优化只会以这种方式发生...

无论哪种方式,分配通常都会执行一次,因此谁在乎是否需要额外的30毫秒:)

单元格阵列或结构阵列可以看到类似的行为。 考虑以下示例:

N = 1000;

tic, a = cell(N,N); toc

tic, b = repmat({[]}, [N,N]); toc

tic, c{N,N} = []; toc

这使:

Elapsed time is 0.001245 seconds.

Elapsed time is 0.040698 seconds.

Elapsed time is 0.004846 seconds.

请注意,即使它们都相等,它们占用的内存量也不同:

>> assert(isequal(a,b,c))

>> whos a b c

Name Size Bytes Class Attributes

a 1000x1000 8000000 cell

b 1000x1000 112000000 cell

c 1000x1000 8000104 cell

实际上,这里的情况更加复杂,因为MATLAB可能为所有单元共享相同的空矩阵,而不是创建多个副本。

单元格数组mxCreateUninitDoubleMatrix实际上是未初始化的单元格数组(NULL指针的数组),而mxCreateUninitNumericArray是单元格数组,其中每个单元格都是空数组mxCreateUninitNumericMatrix(内部并且由于数据共享,只有第一个单元格b{1}指向[] 而其余所有都引用第一个单元格)。 最终数组c与a(未初始化的单元格)相似,但最后一个数组包含空数值矩阵[]。

我浏览了mxCreateUninitDoubleMatrix(使用Dependency Walker工具)导出的C函数的列表,发现了一些有趣的东西。

有一些未记录的函数可用于创建未初始化的数组:mxCreateUninitDoubleMatrix,mxCreateUninitNumericArray和mxCreateUninitNumericMatrix。实际上,文件交换上有一个提交使用这些函数为mxCalloc函数提供了更快的替代方法。

有一个未记录的函数,名为mxCalloc。在线搜索,我可以看到您也将这个问题交叉发布在MATLAB Answers上,那里有一些出色的答案。 James Tursa(之前是UNINIT的同一作者)举了一个有关如何使用此未记录功能的示例。

mxCalloc与mxMalloc共享库链接。 这是Intel TBB可扩展内存分配器。 该库提供了针对并行应用程序优化的等效内存分配功能(mxRealloc、calloc、free)。 请记住,许多MATLAB函数是自动多线程的,因此如果矩阵大小足够大,如果zeros(..)是多线程的并且正在使用Intel的内存分配器,我不会感到惊讶(这是Loren Shure的最新评论证实了这一事实)。

关于内存分配器的最后一点,您可以在C / C ++中编写类似于@PavanYalamanchili的基准,并比较可用的各种分配器。 这样的事情。 请记住,MEX文件的内存管理开销略高,因为MATLAB使用mxCalloc、mxMalloc或mxRealloc函数会自动释放MEX文件中分配的所有内存。 值得一试的是,以前可以在旧版本中更改内部内存管理器。

编辑:

这是一个比较详尽的基准,用于比较讨论的替代方案。 它具体表明,一旦强调使用整个分配的矩阵,所有这三种方法都处于平等地位,并且差异可以忽略不计。

function compare_zeros_init()

iter = 100;

for N = 512.*(1:8)

% ZEROS(N,N)

t = zeros(iter,3);

for i=1:iter

clear z

tic, z = zeros(N,N); t(i,1) = toc;

tic, z(:) = 9; t(i,2) = toc;

tic, z = z + 1; t(i,3) = toc;

end

fprintf('N = %4d, ZEROS = %.9f\n', N, mean(sum(t,2)))

% z(N,N)=0

t = zeros(iter,3);

for i=1:iter

clear z

tic, z(N,N) = 0; t(i,1) = toc;

tic, z(:) = 9; t(i,2) = toc;

tic, z = z + 1; t(i,3) = toc;

end

fprintf('N = %4d, GROW = %.9f\n', N, mean(sum(t,2)))

% ZEROS(N,0)*ZEROS(0,N)

t = zeros(iter,3);

for i=1:iter

clear z

tic, z = zeros(N,0)*zeros(0,N); t(i,1) = toc;

tic, z(:) = 9; t(i,2) = toc;

tic, z = z + 1; t(i,3) = toc;

end

fprintf('N = %4d, MULT = %.9f\n\n', N, mean(sum(t,2)))

end

end

下面是根据矩阵大小增加而在100次迭代中平均的时序。 我在R2013a中进行了测试。

>> compare_zeros_init

N = 512, ZEROS = 0.001560168

N = 512, GROW = 0.001479991

N = 512, MULT = 0.001457031

N = 1024, ZEROS = 0.005744873

N = 1024, GROW = 0.005352638

N = 1024, MULT = 0.005359236

N = 1536, ZEROS = 0.011950846

N = 1536, GROW = 0.009051589

N = 1536, MULT = 0.008418878

N = 2048, ZEROS = 0.012154002

N = 2048, GROW = 0.010996315

N = 2048, MULT = 0.011002169

N = 2560, ZEROS = 0.017940950

N = 2560, GROW = 0.017641046

N = 2560, MULT = 0.017640323

N = 3072, ZEROS = 0.025657999

N = 3072, GROW = 0.025836506

N = 3072, MULT = 0.051533432

N = 3584, ZEROS = 0.074739924

N = 3584, GROW = 0.070486857

N = 3584, MULT = 0.072822335

N = 4096, ZEROS = 0.098791732

N = 4096, GROW = 0.095849788

N = 4096, MULT = 0.102148452

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值