【问题标题】:How to create a function handle of a function with both new input parameters and output parameters from previous call in Matlab?如何使用 Matlab 中先前调用的新输入参数和输出参数创建函数的函数句柄?
【发布时间】:2021-11-01 01:33:58
【问题描述】:

我正在尝试创建一个函数和所述函数的函数句柄,其中该函数接收来自先前调用的输出参数和新的输入参数,并计算函数中的梯度,如下所示的玩具示例中给出。我想将函数句柄传递给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

【问题讨论】:

  • “我在创建函数句柄时遇到问题,需要一些帮助。”你能详细说明一下这个问题吗?它没有按预期工作吗?它是否给出错误消息?在您的示例中,old_theta 是什么?我没有看到它在任何地方定义。此外,normalDistGrad 仅接受 3 个参数,您可能打算调用 logPosterior?
  • 所以我认为您想要做的是:使用新值 theta 调用 logPosterior,同时使用上一次调用的 thetalogpdf 输出。您需要通过函数句柄来执行此操作,该函数句柄将由您无法控制的函数多次调用,因此您需要函数本身或函数句柄来管理存储旧值。可以修改logPosterior吗?如果是这样,那将是最简单的解决方案。第一次调用该函数时应该发生什么?
  • 是的,你是绝对正确的。是的,logPosterior 是我写的,所以可以更改。我是否只是将上一次调用的参数存储在全局变量中,然后在logPosterior 中使用它?在第一次调用中,thetaold_theta 的值应该不同,这样函数才能运行。

标签: matlab function-handle


【解决方案1】:

我将按如下方式实现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);

【讨论】:

    【解决方案2】:

    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
    

    ...

    【讨论】:

    • 我认为这不是我所问问题的答案。
    • @shunyo 也许我没有很好地理解你的问题,我以为你想创建一个函数的句柄,同时将一些其他值(old_values)传递给函数。在这种情况下, f=@(x)myfunc(x,a,b) 是您的答案,除此之外,如果您希望旧值在函数中持久存在(不明确传递给函数),您应该使用解决方案克里斯提供的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多