function [SPM] = spm_spm_Bayes(SPM) % Conditional parameter estimation of a General Linear Model % FORMAT [SPM] = spm_spm_Bayes(SPM) %__________________________________________________________________________ % % spm_spm_Bayes returns to voxels identified by spm_spm (ML parameter % estimation) to get conditional parameter estimates and ReML hyper- % parameter estimates. These estimates use prior covariances, on the % parameters, from empirical Bayes. These PEB prior variances come from % the hierarchical model that obtains by considering voxels as providing a % second level. Put simply, the variance in parameters, over voxels, is % used as a prior variance from the point of view of any one voxel. The % error covariance hyperparameters are re-estimated in the light of these % priors. The approach adopted is essentially a fully Bayesian analysis at % each voxel, using empirical Bayesian prior variance estimators over % voxels. % % Each separable partition (i.e. session) is assigned its own % hyperparameter but within session covariance components are lumped % together, using their relative expectations over voxels. This makes % things much more computationally efficient and avoids inefficient % voxel-specific multiple hyperparameter estimates. % % spm_spm_Bayes adds the following fields to SPM: % % ---------------- % % % SPM.PPM.l = session-specific hyperparameter means % SPM.PPM.Cb = empirical prior parameter covariances % SPM.PPM.C = conditional covariances of parameters % SPM.PPM.dC{i} = dC/dl; % SPM.PPM.ddC{i} = ddC/dldl % % The derivatives are used to compute the conditional variance of various % contrasts in spm_getSPM, using a Taylor expansion about the hyperparameter % means. % % % ---------------- % % SPM.VCbeta - Handles of conditional parameter estimates % SPM.VHp - Handles of hyperparameter estimates % % ---------------- % % Cbeta_????. - conditional parameter images % These are 32-bit (float) images of the conditional estimates. The image % files are numbered according to the corresponding column of the % design matrix. Voxels outside the analysis mask (mask.) are given % value NaN. % % ---------------- % % CHp_????. - error covariance hyperparameter images % This is a 64-bit (double) image of the ReML error variance estimate. % for each separable partition (Session). Voxels outside the analysis % mask are given value NaN. %__________________________________________________________________________ % % For single subject fMRI analysis there is an alternative function % using voxel-wise GLM-AR models that are spatially regularised % using the VB framework. This is implemented using spm_spm_vb.m. %__________________________________________________________________________ % Copyright (C) 2002-2013 Wellcome Trust Centre for Neuroimaging % Karl Friston % $Id: spm_spm_Bayes.m 5354 2013-03-25 18:50:54Z guillaume $ %-Say hello %-------------------------------------------------------------------------- Finter = spm('FigName','Stats: Bayesian estimation...'); %-Select SPM.mat & change directory %-------------------------------------------------------------------------- if ~nargin [Pf, sts] = spm_select(1,'^SPM\.mat$','Select SPM.mat'); if ~sts, return; end swd = spm_file(Pf,'fpath'); load(fullfile(swd,'SPM.mat')) cd(swd) end try M = SPM.xVol.M; DIM = SPM.xVol.DIM; xdim = DIM(1); ydim = DIM(2); zdim = DIM(3); XYZ = SPM.xVol.XYZ; catch helpdlg({ 'Please do a ML estimation first.',... 'This identifies the voxels to analyse.'}); spm('FigName','Stats: done',Finter); spm('Pointer','Arrow') return end %========================================================================== % - A N A L Y S I S P R E L I M I N A R I E S %========================================================================== %-Initialise output images %========================================================================== fprintf('%-40s: %30s','Output images','...initialising') %-# %-Initialise conditional estimate image files %-------------------------------------------------------------------------- xX = SPM.xX; [nScan,nBeta] = size(xX.X); Vbeta(1:nBeta) = deal(struct(... 'fname', [],... 'dim', DIM',... 'dt', [spm_type('float32'), spm_platform('bigend')],... 'mat', M,... 'pinfo', [1 0 0]',... 'descrip', '')); for i = 1:nBeta Vbeta(i).fname = [sprintf('Cbeta_%04d',i) spm_file_ext]; Vbeta(i).descrip = sprintf('Cond. beta (%04d) - %s',i,xX.name{i}); spm_unlink(Vbeta(i).fname) end Vbeta = spm_create_vol(Vbeta); %-Initialise ReML hyperparameter image files %-------------------------------------------------------------------------- try nHp = length(SPM.nscan); catch nHp = nScan; SPM.nscan = nScan; end VHp(1:nHp) = deal(struct(... 'fname', [],... 'dim', DIM',... 'dt', [spm_type('float64'), spm_platform('bigend')],... 'mat', M,... 'pinfo', [1 0 0]',... 'descrip', '')); for i = 1:nHp VHp(i).fname = [sprintf('Hp_%04d',i) spm_file_ext]; VHp(i).descrip = sprintf('Hyperparameter (%04d)',i); spm_unlink(VHp(i).fname) end VHp = spm_create_vol(VHp); fprintf('%s%30s',repmat(sprintf('\b'),1,30),'...initialised') %-# %========================================================================== % - A V E R A G E S A M P L E C O V A R I A N C E M A T R I X %========================================================================== fprintf('%s%30s',repmat(sprintf('\b'),1,30),'...estimating CY') %-# CY = 0; % <(Y - ) * (Y - )'> EY = 0; % for ReML nScan = size(xX.X,1); xVi = SPM.xVi; %-Compute Hsqr and F-threshold under i.i.d. %-------------------------------------------------------------------------- xX.xKXs = spm_sp('Set',spm_filter(xX.K,xX.W*xX.X)); xX.xKXs.X = full(xX.xKXs.X); xX.pKX = spm_sp('x-',xX.xKXs); if isfield(xVi,'Fcontrast') Fcname = 'User-specified contrast'; xCon = spm_FcUtil('Set',Fcname,'F','c',xVi.Fcontrast,xX.xKXs); else Fcname = 'effects of interest'; iX0 = [xX.iB xX.iG]; xCon = spm_FcUtil('Set',Fcname,'F','iX0',iX0,xX.xKXs); end if ~isempty(xCon(1).c) X1o = spm_FcUtil('X1o', xCon(1),xX.xKXs); Hsqr = spm_FcUtil('Hsqr',xCon(1),xX.xKXs); trMV = spm_SpUtil('trMV',X1o); else % Force all voxels to enter non-sphericity trMV = 1; Hsqr = Inf; end trRV = spm_SpUtil('trRV',xX.xKXs); %-Threshold for voxels entering non-sphericity estimates %-------------------------------------------------------------------------- try modality = lower(spm_get_defaults('modality')); UFp = spm_get_defaults(['stats.' modality '.ufp']); catch UFp = 0.001; end xVi.UFp = UFp; UF = spm_invFcdf(1 - UFp,[trMV,trRV]); %-Split data into chunks %-------------------------------------------------------------------------- VY = SPM.xY.VY; mask = logical(spm_read_vols(SPM.VM)); chunksize = floor(spm_get_defaults('stats.maxmem') / 8 / nScan); nbchunks = ceil(prod(DIM) / chunksize); chunks = min(cumsum([1 repmat(chunksize,1,nbchunks)]),prod(DIM)+1); for i=1:nbchunks chunk = chunks(i):chunks(i+1)-1; %-Get data & construct analysis mask %---------------------------------------------------------------------- Y = zeros(nScan,numel(chunk)); cmask = mask(chunk); for j=1:nScan if ~any(cmask), break, end %-Break if empty mask Y(j,cmask) = spm_data_read(VY(j),chunk(cmask));%-Read chunk of data end mask(chunk) = cmask; if ~any(cmask), continue, end Y = Y(:,cmask); %-Data within mask %-Remove filter confounds %---------------------------------------------------------------------- KWY = spm_filter(xX.K,xX.W*Y); %-Ordinary Least Squares estimation %---------------------------------------------------------------------- beta = xX.pKX*KWY; %-Parameter estimates if any(cmask) res = spm_sp('r',xX.xKXs,KWY); %-Residuals else res = zeros(nScan,0); end ResSS = sum(res.^2); %-Residual SSQ clear res %-F-threshold & accumulate spatially whitened Y*Y' %---------------------------------------------------------------------- j = sum((Hsqr*beta).^2,1)/trMV > UF*ResSS/trRV; if nnz(j) Y = Y(:,j); CY = CY + Y*Y'; EY = EY + sum(Y,2); end end %-average sample covariance and mean of Y (over voxels) %-------------------------------------------------------------------------- S = nnz(mask); CY = CY/S; EY = EY/S; CY = CY - EY*EY'; SPM.xVi.CY = CY; clear CY EY %========================================================================== % - E M P I R I C A L B A Y E S F O R P R I O R V A R I A N C E %========================================================================== fprintf('%s%30s\n',repmat(sprintf('\b'),1,30),'...estimating priors') %-# % get row u{i} and column v{i}/v0{i} indices for separable designs %-------------------------------------------------------------------------- s = nHp; if isfield(SPM,'Sess') for i = 1:s u{i} = SPM.Sess(i).row; v{i} = SPM.Sess(i).col; v0{i} = xX.iB(i); end else u{1} = [1:nScan]; v{1} = [xX.iH xX.iC]; v0{1} = [xX.iB xX.iG]; end % cycle over separarable partitions %-------------------------------------------------------------------------- for i = 1:s % Get design X and confounds X0 %---------------------------------------------------------------------- fprintf('%-30s\n',sprintf(' ReML Session %i',i)); %-# X = xX.X(u{i}, v{i}); X0 = xX.X(u{i},v0{i}); [m,n] = size(X); % add confound in 'filter' %---------------------------------------------------------------------- if isstruct(xX.K) X0 = full([X0 xX.K(i).X0]); end % orthogonalize X w.r.t. X0 %---------------------------------------------------------------------- X = X - X0*(pinv(X0)*X); % covariance components induced by parameter variations {Q} %---------------------------------------------------------------------- for j = 1:n Q{j} = X*sparse(j,j,1,n,n)*X'; end % covariance components induced by error non-sphericity {V} %---------------------------------------------------------------------- Q{n + 1} = SPM.xVi.V(u{i},u{i}); % ReML covariance component estimation %---------------------------------------------------------------------- [C,h] = spm_reml(SPM.xVi.CY,X0,Q); % check for negative variance components %---------------------------------------------------------------------- h = abs(h); % 2-level model for this partition using prior variances sP(i) % treat confounds as fixed (i.e. infinite prior variance) %---------------------------------------------------------------------- n0 = size(X0,2); Cb = blkdiag(diag(h(1:n)),speye(n0,n0)*1e8); P{1}.X = [X X0]; P{1}.C = {SPM.xVi.V}; P{2}.X = sparse(size(P{1}.X,2),1); P{2}.C = Cb; sP(i).P = P; sP(i).u = u{:}; sP(i).v = [v{:} v0{:}]; end %========================================================================== % - F I T M O D E L & W R I T E P A R A M E T E R I M A G E S %========================================================================== %-Cycle to avoid memory problems (plane by plane) %========================================================================== spm_progress_bar('Init',100,'Bayesian estimation',''); spm('Pointer','Watch') %-maxMem is the maximum amount of data processed at a time (bytes) %-------------------------------------------------------------------------- MAXMEM = spm_get_defaults('stats.maxmem'); blksz = ceil(MAXMEM/8/nScan); SHp = 0; % sum of hyperparameters for z = 1:zdim % current plane-specific parameters %---------------------------------------------------------------------- U = find(XYZ(3,:) == z); nbch = ceil(length(U)/blksz); CrBl = zeros(nBeta,length(U)); %-conditional parameter estimates CrHp = zeros(nHp, length(U)); %-ReML hyperparameter estimates for bch = 1:nbch %-loop over bunches of lines (planks) %-construct list of voxels in this block %------------------------------------------------------------------ I = [1:blksz] + (bch - 1)*blksz; I = I(I <= length(U)); xyz = XYZ(:,U(I)); nVox = size(xyz,2); %-Get response variable %------------------------------------------------------------------ Y = spm_get_data(SPM.xY.VY,xyz); %-Conditional estimates (per partition, per voxel) %------------------------------------------------------------------ beta = zeros(nBeta,nVox); Hp = zeros(nHp, nVox); for j = 1:s P = sP(j).P; u = sP(j).u; v = sP(j).v; for i = 1:nVox C = spm_PEB(Y(u,i),P); beta(v,i) = C{2}.E(1:length(v)); Hp(j,i) = C{1}.h; end end %-Save for current plane in memory as we go along %------------------------------------------------------------------ CrBl(:,I) = beta; CrHp(:,I) = Hp; SHp = SHp + sum(Hp,2); end % (bch) %-write out plane data to image files %====================================================================== %-Write conditional beta images %---------------------------------------------------------------------- for i = 1:nBeta tmp = sparse(XYZ(1,U),XYZ(2,U),CrBl(i,:),xdim,ydim); tmp(~tmp) = NaN; Vbeta(i) = spm_write_plane(Vbeta(i),tmp,z); end %-Write hyperparameter images %---------------------------------------------------------------------- for i = 1:nHp tmp = sparse(XYZ(1,U),XYZ(2,U),CrHp(i,:),xdim,ydim); tmp(~tmp) = NaN; VHp(i) = spm_write_plane(VHp(i),tmp,z); end %-Report progress %---------------------------------------------------------------------- spm_progress_bar('Set',100*(z - 1)/zdim); end % (for z = 1:zdim) fprintf('\n') %-# spm_progress_bar('Clear') %========================================================================== % - P O S T E S T I M A T I O N %========================================================================== % Taylor expansion for conditional covariance %-------------------------------------------------------------------------- fprintf('%-40s: %30s\n','Non-sphericity','...REML estimation') %-# % expansion point (mean hyperparameters) %-------------------------------------------------------------------------- l = SHp/SPM.xVol.S; % change in conditional coavriance w.r.t. hyperparameters %-------------------------------------------------------------------------- n = size(xX.X,2); PPM.l = l; for i = 1:s PPM.dC{i} = sparse(n,n); PPM.ddC{i} = sparse(n,n); end for i = 1:s P = sP(i).P; u = sP(i).u; v = sP(i).v; % derivatives of conditional covariance w.r.t. hyperparameters %---------------------------------------------------------------------- d = P{1}.X'*inv(P{1}.C{1})*P{1}.X; Cby = inv(d/l(i) + inv(P{2}.C)); d = d*Cby; dC = Cby*d/(l(i)^2); ddC = 2*(dC/(l(i)^2) - Cby/(l(i)^3))*d; % place in output structure %---------------------------------------------------------------------- j = 1:length(v); PPM.Cb(v,v) = P{2}.C(j,j); PPM.Cby(v,v) = Cby(j,j); PPM.dC{i}(v,v) = dC(j,j); PPM.ddC{i}(v,v) = ddC(j,j); end %-Save remaining results files and analysis parameters %========================================================================== fprintf('%-40s: %30s','Saving results','...writing') %-# %-Save analysis parameters in SPM.mat file %-------------------------------------------------------------------------- SPM.VCbeta = Vbeta; % Filenames - parameters SPM.VHp = VHp; % Filenames - hyperparameters SPM.PPM = PPM; % PPM structure save('SPM.mat', 'SPM', spm_get_defaults('mat.format')); fprintf('%s%30s\n',repmat(sprintf('\b'),1,30),'...done') %-# %========================================================================== %- E N D: Cleanup GUI %========================================================================== spm('FigName','Stats: done',Finter); spm('Pointer','Arrow') fprintf('%-40s: %30s\n','Completed',spm('time')) %-#