• 【TensorFlow1.X】系列学习笔记【入门四】


    【TensorFlow1.X】系列学习笔记【入门四】

    大量经典论文的算法均采用 TF 1.x 实现, 为了阅读方便, 同时加深对实现细节的理解, 需要 TF 1.x 的知识

    【TensorFlow1.X】系列学习文章目录



    前言

    实现神经网络的搭建,下一步需要学习神经网络优化原理和实现细节,本篇博文将详解损失函数作用。


    损失函数作用

    损失函数在深度学习中起着重要的作用,它用于衡量模型预测结果与实际标签之间的差异,指导模型的训练过程,是评估模型性能和优化模型参数的关键组成部分。损失函数具有以下几个主要作用:

    1. 衡量模型性能:损失函数用于衡量模型在给定数据上的性能。通过计算预测结果与真实标签之间的差异,可以评估模型的准确性和误差大小。
    2. 反映优化目标:损失函数定义了优化算法的目标,即最小化损失函数的值。通过最小化损失函数,模型可以尽量减少预测结果与真实标签之间的差异,并提高模型的性能。
    3. 指导参数更新:在优化过程中,损失函数的梯度被用于指导参数的更新方向和幅度。通过计算损失函数对于模型参数的梯度,可以确定参数更新的方向,使得损失函数的值逐渐减小。
    4. 支持模型选择和比较:不同的损失函数适用于不同的任务和问题。选择适合任务的损失函数可以帮助模型更好地学习和拟合数据。此外,通过比较不同模型在相同损失函数下的性能,可以选择最佳的模型架构和超参数。

    深度学习常见的损失函数包括:

    • 均方误差(Mean Squared Error,MSE):适用于回归问题,衡量预测值和真实值之间的平均平方差。
    • 交叉熵(Cross Entropy):适用于分类问题,衡量预测概率分布与真实概率分布之间的差异。

    选择合适的损失函数取决于任务类型、数据特征和模型要解决的问题。不同的损失函数对模型的训练和优化过程产生不同的影响,因此需要仔细选择和调整以达到最佳结果。


    均方误差(MSE)

    均方误差mse:n 个样本的预测值 y y y与真实值 y _ y\_ y_之差的平方和,再求平均值。
    M S E ( y _ , y ) = ∑ i = 1 n ( y − y _ ) 2 n MSE({\rm{y\_}},y) = \frac{{\sum\nolimits_{i =1 }^n {{{(y - y\_)}^2}} }}{n} MSE(y_,y)=ni=1n(yy_)2
    在 Tensorflow1.X中用 loss_mse = tf.reduce_mean(tf.square(y_ - y))
    举个小案例:两个神经网络模型解决二分类问题中,已知标准答案为 y _ = ( 1 , 0 ) {\rm{y\_ = (1, 0)}} y_=(1,0),第一个神经网络模型预测结果为 y 1 = ( 0.7 , 0.5 ) {\rm{y_1= (0.7, 0.5)}} y1=(0.7,0.5),第二个神经网络模型预测结果为 y 2 = ( 0.8 , 0.1 ) {\rm{y_2= (0.8, 0.1)}} y2=(0.8,0.1),判断哪个神经网络模型预测的结果更接近标准答案。
    根据均方误差的计算公式得:
    M S E _ 1 ( ( 1 , 0 ) , ( 0 . 7 , 0 . 5 ) ) = ( 0 . 7 − 1 ) 2 + ( 0 . 5 − 0 ) 2 = 0 . 34 {\rm{MSE\_1((1,0),(0}}{\rm{.7, 0}}{\rm{.5)) = (0}}{\rm{.7 - 1}}{{\rm{)}}^2} + {{\rm{(0}}{\rm{.5 - 0)}}^2} = {\rm{0}}{\rm{.34}} MSE_1((1,0),(0.7,0.5))=(0.71)2+(0.50)2=0.34
    M S E _ 2 ( ( 1 , 0 ) , ( 0 . 8 , 0 . 1 ) ) = ( 0 . 8 − 1 ) 2 + ( 0 . 1 − 0 ) 2 = 0 . 05 {\rm{MSE\_2((1,0),(0}}{\rm{.8, 0}}{\rm{.1)) = (0}}{\rm{.8 - 1}}{{\rm{)}}^2} + {{\rm{(0}}{\rm{.1 - 0)}}^2} ={\rm{0}}{\rm{.05}} MSE_2((1,0),(0.8,0.1))=(0.81)2+(0.10)2=0.05
    由于0.34>0.05,所以预测值 y 2 y_2 y2与真实值 y _ y\_ y_更接近, y 2 y_2 y2预测更准确。

    对于多分类问题,MSE并不是一个常用的评估指标

    在上一篇博文【TensorFlow1.X入门三】中的线性回归和非线性回归中都用到了此方法。


    交叉熵(Cross Entropy)

    交叉熵 Cross Entropy:n 个样本的预测值 y y y与真实值 y _ y\_ y_的概率分布之间的距离,交叉熵越大,两个概率分布距离越远,两个概率分布越相异;交叉熵越小,两个概率分布距离越近,两个概率分布越相似。
    H ( y _ , y ) = − ∑ i = 1 n y _ ∗ log ⁡ y H({\rm{y\_}},y) = - \sum\nolimits_{i = 1}^n {y\_} *\log y H(y_,y)=i=1ny_logy
    在 Tensorflow1.X中用loss_ce = -tf.reduce_mean(y_* tf.log(tf.clip_by_value(y, 1e-12, 1.0)))
    同一个小案例,根据交叉熵的计算公式得:
    H _ 1 ( ( 1 , 0 ) , ( 0.7 , 0.5 ) ) = − ( 1 ∗ l o g 0.7 + 0 ∗ l o g 0.3 ) ≈ 0.36 H\_1\left( {\left( {1,0} \right),\left( {0.7,0.5} \right)} \right){\rm{ }} = {\rm{ }} - \left( {1*log0.7{\rm{ }} + {\rm{ }}0*log0.3} \right) \approx {\rm{ }}0.36 H_1((1,0),(0.7,0.5))=(1log0.7+0log0.3)0.36
    H _ 2 ( ( 1 , 0 ) , ( 0.8 , 0.1 ) ) = − ( 1 ∗ l o g 0.8 + 0 ∗ l o g 0.1 ) ≈ 0.22 H\_2\left( {\left( {1,0} \right),\left( {0.8,0.1} \right)} \right){\rm{ }} = {\rm{ }} - \left( {1*log0.8{\rm{ }} + {\rm{ }}0*log0.1} \right) \approx {\rm{ }}0.22 H_2((1,0),(0.8,0.1))=(1log0.8+0log0.1)0.22
    由于0.36>0.22,所以预测值 y 2 y_2 y2与真实值 y _ y\_ y_更接近, y 2 y_2 y2预测更准确。

    这里 n n n分类的输出概率并没有什么联系,而且通常会将每个概率值都压缩在min和max之间:小于min的值等于min,大于max的值等于max。tf.clip_by_value(y, 1e-12, 1.0)即在0到1之间,这样的话上面的H_1的值就被压缩成是 H _ 1 ( ( 1 , 0 ) , ( 0.7 , 0.3 ) ) ≈ 0.36 H\_1\left( {\left( {1,0} \right),\left( {0.7,0.3} \right)} \right){\rm{ }}\approx {\rm{ }}0.36 H_1((1,0),(0.7,0.3))0.36,所以 H _ 1 H\_1 H_1公式博主并没有写错。

    在深度学习中,一般让模型的输出经过softmax函数,以获得输出分类的概率分布,再与真实值对比,求出交叉熵,得到损失函数。softmax函数要求 n n n分类的输出满足以下概率分布要求的函数: p ( X = x i ) ∈ [ 0 , 1 ] p(X = {x_i}) \in [0,1] p(X=xi)[0,1] ∑ i n p ( X = x i ) = 1 \sum\nolimits_i^n {p(X = {x_i}) = 1} inp(X=xi)=1,softmax函数具体表示为: p ( X = x i ) = s o f t m a x ( x i ) = e x i ∑ i = 1 n e x i p(X = {x_i}) = {\rm{softmax}}({x_i}) = \frac{{{e^{{x_i}}}}}{{\sum\nolimits_{i = 1}^n {{e^{{x_i}}}} }} p(X=xi)=softmax(xi)=i=1nexiexi
    在 Tensorflow1.X中结合softmax和Cross Entropy后用loss_ce = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_, 1)))
    同一个小案例,根据改良版本的交叉熵的计算公式得:
    H _ 1 ( ( 1 , 0 ) , s o f t m a x ( 0.7 , 0.5 ) ) ≈ H _ 1 ( ( 1 , 0 ) , ( 0.57 , 0.43 ) ) = 0.56 H\_1\left( {\left( {1,0} \right),softmax\left( {0.7,0.5} \right)} \right) \approx H\_1\left( {\left( {1,0} \right),\left( {0.57,0.43} \right)} \right){\rm{ }} = {\rm{ }}0.56 H_1((1,0),softmax(0.7,0.5))H_1((1,0),(0.57,0.43))=0.56
    H _ 2 ( ( 1 , 0 ) , s o f t m a x ( 0.8 , 0.1 ) ) ≈ H _ 1 ( ( 1 , 0 ) , ( 0.79 , 0.21 ) ) = 0.24 H\_2\left( {\left( {1,0} \right),softmax\left( {0.8,0.1} \right)} \right) \approx H\_1\left( {\left( {1,0} \right),\left( {0.79,0.21} \right)} \right){\rm{ }} = {\rm{ }}0.24 H_2((1,0),softmax(0.8,0.1))H_1((1,0),(0.79,0.21))=0.24
    由于0.56>0.24,所以预测值 y 2 y_2 y2与真实值 y _ y\_ y_更接近, y 2 y_2 y2预测更准确。
    在上一篇博文【TensorFlow1.X入门三】中的逻辑回归中都用到了此方法。


    自定义损失函数

    根据问题的实际情况,定制合理的损失函数。
    举个例子:对于预测酸奶日销量问题,如果预测销量大于实际销量则会损失成本;如果预测销量小于实际销量则会损失利润。在实际生活中,往往制造一盒酸奶的成本和销售一盒酸奶的利润是不等价的。因此,需要使用符合该问题的自定义损失函数: l o s s = ∑ i = 0 n f ( y _ , y ) loss = \sum\nolimits_{i = 0}^n {f(y\_,y)} loss=i=0nf(y_,y)
    自定义损失函数制作为分段函数: f ( y _ , y ) = { p r o f i t × ( y _ − y ) , y < y _ c o s t × ( y _ − y ) , y > = y _ f(y\_,y) = \left\{ {\begin{array}{cc} {profit \times (y\_ - y),y < y\_}\\ {cost \times (y\_ - y),y > = y\_} \end{array}} \right. f(y_,y)={profit×(y_y),y<y_cost×(y_y),y>=y_
    若预测结果 y 小于标准答案 y_,损失函数为利润乘以预测结果 y 与标准答案 y_之差;
    若预测结果 y 大于标准答案 y_,损失函数为成本乘以预测结果 y 与标准答案 y_之差。
    在 Tensorflow1.X中用loss = tf.reduce_sum(tf.where(tf.greater(y,y_),COST(y-y_),PROFIT(y_-y)))
    自定义损失函数的完整的代码:

    #coding:utf-8
    #酸奶成本1元, 酸奶利润9元
    #预测少了损失大,故不要预测少,故生成的模型会多预测一些
    #0导入模块,生成数据集
    import tensorflow as tf
    import numpy as np
    BATCH_SIZE = 8
    SEED = 23455
    COST = 8
    PROFIT = 2
    
    rdm = np.random.RandomState(SEED)
    X = rdm.rand(32,2)
    # 假设市场的真实利润Y=3*COST+2*PROFIT
    Y = [[3*x1+2*x2+(rdm.rand()/10.0-0.05)] for (x1, x2) in X]
    
    # 定义神经网络的输入、参数和输出,定义前向传播过程。
    x = tf.placeholder(tf.float32, shape=(None, 2))
    y_ = tf.placeholder(tf.float32, shape=(None, 1))
    # 希望训练好的网络权重接近w=(a,b)接近(3,2)
    w = tf.Variable(tf.random_normal([2, 1], stddev=1, seed=1))
    y = tf.matmul(x, w)
    
    #定义损失函数及反向传播方法。
    loss = tf.reduce_sum(tf.where(tf.greater(y, y_), (y - y_)*COST, (y_ - y)*PROFIT))
    train_step = tf.train.GradientDescentOptimizer(0.001).minimize(loss)
    
    #生成会话,训练STEPS轮。
    with tf.Session() as sess:
        init_op = tf.global_variables_initializer()
        sess.run(init_op)
        STEPS = 3000
        for i in range(STEPS):
            start = (i*BATCH_SIZE) % 32
            end = (i*BATCH_SIZE) % 32 + BATCH_SIZE
            sess.run(train_step, feed_dict={x: X[start:end], y_: Y[start:end]})
            if i % 1000 == 0:
                print ("After %d training steps, w1 is: " % (i))
                print (sess.run(w), "\n")
        print ("Final w1 is: \n", sess.run(w))
    
    • 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
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40


    采用均方损失函数的完整的代码:

    只需要修改loss部分

    #coding:utf-8
    #酸奶成本1元, 酸奶利润9元
    #预测少了损失大,故不要预测少,故生成的模型会多预测一些
    #0导入模块,生成数据集
    import tensorflow as tf
    import numpy as np
    BATCH_SIZE = 8
    SEED = 23455
    COST = 8
    PROFIT = 2
    
    rdm = np.random.RandomState(SEED)
    X = rdm.rand(32,2)
    # 假设市场的真实利润Y=3*COST+2*PROFIT
    Y = [[3*x1+2*x2+(rdm.rand()/10.0-0.05)] for (x1, x2) in X]
    
    # 定义神经网络的输入、参数和输出,定义前向传播过程。
    x = tf.placeholder(tf.float32, shape=(None, 2))
    y_ = tf.placeholder(tf.float32, shape=(None, 1))
    # 希望训练好的网络权重接近w=(a,b)接近(3,2)
    w = tf.Variable(tf.random_normal([2, 1], stddev=1, seed=1))
    y = tf.matmul(x, w)
    
    #定义损失函数及反向传播方法。
    loss = tf.reduce_mean(tf.square(y_ - y))
    train_step = tf.train.GradientDescentOptimizer(0.001).minimize(loss)
    
    #生成会话,训练STEPS轮。
    with tf.Session() as sess:
        init_op = tf.global_variables_initializer()
        sess.run(init_op)
        STEPS = 3000
        for i in range(STEPS):
            start = (i*BATCH_SIZE) % 32
            end = (i*BATCH_SIZE) % 32 + BATCH_SIZE
            sess.run(train_step, feed_dict={x: X[start:end], y_: Y[start:end]})
            if i % 1000 == 0:
                print ("After %d training steps, w1 is: " % (i))
                print (sess.run(w), "\n")
        print ("Final w1 is: \n", sess.run(w))
    
    • 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
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40


    由执行结果可知,无论怎么修改COST和PROFIT的值,采用自定义损失函数预测的权重(2.98,1.98)都比采用均方误差预测的权重(1.88,2.83)更接近真实值(3,2),更符合实际需求。

    总结

    损失函数在机器学习和深度学习中起着非常重要的作用。它是用来衡量模型预测结果与真实标签之间的差异或误差的函数。通过最小化损失函数,我们可以训练模型的参数以使其能够更好地拟合训练数据,并在新的未见数据上做出准确的预测。博文对深度学习常见的损失函数进行的讲解,并根据问题的实际情况,举例分析讲解了如何定制合理的损失函数。


  • 相关阅读:
    YOLOv7训练自己的数据集
    Kamiya丨Kamiya艾美捷大鼠微量白蛋白酶联免疫吸附试验说明书
    swift语言下SurfGen库做的爬虫是什么样的 ?
    详解Pinia和Vuex
    Spring的读取和存储对象
    使用dasviewer加载osgb模型,不显示纹理,黑乎乎的怎么解决?
    Unity3D 拖拽赋值组件与通过Find赋值组件的优点与缺点详解
    52.seata分布式事务
    学习PS的个人笔记:掌握基本技能和高级应用
    如何通过console线登录交换机
  • 原文地址:https://blog.csdn.net/yangyu0515/article/details/133964538