tensorflow2.0——损失函数

在tensorflow2.0 中,使用模块model.compile时,使用loss选择损失函数。

均方误差损失函数 mean_squared_error

均方误差函数,又称mse,最基本的损失函数表示法,通常情况下mse函数会整体乘上二分之一,方便简化求导出的函数。
loss = ‘mean_squared_error’

优点:1、二次函数仅具有全局最小值。由于没有局部最小值,所以我们永远不会陷入它。因此,可以保证梯度下降将收敛到全局最小值(如果它完全收敛)。2、便于梯度下降,误差大时下降快,误差小时下降慢,有利于函数收敛。
缺点:通过平方误差来惩罚模型犯的大错误。把一个比较大的数平方会使它变得更大,因而对异常值的健壮性低,当数据集存在许多异常值时,不建议使用它。

手写代码

下面图看出MAE非常受离群点的影响,从而导致拟合效果不太好。

import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif']=['SimHei']
#⽤来正常显示中⽂标签
plt.rcParams['axes.unicode_minus']=False 
#⽤来正常显示负号 #有中⽂出现的情况,需要u'内容'
x = np.linspace(0,20,40)  #(40,)
m = x.shape[0]
y = x + [np.random.choice(4) for _ in range(40)]   #(40,)
y[-5:] -= 8   #异常点
X = np.vstack((np.ones((m,)),x))  #(2,40)
W = np.zeros((1,2))  #(1,2)   b,w
iter_num = 100 #迭代次数
L = [] #记录每次迭代前的损失值大小
w_list = [] #记录权重的改变
n = 0.001  #学习率
for i in range(iter_num):
    y_pre = W.dot(X)
    loss = 1/(2*m)*np.sum((y - y_pre)**2)
    L.append(loss)
    W = W + n * 1/m * (y - y_pre).dot(X.T)
    w_list.append(W)
y1 = W[0,0] + W[0,1]*0
y2 = W[0,0] + W[0,1]*20
l = len(L)
x1 = np.linspace(1,l,l)
w0 = [i[0][0] for i in w_list]
w1 = [i[0][1] for i in w_list]
plt.figure(figsize=(10,10))
plt.subplot(2,2,1)
plt.scatter(x, y)
plt.plot([0,20],[y1,y2],'r')
plt.title("MAE")
plt.subplot(2,2,2)
plt.title("损失值变化图")
x1 = np.linspace(1,l,l)
plt.plot(x1,L,'-r')
plt.xlabel('迭代次数')
plt.ylabel('损失值')
plt.subplot(2,2,3)
plt.title('偏置变化图')
plt.xlabel('迭代次数')
plt.ylabel('偏置')
plt.plot(list(x1),w0,'-r')
plt.subplot(2,2,4)
plt.title('权重变化图')
plt.xlabel('迭代次数')
plt.ylabel('权重')
plt.plot(list(x1),w1,'-b')
plt.show()

平均绝对误差 mean_absolute_error

平均绝对误差,又称mae,每个训练样本的绝对误差是预测值和实际值之间的距离,预测值与符号无关。
优点:相比较均方误差,对异常值健壮性更高。
缺点:收敛速度比均方误差慢,因为当误差大或小时其都保持同等速度下降,而且在某一点处还不可导,计算机求导比较困难。

手写代码

下图可以看出MAE函数拟合效果更好,且最后达到的损失值降为2以内。但是从权重和偏置的优化效果可以看出,不如上面的MSE函数,迭代效果出现震荡情况。

x = np.linspace(0,20,40)  #(40,)
m = x.shape[0]
y = x + [np.random.choice(4) for _ in range(40)]   #(40,)
y[-5:] -= 8   #异常点
X = np.vstack((np.ones((m,)),x))  #(2,40)
W = np.zeros((1,2))  #(1,2)   b,w
iter_num = 100 #迭代次数
L = [] #记录每次迭代前的损失值大小
w_list = [] #记录权重的改变
n = 0.01  #学习率
for i in range(iter_num):
    y_pre = W.dot(X)
    loss = 1/m*np.sum(np.abs(y-y_pre))
    L.append(loss)
    mask = (y-y_pre).copy()
    mask[y-y_pre > 0] = 1
    mask[mask <= 0] = -1
    W = W + n * 1/m * mask.dot(X.T)
    w_list.append(W)
y1 = W[0,0] + W[0,1]*0
y2 = W[0,0] + W[0,1]*20

Huber损失 huber_loss

Huber损失结合了MSE和MAE的最佳特性。对于较小的误差,它是二次的,否则是线性的(对于其梯度也是如此)。但是Huber损失需要确定超参数 δ 。

Huber Loss 是对二者的综合,包含了一个超参数 δ。δ 值的大小决定了 Huber Loss 对 MSE 和 MAE 的侧重性,当 |y−f(x)| ≤ δ 时,变为 MSE;当 |y−f(x)| > δ 时,则变成类似于 MAE。

x_ = np.linspace(-10,10,400)
y_ = x_.copy()
q = 1
y_ = np.where(np.abs(y_) <= q ,1/2*y_**2,y_)
y_ = np.where(np.abs(y_) > q,q*np.abs(y_)- 1/2*q**2,y_)
q = 0.1
y_1 = np.where(np.abs(y_) <= q ,1/2*y_**2,y_)
y_1 = np.where(np.abs(y_) > q,q*np.abs(y_)- 1/2*q**2,y_)
plt.plot(x_,y_,'-r',label = 'q = 1')
plt.plot(x_,y_1,'-b',label = 'q = 0.1')
plt.legend()
plt.show()

上图: Huber Loss 在 |y−f(x)| > δ 时,梯度一直近似为 δ,能够保证模型以一个较快的速度更新参数。当 |y−f(x)| ≤ δ 时,梯度逐渐减小,能够保证模型更精确地得到全局最优值。因此,Huber Loss 同时具备了前两种损失函数的优点。

手写代码

可以发现huber函数在一开始损失值函数下降的非常快,基本上迭代10次以内就下降到3以内,但之后的下降就会变得很慢。

x = np.linspace(0,20,40)  #(40,)
m = x.shape[0]
y = x + [np.random.choice(4) for _ in range(40)]   #(40,)
y[-5:] -= 8   #异常点
X = np.vstack((np.ones((m,)),x))  #(2,40)
W = np.zeros((1,2))  #(1,2)   b,w
iter_num = 500 #迭代次数
L = [] #记录每次迭代前的损失值大小
w_list = [] #记录权重的改变
n = 0.01  #学习率
delta = 1
for i in range(iter_num):
    y_pre = W.dot(X)
    y_ = y-y_pre
    y_ = np.where(np.abs(y_) <= delta ,1/2*y_**2,y_)
    y_ = np.where(np.abs(y_) > delta, delta*np.abs(y_)- 1/2* delta**2,y_)
    loss = 1/m*np.sum(y_)
    L.append(loss)
    mask = (y-y_pre).copy()
    mask = np.where(np.abs(y-y_pre) > delta,y-y_pre,mask)
    mask = np.where((-delta <y-y_pre) & (y-y_pre < 0) ,-delta,mask)
    mask = np.where((0 <y-y_pre) & (y-y_pre < delta ),delta,mask)
    W = W + n * 1/m * mask.dot(X.T)
    w_list.append(W)
y1 = W[0,0] + W[0,1]*0
y2 = W[0,0] + W[0,1]*20

softmax损失函数-交叉熵

activation=tf.nn.softmax
loss = ‘sparse_categorical_crossentropy’ #用于数字的标签
loss = ‘categorical_crossentropy’ #用于独热编码标签,如(1,0,0)、(0,1,0)、(0,0,1)
独热编码 = tf.keras.utils.to_categorical(‘数字标签’)
tf.keras.losses.sparse_categorical_crossentropy(y_true, y_pred, from_logits=False, axis=-1)

from_logits=False, 指出进行交叉熵计算时,输入的y_pred是否是logits(没有经过softmax激活函数的fully connect的输出),如果在fully connect层之后经过了激活函数softmax的处理,那这个参数就可以设置为False
Softmax 一般用于实现多分类,使用函数对输出层每一个结果进行运算,得到一个0~1的浮点值,且所有的值之和为1。
函数定义:

下面结果简单的神经网络进行解释上面的公式。

上图中,x1、x2 和 x3 是输入层,它们分别通过两个线性回归模型来产生 y1 和 y2:

然后通过Softmax函数得到y1’和y2’ :

最后将得到的y1 、y2、y1’、y2’ 通过交叉熵得到损失值。

上式中,q 表示有 q 个分类,y^{(j)} 为第 j 个分类的概率。
原因:用交叉熵(cross entropy)来衡量两个概率分布的差异,交叉熵越小,这两个分布越接近

tf.losses.binary_crossentropy

对数损失适,用于二分类的损失,必须给定参数预测值和真实值,并会返回一个矩阵,即每一个位置上的损失。

H p ( q ) = − 1 N ∑ i = 1 n [ y i I n ( p ( y i ) ) + ( 1 − y i ) I n ( 1 − p ( y i ) ) ] H_{p}(q) = - \frac{ 1 }{ N } \sum_{i=1}^n [y_{i}In(p(y_{i})) + (1-y_{i})In(1-p(y_{i}))] Hp(q)=N1i=1n[yiIn(p(yi))+(1yi)In(1p(yi))]

true = tf.Tensor([0. 0. 0. 0. 1. 0. 0. 0. 0. 0.], shape=(10,), dtype=float32)
pred = tf.Tensor([0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1], shape=(10,), dtype=float32)
tf.losses.binary_crossentropy(true, pred)  # tf.Tensor(0.32508284, shape=(), dtype=float32)
math.log(0.1) + 9*math.log(0.9))*0.1   # 0.32508284

待续

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值