目录
[3.1 从感知机到神经网络](#3.1 从感知机到神经网络)
[3.1.1 神经网络的例子](#3.1.1 神经网络的例子)
[3.1.2 复习感知机](#3.1.2 复习感知机)
[3.1.3 激活函数登场](#3.1.3 激活函数登场)
[3.2 激活函数](#3.2 激活函数)
[3.2.1 sigmoid函数](#3.2.1 sigmoid函数)
[3.2.2 阶跃函数的实现](#3.2.2 阶跃函数的实现)
[3.2.3 阶跃函数的图形](#3.2.3 阶跃函数的图形)
[3.2.4 sigmoid函数的实现](#3.2.4 sigmoid函数的实现)
[3.2.5 sigmoid函数和阶跃函数的比较](#3.2.5 sigmoid函数和阶跃函数的比较)
[3.2.6 非线性函数](#3.2.6 非线性函数)
[3.2.7 ReLU函数](#3.2.7 ReLU函数)
[3.3 多维数组的运算](#3.3 多维数组的运算)
[3.3.1 多维数组](#3.3.1 多维数组)
[3.3.2 矩阵乘法](#3.3.2 矩阵乘法)
[3.3.3 神经网络的内积 下面我们使用NumPy矩阵来实现神经网络。这个神经网络省略了偏置和激活函数,只有权重。](#3.3.3 神经网络的内积 下面我们使用NumPy矩阵来实现神经网络。这个神经网络省略了偏置和激活函数,只有权重。)
[3.4 3层神经网络的实现](#3.4 3层神经网络的实现)
[3.4.1 符号确认](#3.4.1 符号确认)
[3.4.2 各层间信号传递的实现](#3.4.2 各层间信号传递的实现)
[3.4.3 代码实现小结](#3.4.3 代码实现小结)
[3.5 输出层的设计](#3.5 输出层的设计)
[3.5.1 恒等函数和 softmax函数](#3.5.1 恒等函数和 softmax函数)
[3.5.2 实现 softmax函数时的注意事项](#3.5.2 实现 softmax函数时的注意事项)
[3.5.3 softmax函数的特征](#3.5.3 softmax函数的特征)
[3.5.4 输出层的神经元数量](#3.5.4 输出层的神经元数量)
[3.6 手写数字识别](#3.6 手写数字识别)
[3.6.1 MNIST数据集](#3.6.1 MNIST数据集)
[3.6.2 神经网络的推理处理](#3.6.2 神经网络的推理处理)
[3.6.3 批处理](#3.6.3 批处理)
[3.7 小结](#3.7 小结)
关于感知机,既有好消息,也有坏消息。
好消息是,即便对于复杂的函数,感知机也隐含着能够表示它的可能性。即便是计算机进行的复杂处理,感知机(理论上)也可以将 其表示出来。
坏消息是,设定权重的工作,即确定合适的、能符合预期的输入与输出的权重,现在还是由人工进行的。
神经网络的出现就是为了解决刚才的坏消息。具体地讲,神经网络的一个重要性质是它可以自动地从数据中学习到合适的权重参数。
3.1 从感知机到神经网络
3.1.1 神经网络的例子
用图来表示神经网络

图中的网络一共由 3层神经元构成,但实质上只有 2层神经元有权重,因此将其称为"2层网络"。
请注意,有的书也会根据构成网络的层数,把图中的网络称为"3层网络"。本书将根据实质上拥有权重的层数(输入层、隐藏层、输出层的总数减去 1后的数量)来表示网络的名称。
神经网络的形状类似上一章的感知机。实际上,就神经元的连接方式而言,与上一章的感知机并没有任何差异。那么,神经网络中信号是如何传递的呢?
3.1.2 复习感知机

感知机接收x1和x2两个输入信号,输出y。如果用数学式来表示图3-2中的感知机,则如下式所示。

b是被称为偏置的参数,用于控制神经元被激活的容易程度;而w1和w2是表示各个信号的权重的参数,用于控制各个信号的重要性
上图的网络中,偏置b并没有被画出来。如果要明确地表示出b,则如下图

这 个感知机将x1、x2、1三个信号作为神经元的输入,将其和各自的权重相乘后, 传送至下一个神经元。在下一个神经元中,计算这些加权信号的总和。如果这个总和超过0,则输出1,否则输出0。另外,由于偏置的输入信号一直是1,所以为了区别于其他神经元,我们在图中把这个神经元整个涂成灰色。
为了简化上面的式子,我们用一个函数来表示这种分情况的动作(超过0则输出1,否则输出0)。引入新函数h(x),改写成下面的式(3.2)和式(3.3)


式(3.2)中,输入信号的总和会被函数h(x)转换,转换后的值就是输出y。
3.1.3 激活函数登场
刚才登场的h(x)函数会将输入信号的总和转换为输出信号,这种函数一般称为激活函数
现在来进一步改写式(3.2)。式(3.2)分两个阶段进行处理,先计算输入信号的加权总和,然后用激活函数转换这一总和。因此,如果将式(3.2)写得详细一点,则可以分成下面两个式子。

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

如图所示,表示神经元的○中明确显示了激活函数的计算过程,即信号的加权总和为节点a,然后节点a被激活函数h()转换成节点y。本书中,"神经元"和"节点"两个术语的含义相同。这里,我们称a和y为"节点",其实它和之前所说的"神经元"含义相同。

左图是一般的神经元的图,右图是在神经元内部明确显示激活函数的计算过程的图(a 表示输入信号的总和,h()表示激活函数,y表示输出)
下面,我们将仔细介绍激活函数。激活函数是连接感知机和神经网络的桥梁。
3.2 激活函数
式(3.3)表示的激活函数以阈值为界,一旦输入超过阈值,就切换输出。这样的函数称为"阶跃函数"。因此,可以说感知机中使用了阶跃函数作为激活函数。也就是说,在激活函数的众多候选函数中,感知机使用了阶跃函数。
那么,如果感知机使用其他函数作为激活函数的话会怎么样呢?实际上,如果将激活函数从阶跃函数换成其他函数,就可以进入神经网络的世界了。下面我们就来介绍一下神经网络使用的激活函数。
3.2.1 sigmoid函数

式(3.6)中的exp(−x)表示

的意思。e是纳皮尔常数2.7182 ...。式(3.6)表示的sigmoid函数看上去有些复杂,但它也仅仅是个函数而已。而函数就是给定某个输入后,会返回某个输出的转换器。比如,向sigmoid函数输入1.0或2.0后,就会有某个值被输出,类似h(1.0) = 0.731 ...、h(2.0) = 0.880 ...这样。
神经网络中用sigmoid函数作为激活函数,进行信号的转换,转换后的信号被传送给下一个神经元。实际上,上一章介绍的感知机和接下来要介绍 的神经网络的主要区别就在于这个激活函数。
3.2.2 阶跃函数的实现
可以像下面这样简单地实现阶跃函数。

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

下面我们通过Python解释器的例子来看一下这里用了什么技巧。下面这个例子中准备了NumPy数组x,并对这个NumPy数组进行了不等号运算。


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

如上所示,可以用astype()方法转换NumPy数组的类型。以上就是阶跃函数的实现中所用到的NumPy的"技巧"。
3.2.3 阶跃函数的图形
下面我们就用图来表示上面定义的阶跃函数,为此需要使用matplotlib库。


阶跃函数以0为界,输出从0切换为1(或者从1切换为0)。它的值呈阶梯式变化,所以称为阶跃函数。
3.2.4 sigmoid函数的实现
下面,我们来实现sigmoid函数。用Python可以像下面这样写出式(3.6)表示的sigmoid函数。

这里,np.exp(-x)对应exp(−x)。
如果在这个sigmoid函数中输入一个NumPy数组,则结果如下所示。

之所以sigmoid函数的实现能支持NumPy数组,秘密就在于NumPy的广播功能(1.5.5)。
下面我们把sigmoid函数画在图上。


3.2.5 sigmoid函数和阶跃函数的比较
首先注意到的是"平滑性"的不同。sigmoid函数是一条平滑的曲线,输出随着输入发生连续性的变化。而阶跃函数以0为界,输出发生急剧性的变化。sigmoid函数的平滑性对神经网络的学习具有重要意义。
另一个不同点是,相对于阶跃函数只能返回0或1,sigmoid函数可以返回0.731 ...、0.880 ...等实数。
也就是说,感知机中神经元之间流动的是0或1的二元信号,而神经网络中流动的是连续的实数值信号。
3.2.6 非线性函数
阶跃函数和sigmoid函数还有其他共同点,就是两者均为非线性函数。
线性函数是一条笔直的直线。而非线性函数,顾名思义,指的是不像线性函数那样呈现出一条直线的函数
神经网络的激活函数必须使用非线性函数。换句话说,激活函数不能使用线性函数。为什么不能使用线性函数呢?因为使用线性函数的话,加深神经网络的层数就没有意义了。
线性函数的问题在于,不管如何加深层数,总是存在与之等效的"无隐藏层的神经网络"。为了具体地(稍微直观地)理解这一点,我们来思考下面这个简单的例子。
这里我们考虑把线性函数 h(x) = cx 作为激活函数,把y(x) = h(h(h(x)))的运算对应3层神经网络A。这个运算会进行 y(x) = c × c × c × x的乘法运算,但是同样的处理可以由y(x) = ax(注意,a = c的三次方)这一次乘法运算(即没有隐藏层的神经网络)来表示。如本例所示,使用线性函数时,无法发挥多层网络带来的优势。因此,为了发挥叠加层所带来的优势,激活函数必须使用非线性函数。
3.2.7 ReLU函数
在神经网络发展的历史上,sigmoid函数很早就开始被使用了,而最近则主要
使用ReLU(Rectified Linear Unit)函数。
ReLU函数在输入大于0时,直接输出该值;在输入小于等于0时,输出0。

ReLU函数可以表示为下面的式(3.7)。

因此,ReLU函数的实现也很简单,可以写成如下形式。

这里使用了NumPy的maximum函数。maximum函数会从输入的数值中选择较大的那个值进行输出。
3.3 多维数组的运算
3.3.1 多维数组

数组的维数可以通过np.dim()函数获得。此外,数组的形状可以通过实例变量shape获得。
下面我们来生成一个二维数组。

这里生成了一个3 × 2的数组B。3 × 2的数组表示第一个维度有3个元素,第二个维度有2个元素。另外,第一个维度对应第0维,第二个维度对应第1维(Python的索引从0开始)。二维数组也称为矩阵。
3.3.2 矩阵乘法

矩阵的乘积是通过左边矩阵的行(横向)和右边矩阵的列(纵向)以对应元素的方式相乘后再求和而得到的。
比如,A的第1行和B的第1列的乘积结果是新数组的第1行第1列的元素,A的第2行和B的第1列的结果是新数组的第2行第1列的元素。


np.dot()接收两个NumPy数组作为参数,并返回数组的乘积。
这里要注意的是,np.dot(A, B)和np.dot(B, A)的值可能不一样。
2 × 3的矩阵和3 × 2 的矩阵的乘积可按如下形式用Python来实现。

矩阵A的第1维的元素个数(列数)必须和矩阵B的第0维的元素个数(行数)相等。
如果这两个值不相等,则无法计算矩阵的乘积。比如,如果用Python计算2 × 3 的矩阵A和2 × 2的矩阵C的乘积,则会输出如下错误。



另外,当A是二维矩阵、B是一维数组时,对应维度的元素个数要保持一致的原则依然成立。
可按如下方式用Python实现


3.3.3 神经网络的内积 下面我们使用NumPy矩阵来实现神经网络。这个神经网络省略了偏置和激活函数,只有权重。

实现该神经网络时,要注意X、W、Y的形状,特别是X和W的对应维度的元素个数是否一致,这一点很重要。


如上所示,使用np.dot(多维数组的点积),可以一次性计算出Y 的结果。
这意味着,即便Y 的元素个数为100或1000,也可以通过一次运算就计算出结果!如果不使用np.dot,就必须单独计算Y 的每一个元素(或者说必须使用for语句),非常麻烦。因此,通过矩阵的乘积一次性完成计算的技巧,在实现的层面上可以说是非常重要的。
3.4 3层神经网络的实现

3层神经网络:输入层(第0层)有2个神经元,第1个隐藏层(第1层)有3个神经元,第2个隐藏层(第2层)有2个神经元,输出层(第3层)有2个神经元
3.4.1 符号确认
在介绍神经网络中的处理之前,我们先导入

等符号。
如图所示,权重和隐藏层的神经元的右上角有一个"(1)",它表示权重和神经元的层号(即第1层的权重、第1层的神经元)。此外,权重的右下角有两个数字,它们是后一层的神经元和前一层的神经元的索引号。
比如,表示前一层的第2个神经元

到后一层的第1个神经元

的权重。权重右下角按照"后一层的索引号、前一层的索引号"的顺序排列。

3.4.2 各层间信号传递的实现
现在看一下从输入层到第1层的第1个神经元的信号传递过程

为了确认前面的内容,现在用数学式表示

。

此外,如果使用矩阵的乘法运算,则可以将第1层的加权和表示成下面的式

其中,A(1) 、X、B(1) 、W(1) 如下所示。

++下图为从输入层到第1层的信号传递++

++第1层到第2层的信号传递++

++从第2层到输出层的信号传递++

3.4.3 代码实现小结
现在我们把之前的代码实现全部整理一下。这里,我们按照神经网络的实现惯例,只把权重记为大
写字母W1,其他的(偏置或中间结果等)都用小写字母表示。



这里定义了init_network()和forward()函数。init_network()函数会进行权重和偏置的初始化,并将它们保存在字典变量network中。这个字典变量network中保存了每一层所需的参数(权重和偏置)。forward()函数中则封装了将输入信号转换为输出信号的处理过程。
另外,这里出现了forward(前向)一词,它表示的是从输入到输出方向的传递处理。后面在进行神经网络的训练时,我们将介绍后向(backward,从输出到输入方向)的处理。
3.5 输出层的设计
神经网络可以用在分类问题和回归问题上,不过需要根据情况改变输出层的激活函数。一般而言,回归问题用恒等函数,分类问题用softmax函数。
机器学习的问题大致可以分为分类问题和回归问题。分类问题是数据属于哪一个类别的问题。比如,区分图像中的人是男性还是女性的问题就是分类问题。而回归问题是根据某个输入预测一个(连续的)数值的问题。比如,根据一个人的图像预测这个人的体重的问题就是回归问题(类似"57.4kg"这样的预测)。
3.5.1 恒等函数和 softmax函数
恒等函数会将输入按原样输出,对于输入的信息,不加以任何改动地直接输出。因此,在输出层使用恒等函数时,输入信号会原封不动地被输出。
另外,将恒等函数的处理过程用之前的神经网络图来表示的话,则如图所示。和前面介绍的隐藏层的激活函数一样,恒等函数进行的转换处理可以用一根箭头来表示。

分类问题中使用的softmax函数可以用下面的式(3.10)表示。

exp(x)是表示

的指数函数(e是纳皮尔常数2.7182 ...)。
式(3.10)表示假设输出层共有n个神经元,计算第k个神经元的输出yk。如式(3.10)所示,softmax函数的分子是输入信号ak的指数函数,分母是所有输入信号的指数函数的和。
用图表示softmax函数的话,如图所示,softmax函数的输出通过箭头与所有的输入信号相连。这是因为,从式(3.10)可以看出,输出层的各个神经元都受到所有输入信号的影响。

现在我们来实现softmax函数。



3.5.2 实现 softmax函数时的注意事项
上面的softmax函数的实现虽然正确描述了式(3.10),但在计算机的运算上有一定的缺陷。这个缺陷就是溢出问题。
softmax函数的实现中要进行指
数函数的运算,但是此时指数函数的值很容易变得非常大。比如,

的值会超过20000,

会变成一个后面有40多个0的超大值,

的结果会返回一个表示无穷大的inf。如果在这些超大值之间进行除法运算,结果会出现"不确定"的情况。

式(3.11)说明,在进行softmax的指数函数的运算时,加上(或者减去)某个常数并不会改变运算的结果。这里的

可以使用任何值,但是为了防止溢出,一般会使用输入信号中的最大值。我们来看一个具体的例子。

如该例所示,通过减去输入信号中的最大值(上例中的c),我们发现原本为nan(not a number,不确定)的地方,现在被正确计算了。综上,我们可以像下面这样实现softmax函数。

3.5.3 softmax函数的特征
使用softmax()函数,可以按如下方式计算神经网络的输出。

如上所示,softmax函数的输出是0.0到1.0之间的实数。并且,softmax函数的输出值的总和是1。输出总和为1是softmax函数的一个重要性质。正因为有了这个性质,我们才可以把softmax函数的输出解释为"概率"。
比如,上面的例子可以解释成y[0]的概率是0.018(1.8 %),y[1]的概率是0.245(24.5 %),y[2]的概率是0.737(73.7 %)。从概率的结果来看,可以说"因为第2个元素的概率最高,所以答案是第2个类别"。而且,还可以回答"有74 %的概率是第2个类别,有25 %的概率是第1个类别,有1 %的概率是第0个类别"。也就是说,通过使用softmax函数,我们可以用概率的(统计的)方法处理问题。
a的最大值是第2个元素,y的最大值也仍是第2个元素。
一般而言,神经网络只把输出值最大的神经元所对应的类别作为识别结果。
并且,即便使用softmax函数,输出值最大的神经元的位置也不会变。因此,神经网络在进行分类时,输出层的softmax函数可以省略。
3.5.4 输出层的神经元数量
输出层的神经元数量需要根据待解决的问题来决定。对于分类问题,输出层的神经元数量一般设定为类别的数量。比如,对于某个输入图像,预测是图中的数字0到9中的哪一个的问题(10类别分类问题),可以像图3-23这样,将输出层的神经元设定为10个。
如图3-23所示,在这个例子中,输出层的神经元从上往下依次对应数字0, 1, ..., 9。此外,图中输出层的神经元的值用不同的灰度表示。这个例子中神经元y2颜色最深,输出的值最大。这表明这个神经网络预测的是y2对应的类别,也就是"2"。

3.6 手写数字识别
这里我们来进行手写数字图像的分类。假设学习已经全部结束,我们使用学习到的参数,先实现神经网络的"推理处理"。这个推理处理也称为神经网络的前向传播(forward propagation)。
3.6.1 MNIST数据集
这里使用的数据集是MNIST手写数字图像集。MNIST是机器学习领域最有名的数据集之一,被应用于从简单的实验到发表的论文研究等各种场合。
实际上,在阅读图像识别或机器学习的论文时,MNIST数据集经常作为实验用的数据出现。
MNIST数据集是由0到9的数字图像构成的。训练图像有6万张,测试图像有1万张,这些图像可以用于学习和推理。MNIST数据集的一般使用方法是,先用训练图像进行学习,再用学习到的模型度量能在多大程度 上对测试图像进行正确的分类。

MNIST的图像数据是28像素 × 28像素的灰度图像(1通道),各个像素的取值在0到255之间。每个图像数据都相应地标有"7""2""1"等标签。
首先,为了导入父目录中的文件,进行相应的设定A。然后,导入dataset/mnist.py中的 load_mnist函数。最后,使用 load_mnist函数,读入MNIST数据集。第一次调用load_mnist函数时,因为要下载MNIST数据集,所以需要接入网络。第2次及以后的调用只需读入保存在本地的文件(pickle文件)即可,因此处理所需的时间非常短。


load_mnist函数以"(训练图像 ,训练标签 ),(测试图像,测试标签 )"的形式返回读入的MNIST数据。
此外,还可以像load_mnist(normalize=True, flatten=True, one_hot_label=False) 这 样,设 置 3 个 参 数。第 1 个参数normalize设置是否将输入图像正规化为0.0~1.0的值。如果将该参数设置为False,则输入图像的像素会保持原来的0~255。第2个参数flatten设置是否展开输入图像(变成一维数组)。如果将该参数设置为False,则输入图像为1 × 28 × 28的三维数组;若设置为True,则输入图像会保存为由784个元素构成的一维数组。第3个参数one_hot_label设置是否将标签保存为one-hot表示(one-hot representation)。one-hot表示是仅正确解标签为1,其余皆为0的数组,就像[0,0,1,0,0,0,0,0,0,0]这样。当one_hot_label为False时,只是像7、2这样简单保存正确解标签;当one_hot_label为True时,标签则
保存为one-hot表示。
现在,我们试着显示MNIST图像,同时也确认一下数据。图像的显示使用PIL(Python Image Library)模块。执行下述代码后,训练图像的第一张就会显示出来,如图3-25所示(源代码在ch03/mnist_show.py中)。


这里需要注意的是,flatten=True时读入的图像是以一列(一维)NumPy数组的形式保存的。因此,显示图像时,需要把它变为原来的28像素 × 28像素的形状。可以通过reshape()方法的参数指定期望的形状,更改NumPy数组的形状。此外,还需要把保存为NumPy数组的图像数据转换为PIL用的数据对象,这个转换处理由Image.fromarray()来完成。
3.6.2 神经网络的推理处理
下面,我们对这个MNIST数据集实现神经网络的推理处理。神经网络的输入层有784个神经元,输出层有10个神经元。输入层的784这个数字来源于图像大小的28 × 28 = 784,输出层的10这个数字来源于10类别分类(数字0到9,共10类别)。此外,这个神经网络有2个隐藏层,第1个隐藏层有50个神经元,第2个隐藏层有100个神经元。这个50和100可以设置为任何值。
下面我们先定义get_data()、init_network()、predict()这3个函数(代码在ch03/neuralnet_mnist.py中)。


init_network()会读入保存在pickle文件sample_weight.pkl中的学习到的权重参数。这个文件中以字典变量的形式保存了权重和偏置参数。剩余的2个函数,和前面介绍的代码实现基本相同,无需再解释。现在,我们用这3个函数来实现神经网络的推理处理。然后,评价它的识别精度(accuracy),即能在多大程度上正确分类。

首先获得MNIST数据集,生成网络。接着,用for语句逐一取出保存在x中的图像数据,用predict()函数进行分类。predict()函数以NumPy数组的形式输出各个标签对应的概率。比如输出[0.1, 0.3, 0.2, ..., 0.04的
数组,该数组表示"0"的概率为0.1,"1"的概率为0.3,等等。然后,我们取出这个概率列表中的最大值的索引(第几个元素的概率最高),作为预测结果。可以用np.argmax(x)函数取出数组中的最大值的索引,np.argmax(x)将获取被赋给参数x的数组中的最大值元素的索引。最后,比较神经网络所预测的答案和正确解标签,将回答正确的概率作为识别精度。
执行上面的代码后,会显示"Accuracy:0.9352"。这表示有93.52 %的数据被正确分类了。
另外,在这个例子中,我们把load_mnist函数的参数normalize设置成了True。将normalize设置成True后,函数内部会进行转换,将图像的各个像素值除以255,使得数据的值在0.0~1.0的范围内。像这样把数据限定到某个范围内的处理称为正规化(normalization)。此外,对神经网络的输入数据进行某种既定的转换称为预处理(pre-processing)。这里,作为对输入图像的一种预处理,我们进行了正规化。
3.6.3 批处理
现在我们来关注输入数据和权重参数的"形状"。再看一下刚才的代码实现。



从整体的处理流程来看,图3-26中,输入一个由784个元素(原本是一个28 × 28的二维数组)构成的一维数组后,输出一个有10个元素的一维数组。这是只输入一张图像数据时的处理流程。
现在我们来考虑打包输入多张图像的情形。比如,我们想用predict()函数一次性打包处理100张图像。为此,可以把x的形状改为100 × 784,将100张图像打包作为输入数据。用图表示的话,如下图所示。

如图 3-27 所示,输入数据的形状为 100 × 784,输出数据的形状为100 × 10。这表示输入的100张图像的结果被一次性输出了。比如,x[0]和y[0]中保存了第0张图像及其推理结果,x[1]和y[1]中保存了第1张图像及其推理结果,等等。
这种打包式的输入数据称为批(batch)。批有"捆"的意思,图像就如同纸币一样扎成一捆。
批处理对计算机的运算大有利处,可以大幅缩短每张图像的处理时间,是因为大多数处理
数值计算的库都进行了能够高效处理大型数组运算的最优化。并且,在神经网络的运算中,当数据传送成为瓶颈时,批处理可以减轻数据总线的负荷

我们来逐个解释粗体的代码部分。首先是range()函数。range()函数若指定为range(start, end),则会生成一个由start到end-1之间的整数构成的列表。若像range(start, end, step)这样指定3个整数,则生成的列表中的下一个元素会增加step指定的值。我们来看一个例子。


在range()函数生成的列表的基础上,通过x[i:i+batch_size]从输入数据中抽出批数据。x[i:i+batch_n]会取出从第i个到第i+batch_n个之间的数据。
本例中是像x[0:100]、x[100:200]......这样,从头开始以100为单位将数据提取为批数据。
然后,通过argmax()获取值最大的元素的索引。不过这里需要注意的是,我们给定了参数axis=1。这指定了在100 × 10的数组中,沿着第1维方向(以第1维为轴)找到值最大的元素的索引(第0维对应第1个维度)A。这里也来看一个例子。

最后,我们比较一下以批为单位进行分类的结果和实际的答案。为此,需要在NumPy数组之间使用比较运算符(==)生成由True/False构成的布尔型数组,并计算True的个数。我们通过下面的例子进行确认。

3.7 小结
本章介绍了神经网络的前向传播。本章介绍的神经网络和上一章的感知机在信号的按层传递这一点上是相同的,但是,向下一个神经元发送信号时,改变信号的激活函数有很大差异。神经网络中使用的是平滑变化的sigmoid函数,而感知机中使用的是信号急剧变化的阶跃函数。
- 神经网络中的激活函数使用平滑变化的sigmoid函数或ReLU函数。
- 通过巧妙地使用NumPy多维数组,可以高效地实现神经网络。
- 机器学习的问题大体上可以分为回归问题和分类问题。
- 关于输出层的激活函数,回归问题中一般用恒等函数,分类问题中一般用softmax函数。
- 分类问题中,输出层的神经元的数量设置为要分类的类别数。
- 输入数据的集合称为批。通过以批为单位进行推理处理,能够实现高速的运算。