《动手学深度学习(PyTorch版)》笔记8.7

注:书中对代码的讲解并不详细,本文对很多细节做了详细注释。另外,书上的源代码是在Jupyter Notebook上运行的,较为分散,本文将代码集中起来,并加以完善,全部用vscode在python 3.9.18下测试通过,同时对于书上部分章节也做了整合。

Chapter8 Recurrent Neural Networks

8.7 Backpropagation Through Time

通过时间反向传播(backpropagation through time,BPTT)是循环神经网络中反向传播技术的一个特定应用,它要求我们将循环神经网络的计算图一次展开一个时间步,以获得模型变量和参数之间的依赖关系,然后,基于链式法则,应用反向传播来计算和存储梯度。由于序列可能相当长,因此依赖关系也可能相当长,在下文中,我们将阐明计算过程会发生什么以及如何在实践中解决它们。

8.7.1 RNN’s Gradient Analysis

我们从一个描述循环神经网络工作原理的简化模型开始,此模型忽略了隐状态的特性及其更新方式的细节,且其数学表示没有明确地区分标量、向量和矩阵。在这个简化模型中,我们将时间步 t t t的隐状态表示为 h t h_t ht,输入表示为 x t x_t xt,输出表示为 o t o_t ot,分别使用 w h w_h wh w o w_o wo来表示隐藏层和输出层的权重。每个时间步的隐状态和输出可以写为:

h t = f ( x t , h t − 1 , w h ) , o t = g ( h t , w o ) , (2) \begin{aligned}h_t &= f(x_t, h_{t-1}, w_h),\\o_t &= g(h_t, w_o),\end{aligned}\tag{2} htot=f(xt,ht1,wh),=g(ht,wo),(2)

其中 f f f g g g分别是隐藏层和输出层的变换。因此,我们有一个链 { … , ( x t − 1 , h t − 1 , o t − 1 ) , ( x t , h t , o t ) , … } \{\ldots, (x_{t-1}, h_{t-1}, o_{t-1}), (x_{t}, h_{t}, o_t), \ldots\} {,(xt1,ht1,ot1),(xt,ht,ot),},它们通过循环计算彼此依赖。前向传播相当简单,一次一个时间步的遍历三元组 ( x t , h t , o t ) (x_t, h_t, o_t) (xt,ht,ot),然后通过一个目标函数在所有 T T T个时间步内评估输出 o t o_t ot和对应的标签 y t y_t yt之间的差异:

L ( x 1 , … , x T , y 1 , … , y T , w h , w o ) = 1 T ∑ t = 1 T l ( y t , o t ) . L(x_1, \ldots, x_T, y_1, \ldots, y_T, w_h, w_o) = \frac{1}{T}\sum_{t=1}^T l(y_t, o_t). L(x1,,xT,y1,,yT,wh,wo)=T1t=1Tl(yt,ot).

对于反向传播,按照链式法则:

∂ L ∂ w h = 1 T ∑ t = 1 T ∂ l ( y t , o t ) ∂ w h = 1 T ∑ t = 1 T ∂ l ( y t , o t ) ∂ o t ∂ g ( h t , w o ) ∂ h t ∂ h t ∂ w h . \begin{aligned}\frac{\partial L}{\partial w_h} & = \frac{1}{T}\sum_{t=1}^T \frac{\partial l(y_t, o_t)}{\partial w_h} \\& = \frac{1}{T}\sum_{t=1}^T \frac{\partial l(y_t, o_t)}{\partial o_t} \frac{\partial g(h_t, w_o)}{\partial h_t} \frac{\partial h_t}{\partial w_h}.\end{aligned} whL=T1t=1Twhl(yt,ot)=T1t=1Totl(yt,ot)htg(ht,wo)whht.

在上式乘积的第一项和第二项很容易计算,而第三项比较棘手,因为我们需要循环地计算参数 w h w_h wh h t h_t ht的影响。根据式(2), h t h_t ht既依赖于 h t − 1 h_{t-1} ht1又依赖于 w h w_h wh,其中 h t − 1 h_{t-1} ht1的计算也依赖于 w h w_h wh。因此,使用链式法则产生:

∂ h t ∂ w h = ∂ f ( x t , h t − 1 , w h ) ∂ w h + ∂ f ( x t , h t − 1 , w h ) ∂ h t − 1 ∂ h t − 1 ∂ w h . (3) \frac{\partial h_t}{\partial w_h}= \frac{\partial f(x_{t},h_{t-1},w_h)}{\partial w_h} +\frac{\partial f(x_{t},h_{t-1},w_h)}{\partial h_{t-1}} \frac{\partial h_{t-1}}{\partial w_h}.\tag{3} whht=whf(xt,ht1,wh)+ht1f(xt,ht1,wh)whht1.(3)

为了导出上述梯度,假设我们有三个序列 { a t } , { b t } , { c t } \{a_{t}\},\{b_{t}\},\{c_{t}\} {at},{bt},{ct},当 t = 1 , 2 , … t=1,2,\ldots t=1,2,时,序列满足 a 0 = 0 a_{0}=0 a0=0 a t = b t + c t a t − 1 a_{t}=b_{t}+c_{t}a_{t-1} at=bt+ctat1。对于 t ≥ 1 t\geq 1 t1,就很容易得出:

a t = b t + ∑ i = 1 t − 1 ( ∏ j = i + 1 t c j ) b i . (4) a_{t}=b_{t}+\sum_{i=1}^{t-1}\left(\prod_{j=i+1}^{t}c_{j}\right)b_{i}.\tag{4} at=bt+i=1t1(j=i+1tcj)bi.(4)

基于下列公式替换 a t a_t at b t b_t bt c t c_t ct

a t = ∂ h t ∂ w h , b t = ∂ f ( x t , h t − 1 , w h ) ∂ w h , c t = ∂ f ( x t , h t − 1 , w h ) ∂ h t − 1 , \begin{aligned}a_t &= \frac{\partial h_t}{\partial w_h},\\ b_t &= \frac{\partial f(x_{t},h_{t-1},w_h)}{\partial w_h}, \\ c_t &= \frac{\partial f(x_{t},h_{t-1},w_h)}{\partial h_{t-1}},\end{aligned} atbtct=whht,=whf(xt,ht1,wh),=ht1f(xt,ht1,wh),

则:

∂ h t ∂ w h = ∂ f ( x t , h t − 1 , w h ) ∂ w h + ∑ i = 1 t − 1 ( ∏ j = i + 1 t ∂ f ( x j , h j − 1 , w h ) ∂ h j − 1 ) ∂ f ( x i , h i − 1 , w h ) ∂ w h . (5) \frac{\partial h_t}{\partial w_h}=\frac{\partial f(x_{t},h_{t-1},w_h)}{\partial w_h}+\sum_{i=1}^{t-1}\left(\prod_{j=i+1}^{t} \frac{\partial f(x_{j},h_{j-1},w_h)}{\partial h_{j-1}} \right) \frac{\partial f(x_{i},h_{i-1},w_h)}{\partial w_h}.\tag{5} whht=whf(xt,ht1,wh)+i=1t1(j=i+1thj1f(xj,hj1,wh))whf(xi,hi1,wh).(5)

虽然我们可以使用链式法则递归地计算 ∂ h t / ∂ w h \partial h_t/\partial w_h ht/wh,但当 t t t很大时这个链就会变得很长,在实践中是不可取的。

8.7.1.1 Cutting Off Time Steps

我们也可以在 τ \tau τ步后截断式(5)中的求和计算,即将求和终止为 ∂ h t − τ / ∂ w h \partial h_{t-\tau}/\partial w_h htτ/wh,这种截断是通过在给定数量的时间步之后分离梯度来实现的。这样做导致该模型主要侧重于短期影响,而不是长期影响,在现实中是可取的。

8.7.1.2 Randomly Truncating

我们也可以用一个随机变量替换 ∂ h t / ∂ w h \partial h_t/\partial w_h ht/wh,这个随机变量通过序列 ξ t \xi_t ξt实现。序列预定义了 0 ≤ π t ≤ 1 0 \leq \pi_t \leq 1 0πt1,其中 P ( ξ t = 0 ) = 1 − π t P(\xi_t = 0) = 1-\pi_t P(ξt=0)=1πt P ( ξ t = π t − 1 ) = π t P(\xi_t = \pi_t^{-1}) = \pi_t P(ξt=πt1)=πt,因此 E [ ξ t ] = 1 E[\xi_t] = 1 E[ξt]=1。使用 z t z_t zt来替换式(3)中的梯度 ∂ h t / ∂ w h \partial h_t/\partial w_h ht/wh得到:

z t = ∂ f ( x t , h t − 1 , w h ) ∂ w h + ξ t ∂ f ( x t , h t − 1 , w h ) ∂ h t − 1 ∂ h t − 1 ∂ w h . z_t= \frac{\partial f(x_{t},h_{t-1},w_h)}{\partial w_h} +\xi_t \frac{\partial f(x_{t},h_{t-1},w_h)}{\partial h_{t-1}} \frac{\partial h_{t-1}}{\partial w_h}. zt=whf(xt,ht1,wh)+ξtht1f(xt,ht1,wh)whht1.

ξ t \xi_t ξt的定义中推导出来 E [ z t ] = ∂ h t / ∂ w h E[z_t] = \partial h_t/\partial w_h E[zt]=ht/wh,当 ξ t = 0 \xi_t = 0 ξt=0时,递归计算终止在这个 t t t时间步。这导致了不同长度序列的加权和,其中长序列出现的很少,所以需要适当地加大权重。

在这里插入图片描述

上图说明了当基于循环神经网络使用通过时间反向传播分析数据集的三种策略:

  • 第一行采用随机截断,方法是将文本划分为不同长度的片断;
  • 第二行采用常规截断,方法是将文本分解为相同长度的子序列;
  • 第三行采用通过时间的完全反向传播,结果是产生了在计算上不可行的表达式。

虽然随机截断在理论上具有吸引力,但由于多种因素在实践中并不总比常规截断更好。首先,在对过去若干个时间步经过反向传播后,观测结果足以捕获实际的依赖关系。其次,增加的方差抵消了时间步数越多梯度越精确的事实。第三,模型可能需要经过一定程度的正则化,以防止过拟合。通过常规截断方法,时间反向传播会引入一定程度的正则化效果,有助于控制模型的复杂度,并提高其泛化能力。

8.7.2 Details of BPTT

下面将展示如何计算目标函数相对于所有模型参数的梯度。简单起见,我们考虑一个没有偏置参数的RNN,其在隐藏层中的激活函数使用恒等映射( ϕ ( x ) = x \phi(x)=x ϕ(x)=x)。对于时间步 t t t,设单个样本的输入及其对应的标签分别为 x t ∈ R d \mathbf{x}_t \in \mathbb{R}^d xtRd y t y_t yt。计算隐状态 h t ∈ R h \mathbf{h}_t \in \mathbb{R}^h htRh和输出 o t ∈ R q \mathbf{o}_t \in \mathbb{R}^q otRq的方式为:

h t = W h x x t + W h h h t − 1 , o t = W q h h t , \begin{aligned}\mathbf{h}_t &= \mathbf{W}_{hx} \mathbf{x}_t + \mathbf{W}_{hh} \mathbf{h}_{t-1},\\ \mathbf{o}_t &= \mathbf{W}_{qh} \mathbf{h}_{t},\end{aligned} htot=Whxxt+Whhht1,=Wqhht,

l ( o t , y t ) l(\mathbf{o}_t, y_t) l(ot,yt)表示时间步 t t t处的损失函数,则目标函数的总体损失是:

L = 1 T ∑ t = 1 T l ( o t , y t ) . L = \frac{1}{T} \sum_{t=1}^T l(\mathbf{o}_t, y_t). L=T1t=1Tl(ot,yt).

模型绘制一个计算图如下所示。

在这里插入图片描述

上图中的模型参数是 W h x \mathbf{W}_{hx} Whx W h h \mathbf{W}_{hh} Whh W q h \mathbf{W}_{qh} Wqh。通常,训练该模型需要分别计算: ∂ L / ∂ W h x \partial L/\partial \mathbf{W}_{hx} L/Whx ∂ L / ∂ W h h \partial L/\partial \mathbf{W}_{hh} L/Whh ∂ L / ∂ W q h \partial L/\partial \mathbf{W}_{qh} L/Wqh。根据上图中的依赖关系,我们可以沿箭头的相反方向遍历计算图,依次计算和存储梯度。为了灵活地表示链式法则中不同形状的矩阵、向量和标量的乘法,我们继续使用4.7中所述的 prod \text{prod} prod运算符。

首先有:

∂ L ∂ o t = ∂ l ( o t , y t ) T ⋅ ∂ o t ∈ R q . (6) \frac{\partial L}{\partial \mathbf{o}_t} = \frac{\partial l (\mathbf{o}_t, y_t)}{T \cdot \partial \mathbf{o}_t} \in \mathbb{R}^q.\tag{6} otL=Totl(ot,yt)Rq.(6)

接着得到:

∂ L ∂ W q h = ∑ t = 1 T prod ( ∂ L ∂ o t , ∂ o t ∂ W q h ) = ∑ t = 1 T ∂ L ∂ o t h t ⊤ ∈ R q × h \frac{\partial L}{\partial \mathbf{W}_{qh}} = \sum_{t=1}^T \text{prod}\left(\frac{\partial L}{\partial \mathbf{o}_t}, \frac{\partial \mathbf{o}_t}{\partial \mathbf{W}_{qh}}\right) = \sum_{t=1}^T \frac{\partial L}{\partial \mathbf{o}_t} \mathbf{h}_t^\top\in \mathbb{R}^{q \times h} WqhL=t=1Tprod(otL,Wqhot)=t=1TotLhtRq×h

其中 ∂ L / ∂ o t \partial L/\partial \mathbf{o}_t L/ot是由式(6)给出的。

接下来,如上图所示,在最后的时间步 T T T,目标函数 L L L仅通过 o T \mathbf{o}_T oT依赖于隐状态 h T \mathbf{h}_T hT。因此,我们通过使用链式法可以很容易地得到梯度$\partial L/\partial \mathbf{h}_T :

∂ L ∂ h T = prod ( ∂ L ∂ o T , ∂ o T ∂ h T ) = W q h ⊤ ∂ L ∂ o T ∈ R h . (7) \frac{\partial L}{\partial \mathbf{h}_T} = \text{prod}\left(\frac{\partial L}{\partial \mathbf{o}_T}, \frac{\partial \mathbf{o}_T}{\partial \mathbf{h}_T} \right) = \mathbf{W}_{qh}^\top \frac{\partial L}{\partial \mathbf{o}_T}\in \mathbb{R}^h.\tag{7} hTL=prod(oTL,hToT)=WqhoTLRh.(7)

隐状态的梯度 ∂ L / ∂ h t ∈ R h \partial L/\partial \mathbf{h}_t \in \mathbb{R}^h L/htRh在任何 t < T t < T t<T时都可以递归地计算为:

∂ L ∂ h t = prod ( ∂ L ∂ h t + 1 , ∂ h t + 1 ∂ h t ) + prod ( ∂ L ∂ o t , ∂ o t ∂ h t ) = W h h ⊤ ∂ L ∂ h t + 1 + W q h ⊤ ∂ L ∂ o t . (8) \frac{\partial L}{\partial \mathbf{h}_t} = \text{prod}\left(\frac{\partial L}{\partial \mathbf{h}_{t+1}}, \frac{\partial \mathbf{h}_{t+1}}{\partial \mathbf{h}_t} \right) + \text{prod}\left(\frac{\partial L}{\partial \mathbf{o}_t}, \frac{\partial \mathbf{o}_t}{\partial \mathbf{h}_t} \right) = \mathbf{W}_{hh}^\top \frac{\partial L}{\partial \mathbf{h}_{t+1}} + \mathbf{W}_{qh}^\top \frac{\partial L}{\partial \mathbf{o}_t}.\tag{8} htL=prod(ht+1L,htht+1)+prod(otL,htot)=Whhht+1L+WqhotL.(8)

对于任何时间步 1 ≤ t ≤ T 1 \leq t \leq T 1tT展开递归计算得:

∂ L ∂ h t = ∑ i = t T ( W h h ⊤ ) T − i W q h ⊤ ∂ L ∂ o T + t − i . (9) \frac{\partial L}{\partial \mathbf{h}_t}= \sum_{i=t}^T {\left(\mathbf{W}_{hh}^\top\right)}^{T-i} \mathbf{W}_{qh}^\top \frac{\partial L}{\partial \mathbf{o}_{T+t-i}}.\tag{9} htL=i=tT(Whh)TiWqhoT+tiL.(9)

我们可以从式(9)中看到,这个简单的线性例子已经陷入到 W h h ⊤ \mathbf{W}_{hh}^\top Whh的潜在的非常大的幂。在这个幂中,小于1的特征值将会消失,大于1的特征值将会发散。这在数值上是不稳定的,表现形式为梯度消失或梯度爆炸,解决此问题的一种方法如8.7.1中所述。

最后,应用链式规则得:

∂ L ∂ W h x = ∑ t = 1 T prod ( ∂ L ∂ h t , ∂ h t ∂ W h x ) = ∑ t = 1 T ∂ L ∂ h t x t ⊤ ∈ R h × d , ∂ L ∂ W h h = ∑ t = 1 T prod ( ∂ L ∂ h t , ∂ h t ∂ W h h ) = ∑ t = 1 T ∂ L ∂ h t h t − 1 ⊤ ∈ R h × d , \begin{aligned} \frac{\partial L}{\partial \mathbf{W}_{hx}} &= \sum_{t=1}^T \text{prod}\left(\frac{\partial L}{\partial \mathbf{h}_t}, \frac{\partial \mathbf{h}_t}{\partial \mathbf{W}_{hx}}\right) = \sum_{t=1}^T \frac{\partial L}{\partial \mathbf{h}_t} \mathbf{x}_t^\top\in \mathbb{R}^{h \times d},\\ \frac{\partial L}{\partial \mathbf{W}_{hh}} &= \sum_{t=1}^T \text{prod}\left(\frac{\partial L}{\partial \mathbf{h}_t}, \frac{\partial \mathbf{h}_t}{\partial \mathbf{W}_{hh}}\right) = \sum_{t=1}^T \frac{\partial L}{\partial \mathbf{h}_t} \mathbf{h}_{t-1}^\top\in \mathbb{R}^{h \times d}, \end{aligned} WhxLWhhL=t=1Tprod(htL,Whxht)=t=1ThtLxtRh×d,=t=1Tprod(htL,Whhht)=t=1ThtLht1Rh×d,

其中 ∂ L / ∂ h t \partial L/\partial \mathbf{h}_t L/ht由式(7)和式(8)递归计算得到,是影响数值稳定性的关键量。在训练过程中一些中间值会被存储,以避免重复计算,例如存储 ∂ L / ∂ h t \partial L/\partial \mathbf{h}_t L/ht,以便在计算 ∂ L / ∂ W h x \partial L / \partial \mathbf{W}_{hx} L/Whx ∂ L / ∂ W h h \partial L / \partial \mathbf{W}_{hh} L/Whh时使用。

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

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

相关文章

C++数据结构与算法——双指针法

C第二阶段——数据结构和算法&#xff0c;之前学过一点点数据结构&#xff0c;当时是基于Python来学习的&#xff0c;现在基于C查漏补缺&#xff0c;尤其是树的部分。这一部分计划一个月&#xff0c;主要利用代码随想录来学习&#xff0c;刷题使用力扣网站&#xff0c;不定时更…

NLP_ChatGPT的RLHF实战

文章目录 介绍小结 介绍 ChatGPT 之所以成为ChatGPT&#xff0c;基于人类反馈的强化学习是其中重要的一环。而ChatGPT 的训练工程称得上是复杂而又神秘的&#xff0c;迄今为止&#xff0c;OpenAl也没有开源它的训练及调优的细节。 从 OpenAl已经公开的一部分信息推知&#xff…

计算机组成原理(2)-----存储芯片与CPU的连接

目录 一.单块存储芯片与CPU的连接 二.多块存储芯片与CPU的连接 1.位扩展 2.字扩展 &#xff08;1&#xff09;线选法 &#xff08;2&#xff09;译码器片选法 3.字位同时扩展 三.译码器相关 一.单块存储芯片与CPU的连接 如图所示是8*8位的芯片&#xff0c;总共8个存储…

OS设备管理

设备管理 操作系统作为系统资源的管理者&#xff0c;其提供的功能有&#xff1a;处理机管理、存储器管理、文件管理、设备管理。其中前三个管理都是在计算机的主机内部管理其相对应的硬件。 I/O设备 I/O即输入/输出。I/O设备即可以将数据输入到计算机&#xff0c;或者可以接收…

高校危化试剂管理:Java与SpringBoot的革新

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

Vue核心基础6:Vue内置指令、自定义指令、生命周期

1 Vue中的内置指令 <script>const vm new Vue({el: #root,data: {n: 1,m: 100,name: Vue,str: <h3>你好</h3>}})</script> 1.1 v-text <div v-text"name"></div>1.2 v-html <div v-html"str"></div> …

最小生成树(Kruskal算法及相关例题)

1.Kruskal算法概念以及基本思路 &#xff08;1&#xff09;概念&#xff1a; 克鲁斯卡尔算法是求连通网的最小生成树的另一种方法。它的时间复杂度为O&#xff08;ElogE&#xff09;(E是图G的边的总数)&#xff0c;适合于求边稀疏的网的最小生成树 。 其基本思想是&#xff…

黄金交易策略(Nerve Nnife.mql4):做单手数设计

完整EA&#xff1a;Nerve Knife.ex4黄金交易策略_黄金趋势ea-CSDN博客 NK的做单量是由参数设定的&#xff0c;以下分别是参数项&#xff1a; 考虑到复利的情况&#xff0c;若10000本金&#xff0c;在以上三个参数的设计下&#xff0c;第1单的购买量是0.01*10,第2单是0.01*10*2…

Java迭代器详解,看这一篇就够了

文章目录 &#x1f6a9;Java 迭代器详解 &#x1f4da;迭代器的定义 &#x1f4d2;认识Iterator ✏️类结构图 ✒️Iterable接口 &#x1f58d;️Iterator接口 &#x1f4c3;Iterator接口的方法 &#x1f4d9;迭代器的使用 &#x1f3f7;️使用迭代器遍历集合 &#x1f516;Ite…

[BIZ] - 1.金融交易系统特点

1. 典型数据汇总 数据 说明 新增数据量(条/天) Qps(条/s) 消息大小(Byte) 实时性 可丢失性 可恢复性 实时行情 1.使用场景&#xff1a;交易&#xff0c;报价&#xff0c;策略验证&#xff1b; 2.冷热分离&#xff1a;彭博行情/其他行情&#xff1b;黄金&期货行情/…

Java图形化界面编程——AWT概论 笔记

2.3 Container容器 2.3.1 Container继承体系 Winow是可以独立存在的顶级窗口,默认使用BorderLayout管理其内部组件布局;Panel可以容纳其他组件&#xff0c;但不能独立存在&#xff0c;它必须内嵌其他容器中使用&#xff0c;默认使用FlowLayout管理其内部组件布局&#xff1b;S…

交通管理|交通管理在线服务系统|基于Springboot的交通管理系统设计与实现(源码+数据库+文档)

交通管理在线服务系统目录 目录 基于Springboot的交通管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、用户信息管理 2、驾驶证业务管理 3、机动车业务管理 4、机动车业务类型管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计…

MySQL学习Day15——MySQL安装与使用

一、Linux下的MySQL的安装与使用: 卸载MySQL: 1.关闭当前MySQL服务:systemctl stop mysql.service 2.查看当前mysql安装状况:rpm -qa | grep -i mysql 3.卸载上述命令查询出的已安装的程序:yum remove mysql-xxx mysql-xxx mysql-xxxx 4.删除mysql相关文件: (1)查找相关文…

解决vscode报错,在赋值前使用了变量“XXX“

问题&#xff1a;如图所示 解决方法&#xff1a; 法一&#xff1a; 补全函数使其完整 法二&#xff1a; 使用断言

c++Qt网络操作

1、基础概念 1.1 TCP/UDP TCP 是一种面向连接的传输层协议&#xff0c;它能提供高可靠性通信(即数据无误、数据无丢失、 数据无失序、数据无重复到达的通信) 适用情况&#xff1a; 1.SN/QQ等即时通讯软件的用户登录账户管理相关的功能通常采用TCP协议 2、适合于对传输质量要求较…

【STM32 CubeMX】串口编程DMA

文章目录 前言一、DMA方式1.1 DMA是什么1.2 CubeMX配置DMA1.3 DMA方式函数使用DMA的发送接收函数 总结 前言 在嵌入式系统中&#xff0c;串口通信是一项至关重要的功能&#xff0c;它允许单片机与外部设备进行数据交换&#xff0c;如传感器、显示器或其他设备。然而&#xff0…

Linux笔记之xhost +和docker的关系以及GDK_SCALE和GDK_DPI_SCALE详解

Linux笔记之xhost 和docker的关系以及GDK_SCALE和GDK_DPI_SCALE详解 ——2024-02-11 code review! 文章目录 Linux笔记之xhost 和docker的关系以及GDK_SCALE和GDK_DPI_SCALE详解xhost 的作用xhost 与 Docker 的关系 -e GDK_SCALE 和 -e GDK_DPI_SCALE详解GDK_SCALEGDK_DPI_SC…

【Linux】进程的初步认识

进程的初步认识 基本概念描述进程task_struct-PCB的一种task_stuct内容分类 查看进程通过系统调用获取进程标识符 基本概念 要了解进程&#xff0c;首先我们要知道两点 我们可以同时启动多个程序&#xff0c;也就意味着我们可以将多个.exe文件加载到内存操作系统如何去管理这些…

036-安全开发-JavaEE应用第三方组件Log4j日志FastJson序列化JNDI注入

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入 #知识点&#xff1a; 1、JavaEE-组件安全-Log4j 2、JavaEE-组件安全-Fastjson 3、JavaEE-基本了解-JNDI-API 演示案例&#xff1a; ➢Java-三方组件-Log4J&JNDI ➢Java-三方组件-Fa…

OpenAI全新发布文生视频模型Sora - 现实,不存在了

OpenAI&#xff0c;发他们的文生视频大模型&#xff0c;Sora了。。。。。 而且&#xff0c;是强到&#xff0c;能震惊我一万年的程度。。。 https://openai.com/sora 如果非要用三个词来总结Sora&#xff0c;那就是“60s超长长度”、“单视频多角度镜头”和“世界模型” &am…