【强化学习】18 —— SAC( Soft Actor-Critic)

文章目录

  • 前言
  • 最大熵强化学习
    • 不同动作空间下的最大熵强化学习
    • 基于能量的模型
    • 软价值函数
    • 最大熵策略
  • Soft Q-learning
    • Soft Q-Iteration
    • Soft Q-Learning
    • 近似采样与SVGD
    • 伪代码
  • Soft Actor-Critic
    • 伪代码
    • 代码实践
      • 连续动作空间
      • 离散动作空间
  • 参考与推荐

前言

之前的章节提到过在线策略算法的采样效率比较低,我们通常更倾向于使用离线策略算法。然而,虽然 DDPG 是离线策略算法,但是它的训练非常不稳定,收敛性较差,对超参数比较敏感,也难以适应不同的复杂环境。2018 年,一个更加稳定的离线策略算法 Soft Actor-Critic(SAC)被提出。SAC 的前身是 Soft Q-learning,它们都属于最大熵强化学习的范畴。Soft Q-learning 不存在一个显式的策略函数,而是使用一个函数 Q Q Q的波尔兹曼分布,在连续空间下求解非常麻烦。于是 SAC 提出使用一个 Actor 表示策略函数,从而解决这个问题。目前,在无模型的强化学习算法中,SAC 是一个非常高效的算法,它学习一个随机性策略,在不少标准环境中取得了领先的成绩。

最大熵强化学习

熵是策略中随机性的一种度量,设 x x x为随机变量,概率密度函数为 P P P,熵 H H H的计算式为: H ( p ) = E x ∼ p [ − log ⁡ p ( x ) ] H(p)=\mathbb{E}_{x\sim p}[-\log p(x)] H(p)=Exp[logp(x)]在强化学习中,我们可以使用 H ( π ( ⋅ ∣ s ) ) H(\pi(\cdot|s)) H(π(s))来表示策略 π \pi π在状态 s s s下的随机程度。最大熵强化学习(maximum entropy RL)的思想就是除了要最大化累积奖励,还要使得策略更加随机,除此之外还要增加算法的鲁棒性以及提升策略的预训练效果。

传统的RL难以适应于复杂变化的环境。如图所示,通过学习,智能体会倾向于选择上面的路径(因为更短),但若在上方的通道设置一个障碍,智能体则无法通过,且需重新学习下方的路径以达到终点。
在这里插入图片描述

如图3a所示,传统的RL策略类似于一个单峰的高斯分布,而最大熵强化学习则是类似于3b中所示的多峰分布。前者会忽视掉其他较低概率的策略,而后者则是增加了对其他的策略的探索,使之能够适应更复杂的环境。
在这里插入图片描述

不同动作空间下的最大熵强化学习

离散动作空间
在最大熵强化学习中,带有最大熵的目标函数通过增加一个熵项,使得最优策略的熵在每次迭代下达到最大。
π M a x E n t ∗ = arg ⁡ max ⁡ π ∑ t E ( s t , a t ) ∼ ρ π [ r ( s t , a t ) + α H ( π ( ⋅ ∣ s t ) ) ] \begin{aligned}\pi_\mathrm{MaxEnt}^*=&\arg\max_\pi\sum_t\mathbb{E}_{(\mathbf{s}_t,\mathbf{a}_t)\sim\rho_\pi}\left[r(\mathbf{s}_t,\mathbf{a}_t)+\alpha\mathcal{H}(\pi(\cdot|\mathbf{s}_t))\right]\end{aligned} πMaxEnt=argπmaxtE(st,at)ρπ[r(st,at)+αH(π(st))] H ( π ( ⋅ ∣ s t ) ) = − ∑ a t π ( a t ∣ s t ) l o g ( π ( a t ∣ s t ) ) {\mathcal H}\big(\pi(\cdot|s_{t})\big)=-\sum_{a_{t}}\pi(a_{t}|s_{t})\mathrm{log}\big(\pi(a_{t}|s_{t})\big) H(π(st))=atπ(atst)log(π(atst))其中, α \alpha α是一个正则化的系数,用来控制熵的重要程度。熵正则化增加了强化学习算法的探索程度,当 α = 0 \alpha=0 α=0时,最大熵强化学习与传统的 RL算法相同;当 α > 0 \alpha>0 α>0时, α \alpha α越大,探索性就越强,有助于加速后续的策略学习,并减少策略陷入较差的局部最优的可能性,鲁棒性越好。

⚠️You Should Know
请注意,优化目标与玻尔兹曼探索(Sallans & Hinton, 2004)和PGQ (O’Donoghue et al., 2016)的行为有质的不同,后者基于贪婪策略在当前时间步长最大化熵,但没有明确会优化未来可能到达高熵状态的策略。这个不同之处很重要,因为最大熵优化目标会最大化策略 π \pi π的整个轨迹的熵。

连续动作空间
a = μ ( ⋅ ∣ s t ) + ϵ a=\mu(\cdot|s_t)+\epsilon a=μ(st)+ϵ
对于连续动作空间,通常会加上噪声项 ϵ \epsilon ϵ,以增强算法的探索能力。 ϵ \epsilon ϵ通常是一个高斯分布。但是这种方法会有难以学到多样化的策略 μ \mu μ以及因为 ϵ \epsilon ϵ服从预定义的分布,而难以泛化到多模态的复杂情况等问题。

基于能量的模型

优化最大熵目标为我们提供了一个训练随机策略的框架,但是其中的策略还未进行表示。以往的工作中有采用多项分布或者高斯分布进行表示,然而,如果我们想使用一类通用的分布来表示复杂的、多模态的行为,我们可以选择使用这种形式的基于能量的通用策略: π ( a t ∣ s t ) ∝ exp ⁡ ( − E ( s t , a t ) ) , \pi(\mathbf{a}_t|\mathbf{s}_t)\propto\exp\left(-\mathcal{E}(\mathbf{s}_t,\mathbf{a}_t)\right), π(atst)exp(E(st,at)),

其中, E \mathcal{E} E代表能量函数,可用深度神经网络进行拟合。接下来简要介绍一下基于能量的模型。

基于能量的模型(Energy-Based Model, EBM)的目标是最大化打分函数 ϕ ( x ) \phi(x) ϕ(x)的期望,同时增加探索性:
max ⁡ p E x ∼ p [ ϕ ( x ) ] + α H ( p ) \max_p \mathbb{E}_{x\sim p}[\phi(x)]+\alpha\mathcal{H}(p) pmaxExp[ϕ(x)]+αH(p)

其中, α \alpha α越大,越鼓励探索。最终求解出的分布符合波兹曼分布(Boltzmann distribution) , p ∗ ( x ) ∝ e − ϕ ( x ) / α ,p^{*}(x)\propto e^{-\phi(x)/\alpha} p(x)eϕ(x)/α(其中 α \alpha α又可以被称为温度系数)。将目标函数除以 α \alpha α,因为 H ( p ) = E x ∼ p [ − log ⁡ p ( x ) ] H(p)=\mathbb{E}_{x\sim p}[-\log p(x)] H(p)=Exp[logp(x)],将两项合并,最终最大化目标函数等价于最小化负的 p p p p ϕ p_\phi pϕ的KL散度。
E x ∼ p [ ϕ ( x ) ] α + H ( p ) = E x ∼ p [ ϕ ( x ) α − log ⁡ p ( x ) ] = − K L ( p ∣ ∣ p ϕ ) \frac{\mathbb{E}_{x\sim p}[\phi(x)]}{\alpha}+\mathcal{H}(p)=\mathbb{E}_{x\sim p}\left[\frac{\phi(x)}{\alpha}-\log p(x)\right]=-KL\big(p||p_{\phi}\big) αExp[ϕ(x)]+H(p)=Exp[αϕ(x)logp(x)]=KL(p∣∣pϕ)

波兹曼分布(Boltzmann distribution) p ϕ ( x ) = e ϕ ( x ) / α z = e − ε ( x ) z p_{\phi}(x)=\frac{e^{\phi(x)/\alpha}}{z}=\frac{e^{-\varepsilon(x)}}{z} pϕ(x)=zeϕ(x)/α=zeε(x)的能量函数为 ε ( x ) = − ϕ ( x ) α \varepsilon(x)=-\frac{\phi(x)}{\alpha} ε(x)=αϕ(x),能量越高越不确定。

在最大熵强化学习中,策略优化目标为(即,令 E ( s t , a t ) = − 1 α Q s o f t ( s t , a t ) \mathcal{E}(s_t, a_t) =-\frac{1}{\alpha}Q_{soft}(s_t, a_t) E(st,at)=α1Qsoft(st,at)):
max ⁡ a E x ∼ π ( ⋅ ∣ s ) [ Q ( s , a ) ] + α H ( π ( ⋅ ∣ s ) ) \max_a \mathbb{E}_{x\sim {\pi(\cdot|s)}}[Q(s,a)]+\alpha\mathcal{H}(\pi(\cdot|s)) amaxExπ(s)[Q(s,a)]+αH(π(s))因此,最大熵强化学习不会像传统RL那样直接选取最大的Q函数值,而是将探索性考虑进来,从而避免陷入局部最小值。在实践应用中,最大熵的优点包括:1)它鼓励更广泛的探索,同时放弃多余的样本;2)该策略可以得到多个近似最优动作;3)该方法可以有效地提高训练速度,是优化传统RL目标函数的一种新方法。

软价值函数

考虑到熵的因素,我们可以对价值函数做一些变更:
V π ( s ) = E τ ∼ π ∑ t = 0 ∞ γ t ( R ( s t , a t , s t + 1 ) + α H ( π ( ⋅ ∣ s t ) ) ) ∣ s 0 = s V^{\pi}(s) = E_{\tau \sim \pi}{ \left. \sum_{t=0}^{\infty} \gamma^t \bigg( R(s_t, a_t, s_{t+1}) + \alpha H\left(\pi(\cdot|s_t)\right) \bigg) \right| s_0 = s} Vπ(s)=Eτπt=0γt(R(st,at,st+1)+αH(π(st))) s0=s Q π ( s , a ) = E τ ∼ π ∑ t = 0 ∞ γ t R ( s t , a t , s t + 1 ) + α ∑ t = 1 ∞ γ t H ( π ( ⋅ ∣ s t ) ) ∣ s 0 = s , a 0 = a Q^{\pi}(s,a) = E_{\tau \sim \pi}{ \left. \sum_{t=0}^{\infty} \gamma^t R(s_t, a_t, s_{t+1}) + \alpha \sum_{\textcolor{red}{t=1}}^{\infty} \gamma^t H\left(\pi(\cdot|s_t)\right)\right| s_0 = s, a_0 = a} Qπ(s,a)=Eτπt=0γtR(st,at,st+1)+αt=1γtH(π(st)) s0=s,a0=a

相应的bellman方程为:
V π ( s ) = E a ∼ π Q π ( s , a ) + α H ( π ( ⋅ ∣ s ) ) V^{\pi}(s) = E_{a \sim \pi}{Q^{\pi}(s,a)} + \alpha H\left(\pi(\cdot|s)\right) Vπ(s)=EaπQπ(s,a)+αH(π(s)) Q π ( s , a ) = E s ′ ∼ P , a ′ ∼ π [ R ( s , a , s ′ ) + γ ( Q π ( s ′ , a ′ ) + α H ( π ( ⋅ ∣ s ′ ) ) ) ] = E s ′ ∼ P [ R ( s , a , s ′ ) + γ V π ( s ′ ) ] . \begin{aligned}Q^{\pi}(s,a) =& E_{s' \sim P ,a' \sim \pi}{[R(s,a,s') + \gamma\left(Q^{\pi}(s',a') + \alpha H\left(\pi(\cdot|s')\right) \right)}] \\=& E_{s' \sim P}{[R(s,a,s') + \gamma V^{\pi}(s')]}.\end{aligned} Qπ(s,a)==EsP,aπ[R(s,a,s)+γ(Qπ(s,a)+αH(π(s)))]EsP[R(s,a,s)+γVπ(s)].

最大熵策略

最大熵强化学习的策略目标是 max ⁡ a E x ∼ π ( ⋅ ∣ s ) [ Q s o f t ( s , a ) ] + α H ( π ( ⋅ ∣ s ) ) \max_a \mathbb{E}_{x\sim {\pi(\cdot|s)}}[Q_{soft}(s,a)]+\alpha\mathcal{H}(\pi(\cdot|s)) maxaExπ(s)[Qsoft(s,a)]+αH(π(s)),基于能量模型的形式 ,则可表示为
π M a x l n t ( a ∣ s ) ∝ exp ⁡ ( Q s o f t ( s , a ) / α ) \pi_{\mathrm{Maxlnt}}(a|s)\propto\exp\bigl(Q_{soft}(s,a)/\alpha\bigr) πMaxlnt(as)exp(Qsoft(s,a)/α)
状态值函数的具体形式为:
V s o f t ( s t ) = E a ∼ π [ Q s o f t ( s t , a t ) ] + α H ( π ( ⋅ ∣ s t ) ) V s o f t ( s t ) ← α log ⁡ ∫ exp ⁡ ( 1 α Q s o f t ( s t , a ′ ) ) d a ′ \begin{aligned}V_{soft}(s_t)&=\mathbb{E}_{a\sim\pi}\big[Q_{soft}(s_t,a_t)\big]+\alpha\mathcal{H}\big(\pi(\cdot|s_t)\big)\\V_{soft}(s_t)&\leftarrow\alpha\log\int\exp\left(\frac{1}{\alpha}Q_{soft}(s_t,a')\right)da'\end{aligned} Vsoft(st)Vsoft(st)=Eaπ[Qsoft(st,at)]+αH(π(st))αlogexp(α1Qsoft(st,a))da

基于此的最优策略为:

π M a x l n t ( a ∣ s ) = exp ⁡ ( 1 α ( Q s o f t ∗ ( s t , a t ) − V s o f t ∗ ( s t ) ) ) \pi_{\mathrm{Maxlnt}}(a|s)=\exp\left(\frac{1}{\alpha}\Big(Q_{soft}^{*}(s_{t},a_{t})-V_{soft}^{*}(s_{t})\Big)\right) πMaxlnt(as)=exp(α1(Qsoft(st,at)Vsoft(st)))

⚠️You Should Know
证明过程可参考 Reinforcement Learning with Deep Energy-Based Policies, 2017, arXiv

Soft Q-learning

Soft Q-Iteration

类似于Q-learning,通过对 Q s o f t Q_{soft}^{} Qsoft以及 V s o f t V_{soft}^{} Vsoft的不断迭代,可以使得结果不断向收敛至 Q s o f t ∗ Q_{soft}^{*} Qsoft V s o f t ∗ V_{soft}^{*} Vsoft以及 π → π M a x E n t ∗ \pi\rightarrow\pi_\mathrm{MaxEnt}^* ππMaxEnt Q s o f t ( s t , a t ) ← r t + γ E s t + 1 ∼ p s [ V s o f t ( s t + 1 ) ] , ∀ s t , a t ( 8 ) V s o f t ( s t ) ← α log ⁡ ∫ A exp ⁡ ( 1 α Q s o f t ( s t , a ′ ) ) d a ′ , ∀ s t ( 9 ) \begin{aligned}Q_{\mathrm{soft}}(\mathbf{s}_t,\mathbf{a}_t)\leftarrow r_t+\gamma\mathbb{E}_{\mathbf{s}_{t+1}\sim p_\mathbf{s}}\left[V_{\mathrm{soft}}(\mathbf{s}_{t+1})\right],\forall\mathbf{s}_t,\mathbf{a}_t\quad(8)\\V_{\mathrm{soft}}(\mathbf{s}_t)\leftarrow\alpha\log\int_{\mathcal{A}}\exp\left(\frac{1}{\alpha}Q_{\mathrm{soft}}(\mathbf{s}_t,\mathbf{a}^{\prime})\right)d\mathbf{a}^{\prime},\forall\mathbf{s}_t(9)\end{aligned} Qsoft(st,at)rt+γEst+1ps[Vsoft(st+1)],st,at(8)Vsoft(st)αlogAexp(α1Qsoft(st,a))da,st(9) c o n v e r g e s t o Q s o f t ∗ a n d V s o f t ∗ , r e s p e c t i v e l y . converges ~to ~Q_\mathrm{soft}^* ~and ~V_\mathrm{soft}^*, respectively. converges to Qsoft and Vsoft,respectively.

⚠️You Should Know
收敛性证明过程可参考 Reinforcement Learning with Deep Energy-Based Policies, 2017, arXiv

但是上述软贝尔曼更新(soft Bellman backup)的方式不能精确地在连续或大的状态和动作空间中执行,其次基于能量模型进行采样是比较困难的。

Soft Q-Learning

由于(9)中存在的积分以及存在无限的状态和动作集合,上述过程难以实现,因此,作者使用了随机优化的方法进行描述,同时上述过程变为了一个随机梯度下降更新过程。Soft Q-function可以被建模成关于参数 θ \theta θ的函数 Q s o f t θ ( s t , a t ) Q_{soft}^{\theta}(s_t,a_t) Qsoftθ(st,at)。为了描述上述的随机过程,Soft Q-Learning使用了重要性采样对价值函数进行描述: V soft θ ( s t ) = α log ⁡ E π [ exp ⁡ ( 1 α Q soft θ ( s t , a ′ ) ) π ( a ′ ) ] V_{\text{soft}}^{\theta}(\mathbf{s}_{t})=\alpha\log\mathbb{E}_{\pi}\left[\frac{\exp\left(\frac{1}{\alpha}Q_{\text{soft}}^{\theta}(\mathbf{s}_{t},\mathbf{a'})\right)}{\pi(\mathbf{a'})}\right] Vsoftθ(st)=αlogEπ[π(a)exp(α1Qsoftθ(st,a))]

π \pi π可以表示为任意的策略分布。之后利用均方误差计算目标函数, Q ^ s o f t θ ˉ ( s t , a t ) = r t + γ E s t + 1 ∼ p s [ V s o f t θ ˉ ( s t + 1 ) ] \hat{Q}_{\mathrm{soft}}^{\bar{\theta}}(\mathbf{s}_t,\mathbf{a}_t)=r_t+\gamma\mathbb{E}_{\mathbf{s}_{t+1}\thicksim p_\mathbf{s}}[V_{\mathrm{soft}}^{\bar{\theta}}(\mathbf{s}_{t+1})] Q^softθˉ(st,at)=rt+γEst+1ps[Vsoftθˉ(st+1)]为目标的Q-值:

J Q ( θ ) = E s t ∼ q s t , a t ∼ q a t [ 1 2 ( Q ^ s o f t θ ˉ ( s t , a t ) − Q s o f t θ ( s t , a t ) ) 2 ] J_Q(\theta)=\mathbb{E}_{\mathbf{s}_t\sim q_{\mathbf{s}_t},\mathbf{a}_t\sim q_{\mathbf{a}_t}}\left[\frac{1}{2}\left(\hat{Q}_{\mathrm{soft}}^{\bar{\theta}}(\mathbf{s}_t,\mathbf{a}_t)-Q_{\mathrm{soft}}^{\theta}(\mathbf{s}_t,\mathbf{a}_t)\right)^2\right] JQ(θ)=Estqst,atqat[21(Q^softθˉ(st,at)Qsoftθ(st,at))2]

⚠️You Should Know
因为 q s t , q a t q_{\mathbf{s}_t},q_{\mathbf{a}_t} qst,qat采样的分布可以是任意的。通常来说可以基于当前policy的一些rollouts进行采样 π ( a t ∣ s t ) ∝ exp ⁡ ( 1 α Q s o f t θ ( s t , a t ) ) \pi(\mathbf{a}_t|\mathbf{s}_t)\propto\exp\left(\frac{1}{\alpha}Q_{\mathrm{soft}}^{\theta}(\mathbf{s}_{t},\mathbf{a}_{t})\right) π(atst)exp(α1Qsoftθ(st,at))
对于 π \pi π的分布,通常来说可以采用均匀分布,但更好的选择是使用当前策略,以达到无偏估计的效果。

近似采样与SVGD

然而,在连续空间中,我们仍然需要一种可行的方法来从策略 π ( a t ∣ s t ) ∝ exp ⁡ ( 1 α Q s o f t θ ( s t , a t ) ) \pi(\mathbf{a}_t|\mathbf{s}_t)\propto\exp\left(\frac{1}{\alpha}Q_{\mathrm{soft}}^{\theta}(\mathbf{s}_{t},\mathbf{a}_{t})\right) π(atst)exp(α1Qsoftθ(st,at))中采样,不仅用于采取策略 π π π的行为,还可以在需要时生成动作样本以估计软值函数。由于策略的形式非常广泛,因此直接从它中采样是不可行的。因此需要一种近似采样的方法。

以往的方案大致可以分为两类:基于马尔可夫链蒙特卡罗(MCMC)的采样;从目标分布中训练输出近似样本的随机抽样网络。但是MCMC的方法不太适用于在线推理过程,因此作者将使用Stein variational gradient descent (SVGD) 和amortized SVGD的采样网络。Amortized SVGD有一些比较有趣的性质:

  1. 它为我们提供了一个随机体素网络,可以用于极快地生成样本。
  2. 它可以证明会收敛到 EBM 的后验分布的准确估计
  3. 该算法类似于actor-critic算法

通过学习一个状态条件随机神经网络 a t = f ϕ ( ξ ; s t ) a_t = f^\phi(ξ; s_t) at=fϕ(ξ;st),由 ϕ \phi ϕ 参数化,它将从正常高斯或其他任意分布中提取的噪声样本 ξ ξ ξ 映射到对应于 Q s o f t θ Q^θ_{soft} Qsoftθ 的目标 EBM 的无偏动作样本。将学习到的策略标为 π ϕ ( s t , a t ) \pi^\phi(s_t,a_t) πϕ(st,at),通过KL 散度(KL divergence)进行近似: J π ( ϕ ; s t ) = K L ( π ϕ ( ⋅ ∣ s t ) ∣ ∣ exp ⁡ ( 1 α ( Q s o f t θ ( s t , ⋅ ) − V s o f t θ ) ) ) a t = f ϕ ( ξ ; s t ) , ξ ∼ N \begin{aligned}J_{\pi}(\phi;s_{t})&=KL\left(\pi^{\phi}(\cdot|s_{t})||\exp\left(\frac{1}{\alpha}\big(Q_{soft}^{\theta}(s_{t},\cdot)-V_{soft}^{\theta}\big)\right)\right)\\a_{t}&=f^{\phi}(\xi;s_{t}),\xi\sim\mathcal{N}\end{aligned} Jπ(ϕ;st)at=KL(πϕ(st)∣∣exp(α1(Qsoftθ(st,)Vsoftθ)))=fϕ(ξ;st),ξN

SVGD的方法提供了贪婪的搜索策略: Δ f ϕ ( ⋅ ; s t ) = E a t ∼ π ϕ ∣ κ ( a t , f ϕ ( ⋅ ; s t ) ) ∇ a ′ Q s o f t θ ( s t , a ′ ) ∣ a ′ = a t + α ∇ a ′ κ ( a ′ , f ϕ ( ⋅ ; s t ) ) ∣ a ′ = a t ] , \begin{gathered} \Delta f^{\phi}(\cdot;\mathbf{s}_{t}) =\mathbb{E}_{\mathbf{a}_{t}\sim\pi^{\phi}}\left|\kappa(\mathbf{a}_{t},f^{\phi}(\cdot;\mathbf{s}_{t}))\nabla_{\mathbf{a}^{\prime}}Q_{\mathrm{soft}}^{\theta}(\mathbf{s}_{t},\mathbf{a}^{\prime})\right|_{\mathbf{a}^{\prime}=\mathbf{a}_{t}} \\ \left.+\alpha\left.\nabla_{\mathbf{a'}}\kappa(\mathbf{a'},f^\phi(\cdot;\mathbf{s}_t))\right|_{\mathbf{a'}=\mathbf{a}_t}\right], \end{gathered} Δfϕ(;st)=Eatπϕ κ(at,fϕ(;st))aQsoftθ(st,a) a=at+αaκ(a,fϕ(;st)) a=at],

之后使用链式法则,并将SVGD反向传播到策略网络中,并使用任意基于梯度的优化方法来学习最优采样网络参数。 ∂ J π ( ϕ ; s t ) ∂ ϕ ∝ E ξ [ Δ f ϕ ( ξ ; s t ) ∂ f ϕ ( ξ ; s t ) ∂ ϕ ] , \frac{\partial J_\pi(\phi;\mathbf{s}_t)}{\partial\phi}\propto\mathbb{E}_\xi\left[\Delta f^\phi(\xi;\mathbf{s}_t)\frac{\partial f^\phi(\xi;\mathbf{s}_t)}{\partial\phi}\right], ϕJπ(ϕ;st)Eξ[Δfϕ(ξ;st)ϕfϕ(ξ;st)],

⚠️You Should Know
Δ f ϕ \Delta f^{\phi} Δfϕ不是严格的策略梯度,而是核函数 κ \kappa κ再现核希尔伯特空间(reproducing kernel Hilbert space)的最优方向

伪代码

在这里插入图片描述

Soft Actor-Critic

Haarnoja T, Zhou A, Abbeel P, et al. Soft actor-critic: Off-policy maximum entropy deep reinforcement learning with a stochastic actor[C]//International conference on machine learning. PMLR, 2018: 1861-1870.

用SVGD做近似推断可能存在需要对随机数的分布进行假设的问题同时会使得复杂度和不稳定性提升。除此之外,相比策略梯度或者actor-critic等算法,近似推断可能不那么直接与有效。SAC对策略和价值函数都进行了函数逼近,通过交替使用随机梯度下降优化两个网络。以下是相关算法细节:

价值函数学习目标:

J V ( ψ ) = E s t ∼ D [ 1 2 ( V ψ ( s t ) − E a t ∼ π ϕ [ Q θ ( s t , a t ) − log ⁡ π ϕ ( a t ∣ s t ) ] ) 2 ] J Q ( θ ) = E ( s t , a t ) ∼ D [ 1 2 ( r ( s t , a t ) + γ E s t + 1 ∼ p [ V ψ ‾ ( s t + 1 ) ] − Q θ ( s t , a t ) ) 2 ] \begin{gathered} J_{V}(\psi)=\mathbb{E}_{s_{t}\sim\mathcal{D}}\left[\frac{1}{2}\Big(V_{\psi}(s_{t})-\mathbb{E}_{a_{t}\sim\pi_{\phi}}\big[Q_{\theta}(s_{t},a_{t})-\log\pi_{\phi}(a_{t}|s_{t})\big]\Big)^{2}\right] \\ J_{Q}(\theta)=\mathbb{E}_{(s_{t},a_{t})\sim\mathbb{D}}\left[{\frac{1}{2}}\left(r(s_{t},a_{t})+\gamma\mathbb{E}_{s_{t+1}\sim p}[V_{\overline{\psi}}(s_{t+1})]-Q_{\theta}(s_{t},a_{t})\right)^{2}\right] \end{gathered} JV(ψ)=EstD[21(Vψ(st)Eatπϕ[Qθ(st,at)logπϕ(atst)])2]JQ(θ)=E(st,at)D[21(r(st,at)+γEst+1p[Vψ(st+1)]Qθ(st,at))2]

策略函数学习目标: J π ( ϕ ) = E s t ∼ D , ϵ t ∼ N [ log ⁡ π ϕ ( f ϕ ( ϵ t ; s t ) ∣ s t ) − Q θ ( s t , f ϕ ( ϵ t ; s t ) ) ] \begin{aligned}J_\pi(\phi)=\mathbb{E}_{\mathbf{s}_t\sim\mathcal{D},\epsilon_t\sim\mathcal{N}}[\log\pi_\phi(f_\phi(\epsilon_t;\mathbf{s}_t)|\mathbf{s}_t)-Q_\theta(\mathbf{s}_t,f_\phi(\epsilon_t;\mathbf{s}_t))]\end{aligned} Jπ(ϕ)=EstD,ϵtN[logπϕ(fϕ(ϵt;st)st)Qθ(st,fϕ(ϵt;st))]

利用两个动作价值函数网络,每次使用Q网络时,使用较小的那一个: L Q ( ω ) = E ( s t , a t , r t , s t + 1 ) ∼ R [ 1 2 ( Q ω ( s t , a t ) − ( r t + γ V ω − ( s t + 1 ) ) ) 2 ] = E ( s t , a t , r t , s t + 1 ) ∼ R , a t + 1 ∼ π θ ( ⋅ ∣ s t + 1 ) [ 1 2 ( Q ω ( s t , a t ) − ( r t + γ ( min ⁡ j = 1 , 2 Q ω j − ( s t + 1 , a t + 1 ) − α log ⁡ π ( a t + 1 ∣ s t + 1 ) ) ) ) 2 ] \begin{aligned} L_{Q}(\omega)& =\mathbb{E}_{(s_t,a_t,r_t,s_{t+1})\sim R}\left[\frac12\left(Q_\omega(s_t,a_t)-(r_t+\gamma V_{\omega^-}(s_{t+1}))\right)^2\right] \\ &=\mathbb{E}_{(s_t,a_t,r_t,s_{t+1})\sim R,a_{t+1}\sim\pi_\theta(\cdot|s_{t+1})}\left[\frac{1}{2}\left(Q_\omega(s_t,a_t)-(r_t+\gamma(\min_{j=1,2}Q_{\omega_j^-}(s_{t+1},a_{t+1})-\alpha\log\pi(a_{t+1}|s_{t+1})))\right)^2\right] \end{aligned} LQ(ω)=E(st,at,rt,st+1)R[21(Qω(st,at)(rt+γVω(st+1)))2]=E(st,at,rt,st+1)R,at+1πθ(st+1)[21(Qω(st,at)(rt+γ(j=1,2minQωj(st+1,at+1)αlogπ(at+1st+1))))2]

重参数化技巧自动调整熵正则项参考《动手学强化学习》SAC 算法

伪代码

在这里插入图片描述

在这里插入图片描述

代码实践

连续动作空间

import gymnasium as gym
import numpy as np
from tqdm import tqdm
import torch
import torch.nn.functional as F
import utilclass PolicyNetContinuous(torch.nn.Module):def __init__(self, state_dim, hidden_dim, action_dim, action_bound):super(PolicyNetContinuous, self).__init__()self.fc1 = torch.nn.Linear(state_dim, hidden_dim)self.mu = torch.nn.Linear(hidden_dim, action_dim)self.std = torch.nn.Linear(hidden_dim, action_dim)self.action_bound = action_bounddef forward(self, x):x = F.relu(self.fc1(x))mu = self.mu(x)std = F.softplus(self.std(x))dist = torch.distributions.Normal(mu, std)normal_sample = dist.rsample()  # rsample()是重参数化采样log_prob = dist.log_prob(normal_sample)action = torch.tanh(normal_sample)# 计算tanh_normal分布的对数概率密度log_prob = log_prob - torch.log(1 - torch.tanh(action).pow(2) + 1e-7)action = action * self.action_boundreturn action, log_probclass QValueNetContinuous(torch.nn.Module):def __init__(self, state_dim, hidden_dim, action_dim):super(QValueNetContinuous, self).__init__()self.fc1 = torch.nn.Linear(state_dim + action_dim, hidden_dim)self.fc2 = torch.nn.Linear(hidden_dim, hidden_dim)self.fc_out = torch.nn.Linear(hidden_dim, 1)def forward(self, x, a):cat = torch.cat([x, a], dim=1)x = F.relu(self.fc1(cat))x = F.relu(self.fc2(x))return self.fc_out(x)class SACContinuous:''' 处理连续动作的SAC算法 '''def __init__(self, state_dim, hidden_dim, action_dim, action_bound, actor_lr, critic_lr, gamma,alpha_lr, target_entropy, tau, buffer_size, minimal_size, batch_size,device, numOfEpisodes, env):self.actor = PolicyNetContinuous(state_dim, hidden_dim, action_dim, action_bound).to(device)self.critic_1 = QValueNetContinuous(state_dim, hidden_dim, action_dim).to(device)self.critic_2 = QValueNetContinuous(state_dim, hidden_dim, action_dim).to(device)self.target_critic_1 = QValueNetContinuous(state_dim, hidden_dim, action_dim).to(device)self.target_critic_2 = QValueNetContinuous(state_dim, hidden_dim, action_dim).to(device)# 令目标Q网络的初始参数和Q网络一样self.target_critic_1.load_state_dict(self.critic_1.state_dict())self.target_critic_2.load_state_dict(self.critic_2.state_dict())self.actor_optimizer = torch.optim.Adam(self.actor.parameters(), lr=actor_lr)self.critic_1_optimizer = torch.optim.Adam(self.critic_1.parameters(), lr=critic_lr)self.critic_2_optimizer = torch.optim.Adam(self.critic_2.parameters(), lr=critic_lr)# 使用alpha的log值,可以使训练结果比较稳定self.log_alpha = torch.tensor(np.log(0.01), dtype=torch.float)self.log_alpha.requires_grad = True  # 可以对alpha求梯度self.log_alpha_optimizer = torch.optim.Adam([self.log_alpha], lr=alpha_lr)self.target_entropy = target_entropyself.gamma = gammaself.tau = tauself.device = deviceself.env = envself.numOfEpisodes = numOfEpisodesself.buffer_size = buffer_sizeself.minimal_size = minimal_sizeself.batch_size = batch_sizedef take_action(self, state):state = torch.FloatTensor(np.array([state])).to(self.device)action = self.actor(state)[0]return [action.item()]def calc_target(self, rewards, next_states, terminateds, truncateds):next_action, log_prob = self.actor(next_states)entropy = -log_probq1_value = self.target_critic_1(next_states, next_action)q2_value = self.target_critic_2(next_states, next_action)next_value = torch.min(q1_value, q2_value) + self.log_alpha.exp() * entropytd_target = rewards + self.gamma * next_value * (1 - terminateds + truncateds)return td_targetdef soft_update(self, net, target_net):for param_target, param in zip(target_net.parameters(), net.parameters()):param_target.data.copy_(param_target.data * (1.0 - self.tau) + param.data * self.tau)def update(self, transition_dict):states = torch.tensor(np.array(transition_dict['states']), dtype=torch.float).to(self.device)actions = torch.tensor(np.array(transition_dict['actions']), dtype=torch.float).view(-1, 1).to(self.device)rewards = torch.tensor(transition_dict['rewards'], dtype=torch.float).view(-1, 1).to(self.device)next_states = torch.tensor(np.array(transition_dict['next_states']), dtype=torch.float).to(self.device)terminateds = torch.tensor(transition_dict['terminateds'], dtype=torch.float).view(-1, 1).to(self.device)truncateds = torch.tensor(transition_dict['truncateds'], dtype=torch.float).view(-1, 1).to(self.device)rewards = (rewards + 8.0) / 8.0# 更新两个Q网络td_target = self.calc_target(rewards, next_states, terminateds, truncateds)critic_loss1 = torch.mean(F.mse_loss(td_target.detach(), self.critic_1(states, actions)))critic_loss2 = torch.mean(F.mse_loss(td_target.detach(), self.critic_2(states, actions)))self.critic_1_optimizer.zero_grad()critic_loss1.backward()self.critic_1_optimizer.step()self.critic_2_optimizer.zero_grad()critic_loss2.backward()self.critic_2_optimizer.step()# 更新策略网络new_actions, log_prob = self.actor(states)entropy = -log_probq1_value = self.critic_1(states, new_actions)q2_value = self.critic_2(states, new_actions)next_value = torch.min(q1_value, q2_value)actor_loss = torch.mean(-self.log_alpha.exp() * entropy - next_value)self.actor_optimizer.zero_grad()actor_loss.backward()self.actor_optimizer.step()# 更新alpha值alpha_loss = torch.mean(self.log_alpha.exp() * (entropy - self.target_entropy).detach())self.log_alpha_optimizer.zero_grad()alpha_loss.backward()self.log_alpha_optimizer.step()self.soft_update(self.critic_1, self.target_critic_1)self.soft_update(self.critic_2, self.target_critic_2)def SACtrain(self):replay_buffer = util.ReplayBuffer(self.buffer_size)returnList = []for i in range(10):with tqdm(total=int(self.numOfEpisodes / 10), desc='Iteration %d' % i) as pbar:for episode in range(int(self.numOfEpisodes / 10)):# initialize statestate, info = self.env.reset()terminated = Falsetruncated = FalseepisodeReward = 0# Loop for each step of episode:while (not terminated) or (not truncated):action = self.take_action(state)next_state, reward, terminated, truncated, info = self.env.step(action)replay_buffer.add(state, action, reward, next_state, terminated, truncated)state = next_stateepisodeReward += reward# 当buffer数据的数量超过一定值后,才进行Q网络训练if replay_buffer.size() > self.minimal_size:b_s, b_a, b_r, b_ns, b_te, b_tr = replay_buffer.sample(self.batch_size)transition_dict = {'states': b_s,'actions': b_a,'next_states': b_ns,'rewards': b_r,'terminateds': b_te,'truncateds': b_tr}self.update(transition_dict)if terminated or truncated:breakreturnList.append(episodeReward)if (episode + 1) % 10 == 0:  # 每10条序列打印一下这10条序列的平均回报pbar.set_postfix({'episode':'%d' % (self.numOfEpisodes / 10 * i + episode + 1),'return':'%.3f' % np.mean(returnList[-10:])})pbar.update(1)return returnListdef test01():device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")env = gym.make("Pendulum-v1")agent = SACContinuous(state_dim=env.observation_space.shape[0],hidden_dim=256,action_dim=env.action_space.shape[0],action_bound=env.action_space.high[0],actor_lr=3e-4,critic_lr=3e-3,gamma=0.99,alpha_lr=3e-4,target_entropy=-env.action_space.shape[0],tau=0.005,buffer_size=100000,minimal_size=1000,batch_size=64,device=device,numOfEpisodes=200,env=env)returnLists1 = agent.SACtrain()ReturnList = []ReturnList.append(util.smooth([returnLists1], sm=20))labelList = ['SAC']util.PlotReward(200, ReturnList, labelList, 'Pendulum-v1')np.save("D:\LearningRL\Hands-on-RL\SAC_Pendulum\ReturnData\SAC_v1_1.npy", returnLists1)env.close()

结果:

在这里插入图片描述
可以看到SAC在连续动作空间的任务中表现优秀。

离散动作空间

⚠️You Should Know
对于离散的动作空间,策略网络和价值网络的网络结构将发生如下改变:

  • 策略网络的输出修改为在离散动作空间上的 softmax 分布;
    该策略网络输出一个离散的动作分布,所以在价值网络的学习过程中,不需要再对下一个动作 a t + 1 a_{t+1} at+1进行采样,而是直接通过概率计算来得到下一个状态的价值。同理,在 α \alpha α的损失函数计算中,也不需要再对动作进行采样。
  • 价值网络直接接收状态和离散动作空间的分布作为输入。
class PolicyNet(torch.nn.Module):def __init__(self, state_dim, hidden_dim, action_dim):super(PolicyNet, self).__init__()self.fc1 = torch.nn.Linear(state_dim, hidden_dim)self.fc2 = torch.nn.Linear(hidden_dim, action_dim)def forward(self, x):x = F.relu(self.fc1(x))return F.softmax(self.fc2(x), dim=1)class QValueNet(torch.nn.Module):''' 只有一层隐藏层的Q网络 '''def __init__(self, state_dim, hidden_dim, action_dim):super(QValueNet, self).__init__()self.fc1 = torch.nn.Linear(state_dim, hidden_dim)self.fc2 = torch.nn.Linear(hidden_dim, action_dim)def forward(self, x):x = F.relu(self.fc1(x))return self.fc2(x)class SACContinuous:''' 处理连续动作的SAC算法 '''def __init__(self, state_dim, hidden_dim, action_dim, actor_lr, critic_lr, gamma,alpha_lr, target_entropy, tau, buffer_size, minimal_size, batch_size,device, numOfEpisodes, env):self.actor = PolicyNet(state_dim, hidden_dim, action_dim).to(device)self.critic_1 = QValueNet(state_dim, hidden_dim, action_dim).to(device)self.critic_2 = QValueNet(state_dim, hidden_dim, action_dim).to(device)self.target_critic_1 = QValueNet(state_dim, hidden_dim, action_dim).to(device)self.target_critic_2 = QValueNet(state_dim, hidden_dim, action_dim).to(device)# 令目标Q网络的初始参数和Q网络一样self.target_critic_1.load_state_dict(self.critic_1.state_dict())self.target_critic_2.load_state_dict(self.critic_2.state_dict())self.actor_optimizer = torch.optim.Adam(self.actor.parameters(), lr=actor_lr)self.critic_1_optimizer = torch.optim.Adam(self.critic_1.parameters(), lr=critic_lr)self.critic_2_optimizer = torch.optim.Adam(self.critic_2.parameters(), lr=critic_lr)# 使用alpha的log值,可以使训练结果比较稳定self.log_alpha = torch.tensor(np.log(0.01), dtype=torch.float)self.log_alpha.requires_grad = True  # 可以对alpha求梯度self.log_alpha_optimizer = torch.optim.Adam([self.log_alpha], lr=alpha_lr)self.target_entropy = target_entropyself.gamma = gammaself.tau = tauself.device = deviceself.env = envself.numOfEpisodes = numOfEpisodesself.buffer_size = buffer_sizeself.minimal_size = minimal_sizeself.batch_size = batch_size# 根据动作概率分布随机采样def take_action(self, state):state = torch.tensor(np.array([state]), dtype=torch.float).to(self.device)action_probs = self.actor(state)action_dist = torch.distributions.Categorical(action_probs)action = action_dist.sample()return action.item()def calc_target(self, rewards, next_states, terminateds, truncateds):next_probs = self.actor(next_states)next_log_probs = torch.log(next_probs + 1e-8)entropy = -torch.sum(next_probs * next_log_probs, dim=1, keepdim=True)q1_value = self.target_critic_1(next_states)q2_value = self.target_critic_2(next_states)next_value = torch.sum(next_probs * torch.min(q1_value, q2_value),dim=1,keepdim=True)  # 直接根据概率计算期望next_value = next_value + self.log_alpha.exp() * entropytd_target = rewards + self.gamma * next_value * (1 - terminateds + truncateds)return td_targetdef soft_update(self, net, target_net):for param_target, param in zip(target_net.parameters(), net.parameters()):param_target.data.copy_(param_target.data * (1.0 - self.tau) + param.data * self.tau)def update(self, transition_dict):states = torch.tensor(np.array(transition_dict['states']), dtype=torch.float).to(self.device)actions = torch.tensor(transition_dict['actions']).view(-1, 1).to(self.device)rewards = torch.tensor(transition_dict['rewards'], dtype=torch.float).view(-1, 1).to(self.device)next_states = torch.tensor(np.array(transition_dict['next_states']), dtype=torch.float).to(self.device)terminateds = torch.tensor(transition_dict['terminateds'], dtype=torch.float).view(-1, 1).to(self.device)truncateds = torch.tensor(transition_dict['truncateds'], dtype=torch.float).view(-1, 1).to(self.device)# 更新两个Q网络td_target = self.calc_target(rewards, next_states, terminateds, truncateds)critic_value1 = self.critic_1(states).gather(1, actions)critic_loss1 = torch.mean(F.mse_loss(critic_value1, td_target.detach()))critic_value2 = self.critic_2(states).gather(1, actions)critic_loss2 = torch.mean(F.mse_loss(critic_value2, td_target.detach()))self.critic_1_optimizer.zero_grad()critic_loss1.backward()self.critic_1_optimizer.step()self.critic_2_optimizer.zero_grad()critic_loss2.backward()self.critic_2_optimizer.step()# 更新策略网络probs = self.actor(states)log_probs = torch.log(probs + 1e-8)entropy = -torch.sum(log_probs * probs, dim=1, keepdim=True)q1_value = self.critic_1(states)q2_value = self.critic_2(states)next_value = torch.sum(probs * torch.min(q1_value, q2_value),dim=1,keepdim=True)  # 直接根据概率计算期望actor_loss = torch.mean(-self.log_alpha.exp() * entropy - next_value)self.actor_optimizer.zero_grad()actor_loss.backward()self.actor_optimizer.step()# 更新alpha值alpha_loss = torch.mean(self.log_alpha.exp() * (entropy - self.target_entropy).detach())self.log_alpha_optimizer.zero_grad()alpha_loss.backward()self.log_alpha_optimizer.step()self.soft_update(self.critic_1, self.target_critic_1)self.soft_update(self.critic_2, self.target_critic_2)def SACtrain(self):replay_buffer = util.ReplayBuffer(self.buffer_size)returnList = []for i in range(10):with tqdm(total=int(self.numOfEpisodes / 10), desc='Iteration %d' % i) as pbar:for episode in range(int(self.numOfEpisodes / 10)):# initialize statestate, info = self.env.reset()terminated = Falsetruncated = FalseepisodeReward = 0# Loop for each step of episode:while (not terminated) or (not truncated):action = self.take_action(state)next_state, reward, terminated, truncated, info = self.env.step(action)replay_buffer.add(state, action, reward, next_state, terminated, truncated)state = next_stateepisodeReward += reward# 当buffer数据的数量超过一定值后,才进行Q网络训练if replay_buffer.size() > self.minimal_size:b_s, b_a, b_r, b_ns, b_te, b_tr = replay_buffer.sample(self.batch_size)transition_dict = {'states': b_s,'actions': b_a,'next_states': b_ns,'rewards': b_r,'terminateds': b_te,'truncateds': b_tr}self.update(transition_dict)if terminated or truncated:breakreturnList.append(episodeReward)if (episode + 1) % 10 == 0:  # 每10条序列打印一下这10条序列的平均回报pbar.set_postfix({'episode':'%d' % (self.numOfEpisodes / 10 * i + episode + 1),'return':'%.3f' % np.mean(returnList[-10:])})pbar.update(1)return returnList

结果:
在这里插入图片描述

参考与推荐

[1] Soft actor-critic: Off-policy maximum entropy deep reinforcement learning with a stochastic actor, 2018, arXiv
[2] Soft Actor-Critic Algorithms and Applications, 2019, arXiv
[3] Reinforcement Learning with Deep Energy-Based Policies, 2017, arXiv
[4] 伯禹AI
[5] 动手学强化学习
[6] https://zhuanlan.zhihu.com/p/444441890
[7] https://zhuanlan.zhihu.com/p/70360272/
[8] https://bair.berkeley.edu/blog/2017/10/06/soft-q-learning/
[9] https://towardsdatascience.com/entropy-in-soft-actor-critic-part-2-59821bdd5671
[10] https://medium.com/towards-data-science/entropy-in-soft-actor-critic-part-1-92c2cd3a3515
[11] Haarnoja T, Zhou A, Abbeel P, et al. Soft actor-critic: Off-policy maximum entropy deep reinforcement learning with a stochastic actor[C]//International conference on machine learning. PMLR, 2018: 1861-1870.

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

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

相关文章

iOS移动应用安全加固:保护您的App免受恶意攻击的重要步骤

目录 iOS移动应用安全加固:保护您的App免受恶意攻击的重要步骤 摘要 引言 一、APP加固的概念 二、APP加固方案的比较 三、保护iOS应用的安全 四、总结 参考资料 摘要 本文介绍了移动应用程序(App)加固的概念和流程,以及市…

【Unity细节】Unity中如何让组件失活而不是物体失活

👨‍💻个人主页:元宇宙-秩沅 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 本文由 秩沅 原创 😶‍🌫️收录于专栏:unity细节和bug 😶‍🌫️优质专栏 ⭐【…

Python之Django

web应用程序 # Django框架是一款专门用来开发web应用的框架 # Web应用程序是一种可以通过浏览器访问的应用程序, B/S架构 案例:淘宝网、京东... # 应用程序有两种模式: C/S:客户端/服务器端程序,这类程序一般独立运行 B/S:…

Python之文件与文件夹操作及 pytest 测试习题

目录 1、文本文件读写基础。编写程序,在 当前目录下创建一个文本文件 test.txt,并向其中写入字符串 hello world。2、编写一个程序 demo.py,要求运行该程序后,生成 demo_new.py 文件,其中内容与demo.py 一样&#xff0…

文件管理技巧:按文件容量大小分类,自动移动至目标文件夹的方法

按文件容量大小分类可以帮助快速识别和筛选出不同大小的文件。这样做有很多好处。首先,可以轻松地查找和访问特定大小的文件,提高工作效率。其次,通过将不同大小的文件分类,可以更好地了解和掌控文件的使用情况,避免存…

springboot高校全流程考勤系统-计算机毕设 附源码 27637

Springboot高校全流程考勤系统 摘 要 本文针对高校考勤等问题,对其进行研究分析,然后开发设计出高校全流程考勤系统以解决问题。高校全流程考勤系统系统主要功能模块包括:考勤签到、课程信息、考勤情况、申请记录列表等,系统功能设…

牛客、赛码网OJ调试(全)

现在无论开发还是测试,面试的时候都需要考察代码能力。 从测试的职业发展来看,现在市场上对于纯功能测试的需求很少,招聘方均要求面试者一方面具备测试基础能力,也要求有点代码能力。 对于测试来说,除了测试开发&#…

自定义类型:联合和枚举

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 1. 联合体 1.1 联合体类型的声明 1.2 联合体的特点 1.3 相同成员的结构体和联合体对比 1.4 联合体大小的计算 1.5 联合的一个练习 2. 枚举类型 2.1 枚举类型的声明…

Linux基础开发工具之分布式版本控制系统Git

文章目录 1.Git是什么?1.1介绍1.2影响世界的大牛1.3English Words 2.Git常用指令2.1Git三板斧2.2解决冲突2.3黑名单文件2.4删除本地远端 1.Git是什么? 1.1介绍 史上最浅显易懂的Git教程! git是一个软件 gitee/github是一个网站但是他们的主…

linux 下非sudo安装cmake

1.查看位数 getconf LONG_BIT2.下载对应压缩包 Download CMake Source Distribution 未编译源代码 Binary Distribution已经编译好的 3.解压至文件夹 tar -zxvf cmake-3.28.0-rc4-linux-x86_64.tar.gz 4.添加环境变量 vi ~/.bashrc 最后一行添加 写到bin目录 export P…

基于element-plus定义表格行内编辑配置化

文章目录 前言一、新增table组件二、使用步骤 前言 在 基于element-plus定义表单配置化 基础上,封装个Element-plus的table表格 由于表格不同于form组件,需自定义校验器,以下组件配置了单个校验,及提交统一校验方法,且…

spring-cloud-stream

系列文章目录 第一章 Java线程池技术应用 第二章 CountDownLatch和Semaphone的应用 第三章 Spring Cloud 简介 第四章 Spring Cloud Netflix 之 Eureka 第五章 Spring Cloud Netflix 之 Ribbon 第六章 Spring Cloud 之 OpenFeign 第七章 Spring Cloud 之 GateWay 第八章 Sprin…

Gradio App生产环境部署教程

如果机器学习模型没有投入生产供人们使用,就无法充分发挥其潜力。 根据我们的经验,将模型投入生产的最常见方法是为其创建 API。 然而,我们发现这个过程对于 ML 开发人员来说可能相当令人畏惧,特别是如果他们不熟悉 Web 开发的话。…

汽车ECU的虚拟化技术初探(一)

目录 1.为什么要提汽车ECU的虚拟化? 2.虚拟化技术分类 2.1 硬件虚拟化 2.2 操作系统虚拟化 问题引入: Hypervisor是如何来管理和隔离硬件资源,保证各个不同功能的应用程序的资源使用安全和资源调度?没有MMU就做不了虚拟化&am…

4.HTML网页开发的工具

4. 网页开发的工具 4.1 快捷键 4.1.1 快速复制一行 快捷键:shiftalt下箭头(上箭头) 或者ctrlc 然后 ctrlv 4.1.2 选定多个相同的单词 快捷键: ctrld 4.1.3 添加多个光标 快捷键:ctrlalt上箭头(下箭头&…

CS224W6.2——深度学习基础

在本文中,我们回顾了深度学习的概念和技术,这些概念和技术对理解图神经网络至关重要。从将机器学习表述为优化问题开始,介绍了目标函数、梯度下降、非线性和反向传播的概念。 文章目录 1. 大纲2. 优化问题2.1 举例损失函数 3. 如何优化目标函…

MySQL on duplicate key update用法

基本使用方法 public static final String SQL_TQI_SINK "insert into " ConfigureContext.get(ConfigKeyConstants.MYSQL_TABLE_TQI) " \n" "(mile_km, mile_start_km, mile_start_m, is_out, tqi_alig_l, \n" "tqi_alig_r, tqi_surf_l…

Redis系列-Redis性能优化与安全【9】

目录 Redis系列-Redis性能优化与安全【9】Redis性能优化策略Redis安全设置与防护措施Redis监控与诊断工具介绍 七、Redis应用案例与实战八、Redis未来发展与趋势 个人主页: 【⭐️个人主页】 需要您的【💖 点赞关注】支持 💯 Redis系列-Redis性能优化与安…

2023年第十六届山东省职业院校技能大赛高职组“信息安全管理与评估”赛项规程

第十六届山东省职业院校技能大赛 高职组“信息安全管理与评估”赛项规程 一、赛项名称 赛项名称:信息安全管理与评估 英文名称:Information Security Management and Evaluation 赛项组别:高职组 赛项归属:电子与信息大类 二…

运行npm install卡住不动的几种解决方案

在前端开发经常会遇到运行npm install 来安装工具包一直卡住不动,为此这里提供几种解决方案,供大家参考学习,不足之处还请指正。 第一种方案、首先检查npm代理,是否已经使用国内镜像 // 执行以下命令查看是否为国内镜像 npm con…