问题背景:在Matlab编写一个函数(如FunManage(fun,params)函数)时,通过函数调用另外一个函数@fun(假设fun的参数是a,b,c), 并通过一个数组接受params, 经过一定的处理后,将params数组拆分成多个参数,传入fun函数中再次调用得到结果
在Matlab编程过程中,常常会遇到需要传入函数和参数的问题:如类似python中的arg**项传入不定项参数等等,这里我以我需要编写的求解梯度的算法为例(这个我是仿python里mxnet包的autograd函数,用来求解梯度的):
基本原理是转换为字符串执行
示例
1. 主函数(调用)
使用autograd求解cos(x*y)在x = pi/6 , y = pi/3 处对x的梯度(第三个参数是指定求梯度的参数位置,第四个是指定步长)
其中使用@函数句柄将函数传入
autograd(@fun, [pi/6, pi/3], 1, 0.01)
function out = fun(x,y)
out = cos(x* y);
end
% 求解cos(x,y)在(pi/6, pi/3)对x的梯度
% \partial fun / \partial x = y * -sin(x * y)
% 注意: [pi/6, pi/3] 是以数组形式输入的多个参数,在autograd中将拆分后用fun进行调用
2. autograd函数
在autograd函数中,使用split将参数用逗号分隔开,再用eval函数来将字符串执行相应的语句(其中join是拼接字符串,join的第二的参数指定拼接无间隔(默认使用空格进行拼接))
function grad = autograd(func, param, argNum, optional_dx)
% func 为需要求解梯度的函数, params作为参数传入, argNum标识参数的位置,
if nargin == 3
optional_dx = 0.01 * param(argNum);
end
param_str = join(split(string(param)),',');
eval(join(['y0 = func(', param_str ,');'],''));
param2 = param; % 新赋一个值,防止由于函数修改堆中的数据导致的原始数组改变
param2(argNum) = param(argNum) + optional_dx;
param2_str = join(split(string(param2)),',');
eval(join(['y1 = func(', param2_str ,');'],''));
grad = ( y1 -y0 ) / optional_dx ;
end
% 定义autograd函数求解损失函数对于相应自变量的梯度
% 使用最简单的思路,将自变量增加一个微小的值,再使用函数计算出函数的变化值
% 使用函数变化值 - 自变量的变化值作为相应的点的梯度
得到的结果是-0.5505, 我计算了一下cos(x*y)对x的偏导数- y* sin(x*y ), 代入x = pi/6, y = pi/3,得到的结果是-0.545848449
这个只需要在主函数中缩小下步长参数origional_dx就行了
当然也是一种近似求解偏导数的方法
至于这个应用的话,可以有和python中的arg**类似的功用
其实国庆事情挺多的,估计还得接着使劲鸽(这篇文章不长就算成是水水吧)