//public int[] Classification(Vector[] features, int[] labels)
        //{
        //}
        public double[] Regression(Vector[] features, double[] values)
        {
            var wMeans = Variable.Vector(Vector.Zero(features[0].Count).ToArray());
            var wPrecision = Variable.WishartFromShapeAndRate(100, PositiveDefiniteMatrix.IdentityScaledBy(features[0].Count, 0.01));
            var w = Variable.VectorGaussianFromMeanAndPrecision(wMeans, wPrecision).Named("w");
            var numItems = Variable.New<int>().Named("numItems");
            var i = new Range(numItems).Named("i");
            i.AddAttribute(new Sequential());

            var noisePrecision = Variable.New<double>().Named("noisePrecision");

            var x = Variable.Array<Vector>(i).Named("x");
            var y = Variable.Array<double>(i).Named("y");

            using (Variable.ForEach(i))
            {
                y[i] = Variable.GaussianFromMeanAndPrecision(Variable.InnerProduct(w, x[i]), noisePrecision);
            }

            numItems.ObservedValue = features.Length;
            x.ObservedValue = features;
            y.ObservedValue = values;

            var engine = new InferenceEngine();
            engine.Compiler.UseSerialSchedules = true;
            engine.ShowProgress = false;
            var wPosterior = engine.Infer<VectorGaussian>(w);
            y.ClearObservedValue();
            w.ObservedValue = wPosterior.GetMean();
            var inferredValues = engine.Infer<IList<Gaussian>>(y);
            return inferredValues.Select(v => v.GetMean()).ToArray();
        }
Example #2
0
        /// <summary>
        /// Constructs the model.
        /// </summary>
        public override void ConstructModel()
        {
            if (this.HasBeenConstructed)
            {
                return;
            }

            this.NumberOfFeatures = Variable.New <int>().Named("numberOfFeatures").Attrib(new DoNotInfer());
            this.NumberOfMessages = Variable.New <int>().Named("numberOfMessages").Attrib(new DoNotInfer());

            Range features = new Range(this.NumberOfFeatures).Named("features");
            Range emails   = new Range(this.NumberOfMessages).Named("emails");

            // Make sure that the range across messages is handled sequentially
            // - this is necessary to ensure the model converges during training
            emails.AddAttribute(new Sequential());

            // observed data
            this.FeatureValue =
                Variable.Array(Variable.Array <double>(features), emails).Named("featureValue").Attrib(new DoNotInfer());

            // The weights
            this.WeightPriors = Variable.New <DistributionStructArray <Gaussian, double> >().Named("WeightPriors").Attrib(new DoNotInfer());
            this.Weight       = Variable.Array <double>(features).Named("weight");
            this.Weight.SetTo(Variable <double[]> .Random(this.WeightPriors));

            this.ThresholdPrior = Variable.New <Gaussian>().Named("ThresholdPrior").Attrib(new DoNotInfer());
            this.Threshold      = Variable.New <double>().Named("threshold");
            this.Threshold.SetTo(Variable <double> .Random(this.ThresholdPrior));

            // Noise Variance
            this.NoiseVariance = Variable.New <double>().Named("NoiseVariance").Attrib(new DoNotInfer());

            // Label: is the message replied to?
            this.RepliedTo = Variable.Array <bool>(emails).Named("repliedTo");

            // Loop over emails
            using (Variable.ForEach(emails))
            {
                var featureScore = Variable.Array <double>(features).Named("featureScore");
                featureScore[features] = this.FeatureValue[emails][features] * this.Weight[features];
                var score = Variable.Sum(featureScore).Named("score");

                this.RepliedTo[emails] = Variable.GaussianFromMeanAndVariance(score, this.NoiseVariance).Named("noisyScore") > this.Threshold;
            }

            this.InitializeEngine();

            this.Engine.OptimiseForVariables = this.Mode == InputMode.Training
                                                   ? new IVariable[] { this.Weight, this.Threshold }
                                                   : this.Engine.OptimiseForVariables = new IVariable[] { this.RepliedTo };

            this.HasBeenConstructed = true;
        }
Example #3
0
            public Model()
            {
                // Classes.
                numClasses = Variable.New <int>().Named("numClasses");
                c          = new Range(numClasses).Named("c");

                // Items.
                numItems = Variable.New <int>().Named("numItems");
                i        = new Range(numItems).Named("i");
                i.AddAttribute(new Sequential());

                // The prior distribution for weight vector for each class. When
                // <see cref="Test"/> is called, this is set to the posterior weight
                // distributions from <see cref="Train"/>.
                wPrior = Variable.Array <VectorGaussian>(c).Named("wPrior");

                // The weight vector for each class.
                w    = Variable.Array <Vector>(c).Named("w");
                w[c] = Variable <Vector> .Random(wPrior[c]);

                noisePrecision = Variable.New <double>().Named("noisePrecision");

                // Arrays of <see cref="Vector"/>-valued items (feature vectors) and integer labels.
                x = Variable.Array <Vector>(i).Named("x");
                y = Variable.Array <int>(i).Named("y");

                // For all items...
                using (Variable.ForEach(i))
                {
                    // ...compute the score of this item across all classes...
                    score = BPMUtils.ComputeClassScores(w, x[i], noisePrecision);
                    y[i]  = Variable.DiscreteUniform(c);

                    // ... and constrain the output.
                    BPMUtils.ConstrainMaximum(y[i], score);
                }

                // Inference engine settings (EP).
                engine.Compiler.UseSerialSchedules = true;
                engine.ShowProgress = false;
            }
Example #4
0
        public void IndexOfMaximumDiverges()
        {
            int numberOfFeatures  = 10;
            int numberOfFolders   = 3;
            int numEmails         = 1000;
            var featuresCountsObs = Enumerable.Range(0, numEmails).Select(o => Rand.Binomial(numberOfFeatures, 5.0 / numberOfFeatures)).ToArray();
            var featureIndicesObs = featuresCountsObs.Select(o => Rand.Perm(numberOfFeatures).ToList().GetRange(0, o).ToArray()).ToArray();
            //var trueFeatureWeights = Enumerable.Range(0, numberOfFolders).Select(p=>Enumerable.Range(0, numberOfFeatures).Select(o => Rand.Normal()).ToArray()).ToArray();
            //var folders = featureIndicesObs.Select(fi=>fi.Select(p=>trueFeatureWeights.Select(q=>q[p]).Sum()
            // random data for now!
            var folders = Enumerable.Range(0, numEmails).Select(o => Rand.Int(numberOfFolders)).ToArray();

            Range numberOfFeaturesRange = new Range(numberOfFeatures).Named("NumberOfFeaturesRange");

            numberOfFeaturesRange.AddAttribute(new Sequential()); // This requires new build of Infer.NET

            // creat a range for the number of classes
            Range numberOfClases = new Range(numberOfFolders).Named("NumberOfClassesRange");

            // Model the total number of items
            var numberOfItems = Variable.New <int>().Named("numberOfItems");

            numberOfItems.ObservedValue = numEmails;
            Range numberOfItemsRange = new Range(numberOfItems).Named("numberOfItemsRange");

            numberOfItemsRange.AddAttribute(new Sequential());

            // Model the number features present in each item in each class
            var   featureCounts         = Variable.Array <int>(numberOfItemsRange).Named("featureCounts");
            Range featureCountItemRange = new Range(featureCounts[numberOfItemsRange]).Named("featureItemCountRange");

            featureCounts.ObservedValue = featuresCountsObs;

            // Model the features we observe
            var featureIndicies = Variable.Array(Variable.Array <int>(featureCountItemRange), numberOfItemsRange).Named("featureIndicies");

            featureIndicies.ObservedValue = featureIndicesObs;
            // Setup the priors
            var FeatureWeights = Variable.Array(Variable.Array <double>(numberOfFeaturesRange), numberOfClases).Named("FeatureWeights");

            FeatureWeights[numberOfClases][numberOfFeaturesRange] = Variable.GaussianFromMeanAndPrecision(0, 1).ForEach(numberOfClases, numberOfFeaturesRange);

            // Setup the label value (Folder)
            var folderValue = Variable.Array <int>(numberOfItemsRange).Named("folderValue");

            folderValue.ObservedValue = folders;

            var sparseWeightVector =
                Variable.Array(Variable.Array(Variable.Array <double>(featureCountItemRange), numberOfClases), numberOfItemsRange).Named("sparseWeightVector");

            ;
            sparseWeightVector[numberOfItemsRange][numberOfClases] = Variable.Subarray <double>(FeatureWeights[numberOfClases], featureIndicies[numberOfItemsRange]);
            var scoresWithNoise = Variable.Array(Variable.Array <double>(numberOfClases), numberOfItemsRange).Named("scoresWithNoise");

            scoresWithNoise[numberOfItemsRange][numberOfClases] = Variable.GaussianFromMeanAndVariance(Variable.Sum(sparseWeightVector[numberOfItemsRange][numberOfClases]), 1);
            folderValue[numberOfItemsRange] = Variable <int> .Factor(MMath.IndexOfMaximumDouble, scoresWithNoise[numberOfItemsRange]);

            folderValue.AddAttribute(new MarginalPrototype(Discrete.Uniform(numberOfClases.SizeAsInt)));

            var ie = new InferenceEngine();

            Console.WriteLine(ie.Infer(FeatureWeights));
        }
Example #5
0
        private void LearnAPIClick5LabelModel(
            int numLabels,
            bool learnScoreMean,
            bool learnScorePrec,
            bool learnJudgePrec,
            bool learnClickPrec,
            bool learnThresholds,
            double nominalScoreMean,
            double nominalScorePrec,
            double nominalJudgePrec,
            double nominalClickPrec,
            int[] labels,
            int[] clicks,
            int[] exams,
            int chunkSize,
            int nPasses,
            bool printToConsole,
            out Gaussian margScoreMean,
            out Gamma margScorePrec,
            out Gamma margJudgePrec,
            out Gamma margClickPrec,
            out Gaussian[] margThresh)
        {
            //------------------------------------------------------
            // Observations
            //------------------------------------------------------
            Gaussian[][][] allObs    = getClickObservations(numLabels, chunkSize, labels, clicks, exams);
            int            numChunks = allObs.Length;

            ////-------------------------------------------------------------
            //// Prior distributions
            ////-------------------------------------------------------------
            Gaussian priorScoreMean = Gaussian.FromMeanAndVariance(nominalScoreMean, learnScoreMean ? 1 : 0);
            Gamma    priorScorePrec = Gamma.FromMeanAndVariance(nominalScorePrec, learnScorePrec ? 1 : 0);
            Gamma    priorJudgePrec = Gamma.FromMeanAndVariance(nominalJudgePrec, learnJudgePrec ? 1 : 0);
            Gamma    priorClickPrec = Gamma.FromMeanAndVariance(nominalClickPrec, learnClickPrec ? 1 : 0);

            Gaussian[] priorThreshMean;
            CalculatePriors(learnThresholds, numLabels, out priorThreshMean);

            ////-----------------------------------------------------
            //// Creates shared variables
            ////-----------------------------------------------------
            int numThresholds = numLabels + 1;
            SharedVariable <double> scoreMean = SharedVariable <double> .Random(priorScoreMean).Named("scoreMean");

            SharedVariable <double> scorePrec = SharedVariable <double> .Random(priorScorePrec).Named("scorePrec");

            SharedVariable <double> judgePrec = SharedVariable <double> .Random(priorJudgePrec).Named("judgePrec");

            SharedVariable <double> clickPrec = SharedVariable <double> .Random(priorClickPrec).Named("clickPrec");

            SharedVariable <double>[] thresholds = new SharedVariable <double> [numThresholds];
            for (int t = 0; t < numThresholds; t++)
            {
                thresholds[t] = SharedVariable <double> .Random(priorThreshMean[t]).Named("threshMeans" + t);
            }

            //----------------------------------------------------------------------------------
            // The model
            //----------------------------------------------------------------------------------

            Model model = new Model(numChunks);

            VariableArray <Gaussian>[] clickObs       = new VariableArray <Gaussian> [numLabels];
            Variable <int>[]           clickObsLength = new Variable <int> [numLabels];

            for (int i = 0; i < numLabels; i++)
            {
                clickObsLength[i] = Variable.New <int>().Named("clickObsLength" + i);
                Range r = new Range(clickObsLength[i]).Named("dataCount" + i);
                clickObs[i] = Variable.Array <Gaussian>(r).Named("Obs" + i);
                VariableArray <double> scores  = Variable.Array <double>(r).Named("scores" + i);
                VariableArray <double> scoresJ = Variable.Array <double>(r).Named("scoresJ" + i);
                VariableArray <double> scoresC = Variable.Array <double>(r).Named("scoresC" + i);
                scores[r] = Variable <double> .GaussianFromMeanAndPrecision(scoreMean.GetCopyFor(model), scorePrec.GetCopyFor(model)).ForEach(r);

                scoresJ[r] = Variable <double> .GaussianFromMeanAndPrecision(scores[r], judgePrec.GetCopyFor(model));

                scoresC[r] = Variable <double> .GaussianFromMeanAndPrecision(scores[r], clickPrec.GetCopyFor(model));

                Variable.ConstrainBetween(scoresJ[r], thresholds[i].GetCopyFor(model), thresholds[i + 1].GetCopyFor(model));
                Variable.ConstrainEqualRandom <double, Gaussian>(scoresC[r], clickObs[i][r]);
                r.AddAttribute(new Sequential());
            }

            InferenceEngine engine = new InferenceEngine();

            //----------------------------------------------------------
            // Outer loop iterates over a number of passes
            // Inner loop iterates over the unique labels
            //----------------------------------------------------------
            for (int pass = 0; pass < nPasses; pass++)
            {
                for (int c = 0; c < numChunks; c++)
                {
                    for (int i = 0; i < numLabels; i++)
                    {
                        clickObsLength[i].ObservedValue = allObs[c][i].Length;
                        clickObs[i].ObservedValue       = allObs[c][i];
                    }

                    // Infer the output messages
                    model.InferShared(engine, c);

                    if (printToConsole)
                    {
                        margScoreMean = scoreMean.Marginal <Gaussian>();
                        margScorePrec = scorePrec.Marginal <Gamma>();
                        margJudgePrec = judgePrec.Marginal <Gamma>();
                        margClickPrec = clickPrec.Marginal <Gamma>();
                        margThresh    = new Gaussian[numThresholds];
                        for (int i = 0; i < numThresholds; i++)
                        {
                            margThresh[i] = thresholds[i].Marginal <Gaussian>();
                        }
                        Console.WriteLine("****** Pass {0}, chunk {1} ******", pass, c);
                        Console.WriteLine("----- Marginals -----");
                        Console.WriteLine("scoreMean = {0}", margScoreMean);
                        Console.WriteLine("scorePrec = {0}", margScorePrec);
                        Console.WriteLine("judgePrec = {0}", margJudgePrec);
                        Console.WriteLine("clickPrec = {0}", margClickPrec);
                        for (int t = 0; t < numThresholds; t++)
                        {
                            Console.WriteLine("threshMean {0} = {1}", t, margThresh[t]);
                        }
                    }
                }
            }
            margScoreMean = scoreMean.Marginal <Gaussian>();
            margScorePrec = scorePrec.Marginal <Gamma>();
            margJudgePrec = judgePrec.Marginal <Gamma>();
            margClickPrec = clickPrec.Marginal <Gamma>();
            margThresh    = new Gaussian[numThresholds];
            for (int i = 0; i < numThresholds; i++)
            {
                margThresh[i] = thresholds[i].Marginal <Gaussian>();
            }
        }
Example #6
0
			public Model()
			{
				// Classes.
				numClasses = Variable.New<int>().Named("numClasses");
				c = new Range(numClasses).Named("c");

				// Items.
				numItems = Variable.New<int>().Named("numItems");
				i = new Range(numItems).Named("i");
				i.AddAttribute(new Sequential());

				// The prior distribution for weight vector for each class. When
				// <see cref="Test"/> is called, this is set to the posterior weight
				// distributions from <see cref="Train"/>.
				wPrior = Variable.Array<VectorGaussian>(c).Named("wPrior");

				// The weight vector for each class.
				w = Variable.Array<Vector>(c).Named("w");
				w[c] = Variable<Vector>.Random(wPrior[c]);

				noisePrecision = Variable.New<double>().Named("noisePrecision");

				// Arrays of <see cref="Vector"/>-valued items (feature vectors) and integer labels.
				x = Variable.Array<Vector>(i).Named("x");
				y = Variable.Array<int>(i).Named("y");

				// For all items...
				using (Variable.ForEach(i))
				{
					// ...compute the score of this item across all classes...
					score = BPMUtils.ComputeClassScores(w, x[i], noisePrecision);
					y[i] = Variable.DiscreteUniform(c);

					// ... and constrain the output.
					BPMUtils.ConstrainMaximum(y[i], score);
				}

				// Inference engine settings (EP).
				engine.Compiler.UseSerialSchedules = true;
				engine.ShowProgress = false;
			}
Example #7
0
		public void Run()
		{
			InferenceEngine engine = new InferenceEngine();
			if (!(engine.Algorithm is ExpectationPropagation))
			{
				Console.WriteLine("This example only runs with Expectation Propagation");
				return;
			} 
			
			Rand.Restart(0);

			int nQuestions = 100;
			int nSubjects = 40;
			int nChoices = 4;
			Gaussian abilityPrior = new Gaussian(0, 1);
			Gaussian difficultyPrior = new Gaussian(0, 1);
			Gamma discriminationPrior = Gamma.FromShapeAndScale(5, 1);

			double[] trueAbility, trueDifficulty, trueDiscrimination;
			int[] trueTrueAnswer;
			int[][] data = Sample(nSubjects, nQuestions, nChoices, abilityPrior, difficultyPrior, discriminationPrior,
				out trueAbility, out trueDifficulty, out trueDiscrimination, out trueTrueAnswer);

			Range question = new Range(nQuestions).Named("question");
			Range subject = new Range(nSubjects).Named("subject");
			Range choice = new Range(nChoices).Named("choice");
			var response = Variable.Array(Variable.Array<int>(question), subject).Named("response");
			response.ObservedValue = data;

			var ability = Variable.Array<double>(subject).Named("ability");
			ability[subject] = Variable.Random(abilityPrior).ForEach(subject);
			var difficulty = Variable.Array<double>(question).Named("difficulty");
			difficulty[question] = Variable.Random(difficultyPrior).ForEach(question);
			var discrimination = Variable.Array<double>(question).Named("discrimination");
			discrimination[question] = Variable.Random(discriminationPrior).ForEach(question);
			var trueAnswer = Variable.Array<int>(question).Named("trueAnswer");
			trueAnswer[question] = Variable.DiscreteUniform(nChoices).ForEach(question);

			using (Variable.ForEach(subject)) {
				using (Variable.ForEach(question)) {
					var advantage = (ability[subject] - difficulty[question]).Named("advantage");
					var advantageNoisy = Variable.GaussianFromMeanAndPrecision(advantage, discrimination[question]).Named("advantageNoisy");
					var correct = (advantageNoisy > 0).Named("correct");
					using (Variable.If(correct))
						response[subject][question] = trueAnswer[question];
					using (Variable.IfNot(correct))
						response[subject][question] = Variable.DiscreteUniform(nChoices);
				}
			}

			engine.NumberOfIterations = 5;
			subject.AddAttribute(new Sequential());  // needed to get stable convergence
			engine.Compiler.UseSerialSchedules = true;
			if (false) {
				// set this to do majority voting
				ability.ObservedValue = Util.ArrayInit(nSubjects, i => 0.0);
				difficulty.ObservedValue = Util.ArrayInit(nQuestions, i => 0.0);
				discrimination.ObservedValue = Util.ArrayInit(nQuestions, i => 1.0);
			}
			var trueAnswerPosterior = engine.Infer<IList<Discrete>>(trueAnswer);
			int numCorrect = 0;
			for (int q = 0; q < nQuestions; q++) {
				int bestGuess = trueAnswerPosterior[q].GetMode();
				if (bestGuess == trueTrueAnswer[q]) numCorrect++;
			}
			double pctCorrect = 100.0*numCorrect/nQuestions;
			Console.WriteLine("{0}% TrueAnswers correct", pctCorrect.ToString("f0"));
			var difficultyPosterior = engine.Infer<IList<Gaussian>>(difficulty);
			for (int q = 0; q < Math.Min(nQuestions, 4); q++) {
				Console.WriteLine("difficulty[{0}] = {1} (sampled from {2})", q, difficultyPosterior[q], trueDifficulty[q].ToString("g2"));
			}
			var discriminationPosterior = engine.Infer<IList<Gamma>>(discrimination);
			for (int q = 0; q < Math.Min(nQuestions, 4); q++) {
				Console.WriteLine("discrimination[{0}] = {1} (sampled from {2})", q, discriminationPosterior[q], trueDiscrimination[q].ToString("g2"));
			}
			var abilityPosterior = engine.Infer<IList<Gaussian>>(ability);
			for (int s = 0; s < Math.Min(nSubjects, 4); s++) {
				Console.WriteLine("ability[{0}] = {1} (sampled from {2})", s, abilityPosterior[s], trueAbility[s].ToString("g2"));
			}
		}
Example #8
0
        public void Run()
        {
            InferenceEngine engine = new InferenceEngine();

            if (!(engine.Algorithm is ExpectationPropagation))
            {
                return;
            }

            int[][] fighter1Data, fighter2Data, outcomeData, winTypeData;
            int[]   firstYearData;
            int[]   lastYearData;

            int nFighters, nYears, startYear;

            LoadData(out fighter1Data, out fighter2Data, out outcomeData, out winTypeData, out firstYearData, out lastYearData,
                     out nFighters, out nYears, out startYear);

            //Skill prior
            var skillPrior = new Gaussian(1000, 500 * 500);
            var performancePrecisionPrior = Gamma.FromShapeAndRate(2, 26 * 26);
            var skillChangePrecisionPrior = Gamma.FromShapeAndRate(2, 26 * 26);

            var performancePrecision = Variable.Random(performancePrecisionPrior).Named("performancePrecision");
            var skillChangePrecision = Variable.Random(skillChangePrecisionPrior).Named("skillChangePrecision");

            var matchupThresholdPrior = new Gaussian(200, 50 * 50);
            var matchupThreshold      = Variable.Random(matchupThresholdPrior).Named("matchupThreshold");

            var finishThresholdPrior = new Gaussian(20, 10 * 10);
            var finishThreshold      = Variable.Random(finishThresholdPrior).Named("finishThreshold");

            var decicionThresholdPrior = new Gaussian(10, 10 * 10);
            var decisionThreshold      = Variable.Random(decicionThresholdPrior).Named("decisionThreshold");

            Range fighter = new Range(nFighters).Named("fighter");
            Range year    = new Range(nYears).Named("year");
            VariableArray <int> firstYear = Variable.Array <int>(fighter).Named("firstYear");
            var skill = Variable.Array(Variable.Array <double>(fighter), year).Named("skill");


            using (var yearBlock = Variable.ForEach(year))
            {
                var y = yearBlock.Index;
                using (Variable.If(y == 0))
                {
                    skill[year][fighter] = Variable.Random(skillPrior).ForEach(fighter);
                }
                using (Variable.If(y > 0))
                {
                    using (Variable.ForEach(fighter))
                    {
                        Variable <bool> isFirstYear = (firstYear[fighter] >= y).Named("isFirstYear");
                        using (Variable.If(isFirstYear))
                        {
                            skill[year][fighter] = Variable.Random(skillPrior);
                        }
                        using (Variable.IfNot(isFirstYear))
                        {
                            skill[year][fighter] = Variable.GaussianFromMeanAndPrecision(skill[y - 1][fighter], skillChangePrecision);
                        }
                    }
                }
            }



            firstYear.ObservedValue = firstYearData;

            int[] nMatchesData = Util.ArrayInit(nYears, y => outcomeData[y].Length);
            var   nMatches     = Variable.Observed(nMatchesData, year).Named("nMatches");
            Range match        = new Range(nMatches[year]).Named("match");
            var   fighter1     = Variable.Observed(fighter1Data, year, match).Named("fighter1");
            var   fighter2     = Variable.Observed(fighter2Data, year, match).Named("fighter2");
            var   outcome      = Variable.Observed(outcomeData, year, match).Named("outcome");
            var   winType      = Variable.Observed(winTypeData, year, match).Named("winType");

            Variable.ConstrainTrue(finishThreshold > decisionThreshold);
            Variable.ConstrainTrue(decisionThreshold > 0);


            using (Variable.ForEach(year))
            {
                using (Variable.ForEach(match))
                {
                    var w = fighter1[year][match];
                    var b = fighter2[year][match];
                    Variable <double> fighter1_performance = Variable.GaussianFromMeanAndPrecision(skill[year][w], performancePrecision).Named("fighter1_performance");
                    Variable <double> fighter2_performance = Variable.GaussianFromMeanAndPrecision(skill[year][b], performancePrecision).Named("fighter2_performance");

                    Variable.ConstrainFalse(skill[year][w] - skill[year][b] > matchupThreshold);
                    Variable.ConstrainFalse(skill[year][b] - skill[year][w] > matchupThreshold);

                    using (Variable.Case(outcome[year][match], 0))
                    { // fighter2 wins
                        Variable.ConstrainTrue((fighter2_performance - fighter1_performance) > decisionThreshold);

                        //Finish
                        using (Variable.Case(winType[year][match], 1))
                        {
                            Variable.ConstrainTrue((fighter2_performance - fighter1_performance) > finishThreshold);
                        }
                    }
                    using (Variable.Case(outcome[year][match], 1))
                    { // draw
                        Variable.ConstrainFalse((fighter2_performance - fighter1_performance) < decisionThreshold);
                        Variable.ConstrainFalse((fighter1_performance - fighter2_performance) < decisionThreshold);
                    }
                    using (Variable.Case(outcome[year][match], 2))
                    { // fighter1 wins
                        Variable.ConstrainTrue((fighter1_performance - fighter2_performance) > decisionThreshold);
                        //Finish
                        using (Variable.Case(winType[year][match], 1))
                        {
                            Variable.ConstrainTrue((fighter1_performance - fighter2_performance) > finishThreshold);
                        }
                    }
                }
            }
            year.AddAttribute(new Sequential());   // helps inference converge faster
            engine.Compiler.UseSerialSchedules = false;
            engine.NumberOfIterations          = 200;
            var skillPost                = engine.Infer <Gaussian[][]>(skill);
            var matchupThresholdPost     = engine.Infer <Gaussian>(matchupThreshold);
            var decisionThresholdPost    = engine.Infer <Gaussian>(decisionThreshold);
            var finishThresholdPost      = engine.Infer <Gaussian>(finishThreshold);
            var skillChangePrecisionPost = engine.Infer <Gamma>(skillChangePrecision);

            Console.WriteLine("Matchup Threshold prec {0}", matchupThresholdPost);
            Console.WriteLine("Decision Threshold {0}", decisionThresholdPost);
            Console.WriteLine("Finish threshold {0}", finishThresholdPost);
            Console.WriteLine("Skilll change prec {0}", skillChangePrecisionPost);

            using (System.IO.StreamWriter file =
                       new System.IO.StreamWriter(@"outfile.txt"))
            {
                file.WriteLine("key year name skillmean variance");
                for (int i = 0; i < nFighters; i++)
                {
                    for (int y = 0; y < nYears; y++)
                    {
                        if (y >= firstYearData[i] && y <= lastYearData[i])
                        {
                            file.WriteLine("{0} {1} {2} {3} {4}", i, startYear + y, keyToFighter[i], skillPost[y][i].GetMean(), skillPost[y][i].GetVariance());
                        }
                    }
                }
            }
        }
Example #9
0
        public void Run()
        {
            InferenceEngine engine = new InferenceEngine();

            if (!(engine.Algorithm is ExpectationPropagation))
            {
                Console.WriteLine("This example only runs with Expectation Propagation");
                return;
            }

            Rand.Restart(0);

            int      nQuestions          = 100;
            int      nSubjects           = 40;
            int      nChoices            = 4;
            Gaussian abilityPrior        = new Gaussian(0, 1);
            Gaussian difficultyPrior     = new Gaussian(0, 1);
            Gamma    discriminationPrior = Gamma.FromMeanAndVariance(1, 0.01);

            double[] trueAbility, trueDifficulty, trueDiscrimination;
            int[]    trueTrueAnswer;
            int[][]  data = Sample(nSubjects, nQuestions, nChoices, abilityPrior, difficultyPrior, discriminationPrior,
                                   out trueAbility, out trueDifficulty, out trueDiscrimination, out trueTrueAnswer);

            Range question = new Range(nQuestions).Named("question");
            Range subject  = new Range(nSubjects).Named("subject");
            Range choice   = new Range(nChoices).Named("choice");
            var   response = Variable.Array(Variable.Array <int>(question), subject).Named("response");

            response.ObservedValue = data;

            var ability = Variable.Array <double>(subject).Named("ability");

            ability[subject] = Variable.Random(abilityPrior).ForEach(subject);
            var difficulty = Variable.Array <double>(question).Named("difficulty");

            difficulty[question] = Variable.Random(difficultyPrior).ForEach(question);
            var discrimination = Variable.Array <double>(question).Named("discrimination");

            discrimination[question] = Variable.Random(discriminationPrior).ForEach(question);
            var trueAnswer = Variable.Array <int>(question).Named("trueAnswer");

            trueAnswer[question] = Variable.DiscreteUniform(choice).ForEach(question);

            using (Variable.ForEach(subject)) {
                using (Variable.ForEach(question)) {
                    var advantage      = (ability[subject] - difficulty[question]).Named("advantage");
                    var advantageNoisy = Variable.GaussianFromMeanAndPrecision(advantage, discrimination[question]).Named("advantageNoisy");
                    var correct        = (advantageNoisy > 0).Named("correct");
                    using (Variable.If(correct))
                        response[subject][question] = trueAnswer[question];
                    using (Variable.IfNot(correct))
                        response[subject][question] = Variable.DiscreteUniform(choice);
                }
            }

            engine.NumberOfIterations = 5;
            subject.AddAttribute(new Sequential());  // needed to get stable convergence
            question.AddAttribute(new Sequential()); // needed to get stable convergence
            bool doMajorityVoting = false;           // set this to 'true' to do majority voting

            if (doMajorityVoting)
            {
                ability.ObservedValue        = Util.ArrayInit(nSubjects, i => 0.0);
                difficulty.ObservedValue     = Util.ArrayInit(nQuestions, i => 0.0);
                discrimination.ObservedValue = Util.ArrayInit(nQuestions, i => 1.0);
            }
            var trueAnswerPosterior = engine.Infer <IList <Discrete> >(trueAnswer);
            int numCorrect          = 0;

            for (int q = 0; q < nQuestions; q++)
            {
                int bestGuess = trueAnswerPosterior[q].GetMode();
                if (bestGuess == trueTrueAnswer[q])
                {
                    numCorrect++;
                }
            }
            double pctCorrect = 100.0 * numCorrect / nQuestions;

            Console.WriteLine("{0}% TrueAnswers correct", pctCorrect.ToString("f0"));
            var difficultyPosterior = engine.Infer <IList <Gaussian> >(difficulty);

            for (int q = 0; q < Math.Min(nQuestions, 4); q++)
            {
                Console.WriteLine("difficulty[{0}] = {1} (sampled from {2})", q, difficultyPosterior[q], trueDifficulty[q].ToString("g2"));
            }
            var discriminationPosterior = engine.Infer <IList <Gamma> >(discrimination);

            for (int q = 0; q < Math.Min(nQuestions, 4); q++)
            {
                Console.WriteLine("discrimination[{0}] = {1} (sampled from {2})", q, discriminationPosterior[q], trueDiscrimination[q].ToString("g2"));
            }
            var abilityPosterior = engine.Infer <IList <Gaussian> >(ability);

            for (int s = 0; s < Math.Min(nSubjects, 4); s++)
            {
                Console.WriteLine("ability[{0}] = {1} (sampled from {2})", s, abilityPosterior[s], trueAbility[s].ToString("g2"));
            }
        }
Example #10
0
			public Model(SharedVariableArray<Vector> w, Range c, int numChunks)
			{
				// Items.
				numItems = Variable.New<int>().Named("numItems");
				i = new Range(numItems).Named("i");
				i.AddAttribute(new Sequential());
	
				// The model identifier for the shared variables.
				model = new MicrosoftResearch.Infer.Models.Model(numChunks).Named("model");
				// The weight vector for each submodel.
				wModel = w.GetCopyFor(model).Named("wModel");

				noisePrecision = Variable.New<double>().Named("noisePrecision");

				// Arrays of <see cref="Vector"/>-valued items (feature vectors) and integer labels.
				x = Variable.Array<Vector>(i).Named("x");
				y = Variable.Array<int>(i).Named("y");

				// For all items...
				using (Variable.ForEach(i))
				{
					// ...compute the score of this item across all classes...
					score = BPMUtils.ComputeClassScores(wModel, x[i], noisePrecision);
					y[i] = Variable.DiscreteUniform(c);

					// ... and constrain the output.
					BPMUtils.ConstrainMaximum(y[i], score);
				}

				// Inference engine settings (EP).
				engine.Compiler.UseSerialSchedules = true;
				engine.ShowProgress = false;
			}
        private static void DistributedScheduleTestProcess(
            ICommunicator comm,
            IList <Gaussian>[] xResults,
            Gaussian[] shiftResults,
            Compiler.Graphs.DistributedCommunicationInfo distributedCommunicationInfo,
            int[][] scheduleForProcess,
            // [distributedStage][thread][block][i]
            int[][][][] schedulePerThreadForProcess)
        {
            var   nodeCountVar = Variable.Observed(0).Named("nodeCount");
            Range node         = new Range(nodeCountVar).Named("node");

            node.AddAttribute(new Sequential()
            {
                BackwardPass = true
            });
            var   itemCountVar = Variable.Observed(0).Named("itemCount");
            Range item         = new Range(itemCountVar).Named("item");
            var   x            = Variable.Array <double>(item).Named("x");

            x[item] = Variable.GaussianFromMeanAndPrecision(0, 1).ForEach(item);
            var   parentCount = Variable.Observed(default(int[]), node).Named("parentCount");
            Range parent      = new Range(parentCount[node]).Named("parent");
            var   indices     = Variable.Observed(default(int[][]), node, parent).Named("indices");

            indices.SetValueRange(item);
            var shift = Variable.GaussianFromMeanAndPrecision(0, 1).Named("shift");

            shift.AddAttribute(new PointEstimate());
            using (Variable.ForEach(node))
            {
                var subArray = Variable.Subarray(x, indices[node]).Named("subArray");
                using (Variable.If(parentCount[node] == 1))
                {
                    Variable.ConstrainEqualRandom(subArray[0], Gaussian.FromMeanAndVariance(0, 1));
                }
                using (Variable.If(parentCount[node] == 2))
                {
                    Variable.ConstrainEqual(subArray[0], subArray[1] + 1);
                }
                Variable.ConstrainEqualRandom(shift, new Gaussian(1, 2));
            }

            // this dummy part of the model causes depth cloning to occur
            Range item2     = new Range(0);
            var   indices2  = Variable.Observed(new int[0], item2).Named("indices2");
            var   subArray2 = Variable.Subarray(x, indices2);

            Variable.ConstrainEqual(subArray2[item2], 0.0);

            var   distributedStageCount = Variable.Observed(0).Named("distributedStageCount");
            Range distributedStage      = new Range(distributedStageCount).Named("stage");
            var   commVar = Variable.Observed(default(ICommunicator)).Named("comm");

            if (schedulePerThreadForProcess != null)
            {
                var   threadCount = Variable.Observed(0).Named("threadCount");
                Range thread      = new Range(threadCount).Named("thread");
                var   blockCountOfDistributedStage = Variable.Observed(default(int[]), distributedStage).Named("blockCount");
                Range gameBlock = new Range(blockCountOfDistributedStage[distributedStage]).Named("block");
                var   gameCountInBlockOfDistributedStage = Variable.Observed(default(int[][][]), distributedStage, thread, gameBlock).Named("GameCountInBlock");
                Range gameInBlock = new Range(gameCountInBlockOfDistributedStage[distributedStage][thread][gameBlock]).Named("gameInBlock");
                var   gamesInBlockOfDistributedStage = Variable.Array(Variable.Array(Variable.Array(Variable.Array <int>(gameInBlock), gameBlock), thread), distributedStage).Named("GamesInBlock");
                gamesInBlockOfDistributedStage.ObservedValue = default(int[][][][]);
                node.AddAttribute(new DistributedSchedule(commVar, gamesInBlockOfDistributedStage));

                threadCount.ObservedValue = schedulePerThreadForProcess[0].Length;
                blockCountOfDistributedStage.ObservedValue       = Util.ArrayInit(schedulePerThreadForProcess.Length, stageIndex => schedulePerThreadForProcess[stageIndex][0].Length);
                gameCountInBlockOfDistributedStage.ObservedValue = Util.ArrayInit(schedulePerThreadForProcess.Length, stageIndex =>
                                                                                  Util.ArrayInit(schedulePerThreadForProcess[stageIndex].Length, t =>
                                                                                                 Util.ArrayInit(schedulePerThreadForProcess[stageIndex][t].Length, b =>
                                                                                                                schedulePerThreadForProcess[stageIndex][t][b].Length)));
                gamesInBlockOfDistributedStage.ObservedValue = schedulePerThreadForProcess;
            }
            else
            {
                var   gameCountInLocalBlock = Variable.Observed(new int[0], distributedStage).Named("gameCountInLocalBlock");
                Range gameInLocalBlock      = new Range(gameCountInLocalBlock[distributedStage]).Named("gameInLocalBlock");
                var   nodesInLocalBlock     = Variable.Observed(new int[0][], distributedStage, gameInLocalBlock).Named("nodesInLocalBlock");
                node.AddAttribute(new DistributedSchedule(commVar, nodesInLocalBlock));

                gameCountInLocalBlock.ObservedValue = Util.ArrayInit(scheduleForProcess.Length, stageIndex =>
                                                                     scheduleForProcess[stageIndex].Length);
                nodesInLocalBlock.ObservedValue = scheduleForProcess;
            }

            var   processCount               = Variable.Observed(0).Named("processCount");
            Range sender                     = new Range(processCount);
            var   arrayIndicesToSendCount    = Variable.Observed(default(int[][]), distributedStage, sender).Named("arrayIndicesToSendCount");
            Range arrayIndexToSend           = new Range(arrayIndicesToSendCount[distributedStage][sender]);
            var   arrayIndicesToSendVar      = Variable.Observed(default(int[][][]), distributedStage, sender, arrayIndexToSend).Named("arrayIndicesToSend");
            var   arrayIndicesToReceiveCount = Variable.Observed(default(int[][]), distributedStage, sender).Named("arrayIndicesToReceiveCount");
            Range arrayIndexToReceive        = new Range(arrayIndicesToReceiveCount[distributedStage][sender]);
            var   arrayIndicesToReceiveVar   = Variable.Observed(default(int[][][]), distributedStage, sender, arrayIndexToReceive).Named("arrayIndexToReceive");

            indices.AddAttribute(new DistributedCommunication(arrayIndicesToSendVar, arrayIndicesToReceiveVar));

            distributedStageCount.ObservedValue = scheduleForProcess.Length;

            commVar.ObservedValue                    = comm;
            processCount.ObservedValue               = comm.Size;
            nodeCountVar.ObservedValue               = distributedCommunicationInfo.indices.Length;
            itemCountVar.ObservedValue               = distributedCommunicationInfo.arrayLength;
            parentCount.ObservedValue                = distributedCommunicationInfo.indicesCount;
            indices.ObservedValue                    = distributedCommunicationInfo.indices;
            arrayIndicesToSendCount.ObservedValue    = distributedCommunicationInfo.arrayIndicesToSendCount;
            arrayIndicesToSendVar.ObservedValue      = distributedCommunicationInfo.arrayIndicesToSend;
            arrayIndicesToReceiveCount.ObservedValue = distributedCommunicationInfo.arrayIndicesToReceiveCount;
            arrayIndicesToReceiveVar.ObservedValue   = distributedCommunicationInfo.arrayIndicesToReceive;

            InferenceEngine engine = new InferenceEngine();

            //engine.Compiler.UseExistingSourceFiles = true;
            engine.ModelName            = "DistributedScheduleTest" + comm.Rank;
            engine.ShowProgress         = false;
            engine.NumberOfIterations   = 2;
            engine.OptimiseForVariables = new IVariable[] { x, shift };
            var xActual = engine.Infer <IList <Gaussian> >(x);

            xResults[comm.Rank] = xActual;
            var shiftActual = engine.Infer <Gaussian>(shift);

            shiftResults[comm.Rank] = shiftActual;
        }
        private int[][][] parallelScheduleTest(int numThreads, int nodeCount, out IReadOnlyList <Gaussian> xMarginal, out Gaussian shiftMarginal, out IReadOnlyList <int[]> variablesUsedByNode)
        {
            int maxParentCount = 1;

            variablesUsedByNode = GenerateVariablesUsedByNode(nodeCount, maxParentCount);
            ParallelScheduler ps = new ParallelScheduler();

            ps.CreateGraph(variablesUsedByNode);
            var schedule = ps.GetScheduleWithBarriers(numThreads);

            ParallelScheduler.WriteSchedule(schedule, true);
            var schedulePerThread = ps.ConvertToSchedulePerThread(schedule, numThreads);

            var   nodeCountVar = Variable.Observed(nodeCount).Named("nodeCount");
            Range node         = new Range(nodeCountVar).Named("node");

            node.AddAttribute(new Sequential()
            {
                BackwardPass = true
            });
            var x = Variable.Array <double>(node).Named("x");

            x[node] = Variable.GaussianFromMeanAndPrecision(0, 1).ForEach(node);
            var   parentCount = Variable.Observed(variablesUsedByNode.Select(a => a.Length).ToArray(), node).Named("parentCount");
            Range parent      = new Range(parentCount[node]).Named("parent");
            var   indices     = Variable.Observed(variablesUsedByNode.ToArray(), node, parent).Named("indices");
            var   shift       = Variable.GaussianFromMeanAndPrecision(0, 1).Named("shift");

            shift.AddAttribute(new PointEstimate());
            using (Variable.ForEach(node))
            {
                var subArray = Variable.Subarray(x, indices[node]).Named("subArray");
                using (Variable.If(parentCount[node] == 1))
                {
                    Variable.ConstrainEqualRandom(subArray[0], Gaussian.FromMeanAndVariance(0, 1));
                }
                using (Variable.If(parentCount[node] == 2))
                {
                    Variable.ConstrainEqual(subArray[0], subArray[1] + 1);
                }
                Variable.ConstrainEqualRandom(shift, new Gaussian(1, 2));
            }

            InferenceEngine engine = new InferenceEngine();

            engine.NumberOfIterations   = 2;
            engine.OptimiseForVariables = new IVariable[] { x, shift };
            var xExpected = engine.Infer(x);
            //Console.WriteLine(xExpected);
            var shiftExpected = engine.Infer(shift);

            var   threadCount      = Variable.Observed(0).Named("threadCount");
            Range thread           = new Range(threadCount).Named("thread");
            var   blockCount       = Variable.Observed(0).Named("blockCount");
            Range gameBlock        = new Range(blockCount).Named("block");
            var   gameCountInBlock = Variable.Observed(default(int[][]), thread, gameBlock).Named("GameCountInBlock");
            Range gameInBlock      = new Range(gameCountInBlock[thread][gameBlock]).Named("gameInBlock");
            var   gamesInBlock     = Variable.Observed(default(int[][][]), thread, gameBlock, gameInBlock).Named("GamesInBlock");

            node.AddAttribute(new ParallelSchedule(gamesInBlock));

            threadCount.ObservedValue      = schedulePerThread.Length;
            blockCount.ObservedValue       = (schedulePerThread.Length == 0) ? 0 : schedulePerThread[0].Length;
            gameCountInBlock.ObservedValue = Util.ArrayInit(schedulePerThread.Length, t =>
                                                            Util.ArrayInit(schedulePerThread[t].Length, b => schedulePerThread[t][b].Length));
            gamesInBlock.ObservedValue = schedulePerThread;

            var xActual = engine.Infer <IReadOnlyList <Gaussian> >(x);

            //Debug.WriteLine(xActual);
            Assert.True(xExpected.Equals(xActual));
            var shiftActual = engine.Infer <Gaussian>(shift);

            Assert.True(shiftExpected.Equals(shiftActual));

            xMarginal     = xActual;
            shiftMarginal = shiftActual;
            return(schedulePerThread);
        }
Example #13
0
			public Model()
			{
				// Classes.
				numClasses = Variable.New<int>().Named("numClasses");
				c = new Range(numClasses).Named("c");

				// Features.
				numFeatures = Variable.New<int>().Named("numFeatures");
				f = new Range(numFeatures).Named("f");

				// Items.
				numItems = Variable.New<int>().Named("numItems");
				i = new Range(numItems).Named("i");
				i.AddAttribute(new Sequential());

				// Features per item.
				numFeaturesPerItem = Variable.Array<int>(i).Named("numFeaturesPerItem");
				fItem = new Range(numFeaturesPerItem[i]).Named("fItem");

				// The prior distribution for weight vector for each class. When
				// <see cref="Test"/> is called, this is set to the posterior weight
				// distributions from <see cref="Train"/>.
				wPrior = Variable.Array(Variable.Array<Gaussian>(f), c).Named("wPrior");

				// The weight vector for each class.
				w = Variable.Array(Variable.Array<double>(f), c).Named("w");
				w[c][f] = Variable<double>.Random(wPrior[c][f]);

				noisePrecision = Variable.New<double>().Named("noisePrecision");

				// Jagged array of feature values - each item is an array of data values 
				// whose indices are given by the corresponding indices[i].
				values = Variable.Array(Variable.Array<double>(fItem), i).Named("values");

				// Jagged array of indices for the items.
				indices = Variable.Array(Variable.Array<int>(fItem), i).Named("indices");

				// Labels.
				y = Variable.Array<int>(i).Named("y");

				// For all items...
				using (Variable.ForEach(i))
				{
					// ...compute the score of this item across all classes...
					score = BPMUtils.ComputeClassScores(w, values[i], indices[i], fItem, noisePrecision);
					y[i] = Variable.DiscreteUniform(c);

					// ...and constrain the output.
					BPMUtils.ConstrainMaximum(y[i], score);
				}

				// Inference engine settings (EP).
				engine.Compiler.UseSerialSchedules = true;
				engine.ShowProgress = false;
			}
Example #14
0
        /// <summary>
        /// Constructs the model.
        /// </summary>
        public override void ConstructModel()
        {
            if (this.HasBeenConstructed)
            {
                return;
            }

            this.NumberOfPeople   = Variable.New <int>().Named("NumberOfPeople").Attrib(new DoNotInfer());
            this.NumberOfFeatures = Variable.New <int>().Named("NumberOfFeatures").Attrib(new DoNotInfer());

            Range buckets = new Range(this.NumberOfFeatures).Named("buckets");
            Range users   = new Range(this.NumberOfPeople).Named("users");

            this.NumberOfMessages = Variable.Array <int>(users).Named("numberOfMessages").Attrib(new DoNotInfer());

            Range emails = new Range(this.NumberOfMessages[users]).Named("emails");

            // Make sure that the range across messages is handled sequentially
            // - this is necessary to ensure the model converges during training
            emails.AddAttribute(new Sequential());

            this.FeatureCounts = Variable.Array(Variable.Array <int>(emails), users).Named("FeatureCounts").Attrib(new DoNotInfer());

            Range indices = new Range(this.FeatureCounts[users][emails]).Named("indices");

            // observed data
            this.FeatureValue =
                Variable.Array(Variable.Array(Variable.Array <double>(indices), emails), users)
                .Named("featureValue")
                .Attrib(new DoNotInfer());

            this.FeatureIndices =
                Variable.Array(Variable.Array(Variable.Array <int>(indices), emails), users)
                .Named("featureIndices")
                .Attrib(new DoNotInfer());

            // The weights
            this.Weight = Variable.Array(Variable.Array <double>(buckets), users).Named("weight");

            // The priors on the weights
            this.WeightMean      = Variable.Array <double>(buckets).Named("weightMean");
            this.WeightPrecision = Variable.Array <double>(buckets).Named("weightPrecision");

            this.WeightMeanPriors      = Variable.New <DistributionStructArray <Gaussian, double> >().Named("WeightMeanPriors").Attrib(new DoNotInfer());
            this.WeightPrecisionPriors = Variable.New <DistributionStructArray <Gamma, double> >().Named("WeightPrecisionPriors").Attrib(new DoNotInfer());

            this.WeightMean.SetTo(Variable <double[]> .Random(this.WeightMeanPriors));
            this.WeightPrecision.SetTo(Variable <double[]> .Random(this.WeightPrecisionPriors));

            // Noise Variance
            this.NoiseVariance = Variable.New <double>().Named("NoiseVariance").Attrib(new DoNotInfer());

            // Label: is the message replied to?
            this.RepliedTo = Variable.Array(Variable.Array <bool>(emails), users).Named("repliedTo");

            // Loop over people
            using (Variable.ForEach(users))
            {
                // Loop over features
                using (Variable.ForEach(buckets))
                {
                    this.Weight[users][buckets] = Variable.GaussianFromMeanAndPrecision(
                        this.WeightMean[buckets],
                        this.WeightPrecision[buckets]);
                }

                // Loop over emails
                using (Variable.ForEach(emails))
                {
                    var featureWeight = Variable.Subarray(this.Weight[users], this.FeatureIndices[users][emails]).Named("featureWeight");
                    var featureScore  = Variable.Array <double>(indices).Named("featureScore");

                    featureScore[indices] = this.FeatureValue[users][emails][indices]
                                            * featureWeight[indices];

                    var score = Variable.Sum(featureScore).Named("score");

                    this.RepliedTo[users][emails] = Variable.GaussianFromMeanAndVariance(score, this.NoiseVariance).Named("noisyScore") > 0;
                }
            }

            this.InitializeEngine();

            // if during personalisation we update the weights rather than the weight mean and precision, then this will need to change
            switch (this.Mode)
            {
            case InputMode.CommunityTraining:
            case InputMode.Training:
                this.Engine.OptimiseForVariables = new IVariable[] { this.Weight, this.WeightMean, this.WeightPrecision };
                break;

            default:
                this.Engine.OptimiseForVariables = this.Engine.OptimiseForVariables = new IVariable[] { this.RepliedTo };
                break;
            }

            this.HasBeenConstructed = true;
        }
        public InferenceResult<ClusterRegressionWeights[]> Regression(Vector[] features, double[] values, int clusters)
        {
            var dimensions = features[0].Count;
            var evidence = Variable.Bernoulli(0.5).Named("evidence");
            var evidenceBlock = Variable.If(evidence);

            var clustersRange = new Range(clusters).Named("clustersRange");
            var wMeans = Variable.Array<Vector>(clustersRange).Named("wMeans");
            var wPrecision = Variable.Array<PositiveDefiniteMatrix>(clustersRange).Named("wPrecision");
            var noise = Variable.Array<double>(clustersRange).Named("noise");
            var w = Variable.Array<Vector>(clustersRange).Named("w");
            using(Variable.ForEach(clustersRange))
            {
                wMeans[clustersRange] = Variable
                    .VectorGaussianFromMeanAndPrecision(
                    Vector.Zero(dimensions),
                    PositiveDefiniteMatrix.IdentityScaledBy(dimensions, 0.01));
                wPrecision[clustersRange] = Variable.WishartFromShapeAndRate(100, PositiveDefiniteMatrix.IdentityScaledBy(dimensions, 0.01));
                w[clustersRange] = Variable.VectorGaussianFromMeanAndPrecision(wMeans[clustersRange], wPrecision[clustersRange]);
                noise[clustersRange] = Variable.GammaFromMeanAndVariance(2, 5);
            }

            var numItems = Variable.New<int>().Named("numItems");
            var i = new Range(numItems).Named("i");
            i.AddAttribute(new Sequential());

            var initialWeights = Enumerable.Range(0, clusters).Select(_ => 1.0).ToArray();
            var mixtureWeightsPrior = Variable.Dirichlet(clustersRange, initialWeights).Named("mixtureWeightsPrior");

            var latentIndex = Variable.Array<int>(i).Named("latentIndex");

            var x = Variable.Array<Vector>(i).Named("x");
            var y = Variable.Array<double>(i).Named("y");

            using (Variable.ForEach(i))
            {
                latentIndex[i] = Variable.Discrete(mixtureWeightsPrior);
                using(Variable.Switch(latentIndex[i]))
                {
                    y[i] = Variable.GaussianFromMeanAndPrecision(Variable.InnerProduct(w[latentIndex[i]], x[i]), noise[latentIndex[i]]);
                }
            }

            numItems.ObservedValue = features.Length;
            var zinit = new Discrete[features.Length];
            for (var j = 0; j < zinit.Length; j++)
                zinit[j] = Discrete.PointMass(Rand.Int(clustersRange.SizeAsInt), clustersRange.SizeAsInt);
            latentIndex.InitialiseTo(Distribution<int>.Array(zinit));

            evidenceBlock.CloseBlock();

            x.ObservedValue = features;
            y.ObservedValue = values;

            var engine = new InferenceEngine(new VariationalMessagePassing());
            engine.Compiler.UseSerialSchedules = true;
            engine.ShowProgress = false;
            var wPosterior = engine.Infer<IList<VectorGaussian>>(w);
            var mixtureWeightsPosterior = engine.Infer<Dirichlet>(mixtureWeightsPrior);
            var noisePosterior = engine.Infer<IList<Gamma>>(noise);
            var bEvidence = engine.Infer<Bernoulli>(evidence);

            var clusterList = new List<ClusterRegressionWeights>();
            for (var c = 0; c < clusters; c++ )
            {
                clusterList.Add(new ClusterRegressionWeights(wPosterior[c].GetMean(), noisePosterior[c], mixtureWeightsPosterior.GetMean()[c]));
            }

            return new InferenceResult<ClusterRegressionWeights[]>(bEvidence, clusterList.ToArray());
        }
Example #16
0
        public void Run()
        {
            // This example requires EP
            InferenceEngine engine = new InferenceEngine();

            if (!(engine.Algorithm is Algorithms.ExpectationPropagation))
            {
                Console.WriteLine("This example only runs with Expectation Propagation");
                return;
            }

            int nPlayers = 10;
            int nYears   = 10;

            Rand.Restart(1);

            var skillPrior                     = new Gaussian(1200, 800 * 800);
            var drawMarginMeanPrior            = new Gaussian(700, 500 * 500);
            var drawMarginPrecisionPrior       = Gamma.FromShapeAndRate(2, 500 * 500);
            var performancePrecisionPrior      = Gamma.FromShapeAndRate(2, 800 * 800);
            var skillChangePrecisionPrior      = Gamma.FromShapeAndRate(2, 26 * 26);
            var drawMarginChangePrecisionPrior = Gamma.FromShapeAndRate(2, 10 * 10);
            var whiteAdvantagePrior            = new Gaussian(0, 200 * 200);

            var drawMarginMean            = Variable.Random(drawMarginMeanPrior).Named("drawMarginMean");
            var drawMarginPrecision       = Variable.Random(drawMarginPrecisionPrior).Named("drawMarginPrecision");
            var performancePrecision      = Variable.Random(performancePrecisionPrior).Named("performancePrecision");
            var skillChangePrecision      = Variable.Random(skillChangePrecisionPrior).Named("skillChangePrecision");
            var drawMarginChangePrecision = Variable.Random(drawMarginChangePrecisionPrior).Named("drawMarginChangePrecision");
            var whiteAdvantage            = Variable.Random(whiteAdvantagePrior).Named("whiteAdvantage");

            Range player = new Range(nPlayers).Named("player");
            Range year   = new Range(nYears).Named("year");
            VariableArray <int> firstYear = Variable.Array <int>(player).Named("firstYear");
            var skill      = Variable.Array(Variable.Array <double>(player), year).Named("skill");
            var drawMargin = Variable.Array(Variable.Array <double>(player), year).Named("drawMargin");

            using (var yearBlock = Variable.ForEach(year))
            {
                var y = yearBlock.Index;
                using (Variable.If(y == 0))
                {
                    skill[year][player]      = Variable.Random(skillPrior).ForEach(player);
                    drawMargin[year][player] = Variable.GaussianFromMeanAndPrecision(drawMarginMean, drawMarginPrecision).ForEach(player);
                }

                using (Variable.If(y > 0))
                {
                    using (Variable.ForEach(player))
                    {
                        Variable <bool> isFirstYear = (firstYear[player] >= y).Named("isFirstYear");
                        using (Variable.If(isFirstYear))
                        {
                            skill[year][player]      = Variable.Random(skillPrior);
                            drawMargin[year][player] = Variable.GaussianFromMeanAndPrecision(drawMarginMean, drawMarginPrecision);
                        }

                        using (Variable.IfNot(isFirstYear))
                        {
                            skill[year][player]      = Variable.GaussianFromMeanAndPrecision(skill[y - 1][player], skillChangePrecision);
                            drawMargin[year][player] = Variable.GaussianFromMeanAndPrecision(drawMargin[y - 1][player], drawMarginChangePrecision);
                        }
                    }
                }
            }

            // Sample parameter values according to the above model
            firstYear.ObservedValue = Util.ArrayInit(nPlayers, i => Rand.Int(nYears));
            Parameters parameters = new Parameters();

            parameters.drawMarginMean            = drawMarginMeanPrior.Sample();
            parameters.drawMarginPrecision       = drawMarginPrecisionPrior.Sample();
            parameters.performancePrecision      = performancePrecisionPrior.Sample();
            parameters.skillChangePrecision      = skillChangePrecisionPrior.Sample();
            parameters.drawMarginChangePrecision = drawMarginChangePrecisionPrior.Sample();
            parameters.whiteAdvantage            = whiteAdvantagePrior.Sample();
            parameters.skill      = Util.ArrayInit(nYears, y => Util.ArrayInit(nPlayers, i => skillPrior.Sample()));
            parameters.drawMargin = Util.ArrayInit(nYears, y => Util.ArrayInit(nPlayers, i => Gaussian.Sample(parameters.drawMarginMean, parameters.drawMarginPrecision)));
            for (int y = 0; y < nYears; y++)
            {
                for (int i = 0; i < nPlayers; i++)
                {
                    if (y > firstYear.ObservedValue[i])
                    {
                        parameters.skill[y][i]      = Gaussian.Sample(parameters.skill[y - 1][i], parameters.skillChangePrecision);
                        parameters.drawMargin[y][i] = Gaussian.Sample(parameters.drawMargin[y - 1][i], parameters.drawMarginChangePrecision);
                    }
                }
            }

            // Sample game outcomes
            int[][] whiteData, blackData, outcomeData;
            GenerateData(parameters, firstYear.ObservedValue, out whiteData, out blackData, out outcomeData);

            bool inferParameters = false;  // make this true to infer additional parameters

            if (!inferParameters)
            {
                // fix the true parameters
                drawMarginMean.ObservedValue            = parameters.drawMarginMean;
                drawMarginPrecision.ObservedValue       = parameters.drawMarginPrecision;
                performancePrecision.ObservedValue      = parameters.performancePrecision;
                skillChangePrecision.ObservedValue      = parameters.skillChangePrecision;
                drawMarginChangePrecision.ObservedValue = parameters.drawMarginChangePrecision;
            }

            // Learn the skills from the data
            int[] nGamesData  = Util.ArrayInit(nYears, y => outcomeData[y].Length);
            var   nGames      = Variable.Observed(nGamesData, year).Named("nGames");
            Range game        = new Range(nGames[year]).Named("game");
            var   whitePlayer = Variable.Observed(whiteData, year, game).Named("whitePlayer");
            var   blackPlayer = Variable.Observed(blackData, year, game).Named("blackPlayer");
            var   outcome     = Variable.Observed(outcomeData, year, game).Named("outcome");

            using (Variable.ForEach(year))
            {
                using (Variable.ForEach(game))
                {
                    var w = whitePlayer[year][game];
                    var b = blackPlayer[year][game];
                    Variable <double> white_performance = Variable.GaussianFromMeanAndPrecision(skill[year][w], performancePrecision).Named("white_performance");
                    Variable <double> black_performance = Variable.GaussianFromMeanAndPrecision(skill[year][b], performancePrecision).Named("black_performance");
                    Variable <double> white_drawMargin  = Variable.Copy(drawMargin[year][w]).Named("white_drawMargin");
                    Variable <double> black_drawMargin  = Variable.Copy(drawMargin[year][b]).Named("black_drawMargin");
                    Variable <double> white_delta       = (white_performance - black_performance + whiteAdvantage).Named("white_delta");
                    using (Variable.Case(outcome[year][game], 0))
                    { // black wins
                        Variable.ConstrainTrue(white_delta + white_drawMargin < 0);
                    }

                    using (Variable.Case(outcome[year][game], 1))
                    { // draw
                        Variable.ConstrainBetween(white_delta, -white_drawMargin, black_drawMargin);
                    }

                    using (Variable.Case(outcome[year][game], 2))
                    { // white wins
                        Variable.ConstrainTrue(white_delta - black_drawMargin > 0);
                    }
                }
            }

            year.AddAttribute(new Models.Attributes.Sequential());   // helps inference converge faster

            engine.NumberOfIterations = 10;
            var skillPost      = engine.Infer <Gaussian[][]>(skill);
            var drawMarginPost = engine.Infer <Gaussian[][]>(drawMargin);

            // compare estimates to the true values
            if (inferParameters)
            {
                Console.WriteLine("drawMargin mean = {0} (truth = {1})", engine.Infer <Gaussian>(drawMarginMean), parameters.drawMarginMean);
                Console.WriteLine("drawMargin precision = {0} (truth = {1})", engine.Infer <Gamma>(drawMarginPrecision).GetMean(), parameters.drawMarginPrecision);
                Console.WriteLine("performancePrecision = {0} (truth = {1})", engine.Infer <Gamma>(performancePrecision).GetMean(), parameters.performancePrecision);
                Console.WriteLine("skillChangePrecision = {0} (truth = {1})", engine.Infer <Gamma>(skillChangePrecision).GetMean(), parameters.skillChangePrecision);
                Console.WriteLine("drawMarginChangePrecision = {0} (truth = {1})", engine.Infer <Gamma>(drawMarginChangePrecision).GetMean(), parameters.drawMarginChangePrecision);
            }

            Console.WriteLine("white advantage = {0} (truth = {1})", engine.Infer <Gaussian>(whiteAdvantage), parameters.whiteAdvantage);
            int countPrinted = 0;

            for (int y = 0; y < nYears; y++)
            {
                for (int p = 0; p < nPlayers; p++)
                {
                    if (y >= firstYear.ObservedValue[p])
                    {
                        if (++countPrinted > 3)
                        {
                            break;
                        }

                        Console.WriteLine("skill[{0}][{1}] = {2} (truth = {3:g4})", y, p, skillPost[y][p], parameters.skill[y][p]);
                        Console.WriteLine("drawMargin[{0}][{1}] = {2} (truth = {3:g4})", y, p, drawMarginPost[y][p], parameters.drawMargin[y][p]);
                    }
                }
            }
        }
Example #17
0
        /// <summary>
        /// Constructs the Matchbox model with the specified settings.
        /// </summary>
        /// <param name="buildTrainingModel">Specifies whether the method should build a training or a prediction model.</param>
        /// <param name="breakTraitSymmetry">Specifies whether the constraints for breaking trait symmetry should be specified.</param>
        /// <param name="usePreAdjustedUserParameters">Specifies whether user parameters should be sampled from custom priors (without using features).</param>
        /// <param name="usePreAdjustedItemParameters">Specifies whether item parameters should be sampled from custom priors (without using features).</param>
        /// <returns>The variables to infer from the built model.</returns>
        public static IVariable[] BuildModel(
            bool buildTrainingModel,
            bool breakTraitSymmetry,
            bool usePreAdjustedUserParameters,
            bool usePreAdjustedItemParameters)
        {
            // Counts
            var userCount          = Variable.Observed(default(int)).Named("UserCount");
            var itemCount          = Variable.Observed(default(int)).Named("ItemCount");
            var userThresholdCount = Variable.Observed(default(int)).Named("UserThresholdCount");
            var observationCount   = Variable.Observed(default(int)).Named("ObservationCount");
            var traitCount         = Variable.Observed(default(int)).Named("TraitCount");

            // Ranges
            var user          = new Range(userCount).Named("user");
            var item          = new Range(itemCount).Named("item");
            var trait         = new Range(traitCount).Named("trait");
            var observation   = new Range(observationCount).Named("observation");
            var userThreshold = new Range(userThresholdCount).Named("userThreshold");
            var ratingValue   = new Range(userThresholdCount - 1).Named("ratingValue");

            if (buildTrainingModel)
            {
                // Use a sequential schedule
                user.AddAttribute(new Sequential());
                item.AddAttribute(new Sequential());
                observation.AddAttribute(new Sequential());
            }

            // Latent variables
            var userTraits     = Variable.Array(Variable.Array <double>(trait), user).Named("UserTraits");
            var itemTraits     = Variable.Array(Variable.Array <double>(trait), item).Named("ItemTraits");
            var userBias       = Variable.Array <double>(user).Named("UserBias");
            var itemBias       = Variable.Array <double>(item).Named("ItemBias");
            var userThresholds = Variable.Array(Variable.Array <double>(userThreshold), user).Named("UserThresholds");

            // User latent variable definitions
            var userFeatureCount        = Variable.Observed(default(int)).Named("UserFeatureCount");
            var userFeature             = new Range(userFeatureCount).Named("userFeature");
            var userTraitFeatureWeights = Variable.Array(Variable.Array <double>(userFeature), trait).Named("UserTraitFeatureWeights");
            var userBiasFeatureWeights  = Variable.Array <double>(userFeature).Named("UserBiasFeatureWeights");

            if (usePreAdjustedUserParameters)
            {
                var userTraitsPrior     = Variable.Observed(default(GaussianMatrix)).Named("UserTraitsPrior");
                var userBiasPrior       = Variable.Observed(default(GaussianArray)).Named("UserBiasPrior");
                var userThresholdsPrior = Variable.Observed(default(GaussianMatrix)).Named("UserThresholdsPrior");

                userTraits.SetTo(Variable <double[][]> .Random(userTraitsPrior));
                userBias.SetTo(Variable <double[]> .Random(userBiasPrior));
                userThresholds.SetTo(Variable <double[][]> .Random(userThresholdsPrior));
            }
            else
            {
                // Features
                var nonZeroUserFeatureCounts  = Variable.Observed(default(IList <int>), user).Named("NonZeroUserFeatureCounts");
                var nonZeroUserFeature        = new Range(nonZeroUserFeatureCounts[user]).Named("nonZeroUserFeature");
                var nonZeroUserFeatureIndices = Variable.Observed(default(IList <IList <int> >), user, nonZeroUserFeature).Named("NonZeroUserFeatureIndices");
                var nonZeroUserFeatureValues  = Variable.Observed(default(IList <IList <double> >), user, nonZeroUserFeature).Named("NonZeroUserFeatureValues");

                // Feature weights
                var userTraitFeatureWeightVariance = Variable.Observed(default(double)).Named("UserTraitFeatureWeightPriorVariance");
                var userBiasFeatureWeightVariance  = Variable.Observed(default(double)).Named("UserBiasFeatureWeightPriorVariance");
                userTraitFeatureWeights[trait][userFeature] =
                    Variable.GaussianFromMeanAndVariance(0.0, userTraitFeatureWeightVariance).ForEach(userFeature).ForEach(trait);
                userBiasFeatureWeights[userFeature] =
                    Variable.GaussianFromMeanAndVariance(0.0, userBiasFeatureWeightVariance).ForEach(userFeature);

                // Traits, biases and thresholds
                var userTraitVariance          = Variable.Observed(default(double)).Named("UserTraitVariance");
                var userBiasVariance           = Variable.Observed(default(double)).Named("UserBiasVariance");
                var userThresholdPriorMean     = Variable.Observed(default(double[]), userThreshold).Named("UserThresholdPriorMean");
                var userThresholdPriorVariance = Variable.Observed(default(double)).Named("UserThresholdPriorVariance");

                var middleUserThresholdIndex = Variable.Observed(default(int)).Named("MiddleUserThresholdIndex");
                using (var userThresholdIterationBlock = Variable.ForEach(userThreshold))
                {
                    var middleThreshold = userThresholdIterationBlock.Index == middleUserThresholdIndex;
                    var userThresholdPriorVarianceForThreshold = Variable.New <double>().Named("UserThresholdPriorVarianceForThreshold");
                    using (Variable.If(middleThreshold))
                    {
                        // Break symmetry between the user thresholds and the user bias
                        userThresholdPriorVarianceForThreshold.SetTo(0.0);
                    }
                    using (Variable.IfNot(middleThreshold))
                    {
                        userThresholdPriorVarianceForThreshold.SetTo(userThresholdPriorVariance);
                    }

                    userThresholds[user][userThresholdIterationBlock.Index] = Variable.GaussianFromMeanAndVariance(
                        userThresholdPriorMean[userThresholdIterationBlock.Index], userThresholdPriorVarianceForThreshold).ForEach(user);
                }

                using (Variable.ForEach(user))
                {
                    var nonZeroUserTraitFeatureWeights = Variable.Subarray(userTraitFeatureWeights[trait], nonZeroUserFeatureIndices[user]);
                    nonZeroUserTraitFeatureWeights.Name = "nonZeroUserTraitFeatureWeights";
                    var nonZeroUserTraitFeatureWeightProducts = Variable.Array(Variable.Array <double>(nonZeroUserFeature), trait).Named("nonZeroUserTraitFeatureWeightProducts");
                    nonZeroUserTraitFeatureWeightProducts[trait][nonZeroUserFeature] =
                        nonZeroUserTraitFeatureWeights[nonZeroUserFeature] * nonZeroUserFeatureValues[user][nonZeroUserFeature];
                    var userTraitMean = Variable.Sum(nonZeroUserTraitFeatureWeightProducts[trait]).Named("userTraitMean");
                    userTraits[user][trait] = Variable.GaussianFromMeanAndVariance(userTraitMean, userTraitVariance);

                    var nonZeroUserBiasFeatureWeights = Variable.Subarray(userBiasFeatureWeights, nonZeroUserFeatureIndices[user]);
                    nonZeroUserBiasFeatureWeights.Name = "nonZeroUserBiasFeatureWeights";
                    var nonZeroUserBiasFeatureWeightProducts = Variable.Array <double>(nonZeroUserFeature).Named("nonZeroUserBiasFeatureWeightProducts");
                    nonZeroUserBiasFeatureWeightProducts[nonZeroUserFeature] =
                        nonZeroUserBiasFeatureWeights[nonZeroUserFeature] * nonZeroUserFeatureValues[user][nonZeroUserFeature];
                    var userBiasMean = Variable.Sum(nonZeroUserBiasFeatureWeightProducts).Named("userBiasMean");
                    userBias[user] = Variable.GaussianFromMeanAndVariance(userBiasMean, userBiasVariance);
                }

                // Trait, bias and threshold messages
                var userTraitsMessage     = Variable.Observed(default(GaussianMatrix)).Named("UserTraitsMessage");
                var userBiasMessage       = Variable.Observed(default(GaussianArray)).Named("UserBiasMessage");
                var userThresholdsMessage = Variable.Observed(default(GaussianMatrix)).Named("UserThresholdsMessage");
                Variable.ConstrainEqualRandom <double[][], GaussianMatrix>(userTraits, userTraitsMessage);
                Variable.ConstrainEqualRandom <double[], GaussianArray>(userBias, userBiasMessage);
                Variable.ConstrainEqualRandom <double[][], GaussianMatrix>(userThresholds, userThresholdsMessage);
                userTraits.AddAttribute(QueryTypes.MarginalDividedByPrior);
                userBias.AddAttribute(QueryTypes.MarginalDividedByPrior);
                userThresholds.AddAttribute(QueryTypes.MarginalDividedByPrior);
                userTraits.AddAttribute(QueryTypes.Marginal);
                userBias.AddAttribute(QueryTypes.Marginal);
                userThresholds.AddAttribute(QueryTypes.Marginal);
                //// User thresholds do not have the initialize backward attribute because we want the
                //// schedule to send their backward message before the affinity backward message.

                if (buildTrainingModel)
                {
                    // Trait, bias and threshold initializers
                    var userTraitsInitializer     = Variable.Observed(default(GaussianMatrix)).Named("UserTraitsInitializer");
                    var userBiasInitializer       = Variable.Observed(default(GaussianArray)).Named("UserBiasInitializer");
                    var userThresholdsInitializer = Variable.Observed(default(GaussianMatrix)).Named("UserThresholdsInitializer");
                    userTraits.InitialiseTo(userTraitsInitializer);
                    userBias.InitialiseTo(userBiasInitializer);
                    userThresholds.InitialiseTo(userThresholdsInitializer);
                }
            }

            // Item latent variable definitions
            var itemFeatureCount        = Variable.Observed(default(int)).Named("ItemFeatureCount");
            var itemFeature             = new Range(itemFeatureCount).Named("itemFeature");
            var itemTraitFeatureWeights = Variable.Array(Variable.Array <double>(itemFeature), trait).Named("ItemTraitFeatureWeights");
            var itemBiasFeatureWeights  = Variable.Array <double>(itemFeature).Named("ItemBiasFeatureWeights");

            if (usePreAdjustedItemParameters)
            {
                // Define using custom priors
                var itemTraitsPrior = Variable.Observed(default(GaussianMatrix)).Named("ItemTraitsPrior");
                var itemBiasPrior   = Variable.Observed(default(GaussianArray)).Named("ItemBiasPrior");

                itemTraits.SetTo(Variable <double[][]> .Random(itemTraitsPrior));
                itemBias.SetTo(Variable <double[]> .Random(itemBiasPrior));
            }
            else
            {
                // Features
                var nonZeroItemFeatureCounts  = Variable.Observed(default(IList <int>), item).Named("NonZeroItemFeatureCounts");
                var nonZeroItemFeature        = new Range(nonZeroItemFeatureCounts[item]).Named("nonZeroItemFeature");
                var nonZeroItemFeatureIndices = Variable.Observed(default(IList <IList <int> >), item, nonZeroItemFeature).Named("NonZeroItemFeatureIndices");
                var nonZeroItemFeatureValues  = Variable.Observed(default(IList <IList <double> >), item, nonZeroItemFeature).Named("NonZeroItemFeatureValues");

                // Feature weights
                var itemTraitFeatureWeightVariance = Variable.Observed(default(double)).Named("ItemTraitFeatureWeightPriorVariance");
                var itemBiasFeatureWeightVariance  = Variable.Observed(default(double)).Named("ItemBiasFeatureWeightPriorVariance");
                itemTraitFeatureWeights[trait][itemFeature] =
                    Variable.GaussianFromMeanAndVariance(0.0, itemTraitFeatureWeightVariance).ForEach(itemFeature).ForEach(trait);
                itemBiasFeatureWeights[itemFeature] =
                    Variable.GaussianFromMeanAndVariance(0.0, itemBiasFeatureWeightVariance).ForEach(itemFeature);

                // Traits and biases
                var itemTraitVariance = Variable.Observed(default(double)).Named("ItemTraitVariance");
                var itemBiasVariance  = Variable.Observed(default(double)).Named("ItemBiasVariance");

                using (Variable.ForEach(item))
                {
                    var nonZeroItemTraitFeatureWeights = Variable.Subarray(itemTraitFeatureWeights[trait], nonZeroItemFeatureIndices[item]);
                    nonZeroItemTraitFeatureWeights.Name = "nonZeroItemTraitFeatureWeights";
                    var nonZeroItemTraitFeatureWeightProducts = Variable.Array(Variable.Array <double>(nonZeroItemFeature), trait);
                    nonZeroItemTraitFeatureWeightProducts[trait][nonZeroItemFeature] =
                        nonZeroItemTraitFeatureWeights[nonZeroItemFeature] * nonZeroItemFeatureValues[item][nonZeroItemFeature];
                    var itemTraitMean = Variable.Sum(nonZeroItemTraitFeatureWeightProducts[trait]).Named("itemTraitMean");
                    itemTraits[item][trait] = Variable.GaussianFromMeanAndVariance(itemTraitMean, itemTraitVariance);

                    var nonZeroItemBiasFeatureWeights = Variable.Subarray(itemBiasFeatureWeights, nonZeroItemFeatureIndices[item]);
                    nonZeroItemBiasFeatureWeights.Name = "nonZeroItemBiasFeatureWeights";
                    var nonZeroItemBiasFeatureWeightProducts = Variable.Array <double>(nonZeroItemFeature);
                    nonZeroItemBiasFeatureWeightProducts[nonZeroItemFeature] =
                        nonZeroItemBiasFeatureWeights[nonZeroItemFeature] * nonZeroItemFeatureValues[item][nonZeroItemFeature];
                    var itemBiasMean = Variable.Sum(nonZeroItemBiasFeatureWeightProducts).Named("itemBiasMean");
                    itemBias[item] = Variable.GaussianFromMeanAndVariance(itemBiasMean, itemBiasVariance);
                }

                // Trait and bias messages
                var itemTraitsMessage = Variable.Observed(default(GaussianMatrix)).Named("ItemTraitsMessage");
                var itemBiasMessage   = Variable.Observed(default(GaussianArray)).Named("ItemBiasMessage");
                Variable.ConstrainEqualRandom <double[][], GaussianMatrix>(itemTraits, itemTraitsMessage);
                Variable.ConstrainEqualRandom <double[], GaussianArray>(itemBias, itemBiasMessage);
                itemTraits.AddAttribute(QueryTypes.MarginalDividedByPrior);
                itemBias.AddAttribute(QueryTypes.MarginalDividedByPrior);
                itemTraits.AddAttribute(QueryTypes.Marginal);
                itemBias.AddAttribute(QueryTypes.Marginal);

                if (buildTrainingModel)
                {
                    // Trait and bias initializers
                    var itemTraitsInitializer = Variable.Observed(default(GaussianMatrix)).Named("ItemTraitsInitializer");
                    var itemBiasInitializer   = Variable.Observed(default(GaussianArray)).Named("ItemBiasInitializer");
                    itemTraits.InitialiseTo(itemTraitsInitializer);
                    itemBias.InitialiseTo(itemBiasInitializer);
                }
            }

            // Initialize first min(itemCount, traitCount) item traits to identity matrix to break symmetry
            if (breakTraitSymmetry)
            {
                // Note that this code affects evidence computation
                using (var traitIterationBlock1 = Variable.ForEach(trait))
                {
                    var traitCopy = trait.Clone();
                    using (var traitIterationBlock2 = Variable.ForEach(traitCopy))
                    {
                        using (Variable.If(traitIterationBlock1.Index < itemCount & traitIterationBlock2.Index < itemCount))
                        {
                            var diagonalElement = traitIterationBlock1.Index == traitIterationBlock2.Index;

                            using (Variable.If(diagonalElement))
                            {
                                Variable.ConstrainEqual(itemTraits[traitIterationBlock1.Index][traitIterationBlock2.Index], 1);
                            }

                            using (Variable.IfNot(diagonalElement))
                            {
                                Variable.ConstrainEqual(itemTraits[traitIterationBlock1.Index][traitIterationBlock2.Index], 0);
                            }
                        }
                    }
                }
            }

            // Observation data
            var userIds = Variable.Observed(default(IList <int>), observation).Named("UserIds");
            var itemIds = Variable.Observed(default(IList <int>), observation).Named("ItemIds");
            var ratings = Variable.IList <int>(observation).Named("Ratings");

            if (buildTrainingModel)
            {
                ratings.ObservedValue = default(IList <int>);
                ratings.SetValueRange(ratingValue);
            }
            else
            {
                ratings[observation] = Variable.DiscreteUniform(ratingValue).ForEach(observation);
            }

            // Noise variances
            var affinityNoiseVariance  = Variable.Observed(default(double)).Named("AffinityNoiseVariance");
            var thresholdNoiseVariance = Variable.Observed(default(double)).Named("UserThresholdNoiseVariance");

            // Connect everything to observations
            // Send VMP messages here for correct message reconstruction in batching
            using (Variable.ForEach(observation))
            {
                var userId = userIds[observation];
                var itemId = itemIds[observation];

                // Products of user and item traits (as if running VMP)
                // Make a copy so that we can attach attributes to the argument of Factor.Product_SHG09, not the original itemTraits array.
                var itemTrait     = Variable.Copy(itemTraits[itemId][trait]).Named("itemTrait");
                var userTrait     = Variable.Copy(userTraits[userId][trait]).Named("userTrait");
                var traitProducts = Variable.Array <double>(trait);
                traitProducts[trait] = Variable <double> .Factor(Factor.Product_SHG09, userTrait, itemTrait);

                // Affinity
                var userBiasObs = Variable.Copy(userBias[userId]).Named("userBiasObs");
                var itemBiasObs = Variable.Copy(itemBias[itemId]).Named("itemBiasObs");
                var affinity    =
                    Variable <double> .Factor(Factor.Product_SHG09, userBiasObs, 1.0)
                    + Variable <double> .Factor(Factor.Product_SHG09, itemBiasObs, 1.0)
                    + Variable.Sum(traitProducts);

                var noisyAffinity = Variable.GaussianFromMeanAndVariance(affinity, affinityNoiseVariance);

                // During prediction, we don't want to update the parameters. Variable.Cut ensures this.
                if (!buildTrainingModel)
                {
                    noisyAffinity = Variable.Cut(noisyAffinity);
                }

                // User thresholds
                var useSharedUserThresholds = Variable.Observed(default(bool)).Named("UseSharedUserThresholds");
                var userThresholdsObs       = Variable.Array <double>(userThreshold).Named("UserThresholdsObs");
                using (Variable.If(useSharedUserThresholds))
                {
                    userThresholdsObs.SetTo(Variable.Copy(userThresholds[0]));
                }
                using (Variable.IfNot(useSharedUserThresholds))
                {
                    userThresholdsObs.SetTo(Variable.Copy(userThresholds[userId]));
                }

                var noisyUserThresholds = Variable.Array <double>(userThreshold).Named("NoisyUserThresholds");
                var noisyUserThreshold  =
                    Variable.GaussianFromMeanAndVariance(
                        Variable <double> .Factor(Factor.Product_SHG09, userThresholdsObs[userThreshold], 1.0),
                        thresholdNoiseVariance);
                if (!buildTrainingModel)
                {
                    noisyUserThreshold = Variable.Cut(noisyUserThreshold);
                }
                noisyUserThresholds[userThreshold] = noisyUserThreshold;

                if (buildTrainingModel)
                {
                    // Every argument to Factor.Product_SHG09 should have an InitialiseBackward attribute, for the special first iteration.
                    // They should also be initialized to the current marginal distribution.
                    // This ensures that the factor receives the marginal during the special first iteration.
                    itemTrait.AddAttribute(new InitialiseBackward());
                    userTrait.AddAttribute(new InitialiseBackward());
                    userBiasObs.AddAttribute(new InitialiseBackward());
                    itemBiasObs.AddAttribute(new InitialiseBackward());
                    userThresholdsObs.AddAttribute(new InitialiseBackward());
                }

                // Rating
                var rating = ratings[observation];
                using (Variable.Switch(rating))
                {
                    // This hack allows indexing the thresholds with the ratingValue range instead of the userThreshold range
                    var currentRating = (rating + 0).Named("CurrentRating");
                    var nextRating    = (rating + 1).Named("NextRating");

                    Variable.ConstrainBetween(
                        noisyAffinity, noisyUserThresholds[currentRating], noisyUserThresholds[nextRating]);
                }
            }

            IVariable[] result;
            if (buildTrainingModel)
            {
                // Community training
                result = new IVariable[]
                {
                    userTraits, userBias, userThresholds, itemTraits, itemBias, userTraitFeatureWeights,
                    userBiasFeatureWeights, itemTraitFeatureWeights, itemBiasFeatureWeights
                };
            }
            else
            {
                // Prediction
                result = new IVariable[] { ratings };
            }

            return(result);
        }
Example #18
0
			public Model(ISharedVariableArray<VariableArray<double>, double[][]> w, Range c, int numChunks)
			{
				// Items.
				numItems = Variable.New<int>().Named("numItems");
				i = new Range(numItems).Named("i");
				i.AddAttribute(new Sequential());

				// Features per item.
				numFeaturesPerItem = Variable.Array<int>(i).Named("numFeaturesPerItem");
				fItem = new Range(numFeaturesPerItem[i]).Named("fItem");

				// The model identifier for the shared variables.
				model = new MicrosoftResearch.Infer.Models.Model(numChunks).Named("model");
				// The weight vector for each submodel.
				wModel = w.GetCopyFor(model).Named("wModel");

				noisePrecision = Variable.New<double>().Named("noisePrecision");

				// Jagged array of feature values - each item is an array of data values 
				// whose indices are given by the corresponding indices[i].
				values = Variable.Array(Variable.Array<double>(fItem), i).Named("values");

				// Jagged array of indices for the items.
				indices = Variable.Array(Variable.Array<int>(fItem), i).Named("indices");

				// Labels.
				y = Variable.Array<int>(i).Named("y");

				// For all items...
				using (Variable.ForEach(i))
				{
					// ...compute the score of this item across all classes...
					score = BPMUtils.ComputeClassScores(wModel, values[i], indices[i], fItem, noisePrecision);
					y[i] = Variable.DiscreteUniform(c);

					// ... and constrain the output.
					BPMUtils.ConstrainMaximum(y[i], score);
				}

				// Inference engine settings (EP).
				engine.Compiler.UseSerialSchedules = true;
				engine.ShowProgress = false;
			}