分类之神经网络

紧接上一回,深入学习神经网络之后,这里讲神经网络在分类和预测的应用。

在本月的专栏中,我将说明如何使用神经网络解决分类和预测问题。 说明分类目标的最好的方法还是通过示例。 假定您具有与鸢尾花有关的历史数据,如下所示:

5.1 3.5 1.4 0.2 Setosa
7.0 3.2 4.7 1.4 Versicolor
6.3 3.3 6.0 2.5 Virginica
6.4 3.2 4.5 1.5 Versicolor
...


每一行数据都具有五个字段,这五个字段用空格分隔。 前四个数字字段是花萼(绿色芽状覆盖物)长度、花萼宽度、花瓣(花朵的带颜色部分)长度和花瓣宽度。 第五个字段是种类: Setosa(山鸢尾)、Versicolor(变色鸢尾)或 Virginica(维吉尼亚鸢尾)。 该分类目标是要确定预测某一鸢尾花属于哪一种类的一个方程式或一组规则。然后,可以使用该规则组基于萼片和花瓣的长度和宽度值预测新鸢尾花的种类。 此鸢尾花植物数据由 R. A. Fisher 在 1936 年首次作为典型示例使用。 分类可能不会令您兴奋,但非常重要。 有关的示例包括:基于收入和每月支出之类的变量对申请人的信用评级进行分类(或者,也可以说是预测申请人的信用可靠性),基于验血的值对医院患者是否患有癌症进行分类。

有许多对数据进行分类的方法,包括使用神经网络。 可以通过这样一种方法来考虑神经网络:神经网络就是虚拟的输入-输出设备,接受任何数目的数字输入并且生成任何数目的数字输出。 要想了解我在本专栏中所讲述的内容,最好是查看图 1 所示的屏幕快照以及图 2 中的图像。 图 1 显示神经网络分类实操。 为了让使用神经网络进行分类的概念更清晰明了,我没有使用真实的数据。 我而是使用了虚构的数据,其中,输入 x 值是没有特定意义的四个任意数值。 用于分类的输出 y 变量是颜色,可取以下三个分类值之一: red、green 或 blue。 图 1 中所示的程序通过生成具有 100 行虚构数据(例如“8.0 5.0 9.0 5.0 green”)的文本开始,然后显示这些数据的前四行。 然后,该程序将此原始数据文件读入内存中,作为具有 80 行数据的定型矩阵以及具有 20 行数据的测试矩阵。 请注意,两个变化形式应用于原始数据。 原始数字输入数据将被规范化,以便所有值都介于 -1.00 和 +1.00 之间,并且原始输出数据(例如“red”)将被编码为具有三个值的向量(“1.0 0.0 0.0”)。

 
图 1 神经网络分类实操

 
图 2 神经网络结构

在创建定型矩阵和测试矩阵后,该演示程序将创建一个完全连接的前向式神经网络,它具有三个输入神经元、五个用于计算的隐藏的神经元以及三个输出神经元。 这表明 4-5-3 完全连接的神经网络要求 43 个权重和偏置。 接下来,分类程序将对定型数据进行分析,以便找到最佳的 43 个权重和偏置(它们将分类总误差降至最低)。 该程序使用粒子群优化以及互熵误差来估计权重和偏置的最佳值。

该分类程序然后将这些最佳权重和偏置值加载到神经网络中,并且对测试矩阵中的 20 行数据评估模型的预测准确性。 请注意,已对神经网络的输出进行了设计,以便三个输出值的总和为 1.0。 在这个示例中,该模型正确预测了 20 个测试向量中的 17 个。 图 2 中的图像阐释一个神经网络,它接受 (-1.00, 1.00, 0.25, -0.50) 的输入并且生成 (0.9, 0.1, 0.0) 的预测输出(对应于红色)。

该示例程序表明,在使用神经网络进行分类(其中,输入数据是数字,输出数据是分类)时要作出以下五个主要决策:

  1. 如何规范化数字输入数据
  2. 如何对分类输出数据进行编码
  3. 如何在 [0.0, 1.0] 范围中生成神经输出
  4. 如何在定型时测量误差
  5. 如何在测试时测量精确性

在随后的部分中,我将说明在该示例程序中作出的如下选择:

  1. 对数字输入数据执行线性转换
  2. 将 1-of-N 编码用于分类输出数据
  3. 将 Softmax 激活函数用于输出层
  4. 使用互熵误差来确定最佳权重
  5. 使用 winner-takes-all(赢家通吃)方法来确定精确性

生成了图 1 中的屏幕快照的程序代码有点过长,无法在本文中提供,因此,我只是强调了所使用的算法。 完整程序源在 MSDN 代码下载网站(网址为archive.msdn.microsoft.com/mag201207TestRun)上提供。 本文假定您具有高级编程技能,并大体上了解神经网络。 我在《MSDN 杂志》2012 年 5 月刊 (msdn.microsoft.com/magazine/hh975375) 中介绍了神经网络基础知识。

程序的整体结构

图 3 列出了在图 1 中运行的示例的程序结构。 我使用 Visual Studio 2010 创建了一个名为 NeuralClassification 的 C# 控制台应用程序。 在解决方案资源管理器窗口中,我将文件 Program.cs 重命名为更具描述性的 NeuralClassificationProgram.cs,它将自动重命名包含 Main 的类。 我删除了 Visual Studio 模板生成的不必要的 using 语句,并且添加了对 System.IO 命名空间的引用。

图 3 神经分类程序结构

          [%$TOPIC/jj190808_zh-cn_MSDN_10_63_0_0%] 
          [%$TOPIC/jj190808_zh-cn_MSDN_10_63_0_1%] 
          [%$TOPIC/jj190808_zh-cn_MSDN_10_63_0_2%] 
          [%$TOPIC/jj190808_zh-cn_MSDN_10_63_0_3%] 
          [%$TOPIC/jj190808_zh-cn_MSDN_10_63_0_4%] 
          [%$TOPIC/jj190808_zh-cn_MSDN_10_63_0_5%] 
          [%$TOPIC/jj190808_zh-cn_MSDN_10_63_0_6%] 
          [%$TOPIC/jj190808_zh-cn_MSDN_10_63_0_7%] 
          [%$TOPIC/jj190808_zh-cn_MSDN_10_63_0_8%] 
          [%$TOPIC/jj190808_zh-cn_MSDN_10_63_0_9%] 
          [%$TOPIC/jj190808_zh-cn_MSDN_10_63_0_10%] 
          [%$TOPIC/jj190808_zh-cn_MSDN_10_63_0_11%] 
          [%$TOPIC/jj190808_zh-cn_MSDN_10_63_0_12%] 
          [%$TOPIC/jj190808_zh-cn_MSDN_10_63_0_13%] 
          [%$TOPIC/jj190808_zh-cn_MSDN_10_63_0_14%] 
          [%$TOPIC/jj190808_zh-cn_MSDN_10_63_0_15%] 
          [%$TOPIC/jj190808_zh-cn_MSDN_10_63_0_16%] 
          [%$TOPIC/jj190808_zh-cn_MSDN_10_63_0_17%] 
          [%$TOPIC/jj190808_zh-cn_MSDN_10_63_0_18%] 
          [%$TOPIC/jj190808_zh-cn_MSDN_10_63_0_19%] 
          [%$TOPIC/jj190808_zh-cn_MSDN_10_63_0_20%] 
        

除了包含 Main 方法的类之外,该程序具有其他三个类。 类 NeuralNetwork 封装完全连接的前向式神经网络。 所有核心程序逻辑都包含在此类中。 类 Helpers 包含六个实用工具例程。 类 Particle 定义粒子群优化算法在 NeuralNetwork 类的 Train 方法中使用的粒子对象。 分类程序的一个特性是存在许多可能的程序结构;此处展示的组织仅仅是其中一个可能性。

生成原始数据文件

在大多数分类方案中,您已具有一组原始数据,但对于本文,我使用方法 MakeData 创建了虚拟原始数据。 下面是伪代码中的进程:

这里的目标是获取具有百分之百精确性的可明确分类的一些数据,而非不清楚分类方法有效性如何的随机数据。 换言之,我使用某个神经网络创建原始数据,然后重新开始使用并使用神经网络尝试对这些数据进行分类。

创建定型矩阵和测试矩阵

在使用一组现有数据执行分类分析时,一个常见的方法(称作似然度验证)是将数据拆分成两部分,其中一个较大的数据集(通常是 80%)用于对神经网络进行定型,另一个较小的数据集 (20%) 用于对模型进行测试。 定型意味着找到将某个误差值降至最低的神经网络权重和偏置。 测试意味着使用一些精确性度量值通过在定型过程中发现的最佳权重对神经网络进行评估。 在这里,方法 MakeTrainAndTest 创建定型矩阵和测试矩阵,并且还规范化数字输入数据以及对分类输出数据进行编码。 在伪代码中,该方法的工作方式如下:

方法签名为:

称作 file 的参数是要创建的原始数据文件的名称。 参数 trainMatrix 和 testMatrix 是用于放置结果的输出参数。 该方法的开头如下所示:

此代码计算原始数据文件中的行数,然后计算多少行构成 80% 的数据,多少行构成 20% 的数据。 这里的这些百分比是硬编码的;您可能要对它们执行参数化。 接下来,将分配存放所有数据的矩阵:

共有七列数据: 四个数字输入各有一列,分类的颜色变量的 1-of-N 编码值有三列。 请注意,对于此示例,目标是预测颜色,颜色可以是以下三个分类值之一: red、green 或 blue。 在此情况下使用 1-of-N 技术进行编码意味着将红色编码为 (1.0, 0.0, 0.0)、将绿色编码为 (0.0, 1.0, 0.0) 以及将蓝色编码为 (0.0, 0.0, 1.0)。 分类数据必须以数字形式进行编码,因为神经网络仅直接处理数值。 事实证明,使用简单方法(例如 1 表示红色、2 表示绿色以及 3 表示蓝色)对颜色进行编码是错误的思路。 要说明这种想法为什么错误的篇幅稍有点长,因此不在本文的论述范围内。

针对分类输出数据的 1-of-N 编码指导原则有一个例外,就是在只有两个可能值(例如“male”或“female”)时,可以使用具有单个数字输出值的 1-of-(N-1) 编码,这样,就上面的例子而言,0.0 表示男性,1.0 表示女性。

该编码由下面的代码执行:

请注意,一行原始数据如下:

8.0 5.0 9.0 5.0 green


使用 String.Split 对这五个字段进行分析。 经验证明,在大多数情况下,在数字输入是 -1.0 和 +1.0 范围内的值时,可以获得更好的结果。 通过对前四个数字输入中的每个输入都先乘以 0.25 再减去 1.25,转换这些输入。 请注意,这个虚拟的数据文件中的数字输入都介于 1.0 和 9.0 之间。 在真实的分类问题中,您需要对原始数据进行扫描,并且确定最小值和最大值。 我们希望 -1.0 对应于 1.0,+1.0 对应于 9.0。 执行线性转换意味着查找斜率(此处为 0.25)和截距 (-1.25)。 这些值可计算为:

有许多可用于对数字输入值执行线性转换的方法,但本文中介绍的方法十分简单,并且在大多数情况下都是很好的起点。

在已转换了四个数字输入值后,将使用 1-of-N 编码对来自原始数据文件的颜色值进行编码。 在来自原始数据文件的所有值都已计算并放置于 allData 矩阵中之后,该矩阵将使用 Helpers 类中的 ShuffleRows 实用工具方法随机重新排列其行。 在 allData 中行的顺序已打乱后,将分配针对矩阵 trainMatrix 和 testMatrix 的空间,然后将 allData 的前 numTrain 行复制到 trainMatrix,将 allData 的其余 numTest 行复制到 testMatrix。

针对此定型-测试方法的一个重要的设计方案就是将原始数据划分为三组: 定型、验证和测试。 具体的思路是使用定型数据确定一组最佳的神经网络权重以及验证数据(用于知道何时停止定型)。 也有其他方法,统称为交叉验证技术。

Softmax 激活函数

在使用输出变量是分类的神经网络执行分类时,在神经网络输出激活函数中有一个相当棘手的关系,在定型期间计算误差以及计算神经网络的可预测精确性。 在使用 1-of-N 编码对分类输出数据(例如具有值 red、green 或 blue 的颜色)进行编码时,例如,(1.0 0.0 0.0) 表示红色,您希望神经网络生成三个数值,以便您可以在对网络进行定型时确定误差。 不过,您不希望生成三个任意数值,因为这样不会完全清楚如何计算误差项。 但是,假定神经网络生成三个数值,它们全都介于 0.0 和 1.0 之间并且总和是 1.0。 然后,可以将生成的值解释为概率,事实证明,这样可以很容易地在定型时计算误差项以及在测试时计算精确度。 Softmax 激活函数以此形式生成输出值。Softmax 函数接受对输出隐藏的神经总和值,并且返回最终的神经输出值;可按如下所示实现该函数:

从原理上讲,Softmax 函数按以下方式计算比例因子:对每个对输出隐藏的总和执行 Exp 计算,对它们求和,然后将每个值的 Exp 除以比例因子。 例如,假定三个对输出隐藏的总和为 (2.0, -1.0, 4.0)。 比例因子将是 Exp(2.0) + Exp(-1.0) + Exp(4.0) = 7.39 + 0.37 + 54.60 = 62.36。 然后,Softmax 输出值将是 Exp(2.0)/62.36, Exp(-1.0)/62.36, Exp(4.0)/62.36) = (0.12, 0.01, 0.87)。 请注意,最终的输出全都介于 0.0 和 1.0 之间并且实际求和结果为 1.0,进一步说,最大的对输出隐藏的总和 (4.0) 具有最大的输出/概率 (0.87),并且对于第二最大值和第三最大值而言该关系是类似的。

但遗憾的是,Softmax 函数的简单实现常常会失败,因为 Exp 函数很快就会变得非常大并且会生成算术溢出。 前面的实现使用 Exp(a - b) = Exp(a) / Exp(b),以便用避免溢出的方式计算输出。 如果您将 (2.0, -1.0, 4.0) 用作输入来跟踪实现的执行,将会得到与在之前部分中说明的相同的 (0.12, 0.01, 0.87) 输出。

互熵误差

对神经网络进行定型的本质是找到一组权重,对于对定型集中的数据,这组权重产生最小的误差。 例如,假定一行规范化的、已编码的定型数据为 (0.75 -0.25 0.25 -0.50 0.00 1.00 0.00)。 请记住,前四个值是规范化输入,最后三个值在 1-of-N 编码中表示绿色。 现在假定输入通过神经网络馈送,该神经网络已加载有某组权重,并且 Softmax 输出为 (0.20 0.70 0.10)。 为此测试向量计算误差的传统方法是使用方差和,在此例子中是 (0.00 - 0.20)^2 + (1.00 - 0.70)^2 + (0.00 - 0.10)^2 = 0.14。 但假定 Softmax 输出为 (0.30 0.70 0.00)。 此向量以及之前的向量都预测输出是绿色,因为绿色的概率是 0.70。 但是,第二个向量的方差和是 0.18,这与第一个误差项不同。 尽管方差和可用于计算定型误差,但某些研究结果表明,使用称作互熵误差的其他测量方法更可取。

从原理上讲,某一给定神经网络输出向量 v 和测试输出向量 t 的互熵误差是通过每个 v 向量分量和相应的 t 向量分量的乘积的负求和来确定的。 最好地解释这个方法的依然是示例。 如果某个测试向量为 (0.75 -0.25 0.25 -0.50 0.00 1.00 0.00) 并且相应的 Softmax 神经网络输出为 (0.20 0.70 0.10),则相应的互熵误差是 -1 * (0.00 * Log(0.20)) + (1.00 * Log(0.70)) + (0.00 * Log(0.10)) = -1 * (0 + -0.15 + 0) = 0.15。 请注意,在使用 1-of-N 编码时,除了一个之外,总和中的所有项都将是零。 整个定型集的互熵误差可计算为所有测试向量的互熵的总和,或者每个测试向量的平均互熵。 互熵误差的实现在图 4 中列出。

图 4 互熵误差

对神经网络进行定型

有许多方法可以对神经网络分类器进行定型,以便找到最好地匹配定型数据(或者,也可以说生成最小的互熵误差)的一组权重值。 在高抽象级别,对神经网络进行定型的方式如下:

迄今为止,用于对神经网络进行定型的最常见技术称作反向传播。 有大量研究文章都在论述这个技术 — 数目是如此之多,实际上,如果您是神经网络分类领域中的新手,可能很容易就会因此误认为反向传播是用于定型的唯一技术。 评估某一神经网络的权重的最佳集合是一个数字最小化问题。 对使用反向传播的两个常见的替代方法是使用真实值遗传算法(也称作进化优化算法)和使用粒子群优化。 每种评估技术都各有优缺点。 图 1 中显示的程序使用粒子群优化。 我在《MSDN 杂志》2012 年 6 月刊 (msdn.microsoft.com/magazine/jj133825) 中介绍了进化优化算法,在 2011 年 8 月刊 ( msdn.microsoft.com/magazine/hh335067) 中介绍了粒子群优化。

有许多技术可用于确定何时停止对神经网络的定型。 尽管在互熵误差非常接近于零(指示接近完美拟合)之前只需让定型算法运行就行了,但这样做的危险在于,最终生成的权重将过度拟合定型数据,并且这些权重所创建的神经网络对不在定型集中的数据进行分类的效果会很差。 此外,定型直到互熵误差中没有变化可能很容易就会导致模型过度拟合。 由示例程序使用的简单方法会将定型限制为固定数目的迭代。 在大多数情况下,避免过度拟合的一个好得多的方法是将源数据集拆分为定型-验证-测试集。 通常,这三个数据集分别使用源数据的 60%、20% 和 20%。 该技术如前所述对定型集计算误差,但在主循环中的每次迭代后,该技术都将对验证数据集计算互熵误差。 在针对验证集的互熵误差开始显示误差在稳步增加时,很可能定型算法已开始过度拟合数据并且定型应该中止。 还有其他许多可能的停止技术。

对神经网络分类器进行评估

在神经网络分类器已定型并且生成了一组最佳权重和偏置后,下一步是确定对于测试数据而言,最终生成的模型的精确度(其中,模型意味着具有一组最佳权重的神经网络)。 尽管可以使用方差和或互熵误差之类的度量值,但精确度的合理度量值只不过是该模型生成的正确预测的百分比。 再次重申,有若干方法可用于测量精确度,但一个简单的方法是使用称作 winner-takes-all 的方法。 还是要用示例来很好地解释这个技术。 假定某个测试向量为 (-1.00 1.00 0.25 -0.50 1.00 0.00 0.00),如图 1 中第一组预测数据所示。 神经网络使用一组最佳权重,生成预测的 Softmax 输出 (0.9 0.1 0.0)。 如果每个输出都解释为概率,则最高概率为 0.9,并且预测的输出可视作 (1 0 0),这样,该模型将作出正确的预测。 换句话说,winner-takes-all 技术确定具有最大值的神经网络输出分量,使该分量为 1,所有其他分量均为 0,并且将该结果与定型向量中的实际数据进行比较。 图 1 的第三组精确性分析数据中,测试向量为 (-0.50 0.75 0.25 -0.75 0.0 0.0 1.0)。 实际输出数据为 (0.0 0.0 1.0),这对应于蓝色。 预测的输出为 (0.3 0.6 0.1)。 最大的分量是 0.6,因此,模型预测是 (0 1 0),这对应于绿色。 该模型生成了错误的预测。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值