locked
Help to solve the problem of my model similar to trueskill model. (Migrated from community.research.microsoft.com) RRS feed

  • Question

  • sungchul kim posted on 12-16-2010 2:43 AM

    Hi all,

    I tried to implement a model to estimate weight vector to make a score by the inner product.

    There is no error, but all marginals are increasing to NaN.

    I use a latent variable RelUnit for the inner product since infer.net does not provide the inner product of two vectors that are random variables.

    Can you find a problem in my code?

    using System;

    using System.IO;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

    using MicrosoftResearch.Infer;

    using MicrosoftResearch.Infer.Maths;

    using MicrosoftResearch.Infer.Models;

    using MicrosoftResearch.Infer.Distributions;

     

    namespace estAttractiveness

    {

        class relModel

        {

            public Gaussian[] wrMeanPrior;

            public Gamma[] wrVarPrior;

            public SharedVariable<double>[] wrMean;

            public SharedVariable<double>[] wrVar;

            //public SharedVariable<double>[] wtMean;

            //public SharedVariable<double>[] wtVar;

     

            Model model;

            Variable<int> NumAds = Variable.New<int>();

            Variable<int> NumAdsMinus1 = Variable.New<int>();

            Variable<int> DimR = Variable.New<int>();

     

            VariableArray<VariableArray<double>, double[][]> Xr;

            VariableArray<double> wr;

     

            VariableArray<double> Rel;

            VariableArray<VariableArray<double>, double[][]> RelUnit;

     

            VariableArray<double> Scr;

            VariableArray<int> LeftIndices;

            VariableArray<int> RightIndices;

            InferenceEngine ie = new InferenceEngine();

     

            public relModel(int dimr, double beta, int sizeOfChunk)

            {

                ie.ShowFactorGraph = true;

     

                model = new Model(sizeOfChunk);

     

                Range n = new Range(NumAds);

                Range n1 = new Range(NumAdsMinus1);

                Range nr = new Range(dimr);

     

                // Declare Variables

                Xr = Variable.Array(Variable.Array<double>(nr), n).Named("Xr");

                wr = Variable.Array<double>(nr).Named("wr");

                wrMeanPrior = new Gaussian[dimr];

                wrVarPrior = new Gamma[dimr];

                wrMean = new SharedVariable<double>[dimr];

                wrVar = new SharedVariable<double>[dimr];

                Rel = Variable.Array<double>(n).Named("Relevance");

                RelUnit = Variable.Array(Variable.Array<double>(nr), n).Named("Relevance Entry");

                Scr = Variable.Array<double>(n).Named("Scr");

                LeftIndices = Variable.Array<int>(n1).Named("leftIndices");

                RightIndices = Variable.Array<int>(n1).Named("rightIndices");

     

                // Set Prior            

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

                {

                    wrMeanPrior[i] = Gaussian.FromMeanAndVariance(0.0, 1.0);

                    wrVarPrior[i] = Gamma.FromMeanAndVariance(2.0, 0.0);

                }

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

                {

                    wrMean[i] = SharedVariable<double>.Random(wrMeanPrior[i]).Named("wrMean" + i);                

                    wrVar[i] = SharedVariable<double>.Random(wrVarPrior[i]).Named("wrVar" + i);                

                }

     

                // Build Model

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

                {               

                    wr[i] = Variable<double>.GaussianFromMeanAndPrecision(wrMean[i].GetCopyFor(model), wrVar[i].GetCopyFor(model)).Named("Wr" + i);

                }

     

                RelUnit[n][nr] = wr[nr] * Xr[n][nr];

                Rel[n] = Variable.Sum(RelUnit[n]);

                Scr[n] = Variable.GaussianFromMeanAndPrecision(Rel[n], beta);

                var left = Variable.Subarray(Scr, LeftIndices).Named("left");

                var right = Variable.Subarray(Scr, RightIndices).Named("right");

                Variable.ConstrainPositive(left[n1] - right[n1]);

            }

     

            public void Infer(StreamWriter sw, double[][] obXr, double[] clicks, int idxModel, out Gaussian[] wrMeanMarginal, out Gamma[] wrVarMarginal)

            {            

                int rdim = obXr[0].Length;

                wrMeanMarginal = new Gaussian[rdim];

                wrVarMarginal = new Gamma[rdim];

     

                Xr.ObservedValue = obXr;            

                Scr.ObservedValue = clicks;

                dataEngine dg = new dataEngine();

     

                int c=0;

                foreach(double[] x in obXr)

                {

                    sw.Write("x: ");

                    foreach (double xi in x)

                        sw.Write(xi + ", ");

                    sw.Write(clicks[c++]);

                    sw.WriteLine();

                }

                sw.WriteLine();

     

                int n1 = obXr.Length - 1;            

                int[] leftIndices = new int[n1];

                int[] rightIndices = new int[n1];

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

                {

                    leftIndices[i] = i;

                    rightIndices[i] = i + 1;

                }

                LeftIndices.ObservedValue = leftIndices;

                RightIndices.ObservedValue = rightIndices;

                NumAdsMinus1.ObservedValue = n1;

     

                NumAds.ObservedValue = obXr.Length;

                model.InferShared(ie, idxModel);

     

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

                {

                    wrMeanMarginal[i] = wrMean[i].Marginal<Gaussian>();

                    wrVarMarginal[i] = wrVar[i].Marginal<Gamma>();

                }

     

                sw.Write("WrMean = ");

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

                    sw.Write(wrMeanMarginal[i] + ", ");

                sw.WriteLine();

                sw.Write("WrVar = ");

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

                    sw.Write(wrVarMarginal[i] + ", ");

                sw.WriteLine();

            }

        }

    }

    Friday, June 3, 2011 6:09 PM

Answers

  • John Guiver replied on 12-16-2010 11:04 AM

    Hi SungChul

    If I understand you problem correctly, something like the following should work - let me know if you can't get this to work.

    var wrMean2Prior = Variable.Array<Gaussian>(nr);
    var wrVar2Prior = Variable.Array<Gamma>(nr);
    wrMean2Prior.ObservedValue = Mean;
    wrVar2Prior.ObservedValue = Var;
    wrMean2[nr] =
    Variable<double>.Random<Gaussian>(wrMean2Prior[nr]);
    wrVar2[nr] =
    Variable<double>.Random<Gamma>(wrVar2Prior[nr]);

    John

    Friday, June 3, 2011 6:10 PM

All replies

  • John Guiver replied on 12-16-2010 4:47 AM

    Hi SungChul

    It would be helpful if you could provide some anonymised data to test your program (you can send via the support alias) + the test code. In the meantime I can make some general comments.

    First of all note that divergence can occur in some models, and this can be affected by the inference schedule. With the shared variable mechanism, you have the opportunity to affect the schedule. Consider the following:

    (1) I'm not sure this point is relevant in your case, as you seem to have only one datum (one set of ads), but it may be relevant as you progress your model: The smaller the chunk size, the better the chance of convergence. Caution: Your relModel method has an argument 'sizeOfChunk' - but your code uses it as if it is the number of chunks (the 'Model' constructor needs the number of chunks). To maximise the chance of convergence, start off with the number of chunks equal to the number of data.

    (2) The Beta noise parameter will probably have a significant effect - try making that looser (decrease Beta)

    (3) You have a dubious mix of .NET indexing and range indexing for wr. I suggest that you create wrMean (and wrVar - which should be wrPrec) as shared variable arrays:

    wrMean = SharedVariable<double>.Random(nr, CreateGaussianArray(dimr, Gaussian.FromMeanAndVariance(0,1)));
    wrPrec =
    SharedVariable<double>.Random(nr, CreateGammaArray(dimr, Gamma.PointMass(2.0)));

    where

    using GaussianArray=DistributionStructArray<Gaussian, double>;
    using GammaArray=DistributionStructArray<Gamma, double>;

    and

    private static GaussianArray CreateGaussianArray(int length, Gaussian g)
    {
       
    Gaussian[] result = new Gaussian[length];
       
    for (int i=0; i < length; i++)
            result[i] = (
    Gaussian)g.Clone();
       
    return (GaussianArray)Distribution<double>.Array<Gaussian>(result);
    }

    and similarly for Gamma.

     

    Then

    wr[nr] = Variable.GaussianFromMeanAndPrecision(wrMean.GetCopyFor(model)[nr], wrPrec.GetCopyFor(model)[nr]);

    John

    Friday, June 3, 2011 6:10 PM
  • sungchul kim replied on 12-16-2010 10:02 AM

    Thanks a lot. Even I don't know how to say to express how much I appreciate to your help.

    I fixed the first problem by using a small beta and I also modified my code as you commented. Specifically, the 3rd comment is really nice.

    However I got another problem. After performing inference of wrMean and wrPrec having the type of Gaussian[] and Gamma[] repectively, I cannot reuse them for prediction. I tried to declare variable array wrMean2 and wrVar2 having estimated distribution of wrMean and wrVar similar to the above way, it doesn't work. 

    How can I declare new variable array initialized by using wrMean and wrPrec as prior and can also use nr as range in the same way to the previous model?

    I make a constructor for prediction model as follows:

    public relModel(Gaussian[] Mean, Gamma[] Var, int dimr, double beta, int numChunk)

            {

                model = new Model(numChunk);

     

                Range n = new Range(NumAds);            

                Range nr = new Range(dimr);

     

                // Declare Variables

                Xr = Variable.Array(Variable.Array<double>(nr), n).Named("Xr");

                wr = Variable.Array<double>(nr).Named("wr");

                Rel = Variable.Array<double>(n).Named("Relevance");

                RelUnit = Variable.Array(Variable.Array<double>(nr), n).Named("Relevance Entry");

                ScrR = Variable.Array<double>(n).Named("ScrR");

                Scr = Variable.Array<double>(n).Named("Scr");

                VariableArray<double> wrMean2 = Variable.Array<double>(nr);

                VariableArray<double> wrVar2 = Variable.Array<double>(nr);

     

                // Build Model            

                wr[nr] = Variable<double>.GaussianFromMeanAndPrecision(wrMean2[nr], wrVar2[nr]).Named("Wr");

                RelUnit[n][nr] = wr[nr] * Xr[n][nr];

                Rel[n] = Variable.Sum(RelUnit[n]);

                ScrR[n] = Variable.GaussianFromMeanAndPrecision(Rel[n], beta);

                Scr[n] = Variable.GaussianFromMeanAndPrecision(ScrR[n], beta);

            }

    But, I cannot connect wrMean2 and wrVar2 to wrMean and wrVar that are priors.

    Friday, June 3, 2011 6:10 PM
  • John Guiver replied on 12-16-2010 11:04 AM

    Hi SungChul

    If I understand you problem correctly, something like the following should work - let me know if you can't get this to work.

    var wrMean2Prior = Variable.Array<Gaussian>(nr);
    var wrVar2Prior = Variable.Array<Gamma>(nr);
    wrMean2Prior.ObservedValue = Mean;
    wrVar2Prior.ObservedValue = Var;
    wrMean2[nr] =
    Variable<double>.Random<Gaussian>(wrMean2Prior[nr]);
    wrVar2[nr] =
    Variable<double>.Random<Gamma>(wrVar2Prior[nr]);

    John

    Friday, June 3, 2011 6:10 PM