使用 Infer.NET 进行概率编程
本文介绍了如何使用 Infer.NET 进行概率性编程。 概率性编程是一种将自定义模型表示为计算机程序的机器学习方法。 借助它可以在模型中包含专业知识,使机器学习系统更易理解。 它还支持在线推断,即在新数据到达时进行学习的过程。 Azure、Xbox 及必应中的多种 Microsoft 产品均使用了 Infer.NET。
什么是概率性编程?
基于概率性编程,创建对真实世界过程的统计模型。
系统必备
-
本地.NET开发环境设置
创建应用程序
- 打开一个新的命令提示符,并运行下面的命令:
dotnet new console -o myApp
cd myApp
dotnet
命令将创建 console
类型的 new
应用程序。 -o
参数将创建名称为 myApp
的目录,会在其中存储应用并填充所需的文件。 cd myApp
命令会将你转到新创建的应用目录。
安装 Infer.NET 包
需安装 Microsoft.ML.Probabilistic.Compiler
包才能使用 Infer.NET。 在命令提示符中运行下面的命令:
dotnet add package Microsoft.ML.Probabilistic.Compiler
设计模型
示例使用在室内中进行的乒乓球或桌上足球比赛。 我们具有参赛者的信息和每场比赛的结果。 我们想要通过此数据推断玩家的实力。 假设每位玩家的潜在实力呈正态分布,且他们在给定比赛中的表现是此实力受干扰后的状态。数据被设定的约束条件是赢家的表现大于输家的表现。 这是热门的 TrueSkill 模型的简化版,此模型也支持团队、平局及其他扩展项。 热销的 Halo 和 Gears of War 游戏中的比赛安排使用了此模型的高级版。
我们需要列出所推断玩家的实力以及他们的差异(衡量实力的不确定性)。
游戏结果示例数据
游戏 | 胜者 | 败者 |
---|---|---|
1 | 玩家 0 | 玩家 1 |
2 | 玩家 0 | 玩家 3 |
3 | 玩家 0 | 玩家 4 |
4 | 玩家 1 | 玩家 2 |
5 | 玩家 3 | 玩家 1 |
6 | 玩家 4 | 玩家 2 |
仔细观察样本数据,你会发现玩家3和4都有1次胜利和1次失败。 让我们看看使用概率编程的排名是什么样的。另请注意基于我们开发的编码习惯,玩家编号是从零开始的,即使是室内游戏匹配列表也是从零开始的。
编写代码
设计模型后,就可以使用 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是总冠军!