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. help to consider parameter-specific values for this scale parameter.
This can be done in the @ref{estimated_params}- block. 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 Note that @code{mode_compute=6} will tune the scale parameter to achieve an
@ref{AcceptanceRateTarget}. The resulting scale parameter will be saved into a file acceptance rate of @ref{AcceptanceRateTarget}. The resulting scale parameter
named @file{@var{MODEL_FILENAME}_mh_scale.mat}. This file can be loaded in subsequent runs will be saved into a file named @file{@var{MODEL_FILENAME}_mh_scale.mat}. This
via the @code{posterior_sampler_options}-option @ref{scale_file}. Both @code{mode_compute=6} file can be loaded in subsequent runs via the
and @code{scale_file} will overwrite any value specified in @code{estimated_params} with the tuned value. @code{posterior_sampler_options}-option @ref{scale_file}. Both
Default: @code{0.2} @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} @item mh_init_scale = @var{DOUBLE}
The scale to be used for drawing the initial value of the 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 @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. 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 @item mh_recover
@anchor{mh_recover} Attempts to recover a Metropolis-Hastings @anchor{mh_recover} Attempts to recover a Metropolis-Hastings
simulation that crashed prematurely, starting with the last available saved 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 elseif isnumeric(options_.mode_compute) && options_.mode_compute==6 %save scaling factor
save([M_.fname '_optimal_mh_scale_parameter.mat'],'Scale'); save([M_.fname '_optimal_mh_scale_parameter.mat'],'Scale');
options_.mh_jscale = Scale; options_.mh_jscale = Scale;
bayestopt_.jscale = ones(length(xparam1),1)*Scale; bayestopt_.jscale(:) = options_.mh_jscale;
end end
if ~isnumeric(options_.mode_compute) || ~isequal(options_.mode_compute,6) %always already computes covariance matrix 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 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.']) error(['Estimation:: Mode value(s) of ', disp_string ,' are outside parameter bounds.'])
end end
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 % runs MCMC
if options_.mh_replic || options_.load_mh_file if options_.mh_replic || options_.load_mh_file
posterior_sampler_options = options_.posterior_sampler_options.current_options; 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_.prior_interval = 0.90;
options_.mh_drop = 0.5; options_.mh_drop = 0.5;
options_.mh_jscale = 0.2; 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_init_scale = 2*options_.mh_jscale;
options_.mh_mode = 1; options_.mh_mode = 1;
options_.mh_nblck = 2; 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_2.mod \
estimation/MH_recover/fs2000_recover_3.mod \ estimation/MH_recover/fs2000_recover_3.mod \
estimation/t_proposal/fs2000_student.mod \ estimation/t_proposal/fs2000_student.mod \
estimation/tune_mh_jscale/fs2000.mod \
moments/example1_var_decomp.mod \ moments/example1_var_decomp.mod \
moments/example1_bp_test.mod \ moments/example1_bp_test.mod \
moments/test_AR1_spectral_density.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