使用 Infer.NET 和概率编程创建游戏匹配列表应用

本作指南介绍了如何使用 Infer.NET 进行概率编程。 概率编程是一种机器学习方法,其中自定义模型表示为计算机程序。 它允许在模型中整合域知识,并使机器学习系统更易于解释。 它还支持在线推理 - 新数据到达时学习的过程。 Infer.NET 用于 Microsoft 的各种产品中,如 Azure、Xbox 和必应。

什么是概率编程?

概率编程允许你创建真实进程的统计模型。

先决条件

  • 本地开发环境。

    本指南要求您拥有一台可以用于开发的计算机。 .NET 教程 Hello World 在 10 分钟内 提供了在 macOS、Windows 或 Linux 上设置本地开发环境的说明。

创建应用

打开新的命令提示符并运行以下命令:

dotnet new console -o myApp
cd myApp

dotnet 命令创建一个类型为 consolenew 应用程序。 该 -o 参数将创建一个名为在其中存储应用的目录,并使用所需的文件填充该目录 myApp 。 该 cd myApp 命令将你放入新创建的应用目录。

安装 Infer.NET 包

若要使用 Infer.NET,需要安装 Microsoft.ML.Probabilistic.Compiler 包。 在命令提示符下运行以下命令:

dotnet add package Microsoft.ML.Probabilistic.Compiler

或者,在 .NET 10+ 中:

dotnet package add Microsoft.ML.Probabilistic.Compiler

设计模型

示例使用在 Office 中进行的乒乓球或桌上足球比赛。 你掌握每场比赛的参与者和结果。 你想要从此数据推断玩家的技能。 假设每位玩家的潜在实力呈正态分布,且他们在给定比赛中的表现是此实力受干扰后的状态。 数据将优胜者的性能限制为大于输家的性能。 这是流行的 TrueSkill 模型的简化版本,它还支持团队、绘图和其他扩展。 此模型的先进版本用于畅销游戏《光环》和《战争机器》的匹配。

你需要列出推断的玩家技能及其差异 - 技能的不确定性度量。

游戏结果示例数据

游戏 胜利者 失败者
1 玩家 0 玩家 1
2 玩家 0 玩家 3
3 玩家 0 玩家 4
4 玩家 1 玩家 2
5 玩家 3 玩家 1
6 玩家 4 玩家 2

仔细查看示例数据后,你会注意到球员 3 和 4 都有一胜一负。 让我们看看使用概率编程时排名情况如何。 还会注意到有一位玩家 0,因为对于开发人员而言,甚至 Office 匹配列表都是从零开始的。

编写一些代码

设计模型后,可以使用 Infer.NET 建模 API 将其表示为概率程序。 在喜欢的文本编辑器中打开 Program.cs ,并将其所有内容替换为以下代码:

namespace myApp

{
    using System;
    using System.Linq;
    using Microsoft.ML.Probabilistic;
    using Microsoft.ML.Probabilistic.Distributions;
    using Microsoft.ML.Probabilistic.Models;

    class Program
    {

        static void Main(string[] args)
        {
            // The winner and loser in each of 6 samples games
            var winnerData = new[] { 0, 0, 0, 1, 3, 4 };
            var loserData = new[] { 1, 3, 4, 2, 1, 2 };

            // Define the statistical model as a probabilistic program
            var game = new Range(winnerData.Length);
            var player = new Range(winnerData.Concat(loserData).Max() + 1);
            var playerSkills = Variable.Array<double>(player);
            playerSkills[player] = Variable.GaussianFromMeanAndVariance(6, 9).ForEach(player);

            var winners = Variable.Array<int>(game);
            var losers = Variable.Array<int>(game);

            using (Variable.ForEach(game))
            {
                // The player performance is a noisy version of their skill
                var winnerPerformance = Variable.GaussianFromMeanAndVariance(playerSkills[winners[game]], 1.0);
                var loserPerformance = Variable.GaussianFromMeanAndVariance(playerSkills[losers[game]], 1.0);

                // The winner performed better in this game
                Variable.ConstrainTrue(winnerPerformance > loserPerformance);
            }

            // Attach the data to the model
            winners.ObservedValue = winnerData;
            losers.ObservedValue = loserData;

            // Run inference
            var inferenceEngine = new InferenceEngine();
            var inferredSkills = inferenceEngine.Infer<Gaussian[]>(playerSkills);

            // The inferred skills are uncertain, which is captured in their variance
            var orderedPlayerSkills = inferredSkills
               .Select((s, i) => new { Player = i, Skill = s })
               .OrderByDescending(ps => ps.Skill.GetMean());

            foreach (var playerSkill in orderedPlayerSkills)
            {
                Console.WriteLine($"Player {playerSkill.Player} skill: {playerSkill.Skill}");
            }
        }
    }
}

运行你的应用程序

在命令提示符下运行以下命令:

dotnet run

结果

结果应如下所示:

Compiling model...done.
Iterating:
.........|.........|.........|.........|.........| 50
Player 0 skill: Gaussian(9.517, 3.926)
Player 3 skill: Gaussian(6.834, 3.892)
Player 4 skill: Gaussian(6.054, 4.731)
Player 1 skill: Gaussian(4.955, 3.503)
Player 2 skill: Gaussian(2.639, 4.288)

在结果中,请注意,根据模型,玩家 3 排名略高于玩家 4。 这是因为球员 3 胜于球员 1 比球员 4 战胜球员 2 的胜利更重要 , 请注意, 玩家 1 击败了球员 2。 玩家 0 是整体冠军!

继续学习

设计统计模型本身就是一项技能。 Microsoft Research Cambridge 团队曾编写过一本免费的在线书籍,其中简要介绍了此文。 本书的第 3 章更详细地介绍了 TrueSkill 模型。 考虑到模型后,可以使用 Infer.NET 网站上的 大量文档 将其转换为代码。

后续步骤

请查看 Infer.NET GitHub 存储库,继续学习并查找更多示例。