百度工程师浅析强化学习

news2024/12/22 19:52:29

作者 | Jane

导读

本文主要介绍了强化学习(Reinforcement Learning,RL)的基本概念以及什么是RL。强化学习让智能体通过与环境的交互来学习如何做出决策,以获得最大的累积奖励。文章还介绍了策略梯度(Policy Gradient,PG)和近端策略优化(PPO)等强化学习算法。

全文7099字,预计阅读时间18分钟。

01 强化学习(Reinforcement Learning,RL)

1.1 基本概念&什么是RL

强化学习(reinforcement learning,RL)专注于让智能体(agent)通过与环境的交互来学习如何做出决策,以使其在不断变化且不确定的环境中获得最大的累积奖励。

这个过程可以用以下几个要素来描述:

智能体(Agent):智能体是执行动作并与环境进行交互的实体。它可以是一个机器人、一个虚拟角色、一个算法等。

环境(Environment):环境包括智能体所处的所有上下文,包括外部条件、状态变量和其他影响智能体的因素。

动作(Action):智能体可以在环境中执行的操作,这些操作可能会改变环境的状态。

状态(State):状态是描述环境的当前情况的信息。智能体的决策通常依赖于当前状态。

奖励(Reward):在每个时间步,智能体执行一个动作后会获得一个奖励信号,用于指示动作的好坏。目标是最大化累积奖励。

策略(Policy):策略定义了智能体如何根据当前状态选择动作。强化学习的目标之一是找到一个最优策略,使智能体能够获得最大的累积奖励。

价值函数(Value Function):价值函数衡量了在某个状态下执行某个策略能够获得的预期累积奖励。这个函数帮助智能体评估不同状态的重要性。

学习过程:强化学习的核心是智能体通过尝试不同的动作并观察奖励信号来学习适应性策略。它可以使用不同的算法,如Q-learning、Deep Q-Networks(DQN)、Policy Gradient等。

图片

△图1 强化学习过程

其中状态(State)是对整个环境的完整描述,包括了所有对智能体的决策和行动有影响的信息。状态通常用来指导智能体的决策,因为它提供了有关环境当前状态的全部信息。

观测(Observation)则是对状态的一种抽象描述,它可能会忽略或省略一些状态信息。在实际问题中,有时候智能体无法直接观测到完整的状态,而只能获取到一部分信息,即观测。这可能是因为某些信息无法直接测量,或者因为为了简化问题而对状态进行了抽象。

因此,智能体基于它的观测来做出决策,而不是直接使用完整的状态。这就需要智能体具备从观测中学习有关状态的信息的能力,以便更好地进行决策和行动。

下面举一些可应用强化学习的示例:

1、在电子游戏中,摇杆是智能体,主机是环境,显示屏上的游戏画面(像素)是观测,击杀怪物得分则是奖励。

2、在阿法狗围棋对弈中,阿法狗是智能体,人类棋手是环境,棋局是观测,围棋的输赢则是奖励。

图片

在强化学习中,智能体持续与环境进行交互,采取一系列的动作,从而形成一个状态和动作的序列,这个序列被称为轨迹(trajectory):

图片

一个交互序列被称为一个回合(episode),在每个回合中,智能体根据当前状态选择动作,与环境互动,并根据奖励信号进行学习和策略优化,以获得最大化累积奖励。

这里需要注意的是,环境对我们来说是黑盒,是不可控的,它在当前状态下跳转到下一状态是服从一定的分布的,也就是说它是有一定的随机性的,那么它产出的奖励也具有了一定的随机性。我们可控的是actor的policy,即可以通过学习,让policy在面对状态 s 时采取一个能让他获得最大奖励的action。所以实际上我们的目标是最大化期望的累积奖励(expected cumulative reward)

1.2 RL和监督学习的区别

监督学习:

1. 数据独立同分布(i.i.d.): 监督学习假设样本是从一个未知分布中独立地采样得到的,数据之间没有时序关联。

2. 标签信息: 在监督学习中,每个样本都有正确的标签信息,即模型需要学习从输入到标签的映射关系。

3. 训练目标:监督学习的目标是使模型的预测尽可能地接近真实标签,通常通过最小化预测与真实标签之间的损失函数来实现。

4. 局限性: 监督学习在需要大量标记数据、难以获取所有可能状态的标签信息或者数据之间存在时序关联的情况下可能受限。

强化学习:

1. 时序关联数据: 强化学习中智能体的观测是时序关联的,当前的决策会影响未来的观测和奖励。

2. 延迟奖励: 强化学习中智能体在做出决策后不会立即得到奖励,奖励可能在未来的时间步骤才会出现,这就需要智能体通过试错来学习哪些决策导致了最终的奖励。

3. 探索与学习: 强化学习中智能体需要在探索和利用之间找到平衡,以发现能够最大化长期累积奖励的有效策略。

4. 超越人类表现: 强化学习的一个优势在于它可以在某些情况下超越人类表现,因为智能体可以自主探索环境并发现人类难以想象的优化策略。

1.3 RL算法类型

按不同类型的智能体方法划分:

1.基于价值的智能体(Value-Based Agents): 智能体显式地学习价值函数,然后从学习到的价值函数中隐式地推导出策略,例如Q-learning和Sarsa,这些算法在训练过程中更新状态-动作值函数(Q值),然后根据Q值选择最佳动作。

2.基于策略的智能体(Policy-Based Agents): 智能体直接学习策略,即在给定状态下选择每个动作的概率分布。策略梯度(Policy Gradient)方法是一种常见的基于策略的强化学习方法,它通过梯度下降或其他优化算法来更新策略参数,以最大化累积奖励。

3.演员-评论员智能体(Actor-Critic Agents): 这是一种综合了前两种方法的智能体。演员(Actor)负责学习策略,而评论员(Critic)负责学习价值函数。演员根据策略选择动作,评论员基于环境的反馈和学习的价值函数提供有关动作的评估。这种结合可以帮助解决价值和策略学习中的某些困难问题,并且在实际应用中表现出很好的性能。

按是否需要对环境建模来划分:

1.Model-Based 方法:需要对环境建模,包括状态转移函数(描述状态之间如何转换)和奖励函数(描述在每个状态下获得的奖励)。一旦模型被建立,智能体可以在模型中进行"心算",即通过模型进行推演,而无需真正地与环境进行交互。这使得智能体可以在模型上进行试错,寻找在真实环境中表现良好的策略。然而,这种方法的关键挑战在于如何准确地建立一个模型,因为环境可能非常复杂且不确定。

2.Model-Free 方法:不需要显式地构建环境模型,而是智能体直接与环境交互,通过尝试和观察来学习策略。这种方法通常需要更多的交互时间和数据,因为智能体需要通过实际的试验来逐步改进策略。Model-free 方法可以分为基于价值和基于策略的方法,前者关注学习状态或状态-动作的价值函数,后者则直接学习策略。

在实际应用中,"model-based"方法可能需要更少的交互次数来找到较优策略,因为它在模型上进行预测和规划。然而,这个模型的建立可能会面临挑战,尤其是在复杂和不确定的环境中。"model-free"方法则更加适用于无法准确建模的情况,但可能需要更多的实际交互来学习策略。选择使用哪种方法通常取决于问题的性质以及可用的数据和计算资源。

02 策略梯度(Policy Gradient,PG)

强化学习的3个核心组成部分:actor(policy、agent)、环境奖励函数。环境和奖励函数不是我们可以控制的,我们能做的是调整Actor的策略,使得它获得最大的奖励。策略一般记作 π \pi π,如果使用深度学习来做强化学习,策略就是一个network,其参数记作 θ \theta θ。其输入是观测(或states),输出是动作空间的一个概率分布 。(同一个states,同一个env,所采去的action也是可能不同的,所以这里是概率分布,action是具有一定的随机性的)。

图片

△图2 神经网络作为策略

奖励的稀疏性和延迟性?

如果把玩一场游戏看做一个回合(episode),在一个episode里,actor不断与环境进行交互,即在s1时采取了action a1,并获得奖励r1,环境接收a1后跳转到s2,actor看到s2后采取了action a2,并获得奖励r3,…,直至达到某个条件结束游戏。这一个episode里,把环境输出 s 和actor输出 a 以及奖励输出 r 的序列组合起来,就形成了一个轨迹(trajactory):

图片

图片

△图3 最大化奖励

计算某个轨迹发生的概率就是:

图片

目标是通过调整actor的参数 θ \theta θ,最大化整个轨迹中获得的total奖励: R ( τ ) = ∑ t = 1 T r t R(\tau)=\sum_{t=1}^T r^t R(τ)=t=1Trt

但是由于采取action的随机性,环境输出states的随机性,得到的reward也是有随机性的,所以在计算中我们需要最大化的不是某个回合的奖励,而是最大化期望奖励。(直观上理解:平均意义上的奖励最大化了,那么某个具体的回合他的奖励也不会小到哪儿去),所以目标就是最大化 R ( τ ) R(\tau) R(τ)的期望值

图片

最大化问题,可以使用梯度上升(gradient ascent)来求解,使用梯度更新公式来更新参数,这就是策略梯度算法。(核心就是采样数据,更新参数,再采样数据,再更新参数。。。)

图片

接下来就是计算 R θ ˉ \bar{R_{\theta}} Rθˉ的梯度

图片

再看下 R θ ˉ = ∑ τ R ( τ ) p θ ( τ ) = E τ ∼ p θ [ R ( τ ) ] \bar{R_{\theta}} =\sum_{\tau} R(\tau)p_{\theta}(\tau) = E_{\tau \sim p_{\theta}} [R(\tau)] Rθˉ=τR(τ)pθ(τ)=Eτpθ[R(τ)] 期望的这个公式的意义:从分布 p θ ( τ ) p_{\theta}(\tau) pθ(τ)采样一个轨迹 τ \tau τ,计算 R ( τ ) R(\tau) R(τ)的期望值,就是期望奖励(expected reward)。我们要最大化期望奖励。即相当于我们穷举所有的轨迹,每个轨迹对应一个概率。但这个期望无法计算,因为没法穷举所有的轨迹。如何解决呢?=>大数定理:做N次采样,用平均代替期望。

图片

注意, p ( s 1 ) p(s_1) p(s1) p ( s t + 1 ∣ s _ t , a _ t ) p(s_{t+1}|s\_t,a\_t) p(st+1s_t,a_t)来自环境,由环境决定, θ \theta θ与 无关,因此 ∇ log ⁡ p ( s 1 ) = 0 \nabla \log p(s_1)=0 logp(s1)=0 ∇ ∑ t = 1 T log ⁡ p ( s t + 1 ∣ s _ t , a _ t ) = 0 \nabla\sum_{t=1}^{T}\log p(s_{t+1}|s\_t,a\_t)=0 t=1Tlogp(st+1s_t,a_t)=0

2.1 2个问题

接下来探讨2个问题:

1.如果采取每个action的奖励都是正的,只是有大有小,会出现什么问题?

2.整个episode里每个(s, a)pair都使用了同一个total reward合适吗?这样公平吗?一场游戏输了那里面的每个step的操作都是失败的吗?一场游戏赢了,中间就不会有失误吗?

如何解决这些问题?

解决问题1:增加baseline

如果采取每个action的奖励都是正的,只是有大有小,会出现什么问题?

例如如果所有的 r >= 10,那么r=10就相对来说是『负』的。也就是说在采样中,没有被采样到的动作的概率会被下降,但该动作不一定是不好的动作,因此奖励最好是有正有负的,这可以增加baselinse解决:

图片

通过这种方法,当\(R(\tau)-b>0\)时即总奖励\(R(\tau)>b\),就让\((s,a)\)的概率上升;当\(R(\tau)<b\),即便\(R(\tau)\)是正的,但如果它值很小也是不好的,就让\((s,a)\)的概率下降。

b b b可通过对 τ \tau τ值取期望来进行设置, 即计算 τ \tau τ的平均值,令 b ≈ E [ R ( τ ) ] b \approx E[R(\tau)] bE[R(τ)]。实践中把训练期间的\(R(\tau)\)的值不断记下来然后计算平均值,用来设置b。

解决问题2:分配合适的分数

1、reward-to-go:未来的总回报

∇ log ⁡ p θ ( a t n ∣ s t n ) \nabla\log p_{\theta}(a_{t}^n|s_t^n) logpθ(atnstn)前面的 R ( τ ) − b R(\tau)-b R(τ)b看作是它的权重,表征了动作a的好坏。这个权重原先是整个轨迹上奖励的总和,现在改成从某个时刻 t t t开始,一直到游戏结束得到的所有奖励的总和。也就是说计算某个状态-动作对的奖励的时候,不再是把整场游戏得到的奖励全部加起来,而是只计算从这个动作执行以后得到的奖励。直观上也比较容易理解:因为这场游戏在执行这个动作之前发生的事情是与执行这个动作是没有关系的,所以在执行这个动作之前得到的奖励都不能算是这个动作的贡献。我们把执行这个动作以后发生的所有奖励加起来,才是这个动作真正的贡献。

图片

2、discount有折扣的:衰减的回报

进一步,我们在未来的奖励中引入折扣因子。为什么要把未来的奖励做一个折扣呢?因为虽然在某一时刻,执行某一个动作,会影响接下来所有的结果(有可能在某一时刻执行的动作,接下来得到的奖励都是这个动作的功劳),但在一般的情况下,时间拖得越长,该动作的影响力就越小。

图片

折扣因子 γ ∈ [ 0 , 1 ] \gamma \in [0,1] γ[0,1],一般设置为0.9或0.99。其中 G t = r t n + γ r t + 1 n + γ 2 r t + 2 n + γ 3 r t + 3 n + . . . + γ T n − t r T n n = r t n + γ G t + 1 G_t = r_t^n + \gamma r_{t+1}^n + \gamma^2 r_{t+2}^n + \gamma^3 r_{t+3}^n +...+ \gamma^{T_n-t} r_{T_n}^n =r_t^n+\gamma G_{t+1} Gt=rtn+γrt+1n+γ2rt+2n+γ3rt+3n+...+γTntrTnn=rtn+γGt+1

。从 G t G_t Gt的展开式可以看到未来的奖励在离t时刻越远时,折扣就越多,这样显然更合理。

2.2 重要性采样

策略梯度算法的缺点:

1.采样效率低:每次当前actor策略与环境交互收集到一批训练资料后,策略一更新,这批数据就不能再使用了,因为actor已经发生了变化,需要重新拿新的actor再次与环境与做交互,拿到新的一批训练资料。而与环境做交互是非常费时间的(相对于在GPU上作训练),整个过程可能大部分时间在做交互收集(采样)数据。

2.迭代步长过长,或步长/学习率难以确定,训练不稳定。

采样效率低的问题,考虑下能不能用另外一个策略 π θ ′ \pi_{\theta'} πθ和一个actor θ ′ \theta' θ与环境交互,用 θ ′ \theta' θ采样到的数据去训练 θ \theta θ,并且利用这些数据去让 θ \theta θ多次执行梯度上升,多次更新参数, 这样就能大幅提升效率。

如何实现这个过程呢?

图片

这个公式可以看做是先从 q q q里面从采样 x x x,再计算 f ( x ) p ( x ) q ( x ) f(x) \frac{p(x)}{q(x)} f(x)q(x)p(x),再取期望值。所以即便没法从 p p p 里面采样数据,但从 q q q里面采样数据,我们依然可以通过这种变换来计算从采样 p p p代入 x x x以后的期望值。因为是从 q q q采样数据,所以我们从 q q q采样出来的每一笔数据,都需要乘一个 p ( x ) q ( x ) \frac{p(x)}{q(x)} q(x)p(x)来修正这两个分布的差异,这个修正银子就叫做重要性权重(importance weight)。

对于用 actor θ \theta θ采样出 s t s_t st a t a_t at的状态-动作的对时,我们使用状态-动作对的优势(advantage): A θ ( s t , a t ) A_{\theta}(s_t,a_t) Aθ(st,at), 来表示累积奖励减去基线这一项,这一项代表的是在状态 s t s_t st采取动作 a t a_t at的好坏(有没有优势)。如果 A θ ( s t , a t ) A_{\theta}(s_t,a_t) Aθ(st,at)是正的,就要增大概率;如果是负的,就要减小概率。

那么回到上面策略梯度的采样效率的问题,就可以考虑,由一个 p θ ’ p_{\theta’} pθ也就是另一个actor(其实就是需要更新的actor的一个副本)去和环境做交互然后收集采样数据,再用这个数据去多次更新 p θ p_{\theta} pθ以提升采样效率。也就是说利用重要性采样,就可以把公式转化为:

图片

上式第3行利用条件概率公式展开,最后去掉 p θ ( s t ) p_{\theta}(s_t) pθ(st) p t h e t a ‘ ( s t ) p_{\\theta‘}(s_t) ptheta(st) 得到最终的简化的结果。所以根据梯度公式我们可以写出目标函数:

图片

重要性采样解决了采样效率的问题,但也可能会引入新问题。我们再来看下重要性采样的公式: E x ∼ p [ f ( x ) ] = E x ∼ q [ f ( x ) p ( x ) q ( x ) ] E_{x\sim p}[f(x)]=E_{x\sim q}[f(x)\frac{p(x)}{q(x)}] Exp[f(x)]=Exq[f(x)q(x)p(x)],虽然它们期望是相等的,但它们的方差如何呢?根据方差计算公式 V a r [ X ] = E [ X 2 ] − ( E [ X ] ) 2 {Var} [X]=E[X^2]-(E[X])^2 Var[X]=E[X2](E[X])2,分别计算出 f ( x ) f(x) f(x) f ( x ) p ( x ) q ( x ) f(x)\frac{p(x)}{q(x)} f(x)q(x)p(x)的方差:

图片

可以看到2个方差的第一项是不同的, Var ⁡ x ∼ q [ f ( x ) p ( x ) q ( x ) ] \operatorname{Var}_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right] Varxq[f(x)q(x)p(x)]的第一项多乘了 p ( x ) q ( x ) \frac{p(x)}{q(x)} q(x)p(x),如果 p ( x ) q ( x ) \frac{p(x)}{q(x)} q(x)p(x)差距很大, p θ ( a t ∣ s t ) p_{\theta}\left(a_{t} | s_{t}\right) pθ(atst)的方差就会很大。也就是说如果 p θ ( a t ∣ s t ) p_{\theta}\left(a_{t} | s_{t}\right) pθ(atst) p θ ′ ( a t ∣ s t ) p_{\theta'}\left(a_{t} | s_{t}\right) pθ(atst) 相差太大,即这两个分布相差太多,重要性采样的结果就会不好。也就是说通过有限次的采样,如果 p ( x ) p(x) p(x) q ( x ) q(x) q(x)的差距过大,我们是无法保证这个期望的等式在采样数据上一定成立。

怎么避免它们相差太多呢?这就是TRPO和PPO要做的事情。

2.3 TRPO

**信任区域策略优化(trust region policy optimization,TRPO)**就是对 θ \theta θ θ ′ \theta' θ进行一个约束,让它们的 KL 散度小于 :

图片

虽然TRPO解决了分布差距不会很大的问题,但计算有难度(引入约束项,使用拉格朗日的对偶法处理后,采用共轭梯度法进行优化),因此我们一般使用在实现上更容易但性能差不多的PPO。

03 近端策略优化(PPO)

3.1 PPO1(近端策略优化惩罚(PPO-penalty))

PPO(ProximalPolicyOptimization) 解决TRPO计算量大的问题,不是把约束放在条件里,而是直接放到目标函数里:

图片

图片

其中惩罚项 β K L ( θ , θ k ) \beta \mathrm{KL}\left(\theta, \theta^{k}\right) βKL(θ,θk)称之为自适应KL散度(adaptive KL divergence), β \beta β可以动态调整,其调整策略为:

  • 如果 K L ( θ , θ k ) > K L m a x KL(\theta,\theta^k)>KL_{max} KL(θ,θk)>KLmax,则增加 β \beta β

  • 如果 K L ( θ , θ k ) < K L m i n KL(\theta,\theta^k)<KL_{min} KL(θ,θk)<KLmin,则减小 β \beta β

3.2 PPO2(近端策略优化裁剪(PPO-clip))

如果我们觉得计算 KL 散度很复杂,那么还有一个PPO2算法,PPO2 即近端策略优化裁剪。近端策略优化裁剪的目标函数里面没有 KL 散度,其要最大化的目标函数为

图片

  • 裁剪(clip)函数,裁剪函数是指,在括号里面有3项,如果第一项小于第二项,那就输出 1 − ε 1-\varepsilon 1ε ;第一项如果大于第三项,那就输出 1 + ε 1+\varepsilon 1+ε

  • ε \varepsilon ε是一个超参数,是我们要调整的,可以设置成 0.1 或 0.2 。

为什么这个式子就可以做到 p θ p_{\theta} pθ p θ ′ p_{\theta'} pθ差距不会太大呢?

图片

  • 如果 A > 0 A>0 A>0,也就是某一个 ( a t , s t ) (a_t,s_t) (at,st)是好的,则我们希望增大这个状态-动作pair的概率。也就是想让 p θ ( a t ∣ s t ) p_{\theta}(a_t∣s_t) pθ(atst)越大越好,但它与 p θ k ( a t ∣ s t ) p_{\theta^k}(a_t∣s_t) pθk(atst)的比值不能超过 1 + ε 1+\varepsilon 1+ε

  • 如果 A < 0 A<0 A<0,也就是某一个 ( a t , s t ) (a_t,s_t) (at,st)是不好的,那则我们希望把 p θ ( a t ∣ s t ) p_{\theta}(a_t∣s_t) pθ(atst)减小,当减到比值是 1 − ε 1-\varepsilon 1ε的时候停止。

通用这个clip的限制,我们不会让 p θ ( a t ∣ s t ) p_{\theta}(a_t∣s_t) pθ(atst) p θ k ( a t ∣ s t ) p_{\theta^k}(a_t∣s_t) pθk(atst)差距太大,并且实现这个其实也很简单,如下:

ratios = paddle.exp(cur_batch_log_probs - batch_log_probs.detach())
surr1 = ratios * A_k
surr2 = paddle.clip(ratios, 1-self.clip, 1-self.clip) * A_k
actor_loss = -paddle.minimum(surr1, surr2) # 负号,把最大化问题转化为最小化问题ratios = paddle.exp(cur_batch_log_probs - batch_log_probs.detach())
surr1 = ratios * A_k
surr2 = paddle.clip(ratios, 1-self.clip, 1-self.clip) * A_k
actor_loss = -paddle.minimum(surr1, surr2) # 负号,把最大化问题转化为最小化问题

04 总结

图片

——END——

参考资料:

[1]https://datawhalechina.github.io/easy-rl/#/

[2]https://speech.ee.ntu.edu.tw/~hylee/ml/2020-spring.php

推荐阅读:

浅谈统一权限管理服务的设计与开发

百度APP iOS端包体积50M优化实践(五) HEIC图片和无用类优化实践

百度知道上云与架构演进

百度APP iOS端包体积50M优化实践(四)代码优化

百度App启动性能优化实践篇

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

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

相关文章

【golang】结构体及其方法的使用(struct)

函数是独立的程序实体。我们可以声明有名字的函数&#xff0c;也可以声明没名字的函数&#xff0c;还可以把它们当做普通的值传来传去。我们能把具有相同签名的函数抽象成独立的函数类型&#xff0c;以作为一组输入、输出&#xff08;或者说一类逻辑组件&#xff09;的代表。 …

onvif中imaging setting图像画质总结!

前言&#xff1a; 大家好&#xff0c;今天给大家来分享一篇关于图像质量的内容&#xff0c;这个内容是我在做onvif中的imaging setting的时候&#xff0c;关注到里面有关于: brightness(亮度)color saturation(色彩饱和度)contrast(对比度)sharpness(锐度)white balance(白平衡…

手机技巧:推荐一款手机省电、提升流畅度APP

目录 软件详情 基本介绍 软件功能 软件特色 使用方法 软件对比 结论 今天给大家推荐一款手机省电、提升流畅度APP&#xff0c;感兴趣的朋友可以下载一下&#xff01; 软件详情 黑阈app是一款非常实用的系统优化类手机APP。使用它能够禁止软件后台运行耗电&#xff0c;既…

Kafka 什么速度那么快

批量发送消息 Kafka 采用了批量发送消息的方式&#xff0c;通过将多条消息按照分区进行分组&#xff0c;然后每次发送一个消息集合&#xff0c;看似很平常的一个手段&#xff0c;其实它大大提升了 Kafka 的吞吐量。 消息压缩 消息压缩的目的是为了进一步减少网络传输带宽。而…

能耗管理系统在大型机场中的应用

摘要&#xff1a;国家倡导绿色环保&#xff0c;新能源电动汽车应运而生&#xff0c;使用清洁能源代替常规能源&#xff0c;而且不会污染自然环境&#xff0c;减少消耗&#xff0c;资源得以很好利用。汽车使用新能源&#xff0c;成本有所减低&#xff0c;而且环境效益显著。所以…

CI/CD入门(二)

CI/CD入门(二) 目录 CI/CD入门(二) 1、代码上线方案 1.1 早期手动部署代码1.2 合理化上线方案1.3 大型企业上线制度和流程1.4 php程序代码上线的具体方案1.5 Java程序代码上线的具体方案1.6 代码上线解决方案注意事项2、理解持续集成、持续交付、持续部署 2.1 持续集成2.2 持续…

Docker安装RabbitMQ服务端

使用docker安装RabbitMQ服务端 1、搜索镜像 docker search rabbitmq2、拉取镜像 默认拉取最后一个版本&#xff0c;可以在后面加版本号拉取指定版本 docker pull rabbitmq 3、运行镜像 docker run -d --hostname my-rabbit --name rabbit -p 15672:15672 rabbitmq4、查看…

知识储备--基础算法篇-二分搜索

1.前言 最近准备开始刷算法题了&#xff0c;搜了很多相关的帖子&#xff0c;下面三个很不错&#xff0c; 计算机视觉秋招准备过程看这个&#xff1a;​​​​​​计算机视觉算法工程师-秋招面经 - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/399813916 复习深度学习相关…

CSS中的字体属性有哪些值,并分别描述它们的作用。

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ font-style⭐ font-weight⭐ font-size⭐ font-family⭐ font-variant⭐ line-height⭐ letter-spacing⭐ word-spacing⭐ font⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专…

系统架构师---软件重用、基于架构的软件设计、软件模型

目录 软件重用 构件技术 基于架构的软件设计 ABSD方法与生命周期 抽象功能需求 用例 抽象的质量和业务需求 架构选项 质量场景 约束 基于架构的软件开发模型 架构需求 需求获取 标识构件 需求评审 架构设计 架构文档 架构复审 架构实现 架构演化 前言&…

【Kubernetes】Kubernetes对外服务之Ingress

Ingress 一、Ingress 的概念1. Ingress 简介2. K8S 对外提供服务的方案2.1 NodePort2.2 LoadBalancer2.3 externalIPs2.4 Ingress 3. Ingress 组成3.1 ingress3.2 ingress-controller 二、Ingress-Nginx 的概念1. Ingress-Nginx 工作原理2. 部署 nginx-ingress-controller2.1 部…

vue导出文件流获取附件名称并下载(在response.headers里解析filename导出)

导出文件流下载&#xff0c;拦截器统一处理配置 需求以往实现的方法&#xff08;各自的业务层写方法&#xff09;现在实现的方法&#xff08;axios里拦截器统一配置处理&#xff09;把文章链接复制粘贴给后端&#xff0c;让大佬自己赏阅。 需求 之前实现的导出都是各自的业务层…

两阶段提交:详解数据库宕机引起的主从不一致问题、redolog与binlog的两阶段提交

0、基础知识and问题 从基础上我们了解&#xff1a; &#xff08;1&#xff09;redolog作为数据库保证持久化的日志&#xff0c;在update事务提交后就会按一定的策略刷入磁盘中&#xff0c;在刷入后&#xff0c;即使数据库断电宕机&#xff0c;mysql也能从redolog中恢复数据到磁…

CentOS 7 安装MySQL8.0.33

一、查看 CentOS 版本 要查看当前 CentOS 版本&#xff0c;你可以执行以下命令&#xff1a; cat /etc/centos-release 该命令将显示当前 CentOS 的版本信息&#xff0c;例如&#xff1a; CentOS Linux release 7.9.2009 (Core) 在这个示例中&#xff0c;CentOS 版本为 7.…

Spring Clould 负载均衡 - Ribbon

视频地址&#xff1a;微服务&#xff08;SpringCloudRabbitMQDockerRedis搜索分布式&#xff09; Ribbon-负载均衡原理&#xff08;P14&#xff09; 具体实现时通过LoaBalanced注解实现&#xff0c;表示RestTemplate要被Ribbon拦截处理 orderservice调用user时候&#xff0c…

【无标题】QT应用编程: QtCreator配置Git版本控制(码云)

QT应用编程: QtCreator配置Git版本控制(码云) 感谢&#xff1a;DS小龙哥的文章&#xff0c;这篇主要参考小龙哥的内容。 https://cloud.tencent.com/developer/article/1930531?areaSource102001.15&traceIdW2mKALltGu5f8-HOI8fsN Qt Creater 自带了git支持。但是一直没…

如何使用CSS实现一个无限滚动效果(Infinite Scroll)?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 使用CSS实现无限滚动效果&#xff08;Infinite Scroll&#xff09;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xf…

接口测试及接口抓包常用测试工具和方法?

作为测试领域中不可或缺的一环&#xff0c;接口测试和抓包技术在软件开发过程中扮演着至关重要的角色。不论你是新手还是有一些经验的小伙伴&#xff0c;本篇文章都会为你详细介绍接口测试的基本概念、常用测试工具和实际操作技巧&#xff0c;让你轻松掌握这一技能。 接口测试…

c语言——输出一个整数的所有因数

//输出一个整数的所有因数 #include<stdio.h> #include<stdlib.h> int main() {int number,i;printf("输入整数&#xff1a;");scanf("%d",&number);printf(" %d 的因数有&#xff1a; ",number);for(i1;i<number;i){if(numb…

java八股文面试[java基础]——String StringBuilder StringBuffer

String类型定义&#xff1a; final String 不可以继承 final char [] 不可以修改 String不可变的好处&#xff1a; hash值只需要算一次&#xff0c;当String作为map的key时&#xff0c; 不需要考虑hash改变 天然的线程安全 知识来源&#xff1a; 【基础】String、StringB…