none
An Influence Model (Migrated from community.research.microsoft.com)

    Question

  • Ali Yaghoubi posted on 05-21-2011 12:43 PM

    Hi John,

    Sorry for my long time absence.

    I am looking for a general coding  framework scheme by Infer.Net about HMMs from:

    1- Asavathiratham, C., Roy, S., Lesieutre, B., and Verghese, G. The influence model. In IEEE Control Systems Magazine, Special Issue on Complex Systems, (12) 2001.

    2- Basu, S., Choudhury, T., Clarkson, B., and Pentland, A., Learning human interactions with the influence model. Technical report, MIT Media Laboratory vision and modeling technical report #539, 2001. URL .

    It would be enough even if you send me a pseudo-code.

    Best,

    Ali

    Friday, June 03, 2011 6:50 PM

Answers

  • John Guiver replied on 05-27-2011 10:09 AM

    Here is a simple example of how to call into the previous model class:

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

    using MicrosoftResearch.Infer.Models;

    using MicrosoftResearch.Infer.Maths;

    using MicrosoftResearch.Infer;

    using MicrosoftResearch.Infer.Distributions;

     

    namespace InfluenceModel

    {

        class Program

        {

            static void Main(string[] args)

            {

                int[][] outputs = new int[][]

                {

                  new int[] {1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1},

                  new int[] {0, 2, 1, 1, 2, 2, 2, 3, 3, 0, 0, 1, 2, 1, 1, 2, 1, 0}

                };

                int[] numStatesPerSite = new int[] { 2, 3 };

                int[] numOutputsPerSite = new int[] { 2, 4 };

     

     

                InfluenceModel model = new InfluenceModel();

                int numSites = outputs.Length;

                int numSteps = outputs[0].Length;

                model.CreateModel(numSteps, numSites);

     

                model.TrainModel(outputs, numStatesPerSite, numOutputsPerSite, 0.2, 0.1);

     

                for (int i = 0; i < numSites; i++)

                {

                    Console.WriteLine("\n****** Site {0} ******", i);

                    Console.WriteLine("\nPosterior for Influence[{0}]:", i);

                    Console.WriteLine(model.InfluencePosterior[i]);

     

                    for (int j = 0; j < numSites; j++)

                    {

                        Console.WriteLine("\nPosterior for A[{0}][{1}]:", i, j);

                        for (int k = 0; k < numStatesPerSite[j]; k++)

                            Console.WriteLine(model.APosterior[i, j][k]);

                    }

                    Console.WriteLine("\nPosterior for B[{0}]:", i);

                    for (int k = 0; k < numStatesPerSite[i]; k++)

                        Console.WriteLine(model.BPosterior[i][k]);

                }

            }

        }

    }

    Friday, June 03, 2011 6:50 PM

All replies

  • John Guiver replied on 05-23-2011 12:22 PM

    OK, I will have a go at putting together some example code, but before I did that I want to clarify some assumptions I will make. Please verify these before I start.

    1. I will put together a model with two chains.
    2. The state at time k+1 of one chain will depend on the state at time k of one or other of the two chains depending on influence probabilities.
    3. Each state can take a finite number of values (which might be different for the two chains)
    4. Each emission can take a finite number of values (which might be different for the two chains)
    5. You want to learn state transition probabilities, emission probabilities, and influence probabilities
    6. The chains are not very long - i.e. not many time steps.

    The reason for the last assumption is that in the current version of Infer.NET, chains must either be written with the discrete time axis using .NET arrays (for which the model compiler generates an unrolled model thus limiting the number of steps - perhaps to 100 or so) or it must be done with advanced use of shared variables which is quite complex, and which I would like to avoid for now. This will all go away in the next major release as one of the major pieces of work we have been doing is to put in place the modeling and scheduling support to do chain models easily and efficiently. In fact, depending on your needs, you may want to wait until then. If not, I can put together this example.

    Let me know

    John

    Friday, June 03, 2011 6:50 PM
  • Ali Yaghoubi replied on 05-23-2011 12:30 PM

    Hi John,

    I was wondering if you could put the example based on the assumptions you mentioned.

    Thanks,

    Ali

    Friday, June 03, 2011 6:50 PM
  • John Guiver replied on 05-27-2011 10:09 AM

    Here is a simple example of how to call into the previous model class:

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

    using MicrosoftResearch.Infer.Models;

    using MicrosoftResearch.Infer.Maths;

    using MicrosoftResearch.Infer;

    using MicrosoftResearch.Infer.Distributions;

     

    namespace InfluenceModel

    {

        class Program

        {

            static void Main(string[] args)

            {

                int[][] outputs = new int[][]

                {

                  new int[] {1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1},

                  new int[] {0, 2, 1, 1, 2, 2, 2, 3, 3, 0, 0, 1, 2, 1, 1, 2, 1, 0}

                };

                int[] numStatesPerSite = new int[] { 2, 3 };

                int[] numOutputsPerSite = new int[] { 2, 4 };

     

     

                InfluenceModel model = new InfluenceModel();

                int numSites = outputs.Length;

                int numSteps = outputs[0].Length;

                model.CreateModel(numSteps, numSites);

     

                model.TrainModel(outputs, numStatesPerSite, numOutputsPerSite, 0.2, 0.1);

     

                for (int i = 0; i < numSites; i++)

                {

                    Console.WriteLine("\n****** Site {0} ******", i);

                    Console.WriteLine("\nPosterior for Influence[{0}]:", i);

                    Console.WriteLine(model.InfluencePosterior[i]);

     

                    for (int j = 0; j < numSites; j++)

                    {

                        Console.WriteLine("\nPosterior for A[{0}][{1}]:", i, j);

                        for (int k = 0; k < numStatesPerSite[j]; k++)

                            Console.WriteLine(model.APosterior[i, j][k]);

                    }

                    Console.WriteLine("\nPosterior for B[{0}]:", i);

                    for (int k = 0; k < numStatesPerSite[i]; k++)

                        Console.WriteLine(model.BPosterior[i][k]);

                }

            }

        }

    }

    Friday, June 03, 2011 6:50 PM
  • Somehow the original model I posted seems to have got lost in the migration, so here it is

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using MicrosoftResearch.Infer.Models;
    using MicrosoftResearch.Infer.Maths;
    using MicrosoftResearch.Infer;
    using MicrosoftResearch.Infer.Distributions;
    namespace InfluenceModel
    {
    	public class InfluenceModel
    	{
    		// Fixed parameters:
    		public int NumTimeSteps;
    		public int NumSites;
    
    		// Variables
    		public Variable<int>[] NumStates; // Observed
    		public Variable<int>[] NumOutputs; // Observed
    		public VariableArray<Vector>[,] A;
    		public VariableArray<Vector>[] B;
    		public Variable<Vector>[] Influence;
    		public Variable<int>[][] InfluencingSite;
    		public Variable<int>[][] X;
    		public Variable<int>[][] Y; // Observed
    
    		// Priors
    		public VariableArray<Dirichlet>[,] APrior; // Observed
    		public VariableArray<Dirichlet>[] BPrior; // Observed
    		public Variable<Dirichlet>[] InfluencePrior; // Observed
    
    		// Posteriors
    		public Dirichlet[,][] APosterior;
    		public Dirichlet[][] BPosterior;
    		public Dirichlet[] InfluencePosterior;
    
    		// Message initialisations (to break symmetry - does not change the model)
    		public Variable<IDistribution<Vector[]>>[,] AInit; // Observed
    		public Variable<IDistribution<Vector[]>>[] BInit; // Observed
    
    		// Inference engine
    		public InferenceEngine engine = new InferenceEngine(new VariationalMessagePassing());
    
    		/// <summary>
    		/// Creates an influence model
    		/// </summary>
    		/// <param name="numTimeSteps">Number of time steps</param>
    		/// <param name="numSites">Number of sites</param>
    		public void CreateModel(int numTimeSteps, int numSites)
    		{
    			NumTimeSteps = numTimeSteps;
    			NumSites = numSites;
    			NumStates = new Variable<int>[numSites];
    			NumOutputs = new Variable<int>[numSites];
    
    			Range[] N = new Range[numSites];
    			Range[] M = new Range[numSites];
    
    			for (int i = 0; i < numSites; i++)
    			{
    				NumStates[i] = Variable.New<int>().Named("NumStates" + i);
    				NumOutputs[i] = Variable.New<int>().Named("NumOutputs" + i);
    				N[i] = new Range(NumStates[i]);
    				M[i] = new Range(NumOutputs[i]);
    			}
    
    			// State Transition probabilities:
    			// Each (current site, influencing site) pair has a set of probability
    			// vectors which determine the state transition from the influencing site
    			// to the current site.
    			APrior = new VariableArray<Dirichlet>[numSites, numSites];
    			AInit = new Variable<IDistribution<Vector[]>>[numSites, numSites];
    			A = new VariableArray<Vector>[numSites, numSites];
    			// i indexes current site, j indexes influencing site
    			for (int i = 0; i < numSites; i++)
    			{
    				for (int j = 0; j < numSites; j++)
    				{
    					APrior[i, j] = Variable.Array<Dirichlet>(N[j]).Named("APrior" + i + "_" + j);
    					A[i, j] = Variable.Array<Vector>(N[j]).Named("A" + i + "_" + j);
    					A[i, j][N[j]] = Variable<Vector>.Random<Dirichlet>(APrior[i, j][N[j]]);
    					A[i, j].SetValueRange(N[i]);
    					// Break symmetry
    					AInit[i, j] = Variable.New<IDistribution<Vector[]>>();
    					A[i, j].InitialiseTo(AInit[i, j]).Named("AInit" + i + "_" + j); ;
    				}
    			}
    
    			// Output (emission) probabilities for each site:
    			BPrior = new VariableArray<Dirichlet>[numSites];
    			BInit = new Variable<IDistribution<Vector[]>>[numSites];
    			B = new VariableArray<Vector>[numSites];
    			for (int i = 0; i < numSites; i++)
    			{
    				BPrior[i] = Variable.Array<Dirichlet>(N[i]).Named("BPrior" + i);
    				B[i] = Variable.Array<Vector>(N[i]).Named("B" + i);
    				B[i][N[i]] = Variable<Vector>.Random<Dirichlet>(BPrior[i][N[i]]);
    				B[i].SetValueRange(M[i]);
    				// Break symmetry
    				BInit[i] = Variable.New<IDistribution<Vector[]>>().Named("BInitr" + i); ;
    				B[i].InitialiseTo(BInit[i]);
    			}
    
    			// The influence matrix - determines the influencing site given the current site.
    			InfluencePrior = new Variable<Dirichlet>[numSites];
    			Influence = new Variable<Vector>[numSites];
    			for (int i = 0; i < numSites; i++)
    			{
    				InfluencePrior[i] = Variable.New<Dirichlet>().Named("InfluencePrior_" + i);
    				Influence[i] = Variable<Vector>.Random<Dirichlet>(InfluencePrior[i]).Named("Influence" + i);
    			}
    
    			// States, outputs, and influencing sites
    			X = new Variable<int>[numSites][];
    			Y = new Variable<int>[numSites][];
    			InfluencingSite = new Variable<int>[numSites][];
    			for (int i = 0; i < numSites; i++)
    			{
    				X[i] = new Variable<int>[numTimeSteps];
    				X[i][0] = Variable.DiscreteUniform(N[i]).Named("X" + i + "_0");
    				Y[i] = new Variable<int>[numTimeSteps];
    				using (Variable.Switch(X[i][0]))
    					Y[i][0] = Variable.Discrete(B[i][X[i][0]]).Named("Y" + i + "_0");
    				InfluencingSite[i] = new Variable<int>[numTimeSteps];
    				InfluencingSite[i][0] = Variable.DiscreteUniform(numSites).Named("InfluencingSite" + i + "_0");
    			}
    
    			for (int k = 1; k < numTimeSteps; k++)
    			{
    				for (int i = 0; i < numSites; i++)
    				{
    					// Infuencing site is randomly chosen from the influence matrix
    					InfluencingSite[i][k] = Variable.Discrete(Influence[i]).Named("InfluencingSite" + i + "_" + k);
    					X[i][k] = Variable.New<int>().Named("X" + i + "_" + k);
    					// For each influencing site case
    					for (int j = 0; j < numSites; j++)
    						using (Variable.Case(InfluencingSite[i][k], j))
    						// Switch on each possible influencing site state
    						using (Variable.Switch(X[j][k - 1]))
    							X[i][k].SetTo(Variable.Discrete(A[i, j][X[j][k - 1]]));
    					// Switch on the current state for the output
    					using (Variable.Switch(X[i][k]))
    						Y[i][k] = Variable.Discrete(B[i][X[i][k]]).Named("Y" + i + "_" + k);
    				}
    			}
    		}
    
    		/// <summary>
    		/// Train the model. Assumes uniform prior for initial states and for state and output transition probabilities.
    		/// </summary>
    		/// <param name="outputs">Outputs indexed by site and time step</param>
    		/// <param name="numStates">Number of values (starting at 0) the state can take for each site</param>
    		/// <param name="numOutputs">Number of values (starting at 0) the output can take for each site</param>
    		/// <param name="influenceFactor">A value between 0 and 1 - how much we want one site to influence another site</param>
    		/// <param name="initialCount">Initial pseudo count for transition probabilities - a value less than 1 encourages sparsity</param>
    		public void TrainModel(
    			int[][] outputs, int[] numStates, int[] numOutputs,
    			double influenceFactor, double initialCount)
    		{
    			if (outputs.Length != NumSites || outputs[0].Length != NumTimeSteps)
    				throw new ApplicationException("Mismatch between data and model");
    
    			// Observe the data, and set the priors and initialisations
    			for (int i = 0; i < NumSites; i++)
    			{
    				for (int t = 0; t < outputs.Length; t++)
    					Y[i][t].ObservedValue = outputs[i][t];
    
    				NumStates[i].ObservedValue = numStates[i];
    				NumOutputs[i].ObservedValue = numOutputs[i];
    				// Set influence prior so that influencing site is more likely to be current site
    				Vector influencePrior = Vector.Constant(NumSites, (influenceFactor / NumSites));
    				influencePrior[i] = 1.0 - ((NumSites-1)*influenceFactor) / NumSites;
    				InfluencePrior[i].ObservedValue = new Dirichlet(influencePrior);
    
    				for (int j = 0; j < NumSites; j++)
    				{
    					APrior[i, j].ObservedValue = UniformDirichletArray(numStates[j], numStates[i], initialCount);
    					AInit[i, j].ObservedValue = RandomDirichletArray(numStates[j], numStates[i], 1, 2);
    				}
    				BPrior[i].ObservedValue = UniformDirichletArray(numStates[i], numOutputs[i], initialCount);
    				BInit[i].ObservedValue = RandomDirichletArray(numStates[i], numOutputs[i], 1, 2);
    			}
    
    			// Run the inference
    			APosterior = new Dirichlet[NumSites, NumSites][];
    			BPosterior = new Dirichlet[NumSites][];
    			InfluencePosterior = new Dirichlet[NumSites];
    
    			// Make sure we only compile once by telling the compiler all the variables we want to infer
    			IList<IVariable> varsToInfer = new List<IVariable>();
    			foreach (IVariable v in A)
    				varsToInfer.Add(v);
    			foreach (IVariable v in B)
    				varsToInfer.Add(v);
    			foreach (IVariable v in Influence)
    				varsToInfer.Add(v);
    			engine.InferAll(varsToInfer);
    
    			for (int i = 0; i < NumSites; i++)
    			{
    				BPosterior[i] = engine.Infer<Dirichlet[]>(B[i]);
    				InfluencePosterior[i] = engine.Infer<Dirichlet>(Influence[i]);
    				for (int j = 0; j < NumSites; j++)
    				{
    					APosterior[i, j] = engine.Infer<Dirichlet[]>(A[i, j]);
    				}
    			}
    		}
    
    		/// <summary>
    		///Creates a random Dirichlet distribution (used for symmetry-breaking)
    		/// </summary>
    		Dirichlet RandomDirichlet(int valueCount, double minInitialCount, double maxInitialCount)
    		{
    			Vector pseudoCounts = Vector.Zero(valueCount);
    			double span = maxInitialCount - minInitialCount;
    			for (int i=0; i < valueCount; i++) pseudoCounts[i] = minInitialCount + span * Rand.Double();
    			return new Dirichlet(pseudoCounts);
    		}
    
    		/// <summary>
    		/// Creates a random Infer.NET Dirichlet distribution array (used for symmetry-breaking)
    		/// </summary>
    		IDistribution<Vector[]> RandomDirichletArray(int count, int valueCount, double minInitialCount, double maxInitialCount)
    		{
    			Dirichlet[] dirArray = new Dirichlet[count];
    			for (int i = 0; i < count; i++)
    				dirArray[i] = RandomDirichlet(valueCount, minInitialCount, maxInitialCount);
    			return Distribution<Vector>.Array(dirArray);
    		}
    
    		/// <summary>
    		/// Creates a .NET array of symmetric Dirichlet distribution with a given initial pseudocount
    		/// </summary>
    		Dirichlet[] UniformDirichletArray(int count, int valueCount, double initialCount)
    		{
    			return Enumerable.Repeat(Dirichlet.Uniform(valueCount, initialCount), count).ToArray();
    		}
    	}
    }
    
    
    Tuesday, June 07, 2011 9:57 AM