如何使用 Matlab 中先前调用的新输入参数和输出参数创建函数的函数句柄?

How to create a function handle of a function with both new input parameters and output parameters from previous call in Matlab?

我正在尝试创建一个函数和所述函数的函数句柄,其中该函数接收上一次调用的输出参数和新的输入参数,并计算函数中的梯度,如下面的玩具示例所示.我想将函数句柄传递给 hmcSampler。但是,我在创建函数句柄时遇到问题,需要一些帮助。

澄清一下:我想用 theta 的新值调用 logPosterior,而且还要用上次调用的 thetalogpdf 输出。我需要通过一个函数句柄来执行此操作,该函数句柄将被我无法控制的函数多次调用,因此我需要 logPosterior 或其句柄来管理旧值的存储。在第一次调用中,thetaold_theta 应该有不同的值,这样函数才能运行。

%% Toy implementation of hmcsampler class in Matlab
NumPredictors = 2;

trueIntercept = 2;
trueBeta = [3;0];
NumData = 100;
rng('default') %For reproducibility
X = rand(NumData,NumPredictors);
mu = X*trueBeta + trueIntercept;
y = mu;

% define the mean and variance of normal distribution of each parameter
means = [0; 0];
standevs = [1;1];


% create multivariate normal log probability distribution
[logpdf, grad_logpdf] = @(theta)logPosterior(theta, old_theta, X, y, means, standevs, old_logpdf); % <- How to write this?
% create the startpoint from which sampling starts
startpoint = randn(2, 1);

% create an HMC sampler object
smp = hmcSampler(logpdf, startpoint);

% estimate maximum of log probability density
[xhat, fitinfo] = estimateMAP(smp);

num_chains = 4;
chains = cell(num_chains, 1);
burnin = 50000;
num_samples = 2000000;


function [logpdf, grad_logpdf] = logPosterior(theta, old_theta, X, y, means, standevs, old_logpdf)
    
    % values
    intercept = theta(1);
    beta = theta(2:end);
    y_computed = X*beta + intercept; 
    log_likelihood = log(y_computed);
    del_loglikelihood = log_likelihood - old_logpdf;
    del_params = theta - old_theta;
    grad_params1 = del_loglikelihood/del_params;
    
    % compute log priors and gradients of parameters
    log_prior_params = 0;
    grad_params2 = [];
    for i = 1:3
        [lp, grad] = normalDistGrad(theta(i), means(i), standevs(i));
        log_prior_params = log_prior_params + lp;
        grad_params2 = [grad_params2; grad];
    end
    % return the log posterior and its gradient
    logpdf = log_likelihood + log_prior_params;
    grad_logpdf = grad_params1 + grad_params2;
end

function [lpdf,glpdf] = normalDistGrad(X, Mu, Sigma)
    Z = (X - Mu)./Sigma;
    lpdf = sum(-log(Sigma) - .5*log(2*pi) - .5*(Z.^2));
    glpdf = -Z./Sigma;
end

matlab help

首先在当前路径中的单独 m 文件中定义函数 :

function [o1,o2]=myfunc(in1,in2,in3)
    o1=in1+in2+in3;
    o2=in3-in2;
end

然后创建函数句柄:

f=@myfunc;
f(1,2,3)
ans= 6

仅使用其中一个输入:

f=@(x)myfunc(x,3,5);
f(1)
ans=9

获得两个输出:

[a,b]=f(1);

或者在你的函数中定义一个输出并在调用它们之后引用它们的索引:

function o=myfunc(in1,in2,in3)
    o1=in1+in2+in3;
    o2=in3-in2;
    o=[o1,o2];
end

...

我将按如下方式实现 logPosterior 以跟踪上次函数调用中的值。 persistent 变量是函数的局部变量,但在调用之间持续存在,使其成为为函数提供内存的理想工具。

function [logpdf, grad_logpdf] = logPosterior(theta, X, y, means, standevs)
    persistent old_theta old_logpdf
    if isempty(old_theta)
       % function hasn't been called before, initialize the old values:
       old_theta = zeros(size(theta));
       old_logpdf = 0; % adjust to be meaningful initial values
    end

    % ... (your original function code here)

    % save new values as old values for next call
    old_theta = theta;
    old_logpdf = logpdf;
end

您现在将采用如下函数句柄:

func = @(theta)logPosterior(theta, X, y, means, standevs);

func 是您传递给调用它的任何函数的句柄。您可以通过 运行 您的函数初始化一次先前的变量(我不确定什么是合适的初始化!):

func(startpoint);
smp = hmcSampler(func, startpoint);