locked
TrueSkill implementation equivalent to Microsft official calculators RRS feed

  • Question

  • Could Infer.NET be used to implement the TrueSkill algorithm with the same parameters as used in official TrueSkill calculators?

    Basically I'm trying to implement skill update for a multiplayer game (e.g. one player per team). I've started from simple case of two players:

    class Program
    {
        static void Main(string[] args)
        {
    
            const double beta = 25.0 / 6;
            var s1 = Variable.GaussianFromMeanAndVariance(25, 25.0/3);
            var s2 = Variable.GaussianFromMeanAndVariance(25, 25.0/3);
            var p1 = Variable.GaussianFromMeanAndVariance(s1, beta);
            var p2 = Variable.GaussianFromMeanAndVariance(s2, beta);
            Variable.ConstrainPositive(p1 - p2);
    
            var engine = new InferenceEngine(new ExpectationPropagation());
            engine.ShowFactorGraph = true;
            engine.SaveFactorGraphToFolder = Environment.CurrentDirectory;
            var r1 = engine.Infer(s1);
            var r2 = engine.Infer(s2);
            Console.WriteLine("p1: {0}", r1);
            Console.WriteLine("p2: {0}", r2);
            Console.ReadLine();
        }
    }
    I recieve different skill updates using official calculators (with draw probability of zero). How do I modify my factor graph to get the same results?


    Monday, March 23, 2015 5:30 PM

All replies

  • Here's the model. Remember to set not only the game count, player count, winners and losers, but also to tune the PerformanceNoiseVariance hyper-parameter.

    /// <summary>
    /// The prior mean of the player skill.
    /// </summary>
    private const double SkillMean = 25.0;
    
    /// <summary>
    /// The prior standard deviation of the player skill.
    /// </summary>
    private const double SkillStandardDeviation = SkillMean / 3.0;
    
    /// <summary>
    /// Gets or sets the variance of the performance noise for each game.
    /// </summary>
    private Variable<double> PerformanceNoiseVariance { get; set; }
    
    /// <summary>
    /// Gets or sets the number of games played.
    /// </summary>
    private Variable<int> GameCount { get; set; }
    
    /// <summary>
    /// Gets or sets the number of unique players.
    /// </summary>
    private Variable<int> PlayerCount { get; set; }
    
    /// <summary>
    /// Gets or sets the winner in each game.
    /// </summary>
    private VariableArray<int> Winners { get; set; }
    
    /// <summary>
    /// Gets or sets the loser in each game.
    /// </summary>
    private VariableArray<int> Losers { get; set; }
    
    /// <summary>
    /// Gets or sets the skills of the players.
    /// </summary>
    private VariableArray<double> PlayerSkills { get; set; }
    
    /// <summary>
    /// Gets or sets the uncertain player skills obtained after training.
    /// </summary>
    private Gaussian[] InferredPlayerSkills { get; set; }
    
    /// <summary>
    /// Creates the Infer.NET model.
    /// </summary>
    /// <returns>The variables to infer.</returns>
    private IVariable[] CreateModel()
    {
    	// Define the number of games
    	this.GameCount = Variable.Observed(default(int)).Named("GameCount");
    	var game = new Range(this.GameCount).Named("game");
    	game.AddAttribute(new Sequential());
    
    	// Define the number of players
    	this.PlayerCount = Variable.Observed(default(int)).Named("PlayerCount");
    	var player = new Range(this.PlayerCount).Named("player");
    
    	// Define the prior skill of each player
    	this.PlayerSkills = Variable.Array<double>(player).Named("PlayerSkills");
    	using (Variable.ForEach(player))
    	{
    		this.PlayerSkills[player] = Variable.GaussianFromMeanAndVariance(
    			SkillMean, SkillStandardDeviation * SkillStandardDeviation);
    	}
    
    	// Define the observed game outcomes
    	this.Winners = Variable.Observed(default(int[]), game).Named("Winners");
    	this.Losers = Variable.Observed(default(int[]), game).Named("Losers");
    	this.PerformanceNoiseVariance = Variable.Observed(default(double)).Named("PerformanceNoiseVariance");
    
    	using (Variable.ForEach(game))
    	{
    		// Define the player performance as a noisy version of their skill
    		var winnerPerformance = Variable.GaussianFromMeanAndVariance(
    			this.PlayerSkills[this.Winners[game]], this.PerformanceNoiseVariance).Named("WinnerPerformance");
    		var loserPerformance = Variable.GaussianFromMeanAndVariance(
    			this.PlayerSkills[this.Losers[game]], this.PerformanceNoiseVariance).Named("LoserPerformance");
    
    		// The winner's performance must be higher than the loser's performance on a given game
    		Variable.ConstrainTrue(winnerPerformance > loserPerformance);
    	}
    
    	return new IVariable[] { this.PlayerSkills };
    }

    -Y-

    Monday, March 23, 2015 6:24 PM