首页 > 其他分享 >神经网络--深度学习(1)

神经网络--深度学习(1)

时间:2024-09-11 23:23:48浏览次数:3  
标签:阶跃 函数 sigmoid -- 矩阵 神经网络 数组 深度 NumPy

上一章我们学习了感知机。关于感知机,既有好消息,也有坏消息。好
消息是,即便对于复杂的函数,感知机也隐含着能够表示它的可能性。上一
章已经介绍过,即便是计算机进行的复杂处理,感知机(理论上)也可以将
其表示出来。坏消息是,设定权重的工作,即确定合适的、能符合预期的输
入与输出的权重,现在还是由人工进行的。上一章中,我们结合与门、或门
的真值表人工决定了合适的权重。
神经网络的出现就是为了解决刚才的坏消息。具体地讲,神经网络的一
个重要性质是它可以自动地从数据中学习到合适的权重参数。本章中,我们
会先介绍神经网络的概要,然后重点关注神经网络进行识别时的处理。在下
一章中,我们将了解如何从数据中学习权重参数。

3.1 从感知机到神经网络
神经网络和上一章介绍的感知机有很多共同点。这里,我们主要以两者
的差异为中心,来介绍神经网络的结构。
3.1.1 神经网络的例子
用图来表示神经网络的话,如图 3-1 所示。我们把最左边的一列称为
输入层,最右边的一列称为输出层,中间的一列称为中间层。中间层有时

也称为隐藏层。“隐藏”一词的意思是,隐藏层的神经元(和输入层、输出
层不同)肉眼看不见。另外,本书中把输入层到输出层依次称为第 0 层、第
1 层、第 2 层(层号之所以从 0 开始,是为了方便后面基于 Python 进行实现)。
图 3-1 中,第 0 层对应输入层,第 1 层对应中间层,第 2 层对应输出层。

图 3-1 中的网络一共由 3 层神经元构成,但实质上只有 2 层神经
元有权重,因此将其称为“2 层网络”。请注意,有的书也会根据
构成网络的层数,把图 3-1 的网络称为“3 层网络”。本书将根据
实质上拥有权重的层数(输入层、隐藏层、输出层的总数减去 1
后的数量)来表示网络的名称。

3.1.2 复习感知机
在观察神经网络中信号的传递方法之前,我们先复习一下感知机。现在

b 是被称为偏置的参数,用于控制神经元被激活的容易程度;而 w1 和 w2
是表示各个信号的权重的参数,用于控制各个信号的重要性。
顺便提一下,在图 3-2 的网络中,偏置 b 并没有被画出来。如果要明确
地表示出 b,可以像图 3-3 那样做。图 3-3 中添加了权重为 b 的输入信号 1。这
个感知机将 x1、x2、1 三个信号作为神经元的输入,将其和各自的权重相乘后,
传送至下一个神经元。在下一个神经元中,计算这些加权信号的总和。如果
这个总和超过 0,则输出 1,否则输出 0。另外,由于偏置的输入信号一直是 1,
所以为了区别于其他神经元,我们在图中把这个神经元整个涂成灰色。
现在将式(3.1)改写成更加简洁的形式。为了简化式(3.1),我们用一个
函数来表示这种分情况的动作(超过 0 则输出 1,否则输出 0)。引入新函数
h(x),将式(3.1)改写成下面的式(3.2)和式(3.3)。
y = h(b + w1x1 + w2x2) (3.2)

3.1.3 激活函数登场
刚才登场的 h(x)函数会将输入信号的总和转换为输出信号,这种函数
一般称为激活函数(activation function)。如“激活”一词所示,激活函数的
作用在于决定如何来激活输入信号的总和。
现在来进一步改写式(3.2)。式(3.2)分两个阶段进行处理,先计算输入
信号的加权总和,然后用激活函数转换这一总和。因此,如果将式(3.2)写
得详细一点,则可以分成下面两个式子。
a = b + w1x1 + w2x2 (3.4)
y = h(a) (3.5)
首先,式(3.4)计算加权输入信号和偏置的总和,记为 a。然后,式(3.5)
用 h() 函数将 a 转换为输出 y。

之前的神经元都是用一个○表示的,如果要在图中明确表示出式(3.4)
和式(3.5),则可以像图 3-4 这样做。

如图 3-4 所示,表示神经元的○中明确显示了激活函数的计算过程,即
信号的加权总和为节点 a,然后节点 a 被激活函数 h() 转换成节点 y。本书中,“神
经元”和“节点”两个术语的含义相同。这里,我们称 a 和 y 为“节点”,其实
它和之前所说的“神经元”含义相同。
通常如图 3-5 的左图所示,神经元用一个○表示。本书中,在可以明确
神经网络的动作的情况下,将在图中明确显示激活函数的计算过程,如图 3-5
的右图所示。

下面,我们将仔细介绍激活函数。激活函数是连接感知机和神经网络的
桥梁。

本书在使用“感知机”一词时,没有严格统一它所指的算法。一
般而言,“朴素感知机”是指单层网络,指的是激活函数使用了阶
跃函数 A 的模型。“多层感知机”是指神经网络,即使用 sigmoid
函数(后述)等平滑的激活函数的多层网络。

(阶跃函数是指一旦输入超过阈值,就切换输出的函数。)

3.2 激活函数
式(3.3)表示的激活函数以阈值为界,一旦输入超过阈值,就切换输出。
这样的函数称为“阶跃函数”。因此,可以说感知机中使用了阶跃函数作为
激活函数。也就是说,在激活函数的众多候选函数中,感知机使用了阶跃函数。
那么,如果感知机使用其他函数作为激活函数的话会怎么样呢?实际上,如
果将激活函数从阶跃函数换成其他函数,就可以进入神经网络的世界了。下
面我们就来介绍一下神经网络使用的激活函数。

信号被传送给下一个神经元。实际上,上一章介绍的感知机和接下来要介绍
的神经网络的主要区别就在于这个激活函数。其他方面,比如神经元的多层
连接的构造、信号的传递方法等,基本上和感知机是一样的。下面,让我们
通过和阶跃函数的比较来详细学习作为激活函数的 sigmoid 函数。

3.2.2 阶跃函数的实现
这里我们试着用 Python 画出阶跃函数的图(从视觉上确认函数的形状对
理解函数而言很重要)。阶跃函数如式(3.3)所示,当输入超过 0 时,输出 1,
否则输出 0。可以像下面这样简单地实现阶跃函数。

这个实现简单、易于理解,但是参数 x 只能接受实数(浮点数)。也就是
说,允许形如 step_function(3.0) 的调用,但不允许参数取 NumPy 数组,例
如 step_function(np.array([1.0, 2.0]))。为了便于后面的操作,我们把它修
改为支持 NumPy 数组的实现。为此,可以考虑下述实现。

对 NumPy 数组进行不等号运算后,数组的各个元素都会进行不等号运算,
生成一个布尔型数组。这里,数组 x 中大于 0 的元素被转换为 True,小于等
于 0 的元素被转换为 False,从而生成一个新的数组 y。
数组 y 是一个布尔型数组,但是我们想要的阶跃函数是会输出 int 型的 0
或 1 的函数。因此,需要把数组 y 的元素类型从布尔型转换为 int 型。

如上所示,可以用 astype() 方法转换 NumPy 数组的类型。astype() 方
法通过参数指定期望的类型,这个例子中是 np.int 型。Python 中将布尔型
转换为 int 型后,True 会转换为 1,False 会转换为 0。以上就是阶跃函数的
实现中所用到的 NumPy 的“技巧”。

3.2.3 阶跃函数的图形
下面我们就用图来表示上面定义的阶跃函数,为此需要使用 matplotlib 库。
import numpy as np
import matplotlib.pylab as plt
def step_function(x):
return np.array(x > 0, dtype=np.int)
x = np.arange(-5.0, 5.0, 0.1)
y = step_function(x)
plt.plot(x, y)
plt.ylim(-0.1, 1.1) # 指定 y 轴的范围
plt.show()
np.arange(-5.0, 5.0, 0.1) 在 −5.0 到 5.0 的范围内,以 0.1 为单位,生成
NumPy 数组([-5.0, -4.9, ���, 4.9])。step_function() 以该 NumPy 数组为
参数,对数组的各个元素执行阶跃函数运算,并以数组形式返回运算结果。
对数组 x、y 进行绘图,结果如图 3-6 所示。

NumPy 数组([-5.0, -4.9, ���, 4.9])。step_function() 以该 NumPy 数组为
参数,对数组的各个元素执行阶跃函数运算,并以数组形式返回运算结果。
对数组 x、y 进行绘图,结果如图 3-6 所示。

如图 3-6 所示,阶跃函数以 0 为界,输出从 0 切换为 1(或者从 1 切换为 0)。
它的值呈阶梯式变化,所以称为阶跃函数

3.2.4 sigmoid 函数的实现
下面,我们来实现 sigmoid 函数。用 Python 可以像下面这样写出式(3.6)
表示的 sigmoid 函数。
def sigmoid(x):
return 1 / (1 + np.exp(-x))
这里,np.exp(-x) 对应 exp(−x)。这个实现没有什么特别难的地方,但
是要注意参数 x 为 NumPy 数组时,结果也能被正确计算。实际上,如果在
这个 sigmoid 函数中输入一个 NumPy 数组,则结果如下所示。
>>> x = np.array([-1.0, 1.0, 2.0])
>>> sigmoid(x)
array([ 0.26894142, 0.73105858, 0.88079708])

之所以 sigmoid 函数的实现能支持 NumPy 数组,秘密就在于 NumPy 的
广播功能(1.5.5 节)。根据 NumPy 的广播功能,如果在标量和 NumPy 数组
之间进行运算,则标量会和 NumPy 数组的各个元素进行运算。这里来看一
个具体的例子。

.在这个例子中,标量(例子中是 1.0)和 NumPy 数组之间进行了数值运
算(+、/ 等)。结果,标量和 NumPy 数组的各个元素进行了运算,运算结
果以 NumPy 数组的形式被输出。刚才的 sigmoid 函数的实现也是如此,因
为 np.exp(-x) 会生成 NumPy 数组,所以 1 / (1 + np.exp(-x)) 的运算将会在
NumPy 数组的各个元素间进行。
下面我们把 sigmoid 函数画在图上。画图的代码和刚才的阶跃函数的代
码几乎是一样的,唯一不同的地方是把输出 y 的函数换成了 sigmoid 函数

3.2.5 sigmoid 函数和阶跃函数的比较
现在我们来比较一下 sigmoid 函数和阶跃函数,如图 3-8 所示。两者的
不同点在哪里呢?又有哪些共同点呢?我们通过观察图 3-8 来思考一下。
观察图 3-8,首先注意到的是“平滑性”的不同。sigmoid 函数是一条平
滑的曲线,输出随着输入发生连续性的变化。而阶跃函数以 0 为界,输出发
生急剧性的变化。sigmoid 函数的平滑性对神经网络的学习具有重要意义。

另一个不同点是,相对于阶跃函数只能返回 0 或 1,sigmoid 函数可以返
回 0.731 . . .、0.880 . . . 等实数(这一点和刚才的平滑性有关)。也就是说,感
知机中神经元之间流动的是 0 或 1 的二元信号,而神经网络中流动的是连续
的实数值信号。
如果把这两个函数与水联系起来,则阶跃函数可以比作“竹筒敲石”A,
sigmoid 函数可以比作“水车”。阶跃函数就像竹筒敲石一样,只做是否传送
水(0 或 1)两个动作,而 sigmoid 函数就像水车一样,根据流过来的水量相应
地调整传送出去的水量。
接着说一下阶跃函数和 sigmoid 函数的共同性质。阶跃函数和 sigmoid
函数虽然在平滑性上有差异,但是如果从宏观视角看图 3-8,可以发现它们
具有相似的形状。实际上,两者的结构均是“输入小时,输出接近 0(为 0);
随着输入增大,输出向 1 靠近(变成 1)”。也就是说,当输入信号为重要信息时,
阶跃函数和 sigmoid 函数都会输出较大的值;当输入信号为不重要的信息时,
两者都输出较小的值。还有一个共同点是,不管输入信号有多小,或者有多
大,输出信号的值都在 0 到 1 之间。
3.2.6 非线性函数
阶跃函数和 sigmoid 函数还有其他共同点,就是两者均为非线性函数。
sigmoid 函数是一条曲线,阶跃函数是一条像阶梯一样的折线,两者都属于
非线性的函数。
在介绍激活函数时,经常会看到“非线性函数”和“线性函数”等术语。
函数本来是输入某个值后会返回一个值的转换器。向这个转换器输
入某个值后,输出值是输入值的常数倍的函数称为线性函数(用数学
式表示为 h(x) = cx。c 为常数)。因此,线性函数是一条笔直的直线。
而非线性函数,顾名思义,指的是不像线性函数那样呈现出一条直
线的函数。

神经网络的激活函数必须使用非线性函数。换句话说,激活函数不能使
用线性函数。为什么不能使用线性函数呢?因为使用线性函数的话,加深神
经网络的层数就没有意义了。
线性函数的问题在于,不管如何加深层数,总是存在与之等效的“无
隐 藏 层 的 神 经 网 络”。为 了 具 体 地(稍 微 直 观 地)理 解 这 一 点,我 们 来 思
考 下 面 这 个 简 单 的 例 子。这 里 我 们 考 虑 把 线 性 函 数 h(x) = cx 作 为 激 活
函 数,把 y(x) = h(h(h(x))) 的 运 算 对 应 3 层 神 经 网 络 A。这 个 运 算 会 进 行
y(x) = c × c × c × x 的乘法运算,但是同样的处理可以由 y(x) = ax(注意,
a = c 3
)这一次乘法运算(即没有隐藏层的神经网络)来表示。如本例所示,
使用线性函数时,无法发挥多层网络带来的优势。因此,为了发挥叠加层所
带来的优势,激活函数必须使用非线性函数。

3.2.7 ReLU 函数
到目前为止,我们介绍了作为激活函数的阶跃函数和 sigmoid 函数。在
神经网络发展的历史上,sigmoid 函数很早就开始被使用了,而最近则主要
使用 ReLU(Rectified Linear Unit)函数。
ReLU 函数在输入大于 0 时,直接输出该值;在输入小于等于 0 时,输
出 0(图 3-9)。
ReLU 函数可以表示为下面的式 (3.7)。

这里使用了 NumPy 的 maximum 函数。maximum 函数会从输入的数值中选
择较大的那个值进行输出。
本章剩余部分的内容仍将使用 sigmoid 函数作为激活函数,但在本书的
后半部分,则将主要使用 ReLU 函数。

3.3 多维数组的运算
如果掌握了 NumPy 多维数组的运算,就可以高效地实现神经网络。因此,
本节将介绍 NumPy 多维数组的运算,然后再进行神经网络的实现。
3.3.1 多维数组
简单地讲,多维数组就是“数字的集合”,数字排成一列的集合、排成
长方形的集合、排成三维状或者(更加一般化的)N 维状的集合都称为多维数
组。下面我们就用 NumPy 来生成多维数组,先从前面介绍过的一维数组开始。

如上所示,数组的维数可以通过 np.dim() 函数获得。此外,数组的形状
可以通过实例变量 shape 获得。在上面的例子中,A 是一维数组,由 4 个元素
构成。注意,这里的 A.shape 的结果是个元组(tuple)。这是因为一维数组的
情况下也要返回和多维数组的情况下一致的结果。例如,二维数组时返回的
是元组 (4,3),三维数组时返回的是元组 (4,3,2),因此一维数组时也同样以
元组的形式返回结果。下面我们来生成一个二维数组。

这里生成了一个 3 × 2 的数组 B。3 × 2 的数组表示第一个维度有 3 个元素,
第二个维度有 2 个元素。另外,第一个维度对应第 0 维,第二个维度对应第
1 维(Python 的索引从 0 开始)。二维数组也称为矩阵(matrix)。如图 3-10 所示,
数组的横向排列称为行(row),纵向排列称为列(column)。
3.3.2 矩阵乘法
下面,我们来介绍矩阵(二维数组)的乘积。比如 2 × 2 的矩阵,其乘积
可以像图 3-11 这样进行计算(按图中顺序进行计算是规定好了的)。

如本例所示,矩阵的乘积是通过左边矩阵的行(横向)和右边矩阵的列(纵
向)以对应元素的方式相乘后再求和而得到的。并且,运算的结果保存为新
的多维数组的元素。比如,A 的第 1 行和 B 的第 1 列的乘积结果是新数组的
第 1 行第 1 列的元素,A 的第 2 行和 B 的第 1 列的结果是新数组的第 2 行第 1
列的元素。另外,在本书的数学标记中,矩阵将用黑斜体表示(比如,矩阵
A),以区别于单个元素的标量(比如,a 或 b)。这个运算在 Python 中可以用
如下代码实现。

这 里,A 和 B 都 是 2 × 2 的 矩 阵,它 们 的 乘 积 可 以 通 过 NumPy 的
np.dot() 函数计算(乘积也称为点积)。np.dot() 接收两个 NumPy 数组作为参
数,并返回数组的乘积。这里要注意的是,np.dot(A, B) 和 np.dot(B, A) 的
值可能不一样。和一般的运算(+ 或 * 等)不同,矩阵的乘积运算中,操作数(A、
B)的顺序不同,结果也会不同。
这里介绍的是计算 2 × 2 形状的矩阵的乘积的例子,其他形状的矩阵的
乘积也可以用相同的方法来计算。比如,2 × 3 的矩阵和 3 × 2 的矩阵的乘积
可按如下形式用 Python 来实现。

2 × 3 的矩阵 A 和 3 × 2 的矩阵 B 的乘积可按以上方式实现。这里需要
注意的是矩阵的形状(shape)。具体地讲,矩阵 A 的第 1 维的元素个数(列数)
必须和矩阵 B 的第 0 维的元素个数(行数)相等。在上面的例子中,矩阵 A
的形状是 2 × 3,矩阵 B 的形状是 3 × 2,矩阵 A 的第 1 维的元素个数(3)和
矩阵 B 的第 0 维的元素个数(3)相等。如果这两个值不相等,则无法计算矩
阵的乘积。比如,如果用 Python 计算 2 × 3 的矩阵 A 和 2 × 2 的矩阵 C 的乘
积,则会输出如下错误。

2 × 3 的矩阵 A 和 3 × 2 的矩阵 B 的乘积可按以上方式实现。这里需要
注意的是矩阵的形状(shape)。具体地讲,矩阵 A 的第 1 维的元素个数(列数)
必须和矩阵 B 的第 0 维的元素个数(行数)相等。在上面的例子中,矩阵 A
的形状是 2 × 3,矩阵 B 的形状是 3 × 2,矩阵 A 的第 1 维的元素个数(3)和
矩阵 B 的第 0 维的元素个数(3)相等。如果这两个值不相等,则无法计算矩
阵的乘积。比如,如果用 Python 计算 2 × 3 的矩阵 A 和 2 × 2 的矩阵 C 的乘
积,则会输出如下错误。

这个错误的意思是,矩阵 A 的第 1 维和矩阵 C 的第 0 维的元素个数不一
致(维度的索引从 0 开始)。也就是说,在多维数组的乘积运算中,必须使两
个矩阵中的对应维度的元素个数一致,这一点很重要。我们通过图 3-12 再来
确认一下。

图 3-12 中,3 × 2 的矩阵 A 和 2 × 4 的矩阵 B 的乘积运算生成了 3 × 4 的
矩阵 C。如图所示,矩阵 A 和矩阵 B 的对应维度的元素个数必须保持一致。
此外,还有一点很重要,就是运算结果的矩阵 C 的形状是由矩阵 A 的行数
和矩阵 B 的列数构成的。
另外,当 A 是二维矩阵、B 是一维数组时,如图 3-13 所示,对应维度
的元素个数要保持一致的原则依然成立。
可按如下方式用 Python 实现图 3-13 的例子。

标签:阶跃,函数,sigmoid,--,矩阵,神经网络,数组,深度,NumPy
From: https://blog.csdn.net/Darling912/article/details/142150671

相关文章

  • 感知机--深度学习
    本章将介绍感知机A(perceptron)这一算法。感知机是由美国学者FrankRosenblatt在1957年提出来的。为何我们现在还要学习这一很久以前就有的算法呢?因为感知机也是作为神经网络(深度学习)的起源的算法。因此,学习感知机的构造也就是学习通向神经网络和深度学习的一种重要思想......
  • requests.exceptions.ConnectionError: (‘Connection aborted .’, ConnectionResetE
    requests.exceptions.ConnectionError:(‘Connectionaborted.’,ConnectionResetError(10054,"远程主机强迫关闭了一个现有的连接。',None,1656,None)欢迎来到英杰社区https://bbs.csdn.net/topics/617804998        欢迎来到我的主页,我是博......
  • Python毕业设计基于Django的 校园菜鸟驿站管理系统
    文末获取资源,收藏关注不迷路文章目录一、项目介绍二、主要使用技术三、研究内容四、核心代码五、文章目录一、项目介绍首先,以需求为依据,根据需求分析结果进行了系统的设计,并将其划分为管理员和用户二种角色和多个主要模块:用户、快递类型、快递信息、取件信息等。......
  • Python毕业设计基于Django的毕业设计选题管理系统
    文末获取资源,收藏关注不迷路文章目录一、项目介绍二、主要使用技术三、研究内容四、核心代码五、文章目录一、项目介绍本文讲述了毕业设计选题管理系统。结合电子管理系统的特点,分析了毕业设计选题管理系统的背景,给出了毕业设计选题管理系统实现的设计方案。本论......
  • 20240909_111725 c语言 关于进位制
    各种进制注意:在较老的版本如VisualStudio2010中,C语言不支持直接使用0b开头来表示二进制数。对于八进制数,如果写成intnum=12;这是十进制的12,如果要明确表示八进制的12,可以写成intnum=012;测一测注,包含了语法错误的情况......
  • 利用AI驱动智能BI数据可视化-深度评测Amazon Quicksight(三)
    简介随着生成式人工智能的兴起,传统的BI报表功能已经无法满足用户对于自动化和智能化的需求,今天我们将介绍亚马逊云科技平台上的AI驱动数据可视化神器–Quicksight,利用生成式AI的能力来加速业务决策,从而提高业务生产力。借助Quicksight中集成的AmazonQ的创作功能,业务分析......
  • 【Unity精品源码】Auto Chess: 自走棋策略游戏开发框架
    ......
  • 在长度 2N 的数组中找出重复 N 次的元素
    给你一个整数数组 nums ,该数组具有以下属性:nums.length==2*n.nums 包含 n+1 个 不同的 元素nums 中恰有一个元素重复 n 次找出并返回重复了 n 次的那个元素。示例1:输入:nums=[1,2,3,3]输出:3示例2:输入:nums=[2,1,2,5,3,2]输出:2示例3:输入:nums......
  • SortableTableView:Android 表格视图库
    在Android应用开发中,提供用户交云和数据展示的功能是非常重要的。SortableTableView是一个开源的Android库,它提供了一个简单的TableView组件以及一个更高级的可排序TableView,允许开发者实现复杂的表格视图和数据排序功能。文章目录......
  • 信号和槽介绍、使用方式
    一、信号与槽的简介    信号与槽是Qt的编程基础,是Qt编程的核心特性,也是Qt区别与其它C++开发框架的重要特性。    信号:是在特定情况下被发射的通知,例如QPushButton较常见的信号就是点击时发射的clicked()信号。GUI程序设计的主要工作就是对界面上各组件的信......