• 深度学习基础--神经网络(3)神经网络的学习,损失函数初识



    本文为学习笔记整理
    参考书籍:《深度学习入门 : 基于Python的理论与实现 》/ (日) 斋藤康毅著 ; 陆宇杰译. – 北京 : 人民邮电出版社, 2018.7(2019.5重印)

    文章中带编号的图片(如:图4-2)均来自书籍内容。

    神经网络的学习

    学习:神经网络可以从输入的训练数据中自动获取最优权重参数的过程。

    损失函数:学习的指标,以损失函数为基准,找出能使它的值达到最小的权重参数。

    从数据中学习

    数据是机器学习的核心,机器学习的方法尝试从收集到的数据中发现答案(模式)。

    从图像中提取特征量,再用机器学习技术学习这些特征量的模式。

    图像的特征量通常表示为向量的形式。在计算机视觉领域,常用的特征量包括 SIFT、SURF和HOG(定向梯度直方图)等使用这些特征量将图像数据转换为向量,然后对 转换后的向量使用机器学习中的SVM、KNN等分类器进行学习

    图像的特征量的设计需要根据不同的任务来设计专门的特征量,才能得到更好的结果。

    请添加图片描述

    在神经网络中,也就是**深度学习中包含的重要特征量也都是由网络自己学习出来的**

    深度学习:端到端机器学习(end-to-end machine learning)。从原始数据中直接获得目标结果。

    神经网络对所有的问题都可以用同样的流程来解决,比如识别问题,无论是识别狗还是人脸还是其他,神经网络都是通过提供的数据,从中发现求解问题的模式。

    数据区分

    数据一般分为:

    • 训练数据(监督数据)
      • 使用训练数据寻找最优的参数
    • 测试数据
      • 使用测试数据评价训练得到的模型的实际能力

    设置训练数据和测试数据是为了正确评价模型的泛化能力,也就是指在处理新的数据时的能力,不能只适用于训练和测试的数据

    过拟合:只是对某个数据集过度拟合,就是说训练出来的模型只适用于某个数据集,无法在其他的数据上解决问题。要避免过拟合。

    损失函数

    损失函数就是一个对学习程度和效果的评价标准

    书中定义:

    损失函数:神经网络的学习中所用的指标称为损失函数,以这个指标为基准,寻找最优权重参数。损失函数可以使用任意函数,但一般用均方误差交叉熵误差等。

    均方误差

    E = 1 2 ∑ k ( y k − t k ) 2 (4.1) E = \frac{1}{2}\sum_k(y_k-t_k)^2 \tag{4.1} E=21k(yktk)2(4.1)

    y k y_k yk:神经网络的输出(实际的输出,如果使用softmax函数输出,就是实际的概率,而不是对应的结果)

    t k t_k tk:监督数据(就是训练数据中的标签)

    k k k:数据的维度(每个数据都需要参与运算)

    举例:

    手写数字识别中的一个输出y:

    在这里插入图片描述

    softmax的输出看作概率,那么推测这个输出对应的输入为“8”

    对应的监督数据(实际标签):

    假设推理正确,实际的结果就是“8”, t t t的形状就是:
    t = [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 ] t=[0, 0, 0, 0, 0, 0, 0, 0, 1, 0] t=[0,0,0,0,0,0,0,0,1,0]
    数组元素的索引从第一个开始依次对应数字0,1,2,…,9

    one-hot表示:正确解标签表示为1,其他标签表示为0

    那么对应的均方误差就是上面y和t对应元素相减再平方,然后求和,除以2,得出E。(也就是每一个元素的误差的平方和再除以2)

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

    交叉熵误差

    E = − ∑ k t k l o g y k (4.2) E = -\sum_k t_k logy_k \tag{4.2} E=ktklogyk(4.2)

    其中 l o g log log为以e为底,即 l n ln ln

    y k y_k yk:神经网络的输出

    t k t_k tk :正确解标签,同样是one-hot表示

    在这里插入图片描述

    因此,式(4.2)中,正确解标签对应的输出越大,E的值越接近0,误差越小。比如:

    还是手写数字

    正确标签:[0, 0, 1, 0, 0, 0, 0, 0, 0, 0],代表正确解为数字“2”

    神经网络输出:[0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0],代表输出的识别结果也是数字"2"

    因为0乘任何数都是0,所以最后的交叉熵误差计算就是: E = − 1 ∗ l o g 0.6 = 0.5108 E=-1*log0.6=0.5108 E=1log0.6=0.5108

    如果神经网络的输出错误,比如是:[0.1, 0.05, 0.1, 0.0, 0.05, 0.6, 0.0, 0.1, 0.0, 0.0]

    那么 E = − 1 ∗ l o g 0.1 = 2.3026 E = -1*log0.1=2.3026 E=1log0.1=2.3026,所以交叉熵误差是基于正确解的一种损失函数的计算方式。

    代码实现:

    def cross_entropy_error(y, t):
        delta = 1e-7  # 加一个微小值是为了防止np.log(0)的情况,这样会无限大
        return -np.sum(t * np.log(y + delta))
    
    • 1
    • 2
    • 3

    mini-batch学习

    机器学习使用训练数据进行学习,就是针对训练数据计算损失函数的值,找出使该值尽可能小的参数。

    如果训练数据有100个,就要把这100个损失函数的总和作为学习的指标

    那么,此时的交叉熵函数就是:
    E = − 1 N ∑ n ∑ k t n k l o g y n k (4.3) E = -\frac{1}{N}\sum_n\sum_kt_{nk}logy_{nk} \tag{4.3} E=N1nktnklogynk(4.3)
    N N N:数据个数

    t n k t_{nk} tnk:第n个数据的第k个元素的值

    式子(4.3)只是把求单个数据的损失函数的式子(4.2)扩大到N个数据然后除以N进行正规化(归一化)

    通过除以N,可以求单个数据的“平均损失函数”。可以获得和训练数据的数量无关的统一指标。

    但是,往往训练数据集的数据量很大,如果以全部数据为对象求损失函数的和,计算过程需要花费较长的时间。因此引出mini-batch学习

    mini-batch学习:从全部数据中选出一批数据(称为mini-batch),然后对每个mini-batch进行学习。

    mini-batch的损失函数也是利用一部分样本数据来近似地计算整体。也就是说,用随机选择的小批 量数据(mini-batch)作为全体训练数据的近似值。我理解有点类似抽样调查的意思。

    代码实现;

    def cross_entropy_error_one_shot(y, t):
        """
        交叉熵误差
        y: 神经网络的输出
        t: 训练数据的标签(监督数据), one-shot表示
        """
        if y.ndim == 1:  # y为一个NumPy矩阵,y.ndim为行数
            # y的维度为1时,即求单个数据的交叉熵误差
            t = t.reshape(1, t.size)
            y = y.reshape(1, y.size)
    
        batch_size = y.shape[0]
        # 此时传入的y为一个batch, y.shape[0]为行数,即结果的数量N
        delta = 1e-7  # 加一个微小值是为了防止np.log(0)的情况,这样会无限大
        return -np.sum(t * np.log(y + delta)) / batch_size
    
    
    def cross_entropy_error_not_one_shot(y, t):
        """
        交叉熵误差
        y: 神经网络的输出
        t: 训练数据的标签(监督数据), 非one-shot表示
        """
        if y.ndim == 1:
            t = t.reshape(1, t.size)
            y = y.reshape(1, y.size)
    
        batch_size = y.shape[0]
        delta = 1e-7
        return -np.sum(np.log(y[np.arange(batch_size), t] + delta)) / batch_size
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    对最后的return结果做一个梳理:

    np.arange(batch_size)  # 生成一个从0~(batch_size-1)的数组
    y[np.arange(batch_size), t]  
    """
    因为t非one-shot表示,所以t就是存储的真正的输出结果,比如[2, 4, 7,...]
    y的一行是一个softmax输出的下标0~9的数组,比如[0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
    因为交叉熵误差是直接按照正确解来计算
    那么这句代码会生成一个NumPY数组:[y[0, 2], y[1, 4], y[2, 7],...,y[batch_size - 1, t对应的结果]]
    y[0, 2]: 第一个结果中对应正确解"2"的概率值
    y[1, 4]: 第二个结果中对应正确解"4"的概率值
    """
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    发现个问题:公式(4.3)中有 t n k t_{nk} tnk l o g y n k logy_{nk} logynk的乘积,为什么在 t t t使用非one-shot表示时,返回值没有乘积操作呢?

    思考:

    如果 t t t为one-shot表示,那么 t t t为0的元素的交叉熵误差也为0,也就是说如果可以获得神经网络在正确解标签处的输出,就可以计算交叉熵误差,此时是输出的正确解标签是乘1,就可以理解为是取 y y y在正确解的位置的输出值,所以在 t t t为非one-shot表示时,也是要取对应的正确位置的输出值,所以就没有乘积操作了。

    损失函数更新的思路

    在寻找最优参数(权重和偏置时),为了找到使损失函数的值尽可能小的地方,需要计算参数的导数(也称“梯度”),然后以这个梯度为指引,逐步更新参数的值。

    如果导数的值为负数,函数沿梯度方向递减,使该权重参数向正方向(顺梯度方向)改变

    如果导数的值为正数,函数沿反梯度方向递减,使该权重参数向反方向改变

    当导数的值为0,此时该权重参数的更新会停在此处

    在进行神经网络的学习时,不能将识别精度作为指标。因为如果以 识别精度为指标,则参数的导数在绝大多数地方都会变为0。

  • 相关阅读:
    在linux服务器中使用rz上传文件乱码问题解决办法
    redis集群中节点fail,noaddr
    文件共享方法
    django 数据库 get_or_create函数update_or_create函数
    写个rpc调用,试试自己了解多少
    【微观经济学】Consumer Theory
    Hudi核心概念二:表和查询类型
    leetcode每天5题-Day41(二叉树7-二叉搜索树)
    【Java 8的新特性】
    OpenCV官方教程中文版 —— 直方图的计算,绘制与分析
  • 原文地址:https://blog.csdn.net/hanxiaochuan1/article/details/127961175