2019 年 2 月

第 34 卷,第 2 期

本文章是由機器翻譯。

[測試回合]

使用 Infer.NET 來為競爭者評分

藉由James McCaffrey

James McCaffreyInfer.NET 是開放原始碼庫,可用來建立隨機性程式設計系統。我傾向於將做為主要以變數指定的類型,例如 char 變數,其值為"Q"。 值為基礎的其中一個或-dinary 電腦 program 機率程式設計主要根據機率分佈,例如高斯分佈,其中有平均 0.0 和 1.0 的標準差。

在本文中,我告訴您如何開始著手使用結果勢均力敵的競爭對手一組運算分級 Infer.NET 程式庫。取得機率程式設計這個想法,並請參閱這篇文章的走向的好方法是要看看的示範程式**[圖 1**。示範設定六個競爭對手 (考慮的運動團體):Angels、 Bruins、 Comets、 一個惡魔啊,Eagles 和傳單。

Infer.NET 作用中的評等
作用中的 [圖 1 Infer.NET 評等

六個小組播放彼此。每個小組會扮演三次,因此會有九個遊戲的總計。示範按字母組定義假設每個小組有內建的強度和高斯,(也稱為一般或鐘型) 可以描述每個強度機率模型發佈與平均值為 2000年,而其標準差則為 200 個任意的單位。

示範程式會使用 win 遺失資料,來推斷六個小組的優勢。Angels 贏了三個遊戲遺失無而且有推斷的強度 2256.8 單位,也就是大約 1.25 優於 2000年個單位的假設平均強度的標準差單位。傳單遺失所有三個遊戲,而且有 1739.7 單位中推斷的程度。

我在這裡使用詞彙的優點,但是您可以將評等為推斷的數字值。請注意,是否您可以推斷 rat-生機械 」 的一組項目,您會自動取得的項目排名。最終排名,從最佳到最差,是 Angels、 Bruins、 Com-ets、 Eagles、 一個惡魔啊、 傳單。

本文假設您有中繼或更好的程式設計技能C#,但不會假設您知道任何關於 Infer.NET 或機率的程式設計。Infer.NET 僅支援C#和F#,因此您可以重整的示範,以F#如果您想要。一旦您了解機率程式設計的基本概念,您應該能夠重寫使用其中一種許多其他機率程式設計架構,例如 Stan 或 Edward 示範程式。

在這篇文章會示範程式的完整原始程式碼。也提供 accompa nying 檔案下載的原始程式碼。已移除所有一般錯誤檢查要保留的主要概念盡可能清楚。

了解隨機變數

示範程式會假設每個小組的強度是高斯分佈隨機變數具有指定之平均值 (aver 歲) 和標準差。完全,這代表什麼,以及從何處這項假設確實?

有許多種類的隨機變數的分佈。每有一或多個特性的參數。例如,執行 dom 的變數後面是統一散發 = 2.0 且 b = 5.0 可以是任何值之間 2.0 和 5.0 版,其中每個 pos sible 值是可能性相等。示範問題有可能會假設 team 強度一致的方式是使用散發 = 1000年和 b = 3000 年字面意思一樣,擁有許多這類優點平均值為 0.5 * (1000 + 3000) = 2000.0 單位和標準差為 sqrt((1/12) * (3000-1000) ^2) = 577.35 的單位。

示範假設小組優點高斯平均值 = 2000年和標準差 = 200,因此許多這類團隊的 aver 壽命強度會大約 2000年和大約 99%的許多這類的小組必須介於 2000-的優點 (3 * 200) = 1400年和 2000年 + (3 * 200) = 2600年。

到目前為止,您可能會想: 「 我有使用 Infer.NET 和建立 prob abilistic 程式的統計資料散發中擁有 mis 博士的很好。 」 這並不完全正確。Infer.NET 支援許多散發套件,但實際上您通常需要少量的獨立少數。我最常使用的項目是高斯,統一、 beta、 二項式、 多維度、 gamma 和波氏。類似的項目是 System.Collections 命名空間的.NET framework 所支援的資料結構的許多類型。即使有很多,您通常會使用只有幾個 (堆疊、 佇列、 字典),而且您會了解新的您需要的 encoun ter 問題。

平均值是資料的平均值和標準差是量值的資料散佈的方式。變異數是標準差的平方和有效位數是變異數的反向作業。發生的原因是三個不同的術語包含完全相同的資訊,有時,某個表單時,比其他更方便使用某種類型的數學方程式中。Infer.NET 程式庫會傾向於使用變異數和有效位數,而不是標準差。

示範程式結構

示範程式,以節省空間,少數稍加編輯的完整原始程式碼所示**[圖 2**。

[圖 2 的完整原始碼

using System;
using Microsoft.ML.Probabilistic.Models;
using Microsoft.ML.Probabilistic.Algorithms;
using Microsoft.ML.Probabilistic.Distributions;
// VS2017 (Framework 4.7) Infer.NET 0.3.1810.501

namespace InferStrengths
{
  class InferStrengthsProgram
  {
    static void Main(string[] args)
    {
      Console.WriteLine("Begin Infer.NET demo ");

      // ===== Set up teams and win-loss data =====================

      string[] teamNames = new string[] { "Angels", "Bruins",
        "Comets", "Demons", "Eagles", "Flyers" };
      int N = teamNames.Length; 

      int[] winTeamIDs =  new int[] { 0, 2, 1, 0, 1, 3, 0, 2, 4 };
      int[] loseTeamIDs = new int[] { 1, 3, 2, 4, 3, 5, 5, 4, 5 };

      Console.WriteLine("Data: \n");
      for (int i = 0; i < winTeamIDs.Length; ++i) {
        Console.WriteLine("game: " + i + "   winning team: " +
          teamNames[winTeamIDs[i]] + "   losing team: " +
          teamNames[loseTeamIDs[i]]);
      }

      // ===== Define a probabilistic model =======================

      Range teamIDsRange = new Range(N).Named("teamsIDRange");
      Range gameIDsRange =
        new Range(winTeamIDs.Length).Named("gameIDsRange");

      double mean = 2000.0;
      double sd = 200.0;
      double vrnc = sd * sd;
      
      Console.WriteLine("\nDefining Gaussian model mean = " +
        mean.ToString("F1") + " and sd = " + sd.ToString("F1"));
      VariableArray<double> strengths =
        Variable.Array<double>(teamIDsRange).Named("strengths");
      
      strengths[teamIDsRange] =
        Variable.GaussianFromMeanAndVariance(mean,
        vrnc).ForEach(teamIDsRange);

      VariableArray<int> winners =
        Variable.Array<int>(gameIDsRange).Named("winners");
      VariableArray<int> losers =
        Variable.Array<int>(gameIDsRange).Named("losers");

      winners.ObservedValue = winTeamIDs;
      losers.ObservedValue = loseTeamIDs;

      using (Variable.ForEach(gameIDsRange))
      {
        var ws = strengths[winners[gameIDsRange]];
        var ls = strengths[losers[gameIDsRange]];
        Variable<double> winnerPerf =
      Variable.GaussianFromMeanAndVariance(ws, 400).Named("winPerf");
        Variable<double> loserPerf =
      Variable.GaussianFromMeanAndVariance(ls, 400).
        Named("losePerf");

        Variable.ConstrainTrue(winnerPerf > loserPerf);
      }

      // ===== Infer team strengths using win-loss data ===========

      Console.WriteLine("\nInferring strengths from win-loss data");
      var iengine = new InferenceEngine();
      iengine.Algorithm = new ExpectationPropagation();
      iengine.NumberOfIterations = 40;
      // iengine.ShowFactorGraph = true;  // needs Graphviz install

      Gaussian[] inferredStrengths =
        iengine.Infer<Gaussian[]>(strengths);
      Console.WriteLine("Inference complete. Inferred strengths: ");

      // ===== Show results =======================================

      for (int i = 0; i < N; ++i) {
        double strength = inferredStrengths[i].GetMean();
        Console.WriteLine(teamNames[i] + ": " +
          strength.ToString("F1"));
      }

      Console.WriteLine("\nEnd demo ");
      Console.ReadLine();
    } // Main
  }
} // ns

若要建立示範程式,啟動 Visual Studio 2017 Community Edition 和已選取 [.NET framework 4.7 版的主控台應用程式範本專案並將它命名為 InferStrengths。Infer.NET 可以執行.NET Core 應用程式中,但比較偏好傳統的.NET Framework。

載入的範本程式碼之後,我以滑鼠右鍵按一下方案總管] 視窗中的 Program.cs 檔案並重新將檔案命名為 InferStrengthsProgram.cs,則允許 Visual Studio 會自動重新命名為我的類別程式。

我以滑鼠右鍵按一下方案總管] 視窗中的專案名稱,並選取 [管理 NuGet 套件] 選項。在 [NuGet] 視窗中,已選取 [瀏覽] 索引標籤並再搜尋 'Infer.NET'。 結果清單中已選取 Microsoft.ML.Probabilistic.Compiler 封裝 (版本 0.3.1810.501) 並按一下 [安裝] 按鈕。Microsoft 計劃移轉 Infer.NET ML.NET 程式庫,在某個時間點,所以如果找不到 Infer.NET 作為獨立封裝,請尋找它 ML.NET 套件內。

設定資料

六個的運動團體中示範的設定,就像這樣:

string[] teamNames = new string[] { "Angels", "Bruins",
  "Comets", "Demons", "Eagles", "Flyers" };
int N = teamNames.Length;

Infer.NET 主要適用於隨機變數,因為在許多程式中所有資料都都會完全是數字。在這裡,小組名稱指定為字串,而不是整數索引只以提高可讀性。輸贏資料是:

int[] winTeamIDs =
  new int[]  { 0, 2, 1, 0, 1, 3, 0, 2, 4 };
int[] loseTeamIDs = 
  new int[]  { 1, 3, 2, 4, 3, 5, 5, 4, 5 };

在 [0] 遊戲中的資料表示,小組 0 (Angels) 訊號小組 1 (Bruins)。在遊戲 [1] 中,小組 2 (Comets) 訊號 team (一個惡魔啊),3,依此類推透過遊戲 [8]。數字的程式設計,使用像這樣的平行陣列多半會是更常見的模式,比將資料放在類別或結構的物件。

請注意,此時示範使用只有原生的.NET 資料型別。不過,Infer.NET 有它自己的型別系統,而且資料將轉換成類型使用 Infer.NET 短時間內。示範會顯示來源資料:

for (int i = 0; i < winTeamIDs.Length; ++i) {
  Console.WriteLine("game: " + i + " winning team: " +
    teamNames[winTeamIDs[i]] + " losing team: " +
    teamNames[loseTeamIDs[i]]);
}

示範中沒有很少的資料。有限的資料搭配使用的功能相較於某些機器學習技術,例如類神經網路 」 或 「 增強式學習,通常需要非常大量的訓練資料有效的機率程式設計的強度。

定義在機率模型

示範準備高斯模型搭配這些陳述式:

Range teamIDsRange = new Range(N).Named("teamsIDRange");
Range gameIDsRange =
  new Range(winTeamIDs.Length).Named("gameIDsRange");
double mean = 2000.0;
double sd = 200.0;
double vrnc = sd * sd;

範圍物件的概念是 Infer.NET 中重要的。不同於標準的程序性程式設計,其中通常會明確地逐一查看使用迴圈或 foreach 迴圈,在 Infer.NET 很多常見要套用的範圍物件透過中繼作業。這是可能有點困難習慣的程式碼範例。

幾乎所有 Infer.NET 物件可以都提供選擇性的字串名稱,使用具名方法鏈結至建構函式呼叫。物件的字串名稱不必符合物件識別項名稱,但它是很好的作法,使兩者相符。如您所見,使用具名方法就很有用 Infer.NET 具有內建的方式來顯示模型的計算圖形中,因此圖表會使用字串的名稱,如果有的話,而不是將程式庫產生的名稱,例如 vdouble23。

小組優點來推斷設定這兩個陳述式:

VariableArray<double> strengths =
  Variable.Array<double>(teamIDsRange).Named("strengths");
strengths[teamIDsRange] =
  Variable.GaussianFromMeanAndVariance(mean,
  vrnc).ForEach(teamIDsRange);

第一個陳述式會設定為特殊的 VariableArray 類型,其中包含六個隨機變數物件的單一物件。第二個陳述式會初始化每個隨機變數與平均值的高斯 = 2000年和變異數 = 4000 (這相當於標準差 = 200)。它是可以設定類似的個別變數物件的陣列:

Variable<double>[] arr = new Variable<double>[6];
for (int i = 0; i < 6; ++i)
  arr[i] = Variable.GaussianFromMeanAndVariance(2000, 4000);

不過,基於效能考量使用 VariableArray 方法 Infer.NET 文件所建議。接下來,int 類型的隨機變數建立保留的成功與失敗的團隊、 索引和原生.NET int 資料轉換成 Infer.NET 物件的然後:

VariableArray<int> winners =
  Variable.Array<int>(gameIDsRange).Named("winners");
VariableArray<int> losers =
  Variable.Array<int>(gameIDsRange).Named("losers");
winners.ObservedValue = winTeamIDs;
losers.ObservedValue = loseTeamIDs;

在此情況下,隨機變數未遵循一種機率分佈;相反地,它們基本上只是一般的整數值。ObservedValue 屬性用來在此情況下設定固定的值。

索引鍵的陳述式,定義在機率模型的特性如下:

using (Variable.ForEach(gameIDsRange)) {
  var ws = strengths[winners[gameIDsRange]];
  var ls = strengths[losers[gameIDsRange]];
  Variable<double> winnerPerf =
    Variable.GaussianFromMeanAndVariance(ws,
    400.0).Named("winPerf");
  Variable<double> loserPerf =
    Variable.GaussianFromMeanAndVariance(ls,
    400.0).Named("losePerf");

  Variable.ConstrainTrue(winnerPerf > loserPerf);
}

此程式碼是很微妙。程式碼是 Variable.ForEach 區塊內,因此作業套用至每個小組和每個遊戲的結果,以中繼的方式。對應至的成功與失敗的小組在每種遊戲效能的隨機變數定義,讓它們根據小組的強度,但它們有雜訊的元件高斯散發的變異數 = 400。將這個方法之一是當小組優勢會加以推斷,沒有機會可能稍微 underperform 一個小組,並可能會稍微優於對手。400 的雜訊變異數值必須試驗和錯誤來判斷。

ConstrainTrue 陳述式會是關鍵,並加入可讓推斷引擎,來計算每個小組的強度的邏輯。是推斷引擎會使用複雜的演算法,來檢查不同的值,表示和變異數的六個的每個小組,並接著會判斷有多少觀察到的輸贏結果指定假設的方式和變異數。推斷演算法找到最佳比對觀察到的資料的變異數的六個方法。聰明 !

推斷小組優點

一旦定義在機率模型之後,這些陳述式會以建立推斷引擎:

var iengine = new InferenceEngine();
iengine.Algorithm = new ExpectationPropagation();
iengine.NumberOfIterations = 40;
// iengine.ShowFactorGraph = true;

Infer.NET 支援三種不同的演算法: 期望傳播、 variational 訊息傳遞和 Gibbs 取樣。不同的演算法適用於不同類型的不確定性的模型。示範模型只期望傳播是有效的。期望傳播特有 Infer.NET 和 Kullback Liebler 分歧度量,來模擬機率分佈的一組觀察到的資料降到最低。來試驗和錯誤,就必須判斷 NumberOfIterations 屬性的值。

Infer.NET 的有趣功能是您可以自動產生的模型計算圖形中,例如中的視覺表示法**[圖 3** ,其對應於示範程式。這項功能會對開放原始碼 Graphviz 程式中的相依性。如果您將 ShowFactorGraph 為 true,而且安裝 Graphviz,圖形將會儲存在目前的工作目錄中的 SVG 格式,並不會顯示在瀏覽器中。

計算圖形的視覺表示法
[圖 3 的計算圖形的視覺表示法

推斷引擎建立之後,很容易計算並顯示 team 優點使用 Infer 方法:

Gaussian[] inferredStrengths =
  iengine.Infer<Gaussian[]>(strengths);
for (int i = 0; i < N; ++i) {
  double strength = inferredStrengths[i].GetMean();
  Console.WriteLine(teamNames[i] + ": " + strength);
}

優點物件會傳遞至 Infer。優點是型別 VariableArray 高斯 random 變數的集合物件的重新叫用是得獎者和輸家 VariableArray 物件,其中具有輸贏的資料相關聯。請注意,Infer.NET 模型鬆散連接的物件,而不是單一的最上層物件的集合。對我來說至少這個概念所花費的時間才能熟悉 Infer.NET 時,取得用來。

總結

機率程式設計使用 Infer.NET 有它比使用標準程序性語言,程式設計太大差異的操作,而且沒有相關的非一般的學習曲線。這篇文章中的範例鬆散根據 TrueSkill 排名用於 Xbox 配對中由 Microsoft Research 所開發的系統。但是,機率程式設計可以套用至評等和排名以外的許多問題。有點不尋常的程式碼程式庫參考資料中具有它的起源,Infer.NET 有絕佳的文件。如果您想要深入了解機率的程式設計,我建議您採取了解在這些教學課程bit.ly/2rEr784


Dr。James McCaffrey適用於在美國華盛頓州雷德蒙的 Microsoft Research他曾經有幾份 Microsoft,包括 Internet Explorer 和 Bing。Dr。McCaffrey 要聯絡jamccaff@microsoft.com

感謝下列 Microsoft 技術專家檢閱這篇文章:Chris Lee, Ricky Loynd


MSDN Magazine 論壇中的這篇文章的討論