Softmax函数防止溢出,稳定计算

embedded/2024/10/17 18:19:24/

Softmax函数

用户:

cv::Mat softmax(const cv::Mat& src) {CV_Assert(src.type() == CV_32FC1); // 确保输入矩阵是单通道的32位浮点类型for (auto i = 0; i < src.rows; ++i) {cv::Mat singleRow = src.row(i);double max;cv::minMaxLoc(singleRow, NULL, &max, NULL, NULL);singleRow -= static_cast<float>(max);cv::exp(singleRow, singleRow);cv::Mat sumMat;cv::reduce(singleRow, sumMat, 1, cv::REDUCE_SUM, CV_32F);float sum = sumMat.at<float>(0, 0); // 假设 sumMat 是一个单列矩阵singleRow /= sum;}return src;
}

根据这个softmax把数学表达式写出来

ChatGPT:

Softmax函数是一种常用于多分类任务的激活函数,它能够将一个向量转换成概率分布。给定一个输入向量 ( z = [ z 1 , z 2 , … , z n ] ) (\mathbf{z} = [z_1, z_2, \ldots, z_n]) (z=[z1,z2,,zn]),Softmax函数的输出是:

softmax ( z i ) = e z i ∑ j = 1 n e z j \text{softmax}(z_i) = \frac{e^{z_i}}{\sum_{j=1}^{n} e^{z_j}} softmax(zi)=j=1nezjezi

这个函数将输入向量中的每个元素 z i z_i zi转换为一个非负数,并且这些非负数的总和为1。

对于你的代码,假设输入矩阵 X \mathbf{X} X m m m 行和 n n n 列。代码的每一步操作可以用数学表达式表示如下:

  1. 取每一行的最大值并减去它
    对于矩阵 X \mathbf{X} X 的第 i i i x i \mathbf{x}_i xi,找到最大值 max ⁡ ( x i ) \max(\mathbf{x}_i) max(xi) 并减去它,用公式表示为:
    x i ′ = x i − max ⁡ ( x i ) \mathbf{x}_i' = \mathbf{x}_i - \max(\mathbf{x}_i) xi=ximax(xi)

  2. 对每个元素取指数
    对于每个元素 x i j ′ \mathbf{x}_{ij}' xij(第 i i i 行第 j j j 列的元素),取指数:
    y i j = e x i j ′ \mathbf{y}_{ij} = e^{\mathbf{x}_{ij}'} yij=exij

  3. 计算每一行的元素和
    对于第 i i i 行,计算所有元素的和:
    S i = ∑ j = 1 n y i j S_i = \sum_{j=1}^{n} \mathbf{y}_{ij} Si=j=1nyij

  4. 每一行的元素除以该行的和
    对于第 i i i 行的每个元素,除以该行的和 S i S_i Si
    z i j = y i j S i \mathbf{z}_{ij} = \frac{\mathbf{y}_{ij}}{S_i} zij=Siyij

综合起来,对于矩阵 X \mathbf{X} X 中的每一行 x i \mathbf{x}_i xi,Softmax函数的数学表达式是:

softmax ( x i ) = [ e x i 1 − max ⁡ ( x i ) ∑ j = 1 n e x i j − max ⁡ ( x i ) , e x i 2 − max ⁡ ( x i ) ∑ j = 1 n e x i j − max ⁡ ( x i ) , … , e x i n − max ⁡ ( x i ) ∑ j = 1 n e x i j − max ⁡ ( x i ) ] \text{softmax}(\mathbf{x}_i) = \left[ \frac{e^{x_{i1} - \max(\mathbf{x}_i)}}{\sum_{j=1}^{n} e^{x_{ij} - \max(\mathbf{x}_i)}}, \frac{e^{x_{i2} - \max(\mathbf{x}_i)}}{\sum_{j=1}^{n} e^{x_{ij} - \max(\mathbf{x}_i)}}, \ldots, \frac{e^{x_{in} - \max(\mathbf{x}_i)}}{\sum_{j=1}^{n} e^{x_{ij} - \max(\mathbf{x}_i)}} \right] softmax(xi)=[j=1nexijmax(xi)exi1max(xi),j=1nexijmax(xi)exi2max(xi),,j=1nexijmax(xi)exinmax(xi)]

用户:

代码里的函数是不是比原始的softmax多了一个减去最大值的操作?有什么好处?

ChatGPT:

在计算Softmax之前,先减去了每一行的最大值。这一步操作在数学上可以写作:

x ′ = x − max ⁡ ( x ) \mathbf{x}' = \mathbf{x} - \max(\mathbf{x}) x=xmax(x)

然后再计算Softmax:

softmax ( x ′ ) = e x ′ ∑ j e x j ′ \text{softmax}(\mathbf{x}') = \frac{e^{\mathbf{x}'}}{\sum_{j} e^{\mathbf{x}'_j}} softmax(x)=jexjex

这种做法的好处主要有以下几个方面:

1. 防止数值溢出

在计算Softmax时,直接计算 e x i e^{\mathbf{x}_i} exi 可能会导致数值溢出(尤其是当 x i \mathbf{x}_i xi 中的某些值很大时)。例如,如果 x i \mathbf{x}_i xi 中有一个值是1000,那么 e 1000 e^{1000} e1000 会非常大,超出浮点数的表示范围,导致数值溢出错误。

通过减去最大值 max ⁡ ( x ) \max(\mathbf{x}) max(x),可以将所有的指数计算稳定在一个合理的范围内,从而避免数值溢出的问题。例如,如果 x i \mathbf{x}_i xi 的最大值是1000,那么减去1000后,最大的指数计算变成 e 0 = 1 e^0 = 1 e0=1,这在数值上是安全的。

2. 稳定数值计算

减去最大值还可以提高数值计算的稳定性。即使在没有溢出的情况下,直接计算 e x i e^{\mathbf{x}_i} exi 也可能导致非常小的数值,从而在浮点数运算中引入较大的误差。通过减去最大值,可以使得计算保持在一个更稳定的数值范围内。

3. 保持结果不变

减去最大值并不会改变Softmax的结果。这是因为Softmax函数的输出是一个概率分布,归一化后总和为1:

softmax ( x ) = e x i ∑ j e x j \text{softmax}(\mathbf{x}) = \frac{e^{\mathbf{x}_i}}{\sum_{j} e^{\mathbf{x}_j}} softmax(x)=jexjexi

减去一个常数 C C C 后,Softmax的计算变为:

softmax ( x − C ) = e x i − C ∑ j e x j − C = e x i ⋅ e − C ∑ j e x j ⋅ e − C = e x i ∑ j e x j \text{softmax}(\mathbf{x} - C) = \frac{e^{\mathbf{x}_i - C}}{\sum_{j} e^{\mathbf{x}_j - C}} = \frac{e^{\mathbf{x}_i} \cdot e^{-C}}{\sum_{j} e^{\mathbf{x}_j} \cdot e^{-C}} = \frac{e^{\mathbf{x}_i}}{\sum_{j} e^{\mathbf{x}_j}} softmax(xC)=jexjCexiC=jexjeCexieC=jexjexi

可以看到,分子和分母同时乘以 e − C e^{-C} eC 后,结果并没有改变。

因此,减去最大值的操作不仅提高了数值计算的稳定性和安全性,还不会影响Softmax函数的最终结果。

用户:

深度学习中,值分布得太分散,经过softmax后使得输出更靠近0或1,为什么会导致梯度比较小?

ChatGPT:

在深度学习中,值分布得太分散,经过Softmax后使得输出更靠近0或1,这种现象称为“输出饱和”。输出饱和会导致梯度比较小,原因主要可以从梯度的计算公式和数值稳定性两个方面来理解。

1. 梯度计算公式

对于Softmax函数,假设输入向量为 z = [ z 1 , z 2 , … , z n ] \mathbf{z} = [z_1, z_2, \ldots, z_n] z=[z1,z2,,zn],Softmax输出为 y = [ y 1 , y 2 , … , y n ] \mathbf{y} = [y_1, y_2, \ldots, y_n] y=[y1,y2,,yn],其中

y i = e z i ∑ j = 1 n e z j y_i = \frac{e^{z_i}}{\sum_{j=1}^{n} e^{z_j}} yi=j=1nezjezi

在反向传播中,损失函数 L L L 对输入 z \mathbf{z} z 的梯度可以表示为:

∂ L ∂ z i = ∑ j = 1 n ∂ L ∂ y j ∂ y j ∂ z i \frac{\partial L}{\partial z_i} = \sum_{j=1}^{n} \frac{\partial L}{\partial y_j} \frac{\partial y_j}{\partial z_i} ziL=j=1nyjLziyj

其中,Softmax的导数 ∂ y j ∂ z i \frac{\partial y_j}{\partial z_i} ziyj 可以表示为:

∂ y j ∂ z i = y j ( δ i j − y i ) \frac{\partial y_j}{\partial z_i} = y_j (\delta_{ij} - y_i) ziyj=yj(δijyi)

其中 δ i j \delta_{ij} δij 是Kronecker delta函数,当 i = j i = j i=j 时为1,否则为0。

因此,梯度 ∂ L ∂ z i \frac{\partial L}{\partial z_i} ziL 可以进一步展开为:

∂ L ∂ z i = y i ( ∂ L ∂ y i − ∑ j = 1 n y j ∂ L ∂ y j ) \frac{\partial L}{\partial z_i} = y_i \left( \frac{\partial L}{\partial y_i} - \sum_{j=1}^{n} y_j \frac{\partial L}{\partial y_j} \right) ziL=yi(yiLj=1nyjyjL)

2. 梯度变小的原因

当Softmax输出 y \mathbf{y} y 非常接近0或1时,意味着输入 z \mathbf{z} z 的值分布非常分散(即有一个或几个值远大于其他值)。这种情况下,Softmax函数会导致以下问题:

  • 对于接近1的输出:假设某个输出 y k ≈ 1 y_k \approx 1 yk1,那么其他输出 y i ≈ 0 y_i \approx 0 yi0(对于 i ≠ k i \neq k i=k)。此时, ∂ y k ∂ z i \frac{\partial y_k}{\partial z_i} ziyk ∂ y i ∂ z k \frac{\partial y_i}{\partial z_k} zkyi 的值都非常小,因为 y i ( 1 − y i ) y_i (1 - y_i) yi(1yi) y k ( 1 − y k ) y_k (1 - y_k) yk(1yk) 都接近0。
  • 对于接近0的输出:类似地, ∂ y i ∂ z i \frac{\partial y_i}{\partial z_i} ziyi ∂ y i ∂ z j \frac{\partial y_i}{\partial z_j} zjyi 的值也会非常小。

这种情况下,梯度的数值会非常小,导致反向传播时梯度更新的步长很小,从而使得网络的参数更新变得非常缓慢。这种现象被称为“梯度消失”。

3. 数值稳定性

当输入值分布非常分散时,Softmax的指数计算会导致数值不稳定。即使在减去最大值后,仍然可能会出现数值精度问题,进一步导致梯度计算的不稳定性和减小。

总结

  • 输出饱和:Softmax输出接近0或1时,梯度 ∂ y i ∂ z i \frac{\partial y_i}{\partial z_i} ziyi ∂ y j ∂ z i \frac{\partial y_j}{\partial z_i} ziyj 都会变得非常小。
  • 梯度消失:梯度变小导致反向传播时参数更新的步长变小,训练过程变得缓慢。
  • 数值稳定性:输入值分布分散会导致数值计算不稳定,进一步影响梯度的计算。

为了缓解这种问题,可以使用一些技术,如Batch Normalization、Gradient Clipping等,或者在网络结构设计时避免过深的网络层数。

用户:

Transformer中的注意力机制,采用了缩放因子来避免梯度消失问题。

ChatGPT:

是的,Transformer中的注意力机制采用了缩放因子来避免梯度消失问题。具体来说,这个缩放因子是用于计算点积注意力(Scaled Dot-Product Attention)中的。

点积注意力

在Transformer模型中,点积注意力的计算公式为:

Attention ( Q , K , V ) = softmax ( Q K T d k ) V \text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right) V Attention(Q,K,V)=softmax(dk QKT)V

其中:

  • (Q) 是查询矩阵(Query)
  • (K) 是键矩阵(Key)
  • (V) 是值矩阵(Value)
  • (d_k) 是键向量的维度

缩放因子

在上面的公式中, 1 d k \frac{1}{\sqrt{d_k}} dk 1 就是缩放因子。这个因子的引入有以下几个目的:

1. 防止点积值过大

点积 Q K T QK^T QKT 的值会随着向量维度 d k d_k dk 的增加而变大。假设查询和键向量的每个元素都是独立同分布的随机变量,且其均值为0,方差为1,那么点积的期望值和方差都会随维度 d k d_k dk 增大。

2. 缩放避免Softmax函数的梯度消失

如果不进行缩放,点积 Q K T QK^T QKT 的值可能会非常大,导致Softmax函数的输出接近于0或1。这种情况下,Softmax函数的梯度会变得非常小,导致梯度消失问题。

通过引入缩放因子 1 d k \frac{1}{\sqrt{d_k}} dk 1,可以将点积的值缩小到一个较为合理的范围内,从而使得Softmax函数的输出更加平滑,梯度也更加稳定。

数学解释

假设查询和键向量的元素都是均值为0,方差为1的独立同分布随机变量,那么点积 Q K T QK^T QKT 的期望为0,方差为 d k d_k dk。为了使点积的方差保持在一个较为稳定的范围内,我们将其除以 d k \sqrt{d_k} dk ,这样点积的方差就变为1:

Q K T d k \frac{QK^T}{\sqrt{d_k}} dk QKT

这样可以确保Softmax函数的输入值不会过大或过小,从而使其输出更加平滑,梯度更加稳定。

总结

在Transformer的注意力机制中,引入缩放因子 1 d k \frac{1}{\sqrt{d_k}} dk 1 的主要目的是:

  1. 防止点积值过大,导致数值不稳定。
  2. 避免Softmax函数输出接近0或1,防止梯度消失问题。

通过这种方法,可以提高注意力机制的数值稳定性,确保模型在训练过程中梯度的有效传播。


http://www.ppmy.cn/embedded/101716.html

相关文章

安卓中 onClick(View v) 方法在主线程还是子线程运行

在Android开发中&#xff0c;onClick(View v) 方法通常是在主线程&#xff08;也称为UI线程&#xff09;中运行的。这个方法是在用户与界面元素&#xff08;如按钮&#xff09;进行交互时&#xff0c;由系统框架自动调用的。由于Android的UI操作必须是线程安全的&#xff0c;并…

力扣面试经典算法150题:除自身以外数组的乘积

除自身以外数组的乘积算法详解 今天的题目是力扣面试经典150题中的数组的中等难度题&#xff1a;除自身以外数组的乘积。 题目链接&#xff1a;https://leetcode.cn/problems/product-of-array-except-self/description/?envTypestudy-plan-v2&envIdtop-interview-150 …

C++对比C语言新的赋值

1.int a(10);//int a10;只能用于初始化不能运用于再次赋值 2.int a{b};//ab; 3.键盘输入cin&#xff1a; 可以使用cin把用户在命令行中的内容赋值到变量中。 空格也算是字符&#xff1b; string str; // C的字符串是string cin>>str>>endl; // 接收键盘输入&am…

【模型】Temporal Fusion Transformer (TFT) 模型

Temporal Fusion Transformer (TFT) 模型是一种专为时间序列预测设计的高级深度学习模型。它结合了神经网络的多种机制来处理时间序列数据中的复杂关系。TFT 由 Lim et al. 于 2019 年提出&#xff0c;旨在处理时间序列中的不确定性和多尺度的依赖关系。 一、TFT模型的核心组成…

laravel “Class \“Redis\“ not found“ 如何解决?

laravel “Class “Redis” not found” 如何解决 问题&#xff1a;laravel 安装好后&#xff0c;运行报错提示&#xff1a;“Class “Redis” not found” 分析&#xff1a;程序并没有用到redis&#xff0c;百度了一下&#xff0c;初步锁定可能是php环境的原因&#xff0c;运…

基于微信小程序的外卖订餐系统设计与实现

外卖| 订餐小程序| 外卖订餐小程序 博主介绍&#xff1a;✌️大家好&#xff01;我是Coder-coco&#xff0c;一名专注以理论为基础、实战为主的技术博主&#xff0c;本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#xff0c;希望你能有所收…

自动化脚本到LabVIEW转换

工业自动化领域中的专用脚本语言转换为LabVIEW时需要注意的问题 语法差异&#xff1a; 脚本语言特点&#xff1a; 工业自动化脚本语言通常具有特定的语法和结构&#xff0c;例如条件判断、循环控制、硬件指令等。这些语言直接面向硬件操作&#xff0c;语法简洁&#xff0c;适用…

FreeMarker是什么?怎么用?

FreeMarker 详细介绍 一、概念 FreeMarker 是一个基于 Java 的模板引擎&#xff0c;用于生成动态文本内容。它的核心功能是将模板&#xff08;.ftl 文件&#xff09;和数据模型结合&#xff0c;生成最终的文本输出。FreeMarker 不仅可以用于 Web 开发中的视图渲染&#xff0c…