在机器学习的世界里,神经网络(Neural Networks,简称NN)是一种模仿人脑结构和功能的计算模型。本文将通过一个简单的三层神经网络示例,介绍如何使用Excel进行神经网络的构建和训练。这个网络包含两个隐藏层,每层有两个神经元。通过这个过程,可以更深入地理解机器学习的工作原理,并且能够亲手实现自己的神经网络模型。
机器学习是一个充满挑战和乐趣的领域。虽然市面上有许多现成的框架和API,但深入了解其背后的原理同样重要。本文的写作灵感来源于Matt Mazur的博客文章《A Step by Step Backpropagation Example》,接下来将基于这篇文章的内容,一步步构建神经网络。
神经网络由多层神经元组成,每层神经元的数目可以是可变的。第一层是输入层,最后一层是输出层,中间可以有一个或多个隐藏层。例如,如果使用神经网络来分类图像,输入层的神经元数量将等于图像的像素数量。输出层的每个神经元则代表图像的一种分类(如动物、花朵或数字)。
在开始计算之前,需要用随机数初始化神经网络中所有权重的值。下面是一个Excel电子表格的截图,它将作为本文后续内容的参考。建议在阅读本文时,保持该电子表格窗口的打开状态,以便更好地理解计算过程。
前向传播是神经网络中信息从输入层流向输出层的过程。每个神经元的值是通过将前一个神经元的值乘以其权重,然后求和得到的。此外,还会加上一个没有对应神经元的偏置权重。例如,计算公式可以表示为:
F3 = A3 * B3 + A7 * B4 + B5
然后,通过激活函数对值进行归一化。在神经网络中,有多种不同的激活函数可以使用。本文中,使用的是逻辑斯蒂函数:
G3 = 1 / (1 + EXP(-F3))
输出层的神经元也以相同的方式计算:
L3 = G3 * H3 + G7 * H4 + H5
M3 = 1 / (1 + EXP(-L3))
接下来,计算输出层每个神经元的误差。误差是通过将实际输出值与期望值(或目标值)进行比较得到的。例如,对于列Q中的误差:
Q3 = (M3 - O3)²
Q7 = (M7 - O7)²
总误差R5是所有误差的平均值,随着网络的训练,这个值应该越来越接近零:
R5 = (Q3 + Q7) / 2
神经网络的训练是通过反复传递大量训练数据来实现的。在每次迭代中,计算误差和增量,然后对所有权重进行微调,使网络的性能越来越好。这个过程被称为反向传播。
由于总误差可以表示为每个权重的数学函数,可以通过求导这些函数来获得函数曲线在某一特定点的斜率。斜率指示了总误差最小化的方向,以及为了使总误差接近零,每个权重应该调整多少。
对于每个权重,计算其增量值。增量值存储在列I和D中,分别对应输出层和隐藏层。
在实践中,希望对输出层的第一个权重H3求总误差R5的导数。首先,需要使用代换将R5表示为H3的函数。由于:
R5 = (Q3 + Q7) / 2
R5 = (M3 - O3)² / 2 + (M7 - O7)² / 2
上述函数看起来不太容易求导。可以使用链式法则来简化这个过程。链式法则表明,如果有一个由两个或更多函数组成的复合函数f(g(x)),并且让F(x) = f(g(x)),那么可以这样求导:
F'(x) = f'(g(x)) * g'(x)
在案例中,有以下依赖关系:
R5(M3(L3(H3)))
可以写出:
Step 9. Output layer Deltas
输出层的总误差函数R5相对于输出层的第一个权重H3求导。在上面的公式中,使用了链式法则来简化求导过程。由于:
P3 = (M3-O3) * M3 * (1 - M3)
最后一个链式导数更简单。由于:
L3 = G3 * H3 + G7 * H4 + H5
现在可以将所有内容整合在一起,并存储在单元格I3中:
I3 = P3 * G3
输出层的其余权重以相同的方式计算,得到:
P7 = (M7-O7) * M7 * (1 - M7)
I4 = G7 * P3
I5 = 1 * P3 (bias neuron)
I7 = G3 * P7
I8 = G7 * P7
I9 = 1 * P7 (bias neuron)
在这一步中,计算:
前几步中的链式法则有助于将其转换为可以利用的形式:
首先,必须将第一项分解为两个错误Q3和Q7:
首先看这个:
可以进一步分解如下:
第一个问题已经解决。
现在来看第二个问题。知道:
已经学会了如何求逻辑函数的导数。现在:
因为:
现在将上述内容整合在一起,得到一个关于隐藏层第一个权重的总误差导数的表达式。这个值存储在单元格C3中。
C3 = (P3 * H3 + P7 *H7) * (G3 *(1 - G3)) * A3
上述计算对所有隐藏层权重重复进行:
C4 = (P3 * H3 + P7 *H7) * (G3 *(1 - G3)) * A7
C5 = (P3 * H3 + P7 *H7) * (G3 *(1 - G3)) * 1
C7 = (P3 * H4 + P7 *H8) * (G7 *(1 - G7)) * A3
C8 = (P3 * H4 + P7 *H8) * (G7 *(1 - G7)) * A7
C9 = (P3 * H4 + P7 *H8) * (G7 *(1 - G7)) * 1
现在,使用选定的学习率(存储在单元格A13中),可以很容易地计算新的权重。例如:(新的B3)
D3 = B3 - C3 * A13
Excel文档中有一个与训练按钮连接的宏。该宏多次迭代,可以观察到列M中的输出神经元越来越接近其目标值,R5中的总误差也越来越接近零。
在版本1.1中,发现通过使用激活函数Leaky Relu可以提高学习率和准确性:
f(x) = x if x > 0 otherwise f(x) = x/20
将逻辑函数替换为Leaky Relu可能是一个很好的练习。
提示:
G3 = IFS(F3 > 0; F3; F3 <= 0; F3/20)
P3= (M3-O3) * IFS(M3 > 0; 1; M3<= 0; 1/20)
(同时附上新版本的xls文件,以防万一...)