BPTT算法详解:深入探究循环神经网络(RNN)中的梯度计算【原理理解】

引言

在深度学习领域中,我们经常处理的是独立同分布(i.i.d)的数据,比如图像分类、文本生成等任务,其中每个样本之间相互独立。然而,在现实生活中,许多数据具有时序结构,例如语言模型中的单词序列、股票价格随时间的变化、视频中的帧等。对于这类具有时序关系的数据,传统的深度学习模型可能无法很好地捕捉到其内在的 时间相关性 。为了解决这一问题,循环神经网络(Recurrent Neural Network, RNN)被广泛应用于处理时序数据。

为什么说反向传播算法不能处理时序数据呢?
在传统的反向传播算法中,处理静态数据时,网络的输出 y ^ \hat{y} y^ 通常只依赖于当前时刻的隐藏状态 h h h,其更新规则可以表示为:
h = W x + b h = Wx + b h=Wx+b
y ^ = V h + c \hat{y} = Vh + c y^=Vh+c
其中, h h h 是隐藏状态, x x x 是输入, W W W V V V 是网络的参数, b b b c c c 是偏置项。

与传统反向传播算法不同,BPTT(Back-Propagation Through Time)算法引入了时间维度,并考虑了序列数据中的时序关系。在 BPTT 中,隐藏状态 h t h_t ht 的更新规则包含了当前时刻的输入 X t X_t Xt 和上一个时刻的隐藏状态 h t − 1 h_{t-1} ht1,从而能够更好地捕捉到序列数据中的时间相关性。
h t = f ( U X t + W h t − 1 ) h_t = f(UX_t + Wh_{t-1}) ht=f(UXt+Wht1)
y t ^ = f ( V h t ) \hat{y_t} = f(Vh_t) yt^=f(Vht)

RNN 结构与BPTT

首先,让我们来了解一下常见的循环神经网络结构。在 RNN 中,隐藏状态会随着时间步的推移而更新,并在每个时间步生成一个输出。这种结构允许网络捕捉到序列数据中的时间相关性,使得其在时序任务中表现出色。

一个常见的RNN结构如下所示:
RNN结构
在RNN中,参数U、V和W是共享的,这意味着它们在每个时间步都保持不变。这意味着它们的值在整个模型运行过程中 始终保持一致

BPTT算法概述

前向传播

在 RNN 中,前向传播阶段通过计算隐藏状态和输出来生成预测结果。

h t = f ( U X t + W h t − 1 ) h_t = f(UX_t + Wh_{t-1}) ht=f(UXt+Wht1)

y t ^ = f ( V h t ) \hat{y_t} = f(Vh_t) yt^=f(Vht)

损失函数

这些结果与真实标签之间的差异通过损失函数来衡量,我们的目标是最小化这个损失函数。整个网络的损失值 L L L是每个时刻损失值 L t L_t Lt的求和,其中 L t L_t Lt是关于预测值 y t ^ \hat{y_t} yt^的函数。

L t = f ( y t ^ ) L_t = f(\hat{y_t}) Lt=f(yt^)
L = ∑ i = 1 T L t L = \sum_{i=1}^{T} L_t L=i=1TLt

损失函数 L L L 可以表示为:

  1. 均方误差(MSE):
    L = ∑ t = 1 T 1 2 ( y t − y ^ t ) 2 L = \sum_{t=1}^T \frac{1}{2} (y_t - \hat{y}_t)^2 L=t=1T21(yty^t)2
    这里,我们计算每个时间步的输出 y t y_t yt 与真实输出 y ^ t \hat{y}_t y^t 之间的平方误差,并将所有时间步的误差求和。
  2. 交叉熵损失:
    L = − ∑ t = 1 T [ y ^ t log ⁡ ( y t ) + ( 1 − y ^ t ) log ⁡ ( 1 − y t ) ] L = -\sum_{t=1}^T [\hat{y}_t \log(y_t) + (1 - \hat{y}_t) \log(1 - y_t)] L=t=1T[y^tlog(yt)+(1y^t)log(1yt)]
    这里,我们计算每个时间步的输出 y t y_t yt 与真实输出 y ^ t \hat{y}_t y^t 之间的交叉熵损失,并将所有时间步的损失求和。

反向传播

接下来,我们使用BPTT算法(随时间反向传播,Back-Propagation Through Time,BPTT)进行反向传播。在这一步中,我们计算损失函数对参数U、V和W的偏导数,以便更新参数以最小化损失。

为什么要使用整个序列的损失函数L对参数U、V和W求导呢?

这是因为我们的目标是最小化整个序列的损失。在梯度下降算法中,梯度指向了损失函数增长最快的方向。因此,通过对整个序列的损失函数求导,我们可以找到在参数空间中使得损失函数逐步减小的方向,然后通过反向传播来更新参数。

由于RNN处理的是时序数据,因此需要基于时间进行反向传播,这也是BPTT名称的由来。尽管BPTT是在时序数据上进行反向传播,但本质上它仍然是反向传播算法,因此求解每个时间步的梯度是该算法的核心操作。

梯度计算

我们以一个长度为3的时间序列为例,展示对于参数U、V和W的偏导数的计算过程。

长度为3的时间序列
首先看看前向传播的计算

隐藏层输出:
h t = f ( U X t + W h t − 1 ) h_t = f(UX_t + Wh_{t-1}) ht=f(UXt+Wht1)

为什么“RNN的隐藏状态更新规则是 h t = f ( U X t + W h t − 1 ) h_t = f(UX_t + Wh_{t-1}) ht=f(UXt+Wht1)”?

从数学角度来看,这个更新规则是由RNN的结构决定的。在RNN中,隐藏状态
h t h_t ht

  • 由当前时间步的输入 X t X_t Xt
  • 前一个时间步的隐藏状态 h t − 1 h_{t-1} ht1

组合而成的。通过线性变换 U X t + W h t − 1 UX_t + Wh_{t-1} UXt+Wht1,加上激活函数 f f f 的作用,得到了新的隐藏状态 h t h_t ht。这个结构使得RNN能够记忆之前的信息并将其应用于当前的预测任务中。

输出层:
y t ^ = f ( V h t ) \hat{y_t} = f(Vh_t) yt^=f(Vht)

  • h t h_t ht 是隐藏状态
  • y t ^ \hat{y_t} yt^ 是输出值
  • X t X_t Xt 输入的序列
  • f f f是激活函数

将上面的RNN用数学表达式来表示就是
{ h 1 = f ( U x 1 + W h 0 ) y ^ 1 = f ( V h 1 ) \left\{\begin{array}{l}h_{1}=f\left(U x_{1}+W h_{0}\right) \\\hat{y}_{1}=f\left(V h_{1}\right)\end{array}\right. {h1=f(Ux1+Wh0)y^1=f(Vh1)
{ h 2 = f ( U x 2 + W h 1 ) y ^ 2 = f ( V h 2 ) \left\{\begin{array}{l}h_{2}=f\left(U x_{2}+W h_{1}\right) \\\hat{y}_{2}=f\left(V h_{2}\right)\end{array}\right. {h2=f(Ux2+Wh1)y^2=f(Vh2)
{ h 3 = f ( U x 3 + W h 2 ) y ^ 3 = f ( V h 1 ) \left\{\begin{array}{l}h_{3}=f\left(U x_{3}+W h_{2}\right) \\\hat{y}_{3}=f\left(V h_{1}\right)\end{array}\right. {h3=f(Ux3+Wh2)y^3=f(Vh1)

针对 t = 3 t=3 t=3时刻,求U,V,W的梯度(偏导),使用链式法则得到:

∂ L 3 ∂ V = ∂ L 3 y ^ 3 × ∂ y ^ 3 ∂ V \frac{\partial L_3}{\partial V} = \frac{\partial L_3}{\hat{y}_{3}} \times \frac{\partial \hat{y}_{3}}{\partial V} VL3=y^3L3×Vy^3

∂ L 3 ∂ W = ∂ L 3 ∂ y ^ 3 × ∂ y ^ 3 ∂ h 3 × ∂ h 3 ∂ W + ∂ L 3 ∂ y ^ 3 × ∂ y ^ 3 ∂ h 3 × ∂ h 3 ∂ h 2 × ∂ h 2 ∂ W + ∂ L 3 ∂ y ^ 3 × ∂ y ^ 3 ∂ h 3 × ∂ h 3 ∂ h 2 × ∂ h 2 ∂ h 1 × ∂ h 1 ∂ W \frac{\partial L_{3}}{\partial W}=\frac{\partial L_{3}}{\partial \hat{y}_{3}} \times \frac{\partial \hat{y}_{3}}{\partial h_{3}} \times \frac{\partial h_{3}}{\partial W}+\frac{\partial L_{3}}{\partial \hat{y}_{3}} \times \frac{\partial \hat{y}_{3}}{\partial h_{3}} \times \frac{\partial h_{3}}{\partial h_{2}} \times \frac{\partial h_{2}}{\partial W}+\frac{\partial L_{3}}{\partial \hat{y}_{3}} \times \frac{\partial \hat{y}_{3}}{\partial h_{3}} \times\frac{\partial h_{3}}{\partial h_{2}} \times \frac{\partial h_{2}}{\partial h_{1}} \times \frac{\partial h_{1}}{\partial W} WL3=y^3L3×h3y^3×Wh3+y^3L3×h3y^3×h2h3×Wh2+y^3L3×h3y^3×h2h3×h1h2×Wh1

∂ L 3 ∂ U = ∂ L 3 ∂ y ^ 3 × ∂ y ^ 3 ∂ h 3 × ∂ h 3 ∂ U + ∂ L 3 ∂ y ^ 3 × ∂ y ^ 3 ∂ h 3 × ∂ h 3 ∂ h 2 × ∂ h 2 ∂ U + ∂ L 3 ∂ y ^ 3 × ∂ y ^ 3 ∂ h 3 × ∂ h 3 ∂ h 2 × ∂ h 2 ∂ h 1 × ∂ h 1 ∂ U \frac{\partial L_{3}}{\partial U}=\frac{\partial L_{3}}{\partial \hat{y}_{3}} \times \frac{\partial \hat{y}_{3}}{\partial h_{3}} \times \frac{\partial h_{3}}{\partial U}+\frac{\partial L_{3}}{\partial \hat{y}_{3}} \times \frac{\partial \hat{y}_{3}}{\partial h_{3}} \times \frac{\partial h_{3}}{\partial h_{2}} \times \frac{\partial h_{2}}{\partial U}+\frac{\partial L_{3}}{\partial \hat{y}_{3}} \times \frac{\partial \hat{y}_{3}}{\partial h_{3}} \times\frac{\partial h_{3}}{\partial h_{2}} \times \frac{\partial h_{2}}{\partial h_{1}} \times \frac{\partial h_{1}}{\partial U} UL3=y^3L3×h3y^3×Uh3+y^3L3×h3y^3×h2h3×Uh2+y^3L3×h3y^3×h2h3×h1h2×Uh1

其实这个时候我们就可以看出,W和U两个参数的需要追溯之前的历史数据,参数V只需关注目前

所以,我们可以根据t3时刻的偏导,来计算任意时刻对U,V,W的偏导

对于V的偏导

对于V的偏导,我们直接将3替换成t即可:
∂ L t ∂ V = ∂ L t y ^ t × ∂ y ^ t ∂ V \frac{\partial L_t}{\partial V} = \frac{\partial L_t}{\hat{y}_{t}} \times \frac{\partial \hat{y}_{t}}{\partial V} VLt=y^tLt×Vy^t

对于W的偏导

对于W的偏导,在 t = 3 t=3 t=3的时刻有三项,那么对应的在T时刻就有T项

∂ L t ∂ W = ∑ k = 1 t ∂ L t ∂ y t ^ × ∂ y t ^ ∂ h t × ∂ h t ∂ h k × ∂ h k W \frac{\partial L_{t}}{\partial W}= \sum_{k=1}^{t} \frac{\partial L_t}{\partial \hat{y_t} } \times \frac{\partial \hat{y_t} }{\partial h_t} \times \frac{\partial h_t}{\partial h_k} \times \frac{\partial h_k}{W} WLt=k=1tyt^Lt×htyt^×hkht×Whk

其中的 ∂ h t ∂ h k \frac{\partial h_t}{\partial h_k} hkht,我们可以进行展开:

例如在 k = 1 k=1 k=1时, ∂ h 3 ∂ h 1 = ∂ h 3 ∂ h 2 × ∂ h 2 ∂ h 1 \frac{\partial h_3}{\partial h_1} = \frac{\partial h_3}{\partial h_2} \times \frac{\partial h_2}{\partial h_1} h1h3=h2h3×h1h2

所以我们推导得到以下式子:
∂ h t ∂ h k = ∂ h t ∂ h k × ∂ h t − 1 ∂ h t − 2 × . . . × ∂ h t − k + 1 ∂ h k \frac{\partial h_t}{\partial h_k} = \frac{\partial h_t}{\partial h_k} \times \frac{\partial h_{t-1}}{\partial h_{t-2}} \times ... \times \frac{\partial h_{t-k+1}}{\partial h_{k}} hkht=hkht×ht2ht1×...×hkhtk+1

也就是等于:
∂ h t ∂ h k = ∏ i = k + 1 t ∂ h i ∂ h i − 1 \frac{\partial h_t}{\partial h_k} = \prod_{i = k+1}^{t} \frac{\partial h_i}{\partial h_{i-1}} hkht=i=k+1thi1hi

所以,
∂ L t ∂ W = ∑ k = 1 t ∂ L t ∂ y t ^ × ∂ y t ^ ∂ h t × ( ∏ i = k + 1 t ∂ h i ∂ h i − 1 ) × ∂ h k W \frac{\partial L_{t}}{\partial W}= \sum_{k=1}^{t} \frac{\partial L_t}{\partial \hat{y_t} } \times \frac{\partial \hat{y_t} }{\partial h_t} \times (\prod_{i = k+1}^{t} \frac{\partial h_i}{\partial h_{i-1}} ) \times \frac{\partial h_k}{W} WLt=k=1tyt^Lt×htyt^×(i=k+1thi1hi)×Whk

对于U的偏导

同样的,我们也可以得到对于U的偏导

∂ L t ∂ U = ∑ k = 1 t ∂ L t ∂ y t ^ × ∂ y t ^ ∂ h t × ( ∏ i = k + 1 t ∂ h i ∂ h i − 1 ) × ∂ h k U \frac{\partial L_{t}}{\partial U}= \sum_{k=1}^{t} \frac{\partial L_t}{\partial \hat{y_t} } \times \frac{\partial \hat{y_t} }{\partial h_t} \times (\prod_{i = k+1}^{t} \frac{\partial h_i}{\partial h_{i-1}} ) \times \frac{\partial h_k}{U} ULt=k=1tyt^Lt×htyt^×(i=k+1thi1hi)×Uhk

为什么U也是这样的链式求导?
h t = f ( U X t + W h t − 1 ) h_t = f(UX_t + Wh_{t-1}) ht=f(UXt+Wht1)
U也是通过链式法则求导的,因为隐藏状态 h t h_t ht是由 U U U X t X_t Xt h t − 1 h_{t-1} ht1共同决定的。因此,当我们计算损失函数关于U的偏导数时,需要考虑 h t h_t ht U U U的影响,而 h t h_t ht又依赖于 h t − 1 h_{t-1} ht1,因此需要使用链式法则进行求导。

当前我们得到了是t时刻的导数,现在我们需要推广到整个网络中的损失值对U,V,W的偏导

总的损失值

因为和的导数等于导数,所以我们可以直接将 L = ∑ i = 1 T L t L = \sum_{i=1}^{T} L_t L=i=1TLt前面的求和符号提出来
所以有,
∂ L ∂ W = ∑ i = 1 T ∂ L t ∂ W \frac{\partial L}{\partial W}= \sum_{i=1}^{T} \frac{\partial L_t}{\partial W} WL=i=1TWLt

现在我们只需要将前面求得的t时刻的带入即可,
∂ L ∂ W = ∑ i = 1 T ∑ k = 1 t ∂ L t ∂ y t ^ × ∂ y t ^ ∂ h t × ( ∏ i = k + 1 t ∂ h i ∂ h i − 1 ) × ∂ h k W \frac{\partial L}{\partial W}= \sum_{i=1}^{T}\sum_{k=1}^{t} \frac{\partial L_t}{\partial \hat{y_t} } \times \frac{\partial \hat{y_t} }{\partial h_t} \times (\prod_{i = k+1}^{t} \frac{\partial h_i}{\partial h_{i-1}} ) \times \frac{\partial h_k}{W} WL=i=1Tk=1tyt^Lt×htyt^×(i=k+1thi1hi)×Whk

同样的,对于U,我们得到:
∂ L ∂ U = ∑ i = 1 T ∑ k = 1 t ∂ L t ∂ y t ^ × ∂ y t ^ ∂ h t × ( ∏ i = k + 1 t ∂ h i ∂ h i − 1 ) × ∂ h k U \frac{\partial L}{\partial U}= \sum_{i=1}^{T}\sum_{k=1}^{t} \frac{\partial L_t}{\partial \hat{y_t} } \times \frac{\partial \hat{y_t} }{\partial h_t} \times (\prod_{i = k+1}^{t} \frac{\partial h_i}{\partial h_{i-1}} ) \times \frac{\partial h_k}{U} UL=i=1Tk=1tyt^Lt×htyt^×(i=k+1thi1hi)×Uhk

对于V,我们得到:

∂ L ∂ V = ∑ i = 1 T ∂ L t y ^ t × ∂ y ^ t ∂ V \frac{\partial L}{\partial V}= \sum_{i=1}^{T}\frac{\partial L_t}{\hat{y}_{t}} \times \frac{\partial \hat{y}_{t}}{\partial V} VL=i=1Ty^tLt×Vy^t

梯度爆炸和梯度消失问题

在W和U中,存在一个连乘 ∏ i = k + 1 t ∂ h i ∂ h i − 1 \prod_{i = k+1}^{t} \frac{\partial h_i}{\partial h_{i-1}} i=k+1thi1hi;也就是说,会出现指数级别的问题;

如果 ∂ h i ∂ h i − 1 > 1 \frac{\partial h_i}{\partial h_{i-1}} > 1 hi1hi>1的话,那么连乘的结果可能会快速增长,导致梯度爆炸。
在这里插入图片描述

如果 ∂ h i ∂ h i − 1 < 1 \frac{\partial h_i}{\partial h_{i-1}} < 1 hi1hi<1的话,连乘的结果会迅速衰减到零,导致梯度消失
在这里插入图片描述
我们来求解一下关于 ∂ h i ∂ h i − 1 \frac{\partial h_i}{\partial h_{i-1}} hi1hi数学上的表示:

因为 h t = f ( U X t + W h t − 1 ) h_t = f(UX_t + Wh_{t-1}) ht=f(UXt+Wht1),所以我们可以得到
∂ h i ∂ h i − 1 = f ′ × W \frac{\partial h_i}{\partial h_{i-1}} = f'\times W hi1hi=f×W

因为 f ′ ∈ [ 0 , 0.25 ] f'∈[0,0.25] f[0,0.25](假设为Sigmoid函数),所以说

  • 如果 W < 4 W < 4 W<4,那么连乘很多次后,导致梯度消失
  • 如果 W > 4 W > 4 W>4,那么连乘很多次后,导致梯度爆炸

为什么 f ′ ∈ [ 0 , 0.25 ] f' \in [0, 0.25] f[0,0.25]

f f f 是Sigmoid函数,其导数 f ′ f' f 的取值范围在0到0.25之间。

Sigmoid函数的导数表达式为 f ′ ( x ) = f ( x ) ( 1 − f ( x ) ) f'(x) = f(x)(1-f(x)) f(x)=f(x)(1f(x)),其中 f ( x ) f(x) f(x) 的取值范围在0到1之间。因此, f ′ ( x ) f'(x) f(x) 的最大值为 0.25 0.25 0.25,在 x = 0.5 x = 0.5 x=0.5 时取得。
如图所示
在这里插入图片描述

解决梯度消失和梯度爆炸的方法

为了缓解梯度消失和梯度爆炸问题,可以采用以下几种常见的方法:

  1. 梯度裁剪(Gradient Clipping)

    • 将梯度的绝对值限制在某个阈值范围内,防止梯度爆炸。
    • 例如,当梯度超过某个阈值时,将其裁剪到这个阈值。
  2. 正则化方法

    • 使用L2正则化(权重衰减)防止过度活跃的神经元。
    • 增加权重更新时的惩罚项,控制权重值不至于过大。
  3. 批归一化(Batch Normalization)

    • 对每个时间步的隐藏状态进行归一化,稳定训练过程。
    • 通过归一化,控制每个时间步的输出范围,防止梯度过大或过小。
  4. 调整激活函数

    • 选择适当的激活函数(如ReLU、Leaky ReLU等),防止梯度消失和爆炸。
    • 例如,Leaky ReLU 在负区间也有非零导数,避免了完全的梯度消失问题。

为什么很小的梯度无法更新权重并导致无法捕捉长期依赖关系?

当梯度非常小时,反向传播的权重更新公式:

Δ W = − η ⋅ ∂ L ∂ W \Delta W = -\eta \cdot \frac{\partial L}{\partial W} ΔW=ηWL

梯度项 ∂ L ∂ W \frac{\partial \mathcal{L}}{\partial W} WL 会非常小。这里, η \eta η 是学习率。当梯度接近零时,权重更新 Δ W \Delta W ΔW 也会接近零。这意味着神经网络的权重几乎不会发生变化,导致模型无法从训练数据中学习到有用的信息,从而无法有效捕捉长期依赖关系。

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

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

相关文章

【BUG】Edge|联想电脑 Bing 搜索报错“Ref A: 乱码、 Ref B:乱码、Ref C: 日期” 的解决办法

文章目录 省流版前言解决办法 详细解释版前言问题描述与排查过程解决办法与总结 省流版 我原以为我解决了&#xff0c;才发的博客&#xff0c;晚上用了一下其他设备发现还是会出现这个问题… 这篇博客并未解决该问题&#xff0c;如果评论里有人解决了这个问题不胜感激&#x…

Linux_应用篇(08) 信号-基础

本章将讨论信号&#xff0c;虽然信号的基本概念比较简单&#xff0c;但是其所涉及到的细节内容比较多&#xff0c;所以本章篇幅也会相对比较长。 事实上&#xff0c;在很多应用程序当中&#xff0c;都会存在处理异步事件这种需求&#xff0c;而信号提供了一种处理异步事件的方法…

6.S081的Lab学习——Lab5: xv6 lazy page allocation

文章目录 前言一、Eliminate allocation from sbrk() (easy)解析&#xff1a; 二、Lazy allocation (moderate)解析&#xff1a; 三、Lazytests and Usertests (moderate)解析&#xff1a; 总结 前言 一个本硕双非的小菜鸡&#xff0c;备战24年秋招。打算尝试6.S081&#xff0…

Facebook开户 | 如何检查公共主页的状态

想要了解你的Facebook公共主页的状态吗&#xff1f; Facebook公共主页是让广告主与粉丝互动、传播信息的绝佳平台&#xff0c;但是大家知道如何检查并维护自己的主页状态吗&#xff1f;别担心&#xff0c;Facebook提供了一系列简单易用的工具来帮助大家实现这一目标。 *Page Q…

自定义数据集上的3D目标检测:使用OpenPCDet训练CenterPointPillar模型

前言 在自动驾驶和机器人领域&#xff0c;3D目标检测是关键技术之一。它能够提供关于周围环境中物体的精确位置和尺寸信息。OpenPCDet是一个基于PyTorch的开源3D目标检测框架&#xff0c;支持多种3D检测网络。在本文中&#xff0c;我们将探讨如何使用OpenPCDet框架和CenterPoi…

每天学点小知识:Windows终端Powershell美化

前言 本章的旨在教会你美化自己的终端&#xff0c;powershell需要以管理员运行 经过我的测试&#xff0c;不同的电脑可能会有不同的报错&#xff0c;具体操作根据官方为主https://ohmyposh.dev/docs 效果展示 Oh My Posh&#xff1a;提供美观的 PowerShell 提示符主题 1.安装…

第16章-超声波跟随功能 基于STM32的三路超声波自动跟随小车 毕业设计 课程设计

第16章-超声波跟随功能 无PID跟随功能 //超声波跟随if(HC_SR04_Read() > 25){motorForward();//前进HAL_Delay(100);}if(HC_SR04_Read() < 20){motorBackward();//后退HAL_Delay(100);}PID跟随功能 在pid.c中定义一组PID参数 tPid pidFollow; //定距离跟随PIDpidFol…

酷黑简洁大气体育直播自适应模板赛事直播门户网站源码

源码名称&#xff1a;酷黑简洁大气体育直播自适应模板赛事直播门户网站源码 开发环境&#xff1a;帝国cms 7.5 安装环境&#xff1a;phpmysql 支持PC与手机端同步生成html&#xff08;多端同步生成插件&#xff09; 带软件采集&#xff0c;可以挂着自动采集发布&#xff0c;无…

用Python实现办公自动化

&#x1f482; 个人网站:【 摸鱼游戏】【神级代码资源网站】【工具大全】&#x1f91f; 一站式轻松构建小程序、Web网站、移动应用&#xff1a;&#x1f449;注册地址&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交…

matlab工具使用记录-编辑器和命令行窗口分开还原

工具&#xff1a;matlab2021b 场景&#xff1a;在使用软件的过程中&#xff0c;我们误操作将matlab的编辑器单独出来了。这时候对软件进行各种操作都还原不回去。 matlab中编辑器和命令行窗口分开了如下图所示。 这时候只需要使用快捷键在编辑器窗口按CtrlshiftD&#xff0c;…

Visual Studio 的调试

目录 引言 一、调试的基本功能 设置断点 启动调试 检查变量 逐步执行代码 调用堆栈 使用即时窗口 二、调试技巧 条件断点 日志断点 数据断点 异常调试 三、调试高级功能 远程调试 多线程调试 内存调试 性能调试 诊断工具 四、调试策略与最佳实践 系统化的…

揭秘python模块导入的“隐身术”:如何控制模块代码的执行?

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言&#xff1a;两个下划线的奥秘 二、案例展示&#xff1a;模块导入与代码执行 1. 导…

leetcode124 二叉树中的最大路径和-dp

题目 二叉树中的 路径 被定义为一条节点序列&#xff0c;序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点&#xff0c;且不一定经过根节点。 路径和 是路径中各节点值的总和。 给你一个二叉树的根节点 root &…

el-upload上传文件使用http-request方法,formdata传集合List到后台

el-upload上传文件 前言1、使用el-upload上传文件1.1代码演示1.2回显列表2、formdata传集合List到Springboot后台前言 在使用el-upload上传文件,会遇到必须使用:action="upload_url"远端链接的问题,本章我们讲解怎样不适用远端链接,通过上传获取到本地的file文件…

AI重塑保险业未来:机器学习在风险评估、欺诈检测与客户服务中的深度应用

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

技术架构设计指南:从需求到实现

技术架构是软件系统的骨架&#xff0c;它决定了系统的性能、可靠性、扩展性等关键特性。本文将介绍技术架构设计的一般步骤和方法。 第一步&#xff1a;需求分析 在设计技术架构之前&#xff0c;首先要对系统需求进行全面深入的分析。这包括功能需求、非功能需求&#xff08;如…

【渗透测试】|文件上传

1、安装使用蚁剑 https://blog.csdn.net/weixin_42474304/article/details/116376746 1、登陆dvwa,进入初级文件上传&#xff0c;上传一句话木马文件cmd.php&#xff0c; //cmd.php <?php eval($_POST[ccit]); ?> //eval: 执行命令的函数 //ccit:一句话木马文件的参数…

一个生动的例子——通过ERC20接口访问Tether合约

生动的例子 USDT&#xff1a;符合ERC20标准的美元稳定币&#xff0c;Tether合约获得测试网上Tether合约地址通过自己写的ERC20接口访问这个合约 Tether合约地址&#xff1a;0xdAC17F958D2ee523a2206206994597C13D831ec7 IERC20.sol // SPDX-License-Identifier: GPL-3.0pra…

K8s service 进阶

文章目录 K8s service 进阶Service 工作逻辑Service 具体实现Service 资源类型ClusterIPNodePortLoadBalancerExternalName Service 与 EndpointEndpoint 与 容器探针自定义Endpoint Service 相关字段sessionAffinityexternalTrafficPolicyinternalTrafficPolicypublishNotRead…

【微机原理及接口技术】可编程计数器/定时器8253

【微机原理及接口技术】可编程计数器/定时器8253 文章目录 【微机原理及接口技术】可编程计数器/定时器8253前言一、8253的内部结构和引脚二、8253的工作方式三、8253的编程总结 前言 本篇文章就8253芯片展开&#xff0c;详细介绍8253的内部结构和引脚&#xff0c;8253的工作方…