一、理解
神经网络的一个重要性质是它可以自动地从数据中学习到合适的权重参数。
感知机和神经网络的主要区别就在于激活函数。
线性函数的问题在于,不管如何加深层数,总是存在与之等效的“无隐藏层的神经网络”。
NumPy数组的图像数据转换为PIL用的数据对象,这个转换处理由Image.fromarray()来完成。
Image.fromarray(np.uint8(img))
将正确解标签表示为1,其他标签表示为0的表示方法称为one-hot表示。
损失函数:
1、均方误差
2、交叉熵误差:将正确解标签表示为1,其他标签表示为0的表示方法称为one-hot表示。
梯度指示的方向是各点处的函数值减小最多的方向
3、梯度法:在梯度法中,函数的取值从当前位置沿着梯度方向前进一定距离,然后在新的地方重新求梯度,再沿着新梯度方向前进,如此反复,不断地沿梯度方向前进。像这样,通过不断地沿梯度方向前进,逐渐减小函数值的过程就是梯度法
4、学习率:学习率决定在一次学习中,应该学习多少,以及在多大程度上更新参数。
5、过拟合:过拟合是指,虽然训练数据中的数字图像能被正确辨别,但是不在训练数据中的数字图像却无法被识别的现象。
二、调参
一、调参小事:
1、SGD:SGD的缺点是,如果函数的形状非均向(anisotropic),比如呈延伸状,搜索的路径就会非常低效。因此,我们需要比单纯朝梯度方向前进的SGD更聪明的方法。SGD低效的根本原因是,梯度的方向并没有指向最小值的方向。
# SGD随机梯度下降
class SGD:
def __init__(self,lr = 0.01):
self.lr = lr
def update(self,params,grads):
for key in params.keys():
params[key] -= self.lr*grads[key]
2、momentum
# MOmentum
class Momentum:
def __init__(self,lr=0.01,momentum=0.9):
self.lr = lr
self.momentum = momentum
self.v = None
def update(self,params,grads):
if self.v is None:
self.v = {}
for key,val in params.items():
self.v[key] = np.zeros_like(val)
for key in params.keys():
self.v[key] = self.momentum*self.v[key] - self.lr*grads[key]
params[key] += self.v[key]
# AdaGrad
class AdaGrad:
def __init__(self,lr=0.01):
self.lr =lr
self.h = None
def update(self,params,grads):
if self.h is None:
self.h = {}
for key,val in params.items():
self.h[key] = np.zeros_like(val)
for key in params.keys():
self.h[key] += grads[key]*grads[key]
params[key] -= self.lr * grads[key]/(np.sqrt(self.h[key]) + 1e-7)
# Adam
4种参数更新方法
一般而言,与SGD相比,其他3种方法可以学习得更快,有时最终的识别精度也更高。
二、权重初始值(影响学习过程)
1、初始值一般随机生成,不全部设为0和相同的值
2、隐藏层的激活值的分布:偏向0和1的数据分布会造成反向传播中梯度的值不断变小,最后消失。这个问题称为梯度消失(gradient vanishing)。Xavier的论文中,为了使各层的激活值呈现出具有相同广度的分布,推导了合适的权重尺度。推导出的结论是,如果前一层的节点数为n,则初始值使用标准差为的分布
3、Relu的权重初始值:推荐使用ReLU专用的初始值,也就是Kaiming He等人推荐的初始值,也称为“He初始值”。当前一层的节点数为n时,He初始值使用标准差为的高斯分布。当Xavier初始值是时,(直观上)可以解释为,因为ReLU的负值区域的值为0,为了使它更有广度,所以需要2倍的系数。
4、总结一下,当激活函数使用ReLU时,权重初始值使用He初始值,当激活函数为sigmoid或tanh等S型曲线函数时,初始值使用Xavier初始值。这是目前的最佳实践。
三、Batch Normalization与正则化
1、优点:可以使学习快速进行(可以增大学习率)。不那么依赖初始值(对于初始值不用那么神经质)。抑制过拟合(降低Dropout等的必要性)。
2、过拟合:过拟合指的是只能拟合训练数据,但不能很好地拟合不包含在训练数据中的其他数据的状态。
发生过拟合的原因:模型拥有大量参数、表现力强;训练数据少。
3、权值衰减:是一直以来经常被使用的一种抑制过拟合的方法。该方法通过在学习的过程中对大的权重进行惩罚,来抑制过拟合。很多过拟合原本就是因为权重参数取值过大才发生的。为损失函数加上权重的L2范数的权值衰减方法。
4、Dropout:是一种在学习的过程中随机删除神经元的方法。训练时,随机选出隐藏层的神经元,然后将其删除。被删除的神经元不再进行信号的传递。通过使用Dropout,即便是表现力强的网络,也可以抑制过拟合。
class Dropout:
def __init__(self,dropout_ratio=0.5):
self.dropout_ratio = dropout_ratio
self.mask = None
def forward(self,x,train_flg=True):
if train_flg:
self.mask = np.random.rand(*x.shape) > self.dropout_ratio
return x*self.mask
else:
return x*(1.0 - self.dropout_ratio)
def backward(self,dout):
return dout*self.mask
四、超参数验证
**1、不能使用测试数据评估超参数的性能。**如果使用测试数据调整超参数,超参数的值会对测试数据发生过拟合。换句话说,用测试数据确认超参数的值的“好坏”,就会导致超参数的值被调整为只拟合测试数据。这样的话,可能就会得到不能拟合其他数据、泛化能力低的模型。
2、调整超参数时,必须使用超参数专用的确认数据。用于调整超参数的数据,一般称为验证数据
3、进行超参数的最优化时,逐渐缩小超参数的“好值”的存在范围非常重要。所谓逐渐缩小范围,是指一开始先大致设定一个范围,从这个范围中随机选出一个超参数(采样),用这个采样到的值进行识别精度的评估;然后,多次重复该操作,观察识别精度的结果,根据这个结果缩小超参数的“好值”的范围。通过重复这一操作,就可以逐渐确定超参数的合适范围。
4、方法:
1)从设定的超参数范围中随机采样。
2)使用步骤1中采样到的超参数的值进行学习,通过验证数据评估识别精度(但是要将epoch设置得很小)。
3)重复步骤1和步骤2(100次等),根据它们的识别精度的结果,缩小超参数的范围。
反复进行上述操作,不断缩小超参数的范围,在缩小到一定程度时,从该范围中选出一个超参数的值。这就是进行超参数的最优化的一种方法。