损失函数(loss function)

损失函数

神经网络的学习通过某个指标表示现在的状态,以这个指标为基准,寻找最优权重参数。神经网络以某个指标为线索寻找最优权重参数。神经网络的学习中所用的指标称为损失函数(loss function)。损失函数是表示神经网络性能的“恶劣程度”的指标,即当前的神经网络对监督数据在多大程度上不拟合。

均方误差

均方误差如下所示:
在这里插入图片描述
这里,yk是表示神经网络的输出,tk表示监督数据,k表示数据的维数。给定两组数据:

t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
y1 = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
y2 = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]

如上式所示,均方误差会计算神经网络的输出和正确解监督数据的各个元素之差的平方,再求总和。现在,我们用Python来实现这个均方误差,实现方式如下所示:

def mean_squared_error(y, t):
    return 0.5 * np.sum((y - t) ** 2)

完整程序实现如下:

import numpy as np

t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
y1 = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
y2 = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]


def mean_squared_error(y, t):
    return 0.5 * np.sum((y - t) ** 2)


print(np.argmax(y1))  # 2  argmax表示函数中会产生最大output的那个参数
print(mean_squared_error(np.array(y1), np.array(t)))  # 0.09750000000000003

print(np.argmax(y2))  # 7  argmax表示函数中会产生最大output的那个参数
print(mean_squared_error(np.array(y2), np.array(t)))  # 0.5975

第一个例子中,正确解是“2”,神经网络的输出的最大值是“2”;第二个例子中,正确解是“2”,神经网络的输出的最大值是“7”。如实验结果所示,我们发现第一个例子的损失函数的值更小,和监督数据之间的误差较小。也就是说,均方误差显示第一个例子的输出结果与监督数据更加吻合。

交叉熵误差

交叉熵误差如下式所示:
在这里插入图片描述
这里,log表示以e为底数的自然对数(log e)。yk是神经网络的输出,tk是正确解标签。并且,tk中只有正确解标签的索引为1,其他均为0(one-hot表示:将正确解标签表示为1,其他标签表示为0的表示方法称为one-hot表示)。因此,上式实际上只计算对应正确解标签的输出的自然对数。比如,假设正确解标签的索引是“2”,与之对应的神经网络的输出是0.6,则交叉熵误差是−log 0.6 = 0.51;若“2”对应的输出是0.1,则交叉熵误差为−log 0.1 = 2.30。也就是说,交叉熵误差的值是由正确解标签所对应的输出结果决定的。下面我们用我们用Python来实现这个均方误差:

def cross_entropy_error(y, t):
    delta = np.array([1e-7, 1e-7, 1e-7, 1e-7, 1e-7, 1e-7, 1e-7, 1e-7, 1e-7, 1e-7])
    return -np.sum(t * np.log(y + delta))

完整程序实现如下:

import numpy as np

t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
y1 = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
y2 = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]


def cross_entropy_error(y, t):
    delta = np.array([1e-7, 1e-7, 1e-7, 1e-7, 1e-7, 1e-7, 1e-7, 1e-7, 1e-7, 1e-7])
    return -np.sum(t * np.log(y + delta))


print(cross_entropy_error(y1, t))  # 0.510825457099338
print(cross_entropy_error(y2, t))  # 2.302584092994546

第一个例子中,正确解标签对应的输出为0.6,此时的交叉熵误差大约为0.51。第二个例子中,正确解标签对应的输出为0.1的低值,此时的交叉熵误差大约为2.3。由此可以看出,这些结果与我们前面讨论的内容是一致的。

mini-batch版交叉熵误差

这里,我们来实现一个可以同时处理单个数据和批量数据(数据作为batch集中输入)两种情况的函数。

def cross_entropy_error(y, t):
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)
    batch_size = y.shape[0]
    return -np.sum(t * np.log(y + 1e-7)) / batch_size

这里,y是神经网络的输出,t是监督数据。y的维度为1时,即求单个数据的交叉熵误差时,需要改变数据的形状。并且,当输入为mini-batch时,要用batch的个数进行正规化,计算单个数据的平均交叉熵误差。程序完整实现如下:

import numpy as np

t = np.array([0, 0, 1, 0, 0, 0, 0, 0, 0, 0])
y1 = np.array([0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0])
y2 = np.array([0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0])


def cross_entropy_error(y, t):
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)
    batch_size = y.shape[0]
    return -np.sum(t * np.log(y + 1e-7)) / batch_size


print(cross_entropy_error(y1, t))  # 0.510825457099338
print(cross_entropy_error(y2, t))  # 2.302584092994546

此外,当监督数据是标签形式(非one-hot表示,而是像“2”“7”这样的标签)时,交叉熵误差可通过如下代码实现:

def cross_entropy_error(y, t):
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)
    batch_size = y.shape[0]
    print(np.arange(batch_size))
    return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size

实现的要点是,由于one-hot表示中t为0的元素的交叉熵误差也为0,因此针对这些元素的计算可以忽略。换言之,如果可以获得神经网络在正确解标签处的输出,就可以计算交叉熵误差。因此,t为one-hot表示时通过t * np.log(y)计算的地方,在t为标签形式时,可用np.log( y[np.arange (batch_size), t] )实现相同的处理(为了便于观察,这里省略了微小值1e-7)。
作为参考,简单介绍一下np.log(y[np.arange(batch_size), t] )。np.arange (batch_size)会生成一个从0到batch_size-1的数组。比如当batch_size为4时,np.arange(batch_size)会生成一个NumPy 数组[0, 1, 2, 3]。因为t中标签是以[2, 2, 2, 2,]的形式存储的,所以y[np.arange(batch_size), t]能抽出各个数据的正确解标签对应的神经网络的输出(在这个例子中,y[np.arange(batch_size), t] 会生成 NumPy 数 组 [y[0,2], y[1,2], y[2,2], y[3,2]])。完整程序实现如下:

import numpy as np

t = np.array([2])
y1 = np.array([0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0])
y2 = np.array([0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0])
y3 = np.array([[0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0],
               [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0],
               [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0],
               [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]])
t2 = np.array([2, 2, 2, 2])


def cross_entropy_error(y, t):
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)
    batch_size = y.shape[0]
    return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size


print(cross_entropy_error(y1, t))  # 0.510825457099338
print(cross_entropy_error(y2, t))  # 2.302584092994546
print(cross_entropy_error(y3, t2))  # 1.406704775046942

猜你喜欢

转载自blog.csdn.net/weixin_43912621/article/details/127269590