I’m a very very quick learner. – Lou Bloom, Nightcrawler
本章主题是神经网络如何自主地从数据中学习,从而得到最优权重
和偏置
参数值。由此引入了损失函数
的概念,用来量化当前的权重参数的不合适度
,学习的目标就是找到让损失函数最小的那一组参数值,使用的方法是梯度法
。
深度学习的意义
由于实际的神经网络具有海量的层数和参数,参数可达成千上万乃至上亿个,凭人力根本无法进行计算,因此需要深度学习来确定参数。
对于机器学习来说,在识别手写数字的场景里,通常需要先从图像中提取特征量
(表现为向量的形式),然后通过机器学习技术来学习这些特征量的模式。特征量用来把图片转换为向量。
而对于深度学习而言,提取特征量
这一操作也是由机器学习完成的。
图:人工学习->机器学习->深度学习
过拟合 over fitting
指参数对某一个数据集过度拟合的情况,即对该数据集精确度很高,但对其它数据集则不然。
过拟合是深度学习中经常要面对的一个问题。
损失函数 loss function
神经网络以损失函数作为量化指标,来寻找最优权重参数,一般采用均方误差
和交叉熵误差
。
均方误差 mean squared error
图:均方误差算式
各参数说明如下:
- yk:神经网络输出
- tk:监督数据
- k:数据维度
1 | py复制代码# 均方误差 |
one-hot表示
将正确解标签表示为1
,其他标签表示为0
。如在数字识别的例子里,一条监督数据是[0,0,1,0,0,0,0,0,0,0]
,表示当前数字为2
。如果使用非one-hot
表示,则t直接就是2
。
交叉熵误差 cross entropy error
图:交叉熵误差的算式
解标签tk
采用one-hot
表示,只有正确解为1
,其它值为0
。因此上式可以简化为E=-logyk
。自然对数log是在(0,1]
区间单调递增的,递增范围是负无穷大~0
,因此yk
越接近1
,E
的值越小,也就表明越接近正确(最佳)结果。
1 | py复制代码# 交叉熵误差 |
作为保护性对策,增加一个极小值delta
防止出现log(0)
的边缘场景。
mini-batch 学习
为了在一次运算中使用更多数据验证参数的损失值,可以通过mini-batch
的思路,即每次对批量数据计算损失函数,先求和再平均,已进行正规化。
图:批量计算交叉熵误差
叫mini-batch
是因为相对于完整的数据集,只选取其中的一小部分(mini
)进行计算。防止计算量过大。可以理解为抽样调查
1 | py复制代码# 通过numpy进行抽样 |
这段逻辑用如果用Java也能实现,但肯定比不上python简洁
numpy中关于array的维度操作
1 | py复制代码# nparray_test.py 测试 |
数值微分
导数用来表示某个瞬间的变化量,即瞬时速度。
图:导数
- 前向差分:
f(x+h)
与f(x)
之间的差分,因为偏离所以有误差 - 中心差分:
f(x+h)
与f(x-h)
之间的差分,更接近真实值
1 | py复制代码# 中心差分 |
数值微分例子
对于下述二次函数,通过python代码计算其微分,以及在函数上x=5
处的斜率,并绘图。
1 | py复制代码import numpy as np |
偏导数
含有多个变量的函数的导数称为偏导数,在使用时应当声明是对其中哪一个变量求导。
上式的python实现为:
1 | py复制代码def function_2(x): |
对应图像是:
其中对x0
、x1
求导分别写作:
在求导时,将已知参数值带入,对未知参数进行中心差分求导,例如求x0=3、x1=4时关于x0的偏导数:
1 | py复制代码def function_tmp1(x0): |
梯度
导数代表某个时间的瞬时速度,对于多维向量每一维求导,则得到了它的梯度(gradient)。当我们声明梯度时,需要说明是在x0=?、x1=?、...xn=?
所有变量处的梯度。
对于函数f和多维参数x计算梯度的方法如下(含批处理):
谨记:x是一个多维向量(即张量)
1 | py复制代码import numpy as np |
梯度指向各点处函数值减小最快的方向。
梯度法
梯度法就是利用梯度的概念来寻找函数最小值的方法,通过不断沿着梯度方向前进,进而不断缩小损失函数值。
- 极小值:局部最小值
- 最小值:全局最小值
- 鞍点:从某个方向看是极小值,从另一方向看是极大值
寻找最小值的梯度法称为梯度下降法(gradient descent method),寻找最大值的梯度法称为梯度上升法(gradient ascent method)。一般来说神经网络中梯度法是指梯度下降法。
在某一点上根据梯度方向前进,这就是梯度法的大白话表述。前进的步长用η
表示,称为学习率(learning rate
)。学习率决定在一次学习(前进)中,应当学习多少,以及在多大程度上更新参数。像学习率这样影响深度学习的值,称为超参数
,以与权重等普通参数区分。
图:更新(学习)一次
学习率过大或者过小,都无法抵达一个“好的位置”,在神经网络中一般会一边改变学习率的值一半尝试学习,以便确认学习是否正常进行。
- 学习率过大:得到一个很大的发散的值
- 学习率过小:没学完就结束了
梯度下降法的python实现:
1 | py复制代码def gradient_descent(f, init_x, lr=0.01, step_num=100): |
神经网络的梯度
在使用神经网络时,需要得出最优的权重矩阵,利用梯度法可以对这个矩阵进行计算,权重W
神经网络和梯度表示如下:
由上例,定义一个simpleNet
的简单神经网络:
1 | py复制代码import sys, os |
有了上面的梯度算法,就可以设置步长和步数,经过迭代得到最小损失函数。
学习算法实现
调整权重和偏置以便拟合训练数据的过程称为学习,分为以下步骤:(由于第一步是随机抽样,因此该方法也称为随机梯度下降法 stochastic gradient descent)
- 抽样 mini-batch:从训练数据中随机选出一部分数据,用这部分数据进行学习
- 计算梯度:随机设定权重,计算各个权重参数梯度,梯度表示损失函数的值减小最多的方向
- 更新参数:由上一步得出的梯度计算新的权重参数
- 重复1~3步
类定义:双层神经网络 TwoLayerNet
首先定义双层网络的结构,它包含每一层的权重和偏置,并且提供计算输出的predict
函数,计算交叉熵损失的loss
函数,计算批量精确度的accuracy
函数,以及生成梯度矩阵的numerical_gradient
函数。
1 | py复制代码# coding: utf-8 |
实现深度学习
引入epoch
的概念,它是一个单位,表示训练集中全部数据均被使用过一次时的更新次数
。对于10000
条数据的训练集来说,如果每个mini-batch
学习100
条,则epoch=100
。
1 | py复制代码# coding: utf-8 |
在每个epoch
里,计算一次训练集和测试集的精度accuracy
,并且显示在图像上,两条曲线吻合,说明没有发生过拟合。
图:未发生过拟合
本文转载自: 掘金