//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(); }
/// <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; }
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; }
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)); }
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>(); } }
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; }
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")); } }
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()); } } } } }
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")); } }
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); }
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; }
/// <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()); }
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]); } } } }
/// <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); }
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; }