学习笔记

V1.0 2015/4/17

如何加速MATLAB代码运行

概述

本文源于LDPCC的MATLAB代码,即《CCSDS标准的LDPC编译码仿真》。由于代码的问题,在信息位长度很长(大于10000)情况下,代码无法正常运行或执行速度很慢。本文将叙述代码修改过程中的一系列手段,然对其加速原理不做探究

修订历史

以下表格展示了本文档的修订过程

日期

版本号

修订内容

2015/04/17

V1.0

初始版本

简介

本程序基于MATLAB 2014a 编写,本文档中提到的"MATLAB"均指该特定版本MATLAB。代码运行结果测试机器是T530i i3 3110M 16G @1600MHz。

MATLAB的帮助文档 - Advancde Software Development - Performance and Memory中提及了一些改善代码性能的一些手段。比较通用的包括向量的预先分配内存,这一点在编辑器里也会提示。有时候预先分配内存与否和性能关系很大,譬如

tic

x = 0;

for i = 2:1000000

x(i) = x(i-1)+5;

end

toc

tic

x = zeros(1,1000000);

for i = 2:1000000

x(i) = x(i-1)+5;

end

toc

运行结果显示为"时间已过 0.500985 秒"和"时间已过 0.073622 秒"。另外在声明变量的时候不使用原有变量,而创建新变量也可以减少运行时间。还有包括选择'&'和'&&'的差异。

MATLAB还提供了一些改善性能的手段,包括

  • 将长脚本拆开成小段,调用执行;
  • 将大的代码块分开为独立的函数;
  • 将过分复杂的函数或是表达式采用简单的来代替;
  • 采用函数,而不是脚本;
  • 向量化代码,采用MATLAB自带的函数;
  • 采用矩阵的稀疏结构;
  • 运行MATLAB的时候不要在后台运行其他大的程序;
  • 不要重载任何MATLAB的内建函数或数据类型。

不得不说上面的技巧有很多是废话,而其中向量化是最有效的一种方法之一。向量化代码中有很多常用的函数,包括

函数

功能(暂略)

all

 

any

 

cumsum

 

diff

 

find

 

ind2sub

 

ipermute

 

logical

 

meshgrid

 

ndgrid

 

permute

 

prod

 

repmat

 

reshape

 

shiftdim

 

sort

 

squeeze

 

sub2ind

 

sum

 

在代码撰写修改过程中,可以多考虑考虑以上函数。

实例

实例来自于《CCSDS标准的LDPC编译码仿真》中代码(实际上有点点差别),代码优化从以下几个方面进行

  • 稀疏
  • 类型转换
  • 向量化

稀疏

仿真中的第一个困难在于ccsdscheckmatrix函数在输入SIZE_M很大的时候,先不说运行时间,直接就爆内存了。(输入参数4096,2/3)

先分析分析内存的问题,实际上这个函数的最后输出结果就是一个矩阵,这个矩阵的大小是12288×28672,计算double型的内存占用也就2G左右。但是函数运行过程中产生了很多中间变量没有清除。当然最后的解决办法也没有去管这些东西,由于矩阵H是稀疏矩阵,所以之际采用sparse后,这个运行就没有任何问题了。

对于矩阵H和H_sparse = spares(H),占用内存如下(当然H要是稀疏的,不然得不偿失)

Name     Size         Bytes      Class   Attributes

H       12288x28672   2818572288   double

H_sparse    12288x28672   1736712     double   sparse

也可以对比稀疏矩阵和原始矩阵的运行时间(和稀疏程度有关)

代码:tic;H*message';toc;

结果:时间已过 0.288934 秒。

代码:tic;H_sparse*message';toc;

结果:时间已过 0.001210 秒。

类型转换

MATLAB中的运算符支持多种类型,譬如矩阵乘法中多用double型变量,但如果一个矩阵是逻辑输入也没有关系。但运算速度差异较大,譬如

>> Gc_logic = Gc>0;

>> a=randi([0 1],1,16384);

>> tic;b = a*Gc;toc

时间已过 0.107618 秒。

>> tic;b = a*Gc_logic;toc

时间已过 0.503132 秒。

观测结果类型为double,我们可以大胆推测实际上逻辑型变量在运算过程中先转化为了double型(逻辑怎么乘呢?)另一个实验结果是

>> tic;Gc_logic=double(Gc_logic);b = a*Gc_logic;toc

时间已过 0.546412 秒。

这一定程度上证明了我们的假设。所以在运算过程中数据类型是重要的,如果上述乘法出现在循环内,那么实现转化矩阵类型是必要的。即使只运行一次,那么显式的转化矩阵类型(特制新建变量)也有好处。譬如

>> tic;Gt=double(Gc_logic);b = a*Gt;toc

时间已过 0.373506 秒。

通过创建新变量,运行速度些许。

向量化

向量化实际上是原代码修改中获益最大的方法,这实际上是因为原先的译码程序写了太多的循环。向量化后运行时间变成了原先的1/40 。当然,原先的代码通用性强,而向量化这个过程实际上是运用了H的一些结构的。译码函数太复杂,此处不做举例。

此处分析差分调制中的例子(实际上对这个程序没有什么影响)

原来的代码是这个样子的(更新值为其本身和前一个值的异或)

encodeData_extend = [1 encodeData];

for num = 2:length(encodeData_extend)

encodeData_extend(num) = xor(encodeData_extend(num),encodeData_extend(num-1));

end

向量化的结果为(累加模二代替异或)

encodeData1 = [1 encodeData];

encodeData1_sum = cumsum(encodeData1);

encodeData_2 = mod(encodeData1_sum,2);

运行时间分别为

时间已过 0.023424 秒。

时间已过 0.015003 秒。

虽然后者没有快很多,但这取决于向量的长度,长度大的话会有较大差距。

其他

MATLAB中提及的都能对代码运行速度带来细微的改进,包括

  • 将长脚本拆开成小段,调用执行;
  • 将大的代码块分开为独立的函数;
  • 将过分复杂的函数或是表达式采用简单的来代替;
  • 采用函数,而不是脚本;

上述测试脚本(和以上运行条件有差别)

%% 稀疏矩阵测试
M=;
theta=[ ];
fai=[ ];
A = zeros(M);
B = eye(M);
L = :M-;
for matrixNum = :
t_k = theta(matrixNum);
f_4i_M = floor(*L/M);
f_k = fai(f_4i_M+,matrixNum)';
col_1 = M/*(mod((t_k+f_4i_M),)) + ...
mod((f_k+L),M/);
row_col = col_1+ + L*M;
C_temp = zeros(M);
C_temp(ind2sub([M,M],row_col)) = ;
C{matrixNum} = sparse(C_temp)';
end
H = [A A A B B+C{};B+C{} B+C{}+C{} A A B;A B B+C{} A C{}+C{}+C{}];
H_23 = [A A;B C{}+C{}+C{};C{}+C{}+C{} B];
H=[H_23 H];
H_full = full(H);
whos H H_full
%% 稀疏矩阵乘法测试
message = randi([ ],,);
tic;H*message';toc;
tic;H_full*message';toc; %% 数据类型测试
Gc = randn();
Gc_logic = Gc>;
a=randi([ ],,);
tic;b = a*Gc;toc
tic;b = a*Gc_logic;toc %逻辑型运行花费时间
tic;Gc_logic=double(Gc_logic);b = a*Gc_logic;toc %类型转换
tic;Gt=double(Gc_logic);b = a*Gt;toc %建立新变量 %% 向量化测试
encodeData = randi([ ],,); tic;
encodeData_extend = [ encodeData];
for num = :length(encodeData_extend)
encodeData_extend(num) = xor(encodeData_extend(num),encodeData_extend(num-));
end
toc;
tic;
encodeData1 = [ encodeData];
encodeData1_sum = cumsum(encodeData1);
encodeData_2 = mod(encodeData1_sum,);
toc;

profile

上一小节内容中有一句"实际上对这个程序没有什么影响",我们怎么判断哪些代码要修改,哪些代码即使修改得再好对整个代码运行也没有什么影响呢?三种方法

  • 感觉(不可靠)
  • tic;toc;(太麻烦)
  • profile工具(很不错)

profile的功能可以help以下如何使用,我没怎么看,所以不怎么会用……profile是用来分析代码各个语句的运行时间的工具。使用方法是

  1. 输入profile on
  2. 运行需要测试的代码
  3. 输入profile viewer

结果如下图

点击各个函数(脚本)可以仔细观测各个语句的运行状态,由此来帮助优化MATLAB代码,就像这样

反正挺不错的,但我不太会用就不多说了。

参考

MATLAB帮助

如何加速MATLAB代码运行的更多相关文章

  1. Frequency-tuned Salient Region Detection MATLAB代码出错修改方法

    论文:Frequency-tuned Salient Region Detection.CVPR.2009 MATLAB代码运行出错如下: Error using makecform>parse ...

  2. 调试和运行matlab代码(源程序)的技巧和教程

    转载请标明出处:专注matlab代码下载的网站http://www.downma.com/ 本文主要给大家分享使用matlab编写代码,完成课程设计.毕业设计或者研究项目时,matlab调试程序的技巧 ...

  3. 【转载】让你的MATLAB代码飞起来

    原文地址:http://developer.51cto.com/art/201104/255128_all.htm MATLAB语言是一种被称为是"演算纸"式的语言,因此追求的是方 ...

  4. SVM实例及Matlab代码

    ******************************************************** ***数据集下载地址 :http://pan.baidu.com/s/1geb8CQf ...

  5. 使用ecilpse(Java)调用Matlab代码

    1 安装java环境: http://www.oracle.com/technetwork/java/javase/downloads/index.html 下载JDK最新版本并安装,CloudSim ...

  6. 高斯混合模型(GMM)及MATLAB代码

    之前在学习中遇到高斯混合模型,卡了很长一段时间,在这里记下学习中的一些问题以及解决的方法.希望看到这篇文章的同学们对高斯混合模型能有一些基本的概念.全文不废话,直接上重点. 本文将从以下三个问题详解高 ...

  7. 熵权法原理及matlab代码实现

    参考原理博客地址https://blog.csdn.net/u013713294/article/details/53407087 一.基本原理 在信息论中,熵是对不确定性的一种度量.信息量越大,不确 ...

  8. 用 Numba 加速 Python 代码

    原文出自微信公众号:Python那些事 一.介绍 pip install numba Numba 是 python 的即时(Just-in-time)编译器,即当你调用 python 函数时,你的全部 ...

  9. Matlab 代码注释

    Matlab 代码注释 一直在找类似doxygen一样将程序注释发表成手册的方法,现在发现,Matlab的publish功能自己就能做到. Publish 简介 并非所有注释都能作为文本进行输出,MA ...

随机推荐

  1. lucene索引

    一.lucene索引 1.文档层次结构 索引(Index):一个索引放在一个文件夹中: 段(Segment):一个索引中可以有很多段,段与段之间是独立的,添加新的文档可能产生新段,不同的段可以合并成一 ...

  2. High Aavialability with Group Replication-by宋利兵

    今天,2016年12月12日, Group Replication GA啦!GA的版本是MySQL-5.7.17. 下载连接如下: http://dev.mysql.com/downloads/mys ...

  3. 更改ubuntu下mysql的密码

    1.首先,进入环境中去,即 mysql  -u  root  -p   ,然后输入原始密码 2.此时会出现 mysql > 3.开始修改密码: mysql >   use  mysql ; ...

  4. 在IT的路上,我在成长

    在IT的路上,我在成长.很荣幸地加入了博客园这个大家庭. 岁月的航船在不断航行,在成长的脚印我要深深留下,回首已往经历,发现自己成长的路上,将来也会有很多美好的回忆,以及丰硕的果实.

  5. 一个初学者对于MVC架构的理解

    我很早之前就开始接触.NET开发,一直都在2.0的框架下,所以对于MVC这种架构,听说过,但没有具体使用过,近期和外部朋友接触时,有了解到他们公司在使用MVC这种架构,所以自己就找来相关资料了解一下M ...

  6. poj 3667 Hotel(线段树,区间合并)

    Hotel Time Limit: 3000MSMemory Limit: 65536K Total Submissions: 10858Accepted: 4691 Description The ...

  7. Mysql在windows下和linux下对表名大小写默认要求的一个细节

    今天在虚拟机里搭建项目环境,偷了下懒,直接把本机数据库中的表用sqlyog复制给虚拟机中的数据库,然后开始部署项目,项目一启动提示: Table 'sdmqrt.QRTZ_LOCKS' doesn't ...

  8. selenium处理滚动条

    1.用js实现 滚动到底部 String js="document.documentElement.scrollTop=10000"滚动到顶部 String js="do ...

  9. UESTC 881 神秘绑架案 --二维DP

    LRJ黑书上的例题. 化简均方差公式: 均值的平方一定,所以只需让矩形的总分的平方和最小即可. 定义:dp[k][x1][y1][x2][y2],以(x1,y1)为左上角坐标,(x2,y2)为右下角坐 ...

  10. UESTC 900 方老师炸弹 --Tarjan求割点及删点后连通分量数

    Tarjan算法. 1.若u为根,且度大于1,则为割点 2.若u不为根,如果low[v]>=dfn[u],则u为割点(出现重边时可能导致等号,要判重边) 3.若low[v]>dfn[u], ...