data.mat0000644061573100372000000001340011167120202011033 0ustar fd258divfMATLAB 5.0 MAT-file, Platform: GLNXA64, Created on: Sun Aug 17 16:09:09 2008 IMé xœ-”{4Ô Çvå%±¡mC!b‹"ÏH%¡L)RÔJ”¢TÓ0•Kn5¹LÂ0É=3ŒÛŒñŒ11B´éEZ—J«M5%!ÊkÏû>ç|Ï÷|ÏóüõœÏù.$Âb>AÈ͹ñ?ÿwæý?«ÏiÑœdˆŸ ßS¡„â¿Ë¹û÷”¯‡ƒ¼ó€êå°¿/ˆóžG¢Í…°Î`Vïïçip޽Pà#Ÿ‡v.›•‚€è6eÅ5!1yæRËno 6ØÚßÊ…"-t¾âØ‚Ô0KÅ�7#‘Øv(Y~†Œ#}†œÿjØfÝåÛÙzðáê!o û´ 1S �2«†;èp<2àt¥ôLè]RŽgCðÍP³ö*xôÊU+V)‰¡ýGÅ�þ n¼ô›$ÿ¨,·kùòt› |J±3/peºN%P•æ�j'À$å•ùö‰èt°\ѾO€¶f«*uØHÚBxä>ÍÃñ8´­© C|ç%äLj‘ZóÞáC)¾rópþüRËøYnùê-`þëÌÍ f.Ô­Bok¤–Ìæè`‚aú‰ŠÅ-pÖMûÅ/äûàËŠ¼°üR.;IϦxPâg£[ËêÚÙ§¦7(PÍt¿guÙïÛš†:Íâxãm—¾£`øs“'ùhêôöÔYxÔ€>«öÞÆHú- ô5üÄ\Öaj�Éœë«û+p£lrÁÍfˆëg,½AƒÎ)»‡³—“ÁbBßåŠRz ž¤6uI@ÞÈÎ$Û�ƒeVÔ»©àþ%dh[a=ŽüÐᧈÀv|¹ì’’‰¶:¯.á S\£Ï]ˆ·ª­�V!PéC‡º(<´‘¶n,Ó„ì‹<<Ça)y̲vŽŸ\f·ÕòÐj骭xPˆžz1Ï¿/Ã'©UNN5øÎû¢2�F/|å9P³ÞK)|8Ëj)©¿õ2¡3Åt‡� }3î˜âBoŸÙB'!8=Úîw‚V‰Zv’LG^𤱷Ÿ‰@nlF9V>_ehÉ\À¨Î–QqwnÐ ûsŠaÔTßu×™8<íRì¦%Y¨à¡QcýúHX²ŒxÇ"0±":â b`Ò‘|-é$UËkñAÓì!œÚ’ úCkŠHñ±(msÕhYÕ {ž¬í±”Ìñf?¥JA£¿;Ò«A'iu§fw-Jn®˜x!,ƒ¢ì½Ùýö¨¤ é_±.óÅ;ÕSãË�Pþ1O-œŒ ”¼ a®Ø©’ð*¥¼ŸßF:Pá' öÛ6á­�SõöQh4>ó2û‹ƒÏ.Jøž_Š2CSÂ77„h4b rÝ{“›�.ª÷ÓŽ×1p à‡&l°x«æÜÉÌÆ/vl; �ãr¿}ÒSúè_[Oãæã´„!ä}R}Ò~ƒg\¨sœ„vŽýãJ…Ç^Ü6»îy[q~¬�Ô ¥œíÜHŒÜ²†>2^ªY;Ì<õ¹ÒÞ¯<>UƒíÆÚ£´£|”8 øÂ){nÜûÞC…tå»å GÚ0`È[} 5‰TEÁºt.œ,^­•RÝ 6öüÂ8ÍxVÂ]¦Q &RÙð=œr°ÙFËá»6€ÎþAò|çbP•W³o(‡¡E#“ž‘ùHý™?î0Ý㩺“Ý­é°Øvcne’û7 .>÷0û¦W7+Á(»>*is9P=²Ö;[ÞGbíõ¨°,$ž+žÛû-'“„³8«ýmÝðˆâS U— SGámŸ¦t�Ä®“@õ‚_W¿å Ìʉ-]F\�êÄÌœÜ-�R#ù*ƒzžú³Þ$>÷Õ¿�­R´wo›m66ì·[˜¼¢GÆ–7,ç�Í>KßšŽFõ@u+·ÿ¾—$õÇ£íX³Àå\QÅÜÿëôÛN¹ cUŸt»¤²bþü8ÒÙ€ ^ÓŸ×Sª *¸Õs� „yŠc]íÁ뽟"ñNâ×Ví!!ôÞ¶M9… ù2› o·à•™íE^�¨Þ[õQ=± GË=n.̬C…ß×Ý3ù8¸èXãù:Hv>–6“(�ì›”^ù*Tw[º¹í'6T—rúƒ_–‚¤8ù¥ƒ <÷vLc A¨Åõ;tþ2â•J^ @mÇÓìu`¿Ûï^h|£´gþ˜_ŠÙO�UêŸ1×?|އàûÆ‹ÊVžL¨ú©Ô‹ò„‹† �?PR‰¿{ËNº‡g²XûKŠàsЗ5ŠPŒÕšû‰§t¸ßóÄ¿p$ åžï ໡tÍkFÃö?CXŒuâ‚F¬fP™ˆ�XRû=ûþå„CJt “Céh¶ÉCû}t<^õ)¼0¹�ú[²bš+Á]VZ¬( �Ì^µc™eSG&|¬s�u®«Kuš†}VùQ��÷ðék—"ý«,<F žÅqFÛ—0!® I/Hú@;éŒÆî�"ŒWªí»Ÿ�a[ä>ŽZ²Alã_·à. þ Î(³$xœãc``0b6 æ€Ò À å3Â1#ƒ�fÒ"@PÉ$xœãc``0b6 æ€Ò À å3Â1#ƒ7�fÒ,@ì¶$xœãc``0b6 æ€Ò À å3Â1#ƒ �fÒ@È»'xœãc``°b6 æ€Ò À å3"a�XbNAF"�fŠ€Ä4z0xœãc``pb6 æ€Ò À å3"av .ÎLÏMŒOdà„Ê[Ìù6áÝm{n`-xœãc``pb6 æ€Ò À å3"av .ÎLÏMŒÏcà„ÊÏš ;íp)øJxœãc``b6 æ€Ò À å31 ˜ff(È,fಀøå5ñw_*ŸÛŸ|ã5÷•Çcû ©ö3ûíӢΔXÍ>`�s @xœmŠ1 QÑÅɇ9ûŸnª]S®Gi€%²(¢œ$¿»ˆ‚š)Û{X�4´I\V¾x Oø6§f—8xœãc``(b6 æ€Ò À å³±3¡#�fb0†!²pÀC0`%(ò ujIî xœ-U 4Ô 5Eɲ”,!Ê–Tu§'I$Ó"¥…GJåñR)¯d-$’Ð$KFö‰©± º3(<¼(žÄ#©že–ÿ >ªoÞù¾{Ï=¿s·sϹçÜß•'‘H–’H‹%(Cúþ+‹þï«HLQbRu—à’“’z~è?'ýO=E_ý©Í[…@úäg¨59[ ~èýý! /—É×yJ? ¾Y]né8| ‰¾q¨S Q¯w®r#„`}ÈÆ*Ê—EèxÓ®ø>J!kô8 öYê&™€HrŸŸŽ2¬¬+<-xðnQv˜å4N:*·»m@I§­ÿò&ó´óèoíFA*ù·ÀP\ÔƒLÛ+ð÷ag�XÙÐÎK·1‚›ì9·QPÐ? u“ lݦOì¾³qŽçÁ‡·=ûŸ�‚î½…lÕ!¬Ö×{{½[/lL×—ë”AI«áƒ+Ðp‡š¦;&†]3Å߯ Î?ŸÚ,‚2³üã+÷@ŸÓò©9'‚4ʶ¯ý² xàqòê�(v˜ú넺 ›ˆ”m¯€Ö¦?«œŠE·¼ƾ—¦ej™?@>kæeåß"èê>V¢§T�+&C«¶ö“(VÆnê»=ÐïsèÑáMDlØÇX&„gA»rqªÇÍëô£/Cuwïìs!,¤èÙ©û�(º£”ñ�|X™¤4•(E@ϬöÂð8X7ÚóºÌJ²E*IbÈ[S!]L¢ ïssªGÍšÌ}ù*-h¾j>)=;Î’ç§%ý>ßäÖq ¸køÐï…R ^Ú§Ý¿‚š‡^ôðkZ×s�ÓAéže§##ÐÛZ·š‰a›¼3¹Š•Ù®¹–7|!ÏÆ$ÈÁ'Ig8õù áÂ×îTŸLÐé}_»Á­ õéÕ¹ÛÃÙà­zÞËPÄDÔì 11H@�óyÛE°�|¯@N½ ãh+ï„6b¢æŸRŠ×…´ÿùd¥§<>^{ÝÕŒÒF¶ÆY®5Øyëç﫜„`¯ –ð`LôÊ·Þiñ ®Òûú½“<8Q¿ÛѬ ¸ŒáYMK!ì7«±ÜÐ.Ù�Æ€=?_Ò¡Õö‹ÁÞ�œ;Ò(òVóä9I<'»ÇR+¨ÔäiŠ¿¶°~úD,ev D„åÀ“'•è]¸hRa �ú½¤™ÏhXµÕC6øË(­M]Ý›�)&.žÆ,ðZ’þÈü {_L™Ê;pÐá÷½Þ~‘å aÛœaÇ~�lbgìƒîz\<1¿,Vú|öO×�ºU‡<{^cOlÓ;Cõe#ÏDßùÀÅ8¸}=ö'ÕL�qS«²ú|›édZ¼][’ÞÄs1dpÆŽ‚'t+¥5jPÝôübŸ…úCE”øX ÚœÕZÖ7á¡ÎÍï76¢m`üìr-Œþî�O¶«D�D³õžjhNZ3ÝÏ)Å¢¬ÃY;˜X9¤ÓªÍ•ö«¤Æ—BäMnã ÉË„>õWã<�5ûî§´â©“W÷PŽ•`°_!÷¨Ík¸/œ}¹#‚‰ ë.~Êšä@À%Å»ßò 54Ëùz‡F#õ·£@|+èÚŠsØyÔs‹ ^ÁϼѸ 7Œ*;vdgÁ¤mA™-D¢ mŒ:°£’Sú’ÿiýv�}y7…ƒ9F¢å�í×Ð.`Þ)L¶‚ ;&ÆœÃðV[]Yæž²d®úX…©Û̽¬p··H™ªÀå™.¦îú,èáµ»f%Š }�6/Ò§šÜbFš8|Èèð_ò¸VÉá+¨ñpfè”Ê`jPÚOÍ^àƒÁaVõJ¥1°ÞQS§þ»KXšÚ!åhL�ƒ1Ÿ£Ø4K­³dtŽ~¤.u,ÆåÒÊ;ÚŸã�âÈŒ{x>è@R„ùÎ1˜JÕ�éi}ˆJ6ÛsÊ»jðÞÀ®:ƒß^¡ë•¯‡“Êq•I�Â/•|`‰Ûï3 (°Pay<&€Å^ÿMŽ)�49Ì™—´ÿ³åË ÷\Yóåþk!LÜØY?/€Y]Å‘Ø-ÍX)·Êìs¤ÖNÛw±°qú/Žþø(0Œ¤+ ^²1àäìÛ—Æ9(è{9[�«CO[ ¯À=j+oMŒp'´¸Zl´>ç©j÷õw¨×N§® ã‚;ãLÎèEL��ŒèHø×!fÅ, Ýœ™g²|pZ¢eºìÀŒ›7pÏ\«À#*ª7ŠÜÅ ¨0¸vÍØÿøÒ–Zåb_äL¤C]9^Óc¶Eÿ…+Z^Z+à_D|Ô‚0µ€�q 1Þ‹»|•µÅ’ã_ÿq1šã �ÎÁ¿Ž­+驾†-zOejp±²l›[U$hgPë|œ è�Xïµê:ôÔåF¶ñà�ÿRU×ÓBˆZ¸{¨m@Šâ˜éÆŒ‹å�kûðÌ þÐ$Wn9-€Ì˜·Â‘.Üõ˜o ­Àˆ€Vw cÉž[3½ì%óš­\zEáð(áŸVí!ö>°I¹z“…_7QF¢6NÀÍù½Çë=΃Jo…P%¡ xÏÝ’ä3jA&ÆësÏ|>ˆŸµxÇÀwxÌXû�Ò? uä¯)½Ò ²oå®¶eXÉ`|b`sñ½Oj4²]Û1-›ƒ –·ŸþeÄf4ס²Ë»,¿Z&–�u-\w noÏø¾”Yï€ÎðM—ðÇwϳÁÀoøm™¥{6V,`x„v²Àð.ä–”æSäébQ.œ¹˜I?ZR„bÿI‹%P ¿)7 �ÞIþñûNß‘<ñ„ä>®T‡ß � kQÔÑlþÂb¨m,ð3¢7¡Âü`ì´ê <âû!¤8¿%ÒÔ¨Èöãðu¡T&ì»°ÕAμ¤Þˆ|™Á‚„ã6»l)ÌþqkãZïWøÞüÐ\J¶+Òd ºì¹Bho+»\V^ÄܽȤT4‘©Ù-ÜPç›9-3€T½Ì;Û±QÂ[Whò««àË\ä@I}=ìýârxÓ6<üƒÈ;sÿtü01É\Ì�=! `ÐêvIŠäÔ+¦:‹[àÐ)j+N%ÚlÕŠ_Jà�ftÎLJì÷êdQ‹Ëð0ó랺‰4 K¼±  £”ê¦Ìóž¶M²ªtäÆtßîç€JZÍ9Íçé(£3ýè)h,…jœˆh%²œ#�>½-?<ºƒ•eR~ÔÀP÷·I¿�i@ÜÕ%Ÿx¦?¹ióoÇC”gáµ™#ɨoŸÃm*GW2Q¼¤±l¥+ŸÎ@,�ýyÚÓê Ð/wu-Ÿ‹„>Ëüˆó ¹ðî³S‘~~½}%¹þã%˜¢µ=rºÂ�Í� ÉhKÌ« ,‚xÙÚú#yùpÅ~±�·± ­}kåÓñ¿E0šgxœãc``(`d``Ò X¡| bF†ˆŒÄ& Û�$ÀÂ@’‘Jácbd`‚p T32À¡`D¡°š7†�ŒEcB8"v)’:&<Ž!Æ}˜Ú(xœãc``°b6 æ€Ò À å3"a�˜wIQi*�fаi4‚README0000644061573100372000000000740111177572726010332 0ustar fd258divf------------------------------------------------------- Variational Inference for the IBP. ------------------------------------------------------- This package contains code for doing variational inference for the Indian Buffet Process. The code is self-contained and runs with recent Matlab distributions (we have tested it with r2008a and r2007a). Please contact Finale Doshi-Velez at finale@alum.mit.edu or Kurt Miller at ktmiller@gmail.com for questions and feedback (and bug-fixes :). Below we describe the different files in the distribution. References: Variational Inference for the Indian Buffet Process Finale Doshi-Velez, Kurt T. Miller, Jurgen Van Gael and Yee Whye Teh Conference on Artificial Intelligence and Statistics (AISTATS 2009). Variational Inference for the Indian Buffet Process Finale Doshi-Velez, Kurt T. Miller, Jurgen Van Gael and Yee Whye Teh University of Cambridge, Engineering Department, Technical Report CBL-2009-001. Files included in the distribution: * tester.m: this is the main starting point for any experiments. It shows how to set up the data structures for the parameters of the inference algorithms and then runs the following algorithms: - finite LG variational - infinite LG variational - infinite iICA variational (to be made available soon) - finite iICA variational (to be made available soon) * run_vibp.m: Runs variational inference for a finite or infinite IBP model. * data.mat: example test data. This is very simple data generated from a linear Gaussian model. * vibp_base/compute_variational_lower_bound.m: Computes the lower bound on the log marginal likelihood of the data based on the variational parameters. * vibp_base/vibp.m: Performs the variational updates for the finite model and keeps track of the lower bound. * util/minimize.m: Minimize a differentiable multivariate function. * util/v2pi.m: Converts stick-breaking variables v into feature probabilities pi. * heuristics/run_search_heuristics.m: Run different heuristics (swapping features, subtracting features, ...) for improving the variational lower bound. * heuristics/update_feature_order.m: Updates the features to be in descending order of probability. * heuristics/update_small_model.m: updates a model proposal, increasing the subset of the data used. * heuristics/initialise_small_model.m: initializes a model proposal using a subset of the data. * vibp_finite/compute_var_theta_k.m: Computes an intermediate value for the update for the finite variational parameter nu. * vibp_finite/update_tau.m: Performs the update for the finite variational parameter tau. * vipb_infinite/compute_expected_pzk0_qjensen.m: Computes E[ ln( 1 - prod( 1 - v ) ) ] using Jensen's inequality and a variational multinomial distribution q (see paper for details). * vipb_infinite/compute_var_theta_k.m: Computes an intermediate value for the update for the infinite variational parameter nu. * vipb_infinite/update_tau.m: Performs the update for the infinite variational parameter tau. Change Log ---------- v 1.0 - May 2009 * Initial release at /revision/view/230/ =========================================================================== (C) Copyright, Finale Doshi-Velez, Kurt T. Miller, Jurgen Van Gael Permission is granted for anyone to copy, use, or modify these programs and accompanying documents for purposes of research or education, provided this copyright notice is retained, and note is made of any changes that have been made. These programs and documents are distributed without any warranty, express or implied. As the programs were written for research purposes only, they have not been tested to the degree that would be advisable in any important application. All use of these programs is entirely at the user's own risk. run_vibp.m0000644061573100372000000002510511177553366011454 0ustar fd258divffunction out = run_vibp( X , param_set ) % function out = run_vibp( X , param_set ) % Inputs and Outputs: % * X is an N by D matrix of data % * param_set is a struct containing parameters for running the algorithm % (see tester.m for definitions) % * out is a struct containing % - out.model_set = model_set; % - out.lower_bounds_log_set = lower_bounds_log_set; % - out.final_lower_bound_set = final_lower_bound_set; % - out.best_model = model; % - out.best_lower_bounds_log = lower_bounds_log; % % Notes: % * the tau parameters are variational parameters on the beta distribution % over either pi (finite model) or v (infinite model) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % get basic info K = param_set.K; [N D] = size( X ); alpha = param_set.alpha; % loop for the number of restarts model_set = cell(1,param_set.restart_count); lower_bounds_log_set = cell(1,param_set.restart_count); final_lower_bound_set = zeros(1,param_set.restart_count); for restart_index = 1:param_set.restart_count fprintf('\n----------------------------------------------\n'); fprintf('Restart number %d of %d (%.2f%%)\n', restart_index, param_set.restart_count, ... restart_index/param_set.restart_count*100.0); % ---------------------------------------------------------- % % Randomly initialize the variational parameters % % ---------------------------------------------------------- % % You can often get better performance by doing a principled % initialisation, but this depends more on the model and data. clear model; % feature probabilities % finite model: pi's(k) ~ Beta(tau(1,k),tau(2,k)); % infinite model: v's(k) ~ Beta(tau(1,k),tau(2,k)); model.tau = ones( 2 , K ); if param_set.use_finite_model model.tau( 1 , : ) = alpha/K; model.tau = model.tau + ... .5 * min( 1 , alpha/K ) * ( rand( size( model.tau ) ) - .5 ); else model.tau( 1 , : ) = alpha; model.tau = model.tau + ... .5 * min( 1 , alpha ) * ( rand( size( model.tau ) ) - .5 ); end % features % A(k,:) ~ Normal(phi_mean(:,k), diag(phi_cov(:,k))) model.phi_mean = randn(D,K)*0.01; model.phi_cov = randn(D,K).^2*0.1; % feature assignments % Z(n,k) ~ Bernoulli(nu(n,k)) model.nu = rand(N,K); % initialise remaining variables initial_time = cputime; lower_bounds_log = zeros(2,0); lower_bounds_log(1,1) = compute_variational_lower_bound( ... param_set, X, alpha, param_set.sigma_a, param_set.sigma_n, model); lower_bounds_log(2,1) = 0; % initialise the model subset if adding data in pieces if param_set.add_data_in_blocks [ model X param_set orig_data ] = initialise_small_model( model , X , param_set ); end % ------------------------------------------------- % % Run the Variational Inference % % ------------------------------------------------- % iter = 1; use_tempering = param_set.use_tempering; while 1 % ---- store model parameters ---- % model.tau_set{iter} = model.tau; model.phi_mean_set{iter} = model.phi_mean; model.phi_cov_set{iter} = model.phi_cov; model.nu_set{iter} = model.nu; % ---- slowly temper sigma_a and sigma_n if we are tempering ---- % % Note that by playing with the rate of tempering, you can % affect the quality of your final solution. The following % rates are ones that we found useful with our data, but % might not be suitable for all data sets. if use_tempering sigma_n = param_set.sigma_n * (1 + 10 * exp(-iter/5)); sigma_a = param_set.sigma_a * (1 + 2.5 * exp(-iter/5)); else sigma_n = param_set.sigma_n; sigma_a = param_set.sigma_a; end % ---- run the variational optimisation updates ---- % initLB = compute_variational_lower_bound(... param_set, X, alpha, param_set.sigma_a, param_set.sigma_n, model ); [ model, lower_bounds_log, num_iters] = vibp(... X, alpha, sigma_a, sigma_n, model, lower_bounds_log, param_set); lower_bounds_log(1,end+1) = compute_variational_lower_bound( ... param_set, X , alpha, param_set.sigma_a, param_set.sigma_n, model); lower_bounds_log(2,end) = 0; iter = iter + 1; % ---- apply various heuristic search moves to improve the variational lower bound ---- % % This applies various search moves to the parameters. if param_set.try_search_heuristics [ model lower_bounds_log ] = run_search_heuristics( model , X , lower_bounds_log , ... alpha , sigma_n , sigma_a , param_set ); end % This incrementally adds data, letting the model learn the % parameters on a subset of the data and slowly adding more % data as we progress. if param_set.add_data_in_blocks [ model X param_set orig_data ] = update_small_model( model , X , param_set , orig_data ); end % This reorders the features to be in order of more likely % to least likely. This improves the lower bound in the % infinite approach, but does not affect the finite approach. if param_set.sort_feature_order [tmp feature_order] = sort(sum(model.nu), 'descend'); model = update_feature_order( model , feature_order , param_set ); if param_set.add_data_in_blocks orig_data.model = update_feature_order( orig_data.model , feature_order , param_set ); end end % --- check stopping criteria ---- % % note: if tempering and we appear to have converged, turn % it off for a final untemperred iteration. if ( ( (lower_bounds_log(1,end) - initLB) < param_set.stopping_thresh * abs(lower_bounds_log(1,end)) ) && ... ( size( X , 1 ) == N ) && (abs(sigma_n - param_set.sigma_n) < 0.01) &&... (abs(sigma_a - param_set.sigma_a) < 0.01)) if use_tempering use_tempering = false; else break; end end % ---- print visual feedback ---- % fprintf('Large Iteration %3d (N = %d of %d, %3d inner itr - time: %.2f) lower bound: %10.2f (%10.3f improvement) ',... iter, size( X , 1 ) , N, num_iters, cputime-initial_time, lower_bounds_log(1,end),... lower_bounds_log(1,end) - initLB); if use_tempering fprintf('tempered sigma_a: %0.2f sigma_n: %0.2f\n', sigma_a, sigma_n); else fprintf('\n'); end if (cputime - initial_time) > 10000 fprintf('Finished %d iterations\n', iter); break end end % loop over single restart fprintf('\n'); % ---- store the results in a cell array for later analysis ---- % % If you do not care about intermediate values, this storage % increases the amount of memory needed and can slow down the % algorithm. You might instead want to only pass back the final % values. model_set{ restart_index } = model; lower_bounds_log_set{ restart_index } = lower_bounds_log; final_lower_bound_set( restart_index ) = lower_bounds_log(1, end); end % loop over restarts % ---- find the best run ---- % [ max_lb max_iter ] = max( final_lower_bound_set ); model = model_set{ max_iter }; lower_bounds_log = lower_bounds_log_set{ max_iter }; fprintf('\n----------------------------------------------\n'); fprintf('Best restart on training data: (%d, %.2f)\n\n', max_iter, max_lb); % ---- store which run was best for the output ---- % out.model_set = model_set; out.lower_bounds_log_set = lower_bounds_log_set; out.final_lower_bound_set = final_lower_bound_set; out.best_model = model; out.best_lower_bounds_log = lower_bounds_log; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Display the predicted pi and Z, the features, and the predicted % denoised data. if param_set.show_final_plots % Get predicted Z Z_predicted = model.nu; if param_set.use_finite_model pi_predicted = model.tau(1,:) ./ sum( model.tau,1); else pi_predicted = v2pi( model.tau(1,:) ./ sum( model.tau,1) ); end A_predicted = model.phi_mean; K_pred = size(Z_predicted, 2); % compute color scale image_scale = [ min( [ min(A_predicted(:)) min(X(:)) 0 ] ) ... max( [ max(A_predicted(:)) max(X(:)) 1 ] ) ]; % Show the predicted features and their weights. Sort in LOF % for easier visual comparison. figure(1) clf; [tmp sorted_indices] = sortrows((1-Z_predicted)'); imagesc([pi_predicted(sorted_indices); Z_predicted(:,sorted_indices)]); colormap gray if K_pred > 0 axis image; end title('Predicted \pi and Z'); % Show the image features figure(2) clf; colormap gray; for k = 1:size(A_predicted,2) subplot(ceil(sqrt(size(A_predicted,2))),ceil(sqrt(size(A_predicted,2))),k); imagesc(reshape(A_predicted(:,sorted_indices(k)),4,4), image_scale ); end title('Predicted image features'); % Show the predicted underlying data uncorrupted by noise. figure(3) clf; colormap gray for n = 1:min([9 size(X,1)]) subplot(3,3,n); if (K_pred > 0) imagesc(reshape(Z_predicted(n,:)*A_predicted',4,4), image_scale ); end end title('Predicted denoised data'); % Show the true data figure(4) clf; colormap gray for n = 1:min([9 size(X,1)]) subplot(3,3,n); imagesc(reshape(X(n,:),4,4), image_scale ); end title('True observed data'); % Plot the LB figure(5); clf; hold on; iter_count = size(lower_bounds_log,2); legends = {'Lower bound'}; plot( lower_bounds_log(1,:), 'k-'); colors = {'c.', 'm.', 'g.', 'b.', 'r.'}; labels = {'\tau optimizations', '\phi optimizations', '\nu optimizations', ... '\eta-\mu optimisations', 'iteration end', }; for i = 1:5 indices = find(lower_bounds_log(2,:) == i); if size(indices,2) > 0 plot(indices, lower_bounds_log(1,indices), colors{i}); legends{end+1} = labels{i}; end end title('Lower bound on marginal likelihood'); AX = legend(legends, 'Location', 'SouthEast'); LEG = findobj(AX,'type','text'); set(LEG,'FontSize',18); legend boxoff; fprintf(['Note that the lower bound in the plot might not' ... ' monotonically increase. This is due to tempering' ... ' and incremental introduction of the data.\n']); drawnow; end return tester.m0000644061573100372000000001002111177553432011117 0ustar fd258divfclear addpath('vibp_base/') addpath('util/') addpath('heuristics/') % load data load( 'data.mat' ); % -------------------------- % % Set Parameters % % -------------------------- % % set basic parameters of the data param_set.alpha = alpha; % IBP concentration parameter param_set.sigma_n = sigma_n; % noise variance param_set.sigma_a = sigma_a; % feature variance % set basic parameters of the algorithm param_set.K = 6; % truncation level param_set.restart_count = 5; % number of random restarts param_set.vibp_iter_count = 2; % number of inner optimisation iterations to perform between heuristic search moves param_set.use_tempering = true; % whether variances should be tempered (recommended) param_set.compute_intermediate_lb = false; % should lb be computed after each parameter update (for logging purposes) param_set.stopping_thresh = 0.1; % multiplicative difference in lower bounds to stop optimising % set output parameters param_set.show_final_plots = false; % should final Z/reconstructions be shown at end? % set held out data: test_mask( i,j ) = 1 indicates data is to be used for training. % this just demonstrates how to set up a mask to treat part of the data as unobserved. param_set.test_mask = ones( size( X ) ); test_n_start1_ind = N - floor( N / 2 ); test_n_end1_ind = N - ceil( N / 3 ); test_n_start2_ind = N - floor( N / 3 ); test_n_end2_ind = N - ceil( N / 6 ); test_n_start3_ind = N - floor( N / 6 ); test_n_end3_ind = N; param_set.test_mask( test_n_start1_ind:test_n_end1_ind , 1:3:end ) = 0; param_set.test_mask( test_n_start2_ind:test_n_end2_ind , 2:3:end ) = 0; param_set.test_mask( test_n_start3_ind:test_n_end3_ind , 3:3:end ) = 0; % set which variational methods to run param_set.do_finite_lg_variational = true; param_set.do_infinite_lg_variational = true; % ---- advanced heuristics (may be of limited use) ---- % % search moves that combine apirs of features (eg sum and difference) param_set.try_search_heuristics = true; % try search moves during optimisation param_set.search_count = 5; % how many search moves per iteration param_set.search_heuristic = 'random'; % 'random' pair,'full' - all pairs, 'correlation' - most correlated pair % adding data slowly (a form of tempering) param_set.add_data_in_blocks = true; param_set.data_block_size = 10; % how many data points to add per iteration % reorder the features by popularity between optimisation iterations - % this improves the lower bound in the infinite approach. param_set.sort_feature_order = true; % recommended for infinite approaches % varying order of optimisation updates of the parameters. param_set.vary_update_order = false; % should order of parameter updates be varied in each optimisation iteration % --------------------------% % Run Inference % % --------------------------% % finite LG variational if param_set.do_finite_lg_variational fprintf('#################################################\n'); fprintf('Running Finite LG Variational\n'); fprintf('#################################################\n'); path(path, './vibp_finite/'); param_set.use_finite_model = true; param_set.model_type = 'LG'; t = cputime; model_finite_LG_variational = run_vibp( X , param_set ); model_finite_LG_variational.time_elapsed = cputime - t; rmpath('./vibp_finite') end % infinite LG variational if param_set.do_infinite_lg_variational fprintf('#################################################\n'); fprintf('Running Infinite LG Variational\n'); fprintf('#################################################\n'); path(path, './vibp_infinite/'); param_set.use_finite_model = false; param_set.model_type = 'LG'; t = cputime; model_infinite_LG_variational = run_vibp( X , param_set ); model_infinite_LG_variational.time_elapsed = cputime - t; rmpath('./vibp_infinite') end heuristics/initialise_small_model.m0000644061573100372000000000126011177553056016504 0ustar fd258divffunction [ model X param_set orig_data ] = initialise_small_model( model , X , param_set ) % Initialises the observed data to be only a subset of the data and % initialises the model with the corresponding parameters. % store original things param_set.orig_test_mask = param_set.test_mask; orig_data.X = X; orig_data.model = model; % reduce observations in current model data_ind_set = zeros( size( X , 1 ) , 1 ); data_ind_set(1:param_set.data_block_size) = 1; X = X(1:param_set.data_block_size,:); model.nu = model.nu(1:param_set.data_block_size,:); param_set.test_mask = param_set.test_mask(1:param_set.data_block_size,:); % store data set ind orig_data.data_ind_set = data_ind_set; heuristics/run_search_heuristics.m0000644061573100372000000001652011177551744016404 0ustar fd258divffunction [model lower_bounds_log] = ... run_search_heuristics( model , X , lower_bounds_log , ... alpha , sigma_n , sigma_a , param_set ) % function [model lower_bounds_log] = ... % run_search_heuristics( model , X , lower_bounds_log , ... % alpha , sigma_n , sigma_a , param_set ); % % This function tries out one of several different search move % proposals, accepting them if they increase the lower bound, % rejecting them otherwise. % get K K = param_set.K; % loop for number of searches to try for search_ind = 1:param_set.search_count switch param_set.search_heuristic % --- TRY ALL PAIRS --- % case 'full' maxLB = lower_bounds_log(1,end); found_better = false; % loop over all pairs for h=1:K for l=[1:(h-1) (h+1):K] % initialise proposal new_model = model_search_move(model, h, l, ceil( rand * 5 ) ); % compute update and store results [new_model nlbl] = vibp(X, alpha, sigma_a, ... sigma_n, new_model, ... lower_bounds_log(:,end), param_set); % if the proposal is better than past ones, store it if nlbl(1,end) > maxLB + 0.1; maxLB = nlbl(1,end); best_model = new_model; best_lbl = nlbl(:,2:end); found_better = true; end end % l loop end % h loop % update if we had an improvement if found_better fprintf(' accepted full proposal\n'); model = best_model; lower_bounds_log = [lower_bounds_log best_lbl]; end % --- RANDOMLY PROPOSE --- % case 'random' % compute proposal h and l h = ceil(rand() * K); l = ceil(rand() * K); while l == h l = ceil(rand() * K); end maxLB = lower_bounds_log(1,end); found_better = false; % initialise proposal new_model = model_search_move(model, h, l, ceil( rand * 5 ) ); % compute update and store results [new_model nlbl] = vibp(X, alpha, sigma_a, sigma_n, ... new_model, lower_bounds_log(:,end), param_set); % if the proposal is better than past ones, store it if nlbl(1,end) > maxLB maxLB = nlbl(1,end); best_model = new_model; best_lbl = nlbl(:,2:end); found_better = true; end % update if we had an improvement if found_better fprintf(' accepted random proposal\n'); model = best_model; lower_bounds_log = [lower_bounds_log best_lbl]; end % --- PROPOSE BASED ON CORRELATIONS --- % case 'correlation' % compute proposal assymetric correlation cc = zeros(K); for feat_i = 1:K for feat_j = 1:K if feat_i == feat_j cc( feat_i , feat_j ) = 0; else cc( feat_i , feat_j ) = model.nu( : , feat_i )' ... * model.nu( : , feat_j ) ... / norm( model.nu( : , feat_i ) ); end end end hl = sampleMultinomial( cc(:) ); h = mod( hl , K ); if h == 0 h = K; end l = ceil(hl / K); % Now have the h,l sampled according to their correlation if h ~= l maxLB = lower_bounds_log(1,end); found_better = false; % initialise proposal new_model = model_search_move(model, h, l, ceil( rand * 5 ) ); % compute update and store results [new_model nlbl] = vibp(X, alpha, sigma_a, sigma_n, ... new_model, lower_bounds_log(:,end), param_set); % if the proposal is better than past ones, store it if nlbl(1,end) > maxLB maxLB = nlbl(1,end); best_model = new_model; best_lbl = nlbl(:,2:end); found_better = true; end % update if we had an improvement if found_better fprintf(' accepted correlation proposal\n'); model = best_model; lower_bounds_log = [lower_bounds_log best_lbl]; end end otherwise fprintf('No search moves\n'); end % end switch over heuristics end % end search loop %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % A helper function for the search moves function new_model = model_search_move(original_model, h, l, search_move) new_model = original_model; if search_move > 5 search_move = mod(search_move, 5); tmp = h; h = l; l = tmp; end switch search_move case 1 % Let h = h - l, leave l alone new_model.phi_mean(:,h) = original_model.phi_mean(:,h) - original_model.phi_mean(:,l); new_model.nu(:,h) = max(original_model.nu(:,h) - original_model.nu(:,l), 0.01); case 2 % Let h = h + l, leave l alone new_model.phi_mean(:,h) = original_model.phi_mean(:,h) + original_model.phi_mean(:,l); new_model.nu(:,h) = min(original_model.nu(:,h) + original_model.nu(:,l), 0.99); phi_cov_avg = (original_model.phi_cov(:,h) + original_model.phi_cov(:,l))/2; new_model.phi_cov(:,h) = phi_cov_avg; new_model.phi_cov(:,l) = phi_cov_avg; case 3 % Let h = h + l, delete l new_model.phi_mean(:,h) = original_model.phi_mean(:,h) + original_model.phi_mean(:,l); new_model.phi_mean(:,l) = zeros(size(original_model.phi_mean(:,l))); new_model.nu(:,h) = min(original_model.nu(:,h) + original_model.nu(:,l), 0.99); new_model.nu(:,l) = 0.01; phi_cov_avg = (original_model.phi_cov(:,h) + original_model.phi_cov(:,l))/2; new_model.phi_cov(:,h) = phi_cov_avg; new_model.phi_cov(:,l) = phi_cov_avg; case 4 % randomly reset h and l new_model.phi_mean(:,h) = randn(size(new_model.phi_mean(:,h)))*0.01; new_model.phi_mean(:,l) = randn(size(new_model.phi_mean(:,h)))*0.01; new_model.nu(:,h) = rand(size(new_model.nu(:,h))); new_model.nu(:,l) = rand(size(new_model.nu(:,h))); phi_cov_avg = (original_model.phi_cov(:,h) + original_model.phi_cov(:,l))/2; new_model.phi_cov(:,h) = phi_cov_avg; new_model.phi_cov(:,l) = phi_cov_avg; case 5 % h = h - l, l = h + l new_model.phi_mean(:,h) = original_model.phi_mean(:,h) - original_model.phi_mean(:,l); new_model.phi_mean(:,l) = original_model.phi_mean(:,h) + original_model.phi_mean(:,l); new_model.nu(:,h) = (original_model.nu(:,h) + original_model.nu(:,l))/2; new_model.nu(:,l) = (original_model.nu(:,h) + original_model.nu(:,l))/2; phi_cov_avg = (original_model.phi_cov(:,h) + original_model.phi_cov(:,l))/2; new_model.phi_cov(:,h) = phi_cov_avg; new_model.phi_cov(:,l) = phi_cov_avg; end return heuristics/update_feature_order.m0000644061573100372000000000037411177553075016200 0ustar fd258divffunction model = update_feature_order( model , feature_order , param_set ) model.tau = model.tau(:,feature_order); model.phi_mean = model.phi_mean(:,feature_order); model.phi_cov = model.phi_cov(:,feature_order); model.nu = model.nu(:,feature_order); heuristics/update_small_model.m0000644061573100372000000000223411177553107015633 0ustar fd258divffunction [ model X param_set orig_data ] = update_small_model( model , X , param_set , orig_data ) % store back into orig_data orig_data.model.tau = model.tau; orig_data.model.phi_mean = model.phi_mean; orig_data.model.phi_cov = model.phi_cov; orig_data.model.nu( find( orig_data.data_ind_set ) , : ) = model.nu; if strcmp( param_set.model_type , 'iICA' ) orig_data.model.eta( find( orig_data.data_ind_set ) , : ) = model.eta; orig_data.model.mu( find( orig_data.data_ind_set ) , : ) = model.mu; end % take out part of the model data_count = size( X , 1 ); N = size( orig_data.X , 1 ); if (data_count < N) remove_count = floor( param_set.data_block_size / 2 ); remove_ind = randsample( find( orig_data.data_ind_set == 1 ) , remove_count ); orig_data.data_ind_set( remove_ind ) = 0; add_ind = randsample( find( orig_data.data_ind_set == 0 ), param_set.data_block_size + remove_count ); orig_data.data_ind_set( add_ind ) = 1; X = orig_data.X( find( orig_data.data_ind_set ) , : ); model.nu = orig_data.model.nu( find( orig_data.data_ind_set ) , : ); param_set.test_mask = param_set.orig_test_mask( find( orig_data.data_ind_set ) , : ); end util/minimize.m0000644061573100372000000002142611177551745012427 0ustar fd258divffunction [X, fX, i] = minimize(X, f, length, varargin) % Minimize a differentiable multivariate function. % % Usage: [X, fX, i] = minimize(X, f, length, P1, P2, P3, ... ) % % where the starting point is given by "X" (D by 1), and the function named in % the string "f", must return a function value and a vector of partial % derivatives of f wrt X, the "length" gives the length of the run: if it is % positive, it gives the maximum number of line searches, if negative its % absolute gives the maximum allowed number of function evaluations. You can % (optionally) give "length" a second component, which will indicate the % reduction in function value to be expected in the first line-search (defaults % to 1.0). The parameters P1, P2, P3, ... are passed on to the function f. % % The function returns when either its length is up, or if no further progress % can be made (ie, we are at a (local) minimum, or so close that due to % numerical problems, we cannot get any closer). NOTE: If the function % terminates within a few iterations, it could be an indication that the % function values and derivatives are not consistent (ie, there may be a bug in % the implementation of your "f" function). The function returns the found % solution "X", a vector of function values "fX" indicating the progress made % and "i" the number of iterations (line searches or function evaluations, % depending on the sign of "length") used. % % The Polack-Ribiere flavour of conjugate gradients is used to compute search % directions, and a line search using quadratic and cubic polynomial % approximations and the Wolfe-Powell stopping criteria is used together with % the slope ratio method for guessing initial step sizes. Additionally a bunch % of checks are made to make sure that exploration is taking place and that % extrapolation will not be unboundedly large. % % See also: checkgrad % % Copyright (C) 2001 - 2006 by Carl Edward Rasmussen (2006-09-08). INT = 0.1; % don't reevaluate within 0.1 of the limit of the current bracket EXT = 3.0; % extrapolate maximum 3 times the current step-size MAX = 20; % max 20 function evaluations per line search RATIO = 10; % maximum allowed slope ratio SIG = 0.1; RHO = SIG/2; % SIG and RHO are the constants controlling the Wolfe- % Powell conditions. SIG is the maximum allowed absolute ratio between % previous and new slopes (derivatives in the search direction), thus setting % SIG to low (positive) values forces higher precision in the line-searches. % RHO is the minimum allowed fraction of the expected (from the slope at the % initial point in the linesearch). Constants must satisfy 0 < RHO < SIG < 1. % Tuning of SIG (depending on the nature of the function to be optimized) may % speed up the minimization; it is probably not worth playing much with RHO. % The code falls naturally into 3 parts, after the initial line search is % started in the direction of steepest descent. 1) we first enter a while loop % which uses point 1 (p1) and (p2) to compute an extrapolation (p3), until we % have extrapolated far enough (Wolfe-Powell conditions). 2) if necessary, we % enter the second loop which takes p2, p3 and p4 chooses the subinterval % containing a (local) minimum, and interpolates it, unil an acceptable point % is found (Wolfe-Powell conditions). Note, that points are always maintained % in order p0 <= p1 <= p2 < p3 < p4. 3) compute a new search direction using % conjugate gradients (Polack-Ribiere flavour), or revert to steepest if there % was a problem in the previous line-search. Return the best value so far, if % two consecutive line-searches fail, or whenever we run out of function % evaluations or line-searches. During extrapolation, the "f" function may fail % either with an error or returning Nan or Inf, and minimize should handle this % gracefully. if max(size(length)) == 2, red=length(2); length=length(1); else red=1; end if length>0, S='Linesearch'; else S='Function evaluation'; end i = 0; % zero the run length counter ls_failed = 0; % no previous line search has failed [f0 df0] = feval(f, X, varargin{:}); % get function value and gradient fX = f0; i = i + (length<0); % count epochs?! s = -df0; d0 = -s'*s; % initial search direction (steepest) and slope x3 = red/(1-d0); % initial step is red/(|s|+1) while i < abs(length) % while not finished i = i + (length>0); % count iterations?! X0 = X; F0 = f0; dF0 = df0; % make a copy of current values if length>0, M = MAX; else M = min(MAX, -length-i); end while 1 % keep extrapolating as long as necessary x2 = 0; f2 = f0; d2 = d0; f3 = f0; df3 = df0; success = 0; while ~success && M > 0 try M = M - 1; i = i + (length<0); % count epochs?! [f3 df3] = feval(f, X+x3*s, varargin{:}); if isnan(f3) || isinf(f3) || any(isnan(df3)+isinf(df3)), error(''), end success = 1; catch % catch any error which occured in f x3 = (x2+x3)/2; % bisect and try again end end if f3 < F0, X0 = X+x3*s; F0 = f3; dF0 = df3; end % keep best values d3 = df3'*s; % new slope if d3 > SIG*d0 || f3 > f0+x3*RHO*d0 || M == 0 % are we done extrapolating? break end x1 = x2; f1 = f2; d1 = d2; % move point 2 to point 1 x2 = x3; f2 = f3; d2 = d3; % move point 3 to point 2 A = 6*(f1-f2)+3*(d2+d1)*(x2-x1); % make cubic extrapolation B = 3*(f2-f1)-(2*d1+d2)*(x2-x1); x3 = x1-d1*(x2-x1)^2/(B+sqrt(B*B-A*d1*(x2-x1))); % num. error possible, ok! if ~isreal(x3) || isnan(x3) || isinf(x3) || x3 < 0 % num prob | wrong sign? x3 = x2*EXT; % extrapolate maximum amount elseif x3 > x2*EXT % new point beyond extrapolation limit? x3 = x2*EXT; % extrapolate maximum amount elseif x3 < x2+INT*(x2-x1) % new point too close to previous point? x3 = x2+INT*(x2-x1); end end % end extrapolation while (abs(d3) > -SIG*d0 || f3 > f0+x3*RHO*d0) && M > 0 % keep interpolating if d3 > 0 || f3 > f0+x3*RHO*d0 % choose subinterval x4 = x3; f4 = f3; d4 = d3; % move point 3 to point 4 else x2 = x3; f2 = f3; d2 = d3; % move point 3 to point 2 end if f4 > f0 x3 = x2-(0.5*d2*(x4-x2)^2)/(f4-f2-d2*(x4-x2)); % quadratic interpolation else A = 6*(f2-f4)/(x4-x2)+3*(d4+d2); % cubic interpolation B = 3*(f4-f2)-(2*d2+d4)*(x4-x2); x3 = x2+(sqrt(B*B-A*d2*(x4-x2)^2)-B)/A; % num. error possible, ok! end if isnan(x3) || isinf(x3) x3 = (x2+x4)/2; % if we had a numerical problem then bisect end x3 = max(min(x3, x4-INT*(x4-x2)),x2+INT*(x4-x2)); % don't accept too close [f3 df3] = feval(f, X+x3*s, varargin{:}); if f3 < F0, X0 = X+x3*s; F0 = f3; dF0 = df3; end % keep best values M = M - 1; i = i + (length<0); % count epochs?! d3 = df3'*s; % new slope end % end interpolation if abs(d3) < -SIG*d0 && f3 < f0+x3*RHO*d0 % if line search succeeded X = X+x3*s; f0 = f3; fX = [fX' f0]'; % update variables % fprintf('%s %6i; Value %4.6e\r', S, i, f0); s = (df3'*df3-df0'*df3)/(df0'*df0)*s - df3; % Polack-Ribiere CG direction df0 = df3; % swap derivatives d3 = d0; d0 = df0'*s; if d0 > 0 % new slope must be negative s = -df0; d0 = -s'*s; % otherwise use steepest direction end x3 = x3 * min(RATIO, d3/(d0-realmin)); % slope ratio but max RATIO ls_failed = 0; % this line search did not fail else X = X0; f0 = F0; df0 = dF0; % restore best point so far if ls_failed || i > abs(length) % line search failed twice in a row break; % or we ran out of time, so we give up end s = -df0; d0 = -s'*s; % try steepest x3 = 1/(1-d0); ls_failed = 1; % this line search failed end end util/v2pi.m0000644061573100372000000000022311177551745011456 0ustar fd258divffunction piSet = v2pi( vSet ) % function piSet = v2pi( vSet ) % converts stick breaks to feature probabilities piSet = cumprod( vSet ); return vibp_base/compute_variational_lower_bound.m0000644061573100372000000000755211177553206020225 0ustar fd258divffunction [lower_bound] = compute_variational_lower_bound(... params, X, alpha, sigma_a, sigma_n, model) % function [lower_bound] = compute_variational_lower_bound(... % params, X, alpha, sigma_a, sigma_n, model ) % % Computes the variational lower bound on the log marginal likelihood % of the data based on the variational parameters. % Get parameters and constants. nu = model.nu; tau = model.tau; phi_mean = model.phi_mean; phi_cov = model.phi_cov; [N K] = size(nu); D = size(phi_mean, 1); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % The feature probabilities digamma_sum = sum(psi(tau(1,:)) - psi(sum(tau,1))); if params.use_finite_model lower_bound = K*log(alpha/K) + (alpha/K-1)*digamma_sum; else lower_bound = K* log(alpha) + (alpha-1)*digamma_sum; end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % The feature stats distribution feature_stat_bound = 0; if params.use_finite_model feature_stat_bound = sum( nu * psi( tau( 1 , : ) )' ) ... + sum( ( 1 - nu )*psi(tau(2,:) )' )... - sum( psi( tau( 1 , : ) + tau( 2 , : ) )' )*N; else for k = 1:K % This computes the expecation of log(1-prod v_i) by % introducing the variational multinomial distribution. % See the paper for details. f = compute_expected_pzk0_qjensen( tau , k ); feature_stat_bound = feature_stat_bound ... + sum(nu(:,k)) * sum( psi( tau(1,1:k) ) - psi( sum(tau(:,1:k)) ) ) ... + (N - sum(nu(:,k))) * f; end end lower_bound = lower_bound + feature_stat_bound; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % The feature distribution feature_dist_bound = sum(phi_cov(:)) + sum(dot(phi_mean, phi_mean)); lower_bound = lower_bound - D*K/2*log(2*pi*sigma_a^2) - 1/(2*sigma_a^2)* feature_dist_bound; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % The likelihood X = X .* params.test_mask; % mask out x's that are test data likelihood_bound = sum( sum( X.^2 ) ); switch params.model_type % linear gaussian case case 'LG' likelihood_bound = likelihood_bound - 2 * sum( sum( nu .* ( X * phi_mean ) )); % first term sums up the number of dimensions present in each % data point for the phi_cov, since this is different for % each; second term computes dot(phi_mean,phi_mean) but again, % for each n, sums only the terms in the dot product with % dimensions present for that n. tmp = params.test_mask * ( phi_cov + phi_mean.^2 ); likelihood_bound = likelihood_bound + sum(sum( nu .* tmp )); % we do sum_n sum_d sum_k sum_k' over all variables and then % subtract out the k=k' part that we do not want; first line % does sum_k nu_nk phi_kd; next we do mask_nd nuphi_nd % nuphi_nd tmp = nu * phi_mean'; tmp2 = nu.^2 * (phi_mean').^2; likelihood_bound = likelihood_bound ... + sum(sum( params.test_mask .* tmp .* tmp )) ... - sum(sum( params.test_mask .* tmp2 )); end lower_bound = lower_bound - sum( params.test_mask(:) )/2*log(2*pi*sigma_n^2) - 1/(2*sigma_n^2)* likelihood_bound; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % The entropy % Add in a factor for pi/v as appropriate. entropy_bound = sum( gammaln(tau(1,:)) + gammaln(tau(2,:)) ... - gammaln(sum(tau,1)) - (tau(1,:)-1) .* psi(tau(1,:)) - ... (tau(2,:)-1) .* psi(tau(2,:)) + (tau(1,:) + tau(2,:) - 2) .* psi(sum(tau,1)) ); % Add in a factor for the nonzero nu(n,k) tmpnu = nu + .5 * ( nu == 0 ) - .5 * ( nu == 1 ); tmp = -1 * tmpnu .* log( tmpnu ) - ( 1 - tmpnu ).* log( 1 - tmpnu ); tmp = tmp .* ( nu > 0 ) .* ( nu < 1 ); entropy_bound = entropy_bound + sum( tmp(:) ); entropy_bound = entropy_bound + K*D/2*log(2*pi*exp(1)); entropy_bound = entropy_bound + 1/2*sum(log( phi_cov(:) )); lower_bound = lower_bound + entropy_bound; return vibp_base/vibp.m0000644061573100372000000001242711177553331012515 0ustar fd258divffunction [model, lower_bounds_log, num_iters] = ... vibp(X, alpha, sigma_a, sigma_n, model, lower_bounds_log, params) % function [model, lower_bounds_log] = ... % vibp(X, alpha, sigma_a, sigma_n, model, lower_bounds_log, params) % % Performs the variational updates for the finite model and keeps % track of the lower bound. % Get parameters and constants. nu = model.nu; tau = model.tau; phi_mean = model.phi_mean; phi_cov = model.phi_cov; [N K] = size(nu); D = size(phi_mean, 1); lower_bound_count = 0; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Perform the variational updates. iter = 1; while 1 % Update all the parameters. % Note that the order of updates might affect speed of % convergence, so we can play with that here. if params.vary_update_order param_update_perm = randperm(4); else param_update_perm = 1:4; end for param_index = param_update_perm switch param_index case 1 %%%%%%%%%%%%%%%%%%% % Update all tau [ tau lower_bounds_log lower_bound_count ] = ... update_tau( params, X, alpha, sigma_a, sigma_n, model, ... lower_bounds_log, lower_bound_count ); model.tau = tau; case 2 %%%%%%%%%%%%%%%%%%% % Update all phi for k = 1:K non_k_indices = [1:(k-1) (k+1):K]; % First compute the B and C matrices as outlined in the notes. switch params.model_type case 'LG' B = (1/sigma_a^2 + params.test_mask' * nu(:,k) /sigma_n^2); C = (X .* params.test_mask)' * nu(:,k); for n = 1:N % multiply in mask with the phi_mean is sufficient to zero out the % dot product with A in the expectation C = C - nu(n,k) * ( sum( nu(n*ones(D,1), non_k_indices) ... .* phi_mean(:, non_k_indices),2) .* params.test_mask(n,:)' ); end C = C/ sigma_n^2; end % Then based on B and C, update phi. phi_cov(:,k) = 1./B; phi_mean(:,k) = C ./ B; model.phi_mean = phi_mean; model.phi_cov = phi_cov; % Update our lower bound if params.compute_intermediate_lb lower_bounds_log(1,end+1) = ... compute_variational_lower_bound(params, X, alpha, params.sigma_a, params.sigma_n, model); lower_bounds_log(2,end) = 2; lower_bound_count = lower_bound_count + 1; end end case 3 %%%%%%%%%%%%%%%%%%% % Update all nu for k = 1:K % First compute var_theta as outlined in the notes. var_theta_k % is the term shared across nu(:,k) so that we don't recompute it. % Minimal value for LG models var_theta_k = compute_var_theta_k( params , tau , k ); non_k_indices = [1:(k-1) (k+1):K]; for n = randperm(N) switch params.model_type case 'LG' var_theta = var_theta_k ... - 1/(2*sigma_n^2) * ( params.test_mask(n,:) * phi_cov(:,k) ... + params.test_mask(n,:) * (phi_mean(:,k).^2))... + 1/(sigma_n^2) * ( params.test_mask(n,:) .* phi_mean(:,k)' ) * ... (X(n,:)' - sum(nu(n*ones(D,1), non_k_indices) .* phi_mean(:, non_k_indices),2)); end % Once we have var_theta, go from the canonical parameter to the % mean parameter. nu(n,k) = 1 / (1 + exp(-var_theta)); model.nu = nu; % Update our lower bound if params.compute_intermediate_lb lower_bounds_log(1,end+1) = ... compute_variational_lower_bound( params, X, alpha, parmas.sigma_a, params.sigma_n, model); lower_bounds_log(2,end) = 3; lower_bound_count = lower_bound_count + 1; end end end end end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% lower_bounds_log(1,end+1) = ... compute_variational_lower_bound( params, X, alpha, params.sigma_a, params.sigma_n, model); lower_bounds_log(2,end) = 5; lower_bound_count = lower_bound_count + 1; % Determine stopping criteria and stop if we have converged or % done enough iterations. if (lower_bounds_log(1,end) - lower_bounds_log(1,end-lower_bound_count) ... < params.stopping_thresh) || (iter >= params.vibp_iter_count) break; end iter = iter + 1; end num_iters = iter; vibp_finite/compute_var_theta_k.m0000644061573100372000000000034611167120111016122 0ustar fd258divffunction var_theta_k = compute_var_theta_k( params , tau , k ) % function var_theta_k = compute_var_theta_k( params , tau , k ) % an intermediate function in computing the nu update var_theta_k = psi(tau(1,k)) - psi(tau(2,k)); vibp_finite/update_tau.m0000644061573100372000000000155211167120111014232 0ustar fd258divffunction [ tau lower_bounds_log lower_bound_count ] = ... update_tau( params, X, alpha, sigma_a, sigma_n, model, ... lower_bounds_log, lower_bound_count ); % function [ tau lower_bounds_log lower_bound_count ] = ... % update_tau( params, X, alpha, sigma_a, sigma_n, model , ... % lower_bounds_log, lower_bound_count ); [ N K ]= size( model.nu ); tau = model.tau; % loop through and update each tau for k = 1:K sum_nu_k = sum( model.nu(:,k)); tau(1,k) = alpha/K + sum_nu_k; tau(2,k) = 1 + N - sum_nu_k; model.tau = tau; % Update our lower bound if params.compute_intermediate_lb lower_bounds_log(1,end+1) = ... compute_variational_lower_bound( params, X, alpha, sigma_a, sigma_n, model ); lower_bounds_log(2,end) = 1; lower_bound_count = lower_bound_count + 1; end end vibp_infinite/compute_expected_pzk0_qjensen.m0000644061573100372000000000125511177551745020500 0ustar fd258divffunction [lb q] = compute_expected_pzk0_qjensen( tau , k ) % function [lb q] = compute_expected_pzk0_qjensen( tau , k ); % computes E[ ln( 1 - prod( 1 - v ) ) ] where the prod is from 1..k % using q-distribution described by YWT % select our relevant set of tau's (up to k) tau = tau( : , 1:k ); digamma_tau = psi( tau ); digamma_sum = psi( sum( tau ) ); % compute the optimal q distribution digamma_tau1_cumsum = [ 0 cumsum( digamma_tau( 1 , : ) ) ] ; digamma_sum_cumsum = cumsum( digamma_sum ); tmp = digamma_tau( 2 , : ) + digamma_tau1_cumsum(1:k) - digamma_sum_cumsum; q = exp( tmp - max(tmp) ); q = q / sum(q); % compute the lb lb = sum( q .* ( tmp - log( q ) ) ); return vibp_infinite/compute_var_theta_k.m0000644061573100372000000000046211177551745016476 0ustar fd258divffunction var_theta_k = compute_var_theta_k( params , tau , k ) % function var_theta_k = compute_var_theta_k( params , tau , k ) % an intermediate function in computing the nu update f = compute_expected_pzk0_qjensen( tau, k ); var_theta_k = sum( psi( tau(1,1:k) ) - psi( sum(tau(:,1:k)) ) ) - f; return vibp_infinite/update_tau.m0000644061573100372000000000276711177551745014620 0ustar fd258divffunction [ tau lower_bounds_log lower_bound_count ] = ... update_tau( params, X, alpha, sigma_a, sigma_n, model , ... lower_bounds_log, lower_bound_count ) % function [ tau lower_bounds_log lower_bound_count ] = ... % update_tau( params, X, alpha, sigma_a, sigma_n, model , ... % lower_bounds_log, lower_bound_count ) nu = model.nu; [ N K ] = size( nu ); sum_n_nu = sum(nu,1); N_minus_sum_n_nu = N - sum_n_nu; % Iterate through and update each tau(:,k) for k = 1:K % First we compute q_k for k:K tau = model.tau; digamma_tau = psi( tau ); digamma_sum = psi( sum( tau ) ); digamma_tau1_cumsum = [ 0 cumsum( digamma_tau( 1 , 1:(K-1) ) ) ] ; digamma_sum_cumsum = cumsum( digamma_sum ); exponent = digamma_tau( 2 , : ) + digamma_tau1_cumsum - digamma_sum_cumsum; unnormalized = exp(exponent - max(exponent)); qs = zeros(K,K); for m = k:K qs(m, 1:m) = unnormalized(1:m) / sum(unnormalized(1:m)); end % Now that we have the q_k, update the tau(:,k) tau(1,k) = sum(sum_n_nu(k:K)) + N_minus_sum_n_nu(k+1:K) * ... sum(qs(k+1:end, k+1:end),2) + alpha; tau(2,k) = N_minus_sum_n_nu(k:K) * qs(k:K, k) + 1; % Finally commit the udpated tau and compute the lower bound if desired. model.tau(:,k) = tau(:,k); if params.compute_intermediate_lb lower_bounds_log(1,end+1) = ... compute_variational_lower_bound( params, X, alpha, sigma_a, sigma_n, model); lower_bounds_log(2,end) = 1; lower_bound_count = lower_bound_count + 1; end end return