locked
Improper distribution during inference... Error Recommender system example RRS feed

  • Question

  • Hi everyone

    I'm tring to test the RecommenderSystem example in the movielens dataset. I've changed a little bit the code in order to import the data from a file. The new implementation is the following:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.IO;
    using MicrosoftResearch.Infer;
    using MicrosoftResearch.Infer.Models;
    using MicrosoftResearch.Infer.Utils;
    using MicrosoftResearch.Infer.Distributions;
    using MicrosoftResearch.Infer.Maths;
    using MicrosoftResearch.Infer.Factors;



    namespace ConsoleApplication4
    {
        public class RS
        {
            public void Run()
            {
                // This example requires EP
                InferenceEngine engine = new InferenceEngine();
                if (!(engine.Algorithm is ExpectationPropagation))
                {
                    Console.WriteLine("This example only runs with Expectation Propagation");
                    return;
                }



                //*********************** File Reading Start ***********************

                int[] tmpUser;
                int[] tmpItem;
                int[] tmpRating;
                string fileName = @"..\..\files\train.txt";
                
                if (!File.Exists(fileName))
                {

                    fileName = @"..\Samples\ConsoleApplication4\ConsoleApplication4\data\train.txt";

                }
                LoadData(fileName, out tmpUser, out tmpItem, out tmpRating);

                //*********************** File Reading End ************************

                // Define counts
                int numUsers = tmpUser.Max()+1;
                int numItems = tmpItem.Max()+1;
                int numTraits = 20;
                Variable<int> numObservations = Variable.Observed(tmpItem.Length).Named("numObservations");
                int numLevels = 5;

                // Define ranges
                Range user = new Range(numUsers).Named("user");
                Range item = new Range(numItems).Named("item");
                Range trait = new Range(numTraits).Named("trait");
                Range observation = new Range(numObservations).Named("observation");
                Range level = new Range(numLevels).Named("level");

                // Define 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>(level), user).Named("userThresholds");

                // Define priors
                var userTraitsPrior = Variable.Array(Variable.Array<Gaussian>(trait), user).Named("userTraitsPrior");
                var itemTraitsPrior = Variable.Array(Variable.Array<Gaussian>(trait), item).Named("itemTraitsPrior");
                var userBiasPrior = Variable.Array<Gaussian>(user).Named("userBiasPrior");
                var itemBiasPrior = Variable.Array<Gaussian>(item).Named("itemBiasPrior");
                var userThresholdsPrior = Variable.Array(Variable.Array<Gaussian>(level), user).Named("userThresholdsPrior");

                // Define latent variables statistically
                userTraits[user][trait] = Variable<double>.Random(userTraitsPrior[user][trait]);
                itemTraits[item][trait] = Variable<double>.Random(itemTraitsPrior[item][trait]);
                userBias[user] = Variable<double>.Random(userBiasPrior[user]);
                itemBias[item] = Variable<double>.Random(itemBiasPrior[item]);
                userThresholds[user][level] = Variable<double>.Random(userThresholdsPrior[user][level]);

                // Initialise priors
                Gaussian traitPrior = Gaussian.FromMeanAndVariance(0.0, 1.0);
                Gaussian biasPrior = Gaussian.FromMeanAndVariance(0.0, 1.0);

                userTraitsPrior.ObservedValue = Util.ArrayInit(numUsers, u => Util.ArrayInit(numTraits, t => traitPrior));
                itemTraitsPrior.ObservedValue = Util.ArrayInit(numItems, i => Util.ArrayInit(numTraits, t => traitPrior));
                userBiasPrior.ObservedValue = Util.ArrayInit(numUsers, u => biasPrior);
                itemBiasPrior.ObservedValue = Util.ArrayInit(numItems, i => biasPrior);
                userThresholdsPrior.ObservedValue = Util.ArrayInit(numUsers, u =>
                        Util.ArrayInit(numLevels, l => Gaussian.FromMeanAndVariance(l - numLevels / 2.0 + 0.5, 1.0)));

                // Break symmetry and remove ambiguity in the traits
                for (int i = 0; i < numTraits; i++)
                {
                    // Assume that numTraits < numItems
                    for (int j = 0; j < numTraits; j++)
                    {
                        itemTraitsPrior.ObservedValue[i][j] = Gaussian.PointMass(0);
                    }
                    itemTraitsPrior.ObservedValue[i][i] = Gaussian.PointMass(1);
                }

                // Declare training data variables

                var userData = Variable.Array<int>(observation).Named("userData");
                var itemData = Variable.Array<int>(observation).Named("itemData");
                var ratingData = Variable.Array(Variable.Array<bool>(level), observation).Named("ratingData");

                // Set model noises explicitly
                Variable<double> affinityNoiseVariance = Variable.Observed(0.1).Named("affinityNoiseVariance");
                Variable<double> thresholdsNoiseVariance = Variable.Observed(0.1).Named("thresholdsNoiseVariance");

                // Model
                using (Variable.ForEach(observation))
                {
                    VariableArray<double> products = Variable.Array<double>(trait).Named("products");
                    products[trait] = userTraits[userData[observation]][trait] * itemTraits[itemData[observation]][trait];

                    Variable<double> bias = (userBias[userData[observation]] + itemBias[itemData[observation]]).Named("bias");
                    Variable<double> affinity = (bias + Variable.Sum(products).Named("productSum")).Named("affinity");
                    Variable<double> noisyAffinity = Variable.GaussianFromMeanAndVariance(affinity, affinityNoiseVariance).Named("noisyAffinity");

                    VariableArray<double> noisyThresholds = Variable.Array<double>(level).Named("noisyThresholds");
                    noisyThresholds[level] = Variable.GaussianFromMeanAndVariance(userThresholds[userData[observation]][level], thresholdsNoiseVariance);
                    ratingData[observation][level] = noisyAffinity > noisyThresholds[level];
                }

                // Observe training data
                GenerateData(numUsers, numItems, numTraits, numObservations.ObservedValue, numLevels,
                                         userData, itemData, ratingData,
                                         userTraitsPrior.ObservedValue, itemTraitsPrior.ObservedValue,
                                         userBiasPrior.ObservedValue, itemBiasPrior.ObservedValue, userThresholdsPrior.ObservedValue,
                                         affinityNoiseVariance.ObservedValue, thresholdsNoiseVariance.ObservedValue,tmpUser,tmpItem,tmpRating);


                // Allow EP to process the product factor as if running VMP
                // as in Stern, Herbrich, Graepel paper.
                engine.Compiler.GivePriorityTo(typeof(GaussianProductOp_SHG09));
                engine.Compiler.ShowWarnings = true;

                // Run inference
                var userTraitsPosterior = engine.Infer<Gaussian[][]>(userTraits);
                var itemTraitsPosterior = engine.Infer<Gaussian[][]>(itemTraits);
                var userBiasPosterior = engine.Infer<Gaussian[]>(userBias);
                var itemBiasPosterior = engine.Infer<Gaussian[]>(itemBias);
                var userThresholdsPosterior = engine.Infer<Gaussian[][]>(userThresholds);

                // Feed in the inferred posteriors as the new priors
                userTraitsPrior.ObservedValue = userTraitsPosterior;
                itemTraitsPrior.ObservedValue = itemTraitsPosterior;
                userBiasPrior.ObservedValue = userBiasPosterior;
                itemBiasPrior.ObservedValue = itemBiasPosterior;
                userThresholdsPrior.ObservedValue = userThresholdsPosterior;

                // Make a prediction
                numObservations.ObservedValue = 1;
                userData.ObservedValue = new int[] { 1 };
                itemData.ObservedValue = new int[] { 6 };
                ratingData.ClearObservedValue();

                Bernoulli[] predictedRating = engine.Infer<Bernoulli[][]>(ratingData)[0];
                Console.WriteLine("Predicted rating:");
                foreach (var rating in predictedRating) Console.WriteLine(rating);
            }

            // Generates data from the model

            void GenerateData(int numUsers, int numItems, int numTraits, int numObservations, int numLevels,
                                                VariableArray<int> userData, VariableArray<int> itemData,
                                                VariableArray<VariableArray<bool>, bool[][]> ratingData,
                                                Gaussian[][] userTraitsPrior, Gaussian[][] itemTraitsPrior,
                                                Gaussian[] userBiasPrior, Gaussian[] itemBiasPrior, Gaussian[][] userThresholdsPrior,
                                                double affinityNoiseVariance, double thresholdsNoiseVariance,
                                                int[] users, int[] items, int[] ratings)
            {

                //int[] generatedUserData = new int[numObservations];
                //int[] generatedItemData = new int[numObservations];

                int[] generatedUserData = users;
                int[] generatedItemData = items;
                bool[][] generatedRatingData = new bool[numObservations][];

                // Sample model parameters from the priors
                Rand.Restart(12347);
                double[][] userTraits = Util.ArrayInit(numUsers, u => Util.ArrayInit(numTraits, t => userTraitsPrior[u][t].Sample()));
                double[][] itemTraits = Util.ArrayInit(numItems, i => Util.ArrayInit(numTraits, t => itemTraitsPrior[i][t].Sample()));
                double[] userBias = Util.ArrayInit(numUsers, u => userBiasPrior[u].Sample());
                double[] itemBias = Util.ArrayInit(numItems, i => itemBiasPrior[i].Sample());
                double[][] userThresholds = Util.ArrayInit(numUsers, u => Util.ArrayInit(numLevels, l => userThresholdsPrior[u][l].Sample()));

                // Repeat the model with fixed parameters
                HashSet<int> visited = new HashSet<int>();
                for (int observation = 0; observation < numObservations; observation++)
                {
                    //int user = Rand.Int(numUsers);
                    //int item = Rand.Int(numItems);

                    int user = users[observation];
                    int item = items[observation];

                    int userItemPairID = user * numItems + item; // pair encoding

                    /*
                    if (visited.Contains(userItemPairID)) // duplicate generated
                    {
                        observation--; // reject pair
                        continue;
                    }
                    */
                    visited.Add(userItemPairID);

                    double[] products = Util.ArrayInit(numTraits, t => userTraits[user][t] * itemTraits[item][t]);
                    double bias = userBias[user] + itemBias[item];
                    double affinity = bias + products.Sum();
                    double noisyAffinity = new Gaussian(affinity, affinityNoiseVariance).Sample();
                    double[] noisyThresholds = Util.ArrayInit(numLevels, l => new Gaussian(userThresholds[user][l], thresholdsNoiseVariance).Sample());

                    //generatedUserData[observation] = user;
                    //generatedItemData[observation] = item;
                    generatedRatingData[observation] = Util.ArrayInit(numLevels, l => noisyAffinity > noisyThresholds[l]);
                }

                userData.ObservedValue = generatedUserData;
                itemData.ObservedValue = generatedItemData;
                ratingData.ObservedValue = generatedRatingData;
            }

            static private void LoadData(
                string ifn,         // The file name
                out int[] tmpUser,   // users
                out int[] tmpItem,   // movies
                out int[] tmpRating)    // ratings
            {
                // File is assumed to have tab or comma separated label, clicks, exams
                tmpUser = null;
                tmpItem = null;
                tmpRating = null;
                int totalDocs = 0;
                string myStr;
                StreamReader mySR;
                char[] sep = { '\t', ',', ' ' };

                for (int pass = 0; pass < 2; pass++)
                {
                    if (1 == pass)
                    {
                        tmpUser = new int[totalDocs];
                        tmpItem = new int[totalDocs];
                        tmpRating = new int[totalDocs];
                        totalDocs = 0;
                    }

                    mySR = new StreamReader(ifn);
                    //mySR.ReadLine(); // Skip over header line
                    while ((myStr = mySR.ReadLine()) != null)
                    {

                        if (1 == pass)
                        {
                            string[] mySplitStr = myStr.Split(sep);
                                int rat = int.Parse(mySplitStr[2]);
                                int urs = int.Parse(mySplitStr[0]);
                                int itm = int.Parse(mySplitStr[1]);
                                tmpUser[totalDocs] = urs-1;
                                tmpItem[totalDocs] = itm-1;
                                tmpRating[totalDocs] = rat;
                        }
                        totalDocs++;
                    }
                    mySR.Close();
                }
            }
        }
    }

    To test the system I've download the movielens dataset and I have used the file u1.base as training set. (the test file is not used yet). However, using this file with 70000 lines i got the following error:

    "Improper distribution during inference (Gaussian(m/v=-222,4, 1/v=0)).  Cannot perform inference on this model."

    Since using the default code the system works(changing the intial variables to

                int numUsers = 943;
                int numItems = 1682;
                int numTraits = 20;
                Variable<int> numObservations = Variable.Observed(70000).Named("numObservations");
                int numLevels = 5;

    ) I've tried to remove some of the lines in the train.txt file and i figure out that some lines make the system crash. Infact, removing all the lines where the film ID (second column) is bigger than 1056 allow the system to finish.

    Does anyone have idea about the meaning of the error?

    Thank you in advance

    Marco

    Tuesday, May 14, 2013 12:02 PM

All replies

  • This is the version of the GenerateData with a fixed bug, but the problem is still present. 

    I don't think that the problem is due to the index bigger than 1056, and i really don't know which kind of problem is...

            void GenerateData(int numUsers, int numItems, int numTraits, int numObservations, int numLevels,
                                                VariableArray<int> userData, VariableArray<int> itemData,
                                                VariableArray<VariableArray<bool>, bool[][]> ratingData,
                                                Gaussian[][] userTraitsPrior, Gaussian[][] itemTraitsPrior,
                                                Gaussian[] userBiasPrior, Gaussian[] itemBiasPrior, Gaussian[][] userThresholdsPrior,
                                                double affinityNoiseVariance, double thresholdsNoiseVariance,
                                                int[] users, int[] items, int[] ratings)
            {
    
    
                int[] generatedUserData = users;
                int[] generatedItemData = items;
                bool[][] generatedRatingData = new bool[numObservations][];
    
              
    
                // Sample model parameters from the priors
                Rand.Restart(12347);
                double[][] userTraits = Util.ArrayInit(numUsers, u => Util.ArrayInit(numTraits, t => userTraitsPrior[u][t].Sample()));
                double[][] itemTraits = Util.ArrayInit(numItems, i => Util.ArrayInit(numTraits, t => itemTraitsPrior[i][t].Sample()));
                double[] userBias = Util.ArrayInit(numUsers, u => userBiasPrior[u].Sample());
                double[] itemBias = Util.ArrayInit(numItems, i => itemBiasPrior[i].Sample());
                double[][] userThresholds = Util.ArrayInit(numUsers, u => Util.ArrayInit(numLevels, l => userThresholdsPrior[u][l].Sample()));
    
    
                // Repeat the model with fixed parameters
                for (int observation = 0; observation < numObservations; observation++)
                {
    
                    int user = users[observation];
                    int item = items[observation];
    
                    switch (ratings[observation])
                    {
    
                        case 1:
                            generatedRatingData[observation] = new bool[] { false, false, false, false };
                            break;
                        case 2:
                            generatedRatingData[observation] = new bool[] { true, false, false, false };
                            break;
                        case 3:
                            generatedRatingData[observation] = new bool[] { true, true, false, false };
                            break;
                        case 4:
                            generatedRatingData[observation] = new bool[] { true, true, true, false };
                            break;
                        case 5:
                            generatedRatingData[observation] = new bool[] { true, true, true, true };
                            break;
    
    
                    }
                }
    
                userData.ObservedValue = generatedUserData;
                itemData.ObservedValue = generatedItemData;
                ratingData.ObservedValue = generatedRatingData;
            }
    I can also provide the file that the system takes as input.

    Any idea?



    • Edited by MarcoASDF Tuesday, May 14, 2013 3:02 PM
    Tuesday, May 14, 2013 3:00 PM
  • Should numLevels be 4 instead of 5?
    Tuesday, May 14, 2013 10:44 PM
  • Yes, this is another bug i've fixed, but however the system doesn't work...

    The strage thing is that if the dataset is randomly computed(as in the original code), even with the dimension of the real dataset, the system works. But if I set the data from the original set, the system crash and gives the error above... 

    Wednesday, May 15, 2013 6:11 AM
  • Running several tests i've noticed the following things:

    1- The numTraits parameter is a key parameter for the error. Infact with a number of traits smaller or equal than 17, the system finish without error; when however this parameters is set to a value bigger than 17 the system crash with the error writed above.

    2- Reducing the number of data or removing some specific entries in the dataset, make the system works.

    I hope these information could be halpful to understand the problem(not for me).

    May I also ask for an explenation of this error??

    Thank you



    • Edited by MarcoASDF Wednesday, May 15, 2013 8:44 AM
    Wednesday, May 15, 2013 7:23 AM
  • Try adding observation.AddAttribute(new Sequential()); in your model. This is briefly explained in the Difficulty vs ability example.
    Wednesday, May 22, 2013 6:25 PM
  • Thank you fro your reply. Actually I have changed a little the code and, because i don't need to run so much iterations, i don't have this problem anymore. However i get some convergence problem as explained in the post titled 

    Strange Results Recommender System Example

    . Any advice??

    Thank you very much in advance

    Marco

    Tuesday, May 28, 2013 9:50 AM