理解神经网络

理解神经网络

神经网络是机器学习领域中最强大、应用最广泛的算法之一。乍一看,神经网络似乎是个黑盒子;输入层将数据输入到“隐藏层”中,经过一个魔术之后,我们可以看到输出层提供的信息。然而,理解隐藏层在做什么是神经网络实现和优化的关键步骤。

在我们理解神经网络的道路上,我们将回答三个问题:

  • 什么是神经网络
  • 神经网络是如何工作的
  • 为什么神经网络能够学习

什么是神经网络?

我们将要考虑的神经网络被严格地称为人工神经网络,顾名思义,它是基于科学对人脑结构和功能的了解。

简单地说,神经网络被定义为一种计算系统,它由许多简单但高度互联的元素或节点组成,称为“神经元”,这些元素或节点被组织成层,利用外部输入的动态状态响应处理信息。在这种结构的上下文中,输入层将模式引入到神经网络中,输入层为输入数据中出现的每个组件都有一个神经元,并与网络中出现的一个或多个隐藏层进行通信;之所以称为“隐藏”,是因为它们不构成输入或输出层。在隐藏层中,所有的处理实际上都是通过一个以权重和偏差(通常称为W和b)为特征的连接系统进行的:接收输入,神经元计算加权和添加偏差并根据结果和一个预设激活函数(最常见的一个是sigmoid,σ),它决定是否应该“fired”或激活。之后,神经元将信息传递到下游的其他连接的神经元,这个过程被称为“forward pass”。在这个过程的最后,最后一个隐藏层被连接到输出层,输出层对于每个可能需要的输出都有一个神经元。

理解神经网络

2层神经网络的基本结构

Wi:相应连接的权重。注意:计算网络中存在的层数时,不包括输入层。

神经网络如何工作?

现在我们已经了解了神经网络基本结构的外观,我们将继续解释它是如何工作的。为了做到这一点,我们需要解释我们可以包含在网络中的不同类型的神经元。

我们要解释的第一种神经元是Perceptron。即使它的使用已经在今天衰退,了解它们如何工作将为我们提供关于更多现代神经元如何运作的良好线索。

感知器使用函数通过将二进制变量的矢量映射到单个二进制输出来学习二元分类器,并且它还可以用于监督学习。在这种情况下,感知器遵循以下步骤:

  1. 将所有输入乘以其权重w, 表示相应输入对输出的重要程度的实数,
  2. 将它们加在一起称为加权和:Σwjxj,
  3. 应用激活函数,换句话说,确定加权和是否大于阈值,其中-threshold等于bias,并指定1 或更小并将0指定为输出。

我们也可以把感知器函数写成这样:

理解神经网络

注意:b是偏差,相当于-threshold,wx是w的点积,是矢量,其中分量是权重,x是由输入组成的矢量。

该算法最突出的一点是,我们可以改变权重和偏差,以获得不同的决策模型。我们可以给这些输入赋予更多的权重,这样如果它们是正的,就会有利于我们想要的输出。另外,因为偏差可以理解为输出1的难易程度的度量,如果我们想让期望的输出或多或少发生,我们可以降低或提高它的值。如果我们注意这个公式,我们可以观察到一个大的正向偏差会使输出1变得非常容易;然而,负的偏见将使输出1的任务变得非常不可能。

因此,感知器可以分析不同的数据,并根据设定的偏好做出决定。事实上,创建更复杂的网络是有可能的,包括更多的感知器层,每一层都取前一层的输出并加权,做出越来越复杂的决定。

如果感知器能很好地做出复杂的决定,为什么我们还需要其他类型的神经元呢?包含感知器的网络的一个缺点是,甚至在只有一个感知器中,权重或偏压的小变化,也会严重地改变从0到1的输出,反之亦然。我们真正想要的是通过引入权重或偏差的小修改来逐渐改变我们网络的行为。这就是一种更现代的神经元派上用场的地方:Sigmoid神经元。Sigmoid neurons和感知器的主要区别在于输入和输出可以是0到1之间的任意连续值。在考虑权重w和偏差b的情况下,将sigmoid函数应用到输入中,得到输出结果。为了更直观的理解,我们可以这样写:

理解神经网络

所以,输出的公式是:

理解神经网络

如果我们对这个函数进行数学分析,我们可以得到我们的函数σ 的图形,如下所示,并得出结论:当z很大且正数时,函数达到其最大渐近值1; 但是,如果z很大且为负,则函数达到其最小渐近值0.这里是sigmoid函数变得非常有趣的地方,因为它具有中等的z值,函数采用平滑且接近线性的形状。在此间隔中,权重(Δwj)或偏差(Δbj)的微小变化将在输出中产生微小变化; 我们所期待的行为是感知器的改进。

z = np.arange(-10, 10, 0.3)
sigm = 1 / (1 + np.exp(-z))
plt.plot(z, sigm, color = 'mediumvioletred', linewidth= 1.5)
plt.xlabel('Z', size = 14, alpha = 0.8)
plt.ylabel('σ(z)', size = 14, alpha = 0.8)
a = plt.title('Sigmoid Function', size = 14)
a = a.set_position([.5, 1.05])

理解神经网络

理解神经网络

我们知道一个函数的导数是y值相对于变量x的变化速率的度量,在这种情况下,变量y是我们的输出变量x是权重和偏差的函数。我们可以利用这一点,用导数来计算输出的变化,特别是偏导数(关于w和关于b的)。在sigmoid函数中,导数将被缩减为计算:f(z)*(1-f(z))。

这里有一个简单的Python代码,可以用来建模一个sigmoid函数:

'''Build a sigmoid function to map any value to a value between zero and one
",
Refers to case of logistic function defined by: s(z) = 1/(1+e^-z)
which derivative is bell shape. derivative is equal to f(z)*(1-f(z))'''
def sigmoid(x, deriv = False):
 if deriv == True:
 return x*(1-x)
 return 1/(1+np.exp(-x))

理解神经网络

我们刚刚解释了我们网络中每个神经元的功能,现在,我们可以检查其余神经元是如何工作的。将来自一层的输出用作下一层的输入的神经网络称为前馈,特别是因为不涉及循环并且信息仅pass forward而从不返回。

假设我们有一个训练集,我们想要使用一个3层神经网络,我们也使用上面看到的sigmoid神经​​元来预测某个特征。根据我们对神经网络结构的解释,需要首先将权重和偏差分配给一层​​中的神经元与下一层中的神经元之间的连接。通常,偏差和权重都在突触矩阵中随机初始化。如果我们在python中编码神经网络,我们可以使用Numpy函数np.random.random 生成高斯分布(其中均值等于0,标准差为1)。

#Create Synapsis matrix
syn0 = 2+np.random.random((3,4)) -1
syn1 = 2+np.random.random((4,1)) -1

理解神经网络

之后,我们将从前馈步骤开始构建神经网络,以计算预测输出; 换句话说,我们只需要构建网络中涉及的不同层:

  • layer0是输入层; 我们的训练集读作矩阵(我们可以称之为X)
  • layer1通过应用激活函数a'=σ(w.X + b)获得,在我们的例子中,执行输入layer0和突触矩阵syn0之间的点乘
  • layer2是通过layer1它和它的突触之间的点乘法获得的输出层syn1

我们还需要迭代训练集以让网络学习。为此,我们将添加for 循环。

#For loop iterate over the training set
for i in range(60000):
 
 #First layer is the input
 layer0 = X
 
 #Second layer can be obtained with the multiplication of each layer 
 #and its synapsis and then running sigmoid function 
 layer1 = sigmoid(np.dot(layer0, syn0))
 
 #Do the same with l1 and its synapsis 
 layer2 = sigmoid(np.dot(layer1,syn1))

理解神经网络

到目前为止,我们已经创建了神经网络的基本结构:不同的层,神经元之间连接的权重和偏差,以及sigmoid 函数。但这些都没有解释神经网络如何在预测数据集中的模式方面做得如此出色。这就是我们最后一个问题。

为什么神经网络能够学习?

机器学习算法的主要优势在于它们每次预测输出时都能学习和改进。但他们能学到什么意味着什么呢?在神经网络的背景下,它意味着定义神经元之间连接的权重和偏差变得更加精确; 最后,选择权重和偏差,例如来自网络的输出近似于所有训练输入的实际值y(x)。

那么,为了让我们知道是否需要继续寻找更精确的参数,我们如何量化我们的预测与实际值的距离?为了这个目标,我们需要计算一个误差,或者换句话说,定义一个成本函数(成本函数不是预测网络正确输出的误差;换句话说,这就是预期和预期输出的差值)。在神经网络中,最常用的是二次成本函数,也称为均方误差,公式定义为:

理解神经网络

w和b分别表示网络中的所有权重和偏差。n是训练输入的总数。a是输出,而x是输入。Σ是所有训练输入的总和。

该函数优于线性误差,因为在神经网络中,权重和偏差的微小变化不会使正确输出的数量发生任何变化; 因此,使用二次函数,其中较大的差值对成本函数的影响比小的差异更有助于确定如何修改这些参数。

另一方面,我们可以看到,对于所有训练输入,我们的成本函数随着输出更接近实际值y而变小。我们算法的主要目标是通过找到一组权重和偏差来使这个成本函数最小化,以使其尽可能小。实现这一目标的主要工具是一种名为Gradient Descent的算法。

那么,我们应该回答的下一个问题是如何最大限度地降低成本函数。从微积分中,我们知道函数可以具有全局最大值和/或最小值,即函数实现其可以具有的最大值或最小值。我们也知道获得这一点的一种方法是计算导数。但是,当我们有一个带有两个变量的函数时,很容易计算,但在神经网络的情况下,它们包含许多变量,这使得这个计算很难完成。

让我们看一下随机函数,如下图:

理解神经网络

我们可以看到这个函数具有全局最小值。正如我们之前所说,我们可以计算导数以计算最小值的位置,或者我们可以采用另一种方法。我们可以从一个随机点开始尝试沿箭头方向做一个小的移动,我们在数学上说,在x方向上移动Δx,在y方向上移动Δy,并计算我们的函数ΔC的变化。因为方向的变化率是函数的导数,我们可以将函数的变化表示为:

理解神经网络

在这里,我们将从函数梯度的微积分中定义:

理解神经网络

函数的梯度:具有偏导数的向量

现在,我们可以将函数中的更改重写为:

理解神经网络

C的梯度将函数C的变化与(x,y)的变化联系起来

现在,我们可以看到当我们选择参数的某个变化时,成本函数会发生什么。我们选择向任何方向移动的数量称为学习率,它定义了我们向全局最小化移动的速度。如果我们选择一个非常小的数字,我们需要做出太多的动作来达到这一点; 但是,如果我们选择一个非常大的数字,我们就有可能超越这一点而永远无法达到它。所以挑战在于选择足够小的学习率。选择学习率后,我们可以更新我们的权重和偏见,并采取另一种行动; 我们在每次迭代中重复的过程。

因此,简而言之,梯度下降通过重复计算梯度∇C,然后更新权重和偏差,并试图找到最小化值来实现。这就是神经网络学习的方式。

有时候,计算梯度可能非常复杂。然而,有一种方法可以加速这种计算,叫做随机梯度下降法。这是通过估算梯度∇C通过计算梯度而不是随机选择的小样本训练的输入。然后,将这些小样本平均起来,就能很好地估计出真实的梯度,加速梯度下降,从而学习得更快。

但是我们如何计算成本函数的梯度呢?这是另一个算法的地方:反向传播。该算法的目标是计算关于任何权重w和任何偏差b的成本函数的偏导数;实际上,这意味着计算从最终层开始的误差矢量,然后将其传播回以更新权重和偏差。我们需要回去的原因是成本是网络输出的函数。我们可以观察公式。

理解神经网络

反向传播算法给出的四个基本公式,可用于实现神经网络

反向传播算法仅针对一个训练示例计算成本函数的梯度。因此,我们需要将反向传播与学习算法相结合,例如随机梯度下降,以便计算所有训练集的梯度。

现在,我们如何将它应用于python中的神经网络?在这里,我们可以逐步看到计算结果:

#Compute the error by checking how far the prediction 
 #is from the real value.
 l2_error = y - l2
 
 #multiply error rate by result of sigmoide on l2 to get derivative
 #from output
 #Delta will be use to reduce error rate of prediction when update syn 
 
 #FORMULA 1
 l2_delta = l2_error*sigmoid(l2, deriv=True)
 
 #How much l1 contributed to error in l2. Multiply
 #layer2_delta with syn1 transpose. 
 l1_error = l2_delta.dot(syn1.T)
 
 #get delta for l1 
 l1_delta = l1_error * sigmoid(l1, deriv=True)
 
 #Update our synapse rates to reduce the error rate every iteration
 #Multiply each layer by a delta
 
 #*BACKPROPAGATION*
 syn1 += l1.T.dot(l2_delta)
 syn0 += l0.T.dot(l1_delta)

理解神经网络

最后

现在我们可以将我们在算法方面看到的所有这些公式和概念放在一起,看看我们如何实现的:

  • INPUT:我们输入一组训练样例,并设置对应于输入层的激活a 。
  • FEEDFORWARD:对于每一层,我们计算函数z = w.a + b,a =σ(z)
  • 输出误差:我们使用上面引用的公式#1计算输出误差。
  • 反向传播:现在我们反向传播误差; 对于每一层,我们计算上面引用的公式#2。
  • 输出:我们使用公式#3和#4计算相对于任何权重和偏差的梯度下降。

当然,还有更多的概念、实现和改进,可以对神经网络进行改进,这些神经网络已经在过去的几年里越来越广泛地被使用。但我希望本文能告诉你什么是神经网络,它是如何工作的,以及它是如何利用梯度下降和反向传播学习的。

相关推荐