前馈神经网络——深度学习之神经网络核心原理与算法

十一、机器学习进阶知识:模糊神经网络(FNN)的实现(Python,附源码及数据集) 本文对模糊神经网络(FNN)的理论基础及建模步骤进行介绍,之后使用Python实现基于FNN的数据预测,通俗易懂,适合新手学习,附源码及实验数据集。 阅读详情

五月两场 | NVIDIA DLI 深度学习入门课程

5月19日/5月26日 640?wx_fmt=jpeg一天密集式学习  快速带你入门 阅读全文 >


正文共7165个字,85张图,预计阅读时间35分钟。

因上几次读者反映,公式代码有乱码和不规整的问题,小编有改善哟,这篇文章开始亲们会看到效果的哟~


前馈神经网络


Feedforward Neural Network


网络结构(一般分两种)


  • Back Propagation Networks - 反向传播网络

  • RBF networks - 径向基函数神经网络


BP网络是所有的神经网络中结构最为简单的一种网络。一般我们习惯把网络画成左边输入右边输出层的结构。

640?wx_fmt=png

一个向量从输入层进入,经过网络作用,在输出层产生输出结果。BP神经网络的网络结构是不固定的。

640?wx_fmt=png


第二个神经网络有三层,两个隐藏层。


前馈神经网络,不要求对称,在不同的网络结构下产生不同的训练效果和运行特点。


每一层的神经元很多,层数也很多,整个模型不够直观。


最简单的BP网络

640?wx_fmt=png


总共有两层,有一个隐藏层和一个输出层,一共两层。从第二层开始算一层。


输入x最简单化,x一维是一个实数。隐藏层h和输出层o结构。


640?wx_fmt=png


由这两个函数所组成。一旦这里输入x,y之后就可以开始训练了。


网络结构-代码部分


 1# coding=utf-8
2import numpy as np
3# 定义神经网络结构
4class Network(object):
5def __init__(self, sizes):
6# [3,2,1] 输入层3个神经元,隐藏层2个,输出层1个 定义总共有多少层,每一层有多少个神经元
7# 网络层数: 一共有多少层
8self.num_layers = len(sizes)
9# 每层神经元的个数
10self.sizes = sizes
11# 初始化每层的偏置 b
12self.biases = [np.random.randn(y, 1) for y in sizes[1:]]
13# self.biases = []
14# # 去size从第一项到最后一项 sizes=[3,2,1] 我们只取2,1
15# for y in sizes[1:]:
16#     # 第一次循环时y为2,第二次为1  输入到隐藏,隐藏到输出: 一共两个偏置
17#     # random.randn 使用标准正态分布来初始化一个数组, 初始化一个y乘以1的数组
18#     # 从输入层到隐藏层有两个偏置,隐藏层到输出层有一个偏置
19#     self.biases.append(np.random.randn(y, 1))
20# 初始化每层的权重 w
21self.weights = [np.random.randn(y, x)
22                for x, y in zip(sizes[:-1], sizes[1:])]
23# self.weights = []
24# # 使用zip同时遍历两个列表
25# for x, y in zip(sizes[:-1], sizes[1:]):
26#     # sizes = [3,2,1]
27#     # 输入层到隐藏层的连线总共有6条: 第一次我们x取3,y取2
28#     # 隐藏层到输出层的连线有2条, x我们取2,y取1
29#     self.weights.append(np.random.randn(y, x))
30sigmoid激励函数(1/1+e的-z次方)
31def sigmoid(z):
32return 1.0 / (1.0 + np.exp(-z))
33# 创建网络
34net = Network([3, 2, 1])
35print(net.num_layers)
36print(net.sizes)
37print(net.biases)
38print(net.weights)


运行结果:


1 3   
2[3, 2, 1]
3[array([[ 0.95438103],
4[-0.16055862]]), array([[-0.84104886]])]
5[array([[-0.50145733, -0.32197873, -0.55151483],
6[-1.57452067, -0.51783342, -0.54714269]]), array([[-0.1588291 , -0.01887209]])]


可以看到我们的神经网络有三层(算上了输入层) 每层的神经元个数分别为: 输入层3,隐藏层2,输出层1个神经元。


偏置为两组(net.biases[0] 或[1]), 从输入到隐藏层有两个偏置(因为隐藏层有两个神经元,每个神经元一个偏置); 隐藏层到输出层有一个偏置(因为输出层只有一个神经元)


而权重则是每条连线有一个权重值: 如输入到隐藏(3x2)一共有6个, 隐藏到输出(2x1)有2个。


net.weights是一个列表,第一项为输入层到隐藏层权重,第二项为隐藏到输出。


线性回归的训练


线性回归的训练,其实和基于统计的机器学习训练很相近。如果你熟悉回归的话,你会觉得bp神经网络的训练很简单。


线性回归的训练过程: 一个线性回归的模型是怎么学到的,以及它学到了什么。为理解BP神经网络的训练做铺垫。


一元线性回归


一元线性回归是所有机器学习中最简单的。


样本:

640?wx_fmt=png


观察到很多数据对,有x有y。


观察记录(通过画图):


640?wx_fmt=png


图中横坐标代表时间,单位是秒。纵坐标代表速度,单位是米每秒。


可以从图中直观的看到,时间和速度有一种线性关系。我们可以尝试画一条直线,从一堆点中穿越过去。

640?wx_fmt=png


这条直线几乎可以满足所有点。我们就可以用这条直线来描述图片上的横纵坐标关系。


横坐标用x或t表示,纵坐标用y或s表示。横纵坐标的关系:


640?wx_fmt=png


因为直线并不是穿过所有的点,会存在误差。


误差:

参数e代表error,表示误差y =wx+b+e。


我们取定任何一个w和b时,只要带入x,y就会产生一个e.产生十个e.


把表达式变为:

640?wx_fmt=png


这里的下标i就表示的是第几个样本: 也就是y的真实值减去我们的预测值(拟合值y帽子)


全局误差总量:

640?wx_fmt=png


将所有单个样本的误差进行累加获得全局误差总量。但是无论这个e是正是负都是误差,这就是残差。这里简单的累加就存在正负抵消。


对于每个e取绝对值或取平方保证非负数。


640?wx_fmt=png


对于第二行表达式进行展开,得到第三行表达式。表达式中的x与y是常数。里面的w和b才是未知数。


对于三式,提取公因式并合并就可以得到如下图公式。


640?wx_fmt=png


其中的ABCDEF全部都是常数系数。未知数是w和b。接下来我们要做的事情就是找到一个比较合适的w和b,使得loss值越小越好。


越接近0,说明我们拟合的误差越小。要让我们的直线,尽可能离样本点近。

640?wx_fmt=png


我们找到上面方程ABCDEF的近似方程:


640?wx_fmt=png


这个图形在三维空间中像一个碗。和二维空间中的抛物线很像,肯定存在极值,极值在碗底。


只要我们求的碗底的(x,y)我们就求的了最佳参数(w,b),这里只是符号字母不同,意义是一样的。只是把其中的w,b替换成了x和y。


梯度下降法


具体怎么求w和b的值:求解w和b的值的方法很多,这里我们就使用梯度下降算法。


一元凸函数

640?wx_fmt=png

我们之前讲的是二元凸函数。


640?wx_fmt=png


三元及以上凸函数,无法画图查看。只能靠自己想象。


640?wx_fmt=png


求极小值,这个是有技巧的,使用挪挪看的方法来求。


我们不知道一元函数fx的极值点,我们可以随便取一点,如:(3,11),我们再在这一点的左右都进行取值。看看哪一边更低。


640?wx_fmt=png


可以看到左边的点更小一点。下次我们就可以以2.8这个点为基准。向

640?wx_fmt=png

挪动。然后左看2.6 右看3.0。2.6会更小一点。一直往过挪动。


这里我们人为规定每次挪动0.2,通常情况下我们不确定挪动多少合适。我们希望有一种方法可以该多挪的时候多挪,该少挪的时候少挪。挪到位了就不要再挪了。


梯度下降算法就可以解决这个问题。让我们的每次挪动不固定在0.2,而是离极值远的地方挪的快一点,而离极值近的地方挪的慢一些。挪到位了就不要挪动了。


梯度下降算法的更新公式

640?wx_fmt=png

640?wx_fmt=png

Xn+1 和 Xn 分别代表两个临近点的x值。Xn+1是Xn更新后的下一次迭代值。


学习率:挪动步长的基数,步长。学习率设置大的话救挪动的多,设置的小的话就挪动的少。


f'(x)就是x点的导数,物理意义是切线的斜率。


梯度下降更新一元函数


640?wx_fmt=png


取x=3, 导数就是(3,11)这一点的切线斜率。


640?wx_fmt=png


直接求出导函数,带入x。

640?wx_fmt=png


假设学习率为0.1,那么我们的学习率x导数值就是我们下一步要挪动的步长

由更新公式:

640?wx_fmt=png

可以得到

640?wx_fmt=png


然后我们进行下一次迭代,


640?wx_fmt=png

每一次移动的步长在逐渐的减小。原因: 临近整个函数底部,斜率是在逐渐降低的。

导致:

640?wx_fmt=png


的绝对值在逐渐的减小。那么更新时的x的改变量也会逐渐的减小。


640?wx_fmt=png


观察我们的更新公式会发现没有之前我们的左右取点看一看的过程,而是直接做更新。

原因直接讲出来,因为当我们取x=3这一点的导数值(斜率为正值)


640?wx_fmt=png


那么:

640?wx_fmt=png


这一项就是一个负数。所以更新后的Xn+1就会变小。朝着曲线底部方向挪动。


如果Xn 取-3就会在曲线的左侧,此时这一点的斜率是一个负数。


640?wx_fmt=png

那么:

640?wx_fmt=png

这一项就会是一个正数。更新之后的Xn+1就会变大,依然是朝着函数底部的方向。

所以X取正三,还是负三都能保证这个函数朝着底部移动。


二元凸函数


之前我们讲解了一元凸函数,可以通过编程方式解决极值问题。

640?wx_fmt=png


二元凸函数我们用同样的方法解决极值问题。


同样我们在这个平面上随便找一个点(x0,y0),然后想把它挪动到极值点上去。跟原来的思路有区别,原来一元凸函数我们有两个方向去尝试,可以先看眼左边,再看眼右边。哪一边离极值点近就像哪一边先挪动。


而二元凸函数我们就有四个方向去尝试。

640?wx_fmt=png

在这个更新公式中我们发现并不需要真的去两边都去尝试一下。这个更新方程本身就可以在一个维度上来识别需要向哪个方向移动。

640?wx_fmt=png

现在在两个维度上的更新方程简化之后就是如上图所示公式。


偏导数:

640?wx_fmt=png


上图表示的是x偏导,曲面上的点沿着平行于x轴方向的切线。


640?wx_fmt=png

沿着x轴方向的切线斜率。


y轴方向切线

640?wx_fmt=png


640?wx_fmt=png

沿着y轴方向的切线斜率。


更新

640?wx_fmt=png


从数学来讲,两者的求法一致。我们的第二种写法显得不专业,但是只是为了表示与一元函数求导没有差别。

640?wx_fmt=png


假设我们有一点(3,4),代入之后可求得值为64


640?wx_fmt=png

更新方程:


640?wx_fmt=png


这个时候就可以通过更新方程进行工作了。但是计算机的有限计算能力,实际的深度学习网络中极有可能有上万个维度的值要更新,效率层面我们希望这种更新能产生最高效的收敛效果。也就是通过多次迭代逐步逼近我们想要的值。如果准确度相当的情况下,收敛快的方法更受我们的欢迎。


更新原则


对于梯度下降算法来说,里面有多个维度可以选择。


640?wx_fmt=png

对于f(x,y)就有两个维度可以选择。我们使用什么原则可以使收敛的速度最快。


如果在一个三维的空间中,我们想从山顶往山下走。最快的方法:沿着山坡上最陡峭的方向向下最快。


640?wx_fmt=png


梯度: 反着写的倒三角形,等于两个方向上的偏导,一个是x的偏导一个是y的偏导。


如果每次进行更新的时候,你就可以使用学习率(一塔)乘以这两个方向上的偏导。各自完成自己的更新量。


假如我们函数中的变量不止两个,而是有一千种。


它表示的形式就是:

640?wx_fmt=png


求出了这1000个参数的偏导数。然后乘以学习率,更新1000个w变量


640?wx_fmt=png


其中w的上标i表示这是第几个w。w的下标n和n+1表示的是第几次迭代。也就是我们完成一次迭代需要对1000个w分别做更新。


这里我们就讲解完梯度下降算法在多元凸函数上的更新步骤和更新原则。开始训练(和之前讲的一元凸函数训练方法是一样的):


需要一个描述残差loss的函数。


640?wx_fmt=png


接着我们可以使用若干个w来表述这个函数。然后我们可以用梯度下降算法用最快方法去更新w的各个维度。最后满足loss极值点的位置就是我们要找的w。


640?wx_fmt=png


神经网络的训练


我们已经介绍了线性回归的训练过程,那么我们再来看一下神经网络的训练过程。


640?wx_fmt=png


这是我们定义的简单的两层简单bp网络。第一层是隐藏层h 第二层是输出层o,隐藏层h和输出层o都是由两部分组成。

640?wx_fmt=png


第一部分是线性单元,第二部分是非线性部分。第一行为隐藏层的输入x经过wh和bh的处理变成Zh,Zh又作为非线性单元的输入。


输出层同理,输入变为了Yh。


训练过程
  • 初始化w,b

  • Loss(w,b)

  • 挪动w,b 逐步变化, 直到Loss足够小。


样本:

640?wx_fmt=png


计算机自己学习出方程中的四个待定系数。Wh Bh Wo Bo,如果你是做图片分类,你就需要给每个图片打上一个标签。

640?wx_fmt=png

x1 猫 x2 狗 xn标对应标签.


前向传播

640?wx_fmt=png


根据网络中两个表达式的描述。可以带入x1:


640?wx_fmt=png


表达式的映射关系就变成上图所示。


由x1和y1所带来的误差值我们也可以定义了

640?wx_fmt=png


这是一个样本的Loss,也就是残差平方。 然后累加求和得到下面:

640?wx_fmt=png


如果预测出来的结果yo1和y很接近,loss1就会比较小。因为我们有10对训练数据,得到十个loss,Loss累加。这就是神经网络中的前向传播: 输入数据通过网络一层一层的作用一直向前传播。


前向传播的代码实现


计算每一层的z, 再计算每一层的a。接着保存每一层的z和a,为后面的反向1传播做准备。


 1# coding=utf-8
2import random
3import numpy as np
4class Network(object):
5def __init__(self, sizes):
6# 网络层数
7self.num_layers = len(sizes)
8# 网络每层神经元个数
9self.sizes = sizes
10# 初始化每层的偏置
11self.biases = [np.random.randn(y, 1) for y in sizes[1:]]
12# 初始化每层的权重
13self.weights = [np.random.randn(y, x)
14                for x, y in zip(sizes[:-1], sizes[1:])]
15# 梯度下降
16# GD函数有两个变量: 训练数据集, 需要训练的轮数
17def GD(self, training_data, epochs):
18# 开始训练 循环每一个epochs: 定义epochs数值为几,就循环几次
19for j in range(epochs):
20    # 洗牌 打乱训练数据 shuffle
21    random.shuffle(training_data)
22    # 让每一次训练的时候,训练数据的顺序不同
23    # 训练每一个数据, 使用x和y来取训练数据data和它对应的y
24    for x, y in training_data:
25        # 使用update方法进行前向传播
26        self.update(x, y)
27    # 每个epoch 完成,打印我们已经训练到了第几个epoch
28    print("Epoch {0} complete".format(j))
29    # 前向传播
30   def update(self, x, y):
31  # 传入输入的训练数据,
32activation = x
33# 保存每一层的激励值a=sigmoid(z) z=wx+b
34# 第一层时输入数据就是它的激励值
35activations = [x]
36# 保存每一层的z=wx+b
37zs = []
38# 前向传播
39# 使用for循环遍历每一层的偏置与权重:同时取第一层的偏置和权重
40for b, w in zip(self.biases, self.weights):
41    # 计算每层的z
42    # dot是点乘方法: 把两个数组进行点乘,对于二维数组相当于矩阵乘法。
43    # 一维数组相当于向量的内积
44    z = np.dot(w, activation) + b
45    # 保存每层的z
46    zs.append(z)
47    # 计算每层的a
48    activation = sigmoid(z)
49    # 保存每一层的a
50    activations.append(activation)
51  def sigmoid(z):
52 return 1.0 / (1.0 + np.exp(-z))


反向传播更新参数


可以开始挪动Wh Bh Wo Bo四个待定系数,来逐步减小Loss值。这个在之前的线性回归的训练过程中我们已经讲过了。也就是需要四个更新公式来帮我们更新。

640?wx_fmt=png

640?wx_fmt=png


和之前线性回归中的更新公式大同小异。只不过线性回归当中是一个三维空间。


我们去找碗底的过程。这里变成了一个五维空间我们去找碗底的过程。


在神经网络中去更新网络中的待定系数的过程,叫做反向更新。因为我们是从最后一层开始,倒数第二层,倒数第三层。这样一层一层的反向更新w和b。如何求这四个公式中的偏loss 偏wh 偏loss 偏bh 偏loss 偏wo 偏loss 偏bo

640?wx_fmt=png

这四个值到底怎么求?

640?wx_fmt=png


我们把我们的损失函数loss的方程改变一下。在前面加上二分之一。这样是为了我们后面求导方便约分。


根据链式法则可以得到:

640?wx_fmt=png

又由于Zo=WoYh+Bo  所以Zo偏Bo求导的值为1.所以得到

640?wx_fmt=png

看一下下图中如何求

640?wx_fmt=png

由于最后一层的Yo就是sigmoid(z) 就等于:

640?wx_fmt=png

变成了求sigmoid(z)的导数。

640?wx_fmt=png

特性: sigmoid函数求导出来是它本身乘以(1-sigmoid函数)。


再来看一下前面这一项:

640?wx_fmt=png

如果我们把loss的表达式带进来,求得的偏yo就等于:

640?wx_fmt=png

640?wx_fmt=png

也就是预测值减去真实值。此时综合一下

640?wx_fmt=png

640?wx_fmt=png

yo是网络预测出来的结果是一个已知量, yi是我们的标签,已知值。Zo也可以通过前向更新,WoYh+Bo得到。也是一个已知值。


反向更新更新w和b,需要下面四个方程配合。


640?wx_fmt=png

我们可以求出最后一层的偏loss/偏b 等于的他0:

640?wx_fmt=png

如果是倒数第二层或倒数第三层也就是非最后一层的偏loss/偏b,你就可以用(的他h)这个公式去计算它的值。


同理,偏loss/偏w 如果是最后一层,你可以把(的他0代进来),如果不是最后一层你可以把的他h带进来。这样你就可以求出偏loss/偏w的值。


利用四个反向更新公式,一步一步的慢慢改变w和b。直到loss最小。


网络中定义的loss函数是一个二次损失函数,如果你使用的不是二次损失函数,那么最后推出来的结果就不是这四个更新方程。需要自己来根据实际情况进行推导。


如果你使用的是框架的话,这些推导的步骤不需要你自己去做,你只需要设置参数就可以了。


反向传播更新代码实现


在梯度下降GD方法中加入反向传播的参数保存


1# 反向: 保存每层偏导
2# 反向: 取到每一层的偏置值,取到它的形状,以这个形状创建零矩阵
3nabla_b = [np.zeros(b.shape) for b in self.biases]
4nabla_w = [np.zeros(w.shape) for w in self.weights]


update方法中加入偏导的保存


1# 前向传播
2def update(self, x, y):
3# 保存每层偏倒
4nabla_b = [np.zeros(b.shape) for b in self.biases]
5nabla_w = [np.zeros(w.shape) for w in self.weights]


将z和activation保存了之后就可以进行反向更新了。


640?wx_fmt=png


网络预测的值减去它的真实值之后,点乘:

640?wx_fmt=png


Zo也就是最后一层的wx+b的值。代码中我们已经把Zo计算出来保存到了zs里面。


最后一层的误差delta就等于我们自定义的cost_derivative函数计算Yo-Yi,最后一层的预测值就是activations[-1],取最后一层计算出来的预测值yo,接着乘以sigmoid_prime函数来计算最后一层sigmoid的偏导。


1# 反向更新了: 从倒数第一层开始
2# 计算最后一层的误差
3delta = self.cost_derivative(activations[-1], y) * sigmoid_prime(zs[-1])


预测值-真实值


1def cost_derivative(self,output_activation, y)
2return (output_activation - y)


sigmoid(Zo)的偏导: 导数的一个特性


1def sigmoid_prime(z):
2return sigmoid(z) * (1 - sigmoid(z))
3# 最后一层权重和偏置的倒数
4# 偏loos/偏b = delta
5# 偏loss/偏w = 倒数第二层y 乘以 delta
6nabla_b[-1] = delta
7# transpose转置操作
8nabla_w[-1] = np.dot(delta, activations[-2].transpose())


可以求倒数第二层直到第一层的权重和偏置的导数。从导数第二层开始,所以(2, self.num_layers) zs[-l]先正向传播后反向更新。求得了每一层的权重和偏置的导数。

在训练中,保存update返回的结果


1# 训练每一个数据
2for x, y in training_data:
3delta_nable_b, delta_nabla_w = self.update(x, y)
4# 保存一次训练网络中每层的偏倒
5nabla_b = [nb + dnb for nb, dnb in zip(nabla_b, delta_nable_b)]
6nabla_w
= [nw + dnw for nw, dnw in zip(nabla_w, delta_nabla_w)]
7


因为nb是零矩阵,加上dnb得出来的结果就是dnb

之后就可以进行真正的反向更新了。


1# eta学习率
2# 更新权重和偏置 Wn+1 = wn - eta * nw
3self.weights = [w - (eta) * nw
4for w, nw in zip(self.weights, nabla_w)]
5self.biases = [b - (eta) * nb
6for b, nb in zip(self.biases, nabla_b)]


循环遍历每一层的权重和权重的导数。Wn+1 = wn - eta * nw


随机梯度下降算法


在介绍梯度下降算法时我们已经介绍了损失函数的公式了。在损失函数的公式里面n表示拥有n个样本。表示求导数的过程中n个样本都要参与计算。

640?wx_fmt=png

可是n的值往往非常大,每个样本都有x个维度,有可能数万,有可能数百万。这种计算需要大量的时间。需要有一种方式缩短这种计算时间。

640?wx_fmt=png

随机梯度下降算法其实没有什么新奇的地方,就是统计学中的抽样。我们从整体的数据中随机的抽取一部分样本,这些样本的特征已经一定程度上代表样本集的特征。


就像统计人类的特征,不需要世界人口普查,只需要抽取一部分具有代表性的特征。只要他们能覆盖所有的人口,年龄,性别。


对这一部分抽取出来的样本进行归纳总结就可以了。


SGD中的几个名词


  • 减少计算量


mini-batch: 从训练样本中随机选取一些数据

epoch: 一次训练一个mini-batch,直到把所有训练数据都用一遍。

这种情况下w和b的更新公式也需要做相应的修改。只要对后面一项除以m就可以了。

640?wx_fmt=png


m的大小就是mini-batch的大小。从训练样本中随机抽取的数据的大小就是m的大小。


SGD代码更新


在了解了随机梯度下降算法之后我们又可以更新之前的算法。


第19行,把梯度下降函数改为SGD随机梯度下降。函数中再多添加一个参数叫做mini_batch_size


1# 随机梯度下降
2def SGD(self, training_data, epochs, mini_batch_size, eta):
3# 取出训练数据总个数
4n = len(training_data)


在洗牌之后,我们循环mini_batch_size


1# mini_batch
2mini_batches = [training_data[k:k + mini_batch_size]
3for k in range(0, n, mini_batch_size)]


我们循环0-n,每隔mini_batch_size取一个k。training_data从k开始一直到k加上minibatch,之前是训练整个数据集,我们现在只需要训练minibatch大小个数据就可以了。


1# 训练mini_batch
2  for mini_batch in mini_batches:
3  self.update_mini_batch(mini_batch, eta)


我们需要实现一个新的函数。update_mini_batch


 1# 更新mini_batch
2def update_mini_batch(self, mini_batch, eta):
3# 保存每层偏倒
4nabla_b = [np.zeros(b.shape) for b in self.biases]
5nabla_w = [np.zeros(w.shape) for w in self.weights]
6# 训练每一个mini_batch
7for x, y in mini_batch:
8    delta_nable_b, delta_nabla_w = self.update(x, y)
9# 保存一次训练网络中每层的偏倒
10    nabla_b = [nb + dnb for nb, dnb in zip(nabla_b, delta_nable_b)]
11    nabla_w = [nw + dnw for nw, dnw in zip(nabla_w, delta_nabla_w)]
12# 更新权重和偏置 Wn+1 = wn - eta * nw
13self.weights = [w - (eta / len(mini_batch)) * nw
14                for w, nw in zip(self.weights, nabla_w)]
15self.biases = [b - (eta / len(mini_batch)) * nb
16               for b, nb in zip(self.biases, nabla_b)]


将training_data改为mini_batch,更新权重和偏置的时候使用eta除以minibatch的总个数。


前馈神经网络手写数字识别


在实现了我们的神经网络之后,我们来看一下如何使用我们刚才的神经网络来做图片的识别。


案例: 手写数字识别

640?wx_fmt=png


640?wx_fmt=png

MNIST dataset


每一张图片为28,28的。数字总共有10种。


如何用我们之前实现的神经网络来实现手写数字识别


随机梯度下降,正向传播,反向更新。


1if __name__ == '__main__':
2import mnist_loader
3traning_data, validation_data, test_data = mnist_loader.load_data_wrapper()


从mnist中取训练数据,验证数据,测试数据。


使用我们的Network类定义我们的网络。定义一个三层的网络,输入层为28,28共784个神经元。隐藏层我们定义30个神经元,输出层有十种数字。    net = Network([784, 30, 10])


1net = Network([784, 30, 10])


调用net的SGD方法训练我们的模型:


传入参数: 训练数据集,epoch数量,minibatch大小,学习率0.5


1net.SGD(traning_data, 30, 10, 0.5, test_data=test_data)


我们再添加一个我们的参数: test_data。每一轮训练完成之后看我们的神经网络在测试集上的表现如何。


1def SGD(self, training_data, epochs, mini_batch_size, eta,
2    test_data=None)
:
3            if test_data:
4    n_test = len(test_data)


在训练完成之后进行测试集上表现的测试


1# 测试集上的表现
2if test_data:
3    print("Epoch {0}: {1} / {2}".format(
4        j, self.evaluate(test_data), n_test))


自定义我们的评估evaluate方法,看当前网络总共预测对了多少:


1def evaluate(self, test_data):
2test_results = [(np.argmax(self.feedforward(x)), y)
3                for (x, y) in test_data]
4return sum(int(x == y) for (x, y) in test_results)


循环遍历test_data中的数据x和label y。可以让我们取出来的x经过一个函数feedforward前向传播就是我们网络的预测结果。因为我们刚才定义的输出层有十个神经元。


每一维代表它是这个数字的可能性。调用argmax取这十维中最大的一个数字。最大的数字就是我们经过网络预测出来最可能的结果。每一对预测结果和真实标签组成我们的test_results。


如果一样就返回1,不一样就返回0。返回10000个比较结果,0或者1.求和一下就是验证正确的总数。


feedforward就是我们的前向传播函数。输入值a


1def feedforward(self, a):
2for b, w in zip(self.biases, self.weights):
3    a = sigmoid(np.dot(w, a) + b)
4return a


遍历当前网络所有层上的w和b。


调用每一个神经元都由线性单元wx+b 经过激励函数组成。网络的预测结果,然后把网络的预测结果返回出去。


640?wx_fmt=png

解决几个Python3下的报错。

  • no module named cPickle


Python3下cpickle改名为了pickle。直接修改修改使用pickle就行了。

  • 报错2


1UnicodeDecodeError: 'ascii' codec can't decode byte 0x90 in position 614
2


这个是因为pickle要指定编码格式。


1training_data, validation_data, test_data = pickle.load(f,encoding='bytes')


添加encoding参数。

  • 报错3:


1TypeError: object of type 'zip' has no len()


将zip对象,强制转化为list类型。


1training_data = list(zip(training_inputs, training_results))


训练结果:

640?wx_fmt=png


隐藏层30 输出层10(代表10种数字0-9) 学习率0.5

跑完30轮之后准确率还蛮高的93%。


640?wx_fmt=png


只改变了隐藏层的神经元个数,准确率提高到了94%


原文链接:https://www.jianshu.com/p/e5dfe52773e1


查阅更为简洁方便的分类文章以及最新的课程、产品信息,请移步至全新呈现的“LeadAI学院官网”:

www.leadai.org


请关注人工智能LeadAI公众号,查看更多专业文章

640?wx_fmt=jpeg

大家都在看

640.png?

LSTM模型在问答系统中的应用

基于TensorFlow的神经网络解决用户流失概览问题

最全常见算法工程师面试题目整理(一)

最全常见算法工程师面试题目整理(二)

TensorFlow从1到2 | 第三章 深度学习革命的开端:卷积神经网络

装饰器 | Python高级编程

今天不如来复习下Python基础

深度学习神经网络基本原理 深度学习面临的挑战是:图像的底层视觉特性和高层语义概念之间的鸿沟。例如人和狗是不一样的图像,但如果他们背景颜色都一样,视觉特征很像,但语义不同。一个卷积核可以提取图像的一种特征,多个卷积核可以提取多个特征。对于全连接的神经网络,有几个结构输入层、隐藏层、输出层。交叉熵损失函数:预测值与真实值越接近,损失函数越小。多通道卷积:输出为对应通道在滑动窗口内的卷积的和。让总损失尽可能的小,预测值与真实值之间的差距。总的流程为:建立模型——损失函数——参数学习。深度全连接模型的不足之处:模型参数太多。 阅读详情

相关推荐

多层感知机(MLP)、全连接神经网络(FCNN)、前馈神经网络(FNN)、深度神经网络(DNN)与BP算法详解

多层感知机(MLP)、全连接神经网络(FCNN)、前馈神经网络(FNN)、深度神经网络(DNN)与BP算法详解。

weixin_60737527的博客 3万+

【深度学习原理第1篇】前馈神经网络,感知机,BP神经网络

前馈神经网络(FNN) 前馈神经网路是一种单向多层的网络结构,信息从输入层开始,逐层向一个方向传递,即单向传递,一直到输出层结束。前馈的意思就是指传播方向指的是前向。前馈神经网络由三部分组成:输入层(第0层),输出层(最后一层),中间部分称为隐藏层,隐藏层可以是一层,也可以是多层 。FNN如下图所示,其中圆圈是神经元。 学习神经网络前向传播与反向传播推导过程必须了解,这是许多网络的基础,推荐下面的up主视频,用案例来讲解底层传播与机理,并做出了推导,跟着推一遍,理解会更深刻,不然后面学习就可能一知半解了

小样yx的博客 7485

深度学习算法全解析与实战对比

深度学习算法分析与比较摘要 本文系统梳理了五种主流深度学习模型的原理与应用: 前馈神经网络(FFNN)通过全连接层处理结构化数据,核心为反向传播算法; 卷积神经网络(CNN)利用卷积核和池化操作提取图像空间特征; 循环神经网络(RNN)通过时序参数共享处理序列数据,但存在梯度消失问题; LSTM引入门控机制有效建模长程依赖,在自然语言处理中表现优异; Transformer基于自注意力机制实现并行化全局建模,成为当前最先进的序列模型。 文章从数学原理、结构设计到PyTorch实现进行了全面对比,并总结出各模

闲人编程的博客 1263

1- 深度学习之神经网络核心原理与算法-前馈神经网络

前馈神经网络 Feedforward Neural Network 网络结构(一般分两种) Back Propagation Networks - 反向传播网络 RBF networks - 径向基函数神经网络 BP网络是所有的神经网络中结构最为简单的一种网络。 一般我们习惯把网络画成左边输入右边输出层的...

weixin_33794672的博客 2751

深度学习简介:AI人工智能与大数据的完美融合

深度学习简介:AI人工智能与大数据的完美融合 1. 背景介绍 1.1 人工智能的兴起 人工智能(AI)是当代最具颠覆性和影响力的技术之一。从最早的专家系统和决策树算法,到今天的深度学习和强化学习,AI已经渗透到了我们生活的方方面

AI天才研究院 1021

深度学习原理与实战:深度学习在航空航天领域的应用

1.背景介绍 深度学习是人工智能领域的一个重要分支,它通过模拟人类大脑的思维方式来解决复杂的问题。近年来,深度学习在各个领域的应用越来越广泛,包括图像识别、自然语言处理、语音识别等。在航空航天领域,深度学习也发挥着重要作用,例如轨道轨道导航、飞行器控制、气候预测等。本文将从深度学习的原理和算法入手,详细介绍深度学习在航空航天领域的应用。

AI天才研究院 514

深度学习的神经网络核心原理与算法 - FNN 前馈神经网络

正文共7165个字,85张图,预计阅读时间35分钟。原文链接:https://www.jianshu.com/p/e5dfe52773e1前馈神经网络Feedforward Neural...

MineData 4240

DeepSpeed Zero3 Offload实战:从GCC版本检查到环境配置的完整避坑指南

本文是一份针对DeepSpeed Zero3 Offload部署的完整避坑指南。针对训练中常见的`AttributeError: ‘DeepSpeedCPUAdam‘ object has no attribute ‘ds_opt_adam`报错,文章深入剖析了其根源在于GCC编译器版本过低。指南提供了从系统GCC版本深度探查、安全启用高版本GCC环境,到DeepSpeed一致性安装验证的全链路实战方案,旨在帮助用户构建稳定的大模型训练环境。

weixin_29070721的博客 473

监督学习的神经网络算法:深度学习

1.背景介绍 深度学习是一种基于神经网络的机器学习方法,它通过大量的数据训练,使神经网络具备了人类级别的智能。深度学习在图像识别、自然语言处理、语音识别等领域取得了显著的成果,并被广泛应用于各个领域。本文将从以下六个方面进行阐述:背景介绍、核心概念与联系、核心算法原理和具体操作步骤以及数学模型公式详细讲解、具体代码实例和详细解释说明、未来发展趋势与挑战以及附录常见问题与解答。 1.1 背景介绍...

AI天才研究院 822

RK3576平台部署NanoTrack:边缘AI视觉跟踪实战指南

边缘AI部署是将深度学习模型在资源受限的嵌入式设备上高效运行的关键技术,其核心在于模型压缩、硬件适配与软件栈优化。通过INT8量化、算子融合与内存优化等原理,能显著降低模型计算量与内存占用,从而在嵌入式NPU上实现实时推理。这项技术的价值在于为安防监控、无人机视觉、工业检测等场景提供低功耗、高响应的智能感知能力。以瑞芯微RK3576平台部署轻量级视觉跟踪模型NanoTrack为例,其过程涉及模型结构分析、RKNN工具链转换、C++推理程序开发及多线程性能优化,完整展现了从算法到产品的工程化路径,为开发者提供

weixin_31887307的博客 426

Tribon Vitesse开发教程(一)

Tribon Vitesse简介 Tribon Vitesse是Tribon提供给Python编程语言的编程接口,它是一系列的API。使用Python的语法调用这些API,结合Python语言自身的语法生成的程序叫做Vitesse程序。Vitesse是法语“速度”的意思,读作“为戴斯”。使用Tribon Vitesse可以直接访问Tribon产品信息模型和使用Tribon应用程序的功能,以控制设计

forevermemory的专栏 2593

前馈神经网络

前馈神经网络

weixin_63016274的博客 278

【unity】解决unity编译器安装中文汉化包失败

查看是否有Localization目录如果没有就进行创建,然后点击打开Localization把下载的zh-hans.po文件复制剪切进去即可。如果有的同学中文包安装失败,我们找到相应的编译器版本,点击在资源管理器中显示按钮,我们找到简体中文,复制downloadUrl后面的值到浏览器打开进行下载,点击Edtior language选择框,选择简体中文,等待加载。我们点击当前目录的上一级,进入编译器目录。返回在文件管理器中点击Editor目录。编译器启动后点击Edit[编辑]按钮。复制或者剪切下载的文件。

weixin_44959182的博客 8022

深度学习与大脑:神经网络的共同语言

1.背景介绍 深度学习是人工智能领域的一个重要分支,它旨在模仿人类大脑中的神经网络,以解决各种复杂问题。在过去的几年里,深度学习已经取得了显著的进展,并在图像识别、自然语言处理、语音识别等领域取得了显著的成功。然而,深度学习仍然面临着许多挑战,例如数据不可知性、泛化能力有限等。为了更好地理解深度学习,我们需要深入了解其背后的理论基础和算法原理。 在本文中,我们将讨论深度学习与大脑之间的共同点和...

AI天才研究院 855

全球建筑物提取数据集(免费下载):微软/GlobalMLBuildingFootprints

这个是GitHub上的开源数据集: https://github.com/microsoft/GlobalMLBuildingFootprints 介绍 必应地图正在世界各地发布开放式建筑足迹。我们从 2014 年到 2021 年间的 Bing Maps 图像中检测到了 7.77 亿座建筑物,包括 Maxar 和 Airbus 的图像。数据可在 ODbL 下免费下载和使用。该数据集补充了我们的其他版本。 包括的地区 执照 此数据由 Microsoft 根据Open Dat..

此星光明博客 6289

scratch绘制旋转彩球 2023年9月电子学会图形化编程scratch编程等级考试四级真题和答案解析

​ scratch绘制旋转彩球 2023年9月电子学会图形化编程Scratch等级考试四级真题 一、题目要求 1、准备工作 (1)删除小猫角色,从角色库选择Ball角色; (2)默认空白背景。 ​

青少年编程学习指导 1368

人工智能与人类智能的法律与政策:如何确保人工智能的可控与安全

人工智能(Artificial Intelligence,AI)是一种计算机科学的分支,旨在模拟人类智能的能力,包括学习、理解自然语言、识图、推理、决策等。随着计算能力和数据量的快速增长,人工智能技术已经取得了显著的进展,并在各个领域得到了广泛应用,如医疗诊断、金融风险评估、自动驾驶汽车等。然而,随着人工智能技术的发展和应用,也引发了一系列法律和政策问题。这些问题涉及到人工智能的可控性、安全性、隐私保护、道德伦理等方面。为了确保人工智能的可控与安全,各国政府和国际组织已经开始制定相关的法律和政策。

ZL_1618的博客 2053

YOLO26 网络结构逐模块解析:Backbone/Neck/Head

本文解析了YOLO26目标检测网络的架构设计,重点介绍其在Backbone、Neck和Head三个核心组件的创新优化。Backbone采用改进的CSP模块与轻量级注意力机制,提升特征提取效率;Neck使用改进的BiFPN结构实现高效多尺度特征融合;Head采用完全解耦设计简化回归流程。文章详细分析了各模块的技术演进、实现细节和设计思想,通过流程图和代码示例展示了YOLO26的整体架构和关键组件实现。该研究对模型优化、定制开发和硬件部署具有重要指导意义。

一键难忘的博客 1245

AI人工智能中的数学基础原理与Python实战:深度学习理论

1.背景介绍 深度学习是人工智能领域的一个重要分支,它主要通过模拟人类大脑中的神经网络来进行数据处理和学习。在过去的几年里,深度学习技术取得了巨大的进展,已经成为许多应用场景中的核心技术,例如图像识别、自然语言处理、语音识别等。 然而,深度学习的理论和实践仍然是一个相对新的领域,很多人对其背后的数学原理和算法实现有限。为了帮助读者更好地理解和掌握深度学习的核心概念和技术,我们编写了这本书《AI...

AI天才研究院 603

强化学习算法案例——一个经典的走迷宫任务。

作者:禅与计算机程序设计艺术 1.简介 在强化学习(Reinforcement Learning, RL)中,有一个经典的任务——走迷宫,其原理简单易懂,但它的实际意义却深远,它让计算机学习如何通过策略网络(policy network),以最佳的方式解决复杂的任务。本文将介绍如何用强化学习解决这个经典

AI天才研究院 3216

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

深度学习的数据驱动:从大数据到深度学习

1.背景介绍 深度学习是一种人工智能技术,它旨在模拟人类大脑中的神经网络,以解决复杂的问题。深度学习的核心是通过大量的数据驱动,使模型能够自动学习和优化。在过去的几年里,深度学习已经取得了显著的成果,并在图像识别、自然语言处理、语音识别等领域取得了突破性的进展。 在本文中,我们将讨论深度学习的数据驱动原理,以及如何从大数据到深度学习。我们将涵盖以下主题: 背景介绍 核心概念与联系 核心算法...

AI天才研究院 909

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

深度学习与复杂问题解决:实践中的成功案例

1.背景介绍 深度学习是一种人工智能技术,它通过模拟人类大脑中的神经网络来解决复杂问题。在过去的几年里,深度学习已经取得了巨大的成功,在图像识别、自然语言处理、语音识别等领域取得了突破性的进展。这篇文章将介绍深度学习的核心概念、算法原理、具体操作步骤以及数学模型公式,并通过实例来说明其应用。 2.核心概念与联系 深度学习的核心概念包括神经网络、前馈神经网络、卷积神经网络、递归神经网络、生成对...

AI天才研究院 1052

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

深度学习与人类智能:解密神经网络的潜力

1.背景介绍 深度学习(Deep Learning)是人工智能(Artificial Intelligence)的一个分支,它旨在模仿人类大脑中的神经网络,以解决复杂的问题。深度学习的核心技术是神经网络,它们由多层次的节点组成,每个节点都可以进行数学计算。这种计算模型使得深度学习可以自动学习和识别复杂的模式,从而实现人类级别的智能。 深度学习的发展历程可以分为以下几个阶段: 1940年代至...

AI天才研究院 1133

深度学习的潜力:如何驱动人工智能的进步

1.背景介绍 深度学习(Deep Learning)是一种人工智能(Artificial Intelligence, AI)的子领域,它旨在模仿人类大脑中的神经网络,以解决复杂的问题。深度学习的核心思想是通过多层次的神经网络来学习数据中的特征表达,从而实现对复杂数据的理解和处理。 深度学习的发展历程可以分为以下几个阶段: 第一代:多层感知器(Multilayer Perceptrons, ...

AI天才研究院 1056

深度学习解密:从初学者到专家的道路

1.背景介绍 深度学习是人工智能领域的一个重要分支,它旨在通过模拟人类大脑中的神经网络来解决复杂的问题。深度学习的核心思想是通过大量的数据和计算资源来训练神经网络,使其能够自动学习和提取有用信息。 深度学习的发展历程可以分为以下几个阶段: 1940年代至1960年代:人工神经网络的诞生和初步研究。 1980年代至1990年代:人工神经网络的再现和研究,但由于计算资源有限,这些研究得不到广泛...

AI天才研究院 974
上一篇: GBDT(梯度提升决策树)总结笔记
下一篇: Python生成器
LeadAI学院
博客等级 码龄9年 706粉丝 48原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值