Как создать дескриптор функции функции как с новыми входными параметрами, так и с выходными параметрами из предыдущего вызова в Matlab?

#matlab #function-handle

Вопрос:

Я пытаюсь создать функцию и дескриптор функции указанной функции, где функция принимает выходные параметры из предыдущего вызова и новые входные параметры и вычисляет градиент в функции, как показано в примере игрушки, показанном ниже. Я хотел бы передать дескриптор функции hmcSampler . Однако у меня возникла проблема с созданием дескриптора функции, и я хотел бы получить некоторую помощь.

Чтобы уточнить: я хочу позвонить logPosterior с новым значением theta , но также с выводом theta и logpdf из предыдущего вызова. И мне нужно сделать это с помощью дескриптора функции, который будет вызываться несколько раз функцией, которую я не контролирую, поэтому мне нужен либо logPosterior один, либо его дескриптор для управления хранением старых значений. В первом вызове должны быть разные значения theta и old_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
 

Комментарии:

1. «У меня возникли проблемы с созданием дескриптора функции, и я хотел бы получить некоторую помощь». Не могли бы вы подробнее остановиться на этой проблеме? Разве это работает не так, как задумывалось? Выдает ли он сообщение об ошибке? Что есть old_theta в вашем примере? Я не вижу, чтобы это где-то определялось. Кроме того, normalDistGrad требуется всего 3 аргумента, которые вы, возможно, намеревались вызвать logPosterior ?

2. Поэтому я думаю , что вы хотите сделать следующее: вызов logPosterior с новым значением theta , но также с выводом theta и logpdf из предыдущего вызова. И вам нужно сделать это с помощью дескриптора функции, который будет несколько раз вызываться функцией, которой вы не управляете, поэтому вам нужна либо сама функция, либо дескриптор функции, чтобы управлять хранением старых значений. Можете ли вы изменить logPosterior ? Если так, то это было бы самым простым решением. Что должно произойти при первом вызове функции?

3. Да, вы абсолютно правы. Да, logPosterior это написано мной, чтобы его можно было изменить. Могу ли я просто сохранить параметры из предыдущего вызова в глобальной переменной, а затем использовать ее в logPosterior ? В первом вызове должны быть разные значения theta и old_theta , чтобы функция могла работать.

Ответ №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

сначала определите свою функцию в отдельном файле 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
 

Комментарии:

1. Я не думаю, что это ответ на вопрос, который я задал.

2. @shunyo может быть, я не очень хорошо понял вашу проблему, я подумал, что вы хотите создать дескриптор функции и в то же время передать функции какое-то другое значение (old_values). в этом случае f=@(x)myfunc(x,a,b) — ваш ответ, кроме этого, если вы хотите, чтобы старое значение сохранялось в функции (не передавалось явно функции), вам следует использовать решение, предоставленное Cris