首页 > 其他分享 >从零开始的全连接神经网络中的反向传播

从零开始的全连接神经网络中的反向传播

时间:2022-09-01 08:12:08浏览次数:92  
标签:输出 num inputs self 传播 神经网络 从零开始 反向

从零开始的全连接神经网络中的反向传播

使用 Python 和 NumPy 构建您自己的全连接神经网络的指南。

A dog. Image from 今日医学新闻

温柔的介绍

在巴甫洛夫进行的一项著名研究中,狗只要听到铃声就会受到治疗。最初,狗并没有被令人费解的铃声打扰——它们摇着尾巴做自己的事情。但是当他们发现食物几乎总是伴随着铃声的响起时,他们的大脑将铃声与传入的食物联系起来。结果,每当狗听到铃响时,它们就会蜂拥而至,唾液滴下,准备吃东西。

狗的条件行为是由于 反向传播 在他们自己的神经网络中。用一种过于简单的方式来解释,比如函数 y=f(x) 决定了狗的行为,其中 x 是狗的兴奋剂输入(光、声、触),y 是狗的输出行为(走路、坐,汪)。反向传播训练狗将 x=bell ringing 映射到 y=eat,而最初 x=bell ringing 将指向 y=什么也不做。

现在我们知道什么是反向传播,我们可以使用这种做法来训练将输入 X 映射到所需 Y 的机器算法。在这篇文章中,我将数字识别作为我们希望机器学习的任务,其中输入 X是 28x28 的图像,Y 是图像对应的数字 (0-9)。

前向传播

要了解反向传播,必须了解正向传播并定义一些变量。我们首先定义网络的大 X 和大 Y。

Uppercase X and Y refer to the inputs and outputs of the entire network, while lowercase x and y are the inputs and outputs of a single layer.

在前向传播过程中,每一层接受一个输入 x = 上一层的输出,进行加权和计算,并将 y = 当前层的输出输出到下一层。随着层向上传播(朝向输出层),网络的最终输出 Y 将等于输出层的输出 y。

现在已经了解了前向传播的大图,让我们深入研究单层内的加权和计算。除了输入 x 和输出 y,还有 4 个其他类型的变量:

对于单个神经元,它的权重与该层的输入数量一样多。它还将有一个偏置项 b 和一个指定的激活函数 g(sigmoid、tanh、relu……)。神经元将使用其权重和偏置来计算其输入的偏置加权和,并对其应用激活函数以找到神经元的输出 y。

Weighted sum calculation of a single neuron.

你可能会问,毕竟有一个激活函数有什么意义呢?具有激活函数会增加网络的非线性。没有它,多层网络将崩溃为一层,从而显着降低其复杂性。所以最后一步,a=g(z),并不是没有原因的。

现在我们有了前向传播的数学公式,让我们对其进行编码。

 DenseLayer 类:  
 def __init__(self, num_neurons, num_inputs, activation_func):  
 self.num_neurons = num_neurons  
 self.num_inputs = num_inputs  
 self.activation_func = 激活函数  
 self.x = np.zeros(num_inputs)  
 self.z = np.zeros(num_neurons)  
 self.w = np.random.randn(num_neurons, num_inputs) * 0.01  
 self.b = np.random.randn(num_neurons) * 0.01  
 self.dw = np.zeros((num_neurons, num_inputs))  
 self.db = np.zeros(num_neurons)  
  
 def forward_propagation(self, x):  
 # x 是一个 numpy 维度数组 (#inputs)  
 self.x = x # 将 x 存储为 back prop  
 对于范围内的神经元数(self.num_neurons):  
 z = 0  
 对于范围内的 weight_num(self.num_inputs):  
 z += self.w[neuron_num][weight_num] * x[weight_num]  
 z += self.b[neuron_num]  
 self.z[neuron_num] = z # 存储 z 作为 back prop  
 a = 激活(self.z,self.activation_func)  
 返回一个

在网络上进行前向传播:

 # network 是一个包含所有层的列表  
 对于索引,枚举(网络)中的层:  
 如果索引 == 0:  
 输出 = layer.forward_propagation(x)  
 别的:  
 输出= layer.forward_propagation(输出)  
 output... # 是网络的最终输出

损失和成本函数

现在我们已经获得了 输出 对于网络,我们希望有一种方法来告诉网络是否需要它的输出。这就是损失函数和成本函数发挥作用的地方。

我们首先定义损失函数。

The cross-entropy loss function, also known as logistic loss.

损失函数测量单个训练样本的输出偏离程度,但我们不希望网络仅从一个训练样本中学习,因此我们取所有训练样本的平均损失,并将其称为成本函数。

You may also see the cost function being named as C(x), or E(x), but I like the letter J.

那么我们想用成本函数做什么呢?我们希望将其最小化。如果你回忆一下微积分,我们可以计算导数来解决优化问题。如果我们反复减去当前导数的一部分,我们可以轻轻地滑下斜坡,当导数达到 0 时,我们知道我们正在降落在某种最小值上。

Using derivatives to find global minima.

这就是反向传播和梯度下降背后的重要思想。找到正确的 ∂J/∂w 和 ∂J/∂b 并更新参数,直到梯度达到接近 0 的位置。

Gradient descent is like walking down a hill. Image from 易艾.

反向传播

顾名思义,反向传播向后传播(朝向输入层)。这背后的原因很直观:您希望对对输出有更直接影响的层进行更大的更新,因此您从输出层开始。

回想一下,成本函数是

计算 J 关于输出层的 ŷ = y 的导数

The uppercase L refers to the output layer, while lowercase l refers to the rest of the layers.

如果您自己进行微积分工作,您可能会注意到导数缺少标量 1/m。我故意省略了这个术语,因为这个标量的影响会被学习率(我们稍后会谈到)减轻,所以现在把它放在这里没有意义。

现在已经计算了输出层的∂J/∂a,我们可以向下传播这个导数(朝向输入层),其中每一层将使用输入的∂J/∂a来计算∂J/∂w,∂J/下一层的∂b和∂J/∂a。

这是反向传播的大图。现在的问题是,给定当前层的∂J/∂a,我们如何找到下一层的∂J/∂w、∂J/∂b和∂J/∂a?答案是更多的微积分。

回忆一下前向传播的公式

如果我们对这些公式进行微积分,我们可以找到我们想要的导数。最容易找到的导数是∂J/∂z。

Using chain rule.

有了∂J/∂z,我们可以更容易地计算其他导数

最后,下一层的∂J/∂a,以便我们可以向下传播网络。

现在我们有了所有的公式,我们可以将它们组装成代码。

 def back_propagation(self, da):  
 # da 是一个 numpy 维度数组 (#neurons)  
 da_prev = np.zeros(self.num_inputs)  
 对于范围内的神经元数(self.num_neurons):  
 dz = da[neuron_num] * activation_prime(self.z[neuron_num],  
 self.activation_func)  
 对于范围内的 weight_num(self.num_inputs):  
 self.dw[neuron_num][weight_num] = dz *  
 self.x[weight_num]  
 da_prev[weight_num] += dz * self.w[neuron_num]  
 [weight_num]  
 self.db[neuron_num] = dz  
 返回 da_prev

沿网络反向传播:

 # 前向传播...  
 # 输出层的∂J/∂a  
 da = np.divide(yhat[:, sample_num] - y[:, sample_num], (1 - yhat[:, sample_num]) * y[:, sample_num] + epsilon)  
 对于反向层(网络):  
 da = layer.back_propagation(da)

Epsilon 是一个非常小的数字,可以防止除以 0。我使用 epsilon = 1e-8。

梯度下降

现在我们已经计算了导数∂J/∂w和∂J/∂b,我们可以做梯度下降了。

Alpha is the learning rate, a scalar for gradient descent.

 # 反向传播...  
 对于网络中的层:  
 layer.w = layer.w - alpha * layer.dw  
 layer.b = layer.b - alpha * layer.db

如果我们运行前向传播、反向传播和梯度下降,我们将只更新一次参数 w 和 b,并实现一步梯度下降。做多步梯度下降后,代价函数值会逐渐减小,如果我们映射代价函数,它可能看起来像这样:

My cost function. Image generated by Matplotlib.

结语

反向传播本质上是你现在正在做的学习过程。为了确保更好的学习体验,我建议您编写自己的神经网络。如果你这样做了,你可能会发现一件事真的很烦人——训练时间。

在我的电脑上,训练 1000 步大约需要 10 分钟。那太长了。在我的下一篇文章中,我们将看到矢量化如何将训练时间减少到几秒钟。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明

本文链接:https://www.qanswer.top/7544/05360108

标签:输出,num,inputs,self,传播,神经网络,从零开始,反向
From: https://www.cnblogs.com/amboke/p/16645175.html

相关文章

  • 全连接神经网络
    全连接神经网络的含义全连接神经网络级联多个变换来实现输入到输出的映射。(非线性操作是不可以被去掉,原因在于若网络中缺少了激活函数,全连接神经网络将变成一个线性分类器......
  • 从零开始配置vim(19)——终端配置
    在上一篇文章中,我们熟悉了终端模式,并且配置了终端模式的一些操作。但是它总是有那么一点不符合我们的使用习惯。这篇我们将通过强大的插件来完善终端操作的体验。在介绍插......
  • 了解细胞神经网络
    了解细胞神经网络Photoby娜斯佳·杜利耶on不飞溅用于生成三维几何的遗传细胞神经网络(arXiv)作者:雨果·马泰抽象的:有许多方法可以通过程序生成有趣的3D......
  • JAVA入门基础_从零开始的培训_MYSQL基础
    目录1、数据库概述与MYSQL5.7、MYSQL8.0安装篇(基于Windows)MYSQL是什么,为什么要使用MYSQLMYSQL的四个版本MYSQL环境搭建MYSQL的安装与卸载Windows10下安装MYSQL8.26版......
  • JAVA入门基础_从零开始的培训_MYSQL高级
    目录第1章Linux下MySQL的安装与使用Linux下MYSQL的卸载安装MYSQL之前的准备步骤正式安装检查/tmp临时目录权限安装前检查依赖并卸载mariadb按照顺序依次安装MYSQL服务的初......
  • nginx 正向代理 反向代理的区别
    1、Nginx代理(1)Nginx出现的早期就是作为一个高性能的http、反向代理的web服务器。(2)同时它也提供了IMAP/POP3/SMTP服务,也就是电子邮件代理服务器。(3)它的特点就是占用内存......
  • 如何从零开始参与 Apache 顶级开源项目?| 墙裂推荐
    ​写在开头从2021开始,有一个很有意思的说法经常在各大技术媒体或开源论坛中出现,「开源正在吞噬一切」。不论是否言过其实,从一个行业从业者的切身感知来看,开源确实从少......
  • 如何从零开始在github上新建项目
    生成新SSH密钥打开Terminal(终端)Terminal(终端)GitBash。粘贴下面的文本(替换为您的GitHub电子邮件地址)。ssh-keygen-ted25519-C"您的GitHub电子邮件地址@qq.c......
  • 基于YOLOv5的Logo检测神经网络
    基于YOLOv5的Logo检测神经网络Usedeeplearningtechnologytodetectwhetherthereisabrandlogointheimageandlocateitslocation.TheLogodetectionmode......
  • 网络流反向边的正确性
    首先,要认识到只要证明了反向边是对的,那么作为一种反悔机制,最后跑出来的一定是最大流(无路增广之时)草稿纸是pdd最便宜且好用的(我只是拿来当草稿纸而已......