本文章是由機器翻譯。

測試回合

使用 C# 進行 Gradient Descent 訓練

James McCaffrey

下載代碼示例

James McCaffrey我學習 (毫升) 的非正式定義是機器的使用資料來做出預測系統。任何人開始迅速調查毫升遇到有幾分神秘的短語"梯度"。在這篇文章,我會解釋什麼梯度下降法是,演示了如何使用它來訓練 logistic 迴歸分析分類系統。

為了得到一個何方這篇文章的想法,看看該演示程式中圖 1。演示開始通過生成 10,000 的合成資料項目目。時調查毫升,因為您可以控制資料的特點,使用人工資料,而不是實際資料常常很有用。每個資料項目目有八個預測變數的值 (通常稱為毫升術語的特點) 其次是單個因變數,可以是 0 或 1。 資料是使用生成的八個隨機權值 (-7.78,-0.65,......-7.97) 再加上一個附加的常量 (-5.02)。

訓練使用梯度下降的 Logistic 迴歸分析分類
圖 1 訓練使用梯度下降的 Logistic 迴歸分析分類

你可以想像合成資料對應于一個問題,當你嘗試去預測性別 (男性 = 0,女性 = 1) 八大特徵如年齡、 年收入、 信用評分和等等,在那裡的特性值已經都縮小了規模所以他們介於-10.0 和 + 10.0 基於一個人。

在生成 10000 個數據專案之後, 演示隨機將資料拆分成 8,000 專案集,用於訓練分類器和 2,000 專案集,用於估計生成的模型的預測準確性。接下來,該演示創建 logistic 迴歸分析二進位分類,然後準備梯度下降法由變數 maxEpochs (1,000) 的設置值培訓和學習率 (0.01)。梯度下降法是一個反覆運算的過程和變數 maxEpochs 上的反覆運算次數設置限制。我會解釋的學習率參數之後,但現在你能想到的學習率作為控制 logistic 迴歸分析分類模型在每個訓練反覆運算中發生多少變化的值。

該演示訓練分類器,並顯示模型的誤差每 100 次反覆運算訓練資料。梯度下降法可用於兩種不同的方式來訓練 logistic 迴歸分析分類器。第一,更常見的是,方法被稱為"隨機"或"線上"或"增量"。(毫升詞彙是混沌的。)第二種方法稱為"批"離線"。我將描述這兩種方法後,但該演示程式使用隨機梯度下降訓練方法。

培訓完成後,演示顯示發現的最佳重量價值觀 (-9.84,-14.88,......-15.09). 注意模型權重都是關於用來生成亂數據的權重的兩倍大。該演示程式計算的培訓資料 (99.88%或 7,990 出的 8000 正確) 生成的模型的準確度和精密度試驗資料 (99.80%或 1,996 出 2000 正確)。

Logistic 迴歸分析分類

Logistic 迴歸分析分類最好使用一個具體的例子來解釋。假設您想要預測一個人的性別 (男性 = 0,女性 = 1) 基於年齡 (1),每年的收入 (2) 和教育水準 (3)。如果 Y 預測的值,邏輯回歸模型為這一問題將採取的形式:

Z = b0 + b1(x1) + b2(x2) + b3(x3)
Y = 1.0 / (1.0 + e^-Z)

在這裡,b0、 b1、 b2 和 b3 是權重,是必須確定的只是數位值。換句話說,你計算中間值 Z,等於輸入的值次 b 權重值,添加 b0 常數,然後將 Z 值傳遞給使用數學常數 e 的方程。 該方程稱為邏輯斯諦乙狀結腸函數。請注意每個輸入的變數 (xi) 有關聯的重量 (bi) 不是額外的重量 (b0) 與任何輸入相關聯。

原來 Y 總是會介於 0 和 1 之間。 如果 Y 小於 0.5 (接近 0),預測的輸出為 0,如果 Y 大於 0.5,你得出結論的輸出是 1,你得出的結論。 如果 n 的功能,將有 n + 1 b 權重。可以使用迴歸分析,建模並不是所有的資料,但是 logistic 迴歸分析因為它是最簡單的分類技術之一,是一個很好的地方開始。

假設一個人有一個規模化的時代,x 1 = +0.80 (較早的高於平均水準),每年的收入 x 2 =-0.50 (略小於平均) 和教育水準 x 3 =-1.00 (遠低於平均水準)。假設那 b0 = 3.0 中,b1 =-2.0,b2 = 2.0 和 b3 = 1.5。然後 Z = 3.0 + (-2.0)(0.80) + (2.0)(-0.50) + (1.5)(-1.00) =-1.10,那麼 Y = 1.0 / (1.0 + e^-(-1.10)) = 0.25。因為 Y 是更接近于 0 (小於 0.5) 比到 1,你所預料的人是男性。

這裡是實現計算回歸輸出的演示代碼:

public double ComputeOutput(double[] dataItem, double[] weights)
{
  double z = 0.0;
  z += weights[0]; // Add b0 constant
  for (int i = 0; i < weights.Length - 1; ++i)
    z += (weights[i + 1] * dataItem[i]); // Skip b0
  return 1.0 / (1.0 + Math.Exp(-z)); // Logistic sigmoid
}

問題是,b 權重從哪裡來?確定的 b 權重值的過程被稱為培養模式。這個想法是使用一套有已知輸入和輸出值,然後嘗試不同的 b 權重值,直到你找到計算的輸出與 (通常稱為目標值或所需的值) 的已知的、 正確的輸出值之間的誤差減到最小的一組值的訓練資料。

很難找到誤差最小的權值,您可以使用許多數值優化演算法。每個演算法具有不同的長處和弱點。最常用的優化演算法包括單純形優化法,L BFGS 優化,粒子群優化演算法、 反覆運算的牛頓-拉夫遜法,加上十幾個別人。最基本的優化演算法被稱為梯度下降法。

理解梯度下降法

讓我嘗試從軟體發展者的角度來解釋梯度下降法。我會與我的解釋和術語的自由使盡可能清晰的想法。看看圖中圖 2。該圖形作為價值的減肥功能錯誤。作為重量變化的價值,由此產生的 logistic 迴歸分析分類器的錯誤將改變。目標是要查找的重量值錯誤是在哪裡在最低限度。為圖 2,這將是 w = 5.0。在這裡,我使用 w 表明任何 b 權重。請注意會有一個類似于圖圖 2 為每個的重量。

偏導數和梯度下降法
圖 2 偏導數和梯度下降法

如果你知道所有錯誤圖表中的形狀,確定每個權重會很容易。但是,不幸的是,你不知道的任何誤差圖形狀。你可能認為你可能只是嘗試每個可能的權重值,然後計算導致的錯誤,但有無限數量的可能的權重值。

微積分導數在某點是函數的在點切線的斜率。邊坡有一個牌子 (+ 或-),指示方向的切線,並指示正切的陡度的大小。例如,在圖 2,當 w = 7.0,(換句話說,衍生品) 切線斜率是 +2.15 (從上部權左下,和陡峭)。當 w =-5.0,衍生品是-0.90 (從左至右下方,並不是太陡的上部)。

每個個體的導數叫做偏導數 (或只是"部分"為簡潔起見) 因為有每個重量的衍生物。漸變是集合所有的偏導數。在休閒的用法中,術語梯度和偏導數經常互換使用,主要是因為喜歡某個短語時,"與重量 b2 的誤差函數的偏導數"是很難說出來或寫比"梯度"。偏導數是經常表明使用一個特殊的數學符號,類似于落後 6。

那麼,什麼是點?如果你仔細觀察在圖 2,你會看到偏導數可以用於從給定的權重值對權重值移動位置誤差減到最小。部份標誌的方向移動,和偏量給出了暗示的遠如何移動 ; 大一個數量級以上意味著你可以考慮移動比規模較小的規模。這種技術被稱為梯度下降法,因為你死定了向最小值的誤差函數。

好的所以到目前為止很好,但這種想法是如何轉化為可用的代碼嗎?或者,換一種說法,更新 logistic 回歸重量的偽代碼是什麼?有在互聯網上的許多資源,表明一些相當複雜的演算推匯出重量更新規則。最終的結果是:

wj = wj + a * (target - computed) * xj

換句話說,"天海重量,新的權重值是舊的重量再加上一個常量的產品 ',' 時代差異訓練資料中的目標值和計算的輸出值之間倍天海重量與關聯的功能 (輸入) 值。"更新規則常常是寫使用希臘字母 theta (θ) 的重量,和阿爾法 (α) 為常數。該常量"a"通常被稱為學習速率。

假設您正在使用一個重量,j = 2,b2。並且假設 b2 的當前值是 0.50。如果對於一些訓練資料項目目,已知的目標值是 1 和計算的輸出值 (使用所有 x 值) 是 0.80,x 2 (單個輸入值對應于重量 b2) 具有價值 3.0,學習速率是 0.10,然後新的 b2 重量是:

b2 = 0.50 + 0.10 * (1 - 0.80) * 3.0
b2 = 0.50 + 0.06
b2 = 0.56

直到停止條件滿足,反復應用更新規則。它是簡直太簡單了。請注意相比目標輸出 (1.0),所以重量更新規則增加的權重值,計算出的輸出 (0.80) 是太小。這會增加培訓下一次反覆運算的計算的輸出值的影響。如果計算出的輸出已太大目標輸出相比,重量更新規則將已經減少重量。很整潔 !

有兩種主要的方法,推匯出重量更新規則。最常見的方法,你會看到在互聯網上的引用中開始通過定義一組給定的權值,得到一組訓練資料的概率,然後使用一種叫做最大似然期望的相當複雜的演算技術來查找的參數的最大限度地觀測資料的概率值。

通過定義何謂錯誤,它使用要麼兩個常見錯誤定義開始的另一種方法 — — 交叉熵誤差或偏差平方的誤差的總和。這種方法然後使用微積分來查找錯誤減到最小的權重值集。當交叉熵誤差入手,由此產生的重量更新規則是相同的規則生成的概率最大化。當開始與偏差平方的誤差的總和,由此產生的更新規則有兩個附加條款:

wj = wj + a * (target - computed) * xj * computed * (1 - computed)

在備用更新規則中,因為計算的術語始終是 0 和 1 之間,該產品的計算和 (1-計算) 將永遠為 0 至 0.25,這就意味著更新權重,用備用更新規則只需要較小的步驟,比簡單的形式。在實踐中,這兩個更新規則給類似的結果,所以幾乎總是用簡單的形式。幸運的是,你不需要知道如何培養 logistic 迴歸分析分類器中派生重量更新規則。

概率推導方法通過上漲的梯度,所以它被稱為梯度上升最大化的概率。錯誤推導方法通過梯度下降最小化錯誤,被稱為梯度下降法。這一點是你會看到訓練使用漸變的 logistic 迴歸分析分類稱為梯度下降技術和梯度提升技術。這兩個術語是指同一重量更新規則。

演示的程式結構

演示程式,與一些小的編輯,以節省空間,結構在圖 3。若要創建演示,我推出Visual Studio,選擇 C# 主控台應用程式範本。我的名字 LogisticGradient 專案。演示有沒有重大的.NET 依賴關係,因此,任何版本的Visual Studio將工作。該演示是太長,無法顯示其全部內容,但所有的原始程式碼是本文附帶的下載中提供。我刪除了所有正常的錯誤檢查,以保持盡可能清晰的主要思想。

圖 3 演示程式結構

using System;
namespace LogisticGradient
{
  class LogisticGradientProgram
  {
    static void Main(string[] args)
    {
      Console.WriteLine("Begin classification demo");
      Console.WriteLine("Demonstrating gradient descent");
      ...
      Console.WriteLine("End demo");
      Console.ReadLine();
    }
    static double[][] MakeAllData(int numFeatures,
      int numRows, int seed) { . . }
    static void MakeTrainTest(double[][] allData, int seed,
      out double[][] trainData, out double[][] testData) { . . }
    static void ShowData(double[][] data, int numRows,
      int decimals, bool indices) { . . }
    static void ShowVector(double[] vector,
      int decimals, bool newLine) { . . }
  }
  public class LogisticClassifier
  {
    private int numFeatures;
    private double[] weights;
    private Random rnd;
    public LogisticClassifier(int numFeatures) { . . }
    public double[] Train(double[][] trainData,
      int maxEpochs, double alpha) { . . }
    private void Shuffle(int[] sequence) { . . }
    private double Error(double[][] trainData,
      double[] weights) { . . }
    private double ComputeOutput(double[] dataItem,
      double[] weights) { . . }
    private int ComputeDependent(double[] dataItem,
      double[] weights) { . . }
    public double Accuracy(double[][] trainData,
      double[] weights) { . . }
  }
}

載入的範本代碼,在解決方案資源管理器視窗中之後, 我按右鍵 Program.cs 檔,並改名為更具描述性的 LogisticGradientProgram.cs 和Visual Studio自動重命名類程式,對我來說。 在編輯器視窗頂部的原始程式碼,我刪除所有不需要使用語句,留下只是一個引用頂級 System 命名空間。

LogisticGradientProgram 類包含 MakeAllData、 MakeTrainTest、 ShowData 和 ShowVector,其中創建和顯示合成資料的説明器方法。所有分類邏輯都包含在程式定義的類 LogisticClassifier。Main 方法創建合成資料包含這些語句:

int numFeatures = 8;
int numRows = 10000;
int seed = 1; // Arbitrary
double[][] allData = MakeAllData(numFeatures, numRows, seed);

方法 MakeAllData 是基本上 logistic 迴歸分析分類在背面。該方法生成隨機權反覆運算生成隨機的輸入的值,結合的權值和輸入的值使用邏輯斯諦的乙狀結腸函數,然後計算對應的輸出值。該方法不會向資料,這意味著,在理論上,100%預測精度是可能添加任何隨機雜訊。合成資料被分割成培訓和測試集,如下所示:

double[][] trainData;
double[][] testData;
MakeTrainTest(allData, 0, out trainData, out testData);
ShowData(trainData, 3, 2, true);
ShowData(testData, 3, 2, true);

方法 MakeTrainTest 使用硬編碼 80%到 20%的列車試驗分裂。你可能想要將培訓百分比作為參數傳遞。Logistic 迴歸分析分類是成立和訓練:

LogisticClassifier lc = new LogisticClassifier(numFeatures);
int maxEpochs = 1000;
double alpha = 0.01; // Learning rate
double[] weights = lc.Train(trainData, maxEpochs, alpha);
ShowVector(weights, 4, true);

訓練參數 maxEpochs 和 Alpha (學習率) 的值測定試驗和錯誤。優化大多數毫升訓練方法通常需要一些試驗,以獲得良好的預測精度。評價訓練好的模型品質就像這樣:

double trainAcc = lc.Accuracy(trainData, weights);
Console.WriteLine(trainAcc.ToString("F4"));
double testAcc = lc.Accuracy(testData, weights);
Console.WriteLine(testAcc.ToString("F4"));

測試資料的模型精度較相關的兩個精度值。它為您提供一個粗略的估計,如何準確的模型會時提出了一種未知的輸出值的新資料。

實施梯度下降法培訓

方法火車的定義的開頭:

public double[] Train(double[][] trainData, int 
  maxEpochs, double alpha)
{
  int epoch = 0;
  int[] sequence = new int[trainData.Length];
  for (int i = 0; i < sequence.Length; ++i)
    sequence[i] = i;
...

可變的時代是訓練迴圈計數器變數。命名序列的陣列初始化為指數的訓練資料。這裡的想法是將在每次反覆運算的不同,隨機的連續處理訓練資料。接下來,主要的重量更新迴圈的開始:

while (epoch < maxEpochs)
{
  ++epoch;
  if (epoch % 100 == 0 && epoch != maxEpochs)
  {
    double mse = Error(trainData, weights);
    Console.Write("epoch = " + epoch);
    Console.WriteLine(" error = " + mse.ToString("F4"));
  }
  Shuffle(sequence); // Process data in random order
...

誤差的測量計算和顯示每 100 的時代。方法錯誤返回平方的誤差的平方誤差的總和平均之間計算和目標輸出值。請注意這是稍有不同的定義是梯度下降重量更新規則的基礎的錯誤。當利用梯度下降法訓練,錯誤隱式地使用,但不直接使用。其他培訓技術,在特定的粒子群優化演算法,顯式地使用的錯誤。法洗牌打亂費舍爾茨演算法的序列陣列中包含的培訓資料指標。

梯度下降法培訓的核心是短的:

for (int ti = 0; ti < trainData.Length; ++ti)
{
  int i = sequence[ti];
  double computed = ComputeOutput(trainData[i], weights);
  int targetIndex = trainData[i].Length - 1;
  double target = trainData[i][targetIndex];
  weights[0] += alpha * (target - computed) * 1;
  for (int j = 1; j < weights.Length; ++j)
    weights[j] += alpha * (target - computed) * trainData[i][j - 1];
}

首先,使用已被置亂的序陣列,確定下一個隨機順序培訓專案。方法 ComputeOutput 使用當前的權重來計算當前的權重值,這將是一個介於 0.0 和 1.0 之間的值集的輸出。目標值,0 或 1,從當前的培訓專案中提取。B0 重量是第一次更新。回想起那段重量更新規則使用被修改的重量與關聯的輸入的值。然而,b0 重量並不與任何實際的投入。為了對付這,回歸 b0 權重據說有一個虛擬的輸入的值始終等於 1.0。演示代碼乘以 1.0 的值,這顯然不起作用,說明更新 b0 和更新任何其他 b 重量之間的相似性。更新週期性 b 權數是相當簡單,只需要一些注意力集中的索引的細節。方法火車最後:

...
} // While loop
  return this.weights;
} // Train

該方法返回引用實際重量 LogisticClassifier 權重陣列中。為安全起見,您可能想要考慮創建一個結果陣列,將權重複制到該陣列,然後返回對陣列的引用。

如前文所述,演示使用隨機梯度下降。遇到時每個培訓專案,這一培訓專案的梯度計算,並用於更新所有的權重。在批次處理梯度下降,與之相反的是,在每次反覆運算梯度在累積起來所有的培訓專案第一次,然後的權數。若要使用批量訓練,方法火車的心會變成中所示的代碼圖 4

圖 4 列車方法使用批量訓練時

double[] accumulatedGradients = new double[weights.Length];
for (int i = 0; i < trainData.Length; ++i)  // Accumulate
{
  double computed = ComputeOutput(trainData[i], weights);
  int targetIndex = trainData[i].Length - 1;
  double target = trainData[i][targetIndex];
  accumulatedGradients[0] += (target - computed) * 1; // For b0
  for (int j = 1; j < weights.Length; ++j)
    accumulatedGradients[j] += (target - computed) * trainData[i][j - 1];
}
for (int j = 0; j < weights.Length; ++j) // Update all wts
  weights[j] += alpha * accumulatedGradients[j];

間歇訓練,因為所有的訓練專案處理之前任何權數,並無優勢培訓資料按隨機連續處理。

梯度下降法培訓第一次在構思時,批次處理方法被認為從理論上更可取,因為這種技術使用所有可用資訊來查找重量梯度。然而,毫升從業人員很快就意識到可通過使用漸變為只是一個單一的培訓專案作為整體的梯度估計提高訓練速度。換句話說,隨機 (這意味著隨機確定) 梯度下降法使用一個漸變整體梯度估計。

接近尾聲了

基本的梯度下降法經常用 logistic 迴歸分析分類器的兩個相關的變化被稱為 BFGS 和 L BFGS。這兩種演算法是一種嘗試改善基本的梯度下降法,以大大增加複雜性為代價。

Logistic 迴歸分析分類,可以與其他幾個毫升技術梯度下降法。尤其是,可以用梯度下降法來訓練神經網路。當神經網路用於梯度下降法時,這項技術被稱為反向傳播。


James McCaffrey適合在雷德蒙的微軟研究院  他曾在幾個 Microsoft 產品包括 Internet Explorer 和冰。 博士。 麥卡弗裡也可以撥打jammc@microsoft.com

感謝以下技術專家在微軟研究院對本文的審閱:理查 · 休斯