深度学习优化器【学习率调整和梯度修正,Optimizer】

news2024/11/6 19:15:53

文章目录

  • 一、学习率调整
    • 1 余弦退火
      • (1)Warm up
      • (2)Cosine Anneal
    • 2 AdaGrad
    • 3 RMSprop算法
    • 4 AdaDelta算法
  • 二、梯度估计修正
    • 1 动量法
    • 2 Nesterov加速梯度
    • 3 Adam
      • 修正的原因
    • 4 AdamW
  • 三、总结
  • 参考资料


在当今快速发展的人工智能领域,优化算法在深度学习模型(比如语言大模型)的训练过程中尤为重要。本文主要介绍与随机梯度下降法相关的两个技巧——学习率调整和梯度修正方法

本文主要基于1,将介绍各种学习率策略,如余弦退火和自适应学习率算法(如 AdaGrad、RMSprop、AdaDelta),这些策略旨在加速收敛和提高训练稳定性。此外,还介绍了梯度估计修正技术,如动量法和 Nesterov 加速梯度,它们通过减少梯度的随机性来提高训练效率。特别地,我们分析了 Adam 和 AdamW 算法,展示了如何通过解耦权重衰减来增强模型的正则化能力。

一、学习率调整

学习率是神经网络优化时的重要超参数.在梯度下降法中,参数的更新规则为:
θ t = θ t − 1 − α ⋅ g t \theta_t = \theta_{t-1}-\alpha\cdot g_t θt=θt1αgt
其中 θ t \theta_t θt为第 t t t次迭代的参数, g t g_t gt是第 t t t次迭代的梯度, α \alpha α为学习率。学习率𝛼的取值非常关键,如果过大就不会收敛,如果过小则收敛速度太慢.

常用的学习率调整方法包括学习率衰减、学习率预热、周期性学习率调整以及一些自适应调整学习率的方法,比如 AdaGrad、RMSprop、AdaDelta 等1.

1 余弦退火

从经验上看,学习率在一开始要保持大些来保证收敛速度,在收敛到最优点附近时要小些以避免来回振荡.下面介绍一个常用的学习率调整方法:warm up + Cosine Anneal.

(1)Warm up

由于一开始参数不稳定, 梯度较大, 如果此时学习率设置过大可能导致数值不稳定。为了提高训练稳定性,我们可以在最初几轮迭代时,采用比较小的学习率,等梯度下降到一定程度后再恢复到初始的学习率,这种方法称为学习率预热(Learning Rate Warmup).使用warm up有助于减缓模型在初始阶段对mini-batch 的提前过拟合现象, 保持分布的平稳, 其次也有助于保持模型深层的稳定性。

(2)Cosine Anneal

梯度下降算法使得loss值接近全局最小值, 学习率应当变得更小, 才能够使其更加容易实现。余弦退火首先使得学习率先缓慢下降, 然后再快速下降, 可以满足上面的需求。公式如下:

α t = α min ⁡ + 1 2 ( α max ⁡ − α min ⁡ ) ( 1 + cos ⁡ ( T cur  T max ⁡ π ) ) \alpha_t=\alpha_{\min }+\frac{1}{2}\left(\alpha_{\max }-\alpha_{\min }\right)\left(1+\cos \left(\frac{T_{\text {cur }}}{T_{\max }} \pi\right)\right) αt=αmin+21(αmaxαmin)(1+cos(TmaxTcur π))

其中, α max ⁡ \alpha_{\max} αmax 为学习率最大值, α min ⁡ \alpha_{\min} αmin 为最小值, T c u r T_{c u r} Tcur 为当前轮次, T m a x T_{ m a x} Tmax 为训练最大迭代步。

Warm up + Cosine Anneal两阶段结合起来的学习率变化如下图所示:

image-20241014150449651

2 AdaGrad

在标准的梯度下降法中,每个参数在每次迭代时都使用相同的学习率.由于每个参数的维度上收敛速度都不相同,因此有必要根据不同参数的收敛情况分别设置学习率.

AdaGrad 算法( Adaptive Gradient Algorithm )[Duchi et al., 2011]是借鉴 ℓ 2 \ell_2 2正则化的思想,每次迭代时自适应地调整每个参数的学习率. 在第 t t t 次迭代时, 先计算每个参数梯度平方的累计值

G t = ∑ τ = 1 t g τ ⊙ g τ , G_t=\sum_{\tau=1}^tg_\tau\odot g_\tau, Gt=τ=1tgτgτ,
其中 ⊙ \odot 为按元素乘积, g τ ∈ R ∣ θ ∣ \mathbf{g}_\tau\in\mathbb{R}^{|\theta|} gτRθ是第 τ \tau τ次迭代时的梯度, G t ∈ R ∣ θ ∣ G_t\in\mathbb{R}^{|\theta|} GtRθ。AdaGrad 算法的参数更新差值为
Δ θ t = − α G t + ε ⊙ g t , \Delta\theta_t=-\frac\alpha{\sqrt{G_t+\varepsilon}}\odot\mathbf{g}_t, Δθt=Gt+ε αgt,
其中

  • α \alpha α 是初始的学习率, ε \varepsilon ε是为了保持数值稳定性而设置的非常小的常数,一般取值 e − 7 \mathrm{e}^{-7} e7 e − 10 \mathrm{e}^{-10} e10.
  • 此外,这里的开平方、除、加运算都是按元素进行的操作
  • 在 AdaGrad 算法中,如果某个参数的偏导数累积比较大,其学习率相对较小; 相反,如果其偏导数累积较小,其学习率相对较大,但整体是随着迭代次数的增加,学习率逐渐缩小.

AdaGrad 算法的缺点是在经过一定次数的迭代依然没有找到最优点时,由于这时的学习率已经非常小,很难再继续找到最优点.

3 RMSprop算法

RMSprop 算法是 Geoff Hinton 提出的一种自适应学习率的方法, 可以在有些情况下避免 AdaGrad 算法中学习率不断单调下降以至于过早衰减的缺点.

RMSprop 算法首先计算每次迭代梯度 g t \mathbf{g}_t gt平方的指数加权移动平均
G t = β G t − 1 + ( 1 − β ) g t ⊙ g t = ( 1 − β ) ∑ τ = 1 t β t − τ g τ ⊙ g τ , \begin{aligned}G_{t}&=\beta G_{t-1}+(1-\beta)\mathbf{g}_t\odot\mathbf{g}_t\\&=(1-\beta)\sum_{\tau=1}^t\beta^{t-\tau}\mathbf{g}_\tau\odot\mathbf{g}_\tau,\end{aligned} Gt=βGt1+(1β)gtgt=(1β)τ=1tβtτgτgτ,
其中 β \beta β 为衰减率,一般取值为0.9.RMSprop 算法的参数更新差值为

Δ θ t = − α G t + ε ⊙ g t , \Delta\theta_t=-\frac\alpha{\sqrt{G_t+\varepsilon}}\odot\mathbf{g}_t, Δθt=Gt+ε αgt,
其中 α \alpha α是初始的学习率,比如0.001.从上式可以看出,RMSProp 算法和 AdaGrad 算法的区别在于 G t G_t Gt 的计算由累积方式变成了指数加权移动平均.在迭代过程中,每个参数的学习率并不是呈衰减趋势,既可以变小也可以变大。

4 AdaDelta算法

AdaDelta 算法 也是 AdaGrad 算法的一个改进. 和 RMSprop算法类似,AdaDelta 算法通过梯度平方的指数衰减移动平均来调整学习率. 此外, AdaDelta算法还引入了每次参数更新差值 Δ θ \Delta \theta Δθ 的平方的指数衰減权移动平均.

t t t 次迭代时, 参数更新差值 Δ θ \Delta \theta Δθ 的平方的指数衰减权移动平均为

Δ X t − 1 2 = β 1 Δ X t − 2 2 + ( 1 − β 1 ) Δ θ t − 1 ⊙ Δ θ t − 1 \Delta X_{t-1}^2=\beta_1 \Delta X_{t-2}^2+\left(1-\beta_1\right) \Delta \theta_{t-1} \odot \Delta \theta_{t-1} ΔXt12=β1ΔXt22+(1β1)Δθt1Δθt1

其中 β 1 \beta_1 β1 为衰减率. 此时 Δ θ t \Delta \theta_t Δθt 还未知, 因此只能计算到 Δ X t − 1 \Delta X_{t-1} ΔXt1.AdaDelta算法的参数更新差值为

Δ θ t = − Δ X t − 1 2 + ε G t + ε g t \Delta \theta_t=-\frac{\sqrt{\Delta X_{t-1}^2+\varepsilon}}{\sqrt{G_t+\varepsilon}} g_t Δθt=Gt+ε ΔXt12+ε gt

其中 G t G_t Gt 的计算方式和 RMSprop 算法一样 , Δ X t − 1 2 \Delta X_{t-1}^2 ΔXt12 为参数更新差值 Δ θ \Delta \theta Δθ 的指数衰减权移动平均.

从上式可以看出,AdaDelta 算法将 RMSprop 算法中的初始学习率 α \alpha α 改为动态计算的 Δ X t − 1 2 \sqrt{\Delta X_{t-1}^2} ΔXt12 , 在一定程度上平抑了学习率的波动.

二、梯度估计修正

在随机(小批量)梯度下降法中,如果每次选取样本数量比较小,损失会呈现振荡的方式下降.也就是说,随机梯度下降方法中每次迭代的梯度估计和整个训练集上的最优梯度并不一致,具有一定的随机性.

如何缓解梯度的随机性?

  • 增加批量大小.
  • 使用最近一段时间内的平均梯度来代替当前时刻的随机梯度来作为参数更新的方向,从而提高优化速度.

1 动量法

动量( Momentum ) 是模拟物理中的概念. 一个物体的动量指的是该物体在它运动方向上保持运动的趋势,是该物体的质量和速度的乘积.动量法( Momentum Method)是用之前积累动量来替代真正的梯度.每次迭代的梯度可以看作加速度.在第 t t t 次迭代时,计算负梯度的“加权移动平均”作为参数的更新方向,

Δ θ t = ρ Δ θ t − 1 − α g t = − α ∑ τ = 1 t ρ t − τ g τ , \Delta\theta_t=\rho\Delta\theta_{t-1}-\alpha\mathbf{g}_t=-\alpha\sum_{\tau=1}^t\rho^{t-\tau}\mathbf{g}_\tau, Δθt=ρΔθt1αgt=ατ=1tρtτgτ,
其中 ρ \rho ρ 为动量因子,通常设为0.9 , α ,\alpha ,α为学习率(注意这里学习率并没有调整)。这样,每个参数的实际更新差值取决于最近一段时间内梯度的加权平均值. 当某个参数在最近一段时间内的梯度方向不一致时,其真实的参数更新幅度变小;相反,当在最近一段时间内的梯度方向都一致时,其真实的参数更新幅度变大,起到加速作用。

如下图所示,引进 momentum 不仅可以加速梯度下降法的收敛速度,还可以一定程度避免在局部最小值处“收敛”(借助前一次的 Momentum,或许可以“冲”过局部最小值处)。

image-20241028141356995

注意到:

  • 一般而言,在迭代初期,梯度方向都比较一致,动量法会起到加速作用,可以更快地到达最优点.(如上图前三个点所示)
  • 在迭代后期,梯度方向会不一致,在收敛值附近振荡,动量法会起到减速作用,增加稳定性,从某种角度来说,当前梯度叠加上部分的上次梯度,一定程度上可以近似看作二阶梯度。

2 Nesterov加速梯度

Nesterov 加速梯度 (Nesterov Accelerated Gradient, NAG) 是一种对动量法的改进 , 也称为Nesterov 动量法 (Nesterov Momentum ).

在动量法中,实际的参数更新方向 Δ θ t \Delta \theta_t Δθt 为上一步的参数更新方向 Δ θ t − 1 \Delta \theta_{t-1} Δθt1 和当前梯度的反方向 − g t -g_t gt 的叠加. 这样, Δ θ t \Delta \theta_t Δθt 可以被拆分为两步进行, 先根据 Δ θ t − 1 \Delta \theta_{t-1} Δθt1 更新一次得到参数 θ ^ \hat{\theta} θ^, 再用 − g t -g_t gt 进行更新.

θ ^ = θ t − 1 + ρ Δ θ t − 1 θ t = θ ^ − α g t \begin{aligned} \hat{\theta} & =\theta_{t-1}+\rho \Delta \theta_{t-1} \\ \theta_t & =\hat{\theta}-\alpha g_t \end{aligned} θ^θt=θt1+ρΔθt1=θ^αgt

其中梯度 g t g_t gt 为点 θ t − 1 \theta_{t-1} θt1 上的梯度, 因此在第二步更新中有些不太合理. 更合理的更新方向应该为 θ ^ \hat{\theta} θ^ 上的梯度.这样,所以Nesterov Momentum修改后的更新方向为
θ ^ = θ t − 1 + ρ Δ θ t − 1 θ t = θ ^ − α g ( θ ^ ) \begin{aligned} \hat{\theta} & =\theta_{t-1}+\rho \Delta \theta_{t-1} \\ \theta_t & =\hat{\theta}-\alpha {g(\hat{\theta})} \end{aligned} θ^θt=θt1+ρΔθt1=θ^αg(θ^)
合并后更新方向为:
Δ θ t = ρ Δ θ t − 1 − α g t ( θ t − 1 + ρ Δ θ t − 1 ) \Delta \theta_t=\rho \Delta \theta_{t-1}-\alpha g_t\left(\theta_{t-1}+\rho \Delta \theta_{t-1}\right) Δθt=ρΔθt1αgt(θt1+ρΔθt1)

其中 g t ( θ t − 1 + ρ Δ θ t − 1 ) g_t\left(\theta_{t-1}+\rho \Delta \theta_{t-1}\right) gt(θt1+ρΔθt1) 表示损失函数在 θ ^ = θ t − 1 + ρ Δ θ t − 1 \hat{\theta}=\theta_{t-1}+\rho \Delta \theta_{t-1} θ^=θt1+ρΔθt1 上的偏导数.

下图给出了动量法和Nesterov加速梯度在参数更新时的比较,红色虚线是主要区别。

截屏2024-10-28 14.30.021

3 Adam

Adam 算法 (Adaptive Moment Estimation Algorithm ) 2可以看作动量法和 RMSprop 算法的结合. 不但使用动量作为参数更新方向, 而且可以自适应调整学习率。

Adam 算法一方面计算梯度平方 g t 2 \mathbf{g}_t^2 gt2 的指数加权平均(和 RMSprop 算法类似), 另一方面计算梯度 g t \mathrm{g}_t gt 的指数加权平均 (和动量法类似).

M t = β 1 M t − 1 + ( 1 − β 1 ) g t , ( 一阶矩估计 ) G t = β 2 G t − 1 + ( 1 − β 2 ) g t ⊙ g t , ( 二阶矩估计 ) \begin{aligned} M_t&=\beta_1 M_{t-1}+\left(1-\beta_1\right) g_t, &(\text{一阶矩估计})\\ G_t&=\beta_2 G_{t-1}+\left(1-\beta_2\right) g_t \odot g_t,&(\text{二阶矩估计})\\ \end{aligned} MtGt=β1Mt1+(1β1)gt,=β2Gt1+(1β2)gtgt,(一阶矩估计)(二阶矩估计)

其中 β 1 \beta_1 β1 β 2 \beta_2 β2 分别为两个移动平均的衰減率, 通常取值为 β 1 = 0.9 , β 2 = 0.99 \beta_1=0.9, \beta_2=0.99 β1=0.9,β2=0.99. 我们可以把 M t M_t Mt G t G_t Gt 分别看作梯度的均值(一阶矩)和未减去均值的方差(二阶矩).

假设 M 0 = 0 , G 0 = 0 M_0=0, G_0=0 M0=0,G0=0 ,那么在迭代初期 M t M_t Mt G t G_t Gt 的值会比真实的均值和方差要小, 特别是当 β 1 \beta_1 β1 β 2 \beta_2 β2 都接近于 1 时, 偏差会很大. 因此, 需要对偏差进行修正.

M ^ t = M t 1 − β 1 t ( 偏差修正 ) G ^ t = G t 1 − β 2 t ( 偏差修正 ) \begin{aligned} \hat{M}_t & =\frac{M_t}{1-\beta_1^t} &(\text{偏差修正})\\ \hat{G}_t & =\frac{G_t}{1-\beta_2^t} &(\text{偏差修正})\\ \end{aligned} M^tG^t=1β1tMt=1β2tGt(偏差修正)(偏差修正)

Adam算法的参数更新差值为

θ t = θ t − 1 − α G ^ t + ϵ M ^ t ( 参数更新 ) \theta_t=\theta_{t-1}-\frac{\alpha}{\sqrt{\hat{G}_t+\epsilon}} \hat{M}_t \quad(\text{参数更新})\\ θt=θt1G^t+ϵ αM^t(参数更新)

其中学习率 α \alpha α 通常设为 0.001 , 并且也可以进行衰減, 比如采用余弦退火.

修正的原因

在 Adam 算法中,初期的估计值偏小是因为 指数加权平均 的计算方式依赖于前面的梯度信息,而在初始阶段,梯度的历史数据很少,因此计算出的平均值往往低于实际值。我们可以用一个具体的例子来说明这个偏差为什么会发生。

假设我们有一个优化过程,在第一个时间步 t = 1 t = 1 t=1,我们记录到的梯度值为 g 1 g_1 g1。我们使用 Adam 的一阶矩的指数加权平均来计算梯度的平均值。

Adam 中一阶矩的指数加权平均的公式为:

M t = β 1 M t − 1 + ( 1 − β 1 ) g t M_t = \beta_1 M_{t-1} + (1 - \beta_1) g_t Mt=β1Mt1+(1β1)gt

  • 假设 β 1 = 0.9 \beta_1 = 0.9 β1=0.9
  • 初始时刻 M 0 = 0 M_0 = 0 M0=0,即指数加权平均的初值为 0。

在第一个时间步 t = 1 t = 1 t=1

M 1 = β 1 M 0 + ( 1 − β 1 ) g 1 M 1 = 0.9 × 0 + ( 1 − 0.9 ) × g 1 M 1 = 0.1 × g 1 \begin{aligned} M_1 &= \beta_1 M_0 + (1 - \beta_1) g_1\\ M_1 &= 0.9 \times 0 + (1 - 0.9) \times g_1\\ M_1 &= 0.1 \times g_1 \end{aligned} M1M1M1=β1M0+(1β1)g1=0.9×0+(10.9)×g1=0.1×g1
由于 M 0 = 0 M_0 = 0 M0=0,所以 M 1 M_1 M1 的值只包含了当前梯度值的 10%。这明显比实际的 g 1 g_1 g1 要小很多,若 β 1 \beta_1 β1约接近于0,那么偏差就越大。

同理可知 G t G_t Gt也是如此,所以两者都需要引入一个修正项。

4 AdamW

AdamW是一个在深度学习中广泛应用的优化器,它是经典Adam优化器的一个变体,专门为了解决Adam在权重衰减(Weight Decay)方面的问题而提出。AdamW最早在论文《Decoupled Weight Decay Regularization》中提出3,它结合了Adam的自适应学习率和L2正则化的优势, 解决了Adam中错误使用权重衰减的问题。

在深度学习中,权重衰减(weight decay) 是一种常用的正则化技术,它通过在每次更新参数时引入一个额外的项来控制权重的增长,从而防止过拟合。在经典的梯度下降方法中,权重衰减的实现非常简单:

θ = θ − η ( ∇ L ( θ ) + λ θ ) \theta=\theta-\eta(\nabla L(\theta)+\lambda \theta) θ=θη(L(θ)+λθ)

其中, λ θ \lambda \theta λθ 是权重衰减项(L2正则化项)。这种方法能够有效防止模型参数过拟合。在原始的 Adam 算法中,如果使用了权重衰减(也就是 L2 正则化),它是将正则化项添加到梯度上,即损失函数对参数的梯度 g t g_t gt被修改为:
g t = ∇ L ( θ t ) + λ θ t g_t = \nabla L(\theta_t)+\lambda \theta_t gt=L(θt)+λθt
L2正则化和Adam的动量更新机制耦合在了一起,导致了不理想的正则化效果。AdamW通过将权重衰减与梯度更新解耦, 解决了Adam在权重衰减方面的缺陷。 它将权重衰减独立处理, 而不再作为Adam优化器更新的一部分。这使得模型在参数更新时可以保持更高的稳定性,并且防止过拟合。

AdamW的参数更新公式如下:

  1. 动量和二阶矩的计算(与Adam相同):

M t = β 1 M t − 1 + ( 1 − β 1 ) g t , ( 一阶矩估计 ) G t = β 2 G t − 1 + ( 1 − β 2 ) g t ⊙ g t , ( 二阶矩估计 ) \begin{aligned} M_t&=\beta_1 M_{t-1}+\left(1-\beta_1\right) g_t, &(\text{一阶矩估计})\\ G_t&=\beta_2 G_{t-1}+\left(1-\beta_2\right) g_t \odot g_t,&(\text{二阶矩估计})\\ \end{aligned} MtGt=β1Mt1+(1β1)gt,=β2Gt1+(1β2)gtgt,(一阶矩估计)(二阶矩估计)
2. 偏差修正:
M ^ t = M t 1 − β 1 t ( 偏差修正 ) G ^ t = G t 1 − β 2 t ( 偏差修正 ) \begin{aligned} \hat{M}_t & =\frac{M_t}{1-\beta_1^t} &(\text{偏差修正})\\ \hat{G}_t & =\frac{G_t}{1-\beta_2^t} &(\text{偏差修正})\\ \end{aligned} M^tG^t=1β1tMt=1β2tGt(偏差修正)(偏差修正)
3. 参数更新:

θ t = θ t − 1 − α ( M ^ t G ^ t + ϵ + λ θ t − 1 ) \theta_t=\theta_{t-1}-\alpha\left(\frac{\hat{M}_t}{\sqrt{\hat{G}_t}+\epsilon}+\lambda \theta_{t-1}\right) θt=θt1α(G^t +ϵM^t+λθt1)

其中:

  • M ^ t G t + ϵ \frac{\hat{M}_t}{\sqrt{G_t}+\epsilon} Gt +ϵM^t 是Adam的梯度更新部分。
  • λ θ t − 1 \lambda \theta_{t-1} λθt1 是独立的权重衰减项,与梯度更新无关。

通过这种方式, AdamW能够更好地控制权重衰减, 防止模型过拟合,而不影响优化器的动量和自适应学习率更新。相比于传统的Adam,AdamW 具有以下优势4

  • 更准确的权重衰减: AdamW将权重衰减与梯度更新解耦,避免了Adam优化器中的错误正则化处理。这样可以有效防止模型的参数过度增长,并提高泛化能力。
  • 更好的正则化效果: 由于权重衰减项是独立处理的,AdamW能够更有效地施加L2正则化,尤其在大模型(如LLaMA等)训练中表现更为稳定。
  • 提高模型的泛化能力: 通过更好的权重控制,AdamW能够在不影响优化过程的前提下提升模型在测试集上的表现,减少过拟合问题。

三、总结

本节介绍的几种优化方法大体上可以分为两类:

  1. 调整学习率,使得优化更稳定;
  2. 梯度估计修正,优化训练速度.

这些优化算法可以使用下面公式来统一描述概括:
Δ θ t = − α t G t + ϵ M t \Delta\theta_t = -\frac{\alpha_t}{\sqrt{G_t+\epsilon}}M_t Δθt=Gt+ϵ αtMt
其中 G t , M t G_t,M_t Gt,Mt都是梯度 g 1 , g 2 , ⋯   , g t g_1,g_2,\cdots,g_t g1,g2,,gt的函数,不同算法的 G t , M t G_t,M_t Gt,Mt取法总结如下表所示:

截屏2024-10-28 15.40.57

参考资料


  1. 邱锡鹏,神经网络与深度学习,机械工业出版社,https://nndl.github.io/, 2020. ↩︎ ↩︎ ↩︎

  2. Kingma, Diederik P., and Jimmy Ba. "Adam: A method for stochastic optimization."arXiv preprint arXiv:1412.6980(2014). ↩︎

  3. Loshchilov, Ilya, and Frank Hutter. "Decoupled weight decay regularization."arXiv preprint arXiv:1711.05101(2017). ↩︎

  4. AdamW和Adam优化器对比分析 ↩︎

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在米尔电子MPSOC实现12G SDI视频采集H.265压缩SGMII万兆以太网推流

1. 引言 随着网络视频平台的发展,用户对于4K高清画质的需求日益增长。然而,许多用户发现,即使购买了视频平台的会员,观看4K内容时画质却不如预期,有时甚至还会出现模糊、卡顿的情况。这种现象背后涉及到视频编码、网络…

项目复盘:TapTap聚光灯Gamejam

前言 三周的开发终于落下帷幕,其实我个人还是对结果很满意的,虽然作品不及他人的万分之一,不过主要目的还是以熟悉Godot引擎本身为主。这次我做的事情其实主要还是把在Unity那边学到的东西Copy到Godot来,仅此而已,几乎…

WPF自定义日历控件Calendar 的方法

推荐下载地址 https://www.haolizi.net/example/view_2107.html <UserControl.Resources><local1:DayConverter x:Key"DayConverter"/><!--导入转换器--><Style x:Key"CalendarStyle1"TargetType"{x:Type Calendar}">&…

《ToDesk云电脑vs青椒云性能测试,谁更能实现游戏自由?》

ToDesk云电脑vs青椒云性能测试 【前言】【使用云电脑的意义】【实测软件】【性能参数对比】1. 硬件配置2.游戏兼容性3. 延迟、流畅度与画面清晰度4. 用户体验5. 价格对比6. 附加功能 【游戏性能测试】《游戏一 黑悟空》《游戏二 赛博朋克 2077》《游戏三 CS反恐精英》 【本文小…

ctfshow文件包含web78~81

目录 web78 方法一&#xff1a;filter伪协议 方法二&#xff1a;input协议 方法三&#xff1a;data协议 web79 方法一:input协议 方法二&#xff1a;data协议 web80 方法一&#xff1a;input协议 方法二&#xff1a;日志包含getshell web81 web78 if(isset($_GET[file]…

动态IP是什么?

随着互联网成为人们生活的重要组成部分&#xff0c;以信息传递为主导的时代种&#xff0c;网络连接质量对我们的工作效率、学习进度以及娱乐体验等方面都有很大影响。 动态IP&#xff0c;作为网络连接中的一种重要IP代理形式&#xff0c;越来越受到用户的欢迎。本文将深入解析…

vue下载安装

目录 vue工具前置要求&#xff1a;安装node.js并配置好国内镜像源下载安装 vue 工具 系统&#xff1a;Windows 11 前置要求&#xff1a;安装node.js并配置好国内镜像源 参考&#xff1a;本人写的《node.js下载、安装、设置国内镜像源&#xff08;永久&#xff09;&#xff…

在JAVA中使用Paho MQTT客户端

1.在maven里面配置好依赖 <dependency><groupId>org.eclipse.paho</groupId><artifactId>org.eclipse.paho.client.mqttv3</artifactId><version>1.2.2</version> </dependency> 2.创建APP类 package com.leo;import org.e…

Django+websocket实现一个简单聊天

WebSocket是一种在单个TCP连接上进行全双工通信的协议。它由IETF在2011年定为标准RFC 6455&#xff0c;并由RFC7936补充规范&#xff0c;同时WebSocket API也被W3C定为标准。 1、定义与原理 WebSocket是独立的、创建在TCP上的协议&#xff0c;它使用HTTP/1.1协议的101状态码进…

MATLAB实现人类学习优化算法HLO

1.算法简介 人类学习优化算法&#xff08;Human Learning-based Optimization&#xff0c;HLO&#xff09;是一种基于人类学习过程开发的启发式算法。HLO算法的设计灵感来源于人类的智慧和经验&#xff0c;特别是人类在学习和调整过程中展现出的适应性、学习能力和创新思维。该…

【果蔬识别】Python+卷积神经网络算法+深度学习+人工智能+机器学习+TensorFlow+计算机课设项目+算法模型

一、介绍 果蔬识别系统&#xff0c;本系统使用Python作为主要开发语言&#xff0c;通过收集了12种常见的水果和蔬菜&#xff08;‘土豆’, ‘圣女果’, ‘大白菜’, ‘大葱’, ‘梨’, ‘胡萝卜’, ‘芒果’, ‘苹果’, ‘西红柿’, ‘韭菜’, ‘香蕉’, ‘黄瓜’&#xff09;…

Android 策略设计模式的使用:使用设计模式,减少烂代码,让项目更好维护

目录 大家好呀~&#xff0c;我是前期后期&#xff0c;在网上冲浪的一名程序员&#xff0c;分享一些自己学到的知识&#xff0c;希望对大家有所帮助 前言&#xff1a;为什么要使用设计模式 在项目开发过程中&#xff0c;我们会对接很多种支付&#xff1a;国内&#xff08;微信…

uniapp和vite项目配置多环境编译,增加测试环境变量配置--mode test

如果你的项目是使用vite和uniapp配置开发的&#xff0c;就可以在代码里面获取到这些变量&#xff0c;但是开发&#xff0c;测试和发布是不同的请求地址&#xff0c;所以需要配置。Vite 使用 dotenv 从你的 环境目录 中的下列文件加载额外的环境变量&#xff1a; .env …

动态规划 - 编辑距离

115. 不同的子序列 困难 给你两个字符串 s 和 t &#xff0c;统计并返回在 s 的 子序列 中 t 出现的个数&#xff0c;结果需要对 10^9 7 取模。 算法思想&#xff1a;利用动态规划&#xff0c;分s[i - 1] 与 t[j - 1]相等&#xff0c;s[i - 1] 与 t[j - 1] 不相等两种情况具…

sudo apt install jupyter-notebook安装notebook失败E: Aborting install.

问题&#xff1a; sudo apt install jupyter-notebook安装notebook失败E: Aborting install. ~/jie/mywork/PointNetCFD$ sudo apt install jupyter-notebook --fix-missing Reading package lists... Done Building dependency tree Reading state information... Do…

第16课 核心函数(方法)

掌握常用的内置函数及其用法。 数学类函数&#xff1a;abs、divmod、max、min、pow、round、sum。 类型转换函数&#xff1a;bool、int、float、str、ord、chr、bin、hex、tuple、list、dict、set、enumerate、range、object。 序列操作函数&#xff1a;all、any、filter、m…

【1个月速成Java】基于Android平台开发个人记账app学习日记——第2天,启动项目

24.11.01 下面讲一下如何通过USB连接手机然后启动app实现真机测试&#xff0c;还是有一些坑的。 调整电脑的驱动程序&#xff0c;完成USB的连接 在启动项目的第一步我就遇见了问题&#xff0c;那就是插入usb线以后没有检测到设备。想要完成连接需要2个步骤&#xff0c;第一步…

使用Mac如何才能提高OCR与翻译的效率

OCR与截图大家都不陌生&#xff0c;或许有的朋友对于这两项功能用到的不多&#xff0c;但是如果经常会用到的话&#xff0c;那你就该看看了 iOCR&#xff0c;快捷键唤出翻译窗口&#xff0c;不论是截图翻译、划词翻译、输入翻译、剪切板翻译&#xff0c;统统快捷键完成&#x…

Etsy又被封号了!这次我终于搞懂了原因...

你是否真的了解在Etsy开店有哪些红线不能踩&#xff1f;你是否真的知道Etsy被封号后如何解决&#xff1f;本文我将探讨Etsy账号被封的常见原因&#xff0c;以及卖家可以采取的应对策略&#xff0c;以期减轻对跨境业务的伤害程度&#xff0c;感兴趣的商家速速码住&#xff0c;不…

MySQL — 事务 (o゚▽゚)o

文本目录&#xff1a; ❄️一、什么是事务&#xff1a; ❄️二、ACID特性&#xff1a; ❄️三、使用事务&#xff1a; ▶1、查看支持事务的存储引擎&#xff1a; ▶2、语法&#xff1a; ▶3、开启并且回滚&#xff1a; ▶4、开启并且提交&#xff1a; ▶ 5、保存点&#xff…