海北wap网站建设公司,展厅设计装修公司,工商局企业信息查询系统官网,怎样在wordpress里面调出菜单基本是《深度学习入门-基于Python的理论与实现》的复制粘贴#xff0c;以作为日后的检索和查询使用
感知机
感知机接收多个输入信号#xff0c;输出一个信号。
感知机原理
感知机接收多个输入信号#xff0c;输出一个信号。 图2-1是一个接收两个输入信号的感知机的例子。…基本是《深度学习入门-基于Python的理论与实现》的复制粘贴以作为日后的检索和查询使用
感知机
感知机接收多个输入信号输出一个信号。
感知机原理
感知机接收多个输入信号输出一个信号。 图2-1是一个接收两个输入信号的感知机的例子。 x1、 x2是输入信号y是输出信号 w1、 w2是权重。 图2-1 有两个输入的感知机 感知机公式 y { 0 ( w 1 x 1 w 2 x 2 ⩽ θ ) 1 ( w 1 x 1 w 2 x 2 θ ) ( 2.1 ) y\begin{cases}0(w_1x_1w_2x_2\leqslant\theta)\\1(w_1x_1w_2x_2\theta)\end{cases}\quad(2.1) y{01(w1x1w2x2⩽θ)(w1x1w2x2θ)(2.1)
实现与门
输入
x1x2y000100010111
满足图2-2的条件的参数的选择方法有无数多个。比如当(w1, w2, θ) (0.5, 0.5, 0.7) 时可以满足图 2-2 的条件。此外当 (w1, w2, θ)为(0.5, 0.5, 0.8)或者(1.0, 1.0, 1.0)时同样也满足与门的条件。设定这样的参数后仅当x1和x2同时为1时信号的加权总和才会超过给定的阈值θ。
实现与非门
x1x2y001101011110
表示与非门可以用(w1, w2, θ) (-0.5, -0.5, -0.7)这样的组合其 他的组合也是无限存在的。
实现或门
x1x2y000101011111
感知机实现
与门实现
def AND(x1, x2):w1, w2, theta 0.5, 0.5, 0.7tmp x1 * w1 x2 * w2if tmp theta:return 0elif tmp theta:return 1导入权重和偏置
为了后续的拓展与使用改成另一种表现形式。把式2.1的θ换成-b于是就可以用式2.2来表示感知机的行为 y { 0 ( b w 1 x 1 w 2 x 2 ⩽ 0 ) 1 ( b w 1 x 1 w 2 x 2 0 ) ( 2.2 ) y\begin{cases}0(bw_1x_1w_2x_2\leqslant0)\\1(bw_1x_1w_2x_20)\end{cases}\quad(2.2) y{01(bw1x1w2x2⩽0)(bw1x1w2x20)(2.2)
导入权重和偏置-与门的实现
def AND(x1, x2):x np.array([x1, x2])w np.array([0.5, 0.5])b -0.7tmp np.sum(w * x) bif tmp 0:return 0else:return 1w1和w2是控制输入信号的重要性的参数而偏置是调整神经元被激活的容易程度输出信号为1的程度的参数。 -θ命名为偏置b若b为-0.1则只要输入信号的加权总和超过0.1神经元就会被激活。但是如果b为-20.0则输入信号的加权总和必须超过20.0神经元才会被激活。
导入权重和偏执-与非门的实现
def NAND(x1, x2):x np.array([x1, x2])w np.array([-0.5, -0.5]) # 仅权重和偏置与AND不同b 0.7tmp np.sum(w * x) bif tmp 0:return 0else:return 1导入权重和偏执-或门的实现
def OR(x1, x2):x np.array([x1, x2])w np.array([0.5, 0.5]) # 仅权重和偏置与AND不同b -0.2tmp np.sum(w * x) bif tmp 0:return 0else:return 1感知机的局限性
异或门
x1x2y000101011110 如图所示圆形代表0三角形代表1我们不能使用一条直线将0和1分开
线性和非线性
由曲线分割而成的空间称为非线性空间由直线分割而成的空间称为线性空间。
多层感知机
感知机的绝妙之处在于它可以“叠加层”进而可以实现本部可以直接实现的异或门
x1x2s1s2y00100101110111111010
异或门的实现
def XOR(x1, x2):s1 NAND(x1, x2)s2 OR(x1, x2)y AND(s1, s2)return y多层感知机
与门、或门是单层感知机异或门是2层感知机 。叠加了多层的感知机也称为多层感知机 。
神经网络
关于感知机即便对于复杂的函数感知机也隐含着能够表示它的可能性。 但是设定权重的工作即确定合适的、能符合预期的输入与输出的权重现在还是由人工进行的。 神经网络的出现就是为了解决这个问题神经网络的一个重要性质是它可以自动地从数据中学习到合适的权重参数。
从感知机到神经网络
神经网络是什么样的
用图来表示神经网络的话如图3-1所示。最左边的一列称为输入层最右边的一列称为输出层中间的一列称为中间层隐藏层。 输入层到输出层依次称为第0层、第1层、第2层。图3-1中第0层对应输入层第1层对应中间层第2层对应输出层。 对于感知机如果要明确地表示出b可以像图3-3那样做。图3-3中添加了权重为b的输入信号1。这个感知机将x1、 x2、 1三个信号作为神经元的输入将其和各自的权重相乘后传送至下一个神经元。在下一个神经元中计算这些加权信号的总和。如果这个总和超过0则输出1否则输出0。另外由于偏置的输入信号一直是1所以为了区别于其他神经元我们在图中把这个神经元整个涂成灰色。
感知机
使用感知机来接收x1和x2两个输入信号输出y。用数学式来表示如式3.1所示。 y { 0 ( b w 1 x 1 w 2 x 2 ⩽ 0 ) 1 ( b w 1 x 1 w 2 x 2 0 ) ( 3.1 ) y\begin{cases}0(bw_1x_1w_2x_2\leqslant0)\\1(bw_1x_1w_2x_20)\end{cases}\quad(3.1) y{01(bw1x1w2x2⩽0)(bw1x1w2x20)(3.1)
加入偏置b 我们用一个函数来表示这种分情况的动作超过0则输出1否则输出0。引入新函数h(x)。 y h ( b w 1 x 1 w 2 x 2 ) ( 3.2 ) yh(bw_1x_1w_2x_2)\quad(3.2) yh(bw1x1w2x2)(3.2) h ( x ) { 0 ( x ⩽ 0 ) 1 ( x 0 ) ( 3.3 ) h(x)\begin{cases}0(x\leqslant0)\\1(x0)\end{cases}\quad(3.3) h(x){01(x⩽0)(x0)(3.3) 在y中输入信号的总和会被函数h(x)转换转换后的值就是输出y。h(x)表示的函数在输入超过0时返回1否则返回0。
使用激活函数
h(x) 函数会将输入信号的总和转换为输出信号这种函数一般称为激活函数激活函数的作用在于决定如何来激活输入信号的总和。 现在来进一步改写式3.2。式3.2分两个阶段进行处理先计算输入信号的加权总和然后用激活函数转换这一总和。因此如果将式3.2写得详细一点则可以分成下面两个式子。 首先式3.4计算加权输入信号和偏置的总和记为a。然后式3.5用h()函数将a转换为输出y。 a b w 1 x 1 w 2 x 2 ( 3.4 ) y h ( a ) ( 3.5 ) \begin{aligned}abw_1x_1w_2x_2(3.4)\\[2ex]yh(a)(3.5)\end{aligned} aybw1x1w2x2h(a)(3.4)(3.5) 通常如图3-5的左图所示神经元用一个○表示。本书中在可以明确神经网络的动作的情况下将在图中明确显示激活函数的计算过程如图3-5的右图所示。 图3-5 左图是一般的神经元的图右图是在神经元内部明确显示激活函数的计算过程的图a表示输入信号的总和 h()表示激活函数 y表示输出
激活函数
如式3.3以阈值为界输入超过阈值就切换输出这样的函数称为“阶跃函数”。感知机使用的就是阶跃函数。更换了其他函数之后就可以进神经网络了。 阶跃函数只能返回0或1 sigmoid函数可以返回任意小数等实数
sigmoid函数
神经网络中经常使用的一个激活函数就是式3.6表示的sigmoid函数 h ( x ) 1 1 exp ( − x ) ( 3.6 ) h(x)\dfrac{1}{1\exp(-x)}\quad(3.6) h(x)1exp(−x)1(3.6) exp(-x)表示e-x的意思。
实现阶跃函数
import numpy as np
import matplotlib.pylab as pltdef step_function(x):return np.array(x 0, dtypenp.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()实现sigmoid函数
import numpy as np
import matplotlib.pylab as pltdef sigmoid(x):return 1 / (1 np.exp(-x))x np.arange(-5.0, 5.0, 0.1)
y sigmoid(x)
plt.plot(x, y)
plt.ylim(-0.1, 1.1) # 指定y轴的范围
plt.show()非线性函数
阶跃函数和sigmoid函数还有其他共同点就是两者均为非线性函数。 神经网络的激活函数必须使用非线性函数。 使用线性函数的话加深神经网络的层数就没有意义了。 线性函数的问题在于不管如何加深层数总是存在与之等效的“无隐藏层的神经网络”。 如果使用线性函数 h(x) cx 作为激活函数把y(x) h(h(h(x)))的运算对应3层神经网络 A。这个运算会进行y(x) c × c × c × x的乘法运算但是同样的处理可以由y(x) ax注意a c3这一次乘法运算即没有隐藏层的神经网络来表示。此时无法发挥多层网络带来的优势。 因此为了发挥叠加层所带来的优势激活函数必须使用非线性函数。
ReLU函数
ReLU函数在输入大于0时直接输出该值在输入小于等于0时输出0图3-9。 h ( x ) { x ( x 0 ) 0 ( x ⩽ 0 ) ( 3.7 ) h(x)\begin{cases}x(x0)\\0(x\leqslant0)\end{cases}\quad(3.7) h(x){x0(x0)(x⩽0)(3.7) 实现
import numpy as np
import matplotlib.pyplot as plt# 定义ReLU函数
def ReLU(x):return np.maximum(0, x)x np.linspace(-5, 5, 100)
y ReLU(x)plt.plot(x, y, linewidth2)
plt.xlabel(x)
plt.ylabel(ReLU(x))
plt.title(ReLU Function)
plt.show()3层神经网络的实现 用数学公式表示a1(1)通过加权信号和偏置按如下方式进行计算 a 1 ( 1 ) w 11 ( 1 ) x 1 w 12 ( 1 ) x 2 b 1 ( 1 ) ( 3.8 ) a_1^{(1)}w_{11}^{(1)}x_1w_{12}^{(1)}x_2b_1^{(1)}\quad(3.8) a1(1)w11(1)x1w12(1)x2b1(1)(3.8) 使用矩阵乘法可以将第1层的加权和表示成小面的式3.9 A ( 1 ) X W ( 1 ) B ( 1 ) ( 3.9 ) A^{(1)}XW^{(1)}B^{(1)}\quad(3.9) A(1)XW(1)B(1)(3.9) 其中 A(1)、X、B(1)、W(1)如下所示 A ( 1 ) ( a 1 ( 1 ) a 2 ( 1 ) a 3 ( 1 ) ) , X ( x 1 x 2 ) , B ( 1 ) ( b 1 ( 1 ) b 2 ( 1 ) b 3 ( 1 ) ) W ( 1 ) ( w 11 ( 1 ) w 21 ( 1 ) w 31 ( 1 ) w 12 ( 1 ) w 22 ( 1 ) w 32 ( 1 ) ) \begin{aligned} A^{(1)} \begin{pmatrix}a_{1}^{(1)}a_{2}^{(1)}a_{3}^{(1)}\end{pmatrix},\boldsymbol{X}\begin{pmatrix}x_{1}x_{2}\end{pmatrix},\boldsymbol{B}^{(1)}\begin{pmatrix}b_{1}^{(1)}b_{2}^{(1)}b_{3}^{(1)}\end{pmatrix} \\ W(1) \begin{pmatrix}w_{11}^{(1)}w_{21}^{(1)}w_{31}^{(1)}\\w_{12}^{(1)}w_{22}^{(1)}w_{32}^{(1)}\end{pmatrix} \end{aligned} A(1)(a1(1)a2(1)a3(1)),X(x1x2),B(1)(b1(1)b2(1)b3(1))W(1)(w11(1)w12(1)w21(1)w22(1)w31(1)w32(1)) 使用NumPy多维数组来实现
import numpy as npdef sigmoid(x):return 1 / (1 np.exp(-x))
def identity_function(x):return x输入层 - 第一层
X np.array([1.0, 0.5])
W1 np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
B1 np.array([0.1, 0.2, 0.3])
print(W1.shape) # (2, 3)
print(X.shape) # (2,)
print(B1.shape) # (3,)
A1 np.dot(X, W1) B1
Z1 sigmoid(A1)
print(A1) # [0.3, 0.7, 1.1]
print(Z1) # [0.57444252, 0.66818777, 0.75026011]第一层 - 第二层
A2 np.dot(Z1, W2) B2
Z2 sigmoid(A2)
print(A2) # [0.51615984 1.21402696]
print(Z2) # [0.62624937 0.7710107 ]第二层 - 输出层
W3 np.array([[0.1, 0.3], [0.2, 0.4]])
B3 np.array([0.1, 0.2])
A3 np.dot(Z2, W3) B3
Y identity_function(A3) # 或者Y A3
print(A3) # [0.31682708 0.69627909]
print(Y) # [0.31682708 0.69627909]代码小结
import numpy as npdef sigmoid(x):return 1 / (1 np.exp(-x))def identity_function(x):return xdef init_network():network {}network[W1] np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])network[b1] np.array([0.1, 0.2, 0.3])network[W2] np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])network[b2] np.array([0.1, 0.2])network[W3] np.array([[0.1, 0.3], [0.2, 0.4]])network[b3] np.array([0.1, 0.2])return networkdef forward(network, x):W1, W2, W3 network[W1], network[W2], network[W3]b1, b2, b3 network[b1], network[b2], network[b3]a1 np.dot(x, W1) b1z1 sigmoid(a1)a2 np.dot(z1, W2) b2z2 sigmoid(a2)a3 np.dot(z2, W3) b3y identity_function(a3)return ynetwork init_network()
x np.array([1.0, 0.5])
y forward(network, x)
print(y) # [ 0.31682708 0.69627909]输出层的设计
神经网络可以用在分类问题和回归问题上不过需要根据情况改变输出层的激活函数。一般而言回归问题用恒等函数分类问题用softmax函数。
恒等函数和softmax函数
恒等函数会将输入按原样输出对于输入的信息不加以任何改动地直接输出。在输出层使用恒等函数时输入信号会原封不动地被输出。 分类问题中使用的softmax函数可以用下面的式3.10表示。 y k exp ( a k ) ∑ i 1 n exp ( a i ) ( 3.10 ) \begin{aligned}y_k\frac{\exp(a_k)}{\sum\limits_{i1}^n\exp(a_i)}(3.10)\end{aligned} yki1∑nexp(ai)exp(ak)(3.10) 假设输出层共有n个神经元计算第k个神经元的输出yk。softmax函数的分子是输入信号ak的指数函数分母是所有输入信号的指数函数的和。softmax函数的输出通过箭头与所有的输入信号相连。
实现softmax函数
import numpy as npdef softmax(a):exp_a np.exp(a)sum_exp_a np.sum(exp_a)y exp_a / sum_exp_areturn ya np.array([0.3, 2.9, 4.0])
y softmax(a)
print(y)实现softmax函数时要注意ex溢出的问题
改造softmax函数 y k exp ( a k ) ∑ i 1 n exp ( a i ) C exp ( a k ) C ∑ i 1 n exp ( a i ) exp ( a k log C ) ∑ i 1 n exp ( a i log C ) ( 3.11 ) exp ( a k C ′ ) ∑ i 1 n exp ( a i C ′ ) \begin{aligned} y_{k}{\frac{\exp(a_{k})}{\sum_{i1}^{n}\exp(a_{i})}} \frac{\mathrm{C}\exp(a_{k})}{\mathrm{C}\sum_{i1}^{n}\exp(a_{i})} \\ \frac{\exp(a_k\log\text{C})}{\sum\limits_{i1}^n\exp(a_i\log\text{C})} (\begin{matrix}3.11\\\end{matrix}) \\ \frac{\exp(a_k\mathrm{C})}{\sum\limits_{i1}^n\exp(a_i\mathrm{C})} \end{aligned} yk∑i1nexp(ai)exp(ak)C∑i1nexp(ai)Cexp(ak)i1∑nexp(ailogC)exp(aklogC)i1∑nexp(aiC′)exp(akC′)(3.11) 首先式3.11在分子和分母上都乘上C这个任意的常数因为同时对分母和分子乘以相同的常数所以计算结果不变。然后把这个C移动到指数函数exp中记为logC。最后把log C替换为另一个符号C’。
实现改造的softmax函数
import numpy as npdef softmax(a):c np.max(a)exp_a np.exp(a - c) # 溢出对策sum_exp_a np.sum(exp_a)y exp_a / sum_exp_areturn ya np.array([0.3, 2.9, 4.0])
y softmax(a)
print(y) # [0.01821127 0.24519181 0.73659691]softmax函数的输出是0.0到1.0之间的实数且输出值的总和是1所以我们把softmax函数的输出解释为“概率”。 一般神经网络只把输出值最大的神经元所对应的类别作为识别结果。并且即便使用softmax函数输出值最大的神经元的位置也不会变。在实际的问题中由于指数函数的运算需要一定的计算机运算量神经网络在进行分类时输出层的softmax函数一般都会省略。 输出层的神经元数量需要根据待解决的问题来决定。 对于分类问题输出层的神经元数量一般设定为类别的数量。 比如对于某个输入图像数字0到9中的哪一个的问题可以像图3-23这样将输出层的神经元设定为10个。
手写数字识别
MNIST数据集
这里使用的数据集是MNIST手写数字图像集。 MNIST是机器学习领域最有名的数据集之一被应用于从简单的实验到发表的论文研究等各种场合。实际上在阅读图像识别或机器学习的论文时 MNIST数据集经常作为实验用的数据出现。 训练图像有6万张测试图像有1万张。
神经网络的学习
数据驱动
机器学习的一切行为都来源于数据数据是机器学习的核心机器学习避免人为的介入 尝试从收集到的数据中发现答案模式。 如何识别数字5
人可以简单的识别出数字5但是说不出来是通过一种怎样的模式来识别出来的。考虑通过有效利用数据来解决这个问题一种方案是 先从图像中提取特征量 再用机器学习技术学习这些特征量的模式。这里所说的“特征量”是指可以从输入数据输入图像中准确地提取本质数据重要的数据的转换器。图像的特征量通常表示为向量的形式。在计算机视觉领域常用的特征量包括SIFT、SURF和HOG等。使用这些特征量将图像数据转换为向量然后对转换后的向量使用机器学习中的SVM、KNN等分类器进行学习。机器学习的方法中由机器从收集到的数据中找出规律性。与从零开始想出算法相比这种方法可以更高效地解决问题也能减轻人的负担。但是需要注意的是将图像转换为向量时使用的特征量仍是由人设计的。对于不同的问题必须使用合适的特征量必须设计专门的特征量才能得到好的结果。比如为了区分狗的脸部人们需要考虑与用于识别5的特征量不同的其他特征量。也就是说即使使用特征量和机器学习的方法也需要针对不同的问题人工考虑合适的特征量。 训练数据学习使用的数据用来寻找最优的参数 测试(监督)数据用来评价训练得到的模型的实际能力的数据 测试数据求的是模型的泛化能力也可以叫做监督数据
损失函数
损失函数“恶劣程度”的指标即当前的神经网络对监督数据在多大程度上不拟合。
均方误差 E 1 2 ∑ k ( y k − t k ) 2 ( 4.1 ) E\frac{1}{2}\sum_{k}(y_{k}-t_{k})^{2}\quad\quad\quad\quad\quad(4.1) E21∑k(yk−tk)2(4.1) yk是标识神经网络的输出tk标识监督数据k标识数据的维数。
交叉熵误差 E − ∑ k t k log y k ( 4.2 ) E-\sum_kt_k\log y_k\quad\quad\quad\quad\quad(4.2) E−∑ktklogyk(4.2) log表示以e为底数的自然对数loge。 yk是神经网络的输出tk是正确解标签。 并且tk中只有正确解标签的索引为1其他均为0one-hot表示。因此式4.2实际上只计算对应正确解标签的输出的自然对数。 交叉熵误差的值是由正确解标签所对应的输出结果决定的。
mini-batch学习
均方误差和交叉熵误差损失函数考虑的都是针对单个数据的损失函数。如果要求所有训练数据的损失函数的总和以交叉熵误差为例可以写成下面的式4_.3。 E − 1 N ∑ n ∑ k t n k log y n k ( 4.3 ) E-\frac{1}{N}\sum_{n}\sum_{k}t_{nk}\log ynk\quad\quad\quad\quad(4.3) E−N1∑n∑ktnklogynk(4.3) 假设数据有N个 tnk表示第n个数据的第k个元素的值ynk是神经网络的输出 tnk是监督数据。 把求单个数据的损失函数的式4.2扩大到了_N_份数据不过最后还要除以_N_进行正规化。通过除以_N可以求单个数据的“平均损失函数”。通过这样的平均化可以获得和训练数据的数量无关的统一指标。比如即便训练数据有1000个或10000个也可以求得单个数据的平均损失函数。 即便训练数据有1000个或10000个也可以求得单个数据的平均损失函数。
为何要设定损失函数
在神经网络的学习中寻找最优参数权重和偏置时要寻找使损失函数的值尽可能小的参数。为了找到使损失函数的值尽可能小的地方需要计算参数的导数确切地讲是梯度然后以这个导数为指引逐步更新参数的值。 假设有一个神经网络现在我们关注这个神经网络中的某一个权重参数。此时对该权重参数的损失函数求导表示的是“如果稍微改变这个权重参数的值损失函数的值会如何变化”。如果导数的值为负通过使该权重参数向正方向改变可以减小损失函数的值反过来如果导数的值为正则通过使该权重参数向负方向改变可以减小损失函数的值。不过当导数的值为0时无论权重参数向哪个方向变化损失函数的值都不会改变此时该权重参数的更新会停在此处。 **在进行神经网络的学习时不能将识别精度作为指标。因为如果以识别精度为指标则参数的导数在绝大多数地方都会变为0。 ** 识别精度对微小的参数变化基本上没有什么反应即便有反应它的值也是不连续地、突然地变化。 神经网络的学习无法使用阶跃函数作为激活函数因为阶跃函数的导数在绝大多数地方除了0以外的地方均为0。 而sigmoid函数不仅函数的输出竖轴的值是连续变化的曲线的斜率导数也是连续变化的。也就是说 sigmoid函数的导数在任何地方都不为0。这对神经网络的学习非常重要。得益于这个斜率不会为0的性质神经网络的学习得以正确进行。
梯度
梯度的计算 设 f ( x 0 x 1 ) x 0 2 x 1 2 \begin{aligned}f(x_0x_1)x_0^2x_1^2\end{aligned} f(x0x1)x02x12
def numerical_gradient(f, x):h 1e-4 # 0.0001grad np.zeros_like(x) # 生成和x形状相同的数组for idx in range(x.size):tmp_val x[idx]# f(xh)的计算x[idx] tmp_val hfxh1 f(x)# f(x-h)的计算x[idx] tmp_val - hfxh2 f(x)grad[idx] (fxh1 - fxh2) / (2*h)x[idx] tmp_val # 还原值return grad求点(3_, 4)、 (0, 2)、 (3, _0)处的梯度。 **numerical_gradient(function_2, np.array([3.0, 4.0])) **array([ 6., 8.]) **numerical_gradient(function_2, np.array([0.0, 2.0])) **array([ 0., 4.]) **numerical_gradient(function_2, np.array([3.0, 0.0])) **array([ 6., 0.]) 梯度指示的方向是各点处的函数值减小最多的方向 机器学习的主要任务是在学习时寻找最优参数。同样神经网络也必须在学习时找到最优参数权重和偏置。最优参数即损失函数取最小值时的参数。但是一般而言损失函数很复杂参数空间庞大我们不知道它在何处能取得最小值。而通过巧妙地使用梯度来寻找函数最小值或者尽可能小的值的方法就是梯度法。**梯度表示的是各点处的函数值减小最多的方向但无法保证梯度所指的方向就是函数的最小值。 ** 梯度法
在梯度法中函数的取值从当前位置沿着梯度方向前进一定距离然后在新的地方重新求梯度再沿着新梯度方向前进如此反复不断地沿梯度方向前进逐渐减小函数值的过程就是梯度法gradient method。梯度法是解决机器学习中最优化问题的常用方法特别是在神经网络的学习中经常被使用。 严格地讲寻找最小值的梯度法称为梯度下降法gradient descent method寻找最大值的梯度法称为梯度上升法gradient ascent method。但通过反转损失函数符号求最小值或最大值的问题会变成相同的问题。一般来说神经网络深度学习中梯度法主要是指梯度下降法。 用数学式来表示梯度法如式4_.7所示。 x 0 x 0 − η ∂ f ∂ x 0 x 1 x 1 − η ∂ f ∂ x 1 ( 4.7 ) \begin{aligned}x_0x_0-\eta\frac{\partial f}{\partial x_0}\\x_1x_1-\eta\frac{\partial f}{\partial x_1}\end{aligned}\quad\quad\quad\quad\quad(4.7) x0x1x0−η∂x0∂fx1−η∂x1∂f(4.7) η_表示更新量在神经网络的学习中称为学习率learningrate。学习率决定在一次学习中应该学习多少以及在多大程度上更新参数。 式4.7是表示更新一次的式子这个步骤会反复执行。也就是说每一步都按式4.7更新变量的值通过反复执行此步骤逐渐减小函数值。 学习率需要事先确定为某个值比如0.01或0.**001。一般而言这个值过大或过小都无法抵达一个“好的位置”。在神经网络的学习中一般会一边改变学习率的值一边确认学习是否正确进行了。 ** 用Python来实现梯度下降法
def gradient_descent(f, init_x, lr0.01, step_num100):x init_xfor i in range(step_num):grad numerical_gradient(f, x)x - lr * gradreturn x参数f是要进行最优化的函数init_x是初始值lr是学习率learningratestep_num是梯度法的重复次数。numerical_gradient(f,x)会求函数的梯度用该梯度乘以学习率得到的值进行更新操作由step_num指定重复的次数。
神经网络的梯度
有一个只有一个形状为2 × 3的权重W的神经网络损失函数用_L_表示。此时梯度可以用 表示。用数学式表示的话如下所示。 W ( w 11 w 12 w 13 w 21 w 22 w 23 ) ( 4.8 ) ∂ L ∂ W ( ∂ L ∂ w 11 ∂ L ∂ w 12 ∂ L ∂ w 13 ∂ L ∂ w 21 ∂ L ∂ w 22 ∂ L ∂ w 23 ) \begin{aligned} \boldsymbol{W} \left.\left(\begin{array}{ccc}w_{11}w_{12}w_{13}\\w_{21}w_{22}w_{23}\end{array}\right.\right) \\ \left.\left(\begin{matrix}4.8\end{matrix}\right.\right) \\ \begin{aligned}\frac{\partial L}{\partial\boldsymbol{W}}\end{aligned} \left.\left(\begin{array}{ccc}\frac{\partial L}{\partial w_{11}}\frac{\partial L}{\partial w_{12}}\frac{\partial L}{\partial w_{13}}\\\frac{\partial L}{\partial w_{21}}\frac{\partial L}{\partial w_{22}}\frac{\partial L}{\partial w_{23}}\end{array}\right.\right) \end{aligned} W∂W∂L(w11w21w12w22w13w23)(∂w11∂L∂w21∂L∂w12∂L∂w22∂L∂w13∂L∂w23∂L)(4.8) ∂ L ∂ W \frac{\partial L}{\partial W} ∂W∂L的元素由各个元素关于W的偏导数构成。比如第1行第1列的元素 ∂ L ∂ w 11 \frac{\partial L}{\partial w_{11}} ∂w11∂L表示当w11稍微变化时损失函数L会发生多大变化。重点是 ∂ L ∂ W \frac{\partial L}{\partial W} ∂W∂L的形状和W相同。
学习算法的实现
神经网络的学习步骤 前提 神经网络存在合适的权重和偏置调整权重和偏置以便拟合训练数据的过程称为“学习”。神经网络的学习分成下面4个步骤。 步骤1 mini-batch 从训练数据中随机选出一部分数据这部分数据称为mini-batch。我们的目标是减小mini-batch的损失函数的值。 步骤2计算梯度 为了减小mini-batch的损失函数的值需要求出各个权重参数的梯度。 梯度表示损失函数的值减小最多的方向。 步骤3更新参数 将权重参数沿梯度方向进行微小更新。 步骤4重复 重复步骤1、步骤2、步骤3。 因为使用的数据是随机选择的mini batch数据所以又称为随机梯度下降法stochastic gradient descent一般由一个名为SGD的函数来实现随机梯度下降法是“对随机选择的数据进行的梯度下降法”。
误差反向传播法
使用计算图来理解误差反向传播法
计算图
计算图的特征是可以通过传递“局部计算”获得最终结果。局部计算是指无论全局发生了什么都能只根据与自己相关的信息输出接下来的结果。 例如假设经过复杂的计算购买的其他很多东西总共花费4000日元各个节点处的计算都是局部计算如苹果和其他很多东西的求和运算4000 200 _→ _4200并不关心4000是如何计算而来的各个节点处只需进行与自己有关的计算本例中只把两个数字相加即可。
为什么用计算图
局部计算保存计算的中间结果通过反向传播高效计算导数 购买2个苹果每个100日元消费税10%最终支付220日元。假设我们想知道苹果价格的上涨会在多大程度上影响最终的支付金额即求**“支付金额关于苹果的价格的导数”**。设苹果的价格为_x_支付金额为_L_则相当于求 ∂ L ∂ x \frac{\partial L}{\partial x} ∂x∂L。这个导数的值表示当苹果的价格稍微上涨时支付金额会增加多少。 在图中反向传播使用反向箭头粗线表示。反向传播传递“局部导数”导数值在箭头的下方。 反向传播从右向左传递导数的值1 _→ 1._1 _→ 2.2可知“支付金额关于苹果的价格的导数”的值是2.2也就是苹果的价格上涨1日元支付金额增加2.2日元严格地讲如果苹果的价格增加某个微小值则最终的支付金额将增加那个微小值的2._2倍。同理“支付金额关于消费税的导数”、“支付金额关于苹果的个数的导数”都可以计算。并且计算中途求得的导数的结果中间传递的导数可以被共享从而可以高效地计算多个导数。 综上计算图的优点是可以通过正向传播和反向传播高效地计算各个变量的导数值。
链式法则
计算图的反向传播 反向传播的计算顺序是将信号_E_乘以节点的局部导数 ∂ y ∂ x \frac{\partial y}{\partial x} ∂x∂y然后将结果传递给下一个节点。这里所说的局部导数是指正向传播中y f(x)的导数也就是_y_关于_x_的导数 ∂ y ∂ x \frac{\partial y}{\partial x} ∂x∂y。比如假设y f(x) x2则局部导数为 ∂ y ∂ x \frac{\partial y}{\partial x} ∂x∂y 2_x_。把这个局部导数乘以上游传过来的值本例中为_E_然后传递给前面的节点。 如果某个函数由复合函数表示则该复合函数的导数可以用构成复合函数的各个函数的导数的乘积表示。 z t 2 t x y ( 5.1 ) \begin{aligned}zt^2\\txy\end{aligned}\quad\quad\quad\quad(5.1) ztt2xy(5.1) 链式求导为 ∂ z ∂ x ∂ z ∂ t ∂ t ∂ x ( 5.2 ) \begin{aligned}\frac{\partial z}{\partial x}\frac{\partial z}{\partial t}\frac{\partial t}{\partial x}\quad\quad\quad\quad(5.2)\end{aligned} ∂x∂z∂t∂z∂x∂t(5.2) 偏导数为 ∂ z ∂ t 2 t ∂ t ∂ x 1 ( 5.3 ) \begin{aligned}\frac{\partial z}{\partial t}2t\\\frac{\partial t}{\partial x}1\end{aligned}\quad\quad\quad\quad(5.3) ∂t∂z∂x∂t2t1(5.3) 则z关于x的偏导数即为 ∂ z ∂ x ∂ z ∂ t ∂ t ∂ x 2 t ⋅ 1 2 ( x y ) ( 5.4 ) \begin{aligned}\frac{\partial z}{\partial x}\frac{\partial z}{\partial t}\frac{\partial t}{\partial x}2t\cdot12(xy)\quad\quad\quad\quad(5.4)\end{aligned} ∂x∂z∂t∂z∂x∂t2t⋅12(xy)(5.4) 计算图为 计算图的反向传播从右到左传播信号。反向传播的计算顺序是先将节点的输入信号乘以节点的局部导数偏导数然后再传递给下一个节点。 反向传播时“**2”节点的输入是 ∂ z ∂ x \frac{\partial z}{\partial x} ∂x∂z将其乘以局部导数 ∂ z ∂ t \frac{\partial z}{\partial t} ∂t∂z因为正向传播时输入是_t_、输出是_z_所以这个节点的局部导数是 然后传递给下一个节点。另外上图中反向传播最开始的信号 ∂ z ∂ z \frac{\partial z}{\partial z} ∂z∂z在前面的数学式中没有出现这是因为 ∂ z ∂ z 1 \frac{\partial z}{\partial z} 1 ∂z∂z1所以在刚才的式子中被省略了。 上图中需要注意的是最左边的反向传播的结果。根据链式法则 ∂ z ∂ z ∂ z ∂ t ∂ t ∂ x ∂ z ∂ t ∂ t ∂ x ∂ z ∂ x \frac{\partial z}{\partial z}\frac{\partial z}{\partial t}\frac{\partial t}{\partial x} \frac{\partial z}{\partial t}\frac{\partial t}{\partial x} \frac{\partial z}{\partial x} ∂z∂z∂t∂z∂x∂t∂t∂z∂x∂t∂x∂z成立对应“z_关于_x_的导数”。也就是说反向传播是基于链式法则的。把式5._3的结果代入到上图中结果如下图 的结果为2(_x _ y)。 )
反向传播
加法节点的反向传播 z x y zxy zxy则 ∂ z ∂ x 1 ∂ z ∂ y 1 ( 5.5 ) \begin{aligned}\frac{\partial z}{\partial x}1\\\frac{\partial z}{\partial y}1\end{aligned}\quad\quad\quad\quad(5.5) ∂x∂z∂y∂z11(5.5) 计算图如下图表示 加法节点的反向传播只乘以1所以输入的值会原封不动地流向下一个节点。
乘法节点的反向传播 z x y z xy zxy则 ∂ z ∂ x y ∂ z ∂ y x ( 5.6 ) \begin{aligned}\frac{\partial z}{\partial x}y\\\frac{\partial z}{\partial y}x\end{aligned}\quad\quad\quad\quad(5.6) ∂x∂z∂y∂zyx(5.6) 计算图如下图表示 乘法的反向传播会将上游的值乘以正向传播时的输入信号的“翻转值”后传递给下游。翻转值表示一种翻转关系如图5-12所示正向传播时信号是_x_的话反向传播时则是_y_正向传播时信号是_y_的话反向传播时则是_x_。
回到买苹果 苹果的价格的导数是2_.2苹果的个数的导数是110消费税的导数是200。这可以解释为如果消费税和苹果的价格增加相同的值则消费税将对最终价格产生200倍大小的影响苹果的价格将产生2._2倍大小的影响。不过因为这个例子中消费税和苹果的价格的量纲不同所以才形成了这样的结果消费税的1是100%苹果的价格的1是1日元。
误差反向传播法的实现
前提 神经网络中有合适的权重和偏置调整权重和偏置以便拟合训练数据的 过程称为学习。神经网络的学习分为下面4个步骤。 步骤1 mini-batch 从训练数据中随机选择一部分数据。 步骤2计算梯度 计算损失函数关于各个权重参数的梯度。 步骤3更新参数 将权重参数沿梯度方向进行微小的更新。 步骤4重复 重复步骤1、步骤2、步骤3。
与学习相关的技巧
参数的更新
以下方法各有千秋SGD相对较慢其他三种使用较多最近很多人大多喜欢使用Adam
SGD与SGD的缺点 W ← W − η ∂ L ∂ W ( 6.1 ) \begin{aligned}\boldsymbol{W}\leftarrow\boldsymbol{W}-\boldsymbol{\eta}\frac{\partial L}{\partial\boldsymbol{W}}\quad\quad\quad\quad\quad(6.1)\end{aligned} W←W−η∂W∂L(6.1) SGD(stochastic gradient descent)随机梯度下降法比起胡乱地搜索参数空间也算是“聪明”的方法。 对于 f ( x , y ) 1 20 x 2 y 2 ( 6.2 ) \begin{aligned}f(x,y)\frac{1}{20}x^2y^2\quad\quad\quad\quad(6.2)\end{aligned} f(x,y)201x2y2(6.2) 的图形左图和它的等高线右图“) 的梯度”) 假设从(x, y) (_-7.0, 2._0)处初始值开始搜索结果如下图所示。SGD呈“之”字形移动所以如果函数的形状非均向anisotropic搜索的路径就会非常低效。因此我们需要比单纯朝梯度方向前进的SGD更聪明的方法。** SGD低效的根本原因是梯度的方向并没有指向最小值的方向。 ** 移动效率低)
Momentum v ← α v − η ∂ L ∂ W ( 6.3 ) W ← W v ( 6.4 ) \begin{aligned}v\leftarrow\alpha v-\eta\frac{\partial L}{\partial\boldsymbol{W}}\quad\quad\quad\quad(6.3)\\\\\boldsymbol{W}\leftarrow \boldsymbol{W}v\quad\quad\quad\quad\quad\quad(6.4)\end{aligned} vW←αv−η∂W∂L(6.3)←Wv(6.4) v对应物理上的速度。 下图中更新路径就像小球在碗中滚动一样。这是因为虽然_x_轴方向上受到的力非常小但是一直在同一方向上受力所以朝同一个方向会有一定的加速。反过来虽然_y_轴方向上受到的力很大但是因为交互地受到正方向和反方向的力它们会互相抵消所以_y_轴方向上的速度不稳定。因此和SGD时的情形相比可以更快地朝_x_轴方向靠近减弱“之”字形的变动程度。
AdaGrad
在关于学习率的有效技巧中有一种被称为学习率衰减learning ratedecay的方法即随着学习的进行使学习率逐渐减小。也就是一开始“多”学然后逐渐“少”学。 公式表示为 h ← h ∂ L ∂ W ⊙ ∂ L ∂ W ( 6.5 ) W ← W − η 1 h ∂ L ∂ W ( 6.6 ) \begin{aligned}\boldsymbol{h}\leftarrow\boldsymbol{h}\frac{\partial L}{\partial\boldsymbol{W}}\odot\frac{\partial L}{\partial\boldsymbol{W}}\quad\quad\quad\quad\quad\quad\quad(6.5)\\\\\boldsymbol{W}\leftarrow\boldsymbol{W}-\eta\frac{1}{\sqrt{\boldsymbol{h}}}\frac{\partial L}{\partial\boldsymbol{W}}\quad\quad\quad\quad\quad\quad\quad(6.6)\end{aligned} h←h∂W∂L⊙∂W∂L(6.5)W←W−ηh 1∂W∂L(6.6) 这里新出现了变量_h它保存了以前的所有梯度值的平方和式6._5中的 ⊙ \odot ⊙表示对应矩阵元素的乘法。然后在更新参数时通过乘以 1 h \frac{1}{\sqrt{\boldsymbol{h}}} h 1就可以调整学习的尺度。这意味着参数的元素中变动较大被大幅更新的元素的学习率将变小。也就是说可以按参数的元素进行学习率衰减使变动大的参数的学习率逐渐减小。 AdaGrad会记录过去所有梯度的平方和。因此学习越深入更新的幅度就越小。实际上如果无止境地学习更新量就会变为 0完全不再更新。为了改善这个问题可以使用 RMSProp方法。RMSProp方法并不是将过去所有的梯度一视同仁地相加而是逐渐地遗忘过去的梯度在做加法运算时将新梯度的信息更多地反映出来。这种操作从专业上讲称为“指数移动平均”呈指数函数式地减小过去的梯度的尺度。
Adam
融合了Momentum和AdaGrad的方法。通过组合前面两个方法的优点有望实现参数空间的高效搜索。基于Adam的更新过程就像小球在碗中滚动一样。虽然Momentun也有类似的移动但是相比之下 Adam的小球左右摇晃的程度有所减轻。这得益于学习的更新程度被适当地调整了。 Adam会设置3个超参数。一个是学习率论文中以_α_出现另外两个是一次momentum系数_β_1和二次momentum系数_β_2。根据论文标准的设定值是_β_1为0.9 _β_2 为0.999。设置了这些值后大多数情况下都能顺利运行。
权重的初始值
权值衰减weight decay是抑制过拟合、提高泛化能力的技巧。是一种以减小权重参数的值为目的进行学习的方法。通过减小权重参数的值来抑制过拟合的发生。 todo: 看不懂
Batch Normalization
如果设定了合适的权重初始值则各层的激活值分布会有适当的广度从而可以顺利地进行学习。那么为了使各层拥有适当的广度“强制性”地调整激活值的分布会怎样呢实际上 Batch Normalization方法就是基于这个想法而产生的。 优点 • 可以使学习快速进行可以增大学习率。 • 不那么依赖初始值对于初始值不用那么神经质。 • 抑制过拟合降低Dropout等的必要性。
正则化
过拟合指的是只能拟合训练数据但不能很好地拟合不包含在训练数据中的其他数据的状态。机器学习的目标是提高泛化能力即便是没有包含在训练数据里的未观测数据也希望模型可以进行正确的识别。我们可以制作复杂的、表现力强的模型但是相应地抑制过拟合的技巧也很重要。 发生过拟合的原因主要原因为1、模型拥有大量参数、表现力强2、训练数据少。 权值衰减是一直以来经常被使用的一种抑制过拟合的方法。该方法通过在学习的过程中对大的权重进行惩罚来抑制过拟合。很多过拟合原本就是因为权重参数取值过大才发生的。 当网络的模型变得很复杂时就是用Dropout方法Dropout方法在学习的过程中随机删除神经元训练时随机选出隐藏层的神经元然后将其删除被删除的神经元不再进行信号的传递。训练时每传递一次数据就会随机选择要删除的神经元。测试时虽然会传递所有的神经元信号但是对于各个神经元的输出要乘上训练时的删除比例后再输出。
超参数的验证
超参数是指比如各层的神经元数量、 batch大小、参数更新时的学习率或权值衰减等。如果这些超参数没有设置合适的值模型的性能就会很差。虽然超参数的取值非常重要但是在决定超参数的过程中一般会伴随很多的试错。下面介绍尽可能高效地寻找超参数的值的方法。 验证数据 调整超参数时必须使用超参数专用的确认数据。用于调整超参数的数据一般称为验证数据validation data。我们使用这个验证数据来评估超参数的好坏。 超参数的最优化 进行超参数的最优化时逐渐缩小超参数的“好值”的存在范围非常重要。所谓逐渐缩小范围是指一开始先大致设定一个范围从这个范围中随机选出一个超参数采样用这个采样到的值进行识别精度的评估然后多次重复该操作观察识别精度的结果根据这个结果缩小超参数的“好值”的范围。通过重复这一操作就可以逐渐确定超参数的合适范围。 超参数的范围只要“大致地指定”即可也就是指像0_._001到1000这样以“10的阶乘”的尺度指定范围。 超参数的最优化中要注意的是深度学习需要很长时间比如几天或几周。因此在超参数的搜索中需要尽早放弃那些不符合逻辑的超参数。于是在超参数的最优化中减少学习的epoch缩短一次评估所需的时间是一个不错的办法。 超参数的最优化的步骤 步骤0 设定超参数的范围。 步骤1 从设定的超参数范围中随机采样。 步骤2 使用步骤1中采样到的超参数的值进行学习通过验证数据评估识别精度但是要将epoch设置得很小。 步骤3 重复步骤1和步骤2100次等根据它们的识别精度的结果缩小超参数的范围
卷积神经网络
卷积神经网络Convolutional Neural Network CNN。CNN被用于图像识别、语音识别等各种场合在图像识别的比赛中基于深度学习的方法几乎都以CNN为基础。本章将详细介绍CNN的结构并用Python实现其处理内容。CNN中新出现了卷积层Convolution层和池化层Pooling层。 Affine层后面跟着激活函数ReLU层或者Sigmoid层。这里堆叠了4层“Affine-ReLU”组合然后第5层是Affine层最后由Softmax层输出最终结果概率。 CNN 中 新 增 了 Convolution 层 和 Pooling 层。 CNN 的层的连接顺序是“Convolution - ReLU -Pooling”Pooling层有时会被省略。这可以理解为之前的“Affi ne - ReLU”连接被替换成了“Convolution - ReLU -Pooling”连接。
卷积层
全连接的神经网络中使用了全连接层Affine层。在全连接层中相邻层的神经元全部连接在一起输出的数量可以任意决定。 全连接层的问题是数据的形状被“忽视”了。比如输入一个1通道、高28像素、长28像素的1_, 28, _28形状的图像时全连接层需要将3维数据拉平为1维数据。 图像是3维形状这个形状中应该含有重要的空间信息。比如空间上邻近的像素为相似的值、 RBG的各个通道之间分别有密切的关联性、相距较远的像素之间没有什么关联等 3维形状中可能隐藏有值得提取的本质模式。但是因为全连接层会忽视形状将全部的输入数据作为相同的神经元同一维度的神经元处理所以无法利用与形状相关的信息。 卷积层可以保持形状不变。当输入数据是图像时卷积层会以3维数据的形式接收输入数据并同样以3维数据的形式输出至下一层。因此在CNN中可以有可能正确理解图像等具有形状的数据。 另外 CNN 中有时将卷积层的输入输出数据称为特征图featuremap。其中卷积层的输入数据称为输入特征图input feature map输出数据称为输出特征图output feature map。
卷积运算 包含偏置的卷积运算的处理流程
填充
在进行卷积层的处理之前有时要向输入数据的周围填入固定的数据比如0等这称为填充padding。
步幅
应用滤波器的位置间隔称为步幅stride。之前的例子中步幅都是1如果将步幅设为2则如下图所示应用滤波器的窗口的间隔变为2个元素。
3维数据的卷积运算
通道方向上有多个特征图时会按通道进行输入数据和滤波器的卷积运算并将结果相加从而得到输出。多维卷积运算中输入数据和滤波器的通道数要设为相同的值。
结合方块思考 批处理 池化层
池化是缩小高、长方向上的空间的运算。 池化层的特征 没有要学习的参数 池化层和卷积层不同没有要学习的参数。池化只是从目标区域中取最大值或者平均值所以不存在要学习的参数。 通道数不发生变化 经过池化运算输入数据和输出数据的通道数不会发生变化。如图7-15所示计算是按通道独立进行的。 对微小的位置变化具有鲁棒性健壮 输入数据发生微小偏差时池化仍会返回相同的结果。因此池化对输入数据的微小偏差具有鲁棒性。比如 3 _× _3的池化的情况下如图7-16所示池化会吸收输入数据的偏差根据数据的不同结果有可能不一致。
im2colimage to column
im2col会把输入数据展开以适合滤波器权重。 为了便于观察将步幅设置得很大以使滤波器的应用区域不重叠。而在实际的卷积运算中滤波器的应用区域几乎都是重叠的。在滤波器的应用区域重叠的情况下使用im2col展开后展开后的元素个数会多于原方块的元素个数。因此使用im2col的实现存在比普通的实现消耗更多内存的缺点。但是汇总成一个大的矩阵进行计算对计算机的计算颇有益处。比如在矩阵计算的库线性代数库等中矩阵计算的实现已被高度最优化可以高速地进行大矩阵的乘法运算。因此通过归结到矩阵计算上可以有效地利用线性代数库。