3.深度学习之损失函数(1)

1.损失函数简介

1.1损失函数作用

损失函数绝对是深度学习中最重要的一部分,要想训练出好的模型,就必须要有个好的损失函数。
首先,得明确损失函数是干嘛用的!
通俗地说,损失函数就是告诉网络模型预测值与真实值的差距,描述模型预测的好坏,好让网络模型朝着我们期望的好的方向进行学习。
举个简单的例子,就像猜数字游戏,我们随便写下一个数字,让计算机来预测我们写的值,这时我们就需要一个损失函数来告诉计算机预测值大了还是小了,然后计算机再通过损失函数的反馈来调整模型,最后接近我们的真实值。
例如以下实验:

import numpy as np
y = int(input('请输入一个整数(0-100):'))
#预测次数
i = 1
#预测值上限
upmax = 100
预测值下限
lowmin = 0

while True:
	#AI预测
    pred = np.random.randint(lowmin,upmax)
    print('我是AI,这是我第%s次预测这个数,这个数是:%s' % (i,pred))
    #损失函数
    loss = pred - y
    print('我是损失函数,损失值是:%s' % loss)
    
    if loss==0:
        print('恭喜预测正确!')
        break
    elif loss < 0:
        print('预测值小了,请重新预测!')
        lowmin = pred
    else:
        print('预测值大了,请重新预测!')
        upmax = pred
    i += 1
    print('---------')

损失函数很重要,不同的模型拥有不同的损失函数,接下来简单介绍几种损失函数。

1.2 损失函数的分类

因为深度学习模型需要解决的问题无非是分类问题和回归问题,对于解决不同问题的模型来说,所需要的损失函数自然不同。
因此我们可以将损失函数分为分类损失函数和回归损失函数


2.回归损失函数

2.1平均绝对误差(MAE)与L1_Loss

MAE公式:

M A E = ∑ 1 n ∣ y i − p r e d i ∣ n MAE =\frac{\sum_1^n\left|y_i-pred_i\right|}{n} MAE=n1nyipredi

L1_loss公式:

L 1 _ l o s s = ∑ 1 n ∣ y i − p r e d i ∣ L1\_loss =\sum_1^n\left|y_i-pred_i\right| L1_loss=1nyipredi
从公式可以看出,MAE就是L1_loss取平均值,他们没多大区别,效果是一样的,所以介绍L1_loss就可以了。

(1)L1_loss代码实现:
import numpy as np
import matplotlib.pyplot as plt

#定义L1_loss函数:
def L1_Loss_fuction(pred):
    losses = []
    for i in range(len(pred)):     
        losses.append(np.abs(y[i]-pred[i]))
    return np.sum(losses)

#定义预测方法1:
def pred_fuction1(x):
    a = x/2
    b = 2*x
    c = 500
    return a,b,c

#定义预测方法2:
def pred_fuction2(x):
    a = x/10
    b = a*9+99
    c = a+b
    return a,b,c

#输入值x是[-1000,1000]的整数
x = np.linspace(-1000,1000,2001,dtype=int)
#真实值y是一个包含3个元素的向量
y = [1,2,9]

#损失函数
L1_losses1 = []
L1_losses2 = []
for i in range(2):
    for j in x:
        pred = []
        #预测方法1的L1_loss
        if i == 0:
            pred1,pred2,pred3 = pred_fuction1(j)
            pred = [pred1,pred2,pred3]
            L1_losses1.append(L1_Loss_fuction(pred))
        #预测方法2的L1_loss
        else:
            pred1,pred2,pred3 = pred_fuction2(j)
            pred = [pred1,pred2,pred3]
            L1_losses2.append(L1_Loss_fuction(pred))
plt.plot(x, L1_losses1, linewidth=1,c='r',label='pred_fuction1')
plt.plot(x, L1_losses2, linewidth=1,c='g',label='pred_fuction2')
plt.legend(loc = 'best')
plt.show()

在这里插入图片描述

(2)L1_loss解析

1.从L1_loss的公式可以看出,它是无法求导的,所以计算机在计算时,无法精确找到那个最小值,只能将损失降到最小值附近区间。
2.从L1_loss的图像来看,在折点左右两边是具有稳定的梯度的,所以在损失值计算方面快捷方便且稳定。


2.2 均值平方差(MSE)与L2_Loss

MSE公式:

M S E = ∑ 1 n ( y i − p r e d i ) 2 n MSE =\frac{\sum_1^n(y_i-pred_i)^2}{n} MSE=n1n(yipredi)2

L2_loss公式:

L 2 _ l o s s = ∑ 1 n ( y i − p r e d i ) 2 L2\_loss =\sum_1^n(y_i-pred_i)^2 L2_loss=1n(yipredi)2
从公式可以看出,MSE就是L2_loss取平均值,他们没多大区别,效果是一样的,所以介绍L2_loss就可以了。

(1)L2_loss代码实现:
import numpy as np
import matplotlib.pyplot as plt

#定义L2_loss函数:
def L2_Loss_fuction(pred):
    losses = []
    for i in range(len(pred)):     
        losses.append((y[i]-pred[i])**2)
    return np.sum(losses)

#定义预测方法1:
def pred_fuction1(x):
    a = x/2
    b = 2*x
    c = 500
    return a,b,c

#定义预测方法2:
def pred_fuction2(x):
    a = x/10
    b = a*9+99
    c = a+b
    return a,b,c

#输入值x,真实值y
x = np.linspace(-1000,1000,2001,dtype=int)
y = [1,2,9]

#损失函数
L2_losses1 = []
L2_losses2 = []
for i in range(2):
    
    for j in x:
        pred = []
        #预测方法1的L1_loss
        if i == 0:
            pred1,pred2,pred3 = pred_fuction1(j)
            pred = [pred1,pred2,pred3]
            L2_losses1.append(L2_Loss_fuction(pred))
        #预测方法2的L1_loss
        else:
            pred1,pred2,pred3 = pred_fuction2(j)
            pred = [pred1,pred2,pred3]
            L2_losses2.append(L2_Loss_fuction(pred))
plt.plot(x, L2_losses1, linewidth=1,c='r',label='L2_loss_1')
plt.plot(x, L2_losses2, linewidth=1,c='g',label='L2_loss_2')
plt.legend(loc = 'best')
plt.show()

在这里插入图片描述

(2)L2_loss解析

1.从公式上来看,L2_loss可以求导,所以可以精确地找到它的最小值。
2.从L2_loss的图像来看,请观察其纵坐标的值,然后再去看L1_loss纵坐标的值。两者的数据是一样的,唯一不同就是损失函数,L2_loss损失函数会将误差扩大会导致梯度爆炸!

举个简单的例子:

假如真实值y = [1,1,1,1],
预测值 pred = [3,8,6,20]
L 1 _ l o s s = ∑ [ 2 , 7 , 5 , 19 ] L1\_loss = \sum[2,7,5,19] L1_loss=[2,7,5,19]
L 2 _ l o s s = ∑ [ 4 , 49 , 25 , 361 ] L2\_loss = \sum[4,49,25,361] L2_loss=[4,49,25,361]
看到了吧,对于L1_loss来说,19对整体的影响不是很大;但对于L2_loss来说, 1 9 2 19^2 192 对于整体的影响很大,如果要降低 1 9 2 19^2 192势必要求其他值变化大,这样就会造成梯度爆炸!


2.3 Huber损失函数

(1)总结下L1和L2损失;

1.L1无法找到精确的最小值,但L2可以。
2.L1梯度下降稳定,异常点影响小,但L2对异常点很敏感,出现异常点容易造成梯度爆炸。

3.既然L1和L2都各有优缺点,那是否有函数能将他们的有点结合,同时又能摒弃他们的缺点呢?当然,那就是我们的Huber函数!

(2)Huber函数公式:

H u b e r = ∑ 1 n { 1 2 ( y i − p r e d i ) 2 , ∣ y i − p r e d i ∣ ⩽ δ δ ∣ y i − p r e d i ∣ − 1 2 δ 2 , otherwise Huber = \sum_1^n\begin{cases} \frac{1}{2}(y_i-pred_i)^2, & \text{$\left|y_i-pred_i\right|\leqslant\delta$} \\ \delta\left|y_i-pred_i\right|-\frac{1}{2}\delta^2, & \text{otherwise} \end{cases} Huber=1n{21(yipredi)2,δyipredi21δ2,yiprediδotherwise
公式中的 δ \delta δ是需要自己调整的。

(3)代码实现:
import numpy as np
import matplotlib.pyplot as plt

#定义Huber函数:
def Huber_fuction(pred,delta=300):
    losses = []
    for i in range(len(pred)):
        a = y[i]-pred[i]
        a = np.abs(a)
        if a<delta:
            losses.append(0.5*(a**2))
        else:
            losses.append(delta*a-(delta**2)/2)
    return np.sum(losses)

#定义预测方法1:
def pred_fuction1(x):
    a = x/2
    b = 2*x
    c = 500
    return a,b,c

#定义预测方法2:
def pred_fuction2(x):
    a = x/10
    b = a*9+99
    c = a+b
    return a,b,c

#输入值x,真实值y
x = np.linspace(-1000,1000,2001,dtype=int)
y = [1,2,9]

#损失函数
Huber1 = []
Huber2 = []
for i in range(2):
    
    for j in x:
        pred = []
        #预测方法1的Huber损失
        if i == 0:
            pred1,pred2,pred3 = pred_fuction1(j)
            pred = [pred1,pred2,pred3]
            Huber1.append(Huber_fuction(pred))
        #预测方法2的Huber损失
        else:
            pred1,pred2,pred3 = pred_fuction2(j)
            pred = [pred1,pred2,pred3]
            Huber2.append(Huber_fuction(pred))
plt.plot(x, Huber1, linewidth=1,c='r',label='Huber1')
plt.plot(x, Huber2, linewidth=1,c='g',label='Huber2')
plt.legend(loc = 'best')
plt.show()

在这里插入图片描述
公式看起来很复杂,但看图就很直观了,其实就是将L1和L2损失函数各自截取一部分,从哪里截取则由我们通过调整 δ \delta δ来控制。
上图是 δ = 300 \delta=300 δ=300时的结果,下图则是 δ = 30 \delta=30 δ=30时的结果:

在这里插入图片描述

(4)Huber的优缺点

1.Huber拥有L1和L2的所有优点,并且没有他们的缺点,是个非常不错的选择。
2.但Huber使用效果的好坏由 δ \delta δ决定,需要人为调整,比较麻烦。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值