spm_spm_Bayes.m 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. function [SPM] = spm_spm_Bayes(SPM)
  2. % Conditional parameter estimation of a General Linear Model
  3. % FORMAT [SPM] = spm_spm_Bayes(SPM)
  4. %__________________________________________________________________________
  5. %
  6. % spm_spm_Bayes returns to voxels identified by spm_spm (ML parameter
  7. % estimation) to get conditional parameter estimates and ReML hyper-
  8. % parameter estimates. These estimates use prior covariances, on the
  9. % parameters, from empirical Bayes. These PEB prior variances come from
  10. % the hierarchical model that obtains by considering voxels as providing a
  11. % second level. Put simply, the variance in parameters, over voxels, is
  12. % used as a prior variance from the point of view of any one voxel. The
  13. % error covariance hyperparameters are re-estimated in the light of these
  14. % priors. The approach adopted is essentially a fully Bayesian analysis at
  15. % each voxel, using empirical Bayesian prior variance estimators over
  16. % voxels.
  17. %
  18. % Each separable partition (i.e. session) is assigned its own
  19. % hyperparameter but within session covariance components are lumped
  20. % together, using their relative expectations over voxels. This makes
  21. % things much more computationally efficient and avoids inefficient
  22. % voxel-specific multiple hyperparameter estimates.
  23. %
  24. % spm_spm_Bayes adds the following fields to SPM:
  25. %
  26. % ----------------
  27. %
  28. %
  29. % SPM.PPM.l = session-specific hyperparameter means
  30. % SPM.PPM.Cb = empirical prior parameter covariances
  31. % SPM.PPM.C = conditional covariances of parameters
  32. % SPM.PPM.dC{i} = dC/dl;
  33. % SPM.PPM.ddC{i} = ddC/dldl
  34. %
  35. % The derivatives are used to compute the conditional variance of various
  36. % contrasts in spm_getSPM, using a Taylor expansion about the hyperparameter
  37. % means.
  38. %
  39. %
  40. % ----------------
  41. %
  42. % SPM.VCbeta - Handles of conditional parameter estimates
  43. % SPM.VHp - Handles of hyperparameter estimates
  44. %
  45. % ----------------
  46. %
  47. % Cbeta_????.<ext> - conditional parameter images
  48. % These are 32-bit (float) images of the conditional estimates. The image
  49. % files are numbered according to the corresponding column of the
  50. % design matrix. Voxels outside the analysis mask (mask.<ext>) are given
  51. % value NaN.
  52. %
  53. % ----------------
  54. %
  55. % CHp_????.<ext> - error covariance hyperparameter images
  56. % This is a 64-bit (double) image of the ReML error variance estimate.
  57. % for each separable partition (Session). Voxels outside the analysis
  58. % mask are given value NaN.
  59. %__________________________________________________________________________
  60. %
  61. % For single subject fMRI analysis there is an alternative function
  62. % using voxel-wise GLM-AR models that are spatially regularised
  63. % using the VB framework. This is implemented using spm_spm_vb.m.
  64. %__________________________________________________________________________
  65. % Copyright (C) 2002-2013 Wellcome Trust Centre for Neuroimaging
  66. % Karl Friston
  67. % $Id: spm_spm_Bayes.m 5354 2013-03-25 18:50:54Z guillaume $
  68. %-Say hello
  69. %--------------------------------------------------------------------------
  70. Finter = spm('FigName','Stats: Bayesian estimation...');
  71. %-Select SPM.mat & change directory
  72. %--------------------------------------------------------------------------
  73. if ~nargin
  74. [Pf, sts] = spm_select(1,'^SPM\.mat$','Select SPM.mat');
  75. if ~sts, return; end
  76. swd = spm_file(Pf,'fpath');
  77. load(fullfile(swd,'SPM.mat'))
  78. cd(swd)
  79. end
  80. try
  81. M = SPM.xVol.M;
  82. DIM = SPM.xVol.DIM;
  83. xdim = DIM(1); ydim = DIM(2); zdim = DIM(3);
  84. XYZ = SPM.xVol.XYZ;
  85. catch
  86. helpdlg({ 'Please do a ML estimation first.',...
  87. 'This identifies the voxels to analyse.'});
  88. spm('FigName','Stats: done',Finter); spm('Pointer','Arrow')
  89. return
  90. end
  91. %==========================================================================
  92. % - A N A L Y S I S P R E L I M I N A R I E S
  93. %==========================================================================
  94. %-Initialise output images
  95. %==========================================================================
  96. fprintf('%-40s: %30s','Output images','...initialising') %-#
  97. %-Initialise conditional estimate image files
  98. %--------------------------------------------------------------------------
  99. xX = SPM.xX;
  100. [nScan,nBeta] = size(xX.X);
  101. Vbeta(1:nBeta) = deal(struct(...
  102. 'fname', [],...
  103. 'dim', DIM',...
  104. 'dt', [spm_type('float32'), spm_platform('bigend')],...
  105. 'mat', M,...
  106. 'pinfo', [1 0 0]',...
  107. 'descrip', ''));
  108. for i = 1:nBeta
  109. Vbeta(i).fname = [sprintf('Cbeta_%04d',i) spm_file_ext];
  110. Vbeta(i).descrip = sprintf('Cond. beta (%04d) - %s',i,xX.name{i});
  111. spm_unlink(Vbeta(i).fname)
  112. end
  113. Vbeta = spm_create_vol(Vbeta);
  114. %-Initialise ReML hyperparameter image files
  115. %--------------------------------------------------------------------------
  116. try
  117. nHp = length(SPM.nscan);
  118. catch
  119. nHp = nScan;
  120. SPM.nscan = nScan;
  121. end
  122. VHp(1:nHp) = deal(struct(...
  123. 'fname', [],...
  124. 'dim', DIM',...
  125. 'dt', [spm_type('float64'), spm_platform('bigend')],...
  126. 'mat', M,...
  127. 'pinfo', [1 0 0]',...
  128. 'descrip', ''));
  129. for i = 1:nHp
  130. VHp(i).fname = [sprintf('Hp_%04d',i) spm_file_ext];
  131. VHp(i).descrip = sprintf('Hyperparameter (%04d)',i);
  132. spm_unlink(VHp(i).fname)
  133. end
  134. VHp = spm_create_vol(VHp);
  135. fprintf('%s%30s',repmat(sprintf('\b'),1,30),'...initialised') %-#
  136. %==========================================================================
  137. % - 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
  138. %==========================================================================
  139. fprintf('%s%30s',repmat(sprintf('\b'),1,30),'...estimating CY') %-#
  140. CY = 0; % <(Y - <Y>) * (Y - <Y>)'>
  141. EY = 0; % <Y> for ReML
  142. nScan = size(xX.X,1);
  143. xVi = SPM.xVi;
  144. %-Compute Hsqr and F-threshold under i.i.d.
  145. %--------------------------------------------------------------------------
  146. xX.xKXs = spm_sp('Set',spm_filter(xX.K,xX.W*xX.X));
  147. xX.xKXs.X = full(xX.xKXs.X);
  148. xX.pKX = spm_sp('x-',xX.xKXs);
  149. if isfield(xVi,'Fcontrast')
  150. Fcname = 'User-specified contrast';
  151. xCon = spm_FcUtil('Set',Fcname,'F','c',xVi.Fcontrast,xX.xKXs);
  152. else
  153. Fcname = 'effects of interest';
  154. iX0 = [xX.iB xX.iG];
  155. xCon = spm_FcUtil('Set',Fcname,'F','iX0',iX0,xX.xKXs);
  156. end
  157. if ~isempty(xCon(1).c)
  158. X1o = spm_FcUtil('X1o', xCon(1),xX.xKXs);
  159. Hsqr = spm_FcUtil('Hsqr',xCon(1),xX.xKXs);
  160. trMV = spm_SpUtil('trMV',X1o);
  161. else
  162. % Force all voxels to enter non-sphericity
  163. trMV = 1;
  164. Hsqr = Inf;
  165. end
  166. trRV = spm_SpUtil('trRV',xX.xKXs);
  167. %-Threshold for voxels entering non-sphericity estimates
  168. %--------------------------------------------------------------------------
  169. try
  170. modality = lower(spm_get_defaults('modality'));
  171. UFp = spm_get_defaults(['stats.' modality '.ufp']);
  172. catch
  173. UFp = 0.001;
  174. end
  175. xVi.UFp = UFp;
  176. UF = spm_invFcdf(1 - UFp,[trMV,trRV]);
  177. %-Split data into chunks
  178. %--------------------------------------------------------------------------
  179. VY = SPM.xY.VY;
  180. mask = logical(spm_read_vols(SPM.VM));
  181. chunksize = floor(spm_get_defaults('stats.maxmem') / 8 / nScan);
  182. nbchunks = ceil(prod(DIM) / chunksize);
  183. chunks = min(cumsum([1 repmat(chunksize,1,nbchunks)]),prod(DIM)+1);
  184. for i=1:nbchunks
  185. chunk = chunks(i):chunks(i+1)-1;
  186. %-Get data & construct analysis mask
  187. %----------------------------------------------------------------------
  188. Y = zeros(nScan,numel(chunk));
  189. cmask = mask(chunk);
  190. for j=1:nScan
  191. if ~any(cmask), break, end %-Break if empty mask
  192. Y(j,cmask) = spm_data_read(VY(j),chunk(cmask));%-Read chunk of data
  193. end
  194. mask(chunk) = cmask;
  195. if ~any(cmask), continue, end
  196. Y = Y(:,cmask); %-Data within mask
  197. %-Remove filter confounds
  198. %----------------------------------------------------------------------
  199. KWY = spm_filter(xX.K,xX.W*Y);
  200. %-Ordinary Least Squares estimation
  201. %----------------------------------------------------------------------
  202. beta = xX.pKX*KWY; %-Parameter estimates
  203. if any(cmask)
  204. res = spm_sp('r',xX.xKXs,KWY); %-Residuals
  205. else
  206. res = zeros(nScan,0);
  207. end
  208. ResSS = sum(res.^2); %-Residual SSQ
  209. clear res
  210. %-F-threshold & accumulate spatially whitened Y*Y'
  211. %----------------------------------------------------------------------
  212. j = sum((Hsqr*beta).^2,1)/trMV > UF*ResSS/trRV;
  213. if nnz(j)
  214. Y = Y(:,j);
  215. CY = CY + Y*Y';
  216. EY = EY + sum(Y,2);
  217. end
  218. end
  219. %-average sample covariance and mean of Y (over voxels)
  220. %--------------------------------------------------------------------------
  221. S = nnz(mask);
  222. CY = CY/S;
  223. EY = EY/S;
  224. CY = CY - EY*EY';
  225. SPM.xVi.CY = CY;
  226. clear CY EY
  227. %==========================================================================
  228. % - 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
  229. %==========================================================================
  230. fprintf('%s%30s\n',repmat(sprintf('\b'),1,30),'...estimating priors') %-#
  231. % get row u{i} and column v{i}/v0{i} indices for separable designs
  232. %--------------------------------------------------------------------------
  233. s = nHp;
  234. if isfield(SPM,'Sess')
  235. for i = 1:s
  236. u{i} = SPM.Sess(i).row;
  237. v{i} = SPM.Sess(i).col;
  238. v0{i} = xX.iB(i);
  239. end
  240. else
  241. u{1} = [1:nScan];
  242. v{1} = [xX.iH xX.iC];
  243. v0{1} = [xX.iB xX.iG];
  244. end
  245. % cycle over separarable partitions
  246. %--------------------------------------------------------------------------
  247. for i = 1:s
  248. % Get design X and confounds X0
  249. %----------------------------------------------------------------------
  250. fprintf('%-30s\n',sprintf(' ReML Session %i',i)); %-#
  251. X = xX.X(u{i}, v{i});
  252. X0 = xX.X(u{i},v0{i});
  253. [m,n] = size(X);
  254. % add confound in 'filter'
  255. %----------------------------------------------------------------------
  256. if isstruct(xX.K)
  257. X0 = full([X0 xX.K(i).X0]);
  258. end
  259. % orthogonalize X w.r.t. X0
  260. %----------------------------------------------------------------------
  261. X = X - X0*(pinv(X0)*X);
  262. % covariance components induced by parameter variations {Q}
  263. %----------------------------------------------------------------------
  264. for j = 1:n
  265. Q{j} = X*sparse(j,j,1,n,n)*X';
  266. end
  267. % covariance components induced by error non-sphericity {V}
  268. %----------------------------------------------------------------------
  269. Q{n + 1} = SPM.xVi.V(u{i},u{i});
  270. % ReML covariance component estimation
  271. %----------------------------------------------------------------------
  272. [C,h] = spm_reml(SPM.xVi.CY,X0,Q);
  273. % check for negative variance components
  274. %----------------------------------------------------------------------
  275. h = abs(h);
  276. % 2-level model for this partition using prior variances sP(i)
  277. % treat confounds as fixed (i.e. infinite prior variance)
  278. %----------------------------------------------------------------------
  279. n0 = size(X0,2);
  280. Cb = blkdiag(diag(h(1:n)),speye(n0,n0)*1e8);
  281. P{1}.X = [X X0];
  282. P{1}.C = {SPM.xVi.V};
  283. P{2}.X = sparse(size(P{1}.X,2),1);
  284. P{2}.C = Cb;
  285. sP(i).P = P;
  286. sP(i).u = u{:};
  287. sP(i).v = [v{:} v0{:}];
  288. end
  289. %==========================================================================
  290. % - 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
  291. %==========================================================================
  292. %-Cycle to avoid memory problems (plane by plane)
  293. %==========================================================================
  294. spm_progress_bar('Init',100,'Bayesian estimation','');
  295. spm('Pointer','Watch')
  296. %-maxMem is the maximum amount of data processed at a time (bytes)
  297. %--------------------------------------------------------------------------
  298. MAXMEM = spm_get_defaults('stats.maxmem');
  299. blksz = ceil(MAXMEM/8/nScan);
  300. SHp = 0; % sum of hyperparameters
  301. for z = 1:zdim
  302. % current plane-specific parameters
  303. %----------------------------------------------------------------------
  304. U = find(XYZ(3,:) == z);
  305. nbch = ceil(length(U)/blksz);
  306. CrBl = zeros(nBeta,length(U)); %-conditional parameter estimates
  307. CrHp = zeros(nHp, length(U)); %-ReML hyperparameter estimates
  308. for bch = 1:nbch %-loop over bunches of lines (planks)
  309. %-construct list of voxels in this block
  310. %------------------------------------------------------------------
  311. I = [1:blksz] + (bch - 1)*blksz;
  312. I = I(I <= length(U));
  313. xyz = XYZ(:,U(I));
  314. nVox = size(xyz,2);
  315. %-Get response variable
  316. %------------------------------------------------------------------
  317. Y = spm_get_data(SPM.xY.VY,xyz);
  318. %-Conditional estimates (per partition, per voxel)
  319. %------------------------------------------------------------------
  320. beta = zeros(nBeta,nVox);
  321. Hp = zeros(nHp, nVox);
  322. for j = 1:s
  323. P = sP(j).P;
  324. u = sP(j).u;
  325. v = sP(j).v;
  326. for i = 1:nVox
  327. C = spm_PEB(Y(u,i),P);
  328. beta(v,i) = C{2}.E(1:length(v));
  329. Hp(j,i) = C{1}.h;
  330. end
  331. end
  332. %-Save for current plane in memory as we go along
  333. %------------------------------------------------------------------
  334. CrBl(:,I) = beta;
  335. CrHp(:,I) = Hp;
  336. SHp = SHp + sum(Hp,2);
  337. end % (bch)
  338. %-write out plane data to image files
  339. %======================================================================
  340. %-Write conditional beta images
  341. %----------------------------------------------------------------------
  342. for i = 1:nBeta
  343. tmp = sparse(XYZ(1,U),XYZ(2,U),CrBl(i,:),xdim,ydim);
  344. tmp(~tmp) = NaN;
  345. Vbeta(i) = spm_write_plane(Vbeta(i),tmp,z);
  346. end
  347. %-Write hyperparameter images
  348. %----------------------------------------------------------------------
  349. for i = 1:nHp
  350. tmp = sparse(XYZ(1,U),XYZ(2,U),CrHp(i,:),xdim,ydim);
  351. tmp(~tmp) = NaN;
  352. VHp(i) = spm_write_plane(VHp(i),tmp,z);
  353. end
  354. %-Report progress
  355. %----------------------------------------------------------------------
  356. spm_progress_bar('Set',100*(z - 1)/zdim);
  357. end % (for z = 1:zdim)
  358. fprintf('\n') %-#
  359. spm_progress_bar('Clear')
  360. %==========================================================================
  361. % - P O S T E S T I M A T I O N
  362. %==========================================================================
  363. % Taylor expansion for conditional covariance
  364. %--------------------------------------------------------------------------
  365. fprintf('%-40s: %30s\n','Non-sphericity','...REML estimation') %-#
  366. % expansion point (mean hyperparameters)
  367. %--------------------------------------------------------------------------
  368. l = SHp/SPM.xVol.S;
  369. % change in conditional coavriance w.r.t. hyperparameters
  370. %--------------------------------------------------------------------------
  371. n = size(xX.X,2);
  372. PPM.l = l;
  373. for i = 1:s
  374. PPM.dC{i} = sparse(n,n);
  375. PPM.ddC{i} = sparse(n,n);
  376. end
  377. for i = 1:s
  378. P = sP(i).P;
  379. u = sP(i).u;
  380. v = sP(i).v;
  381. % derivatives of conditional covariance w.r.t. hyperparameters
  382. %----------------------------------------------------------------------
  383. d = P{1}.X'*inv(P{1}.C{1})*P{1}.X;
  384. Cby = inv(d/l(i) + inv(P{2}.C));
  385. d = d*Cby;
  386. dC = Cby*d/(l(i)^2);
  387. ddC = 2*(dC/(l(i)^2) - Cby/(l(i)^3))*d;
  388. % place in output structure
  389. %----------------------------------------------------------------------
  390. j = 1:length(v);
  391. PPM.Cb(v,v) = P{2}.C(j,j);
  392. PPM.Cby(v,v) = Cby(j,j);
  393. PPM.dC{i}(v,v) = dC(j,j);
  394. PPM.ddC{i}(v,v) = ddC(j,j);
  395. end
  396. %-Save remaining results files and analysis parameters
  397. %==========================================================================
  398. fprintf('%-40s: %30s','Saving results','...writing') %-#
  399. %-Save analysis parameters in SPM.mat file
  400. %--------------------------------------------------------------------------
  401. SPM.VCbeta = Vbeta; % Filenames - parameters
  402. SPM.VHp = VHp; % Filenames - hyperparameters
  403. SPM.PPM = PPM; % PPM structure
  404. save('SPM.mat', 'SPM', spm_get_defaults('mat.format'));
  405. fprintf('%s%30s\n',repmat(sprintf('\b'),1,30),'...done') %-#
  406. %==========================================================================
  407. %- E N D: Cleanup GUI
  408. %==========================================================================
  409. spm('FigName','Stats: done',Finter); spm('Pointer','Arrow')
  410. fprintf('%-40s: %30s\n','Completed',spm('time')) %-#