搭建最简单的神经网络———从单层到多层

1.单层神经网络

1.1 介绍

我们在前面的课题中介绍了什么是感知器模型,还介绍了感知器模型的训练方法,已经损失函数和激活函数是什么。现在我们可以着手开始搭建自己的神经网络了。其实所谓神经网络就是多个感知器组合成的网络,如果只有一列就是单层,有多列就是多层,现在我们先从最简单的单层神经网络开始介绍。

1.2 单层神经网络的结构

单层网络 神经网络 python代码 什么是单层神经网络_感知器


上图就是一个单层神经网络的结构,当然或许你看到的是好几层,不只是三层,那下面我就来一一介绍一下每一层的作用。

第一层:第一层叫做输入层,就是单层网络 神经网络 python代码 什么是单层神经网络_神经网络_02,故名思意,输入层就是我们前面一章提到的感知器的输入部分,可以是图片的像素,也可以是电线杆的粗细和麻雀的数量等。

第二层:第二层叫做隐含层,它就是我们之前见到的感知器的中间部分,只不过这里变成了多个感知器,它这里放的就是我们的激活函数单层网络 神经网络 python代码 什么是单层神经网络_神经网络_03它的作用就是处理前面过来的输入,把它变成单层网络 神经网络 python代码 什么是单层神经网络_激活函数_04进行输出。在这里也就可以说明ReLU函数为什么可以逼近任何图形,这是因为每一个神经元(就是隐含层的小圆圈),里面的激活函数都是不一样的,所以许多个不同的ReLU在一起合成的图形就是一个非线性的图形,之所以不直接用线性模型是因为它不具有筛选能力。为什么是叫“隐含层”呢,因为作为程序员的我们,在程序运行起来的时候,只能看见输入和输出的结果,比如丢进去一张图片,出来一个模型,但是看不到中间的处理的结果,是不知道激活函数操作的每一个具体过程的,所以这一层就像是被隐藏了一样。

第三层:第三层读者肯定是可以猜到,就叫输出层,最后的圆圈和Y都是输出层,最后的圆圈把前面隐含层的输出整理一下(可以用一个激活函数来整合),变成最终的输出y。它和感知器的输出部分是一样。

我们可以看到,其实整个网络结构里面最复杂的部分,也是起到关键作用的部分就是隐含层,因为隐含层只有一层,所以这个网络也就叫做单层神经网络。(部分的人也叫它三层或者两层(两层是因为输出层也可能涉及激活函数)神经网络,我参考的资料还是以隐含层的数量来决定名称,读者可以根据自己的喜好来取名,名字不重要,重要的是知识能否被掌握)

1.3 单层神经网络的参数

其实神经网络的参数是什么,我们在之前已经学习过,就是权值单层网络 神经网络 python代码 什么是单层神经网络_深度学习_05和偏置数单层网络 神经网络 python代码 什么是单层神经网络_神经网络_06。每一个激活函数在接受输入的时候,他们接受的输入是加上了权值和偏执数的输入,所以在把输入放入激活函数中前,需要把其对应的单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_07单层网络 神经网络 python代码 什么是单层神经网络_深度学习_08定义好,就如下图所示。

单层网络 神经网络 python代码 什么是单层神经网络_感知器_09


对上图的说明:

(1)隐含层和输出层都有激活函数,所以它们都需要设置好权值单层网络 神经网络 python代码 什么是单层神经网络_深度学习_10和偏置数单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_11

(2)单层网络 神经网络 python代码 什么是单层神经网络_深度学习_05的n就代表他来自第几层。

(3)单层网络 神经网络 python代码 什么是单层神经网络_神经网络_06的n则是从隐含层开始,因为隐含层才开始有n。

(4)单层网络 神经网络 python代码 什么是单层神经网络_神经网络_06的i代表了它是该层的第几个单元。

(5)单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_07单层网络 神经网络 python代码 什么是单层神经网络_神经网络_16代表的是它是下一层哪个节点的输入,单层网络 神经网络 python代码 什么是单层神经网络_神经网络_17代表它是上一层的哪个节点的输出(如果学过离散数学,应该知道i其实代表着这是前一个节点的第几出度,j代表着这是后一节点的第几入度),这样有一个规范以后,可以方便我们后续的学习(它和参数矩阵化后的坐标一致,后面会细讲)。

1.4 单层神经网络的向前传播
上一章我们学过感知器模型的向后传播,就是把输入的结果通过激活函数处理,之后再计算误差,计算新的权值传递回来。其中,把输入的结果往前丢给激活函数处理,激活函数处理以后又往前丢出输出,这就是一个向前传播。后面我们把输出处理以后,得到新的权值,把这个新的权值丢回最开始的地方,这就是向后传播

其实单层神经网络向前还是向后的原理和感知器没有任何区别,为了进一步加深影响,我们还是从数学公式的角度来细讲一下什么是向前传播。如果你已经理解上面的那段话,那完全可以不看这里的内容。我们用刚才的图为例:

单层网络 神经网络 python代码 什么是单层神经网络_神经网络_18


第一次向前传播为,从输入层向隐含层的传播,输入了单层网络 神经网络 python代码 什么是单层神经网络_激活函数_19,输出为单层网络 神经网络 python代码 什么是单层神经网络_深度学习_20

单层网络 神经网络 python代码 什么是单层神经网络_激活函数_21

第二次向前传播为把单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_22向前传播到输出层单元处理,输出最终结果单层网络 神经网络 python代码 什么是单层神经网络_激活函数_04

单层网络 神经网络 python代码 什么是单层神经网络_感知器_24

当然,有时候输出不仅仅是一个,可以像第一次向前传播一样,列多个公式。

2. 训练单层神经网络的方法

2.1 介绍
我们在第一部分已经搭建了一个单层的神经网络模型,现在需要学习的就是如何去训练它,本部分十分的重要,因为这个训练方法在神经网络中是通用的,你学会了,你就可以去做自己的神经网络了。

2.2 梯度下降算法
梯度下降算法很关键,也很常用,是一个非常好用的算法。但是这个算法我们之前已经介绍过,就是我们之前说的训练感知器模型的方法。我们来用现有知识描述一下,并且附上一个测试代码描述:
(1)首先,我们假设我们的目标函数是单层网络 神经网络 python代码 什么是单层神经网络_深度学习_25,但是我们目前并且不知道这个z长这样样子,我们只知道输入的单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_26,输出的单层网络 神经网络 python代码 什么是单层神经网络_激活函数_27。我们知道有一个单层网络 神经网络 python代码 什么是单层神经网络_深度学习_05和一个单层网络 神经网络 python代码 什么是单层神经网络_神经网络_06,所以单层网络 神经网络 python代码 什么是单层神经网络_激活函数_30,我们的目标就是把这个函数猜测出来。我们先定义一下这个函数,记为funz:

def funcz(x,w,b):
    """
    @Description:z的公式
    """
    return w*x+b

(2)第二步,我们需要选择一个激活函数,这里我们选择Sigmoid函数
单层网络 神经网络 python代码 什么是单层神经网络_感知器_31
Sigmoid 的代码如下,需要用到numpy库,没有的在cmd里面pip install就行:

import numpy as np
def sigmoid(z):
    y = 1.0/(1+np.exp(-z))
    return y

(3)第三步,我们需要选择一个损失函数,这里我们选择使用均方差损失函数
单层网络 神经网络 python代码 什么是单层神经网络_感知器_32
代码如下:

def mse(y,ey):
    """
    @Description:y是输出的结果,ey是数学期望
    """
    return ((y-ey)**2)/2

(4)第四步,也是最关键的一步,求单层网络 神经网络 python代码 什么是单层神经网络_感知器_33,也就是求单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_34
我们先求一个单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_35单层网络 神经网络 python代码 什么是单层神经网络_神经网络_06的偏导数,根据复合函数求导法(也可根据链式求导法)可得:
单层网络 神经网络 python代码 什么是单层神经网络_感知器_37
单层网络 神经网络 python代码 什么是单层神经网络_激活函数_38
单层网络 神经网络 python代码 什么是单层神经网络_激活函数_39的求导,我们之前已经记过Sigmoid求导结果:
单层网络 神经网络 python代码 什么是单层神经网络_激活函数_40
最后对单层网络 神经网络 python代码 什么是单层神经网络_深度学习_41单层网络 神经网络 python代码 什么是单层神经网络_深度学习_05的偏导是很简单的:
单层网络 神经网络 python代码 什么是单层神经网络_感知器_43
把结果一到结果三代入公式一里面,可以得到最终结果,这也就是对以sigmoid为激活函数,用均方差为损失函数对单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_07求偏导的结果,看不懂没有关系,背下来即可:
单层网络 神经网络 python代码 什么是单层神经网络_感知器_45
这里给出其代码,我们就叫它delossw,用户可自己扩展到m组:

def delossw(y, ey,x):
    return (y-ey)*y(1-y)*x

我们可以很容易的把它扩展至有单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_46(也就是有多个输入,那也就要有多个输出):
单层网络 神经网络 python代码 什么是单层神经网络_深度学习_47
这里可能会有人有疑惑,因为我们发现它好像和单层网络 神经网络 python代码 什么是单层神经网络_深度学习_05无关,那岂不是如果有多个单层网络 神经网络 python代码 什么是单层神经网络_深度学习_05,每一个单层网络 神经网络 python代码 什么是单层神经网络_深度学习_05的变化都是一样的?其实不是这样的,因为我这里的例子只有一个单层网络 神经网络 python代码 什么是单层神经网络_深度学习_05,但是在实际情况下,至少都有2个单层网络 神经网络 python代码 什么是单层神经网络_深度学习_05,比如单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_53,可以看到不同的单层网络 神经网络 python代码 什么是单层神经网络_深度学习_05旁边的单层网络 神经网络 python代码 什么是单层神经网络_神经网络_55是不一样的,而这个公式是与单层网络 神经网络 python代码 什么是单层神经网络_神经网络_55有关的,所以不同的单层网络 神经网络 python代码 什么是单层神经网络_深度学习_05结果会不一样。同时这里的单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_58不是只单层网络 神经网络 python代码 什么是单层神经网络_激活函数_19这样,而是说有多组单层网络 神经网络 python代码 什么是单层神经网络_激活函数_60比如单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_61,所以对应的还是同一个单层网络 神经网络 python代码 什么是单层神经网络_深度学习_05。如果有多个单层网络 神经网络 python代码 什么是单层神经网络_深度学习_05,那么对每一个单层网络 神经网络 python代码 什么是单层神经网络_深度学习_05都要求一次偏导。

我们求单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_35单层网络 神经网络 python代码 什么是单层神经网络_神经网络_06的偏导数,我们如法炮制可以得到:
单层网络 神经网络 python代码 什么是单层神经网络_激活函数_67
我们不难发现,公式二和公式一几乎没有区别,唯一区别在于最后是单层网络 神经网络 python代码 什么是单层神经网络_激活函数_68
我们只需要求一下单层网络 神经网络 python代码 什么是单层神经网络_激活函数_68
单层网络 神经网络 python代码 什么是单层神经网络_深度学习_70
所以,单层网络 神经网络 python代码 什么是单层神经网络_深度学习_08求偏导的结果为
单层网络 神经网络 python代码 什么是单层神经网络_深度学习_72
代码如下,我们叫它delossb:

def delossb(y, ey):
    return (y-ey)*y*(1-y)

扩展到m个输入(输出),也就有m个b:
单层网络 神经网络 python代码 什么是单层神经网络_神经网络_73
这里有的人会认为delossw就是delossb在乘以x,但是要注意的是,仅仅在只有一组输如和输出时是这样的,如果有m组,那就不成立了,要分别写代码,因为:
单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_74

(5)接下来,我们只需要计算单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_07单层网络 神经网络 python代码 什么是单层神经网络_深度学习_08的变化值就可以了,公式如下:
单层网络 神经网络 python代码 什么是单层神经网络_激活函数_77
单层网络 神经网络 python代码 什么是单层神经网络_深度学习_78

代码如下,因为是向后传播,所以叫goback,学习率单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_79我设了0.9,因为发现运行的时候太慢了,但是设的太大可能导致无法收敛,所以要自己慢慢调整,后面会细讲:

def goback(w,b,x,y,ey):
    """
    :param w: 当前的w
    :param b: 当前的b
    :return: 新的wn,bn
    """
    a = 0.9 # 学习率
    db = delossb(y,ey)  # b的变化值
    dw = db*x           # w的变化值,注意,只有单输入输出时可以这么写
    wn = w - a*dw   # 新的w
    bn = b - a*db   # 新的b
    return wn,bn

(6)到了最后,我们就可以开始训练了,训练过程很简单,每次都计算一下损失函数loss,如果太大了就继续训练,直到loss可以到能接受的范围,代码如下单层网络 神经网络 python代码 什么是单层神经网络_深度学习_05单层网络 神经网络 python代码 什么是单层神经网络_神经网络_06一开始可以是任意值:

def net(w=1, b=1):
    while 1:
        """神经网络模型,可以先输入一组w和b"""
        z = funcz(1,w,b)
        y = sigmoid(z)
        ey = sigmoid(9)

        loss = (mse(y, ey))
        print(loss)
        if loss>=0.00000001:
            w,b = goback(w,b,x,y,ey)
        else:
            print(w,b)
            break

注意,如果你用的语言也是python,那千万别用递归的写法,如果递归会出现超过最大递归上限的错误(因为我们需要递归上千万次,但是这个超过python最大栈的阈值了),而且尾递归优化无效,这是因为python编译器没有进行尾递归优化(听不懂也没有关系,记得别递归就行,真的想知道就百度一下,我用网上找到装饰器也没有解决这个问题,所以直接放弃),如果用while循环则没有任何问题。

运行结果如下:精度是0.00000001时,它把数据逼近到都是4.1和4.1

这是因为我把x设为了1,所以公式一和公式二结果是一样的,如果我们把x换为2,ey变成12,结果会好很多,5.5和3.2不太准确的原因是只有一个输入,所以有多个结果:

单层网络 神经网络 python代码 什么是单层神经网络_激活函数_82


所以处理回归问题,尽可能别让输入为1。

整体代码如下,可以复制去pycharm上运行,感受一下:

@FileName:Simple_net.py
@Description:一个简单的神经网络模型:我们假设目前有一个公式是 z = 3x+6,将使用梯度下降的方法来获得这个公式
@Author:段鹏浩
@Time:2023/3/2 22:27
"""
import numpy as np
import sys

# sys.setrecursionlimit(1000000)  # 尝试用它解决递归问题,失败了

def funcz(x,w,b):
    """
    @Description:z的公式
    """
    return w*x+b

# 我们目前已经知道的输入有:
x = 2

# 那么输出就是:
ey = 12


# 我们选择Sigmoid函数作为我们的激活函数,Sigmoid函数可以这么定义
def sigmoid(z):
    y = 1.0/(1+np.exp(-z))
    return y

# 同时,我们选择均方差函数作为我们的损失函数,均方差函数如此定义:
def mse(y,ey):
    """
    @Description:y是输出的结果,ey是数学期望\n
    """
    return ((y-ey)**2)/2

# 对mse函数进行w求导可以得到,最后的偏导结果为:
def delossw(y, ey,x):
    return (y-ey)*y(1-y)*x

# 对mse函数的b求偏导。可以得到:
def delossb(y, ey):
    return (y-ey)*y*(1-y)


# 所以我们可以得出反向传播函数:
def goback(w,b,x,y,ey):
    """
    :param w: 当前的w
    :param b: 当前的b
    :return: 新的wn,bn
    """
    a = 0.9 # 学习率
    db = delossb(y,ey)  # b的变化值
    dw = db*x           # w的变化值
    wn = w - a*dw   # 新的w
    bn = b - a*db   # 新的b
    return wn,bn

def net(w=1, b=1):
    while 1:
        """神经网络模型,可以先输入一组w和b"""
        z = funcz(1,w,b)
        y = sigmoid(z)
        ey = sigmoid(12)

        loss = (mse(y, ey))
        print(loss)
        if loss>=0.00000001:	# 比较一下看看精度是否达标
            w,b = goback(w,b,x,y,ey)
        else:
            print(w,b)
            break

if __name__ == "__main__":
    net(1,1)

当然,这个代码是有缺陷的,因为它只能从低往高逼近,如果一开始单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_07单层网络 神经网络 python代码 什么是单层神经网络_深度学习_08设置的太大(大于5),代码就不能工作了,这是因为我们前面提到的Sigmoid函数具有数值较大时发生梯度消失的特性,后面我们将学习如何解决这样的情况。

3.反向传播算法

3.1 介绍

反向传播算法的思想是很重要的,所以即便你在上面的内容中已经认为自己十分理解反向传播的思想,也一定要在这里再巩固一下,因为无论是面试还是工作甚至是做研究,都会提到它。我们还是以刚刚的单层神经网络为例子:

单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_85


在这个例子中我们以sigmoid函数为激活函数,用交叉熵函数当损失函数,我们的目标是把误差传递回去,用来更新各个权值。我们把误差记为单层网络 神经网络 python代码 什么是单层神经网络_感知器_86,上标代表它在第几层,下标代表它是该层的哪一个节点传回来的误差。现在我们来一层层地分析一下。

3.2 输出层
输出层的误差只有一个节点,所以误差记为单层网络 神经网络 python代码 什么是单层神经网络_激活函数_87,所以可以得到公式,其实就是上面的梯度下降:
单层网络 神经网络 python代码 什么是单层神经网络_感知器_88
为什么单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_89是这样的呢,其实是用梯度下降推导来的:
单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_90
我们来一一算一下交叉熵函数的导数,很好求:
单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_91
之后的Sigmoid函数的导数我们是记得的:
单层网络 神经网络 python代码 什么是单层神经网络_感知器_92
最后:
单层网络 神经网络 python代码 什么是单层神经网络_神经网络_93
所以:
单层网络 神经网络 python代码 什么是单层神经网络_深度学习_94
我们可以看到一开始,在隐含层和输出层之间的参数并不是单层网络 神经网络 python代码 什么是单层神经网络_神经网络_55而是单层网络 神经网络 python代码 什么是单层神经网络_激活函数_04,所以在这里的规则是单层网络 神经网络 python代码 什么是单层神经网络_深度学习_97,到后面输入层和隐含层之间的参数才变成单层网络 神经网络 python代码 什么是单层神经网络_神经网络_55,这时的规则才是单层网络 神经网络 python代码 什么是单层神经网络_激活函数_99
这里我们可以发现,使用交叉熵和sigmoid配合的好处就是,我们只需要使用减法就能得到的单层网络 神经网络 python代码 什么是单层神经网络_深度学习_100就可以完成梯度下降的计算,不需要求导。

3.3 更新隐含层和输出层的权值
更新的话为了方便,直接使用单层网络 神经网络 python代码 什么是单层神经网络_激活函数_87,来对每一个权值单层网络 神经网络 python代码 什么是单层神经网络_深度学习_05都进行更新,需要用到的就是隐含层的各个y值,单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_79是学习率:
单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_104

3.4 计算出隐含层各个节点的误差
更新好隐含层和输出层各个节点的权值以后,就可以把误差继续往后传递,用到的是刚刚更新好的权值单层网络 神经网络 python代码 什么是单层神经网络_神经网络_105(因为已经修正过一遍,传下去的时候误差会减小一些,如果先用原本的和输出层的误差相乘,那么误差会被拉大)和输出层传过来的误差单层网络 神经网络 python代码 什么是单层神经网络_激活函数_87相乘,公式如下,这样,我们就计算出了隐含层每个节点的误差值
单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_107

3.5 更新输入层和隐含层之间的权值
输入层和隐含层之间的权值的更新方法和前面更新隐含层和输出层之间权值的方法一样:
这是和单层网络 神经网络 python代码 什么是单层神经网络_激活函数_60相连的权值:
单层网络 神经网络 python代码 什么是单层神经网络_激活函数_109
这是和单层网络 神经网络 python代码 什么是单层神经网络_感知器_110相连的权值:
单层网络 神经网络 python代码 什么是单层神经网络_激活函数_111

3.6 误差的反向传播总结
(1)计算输出层的误差单层网络 神经网络 python代码 什么是单层神经网络_深度学习_112;
(2)更新隐含层和输出层之间的权值:单层网络 神经网络 python代码 什么是单层神经网络_神经网络_113;
(3)用刚刚更新的权值和误差来计算隐含层的误差:单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_114;
(4)用隐含层的误差来更新输入层和隐含层之间的权值:单层网络 神经网络 python代码 什么是单层神经网络_感知器_115

4.简单的多层神经网络

4.1 什么是多层神经网络

在前面,我们介绍了单层神经网络,以及如何训练这个单层的神经网络,我们可以在前面的代码中看到,单层的神经网络的训练精度不是那么高,即便是设置精度到0.000001,训练200000万次,结果也不是那么好,而且关键的是sigmoid还会出现梯度消失问题,以及之前提到的ReLU函数是否有效的问题,都可用多层神经网络解决,因为一旦搭建了多层神经网络,就生成了更加复杂的数学结构,足以模拟任何的图形。其实多层神经网络的原理很简单,就是隐含层数目的增加,图形如下:

单层网络 神经网络 python代码 什么是单层神经网络_神经网络_116


一般而言,神经网络的层数,也就是隐含层越多,这个网络的精度也就越高,但是也就越复杂,代码写起来也就更困难,因为参数实在是太多了,我们可以用参数向量化的方法来规范参数的使用。同时,当神经网络的隐含层大于等于三层的时候,我们将其称之为深度学习

4.2 什么是矩阵
首先,如果你没有学过线性代数,那么我们在学习向量参数化前,需要首先了解一下什么是矩阵。在数学中,矩阵(Matrix)是一个按照长方阵列排列的复数或实数集合。由 m × n 个数aij排成的m行n列的数表称为m行n列的矩阵,简称m × n矩阵,记作A:
单层网络 神经网络 python代码 什么是单层神经网络_激活函数_117
这m×n 个数称为矩阵A的元素,简称为元,数aij位于矩阵A的第i行第j列,称为矩阵A的(i,j)元,以数 aij为(i,j)元的矩阵可记为(aij)或(aij)m × n,m×n矩阵A也记作Amn。元素是实数的矩阵称为实矩阵,元素是复数的矩阵称为复矩阵。而行数与列数都等于n的矩阵称为n阶矩阵或n阶方阵 。

4.3 矩阵基本运算法则:

现在我们有一个矩阵A一个矩阵B
单层网络 神经网络 python代码 什么是单层神经网络_神经网络_118
(1)加法:A+B,同位置相加就行,没有的加0
单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_119
(2)减法:和加法相同
单层网络 神经网络 python代码 什么是单层神经网络_感知器_120
(3)数乘:如果单层网络 神经网络 python代码 什么是单层神经网络_激活函数_121是一个实数,那么:
单层网络 神经网络 python代码 什么是单层神经网络_神经网络_122
(4)相乘:两个矩阵的乘法仅当第一个矩阵A的行的长度和另一个矩阵B的列的长度相等时才能定义,因为矩阵相乘就是用A的每一行乘以B的每一列对应元素,然后求和。如A是m×n矩阵和B是n×p矩阵,它们的乘积C是一个m×p矩阵。例如:A是一个2x3(两行三列)的矩阵,B是一个3x2(三行两列)的矩阵,可以得到一个2x2的矩阵:
单层网络 神经网络 python代码 什么是单层神经网络_深度学习_123

4.4 参数向量化

在掌握了什么是矩阵,以及矩阵的基本运算法则之后,我们开始学习参数的向量化。首先,向量就是有方向的量,可以理解为一维的矩阵,比如(x,y,z),x,y,z代表空间中的一条从原点发出的射线,它是有方向的。所以,我们也把一维的矩阵(不管是横的还是竖着的),叫做向量,不管是矩阵还是向量,在计算机里面就是数组,所以很好计算。我们将从向前传播和向后传播两个方面学习和理解参数的向量化。我们以n层神经网络,且忽略偏置数b为例,并且用sigmoid函数作为隐含层和输出层的激活函数(且假设输入都大于0),用交叉熵函数作为损失函数。用来参数化的例子,还是原来这张图:

单层网络 神经网络 python代码 什么是单层神经网络_深度学习_124

1.向前传播:
(1)从输入到隐含层:
单层网络 神经网络 python代码 什么是单层神经网络_神经网络_125
我们可以把单层网络 神经网络 python代码 什么是单层神经网络_深度学习_126单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_58,用矩阵的形式列出来:
单层网络 神经网络 python代码 什么是单层神经网络_神经网络_128
我们可以看到,只需要让单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_129就可以得到上面的公式中的数值,4x2和2x1的矩阵,可以得到一个4x1的矩阵,也就是一维数组,我们只需要遍历该数组,一一放入激活函数单层网络 神经网络 python代码 什么是单层神经网络_神经网络_03中即可。
(2)从隐含层到其他隐含层:
单层网络 神经网络 python代码 什么是单层神经网络_感知器_131
(3)从隐含层到输出层:
单层网络 神经网络 python代码 什么是单层神经网络_感知器_132
其实下面两个也是一样的,把上面的单层网络 神经网络 python代码 什么是单层神经网络_神经网络_55换成对应的单层网络 神经网络 python代码 什么是单层神经网络_激活函数_04就可以。
2.反向传播:
反向传播也特别简单,因为就三个公式:
(1)计算输出层误差
单层网络 神经网络 python代码 什么是单层神经网络_激活函数_135
如果y有多个,可以形成一个向量,那么单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_136也写成一个向量就可以,可以写多个重复的。
(2)计算隐含层误差
单层网络 神经网络 python代码 什么是单层神经网络_激活函数_137
这里插个题外话,为了防止弄混,这里申明一下,正向传播时,单层网络 神经网络 python代码 什么是单层神经网络_深度学习_138是拿单层网络 神经网络 python代码 什么是单层神经网络_神经网络_139单层网络 神经网络 python代码 什么是单层神经网络_激活函数_140计算的,反向传播时,单层网络 神经网络 python代码 什么是单层神经网络_感知器_141是拿单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_142单层网络 神经网络 python代码 什么是单层神经网络_神经网络_143计算的。
于是我们只需要把单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_89单层网络 神经网络 python代码 什么是单层神经网络_深度学习_05的数值排列成矩阵,然后进行矩阵乘法就行。
(4)权值更新
单层网络 神经网络 python代码 什么是单层神经网络_深度学习_146
其中单层网络 神经网络 python代码 什么是单层神经网络_神经网络_147,不仅涉及到矩阵的乘法,还有矩阵的数乘运算,参考上面即可。

4.5 Python如何操作矩阵
我们用一个例子来描述矩阵的创建,以及各种运算。
目前我们有两个矩阵:
单层网络 神经网络 python代码 什么是单层神经网络_感知器_148
(1)创建矩阵,这时候我们需要用到numpy库

import numpy as np

之后我们创建A和B,用到的是numpy库的mat函数,注意,传入的必须是一个矩阵,所以[]不能漏,而且只能传入一个,所以是数组嵌套数组的形式:

"""
@FileName:matrix.py
@Description:矩阵的基本运算
@Author:段鹏浩
@Time:2023/3/5 14:31
"""
import numpy as np

A = np.mat([[1,3,5],[7,9,11]])
B = np.mat([[2,4],[6,8],[10,12]])


if __name__ == "__main__":
    print(A)
    print("")
    print(B)

输出结果如下:

单层网络 神经网络 python代码 什么是单层神经网络_单层网络 神经网络 python代码_149


(2)矩阵加法:

直接加就行,需注意,这里做加法,两个矩阵规模必须一样,不然会报错,你只能手动补零,让两个一样

"""
@FileName:matrix.py
@Description:矩阵的基本运算
@Author:段鹏浩
@Time:2023/3/5 14:31
"""
import numpy as np

A = np.mat([[1,3,5],[7,9,11]])
B = np.mat([[2,4],[6,8],[10,12]])
C=A+A


if __name__ == "__main__":
    print(C)

结果是:

单层网络 神经网络 python代码 什么是单层神经网络_激活函数_150


(3)矩阵乘法:和加法一样的

"""
@FileName:matrix.py
@Description:矩阵的基本运算
@Author:段鹏浩
@Time:2023/3/5 14:31
"""
import numpy as np

A = np.mat([[1,3,5],[7,9,11]])
B = np.mat([[2,4],[6,8],[10,12]])
C=A-A


if __name__ == "__main__":
    print(C)

结果如下:

单层网络 神经网络 python代码 什么是单层神经网络_激活函数_151


(4)数乘运算:直接乘就行,注意:没有除法

"""
@FileName:matrix.py
@Description:矩阵的基本运算
@Author:段鹏浩
@Time:2023/3/5 14:31
"""
import numpy as np

A = np.mat([[1,3,5],[7,9,11]])
B = np.mat([[2,4],[6,8],[10,12]])
C=3*A


if __name__ == "__main__":
    print(C)

结果如下:

单层网络 神经网络 python代码 什么是单层神经网络_感知器_152


(5)矩阵乘法:

也是直接乘就行,特别方便,当然,还有一种dot函数的用法,结果是一样的:

"""
@FileName:matrix.py
@Description:矩阵的基本运算
@Author:段鹏浩
@Time:2023/3/5 14:31
"""
import numpy as np

A = np.mat([[1,3,5],[7,9,11]])
B = np.mat([[2,4],[6,8],[10,12]])
C=A*B
D=np.dot(A,B)


if __name__ == "__main__":
    print(C)
    print("")
    print(D)

结果如下:

单层网络 神经网络 python代码 什么是单层神经网络_激活函数_153


(6)矩阵的另一种表示法,更加常用,是array函数的用法,但是做乘法只能用dot的方法:

"""
@FileName:matrix.py
@Description:矩阵的基本运算
@Author:段鹏浩
@Time:2023/3/5 14:31
"""
import numpy as np

A = np.array([[1,3,5],[7,9,11]])
B = np.array([[2,4],[6,8],[10,12]])
D=np.dot(A,B)
E=A+A
F=A-A
G=3*A


if __name__ == "__main__":
    print(D)
    print(E)
    print(F)
    print(G)

运行结果如下:

单层网络 神经网络 python代码 什么是单层神经网络_感知器_154

5.本章总结

在这一章,我们学习了单层神经网络和多层神经网络的结构,学习了梯度下降和反向传播的思想,并且写了一个简单的神经网络代码。同时还学习了参数向量法,以及如何进行矩阵的运算代码。下一章,我们将学习更复杂的多层神经网络----卷积神经网络的各种知识。