Daniel@0: %DEMGMM1 Demonstrate EM for Gaussian mixtures. Daniel@0: % Daniel@0: % Description Daniel@0: % This script demonstrates the use of the EM algorithm to fit a mixture Daniel@0: % of Gaussians to a set of data using maximum likelihood. A colour Daniel@0: % coding scheme is used to illustrate the evaluation of the posterior Daniel@0: % probabilities in the E-step of the EM algorithm. Daniel@0: % Daniel@0: % See also Daniel@0: % DEMGMM2, DEMGMM3, DEMGMM4, GMM, GMMEM, GMMPOST Daniel@0: % Daniel@0: Daniel@0: % Copyright (c) Ian T Nabney (1996-2001) Daniel@0: Daniel@0: clc; Daniel@0: disp('This demonstration illustrates the use of the EM (expectation-') Daniel@0: disp('maximization) algorithm for fitting of a mixture of Gaussians to a') Daniel@0: disp('data set by maximum likelihood.') Daniel@0: disp(' ') Daniel@0: disp('The data set consists of 40 data points in a 2-dimensional') Daniel@0: disp('space, generated by sampling from a mixture of 2 Gaussian') Daniel@0: disp('distributions.') Daniel@0: disp(' ') Daniel@0: disp('Press any key to see a plot of the data.') Daniel@0: pause; Daniel@0: Daniel@0: % Generate the data Daniel@0: randn('state', 0); rand('state', 0); Daniel@0: gmix = gmm(2, 2, 'spherical'); Daniel@0: ndat1 = 20; ndat2 = 20; ndata = ndat1+ndat2; Daniel@0: gmix.centres = [0.3 0.3; 0.7 0.7]; Daniel@0: gmix.covars = [0.01 0.01]; Daniel@0: x = gmmsamp(gmix, ndata); Daniel@0: Daniel@0: h = figure; Daniel@0: hd = plot(x(:, 1), x(:, 2), '.g', 'markersize', 30); Daniel@0: hold on; axis([0 1 0 1]); axis square; set(gca, 'box', 'on'); Daniel@0: ht = text(0.5, 1.05, 'Data', 'horizontalalignment', 'center'); Daniel@0: disp(' '); Daniel@0: disp('Press any key to continue.') Daniel@0: pause; clc; Daniel@0: Daniel@0: disp('We next create and initialize a mixture model consisting of a mixture') Daniel@0: disp('of 2 Gaussians having ''spherical'' covariance matrices, using the') Daniel@0: disp('function GMM. The Gaussian components can be displayed on the same') Daniel@0: disp('plot as the data by drawing a contour of constant probability density') Daniel@0: disp('for each component having radius equal to the corresponding standard') Daniel@0: disp('deviation. Component 1 is coloured red and component 2 is coloured') Daniel@0: disp('blue.') Daniel@0: disp(' ') Daniel@0: disp('Note that a particulary poor choice of initial parameters has been') Daniel@0: disp('made in order to illustrate more effectively the operation of the') Daniel@0: disp('EM algorithm.') Daniel@0: disp(' ') Daniel@0: disp('Press any key to see the initial configuration of the mixture model.') Daniel@0: pause; Daniel@0: Daniel@0: % Set up mixture model Daniel@0: ncentres = 2; input_dim = 2; Daniel@0: mix = gmm(input_dim, ncentres, 'spherical'); Daniel@0: Daniel@0: % Initialise the mixture model Daniel@0: mix.centres = [0.2 0.8; 0.8, 0.2]; Daniel@0: mix.covars = [0.01 0.01]; Daniel@0: Daniel@0: % Plot the initial model Daniel@0: ncirc = 30; theta = linspace(0, 2*pi, ncirc); Daniel@0: xs = cos(theta); ys = sin(theta); Daniel@0: xvals = mix.centres(:, 1)*ones(1,ncirc) + sqrt(mix.covars')*xs; Daniel@0: yvals = mix.centres(:, 2)*ones(1,ncirc) + sqrt(mix.covars')*ys; Daniel@0: hc(1)=line(xvals(1,:), yvals(1,:), 'color', 'r'); Daniel@0: hc(2)=line(xvals(2,:), yvals(2,:), 'color', 'b'); Daniel@0: set(ht, 'string', 'Initial Configuration'); Daniel@0: figure(h); Daniel@0: disp(' ') Daniel@0: disp('Press any key to continue'); Daniel@0: pause; clc; Daniel@0: Daniel@0: disp('Now we adapt the parameters of the mixture model iteratively using the') Daniel@0: disp('EM algorithm. Each cycle of the EM algorithm consists of an E-step') Daniel@0: disp('followed by an M-step. We start with the E-step, which involves the') Daniel@0: disp('evaluation of the posterior probabilities (responsibilities) which the') Daniel@0: disp('two components have for each of the data points.') Daniel@0: disp(' ') Daniel@0: disp('Since we have labelled the two components using the colours red and') Daniel@0: disp('blue, a convenient way to indicate the value of a posterior') Daniel@0: disp('probability for a given data point is to colour the point using a') Daniel@0: disp('scale ranging from pure red (corresponding to a posterior probability') Daniel@0: disp('of 1.0 for the red component and 0.0 for the blue component) through') Daniel@0: disp('to pure blue.') Daniel@0: disp(' ') Daniel@0: disp('Press any key to see the result of applying the first E-step.') Daniel@0: pause; Daniel@0: Daniel@0: % Initial E-step. Daniel@0: set(ht, 'string', 'E-step'); Daniel@0: post = gmmpost(mix, x); Daniel@0: dcols = [post(:,1), zeros(ndata, 1), post(:,2)]; Daniel@0: delete(hd); Daniel@0: for i = 1 : ndata Daniel@0: hd(i) = plot(x(i, 1), x(i, 2), 'color', dcols(i,:), ... Daniel@0: 'marker', '.', 'markersize', 30); Daniel@0: end Daniel@0: figure(h); Daniel@0: Daniel@0: disp(' '); Daniel@0: disp('Press any key to continue') Daniel@0: pause; clc; Daniel@0: Daniel@0: disp('Next we perform the corresponding M-step. This involves replacing the') Daniel@0: disp('centres of the component Gaussians by the corresponding weighted means') Daniel@0: disp('of the data. Thus the centre of the red component is replaced by the') Daniel@0: disp('mean of the data set, in which each data point is weighted according to') Daniel@0: disp('the amount of red ink (corresponding to the responsibility of') Daniel@0: disp('component 1 for explaining that data point). The variances and mixing') Daniel@0: disp('proportions of the two components are similarly re-estimated.') Daniel@0: disp(' ') Daniel@0: disp('Press any key to see the result of applying the first M-step.') Daniel@0: pause; Daniel@0: Daniel@0: % M-step. Daniel@0: set(ht, 'string', 'M-step'); Daniel@0: options = foptions; Daniel@0: options(14) = 1; % A single iteration Daniel@0: options(1) = -1; % Switch off all messages, including warning Daniel@0: mix = gmmem(mix, x, options); Daniel@0: delete(hc); Daniel@0: xvals = mix.centres(:, 1)*ones(1,ncirc) + sqrt(mix.covars')*xs; Daniel@0: yvals = mix.centres(:, 2)*ones(1,ncirc) + sqrt(mix.covars')*ys; Daniel@0: hc(1)=line(xvals(1,:), yvals(1,:), 'color', 'r'); Daniel@0: hc(2)=line(xvals(2,:), yvals(2,:), 'color', 'b'); Daniel@0: figure(h); Daniel@0: disp(' ') Daniel@0: disp('Press any key to continue') Daniel@0: pause; clc; Daniel@0: Daniel@0: disp('We can continue making alternate E and M steps until the changes in') Daniel@0: disp('the log likelihood at each cycle become sufficiently small.') Daniel@0: disp(' ') Daniel@0: disp('Press any key to see an animation of a further 9 EM cycles.') Daniel@0: pause; Daniel@0: figure(h); Daniel@0: Daniel@0: % Loop over EM iterations. Daniel@0: numiters = 9; Daniel@0: for n = 1 : numiters Daniel@0: Daniel@0: set(ht, 'string', 'E-step'); Daniel@0: post = gmmpost(mix, x); Daniel@0: dcols = [post(:,1), zeros(ndata, 1), post(:,2)]; Daniel@0: delete(hd); Daniel@0: for i = 1 : ndata Daniel@0: hd(i) = plot(x(i, 1), x(i, 2), 'color', dcols(i,:), ... Daniel@0: 'marker', '.', 'markersize', 30); Daniel@0: end Daniel@0: pause(1) Daniel@0: Daniel@0: set(ht, 'string', 'M-step'); Daniel@0: [mix, options] = gmmem(mix, x, options); Daniel@0: fprintf(1, 'Cycle %4d Error %11.6f\n', n, options(8)); Daniel@0: delete(hc); Daniel@0: xvals = mix.centres(:, 1)*ones(1,ncirc) + sqrt(mix.covars')*xs; Daniel@0: yvals = mix.centres(:, 2)*ones(1,ncirc) + sqrt(mix.covars')*ys; Daniel@0: hc(1)=line(xvals(1,:), yvals(1,:), 'color', 'r'); Daniel@0: hc(2)=line(xvals(2,:), yvals(2,:), 'color', 'b'); Daniel@0: pause(1) Daniel@0: Daniel@0: end Daniel@0: Daniel@0: disp(' '); Daniel@0: disp('Press any key to end.') Daniel@0: pause; clc; close(h); clear all Daniel@0: