神经网络NN以某个指标为线索寻找最优参数,NN的学习中用的指标被称为损失函数,它是表示NN性能的指标,即NN对训练数据在多大程度上不拟合,不一致。
很多函数都可以作为损失函数loss function,但常用的是均方误差和交叉熵误差等。
E = 1 2 ∑ k ( y k − t k ) 2 E=\frac12\sum_{k}(y_k-t_k)^2 E=21k∑(yk−tk)2
y k y_k yk是NN的输出
t k t_k tk是one-hot标签,只有正确解的标签为1,其他均为0.
k k k是数据维数
所以,均方误差计算NN的输出和正确标签数据的各个元素的差值的平方,再求总和。
例如下图的python程序,识别0-9的数字,假设2是正确解,则t=[0,0,1,0,0,0,0,0,0,0]是one-hot标签,y是NN输出,则第一个y(2的概率最高,0.7)的均方误差更小:
只计算正确解标签的输出的自然对数。
E = − ∑ k t k log e y k E=-\sum_{k}t_k\log_e y_k E=−k∑tklogeyk
y k y_k yk是NN的输出
t k t_k tk是one-hot标签,只有正确解的标签为1,其他均为0.
k k k是数据维数
如,若正确解是2,而NN输出中2的概率是0.6,则交叉熵误差是 − 1 ∗ l n 0.6 = − 0.51 -1*ln0.6=-0.51 −1∗ln0.6=−0.51
所以,当NN输出的正确解的概率y为1时,交叉熵损失为0;随着正确解的概率y向0减小,交叉熵损失减小(向负值减小,实际上损失值是在增大)
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0,1,0.01)
delta = 1e-5
y = -np.log(x + delta) # 保护性对策,加个微小值,防止出现log(0)=-inf
plt.plot(x,y)
plt.xlabel('x')
plt.ylabel('y')
plt.title('cross entropy error')
plt.show()
实际的机器学习任务中,一般不会一次计算一个训练数据的输出的损失函数,因为这样很慢,如果数据集大,比如有100000个训练数据,则每计算一个输入数据的损失函数后更新参数的学习过程十分耗时。所以我们计算损失函数需要针对所有训练数据,即把由所有训练数据计算出的损失函数的总和作为学习指标。 但这样做仍然存在问题,因为这样做对于大数据集,计算过程也需要花很长的时间,对于有几百万,几千万数据量的数据集,求其损失函数总和去更新参数几乎是不现实的。所以我们采用mini-batch。
mini-batch学习:
从全部数据中选出一部分,作为全部数据的“近似”。这种小批量数据叫做mini-batch,比如,从100000个训练数据中随机选择一批,如100个,用这100个训练数据的损失函数的总和作为学习指标,不断随机选择mini-batch,重复学习过程以更新参数实现参数寻优。
抽取mini-batch以近似总体所有训练数据的行为,类似于抽样,比如调查电视收视率,男性平均身高,女性平均身高,不会调查所有电视机和所有人,只以被抽取的个体为处理对象。
但是要知道,这种多次随机抽取mini-batch不保证所有训练数据都被抽取到,毕竟是随机抽取嘛,很好理解。所以随机抽取的实现,在实际任务中经常是先把所有训练数据随机打乱,乱序后,从数据的开头到结尾依次按序取一个mini-batch,这样不仅保证了一个batch的随机性,还保证所有训练数据被用到学习任务中去。
E = − 1 N ∑ n ∑ k t n k log y n k E=-\frac1N\sum_{n}\sum_{k}t_{nk}\log y_{nk} E=−N1n∑k∑tnklogynk
可以看出,mini-batch学习中的交叉熵损失函数,是mini-batch中所有N个训练数据的正确标签对应输出的自然对数之和的负数。
如MNIST手写数据集,有60000张 28 × 28 28\times28 28×28的训练图片,把图像拉长为一维数组(flatten函数),即NN的输入X_train是一个 60000 × 784 60000\times784 60000×784的矩阵(python中是numpy数组),假设mini-batch的size是50,则
import numpy as np
# x_train, t_train分别是训练数据集和训练标签集
train_size = x_train.shape[0] # 取X_train的行数,60000
batch_size = 50
batch_mask = np.random.choice(train_size, batch_size) # 随机选择50个索引值
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]
# mini-bacth版交叉熵误差,可同时处理单个数据和批量数据(mini-bacth),针对one-hot标签
def cross_entropy_error(y, t):
# 如果输入数据是一维的,即单个数据,则需要确保把y,t变为行向量而非列向量
# 确保后面计算batch_size为1
if y.ndim == 1:
t = t.reshape(1, t.size) # t是one-hot标签
y = y.reshape(1, y.size)
batch_size = y.shape[0] # y的行数
return -np.sum(t * np.log(y + 1e-7)) / batch_size
# mini-bacth版交叉熵误差,可同时处理单个数据和批量数据(mini-bacth),针对非one-hot标签
def cross_entropy_error(y, t):
# 如果输入数据是一维的,即单个数据,则需要确保把y,t变为行向量而非列向量
# 确保后面计算batch_size为1
if y.ndim == 1:
t = t.reshape(1, t.size) # t是非one-hot标签,如手写数字识别中的0-9
y = y.reshape(1, y.size)
batch_size = y.shape[0] # y的行数
return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size