机器学习中的损失函数(均方误差,交叉熵误差)及其python实现

神经网络NN以某个指标为线索寻找最优参数,NN的学习中用的指标被称为损失函数,它是表示NN性能的指标,即NN对训练数据在多大程度上不拟合,不一致。
很多函数都可以作为损失函数loss function,但常用的是均方误差和交叉熵误差等。

一、均方误差Mean Squared Error

E = 1 2 ∑ k ( y k − t k ) 2 E=\frac12\sum_{k}(y_k-t_k)^2 E=21k(yktk)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)的均方误差更小:
机器学习中的损失函数(均方误差,交叉熵误差)及其python实现_第1张图片

二、交叉熵误差Cross Entropy Error

(1)单个训练数据的交叉熵误差

只计算正确解标签的输出的自然对数。
E = − ∑ k t k log ⁡ e y k E=-\sum_{k}t_k\log_e y_k E=ktklogeyk

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 1ln0.6=0.51
机器学习中的损失函数(均方误差,交叉熵误差)及其python实现_第2张图片
所以,当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()

机器学习中的损失函数(均方误差,交叉熵误差)及其python实现_第3张图片

(2)mini-batch学习,多个数据的交叉熵误差

实际的机器学习任务中,一般不会一次计算一个训练数据的输出的损失函数,因为这样很慢,如果数据集大,比如有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=N1nktnklogynk

  • N是mini-batch的size,即有多少个数据,如上例的100,除以N是为了正规化求出单个数据的“平均损失函数”,以获得和训练数据数量无关的统一指标
  • t n k t_{nk} tnk是第n个数据的第k维的标签,0或1
  • y n k y_{nk} ynk是第n个数据第k维的NN的输出

可以看出,mini-batch学习中的交叉熵损失函数,是mini-batch中所有N个训练数据的正确标签对应输出的自然对数之和的负数。

从训练数据中随机抽取一个mini-batch的python实现:

如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版交叉熵误差,可同时处理单个数据和批量数据(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

你可能感兴趣的:(机器学习)