深度学习-2.9梯度不稳定和Glorot条件

梯度不稳定和Glorot条件

一、梯度消失和梯度爆炸

  对于神经网络这个复杂系统来说,在模型训练过程中,一个最基础、同时也最常见的问题,就是梯度消失和梯度爆炸。

  我们知道,神经网络在进行反向传播的过程中,各参数层的梯度计算会涉及到激活函数导函数取值,具体来说,假设现在有一个三层的神经网络,其中两个隐藏层的激活函数为 F ( x ) F(x) F(x),对应的导函数为 f ( x ) f(x) f(x),设X为输入训练的数据特征,y为标签, y ^ \hat{y} y^为模型向前传播输出结果,$ w_1 为第一层参数、 为第一层参数、 为第一层参数、w_2 为第二层参数、 为第二层参数、 为第二层参数、w_3$为第三层参数,loss为损失函数,则有如下计算公式:

  每一次正向传播计算结果:
y ^ = F ( F ( X ∗ w 1 ) ∗ w 2 ) ∗ w 3 \hat y = F(F(X * w_1) * w_2) * w_3 y^=F(F(Xw1)w2)w3
  而loss是一个关于y和 y ^ \hat{y} y^的函数,而y是常量, y ^ \hat{y} y^是一个关于w的函数,因此 l o s s loss loss也进行如下表示:
l o s s ( y ^ ) loss(\hat{y}) loss(y^)
  在进行梯度求解时候,假设 w 1 w_1 w1对应梯度为 g r a d 1 grad_1 grad1, w 2 w_2 w2对应梯度为 g r a d 2 grad_2 grad2, w 3 w_3 w3对应梯度为 g r a d 3 grad_3 grad3,为了简化计算,我们假设所有的 x 、 w 1 、 w 2 、 w 3 x、w_1、w_2、w_3 xw1w2w3都是标量,根据链式法则,有计算过程如下:
g r a d 1 = ∂ l o s s ∂ w 1 = ∂ l o s s ∂ y ^ ⋅ ∂ y ^ ∂ w 1 = ∂ l o s s ∂ y ^ ⋅ ∂ ( F ( F ( X ∗ w 1 ) ∗ w 2 ) ∗ w 3 ) ∂ w 1 = ∂ l o s s ∂ y ^ ⋅ ∂ ( F ( F ( X ∗ w 1 ) ∗ w 2 ) ∗ w 3 ) ∂ ( F ( F ( X ∗ w 1 ) ∗ w 2 ) ⋅ ∂ F ( F ( X ∗ w 1 ) ∗ w 2 ) ∂ F ( X ∗ w 1 ) ⋅ ∂ F ( X ∗ w 1 ) ∂ w 1 = ∂ l o s s ∂ y ^ ⋅ w 3 ⋅ f ( F ( X ∗ w 1 ) ∗ w 2 ) ⋅ w 2 ⋅ f ( X ∗ w 1 ) ⋅ X \begin{aligned} grad_1 &=\frac{\partial loss}{\partial w_1} \\ &= \frac{\partial loss}{\partial \hat y} \cdot \frac{\partial \hat y}{\partial w_1} \\ &= \frac{\partial loss}{\partial \hat y} \cdot \frac{\partial (F(F(X * w_1) * w_2) * w_3)}{\partial w_1} \\ &= \frac{\partial loss}{\partial \hat y} \cdot \frac{\partial (F(F(X * w_1) * w_2) * w_3)}{\partial (F(F(X * w_1) * w_2)} \cdot \frac{\partial F(F(X * w_1) * w_2)}{\partial F(X * w_1)} \cdot \frac{\partial F(X * w_1)}{\partial w_1}\\ &= \frac{\partial loss}{\partial \hat y} \cdot w_3 \cdot f(F(X * w_1) * w_2) \cdot w_2 \cdot f(X * w_1) \cdot X \\ \end{aligned} grad1=w1loss=y^lossw1y^=y^lossw1(F(F(Xw1)w2)w3)=y^loss(F(F(Xw1)w2)(F(F(Xw1)w2)w3)F(Xw1)F(F(Xw1)w2)w1F(Xw1)=y^lossw3f(F(Xw1)w2)w2f(Xw1)X
  值得注意的是,此时 g r a d 1 grad_1 grad1中计算了两次激活函数的导函数,并且在上述过程中, X ∗ w 1 X * w_1 Xw1是第一层隐藏层接收到的数据,而 F ( X ∗ w 1 ) ∗ w 2 F(X*w_1)*w_2 F(Xw1)w2则是第二层隐藏层接收到的数据。而对比如果是计算 w 2 w_2 w2的梯度,则有如下过程:
g r a d 2 = ∂ l o s s ∂ w 2 = ∂ l o s s ∂ y ^ ⋅ ∂ y ^ ∂ w 2 = ∂ l o s s ∂ y ^ ⋅ ∂ ( F ( F ( X ∗ w 1 ) ∗ w 2 ) ∗ w 3 ) ∂ w 2 = ∂ l o s s ∂ y ^ ⋅ ∂ ( F ( F ( X ∗ w 1 ) ∗ w 2 ) ∗ w 3 ) ∂ ( F ( F ( X ∗ w 1 ) ∗ w 2 ) ⋅ ∂ F ( F ( X ∗ w 1 ) ∗ w 2 ) ∂ w 2 = ∂ l o s s ∂ y ^ ⋅ w 3 ⋅ ∂ F ( F ( X ∗ w 1 ) ∗ w 2 ) ∂ w 2 = ∂ l o s s ∂ y ^ ⋅ w 3 ⋅ f ( F ( X ∗ w 1 ) ∗ w 2 ) ⋅ ∂ ( F ( X ∗ w 1 ) ∗ w 2 ) ∂ w 2 = ∂ l o s s ∂ y ^ ⋅ w 3 ⋅ f ( F ( X ∗ w 1 ) ∗ w 2 ) ⋅ F ( X ∗ w 1 ) \begin{aligned} grad_2 &=\frac{\partial loss}{\partial w_2} \\ &= \frac{\partial loss}{\partial \hat y} \cdot \frac{\partial \hat y}{\partial w_2} \\ &= \frac{\partial loss}{\partial \hat y} \cdot \frac{\partial (F(F(X * w_1) * w_2) * w_3)}{\partial w_2} \\ &= \frac{\partial loss}{\partial \hat y} \cdot \frac{\partial (F(F(X * w_1) * w_2) * w_3)}{\partial (F(F(X * w_1) * w_2)} \cdot \frac{\partial F(F(X * w_1) * w_2)}{\partial w_2} \\ &= \frac{\partial loss}{\partial \hat y} \cdot w_3 \cdot \frac{\partial F(F(X * w_1) * w_2)}{\partial w_2} \\ &= \frac{\partial loss}{\partial \hat y} \cdot w_3 \cdot f(F(X*w_1)*w_2) \cdot \frac{\partial (F(X * w_1) * w_2)}{\partial w_2} \\ &= \frac{\partial loss}{\partial \hat y} \cdot w_3 \cdot f(F(X*w_1)*w_2) \cdot F(X * w_1) \\ \end{aligned} grad2=w2loss=y^lossw2y^=y^lossw2(F(F(Xw1)w2)w3)=y^loss(F(F(Xw1)w2)(F(F(Xw1)w2)w3)w2F(F(Xw1)w2)=y^lossw3w2F(F(Xw1)w2)=y^lossw3f(F(Xw1)w2)w2(F(Xw1)w2)=y^lossw3f(F(Xw1)w2)F(Xw1)
  我们发现,在计算过程中只出现了一次激活函数的导函数。当然如果我们是计算 w 3 w_3 w3的梯度,则与如下计算过程:
g r a d 3 = ∂ l o s s ∂ w 3 = ∂ l o s s ∂ y ^ ⋅ ∂ y ^ ∂ w 3 = ∂ l o s s ∂ y ^ ⋅ ∂ ( F ( F ( X ∗ w 1 ) ∗ w 2 ) ∗ w 3 ) ∂ w 3 = ∂ l o s s ∂ y ^ ⋅ F ( F ( X ∗ w 1 ) ∗ w 2 ) \begin{aligned} grad_3 &=\frac{\partial loss}{\partial w_3} \\ &= \frac{\partial loss}{\partial \hat y} \cdot \frac{\partial \hat y}{\partial w_3} \\ &= \frac{\partial loss}{\partial \hat y} \cdot \frac{\partial (F(F(X * w_1) * w_2) * w_3)}{\partial w_3} \\ &= \frac{\partial loss}{\partial \hat y} \cdot F(F(X * w_1) * w_2) \\ \end{aligned} grad3=w3loss=y^lossw3y^=y^lossw3(F(F(Xw1)w2)w3)=y^lossF(F(Xw1)w2)

  此时 g r a d 3 grad_3 grad3在计算过程中就已经不涉及激活函数的导函数的计算了。

  其实如果当神经网络层数继续增加、激活函数的数量继续增加,第一层参数在计算梯度的过程中需要相乘的激活函数导函数个数也会随之增加,而后面几层参数的梯度计算中涉及到的激活函数导函数个数逐级递减。

当然,上述过程如果换成矩阵求导,公式主体部分基本不变,只有最后一项会发生变化。由于最终运算结果无法写成较为简洁的矩阵运算形式(矩阵变元的实向量函数),因此此处以标量运算为例。

  而累乘就容易造成指数级变化,当激活函数值 F ( F ( X ∗ w 1 ) ) F(F(X*w_1)) F(F(Xw1))、激活函数导函数值 f ( X ∗ w 1 ) f(X*w_1) f(Xw1)或者参与相乘的参数取值( w 3 w_3 w3)较大(>1)时,会出现 g r a d 1 grad_1 grad1远大于 g r a d 2 grad_2 grad2远大于 g r a d 3 grad_3 grad3的情况,也就是神经网络前几层参数梯度非常大、而后几层参数梯度相对较小的情况,此时就被称为梯度爆炸,并且受到累乘效应的影响,前几层梯度也会大于甚至远大于1,此时就会造成模型迭代过程不稳定的情况发生;而反之如果上述几个变量均小于1,甚至远小于1,则会出现前几层参数梯度非常小、而后几层参数梯度非常大的情况,此时就被称为梯度消失,此时由于模型各层参数学习率伴随层数增加逐渐增加,并且由于构成梯度的基本参数均小于1,因此最后几层梯度也会小于1甚至远小于1,此时前几层参数梯度取值将非常小,甚至趋于0,因而会使得前几层的参数无法在迭代中得到更新。

  总结一下,不同层参数的梯度在计算过程中都有很大的差异,并且这种差异是一种累乘效应,我们也可以简单理解为是一种伴随着层数增加指数级变化的差异。而这种累乘效应会导致线性层参数的一部分梯度过大而另一部分过小,从而影响模型平稳训练。而从具体原因来说,每一层参数的梯度主要和两个因素相关,其一是线性层输入数据,如 X X X F ( X ∗ W ) F(X*W) F(XW),其二则是激活函数导函数计算结果 f ( X ∗ w 1 ) f(X*w_1) f(Xw1)

  接下来,我们就从梯度消失和梯度爆炸的角度剖析Sigmoid和tanh激活函数叠加过程中可能存在的隐患。

二、Sigmoid和tanh激活函数的梯度更新问题

1.Sigmoid激活函数的梯度消失问题

  • 理论说明

  对于sigmoid激活函数来说,简答的叠加是极容易出现梯度消失的问题。sigmoid函数及导函数图像如下所示:

在这里插入图片描述

在这里插入图片描述

  我们发现,Sigmoid导函数最大值为0.25(在0点处取到),当x较大或者较小时,导函数取值趋于0。

  此时如果我们假设还是上述结构的三层神经网络,则第一层参数梯度 g r a d 1 grad_1 grad1由于计算过程出现两次导函数连乘,哪怕两次都导函数都取到最大值(虽然可能性较小), g r a d 1 grad_1 grad1都将在0.0625的基础上进行其余部分相乘,最终结果也极有可能是个非常小的值,因此对于Sigmoid激活函数叠加的情况来说,是极容易出现梯度消失情况的。
g r a d 1 = ∂ l o s s ∂ y ^ ⋅ w 3 ⋅ f ( F ( X ∗ w 1 ) ∗ w 2 ) ⋅ w 2 ⋅ f ( X ∗ w 1 ) ⋅ X grad_1 = \frac{\partial loss}{\partial \hat y} \cdot w_3 \cdot f(F(X*w_1)*w_2) \cdot w_2 \cdot f(X * w_1) \cdot X grad1=y^lossw3f(F(Xw1)w2)w2f(Xw1)X

g r a d 2 = ∂ l o s s ∂ y ^ ⋅ w 3 ⋅ f ( F ( X ∗ w 1 ) ∗ w 2 ) ⋅ F ( X ∗ w 1 ) grad_2 = \frac{\partial loss}{\partial \hat y} \cdot w_3 \cdot f(F(X*w_1)*w_2) \cdot F(X * w_1) grad2=y^lossw3f(F(Xw1)w2)F(Xw1)

g r a d 3 = ∂ l o s s ∂ y ^ ⋅ F ( F ( X ∗ w 1 ) ∗ w 2 )   梯度消失或者梯度爆炸,始终是个概率问题。我们不能说导函数取值取值小就一定会发生梯度消失问题,只是导函数最大值越小,越有可能发生梯度消失。 grad_3 = \frac{\partial loss}{\partial \hat y} \cdot F(F(X * w_1) * w_2)\> 梯度消失或者梯度爆炸,始终是个概率问题。我们不能说导函数取值取值小就一定会发生梯度消失问题,只是导函数最大值越小,越有可能发生梯度消失。 grad3=y^lossF(F(Xw1)w2)梯度消失或者梯度爆炸,始终是个概率问题。我们不能说导函数取值取值小就一定会发生梯度消失问题,只是导函数最大值越小,越有可能发生梯度消失。

  • Sigmoid函数饱和区间

  一般来说我们会将靠近sigmoid函数的左右两端的区间称为函数的饱和区间(如下图圈出部分)(也就是自变量绝对值较大的区间),不难发现,当自变量落入饱和区间时,因变量会趋于0或者1,而无论自变量是极小(负数绝对值极大)还是极大,都会使得导函数取值趋于0,从而更容易导致模型梯度消失。

在这里插入图片描述

  设计一个函数,构建一个使用了三层sigmoid激活层的函数

在这里插入图片描述

  将多层网络的权重进行输出:

for i, m in enumerate(sigmoid_model3.modules()):
  if isinstance(m, nn.Linear):
    vp_x = m.weight.grad.detach().reshape(-1, 1).numpy()       # 每一层参数梯度
    vp_y = np.full_like(vp_x, i)                   				# 对层进行标记
    vp_a = np.concatenate((vp_x, vp_y), 1)vp.append(vp_a)

在这里插入图片描述

  类似的,tanh也存在问题:

在这里插入图片描述

随着训练次数的增多,网络之间的权重逐渐消失,模型无法有效学习,最终影响模型效果。

三、Zero-Centered Data与Glorot条件

  通过对Sigmoid和tanh激活函数叠加后的模型梯度变化情况分析,我们不难发现,梯度不平稳是影响模型建模效果的非常核心的因素。而这个看似简单问题的解决方案,却花费了研究人员数十年的时间才逐渐完善,我们现在所接触到的优化方法,也基本上是在15年前后提出的,而这些被验证的切实可行的优化方法,也是推动这一轮深度学习浪潮的技术因素。

当然,这些优化方法主要是针对深层次神经网络的。

  整体来看,针对梯度不平稳的解决方案(优化方法)总共分为五类,分别是参数初始化方法、输入数据的归一化方法、衍生激活函数使用方法、学习率调度方法以及梯度下降优化方法。接下来,先介绍所有上述优化算法的一个基本理论,由Xavier Glorot在2010提出的Glorot条件。

值得注意的是,虽然不同优化算法有不同的出发点和不同的论证方式,但基本都可以从Glorot条件出发进行思考。

1.Zero-centered Data

  在介绍Glorot条件之前,我们先从一个更加朴素的角度出发,讨论关于Zero-Centered Data相关作用,从而帮助我们理解后续Glorot条件。

  首先,我们还是假设当前模型是一个三层神经网络,其中两个隐藏层的激活函数为 F ( x ) F(x) F(x),对应的导函数为 f ( x ) f(x) f(x),设X为输入训练的数据特征,y为标签, y ^ \hat y y^为模型向前传播输出结果, w 1 w_1 w1为第一层参数、 w 2 w_2 w2为第二层参数、 w 3 w_3 w3为第三层参数,loss为损失函数,则有如下计算公式:

  每一次正向传播计算结果:
y ^ = F ( F ( X ∗ w 1 ) ∗ w 2 ) ∗ w 3 \hat y = F(F(X * w_1) * w_2) * w_3 y^=F(F(Xw1)w2)w3
  假设 Z i Z_i Zi为第i层接收到的数据, P i P_i Pi为第i层输出的数据,则有:
Z 1 = X ∗ w 1 Z_1 = X*w_1 Z1=Xw1

P 1 = F ( Z 1 ) = F ( X ∗ w 1 ) P_1 = F(Z_1) = F(X*w_1) P1=F(Z1)=F(Xw1)

Z 2 = P 1 ∗ w 2 = F ( X ∗ w 1 ) ∗ w 2 Z_2 = P_1 * w_2 = F(X*w_1)*w_2 Z2=P1w2=F(Xw1)w2

P 2 = F ( Z 2 ) = F ( F ( X ∗ w 1 ) ∗ w 2 ) P_2 = F(Z_2) = F(F(X*w_1)*w_2) P2=F(Z2)=F(F(Xw1)w2)

Z 3 = y ^ = F ( F ( X ∗ w 1 ) ∗ w 2 ) ∗ w 3 Z_3 = \hat y = F(F(X * w_1) * w_2) * w_3 Z3=y^=F(F(Xw1)w2)w3

  依次类推。而在反向传播过程,各参数层的梯度如下:
g r a d 1 = ∂ l o s s ∂ y ^ ⋅ w 3 ⋅ f ( F ( X ∗ w 1 ) ∗ w 2 ) ⋅ w 2 ⋅ f ( X ∗ w 1 ) ⋅ X grad_1 = \frac{\partial loss}{\partial \hat y} \cdot w_3 \cdot f(F(X*w_1)*w_2) \cdot w_2 \cdot f(X * w_1) \cdot X grad1=y^lossw3f(F(Xw1)w2)w2f(Xw1)X

g r a d 2 = ∂ l o s s ∂ y ^ ⋅ w 3 ⋅ f ( F ( X ∗ w 1 ) ∗ w 2 ) ⋅ F ( X ∗ w 1 ) grad_2 = \frac{\partial loss}{\partial \hat y} \cdot w_3 \cdot f(F(X*w_1)*w_2) \cdot F(X * w_1) grad2=y^lossw3f(F(Xw1)w2)F(Xw1)

g r a d 3 = ∂ l o s s ∂ y ^ ⋅ F ( F ( X ∗ w 1 ) ∗ w 2 ) grad_3 = \frac{\partial loss}{\partial \hat y} \cdot F(F(X * w_1) * w_2) grad3=y^lossF(F(Xw1)w2)

  在梯度消失和梯度爆炸的案例中,我们不难发现,为了确保多层神经网络的有效性,各层梯度的差距不应太大,此时一个最为基本的想法就是,就是能否让所有的输入数据(也就是X)以及所有层的参数都设置为Zero-Centered Data,也就是零点对称数据,不难发现,由于X和 w i w_i wi都是零点对称的,因此每一个线性层中的导函数也取值也能够维持在0-1之间,进而每一层的梯度基本能维持在比较平稳的状态。

另外,除了能够避免梯度不平稳问题以外,创建Zero-Centered的参数和数据集,还能够更好的在正向传播中将信息传播到各层,以及确保各层学习的平稳性。

  关于如何将带入模型训练的数据转化为Zero-Centered Data,一般来说我们会使用一系列标准化方法对其进行转化,具体方法我们会在Lesson 14进行详细介绍,由于我们此前创建的数据生成器生成的就是Zero-Centered Data,因此暂时这些数据不会影响接下来的优化方法使用。而如何将参数转化为Zero-Centered Data,就是核心需要考虑的问题了。

对于输入的数据来说,我们可以尽量保证其Zero-Centered的特性,但模型参数是随着模型迭代不断变化的,我们无法把控模型每一轮迭代后的情况,因此只能从模型参数初始值入手,尽量保证其Zero-Centered属性。

  很明显,我们不能将参数的初始值全部设为0,我们只能考虑借助统计工具生成均值是0的随机数,也就是0均值的均匀分布或者是0均值的高斯分布,但这里需要考虑的另一个问题就是,该随机数的方差应该如何确定?

2.Glorot条件和Xavier方法

  初始化参数的方差如何确定这一问题在一个严谨论述如何保证模型有效性的论文中,从另一个角度出发,得到了回答。根据Xavier Glorot在2010年发表的《Understanding the difficulty of training deep feedforward neural networks》论文中的观点,为保证模型本身的有效性和稳定性,我们希望正向传播时,每个线性层输入数据的方差等于输出数据的方差,同时我们也希望反向传播时,数据流经某层之前和流经某层之后该层的梯度也具有相同的方差,虽然二者很难同时满足(除非相邻两层神经元个数相同),但Glorot和Bengio(论文第二作者)表示,如果我们适当修改计算过程、是可以找到一种折中方案去设计初始参数取值,从而同时保证二者条件尽可能得到满足,这种设计参数初始值的方法也被称为Xavier方法,而这种方法也经过一段时间的实践验证被证明是很好的一种初始化模型参数的方法,尤其是对于使用tanh激活函数的神经网络来说,效果更为显著。

  而这种正向传播时数据方差保持一致、反向传播时参数梯度方差保持一致的条件,也被称为Glorot条件,满足该条件的模型能够进行有效平稳的训练,而为了满足该条件而创建的(当然也是由上述论文提出的)模型初始化参数值设计方法,也被称为Xavier方法。而在Xavier方法中,最核心解决的问题,也就是为了创建Zero-Centered的初始化参数时参数的方差。和我们从朴素的角度思考的方向是一致的。

  由于Glorot条件和Xavier方法是在2010年提出的,彼时ReLU激活函数还未兴起,因此Xavier方法主要是围绕tanh激活函数可能存在的梯度爆炸或梯度消失进行的优化,Sigmoid激活函数效果次之。不过尽管如此,Glorot条件却是一个通用条件,后续围绕ReLU激活函数、用于解决神经元活性失效的优化方法(如HE初始化方法),也是遵照Glorot条件进行的方法设计。

3.模型初始化参数取值影响

  Xavier初始化方法的推导和使用我们将在下一节详细介绍,此处我们先通过另外一个实例,去展示为何初始参数取值不同,会够得到不同的建模结果。模型初始化时得到的不同参数,本质上等价于在损失函数上找到了不同的初始点,而同一损失函数,初始点选取的不同应该不会影响最终迭代结果才对,但事实情况并非如此。

在这里插入图片描述

  我们发现,初始参数值的选取不仅会影响模型收敛速度,甚至在某些情况下还会影响模型的最终表现。造成此现象的根本原因还是在于神经网络模型在进行训练时,不确定性过多,而在一个拥有诸多不确定性的系统中再加上不确定的初始参数,初始参数的不确定性会被这个系统放大。并且,值得一提的是,每一个epoch中的每一次迭代并不是在一个损失函数上一步步下降的,当我们使用小批量梯度下降算法时,带入不同批的数据,实际创建的损失函数也会不同。

参考

菜菜子的深度学习

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

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

相关文章

工大智信智能听诊智慧医疗的创新

智能听诊器,智慧医疗的新突破 工大智信智能听诊器是一款结合了先进技术和医疗专业知识的创新产品。它以其独特的优势,为医疗行业带来了前所未有的突破和变革。 传统听诊器依赖于医生的主观判断和经验,而工大智信智能听诊器采用了先进的传感技…

颠覆传统编程:Codigger极致体验之旅

在数字化浪潮汹涌的当下,编程已成为推动科技发展的重要引擎。而在这其中,极致编程体验无疑是每位开发者所追求的目标。它不仅代表着工具的高效能与稳定性,更映射出开发者在编程世界中的自由与创造力。Codigger,以其领先的开发框架…

LeetCode---388周赛

题目列表 3074. 重新分装苹果 3075. 幸福值最大化的选择方案 3076. 数组中的最短非公共子字符串 3077. K 个不相交子数组的最大能量值 一、重新分装苹果 注意题目中说同一个包裹中的苹果可以分装,那么我们只要关心苹果的总量即可,在根据贪心&#x…

【Linux Day16 I/O复用】

I/O复用 用途:I/O 复用能同时监听多个文件描述符。 I/O 复用虽然能同时监听多个文件描述符,但它本身是阻塞的。并且当多个文件描述符同时就绪时,如果不采取额外的措施,程序就只能按顺序依处理其中的每一个文件描述符,…

一些刷题需要用的大数据

无符号版本和有符号版本的区别就是有符号类型需要使用一个bit来表示数字的正负。 如果需声明无符号类型的话就需要在类型前加上unsigned。 整型的每一种都分为:无符号(unsigned)和有符号(signed)两种类型(f…

8.测试教程-自动化测试selenium-3

文章目录 1.unittest框架解析2.批量执行脚本2.1构建测试套件2.2用例的执行顺序2.3忽略用例执行 3.unittest断言4.HTML报告生成5.异常捕捉与错误截图6.数据驱动 大家好,我是晓星航。今天为大家带来的是 自动化测试selenium第三节 相关的讲解!&#x1f600…

提升企业内训效率:定制化企业培训APP开发教学

当下,定制化企业培训APP的开发成为提升企业内训效率的重要途径之一。接下来小编将深入讲解如何通过定制化企业培训APP来提升内训效率,并提供相关开发教学。 一、定制的重要性 灵活、便捷:定制化企业培训APP则能够使培训内容随时随地可用&…

Java代码基础算法练习-求给定3个数, 进行从小到大排序-2024.03.20

任务描述&#xff1a; 输入三个整数 x,y,z(0<x<1000&#xff0c;0<y<1000&#xff0c;0<z<1000)&#xff0c;请把这三个数由小到大输出。 任务要求&#xff1a; 代码示例&#xff1a; package march0317_0331;import java.util.Scanner;public class m24…

webpack5零基础入门-10babel的使用

Babel JavaScript 编译器。 主要用于将 ES6 语法编写的代码转换为向后兼容的 JavaScript 语法&#xff0c;以便能够运行在当前和旧版本的浏览器或其他环境中 1.安装相关包 npm install -D babel-loader babel/core babel/preset-env 2.进行相关配置 2.1第一种写法是在webp…

面向低成本线跟随机器人的PID控制器优化——文末源码

目录 介绍 测试 电子元器件 系统特征 控制器设计 位置误差的计算 比例控制 积分控制 微分控制 改进的PID控制器 测试轨迹 源码链接 本文对经典PID控制器的改进和开环控制机制的发展进行了讨论&#xff0c;以提高差动轮式机器人的稳定性和鲁棒性。为了部署该算法&am…

5G里面NR,gNB,en-gNB,ng-eNB是什么意思

不得不提一个国际组织&#xff0c;叫国际电信联盟(ITU, International Telecommunication Union)&#xff0c;简称国际电联。我们先看看国际电联的自我介绍&#xff1a; 国际电信联盟 『国际电联 (国际电信联盟) 是主管信息通信技术事务&#xff08;ICT&#xff09;的联合国机…

26-分支和循环语句_循环练习(上)

写代码的思路&#xff1a; 办法&#xff08;编程思维&#xff09;写代码&#xff08;按照语法形式写&#xff09; 编程思维&#xff1a;需要慢慢训练 1、计算n的阶乘 代码1&#xff1a; int main(){int i 1;int n 0;scanf("%d", &n);int ret 1;do{retret…

MyBatis核心配置文件:解锁数据之美的密码

MyBatis&#xff0c;这位编程的诗人&#xff0c;通过其独特的核心配置文件&#xff0c;为我们描绘出一幅数据之美的画卷。本篇博客将带你深入探讨MyBatis核心配置文件的奥秘&#xff0c;让你能够更好地理解和运用这个优雅的数据持久化框架。 最近想搞私域&#xff0c;欢迎各位…

Windows创建Linux虚拟环境-WSL

使用工具WSL 官方安装使用文档 安装 WSL | Microsoft Learn 开始通过 WSL 使用 VS Code | Microsoft Learn 具体过程 1. cmd以“管理员身份运行”&#xff0c;执行以下指令&#xff0c;安装完成后&#xff0c;电脑重启&#xff0c;安装完成生效。 wsl --install 2. 查看…

离散化算法

简介 预先空间中的有效个体映射到有限空间中去&#xff0c;以此提高算法的时空效率 离散化是一种将数组的值域压缩&#xff0c;从而更加关注元素的大小关系的算法 一些依靠下标实现的算法和数据结构无法实现时&#xff0c;我们就需要离散化 例如原数组的范围是{1&#xff0…

unity学习(66)——控制器Joystick Pack优化

Joystick Pack这种重力带惯性不利于正常开发。决定进行优化。有一种万事俱备只欠东风的感觉。 源代码如下&#xff1a; 1.在脚本中找到轮盘所输出的方向值 2.把方向的改变值加到鸣人模型身上。 2.1控制器脚本中添加model变量 2.2在unity中赋值 2.3代码中修改位置 using Syst…

windows docker

写在前面的废话 最近在学习riscv的软件相关内容&#xff0c;倒是有别人的sg2042机器可以通过ssh使用&#xff0c;但是用起来太不方便了&#xff0c;经常断掉&#xff0c;所以想着在自己的机器上跑一跑riscv的操作系统。最常见的有两种方法吧&#xff0c;第一个就是qemu&#xf…

深入解析stressapptest源码的OsLayer:操作系统相关的抽象接口详解

深入解析stressapptest的OsLayer&#xff1a;操作系统相关的抽象接口详解 一、类概述二、类属性三、主要方法四、功能架构4.1、Initialize()接口4.2、VirtualToPhysical()函数4.3、FlushPageCache(void)函数4.4、FastFlush()函数4.5、FindDimm(uint64, char *, int)函数4.6、Fi…

k8s为什么删除了pod但是还是没删除掉的问题,deployment在影响

deployment 影响pod删除 一、问题所在二、解决问题 一、问题所在 执行&#xff1a;kubectl get pods --all-namespaces&#xff0c;获取dashboard相关的pod kubectl get pods --all-namespaces | grep dashboardkubectl delete pod dashboard-metrics-scraper-546d6779cb-4x6…

AI换脸软件facefusion2.4.1汉化版整合包分享及使用教程

FaceFusion2.4.1版本软件功能:图片换脸&#xff0c;视频换脸&#xff0c;此版本侧脸效果大幅度优化提高无需配置任何环境&#xff0c;解压即用&#xff0c;本地版本&#xff0c;无需联网也可使用&#xff0c;一次下载&#xff0c;永久免费使用效果演示&#xff1a;https://www.…