此文章由机器翻译。
测试运行
使用 C# 进行梯度下降训练
我学习 (毫升) 的非正式定义是机器的使用数据来做出预测系统。任何人开始迅速调查毫升遇到有几分神秘的短语"梯度"。在这篇文章,我会解释什么梯度下降法是,演示了如何使用它来训练 logistic 回归分析分类系统。
为了得到一个何方这篇文章的想法,看看该演示程序中图 1。演示开始通过生成 10,000 的合成数据项目。时调查毫升,因为您可以控制数据的特点,使用人工数据,而不是实际数据常常很有用。每个数据项目有八个预测变量的值 (通常称为毫升术语的特点) 其次是单个因变量,可以是 0 或 1。 数据是使用生成的八个随机权值 (-7.78,-0.65,......-7.97) 再加上一个附加的常量 (-5.02)。
图 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。
衷心感谢以下 Microsoft 技术专家对本文的审阅:理查德 · 休斯