Added new option mh_tune_jscale.

Works only with the Random Walk Metropolis Hastings algorithm.

Closes #1598
time-shift
Stéphane Adjemian(Charybdis) 2018-05-16 16:15:42 +02:00
parent 3f674f0f26
commit f53be721c1
7 changed files with 264 additions and 8 deletions

View File

@ -5595,12 +5595,17 @@ variance if the acceptance ratio is too low. In some situations it may
help to consider parameter-specific values for this scale parameter.
This can be done in the @ref{estimated_params}- block.
Note that @code{mode_compute=6} will tune the scale parameter to achieve an acceptance rate of
@ref{AcceptanceRateTarget}. The resulting scale parameter will be saved into a file
named @file{@var{MODEL_FILENAME}_mh_scale.mat}. This file can be loaded in subsequent runs
via the @code{posterior_sampler_options}-option @ref{scale_file}. Both @code{mode_compute=6}
and @code{scale_file} will overwrite any value specified in @code{estimated_params} with the tuned value.
Default: @code{0.2}
Note that @code{mode_compute=6} will tune the scale parameter to achieve an
acceptance rate of @ref{AcceptanceRateTarget}. The resulting scale parameter
will be saved into a file named @file{@var{MODEL_FILENAME}_mh_scale.mat}. This
file can be loaded in subsequent runs via the
@code{posterior_sampler_options}-option @ref{scale_file}. Both
@code{mode_compute=6} and @code{scale_file} will overwrite any value specified
in @code{estimated_params} with the tuned value. Default: @code{0.2}
Note also that for the Random Walk Metropolis Hastings algorithm, it is
possible to use option @ref{mh_tune_jscale}, to automatically tune the value of
@code{mh_jscale}.
@item mh_init_scale = @var{DOUBLE}
The scale to be used for drawing the initial value of the
@ -5617,6 +5622,16 @@ If the @ref{nointeractive}-option has been invoked, the program will instead aut
@code{mh_init_scale} by 10 percent after 100 futile draws and try another 100 draws. This iterative
procedure will take place at most 10 times, at which point Dynare will abort with an error message.
@item mh_tune_jscale [= @var{DOUBLE}]
@anchor{mh_tune_jscale} Automatically tunes the scale parameter of the jumping
distribution's covariance matrix (Metropolis-Hastings), so that the overall
acceptance ratio is close to the desired level. Default value is
@code{0.33}. It is not possible to match exactly the desired
acceptance ratio because of the stochastic nature of the algoirithm (the
proposals and the initialial conditions of the markov chains if
@code{mh_nblocks>1}). This option is only available for the Random Walk
Metropolis Hastings algorithm.
@item mh_recover
@anchor{mh_recover} Attempts to recover a Metropolis-Hastings
simulation that crashed prematurely, starting with the last available saved

View File

@ -0,0 +1,111 @@
function Scale = calibrate_mh_scale_parameter(ObjectiveFunction, CovarianceMatrix, Parameters, MhBounds, options, varargin)
% Tune the MH scale parameter so that the overall acceptance ratio is close to AcceptanceTarget.
%
% INPUTS
% - ObjectiveFunction [fhandle] Function (posterior kernel).
% - CovarianceMatrix [double] n*n matrix, covariance matrix of the jumping distribution.
% - Parameters [double] n*1 vector, parameter values.
% - MhBounds [double] n*2 matrix, bounds on the possible values for the parameters.
% - options [structure] content of options_.tune_mh_jscale.
% - varargin [cell] Additional arguments to be passed to ObjectiveFunction.
%
% OUTPUTS
% - Scale [double] scalar, optimal scale parameter for teh jumping distribution.
% Fire up the wait bar
hh = dyn_waitbar(0,'Tuning of the scale parameter...');
set(hh,'Name','Tuning of the scale parameter.');
% Intilialize various counters.
j = 1; jj = 1; isux = 0; jsux = 0; i = 0;
% Evaluate the objective function.
logpo0 = - feval(ObjectiveFunction, Parameters, varargin{:});
logpo1 = logpo0;
% Get the dimension of the problem.
n = length(Parameters);
% Initialize the correction on the scale factor.
correction = 1.0;
% Set the initial value of the scale parameter
Scale = options.guess;
% Transposition of some arrays.
MhBounds = MhBounds';
Parameters = Parameters';
% Compute the Cholesky of the covariance matrix, return an error if the
% matrix is not positive definite.
try
dd = chol(CovarianceMatrix);
catch
error('The covariance matrix has to be a symetric positive definite matrix!')
end
% Set parameters related to the proposal distribution
if options.rwmh.proposal_distribution=='rand_multivariate_normal'
nu = n;
elseif options.rwmh.proposal_distribution=='rand_multivariate_student'
nu = options.rwmh.student_degrees_of_freedom;
end
% Random Walk Metropolis Hastings iterations...
while j<=options.maxiter
% Obtain a proposal (jump)
proposal = feval(options.rwmh.proposal_distribution, Parameters, Scale*dd, nu);
% If out of boundaries set the posterior kernel equal to minus infinity
% so that the proposal will be rejected with probability one.
if all(proposal > MhBounds(1,:)) && all(proposal < MhBounds(2,:))
logpo0 = -feval(ObjectiveFunction, proposal(:), varargin{:});
else
logpo0 = -inf;
end
% Move if the proposal is enough likely...
if logpo0>-inf && log(rand)<logpo0-logpo1
Parameters = proposal;
logpo1 = logpo0;
isux = isux + 1;
jsux = jsux + 1;
end% ... otherwise I don't move.
prtfrc = j/options.maxiter;
% Update the waitbar
if ~mod(j, 10)
dyn_waitbar(prtfrc, hh, sprintf('Acceptance ratio [during last 500]: %f [%f]', isux/j, jsux/jj));
end
% Adjust the value of the scale parameter.
if ~mod(j, options.stepsize)
r1 = jsux/jj; % Local acceptance ratio
r2 = isux/j; % Overall acceptance ratio
% Set correction for the scale factor
c1 = r1/options.target;
if abs(c1-1)>.05
correction = correction^options.rho*c1^(1-options.rho);
else
correction = c1;
end
% Apply correction
if c1>0
Scale = Scale*correction;
else
Scale = Scale/10;
end
% Update some counters.
jsux = 0; jj = 0;
if abs(r2-options.target)<options.c2 && abs(r1-options.target)<options.c1
i = i+1;
else
i = 0;
end
% Test convergence.
if i>options.c3
break
end
end
j = j+1;
jj = jj + 1;
end
dyn_waitbar_close(hh);

View File

@ -228,7 +228,7 @@ if ~isequal(options_.mode_compute,0) && ~options_.mh_posterior_mode_estimation
elseif isnumeric(options_.mode_compute) && options_.mode_compute==6 %save scaling factor
save([M_.fname '_optimal_mh_scale_parameter.mat'],'Scale');
options_.mh_jscale = Scale;
bayestopt_.jscale = ones(length(xparam1),1)*Scale;
bayestopt_.jscale(:) = options_.mh_jscale;
end
if ~isnumeric(options_.mode_compute) || ~isequal(options_.mode_compute,6) %always already computes covariance matrix
if options_.cova_compute == 1 %user did not request covariance not to be computed
@ -438,6 +438,21 @@ if (any(bayestopt_.pshape >0 ) && options_.mh_replic) || ...
error(['Estimation:: Mode value(s) of ', disp_string ,' are outside parameter bounds.'])
end
end
% Tunes the jumping distribution's scale parameter
if options_.mh_tune_jscale.status
if options_.posterior_sampler_options.posterior_sampling_method=='random_walk_metropolis_hastings'
options = options_.mh_tune_jscale;
options.rwmh = options_.posterior_sampler_options.rwmh;
options_.mh_jscale = calibrate_mh_scale_parameter(objective_function, ...
invhess, xparam1, [bounds.lb,bounds.ub], ...
options, dataset_, dataset_info, options_, M_, estim_params_, bayestopt_, bounds, oo_);
bayestopt_.jscale(:) = options_.mh_jscale;
disp(sprintf('mh_jscale has been set equal to %s', num2str(options_.mh_jscale)))
skipline()
else
warning('mh_tune_jscale is only available with Random Walk Metropolis Hastings!')
end
end
% runs MCMC
if options_.mh_replic || options_.load_mh_file
posterior_sampler_options = options_.posterior_sampler_options.current_options;

View File

@ -442,6 +442,15 @@ options_.mh_conf_sig = 0.90;
options_.prior_interval = 0.90;
options_.mh_drop = 0.5;
options_.mh_jscale = 0.2;
options_.mh_tune_jscale.status = false;
options_.mh_tune_jscale.guess = .2;
options_.mh_tune_jscale.target = .33;
options_.mh_tune_jscale.maxiter = 200000;
options_.mh_tune_jscale.rho = .7;
options_.mh_tune_jscale.stepsize = 1000;
options_.mh_tune_jscale.c1 = .02;
options_.mh_tune_jscale.c2 = .05;
options_.mh_tune_jscale.c3 = 4;
options_.mh_init_scale = 2*options_.mh_jscale;
options_.mh_mode = 1;
options_.mh_nblck = 2;

@ -1 +1 @@
Subproject commit d686275da142e2d1e1afcdb32785c25f25b5a5a7
Subproject commit 1ba023e37d6ee7fc8d393840e42a4542274efbb7

View File

@ -41,6 +41,7 @@ MODFILES = \
estimation/MH_recover/fs2000_recover_2.mod \
estimation/MH_recover/fs2000_recover_3.mod \
estimation/t_proposal/fs2000_student.mod \
estimation/tune_mh_jscale/fs2000.mod \
moments/example1_var_decomp.mod \
moments/example1_bp_test.mod \
moments/test_AR1_spectral_density.mod \

View File

@ -0,0 +1,105 @@
/*
* Copyright (C) 2004-2018 Dynare Team
*
* This file is part of Dynare.
*
* Dynare is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Dynare is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Dynare. If not, see <http://www.gnu.org/licenses/>.
*/
var m P c e W R k d n l gy_obs gp_obs y dA;
varexo e_a e_m;
parameters alp bet gam mst rho psi del;
alp = 0.33;
bet = 0.99;
gam = 0.003;
mst = 1.011;
rho = 0.7;
psi = 0.787;
del = 0.02;
model;
dA = exp(gam+e_a);
log(m) = (1-rho)*log(mst) + rho*log(m(-1))+e_m;
-P/(c(+1)*P(+1)*m)+bet*P(+1)*(alp*exp(-alp*(gam+log(e(+1))))*k^(alp-1)*n(+1)^(1-alp)+(1-del)*exp(-(gam+log(e(+1)))))/(c(+2)*P(+2)*m(+1))=0;
W = l/n;
-(psi/(1-psi))*(c*P/(1-n))+l/n = 0;
R = P*(1-alp)*exp(-alp*(gam+e_a))*k(-1)^alp*n^(-alp)/W;
1/(c*P)-bet*P*(1-alp)*exp(-alp*(gam+e_a))*k(-1)^alp*n^(1-alp)/(m*l*c(+1)*P(+1)) = 0;
c+k = exp(-alp*(gam+e_a))*k(-1)^alp*n^(1-alp)+(1-del)*exp(-(gam+e_a))*k(-1);
P*c = m;
m-1+d = l;
e = exp(e_a);
y = k(-1)^alp*n^(1-alp)*exp(-alp*(gam+e_a));
gy_obs = dA*y/y(-1);
gp_obs = (P/P(-1))*m(-1)/dA;
end;
shocks;
var e_a; stderr 0.014;
var e_m; stderr 0.005;
end;
steady_state_model;
dA = exp(gam);
gst = 1/dA;
m = mst;
khst = ( (1-gst*bet*(1-del)) / (alp*gst^alp*bet) )^(1/(alp-1));
xist = ( ((khst*gst)^alp - (1-gst*(1-del))*khst)/mst )^(-1);
nust = psi*mst^2/( (1-alp)*(1-psi)*bet*gst^alp*khst^alp );
n = xist/(nust+xist);
P = xist + nust;
k = khst*n;
l = psi*mst*n/( (1-psi)*(1-n) );
c = mst/P;
d = l - mst + 1;
y = k^alp*n^(1-alp)*gst^alp;
R = mst/bet;
W = l/n;
ist = y-c;
q = 1 - d;
e = 1;
gp_obs = m/dA;
gy_obs = dA;
end;
steady;
check;
estimated_params;
alp, beta_pdf, 0.356, 0.02;
bet, beta_pdf, 0.993, 0.002;
gam, normal_pdf, 0.0085, 0.003;
mst, normal_pdf, 1.0002, 0.007;
rho, beta_pdf, 0.129, 0.100;
psi, beta_pdf, 0.65, 0.05;
del, beta_pdf, 0.01, 0.005;
stderr e_a, inv_gamma_pdf, 0.035449, inf;
stderr e_m, inv_gamma_pdf, 0.008862, inf;
end;
varobs gp_obs gy_obs;
estimation(order=1, datafile='../fsdat_simul', nobs=192, loglinear, mh_replic=20000, mh_nblocks=2, mh_tune_jscale=0.33);
mhdata = load('fs2000/metropolis/fs2000_mh_history_0.mat');
if any(abs(mhdata.record.AcceptanceRatio-options_.mh_tune_jscale.target)>options_.mh_tune_jscale.c1)
error('Automagic tuning of the MCMC proposal scale parameter did not work as expected!')
end