通过在 C# 中实现神经网络真正理解它们






2.45/5 (5投票s)
如何在 C# 中实现神经网络?
引言
神经网络是一种受人脑生物神经网络功能启发的计算模型,由相互连接的节点或人工神经元组成,并组织成层。信息通过这些层进行处理,每个连接都有一个在学习过程中调整的关联权重。神经网络通常用于机器学习中,以识别模式、做出预测并根据数据输入执行各种任务。
我们将在后续的帖子中深入探讨此定义的细节,展示神经网络如何优于其他方法。特别是,我们将从逻辑回归开始,并通过一个简单的例子来说明它可能存在的不足,以及深度学习如何相反地具有优势。一如既往,我们将采取循序渐进的方法,逐步解决与此数据结构相关的挑战。
我们在撰写本系列文章时参考了以下书籍。
本系列文章最初发布于 此处。
什么是逻辑回归?
在本帖中,我们不会深入探讨逻辑回归的细节,因为我们之前已经用一个完整的系列来讨论过这个主题。我们在此将读者引导至此 链接。在这里,我们将简要回顾最终结果。
逻辑回归是一种用于二分类问题的统计方法,其中结果变量有两种可能的类别。它模拟一个实例属于特定类别的概率,并且其预测形式为介于 0 和 1 之间的概率。采用逻辑函数 σσ (sigmoid) 将输入特征的线性组合转换为概率分数。
重要
逻辑回归中出现的 Sigmoid 函数并非任意选择,可以通过简单的数学研究推导得出。再次,有关详细解释,请参阅我们之前的帖子。
观察逻辑回归的实际应用
为了观察逻辑回归的实际应用,我们将通过下面概述的简单示例,使用 ML.NET 快速实现它,其中对于 2 维输入有两种可能的输出。
下面展示了相应的数据集
X;Y;Category
0.12;0.154;1
0.135;0.26;1
0.125;0.142;1
0.122;0.245;1
0.115;0.142;1
0.132;0.2;1
0.84;0.76;0
0.834;0.8;0
0.855;0.78;0
0.865;0.84;0
0.835;0.82;0
0.82;0.745;0
...
使用 ML.NET 实现逻辑回归
ML.NET 是微软开发的开源机器学习框架,允许开发人员将机器学习模型集成到其 .NET 应用程序中。ML.NET 支持各种机器学习任务,包括分类、回归、聚类和推荐。
下面提供了使用逻辑回归的 C# 代码
static void Main(string[] args)
{
var ctx = new MLContext();
// Load data from file
var path = AppContext.BaseDirectory + "/dataset.csv";
var data = ctx.Data.LoadFromTextFile<DataRecord>
(path, hasHeader: true, separatorChar: ';');
var dataPipe = ctx.Transforms.Concatenate("Features", new[]
{
"X", "Y"
}).Append(ctx.BinaryClassification.Trainers.LbfgsLogisticRegression
(featureColumnName: "Features"));
var model = dataPipe.Fit(data);
// Predict an unforeseen input
var record = new DataRecord()
{
X = 0.25f,
Y = 0.24f
};
var pe = ctx.Model.CreatePredictionEngine<DataRecord, DataRecordPrediction>(model);
var category = pe.Predict(record);
}
以下是一些生成输入值的预测值。
X | Y | 预测 |
0.25 | 0.24 | 1 |
0.05 | 0.02 | 1 |
0.92 | 0.86 | 0 |
0.5 | 0.55 | 0 |
这个例子是一个简化的例子,因为数据是明显可分的,使得逻辑回归这样的方法可以相对容易地预测正确的值。但是,该算法在处理更复杂的数据集时表现如何?
如果数据不是线性可分的怎么办?
我们现在将逻辑回归应用于下图所示的数据集。它比之前的数据集明显更复杂(尽管它仍然是二维空间,便于数据可视化),最重要的是,数据不是线性可分的。目标是观察逻辑回归在这种情况下如何表现。
我们将使用与上面相同的 C# 代码(数据不同),并观察一些预测值。
X | Y | 预测 |
-0.25 | 0.24 | 0 |
0.45 | -0.72 | 0 |
0.92 | 0.86 | 0 |
-0.5 | -0.55 | 0 |
这里,显然许多预测值都是不准确的。该算法始终返回相同的预测概率 (0.5),表明它无法适应当前特定的问题。
这是正常的,因为我们必须记住,逻辑回归将 Sigmoid 函数应用于线性数据,并且只能有效地分离线性可分的数据。在给定的样本中显然不是这种情况,因此此方法证明是不合适的。
是否可以缓解这种现象?
简而言之,答案是肯定的:理论上,存在可以解决此问题的数学方法,我们将在下一篇文章中观察它们。更长的答案是,实际上,这可能非常具有挑战性。
那么,如何克服这个问题?
这个想法并不具有革命性,它只是涉及在输入数据上应用一个固定的非线性变换 ff,而不是直接处理原始输入。
然后将逻辑回归算法应用于新的数据集。
信息 1
将输入空间映射到另一个空间以使数据在该新空间中线性可分或更易于处理的方法是核方法(从中我们可以推导出支持向量机和类似技术)的基础。如果应用得当,此过程可能非常有益,并具有显著的优势。
信息 2
在上图中,为了表示方便,两个空间具有相同的维度,但实际上,它们不必相同。
我们应该如何处理我们 cases?
这个过程起初听起来可能有些理论化和抽象,但我们将在上一篇文章的示例中看到如何将其付诸实践。为此,我们将对输入应用以下函数。
f(X,Y)=XY
以下是此映射的一些值的結果
XX | YY | f(X,Y)f(X,Y) |
-0.9 | 0.5664324069 | -0.509789165 |
0.89 | -0.4208036774 | -0.374515273 |
0.18 | 0.9626599405 | 0.173267893 |
... | ... | ... |
信息
在我们的例子中,最终空间是 1 维空间,而输入空间是 2 维空间。这绝不是一个普遍的经验法则:最终空间可以比输入空间大得多。
将逻辑回归算法应用于新数据集
对输入空间执行映射后,只需将逻辑回归应用于新数据集,我们就有望做出准确的预测。显然,在被训练模型评估之前,必须先将预测值映射到新空间。
XX | YY | f(X,Y)f(X,Y) | 预测 |
-0.25 | 0.24 | -0.06 | 1 |
0.05 | -0.02 | -0.001 | 1 |
0.92 | 0.86 | 0.7912 | 0 |
-0.5 | -0.55 | 0.275 | 0 |
现在预测是完全准确的。
这种方法的缺点是什么?
我们上面开发的数学方法似乎非常适合具有不规则形状的数据:它基本上涉及在空间之间进行神奇的映射,以使数据在最终空间中线性可分。
然而,挑战在于如何识别这种映射。在我们的玩具示例中,推导出变换相对容易,因为我们可以图形化地可视化数据。但现实世界场景涉及更多的维度和更复杂的数据,这些数据可能难以或不可能可视化。这确实是此过程的主要问题:我们永远无法确定在最终空间中,我们的数据是否具有明显的线性可分性。
这是否意味着当前的方法没有成效?绝对不是!虽然我们可以坚持将数据映射到另一个空间的概念思想,但关键在于完善执行此映射的过程。设想一下自动发现这种映射而不是依赖猜测的前景,这难道不是一个重大的进步吗?这种自动化是存在的:进入神经网络和深度学习。
什么是神经网络?
我们将讨论多类分类(具有 KK 个类别)神经网络的原理,但以下内容可以轻松地应用于回归。
目标是通过使基函数 ϕ1, ..., ϕD 依赖于参数,然后允许在训练期间与系数 w1, ..., wD 一起调整这些参数来扩展此模型。
神经网络的思想是使用本身是输入的线性组合的非线性函数的基函数。 这就 dẫn đến 了基本神经网络模型,可以将其描述为一系列函数变换。
具体来说它是如何工作的?
我们继续假设我们有一个由 N 条记录组成的数据集,每条记录都有 D 个特征。例如,我们之前的玩具示例有 2 个特征(X 和 Y)。
- 构造输入变量 x1, ..., xD 的 M 个线性组合 a1, ..., aM
信息
M 是什么,它代表什么?目前这并不重要,但这个公式背后的直观想法是从我们原始的 D 维输入空间映射到另一个 M 维特征空间。我们将在本帖稍后重新讨论这一点。
在二元分类的情况下,σ 可以是 Sigmoid(或其他激活函数),在回归的情况下,可以是恒等函数。
信息 1
我们可以看到,输出的最终表达式比简单逻辑回归的表达式复杂得多。这种复杂性提供了灵活性,因为现在我们将能够模拟复杂的配置(例如非线性可分数据),但代价是学习复杂性。我们现在需要调整的权重更多,并且用于此任务的算法并不简单。正是这种复杂性阻碍了神经网络在 80 年代末的发展。
信息 2
通过自定义激活函数,可以进一步推广神经网络;例如,我们可以使用 tanh 代替 Sigmoid。
通常以图形形式表示神经网络,如下所示。
这种图形表示法比数学形式有几个优点,因为它强调了两个关键点。
- 首先,我们可以考虑更多的处理层。
信息
层数越多,神经网络就越灵活。在此背景下,人们可能会认为增加层数最终将使模型能够处理所有现实情况(这是深度学习的前提)。然而,这种方法会显着增加学习参数的复杂性,因此需要大量的计算资源。
- 其次,我们可以看到 M 代表“隐藏”单元的数量。“隐藏”一词源于这些单元不是输入层或输出层的一部分,而是存在于中间层,它们有助于网络从数据中学习复杂模式和表示的能力。
信息
M 必须明智地选择:如果 M 太小,神经网络可能难以准确地泛化。另一方面,如果 M 太大,则存在过拟合的风险,并伴随着学习参数的增加。
神经网络的输入和输出单元的数量通常由数据集的维度决定,而隐藏单元的数量 M 是一个自由参数,可以进行调整以获得最佳的预测性能。
Bishop (模式识别与机器学习)
现在我们已经介绍了形式化并演示了神经网络如何表示复杂配置,是时候探索过程中涉及的参数和权重是如何学习的了。我们将深入研究为此目的开发的专用过程。
为避免本文过于冗长,对实现和反向传播算法感兴趣的读者可以在 此处 找到续集。
历史
- 2024 年 1 月 17 日:初始版本