加速Matlab编程指南—持续更新
- 加速Matlab编程指南(CUDA实现)
- 为什么使用MATLAB
- MATLAB程序的性能评估
- 运行程序前的性能评估
- 运行程序后的性能评估
- 基于多核处理器的MATLAB程序加速
- 利用MATLAB内置函数更高效的运算
- 向量化编程有利于矩阵高效运算
- 矩阵运算中,MATLAB要要求参与的数组应具有相同的大小。
加速Matlab编程指南(CUDA实现)
本教程适用于具有一定Matlab编程基础的读者。说是教程,更像是读书笔记,文中出现的内容多是笔者阅读以下资料的归纳和整理。主要参考的书籍及资料有:
《加速MATLAB编程指南CUDA实现》 赵地 清华大学出版社
《Matlab从入门到精通》
https://www.mathworks.comMATLAB正版下载
为什么使用MATLAB
众所周知,当前机器学习,深度学习的代码实现往往都是在python上。笔者为什么非要在MATLAB上编写代码呢,主要原因有以下几点:
- 配置简单 ,MATLAB更像是一款应用软件。环境配置和代码编译由程序后台自动执行,只用编写代码并执行即可,
- 语言简单,MATLAB更注重算法,而不是代码实现。这里的算法是指按照人类思维方式,系统而又完整地描述解决问题的方案,因此按照算法编写的MATLAB程序在语言上,与算法本身具有很大的相似性。在MATLAB实现某种算法,只需创建矩阵和对矩阵进行运算;
- 可视化高 ,往往一些数学运算的代码实现是繁琐的,例如:计算FFT(快速傅里叶变换),MATLAB提供了fft()函数,工程师们已经将该函数的底层代码优化到了尽可能的高效。因此我们无需自己设计代码和对其修改,拿来即用。除此之外还需许多丰富的工具箱,和简洁明了的图形化操作界面;
- 最后,其实最主要的原因还是因为笔者长期处在高校,学术界使用MATLAB的情况颇多。笔者科研中常常使用MATLAB,也遇到诸多麻烦,结合了自己使用MATLAB的情况,希望能够分享给大家一些使用MATLAB的技巧。
总结就是:MATLAB更注重算法的研究,而不是代码的实现。作为初学者,使用MATLAB学习,能够避免繁杂的编程语言学习,将更多的时间放在算法的数学思考上面。
MATLAB程序的性能评估
MATLAB程序的性能评估(profiling)是指对MATLAB程序的空间复杂度(space complexity)和时间复杂度(time complexity)进行分析。不过,最简单粗暴的方式,就是对MATLAB函数的运行时间进行分析,自然越快越好。
运行程序前的性能评估
运行MATLAB程序之前,程序员首先希望知道当前计算机的性能。MATLAB的 bench()
函数的功能是运行MATLAB基准程序,测试MATLAB在本计算机上的性能。
在命令窗口输入 bench( ) ,
运行程序后的性能评估
在运行一段程序后,如果能够获得程序的运行时间,并再加以分析,将有利于对MATLAB程序进行优化。
MATLAB的tic()/toc()
函数能够帮助我们快速地完成这个操作。 tic() 与 toc() 函数一般配合使用。执行 tic() 函数时,程序将启动秒表计时器(stopwatch), toc() 函数将种植秒表计时器并读数, tic() 与 toc() 函数的调用格式是:
tic
% 程序中计时的部分;
toc
- 程序员在度量CPU端MATLAB代码运行时间可以执行
cputime()
函数,该函数返回CPU运行时间,单位为秒。注意:与 tic()/toc() 函数不同之处在于, tic()/toc() 计算的是MATLAB程序运行的总的时间,包括CPU运行时间,内存读写时间等所有内容;而 cputime() 函数仅仅衡量MATLAB程序占用CPU的时间。 - 程序员在度量CPU端MATLAB代码运行时间可以执行
gputimeit()
函数在一些GPU上运行的程序, gputimeit() 能为我们度量程序在GPU端的运行时间。
不管是在GPU端还是CPU端运行的函数,都可以timeit()
函数度量。 timeit() 可以将被计时的函数调用多次并记录运行时间,返回多次运行时间的平均值。
最后MATLAB还为程序员提供了更简洁的图形化操作。仅需点击MATLAB图形化界面的 运行并计时(profiler)。程序执行完毕后将返回每一条命令、每一个函数耗时的细节。
本节涉及函数的参考连接:
bench()tic()/toc()timeit()cputimegputimeit()
基于多核处理器的MATLAB程序加速
MATLAB储存的数值数据是由矩阵(matrix)构成的。这也正式MATLAB的名字由来:Matrix Lab 矩阵实验室。
- 标量:可以认为是1X1的矩阵,表示为:
- 向量(数组):可以认为是一维矩阵,表示为:
- 矩阵:表示为:
- 张量:可以认为是多个矩阵的叠加,比较难表示,用的也少。
因为,为叙述方便,以后对所有的此类结构都用矩阵来描述。这些矩阵的创建方式也有多种,在任何一本入门级的教程都有详细的介绍,这里就不赘述了。
需要注意的是:MATLAB矩阵默认的数据类型为双精度型(double)。与C/C++等语言不同,MATLAB具有对不同类型数据进行转换的内在机制,这就使得不需要对数据类型严格的定义。
利用MATLAB内置函数更高效的运算
在MATLAB的程序的编制过程中,程序员经常需要对矩阵的性质判断。由于大多数MATLAB内置函数已经做了多核多线程的优化,通过利用如下内置函数,可以实现更高效的运算:
函数名称 | 实现功能 |
isempty() | 检验矩阵是否为空集 |
isinf() | 检验矩阵每一个元素是否为Inf |
isnan() | 检验矩阵每一个元素是否为NaN |
isprime() | 检验矩阵每一个元素是否为素数 |
issorted() | 检验矩阵是否经过排序 |
ismember() | 检验一个元素是否被矩阵包含 |
histcounts() | 计算矩阵中某一数值区间的元素数量 |
prod() | 计算矩阵中元素的乘积 |
intersect() | 计算两个矩阵的交集 |
setdiff() | 计算两个矩阵的集合差 |
setxor() | 计算两个矩阵的集合对称差 |
union() | 计算两个矩阵的元素集合,每个元素只出现一次 |
例如:计算100的阶乘
利用prod()函数要比利用循环要高效得多
tic
%循环计算阶乘;
p = 1;
for i=1:100
p = p * i;
end
toc
计算时间:
tic
%prod()函数计算阶乘;
a = 1:100;
p = prod(a);
toc
计算时间:
向量化编程有利于矩阵高效运算
所谓“向量化编程”,即尽量使用矩阵运算来代替使用for循环。这要求使用者要较为熟练高等代数的内容。
向量化编程更快同样是因为MATLAB矩阵运算已经做了多核多线程的优化,
例如:计算不同 下多项式的值的和:
对于
当 时,所有
tic
% 循环计算;
s = 0;
for i=1:50
p = 1 + 2*i + 3*i^2 + 4*i^3 + 5*i^4 + 6*i^5;
s = s + p;
end
toc
计算时间:
tic
% 向量化编程;
i = 1:50';
x = [i^0 i^1 i^2 i^3 i^4 i^5];
s = sum(x*[1 2 3 4 5]');
toc
计算时间:
矩阵运算中,MATLAB要要求参与的数组应具有相同的大小。
- 如果数组大小不一致,采用
repmat()
或者repelem()
将尺寸一致化。 - 如果矩阵维度不一致,则用
reshape()
将尺寸一致化。 -
repmat()
、repelem()
、reshape()
计算开销、内存开销大。bsxfun()
、cellfun()
、arrayfun()
例如在深度学习工具箱DeepLearnToolbox的卷积神经网络(Convolutional Neural Network, CNN)中,训练数据进行归一化的代码为:
funtion x = normalize(x, mu, sigma)
x = bsxfun(@minux, x, mu);
x = bsxfun(@rdivide, x, sigma);
end
计算softmax()函数的代码为:
funtion mu = softmax(eta)
tmp = exp(3 * eta);
denom = sum(tmp, 2);
mu = bsxfun(@rdivide, tmp, denom);
end