社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  机器学习算法

深度学习基础系列 | 损失函数

集智书童 • 1 年前 • 231 次点击  

本系列的目的是帮助大家可以在不使用任何深度学习框架的情况下,实现神经网络的反向传播算法。因此从本篇开始,我们将逐步实现手写算法的各个功能。首先学习最常使用的两个损失函数,SigmoidCrossEntropyLoss和SoftmaxCrossEntropyLoss,损失函数虽然是模型推理后才会使用到,但其作用是计算网络模型每次迭代的前向计算结果与真实值的差距,从而指导下一步的训练向正确的方向进行。因此小编放到最开始讲,这样才能更加清楚我们的模型到底在做什么以及期望得结果。

花一点时间,学一点东西

1. 介绍

SigmoidCrossEntropyLoss我们在上一篇逻辑回归中已经使用过。这里再看一下sigmoid的函数图像,模型输出的结果经过sigmoid函数后可以被压缩到(0-1)之间,但sigmoid在变量取非常大的正值或负值时会出现饱和现象。

关于sigmoid损失函数公式我们已经推导过了:

常用于二元分类的问题,输出结果表示分类为目标的概率P和不是该目标的概率(1-P)。

SoftmaxCrossEntropyLoss,也叫归一化指数函数,是经常在多分类问题中使用的损失函数,也是深度学习变种最多的函数之一。我们在度量学习中使用的arcfaceloss、AMSoftmax等函数都是基于此优化的。损失函数公式如下(仍然可由对数似然推导出来,这里就不再赘述):

Softmax损失函数在多分类问题中不但可以将输出结果转为非负值,并且使得预测结果的概率之和为1。

2. 溢出问题

2.1 关于sigmoid精度溢出问题

x的取值可能>=0,也可能<0。 在计算机中,np.exp(1000)会上溢,而np.exp(-1000)为0.0,不会溢出。

利用这一特性,可以对sigmoid进行改写。

分子分母同乘以。此时,当x<0时不会溢出。

2.2 关于softmax的溢出问题

同样的,我们只考虑x大于0的场景,怎样可以使得不会溢出呢?我们可以给函数分子分母同乘以,而这个n便是max(x)求得。

此时便转换为

3. SoftmaxCrossEntropy求导

网上大部分都是纯粹的数学公式去推到softmax的导数,我们这里将演示在实际使用中,将类别标签改为one-hot形式后SoftmaxCrossEntropy是如何求导的。

3.1 思路:
  • 确定预测的值Y是1x3维度,确定标签T是1x3维度。根据此描述对loss进行标量式推导,然后推广到更多情况;
  • softmax函数,由于分母是sum(所有元素),所以对每个元素求导时,都要加上其他元素上的导数。
3.2 求解
  • 标签的定义为:,比如是onehot,label=1,则

  • Loss的定义为:

  • 计算y1导数

4. 代码实现

  • SigmoidCrossEntropyLoss
class SigmoidCrossEntropy(Module):
    def __init__(self, params, weight_decay=1e-5):
        super().__init__()
        self.params = params
        self.weight_decay = weight_decay
        
    def sigmoid(self, x):
        p0 = x 0
        p1 = ~p0
        x = x.copy()
        x[p0] = np.exp(x[p0]) / (1 + np.exp(x[p0]))
        x[p1] = 1 / (1 + np.exp(-x[p1]))
        return x
 
    def forward(self, x, label_onehot):
        eps = 1e-6
        self.label_onehot = label_onehot
        self.predict = self.sigmoid(x)
        self.predict = np.clip(self.predict, a_max=1-eps, a_min=eps)  # 裁切
        self.batch_size = self.predict.shape[0]
        return -np.sum(label_onehot * np.log(self.predict) + (1 - label_onehot) * 
                        np.log(1 - self.predict)) / self.batch_size
    
    def backward(self):
        self.decay_backward()
        return (self.predict - self.label_onehot) / self.batch_size
  • SoftmaxCrossEntropyLoss
class SoftmaxCrossEntropy(Module):
    def __init__(self):
        super().__init__()
        
    def softmax(self, x):
        max_x = np.max(x, axis=1, keepdims=True)
        exp_x = np.exp(x - max_x)
        return exp_x / np.sum(exp_x, axis=1, keepdims=True)

    def forward(self, x, label_onehot):
        eps = 1e-6
        self.label_onehot = label_onehot
        self.predict = self.softmax(x)
        self.predict = np.clip(self.predict, a_max=1-eps, a_min=eps)  # 裁切
        self.batch_size = self.predict.shape[0]
        return -np.sum(label_onehot * np.log(self.predict)) / self.batch_size
    
    def backward(self):
        return (self.predict - self.label_onehot) / self.batch_siz

5. 推荐阅读

        深度学习之逻辑回归

        深度学习之正则化

        重新学习线性回归

        重新学习梯度下降法



声明:转载请说明出处

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/147778
 
231 次点击