深度学习被你忽略的细节系列篇——Softmax、LogSumExp和Sigmoid

news/2024/5/6 11:23:48/文章来源:https://blog.csdn.net/u014665013/article/details/129300622

平时我们基本用pytorch或者tensorflow框架时,基本对特别底层的函数实现关注不多,仅限于知道公式的原理。但是很多大佬往往自己会实现一些源码(比如ListNet复现),在看这些源码时,经常出现各种有点难以理解的代码,本来很简单的东西,莫名其妙的各种转换,化简完之后可能感觉是一样的,这么费劲周折的折腾啥?殊不知还是对底层的实现原理了解少了,虽然有些源码不需要我们从底层造轮子(完全从底层造轮子也影响效率),但是能理解其原理在我们debug以及看一些源码时不至于太多疑惑(毕竟国外很多大佬都喜欢实现一些底层utils)。

今天我们来重新认识一下我们经常用的Softmax、LogSumExp和Sigmoid

1. 背景概要

我们知道编程语言中的数值都有一个表示范围的,如果数值过大,超过最大的范围,就是上溢;如果过小,超过最小的范围,就是下溢。
今天要讨论的Softmax、LogSumExp和Sigmoid,就面临着上述溢出的问题,下面的一些梳理也主要用来解决计算Softmax或CrossEntropy时出现的上溢(overflow)或下溢(underflow)问题。
在这里插入图片描述

2. Softmax

在机器学习中,计算概率输出基本都需要经过Softmax函数,它的公式应该很熟悉了吧
Softmax(xi)=exp⁡(xi)∑j=1nexp⁡(xj)(1)\text{Softmax}(x_i) = \frac{\exp(x_i)}{\sum_{j=1}^n \exp(x_j)} \tag{1} Softmax(xi)=j=1nexp(xj)exp(xi)(1)
但是Softmax存在上溢和下溢大问题。如果xix_ixi太大,对应的指数函数也非常大,此时很容易就溢出,得到nan结果;如果xix_ixi太小,或者说负的太多,就会导致出现下溢而变成0,如果分母变成0,就会出现除0的结果。
此时我们经常看到一个常见的做法是(其实用到的是指数归一化技巧, exp-normalize),先计算x中的最大值b=max⁡i=1nxib = \max_{i=1}^n x_ib=maxi=1nxi,然后根据
Softmax(xi)=exp⁡(xi)∑j=1nexp⁡(xj)=exp⁡(xi−b)⋅exp⁡(b)∑j=1n(exp⁡(xj−b)⋅exp⁡(b))=exp⁡(xi−b)⋅exp⁡(b)exp⁡(b)⋅∑j=1nexp⁡(xj−b)=exp⁡(xi−b)∑j=1nexp⁡(xj−b)=Softmax(xi−b)\begin{aligned} \text{Softmax}(x_i) &= \frac{\exp(x_i)}{\sum_{j=1}^n \exp(x_j)} \\ &= \frac{\exp(x_i - b) \cdot \exp(b)}{\sum_{j=1}^n \left (\exp(x_j - b) \cdot \exp(b) \right)} \\ &= \frac{\exp(x_i - b) \cdot \exp(b)}{ \exp(b) \cdot \sum_{j=1}^n \exp(x_j - b) } \\ &= \frac{\exp(x_i - b)}{\sum_{j=1}^n \exp(x_j - b)} \\ &= \text{Softmax}(x_i - b) \end{aligned}Softmax(xi)=j=1nexp(xj)exp(xi)=j=1n(exp(xjb)exp(b))exp(xib)exp(b)=exp(b)j=1nexp(xjb)exp(xib)exp(b)=j=1nexp(xjb)exp(xib)=Softmax(xib)
这种转换是等价的,经过这一变换,就避免了上溢,最大值变成了exp⁡(0)=1\exp(0)=1exp(0)=1;同时分母中也会有一个1,就避免了下溢。
我们通过实例来理解一下。

def bad_softmax(x):y = np.exp(x)return y / y.sum()x = np.array([1, -10, 1000])
print(bad_softmax(x)) #运行结果
#... RuntimeWarning: overflow encountered in exp
#... RuntimeWarning: invalid value encountered in true_divide
#array([ 0.,  0., nan])

接下来进行上面的优化,并进行测试:

def softmax(x):b = x.max()y = np.exp(x - b)return y / y.sum()print(softmax(x))
# array([0., 0., 1.])
x = np.array([-800, -1000, -1000])
print(bad_softmax(x))
# array([nan, nan, nan])
print(softmax(x))
# array([1.00000000e+00, 3.72007598e-44, 3.72007598e-44])

关于softmax的另外实现,参加下文。

3. LogSumExp

什么是LSE?
LSE被定义为参数指数之和的对数:
LSE(x1,⋯,xn)=log⁡∑i=1nexp⁡(xi)=log⁡(exp⁡(x1)+⋯+exp⁡(xn))\text{LSE}(x_1,\cdots,x_n) = \log \sum_{i=1}^n \exp(x_i) =\log \left(\exp(x_1) + \cdots + \exp(x_n) \right)LSE(x1,,xn)=logi=1nexp(xi)=log(exp(x1)++exp(xn))
输入可以看成是一个n维的向量,输出是一个标量。

什么场景下要到LogSumExp呢?
交叉熵loss大家肯定不陌生,其中就有一项是logppp,比如多分类场景里面就需要在对softmax的结果做对数处理:
log⁡(Softmax(xi))=log⁡exp⁡(xi)∑j=1nexp⁡(xj)=xi−log⁡∑j=1nexp⁡(xj)\begin{aligned} \log \left( \text{Softmax}(x_i) \right) &= \log \frac{\exp(x_i)}{\sum_{j=1}^n \exp(x_j)} \\ &= x_i - \log \sum_{j=1}^n \exp(x_j) \\ \end{aligned}log(Softmax(xi))=logj=1nexp(xj)exp(xi)=xilogj=1nexp(xj)

能看出来不,后面这一项就是我们上面说的LSE。

理清前因后果之后,我们就来看LSE的实现问题。

因为上面最后一项也有上溢的问题,所以应用跟softmax同样的技巧,得
log⁡∑j=1nexp⁡(xj)=log⁡∑j=1nexp⁡(xj−b)exp⁡(b)=b+log⁡∑j=1nexp⁡(xj−b)(4)\log \sum_{j=1}^n \exp(x_j) = \log \sum_{j=1}^n \exp(x_j - b) \exp(b) = b + \log \sum_{j=1}^n \exp(x_j - b) \tag{4}logj=1nexp(xj)=logj=1nexp(xjb)exp(b)=b+logj=1nexp(xjb)(4)

bbb同样是取xxx中的最大值。

这样,我们就得到了LSE的最终表示:
LSE(x)=b+log⁡∑j=1nexp⁡(xj−b)(5)\text{LSE}(x) = b + \log \sum_{j=1}^n \exp(x_j - b) \tag{5}LSE(x)=b+logj=1nexp(xjb)(5)
对LogSumExp求导就得到了exp-normalize(Softmax)的形式,
∂(b+log⁡∑j=1nexp⁡(xj−b))∂xj=exp⁡(xi−b)∑j=1nexp⁡(xj−b)(6)\frac{\partial \left (b + \log \sum_{j=1}^n \exp(x_j - b) \right )}{\partial x_j} = \frac{\exp(x_i - b)}{\sum_{j=1}^n \exp(x_j - b)} \tag{6} xj(b+logj=1nexp(xjb))=j=1nexp(xjb)exp(xib)(6)

怎么实现LSE

def logsumexp(x):b = x.max()return b + np.log(np.sum(np.exp(x - b)))def softmax_lse(x):return np.exp(x - logsumexp(x))x1 = np.array([1, -10, 1000])
x2 = np.array([-900, -1000, -1000])
print(softmax_lse(x1))
# array([0., 0., 1.])
print(softmax(x1))
# array([0., 0., 1.])
print(softmax_lse(x2))
# array([1.00000000e+00, 3.72007598e-44, 3.72007598e-44])
print(softmax(x2))
# array([1.00000000e+00, 3.72007598e-44, 3.72007598e-44])

到此LSE的实现就清晰了,不过返回来再看Softmax,Softmax也可以这样表示:
Softmax(xi)=exp(log(Softmax(xi)))=exp(xi−log⁡∑j=1nexp⁡(xj))=exp⁡(xi−b−log⁡∑j=1nexp⁡(xj−b))(7)\begin{aligned}\text{Softmax}(x_i) &= \text{exp}(\text{log}(\text{Softmax}(x_i)))\\ &=\text{exp}(x_i-\log \sum_{j=1}^n \exp(x_j)) \\ &= \exp \left( x_i - b - \log \sum_{j=1}^n \exp(x_j - b) \right) \tag{7} \\ \end{aligned}Softmax(xi)=exp(log(Softmax(xi)))=exp(xilogj=1nexp(xj))=exp(xiblogj=1nexp(xjb))(7)

那我们是使用exp-normalize还是使用LogSumExp呢?

如果你需要保留Log空间,那么就计算log⁡(Softmax)\log(\text{Softmax})log(Softmax),此时使用LogSumExp技巧;如果你只需要计算Softmax,那么就使用exp-normalize技巧。

4. Sigmoid

我们知道Sigmoid函数是交叉熵之前常用的激活函数,公式为:
σ(x)=11+exp⁡(−x)(8)\sigma(x) = \frac{1}{1 + \exp(-x)} \tag{8} σ(x)=1+exp(x)1(8)

对应的图像如下:
在这里插入图片描述
其中包含一个exp⁡(−x)\exp(-x)exp(x),我们看一下exe^xex的图像:
在这里插入图片描述
从上图可以看出,如果x很大,exe^xex会非常大,而很小就没事,变成无限接近0。

当Sigmoid函数中的x负的特别多,那么exp⁡(−x)\exp(-x)exp(x)就会变成∞\infty​,就出现了上溢;

那么如何解决这个问题呢?σ(x)\sigma(x)σ(x)可以表示成两种形式:
σ(x)=11+exp⁡(−x)=exp⁡(x)1+exp⁡(x)(9)\sigma(x) = \frac{1}{1 + \exp(-x)} = \frac{\exp(x)}{1 + \exp(x)} \tag{9} σ(x)=1+exp(x)1=1+exp(x)exp(x)(9)

x≥0x \geq 0x0时,我们根据exe^{x}ex的图像,我们取11+exp⁡(−x)\frac{1}{1 + \exp(-x)}1+exp(x)1的形式;

当 x < 0 时,我们取exp⁡(x)1+exp⁡(x)\frac{\exp(x)}{1 + \exp(x)}1+exp(x)exp(x)

# 原来的做法
def sigmoid_naive(x):return 1 / (1 + math.exp(-x))# 优化后的做法
def sigmoid(x):if x < 0:return math.exp(x) / (1 + math.exp(x))else:return 1 / (1 + math.exp(-x))print(sigmoid_naive(2000))
# 1.0
print(sigmoid(2000))
# 1.0
print(sigmoid_naive(-2000))
# OverflowError: math range error
print(sigmoid(-2000))
# 0.0

参考链接:

  • The Log-Sum-Exp Trick
  • 一文弄懂交叉熵损失
  • Exp-normalize trick
  • 一文弄懂LogSumExp技巧

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_76446.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

教你如何搭建设备-巡检管理系统,demo可分享

1、简介1.1、案例简介本文将介绍&#xff0c;如何搭建设备-巡检管理。1.2、应用场景设备管理员进行制定设备巡检时间/内容计划、记录设备巡检信息、可以查看今日待巡检设备。2、设置方法2.1、表单搭建1&#xff09;新建表单【设备档案-履历表】&#xff0c;字段设置如下&#x…

安卓手机当旁路网关

一、安卓shell调试工具下载【电脑版下载地址】安卓adb调试工具&#xff0c;包含MAC苹果、Windows和Linux 三种版【手机版下载地址Termux】下载地址&#xff1a;https://github.com/termux/termux-app/releases如果不懂下载哪个版本&#xff0c;可以直接下载通用版&#xff1a;t…

【unity3d】rts engine 5 设置集结点;放置建筑

一 接上回新建建筑&#xff0c;设置生产单位&#xff0c;现在设置集结点 1 进入建筑预制体&#xff0c;add component 添加 rallypoint setting target 页面&#xff0c;设置面板按钮&#xff0c;音频 resource dead是可设置在耗尽的资源上&#xff0c;下一个是自动寻找附近同…

QT打包的两种方式

QT打包的两种方式&#xff1a; 一个是QT5自带的windeployqt&#xff08;不需要下载安装&#xff09;&#xff0c;它可以找到程序&#xff08;exe&#xff09;用到的所有库文件&#xff0c;并且都拷贝到exe程序的当前文件。此时打包的exe较小&#xff0c;需要和拷贝进来的文件放…

Modbus网关在锂电池干燥箱的应用

在锂离子电池生产过程中&#xff0c;将正负极片辊压绕卷再放入电池盒之后&#xff0c;须对锂电池电芯极组进行烘烤干燥。相信大家也了解水分对锂电池的性能影响是很大的&#xff0c;需要注液前在装配车间将锂离子电池电芯内部的水分去除&#xff0c;以免影响锂电池质量。在锂电…

在 The Sandbox 中以全新的 Rabbids 体验庆祝兔年!

育碧(Ubisoft) 和 The Sandbox 联手为你们带来终极的农历新年体验&#xff01; 穿戴上你们新鲜出炉的 Rabbids 人物化身来参加派对吧&#xff0c;保证震撼整个元宇宙&#xff01;这个全新体验为 Rabbids 人物化身持有者专属。没有获得 Rabbids 人物化身吗&#xff1f;不要担心&…

你知道Java中的JCP, JEP, JLS, JSR是什么意思吗?

目录 一、JCP 二、JSR 三、JLS 四、JEP 公众号&#xff1a;MCNU云原生&#xff0c;欢迎微信搜索关注&#xff0c;更多干货&#xff0c;及时掌握。 JCP, JEP, JLS, JSR这些概念是Java社区中的一些概念&#xff0c;但是没有没有经常关注社区的童鞋们未必知道这些缩写所代表的…

围棋

围棋 规则 棋盘 围棋使用矩形格状棋盘及黑白二色圆形棋子进行对弈&#xff0c;正规棋盘上有纵横各19条线段&#xff0c;361个交叉点。 基本下法 1&#xff0e;对局双方各执一色棋子&#xff0c;黑先白后&#xff0c;交替下子&#xff0c;每次只能下一子。 2&#xff0e;棋子…

Go 实现 AOI 区域视野管理

在游戏中,场景里存在大量的物体.如果我们把所有物体的变化都广播给玩家.那客户端很难承受这么大的压力.因此我们肯定会做优化.把不必要的信息过滤掉.如只关心玩家视野所看到的.减轻客户端的压力,给玩家更流畅的体验. 优化的思路一般是: 第一个是尽量降低向客户端同步对象的数量…

为什么FPGA在深度学习领域有着得天独厚的优势?

01 FPGA在深度学习领域有哪些优势 FPGA&#xff08;Field-Programmable Gate Array&#xff09;是一种灵活的可编程硬件设备&#xff0c;它在深度学习应用领域中具有许多优势。 首先&#xff0c;FPGA具有非常高的并行性。在深度学习中&#xff0c;许多计算都可以并行化&…

“数字档案室测评”相关参考依据梳理

数字档案室建设无疑比数字档案馆建设应用范围更为广泛&#xff0c;涉及的单位类型和专业领域也更多。这一点从国家档案局的机构设置上也可以看出端倪&#xff1a; 国家档案局两个内设业务指导司中&#xff0c;档案馆(室)业务指导司主要针对档案馆和机关档案室&#xff0c;而经济…

施工机械设备群远程在线监控管理系统

一、项目背景 在加强基础设施建设等一系列政策的牵引下&#xff0c;我国工程机械设备市场连续保持强劲增长势头&#xff0c;伴随国内中高端机械设备公司业务的不断扩展&#xff0c;施工大型机械设备的应用率不断提高&#xff0c;铁路施工特别是架桥机作业过程被认为是一个极易出…

Windows搭建机器学习环境

一、环境介绍Anaconda&#xff1a;Anaconda offers the easiest way to perform Python/R data science and machine learning on a single machine. Start working with thousands of open-source packages and libraries today.Anaconda包括Conda、Python以及一大堆安装好的工…

边缘计算开源项目解读——kubeedge mappers实现

0 背景 本文重点解读kubeedge项目中的mapper模块。该模块位于kubeedge的edgecore的南向边缘侧&#xff0c;主要对接入kubeedge的终端设备&#xff0c;进行协议的适配和转换&#xff0c;使其可以和边缘设备通信&#xff0c;转换后的协议是我们前面描述的mqtt协议&#xff0c;当然…

快速上手配置firewalld

firewalld使用firewall-cmd命令配置策略。 查看当前firewalld当前服务运行状态 firewall-cmd --state firewalld防火墙状态还用使用如下命令查看状态 systemctl status firewalld 查看所有打开运行的端口 firewall-cmd --zonepublic --list-ports 查看区域信息情况 firewall…

04 Android基础--RelativeLayout

04 Android基础--RelativeLayout什么是RelativeLayout&#xff1f;RelativeLayout的常见用法&#xff1a;什么是RelativeLayout&#xff1f; 相对布局&#xff08;RelativeLayout&#xff09;是一种根据父容器和兄弟控件作为参照来确定控件位置的布局方式。 根据父容器定位 在相…

maven高级知识。

目录 一、分模块开发 1、分模块开发设计 2、依赖管理 二、继承和聚合 1、聚合 2、继承 三、属性 1、基本介绍 2、版本管理 四、多环境配置与应用 1、多环境开发 2、跳过测试 五、私服 1、私服安装 2、私服仓库分类 一、分模块开发 1、分模块开发设计 ▶ 示意图 …

南卡Neo骨传导运动耳机发布,重塑骨传导耳机舒适听感新体验!

近日&#xff0c;在骨传导耳机领域中最专业的南卡发布了今年全新系列——NEO&#xff0c;如果说南卡Runner Pro4的音质是偏向于节奏性&#xff0c;那么这款南卡NEO是更加偏向于沉稳性节奏&#xff0c;能够轻松征服轻运动场景&#xff0c;此系列在舒适度以及音质上&#xff0c;更…

【GNN笔记】GNN图论文相关笔记公开汇总清单

图神经网络相关论文笔记清单持续待更....&#x1f600; &#x1f427;&#x1f427;&#x1f427;&#x1f427;~【异构图笔记】1. 异构图笔记部分示例2. 异构图笔记清单罗列【图-注意力机制笔记】1. 图-注意力机制笔记部分示例2. 图-注意力机制笔记清单罗列这是一份有关我自己…

经典蓝牙Sniff Mode

文章目录IntroductionApplicationSniff Sub-ratingReferenceIntroduction Sniff mode为两个已连接的经典蓝牙设备提供了有效的降低功耗的方法。我们知道&#xff0c;当没有数据需要传输的时候&#xff0c;两个已连接的蓝牙设备之间也需要每两个slots完成一次POLL packet - NUL…