深入理解深度神经网络背后的数学(Mysteries of Neural Networks Part I)

本文深入探讨了深度学习神经网络的工作原理,从单个神经元到多层网络的构建,解释了激活函数的作用、损失函数的选择以及反向传播算法在训练过程中的应用。通过实例展示了使用Keras构建神经网络的简洁性,并强调了理解这些基本概念对于优化网络结构、超参数调优和选择合适优化器的重要性。
摘要由CSDN通过智能技术生成

原文标题:Deep Dive into Math Behind Deep Networks
原文作者:Piotr Skalski
原文链接:https://medium.com/towards-data-science/https-medium-com-piotr-skalski92-deep-dive-into-deep-networks-math-17660bc376ba

当前我们已经有了很多高水平的专用库和框架比如Keras, TensorFlow 和 PyTorch,我们不再需要特别担心我们权重矩阵的规模或者记住我们决定使用的一系列激活函数的公式推导。当我们需要创建一个神经网络时,即使它有比较复杂的结构,我们也可以通过很少的几行代码将其构建出来。这节省了我们很多找bug的时间并简化了我们的工作。然而只有我们通过学习神经网络背后的知识才能帮助我们对一些像网络结构选择、调节超参数或者优化器起到有效的作用。

Introduction

图一

举个例子我们将解决如上图的二分类问题,所有的点属于两类形式的圆。解决这个问题使用传统的机器学习算法很不方便,但是一个小的神经网络将能很好的解决这个问题。为了解决这个问题我们需要如下图的神经网络结构——五个全连接网络包含不同数量的神经元。隐藏层采用ReLU激活函数,输出层使用Sigmoid激活函数。这是一个很简单的结构,但是足够有用对于上面的问题。
在这里插入图片描述

KERAS solution

接下来展示一下用比较流行的机器学习库KERAS构建上面的神经网络。

from keras.models import Sequential
from keras.layers import Dense

model = Sequential()
model.add(Dense(4, input_dim=2,activation='relu'))
model.add(Dense(6, activation='relu'))
model.add(Dense(6, activation='relu'))
model.add(Dense(4, activation='relu'))
model.add(Dense(1, activation='sigmoid'))

model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
model.fit(X_train, y_train, epochs=50, verbose=0)

可以看到正如introduction中所描述的通过很少的几行代码就能创建一个模型进行对数据集的数据分类并达到接近100%的准确率。我们的任务归结于对选定的结构提供超参数(层的数量、每层神经元个数、激活函数、训练的回合数)下图为训练过程背后的效果图。
在这里插入图片描述

What are neural networks?

它是一种有生物学启发而来的通过构建计算机程序去学习发现相互独立的数据之间的联系。就像上面的第二张图所示,网络是一系列神经元联结成的层,并且这些层之间以某种方式连接允许进行交流。

Single neuron

每个神经元接收一系列x值作为输入并计算预测值y-hat。向量x实际上包含了训练集中m个例子中的一个的特征值。更重要的是,每个神经元都有自己的一组参数,通常称为w(权重列向量)和b(偏差),在学习过程中会发生变化。在每次迭代中,神经元根据其当前的权向量w计算向量x的值的乘积,并添加偏差。最后,这个计算的结果传递给一个非线性激活函数g。在这里插入图片描述

Single layer

现在我们分析一下一个神经网络层的计算。我们将利用我们在单个神经元部分的知识,并对整个层进行矢量化,将这些计算结合到矩阵方程中。为了统一符号,将所选层的方程写成[l]。顺便说一下,i表示在神经网络层中神经元的索引值。
在这里插入图片描述
还有一个重要的注释:当我们写单个神经元的计算式时,我们使用x-hat和y-hat,分别是特征的列向量和预测值。当转换到层的一般表示法时,我们使用向量a ——代表上一层激活函数的输出。因此,x向量代表0层——输入层的激活函数的输出。层中的每个神经元根据以下公式进行类似的计算:

在这里插入图片描述
为了清晰起见,让我们以第2层为例,写下这些方程:
在这里插入图片描述
如您所见,对于每一层,我们都必须执行许多非常相似的操作。为此目的使用for-loop的效率不是很高,因此为了加快计算速度,我们将对数据进行向量化。首先,通过将权值w的水平向量(转置)叠加在一起,我们将构建矩阵w。类似地,我们将层中每个神经元的偏差叠加在一起,形成垂直向量b。现在没有什么能阻止我们建立一个矩阵方程,它能让我们一次对这一层的所有神经元进行计算。让我们也写下矩阵和向量的维数。
在这里插入图片描述
在这里插入图片描述

Vectorizing across multiple examples

我们到目前为止使用的等式只有一条数据。在神经网络的学习过程中,你通常要处理巨大的数据集,多达数百万个条目。因此,下一步将是跨多个例子的矢量化。让我们假设我们的数据集有m个条目,每个条目有nx个特征。首先,我们将把每一层的垂直向量x、a和z放在一起,分别创建X、A和Z矩阵。然后我们重写之前布置的方程,考虑到新创建的矩阵。(这部分应该是对应batch计算)
在这里插入图片描述
在这里插入图片描述

What is activation function and why do we need it?

激活函数是神经网络的一个关键要素。没有激活函数我们的神经网络将变成很多线性函数的结合体,进而还是一个线性函数。我们的模型的扩张性有限,不超过逻辑回归。非线性元素允许更大的灵活性和在学习过程中创建复杂的功能。激活函数对学习速度也有显著的影响,这是选择它们的主要标准之一。下图展示了一些常用的激活函数。目前,最流行的隐藏层可能是ReLU。我们有时仍然使用sigmoid,特别是在输出层,当我们处理一个二元分类,我们希望从模型返回的值在0到1的范围内。
在这里插入图片描述

Loss function

学习过程进展的基本信息来源是损失函数的值。一般来说,损失函数的设计是为了显示我们离“理想”解有多远。在我们的例子中,我们使用了二分类交叉熵损失函数,但根据我们处理的问题,可以使用不同的函数。我们使用的函数用下面的公式来描述,其值在学习过程中的变化如下所示。它显示了如何随着每次迭代的损失函数的值下降和精度增加。

在这里插入图片描述
在这里插入图片描述

How do neural networks learn?

神经网络学习的过程就是改变W和b参数值以使得损失函数值的最小化的过程。为了实现这一目标,我们将求助于微积分,使用梯度下降法来寻找函数的最小值。在每次迭代中,我们将计算损失函数关于神经网络每个参数的偏导数的值。对于那些不太熟悉这种计算的人,我只想说导数在描述函数斜率方面有很好的能力。正因为如此,我们知道了如何操作变量以便在图中向下移动。为了形成关于梯度下降是如何工作的直觉(并防止你再次入睡),我准备了一个小的可视化。你可以看到,随着每个连续的epoch,我们是如何走向最小值的。在我们的神经网络中,它以同样的方式工作——每次迭代计算的梯度显示我们应该移动的方向。主要的区别在于,在我们的示例性神经网络中,我们有更多的参数要操作。是啊,这么复杂的导数怎么算?
在这里插入图片描述

Backpropagation

反向传播是一个算法它允许我们计算一个非常
复杂的梯度。神经网络的参数调整如下公式:

在这里插入图片描述
在上面的方程中,α代表学习率-一个超参数,它允许你控制执行调整的值。选择学习率是至关重要的——我们设置得太低,我们的NN将学习得很慢,我们设置得太高,我们将无法达到最小值。dW和db的计算采用链式法则,即损失函数对W和b的偏导数,dW和db的size分别与W和b的size相同。下图显示了神经网络内的操作序列。我们清楚地看到向前和向后传播如何协同工作,以优化损失函数。

在这里插入图片描述
在这里插入图片描述

Conclusion

在使用NN时,至少理解这个过程的基础知识会非常有帮助。我认为我提到的事情是最重要的,但它们只是冰山一角。我强烈建议您自己尝试编写这样一个小的神经网络,而不使用高级框架,只使用Numpy。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值