机器学习 损失函数
2022-04-05 14:04 jym蒟蒻 阅读(270) 评论(0) 编辑 收藏 举报损失函数
- what is 损失函数
- 均方误差
- 交叉熵误差
- 计算mini-batch学习的损失函数
- why 损失函数
神经网络学习目标是找到各层合适的权重参数w和偏置b,使得最终的输出结果能够与实际结果更加接近。那神经网络的这些权重参数是如何得到的:靠损失函数这个指标来进行一步步训练优化得到。
通过使损失函数最小,来寻找最优权重参数。学习的目的就是以该损失函数为基准,找出能使它的值达到最小的权重参数。
yk是神经网络的输出, tk是监督数据, k是数据的维数。
用python实现均方误差函数:
def mean_squared_error(y, t):
return 0.5 * np.sum((y-t)**2)
下面是调用这个函数的例子:
以手写数字识别为例,数组下标对应的是0-9的数字,y1和y2是神经网络经过softmax函数的输出,y1、y2的元素值是该网络经过判断这张图片,得到的0-9数字的概率。t是监督数据,t[2]=1,表明这张图片是2 。看到均方误差输出结果,可以发现,y1的损失函数比y2小,这是因为y1[2]=0.6,而y2[2]=0.1,也就是说y1估计出来的更接近真实的判断。
# coding: utf-8
import sys, os
sys.path.append(os.pardir) # 为了导入父目录的文件而进行的设定
import numpy as np
from common.functions import mean_squared_error
if __name__ == '__main__':
y1 = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
t = [0, 0, 1, 0, 0, 0, 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]
r1 = mean_squared_error(np.array(y1), np.array(t))
print(r1)
r2 = mean_squared_error(np.array(y2), np.array(t))
print(r2)
输出:
0.09750000000000003
0.5975
yk是神经网络的输出, tk是正确解标签, k表示数据的维数。
如果标签为one-hot表示,即tk中只有正确解标签索引为1,其他均为0 。
那么式子只计算对应正确解标签的输出的自然对数。
如上面的例子,t[2]=1,正确解标签索引为2,对应的神经网络输出为y1[2]=0.6,则交叉熵误差为-log0.6。
由上图y=logx曲线可看出,对于对数函数y=logx,x=1时,y=0;
交叉熵误差是一个-log函数,也就意味着,交叉熵误差值越小,神经网络在对应正确解标签的输出越接近1,即神经网络的判断和正确解标签越接近。
用python实现交叉熵误差函数:
函数里面的参数y、t是Numpy数组,函数计算log时,加上了一个微小值,这是防止出现np.log(0)导致后续计算无法进行。
def cross_entropy_error(y, t):
delta = 1e-7
return -np.sum(t * np.log(y + delta))
调用这个函数的例子:和均方误差调用的例子类似。
import sys, os
sys.path.append(os.pardir) # 为了导入父目录的文件而进行的设定
import numpy as np
from common.functions import cross_entropy_error
if __name__ == '__main__':
y1 = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
t = [0, 0, 1, 0, 0, 0, 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]
r1 = cross_entropy_error(np.array(y1), np.array(t))
print(r1)
r2 = cross_entropy_error(np.array(y2), np.array(t))
print(r2)
输出:
0.510825457099338
2.302584092994546
上述仅对单个数据进行了损失函数的计算,实际工程中,要把所有训练数据的损失函数的总和作为学习的指标。以交叉熵误差为例:
数据有N个, tnk表示第n个数据的第k个元素的值( ynk是神经网络的输出, tnk是监督数据)。
这个式子,也就是把所有数据的损失函数值加起来再除以总的数据个数。通过除以N可以求单个数据的平均损失函数,与训练数据的数量无关。
由于数据集的数据量可能会很大,求全部数据的损失函数的和,将花费很长时间。可以从全部数据中抽出一小部分数据,作为全部数据的近似,称为mini-batch(小批量),然后对每个mini-batch学习。
下面介绍一下如何使用python进行mini-batch的损失函数计算。
首先,从训练数据中随机抽取数据得到mini-batch:
调用(x_train, t_train), (x_test, t_test) = load_mnist(one_hot_label=True, normalize=True)函数,读取出MINIST数据,输出x_train.shape、t_train.shape可以看到,训练数据有60000个。使用np.random.choice(train_size, batch_size)可以从0到train_size-1之间随机选择batch_size个数字。输出batch_mask可以得到一个索引数组。把索引对应的数据存到小批量数据集里,抽出来的数据就有了。也就是说在60000个数据里面随机选了十个数据,存到了x_batch、t_batch里面。
import sys, os
sys.path.append(os.pardir) # 为了导入父目录的文件而进行的设定
import numpy as np
from dataset.mnist import load_mnist
(x_train, t_train), (x_test, t_test) = load_mnist(one_hot_label=True, normalize=True)
if __name__ == '__main__':
print(x_train.shape)
print(t_train.shape)
train_size = x_train.shape[0]
batch_size = 10
batch_mask = np.random.choice(train_size, batch_size)
print(batch_mask)
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]
输出:
(60000, 784)
(60000, 10)
[44839 5657 46048 51825 44057 50445 1374 19821 38720 14117]
(10, 784)
(10, 10)
之后,编写mini-batch版本的交叉熵误差函数:
函数参数y是神经网络输出,它是个二维的,第一维是该数据在mini-batch数据集里面的索引,第二维是数据,t是监督数据。y[np.arange(batch_size), t] 能抽出各个数据正确解标签对应的神经网络的输出。
重点的是,只用求神经网络在正确解标签处的输出。举个例子y[0,2],这就取出来了mini-batch里面第一个数据在2处的输出。
def cross_entropy_error(y, t):
if y.ndim == 1:
t = t.reshape(1, t.size)
y = y.reshape(1, y.size)
# 监督数据是one-hot-vector的情况下,转换为正确解标签的索引
if t.size == y.size:
t = t.argmax(axis=1)
batch_size = y.shape[0]
return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size
寻找最优权重和偏置时,要使损失函数尽可能小。
为什么不能用识别精度来作为指标,使让精度尽可能高,来寻找最优参数?
我的理解是,精度是除法做出来的,对网络的权重和偏置调整后,可能除法的结果没什么变化,也有可能出现突然的变化。这样的话无法进行调优,因为结果是不连续的。