强化学习:时序差分法【Temporal Difference Methods】

强化学习笔记

主要基于b站西湖大学赵世钰老师的【强化学习的数学原理】课程,个人觉得赵老师的课件深入浅出,很适合入门.

第一章 强化学习基本概念
第二章 贝尔曼方程
第三章 贝尔曼最优方程
第四章 值迭代和策略迭代
第五章 强化学习实例分析:GridWorld
第六章 蒙特卡洛方法
第七章 Robbins-Monro算法
第八章 多臂老虎机
第九章 强化学习实例分析:CartPole


文章目录

  • 强化学习笔记
  • 一、on-policy vs off-policy
  • 二、TD learning of state values
    • 1 迭代格式
    • 2 推导
    • 3 分析
    • 4 TD(0)与蒙特卡洛方法的对比
  • 三、Sarsa
  • 四、Expected Sarsa
  • 五、Q-learning
  • 六、参考资料


在强化学习实例分析:CartPole中,我们通过实验发现了蒙特卡洛方法的一些缺点:

  1. 每次更新需要等到一个episode结束;
  2. 越到后面的episode,耗时越长,效率低.

本节介绍强化学习中经典的时序差分方法(Temporal Difference Methods,TD)。与蒙特卡洛(MC)学习类似,TD学习也是Model-free的,但由于其增量形式在效率上相较于MC方法具有一定的优势。

一、on-policy vs off-policy

在介绍时序差分算法之前,首先介绍一下on-policy 和 off-policy的概念:

  • On-policy:我们把用于产生采样样本的策略称为behavior-policy,在policy-improvement步骤进行改进的策略称为target-policy.如果这两个策略相同,我们称之为On-policy算法。
  • Off-policy:如果behavior-policytarget-policy不同,我们称之为Off-policy算法。

比如在Monte-Carlo算法中,我可以用一个给定策略 π a \pi_a πa来产生样本,这个策略可以是 ϵ \epsilon ϵ-greedy策略,以保证能够访问所有的 s s s a a a。而我们目标策略可以是greedy策略 π b \pi_b πb,在policy-imporvement阶段我们不断改进 π b \pi_b πb,最终得到一个最优的策略。这样我们最后得到的最优策略 π b ∗ \pi_b^* πb就是一个贪婪策略,不用去探索不是最优的动作,这样我们用 π b ∗ \pi_b^* πb可以得到更高的回报。

二、TD learning of state values

1 迭代格式

和蒙特卡洛方法一样,用TD learning来估计状态值 v ( s ) v(s) v(s),我们也需要采样的数据,假设给定策略 π \pi π,某个episode采样得到的序列如下:
( s 0 , r 1 , s 1 , . . . , s t , r t + 1 , s t + 1 , . . . ) (s_0, r_1, s_1, . . . , s_t , r_{t+1}, s_{t+1}, . . .) (s0,r1,s1,...,st,rt+1,st+1,...)
那么TD learning给出在第 t t t步状态值 v ( s ) v(s) v(s)的更新如下:
v ( s t ) = v ( s t ) + α t ( s t ) [ r t + 1 + γ v ( s t + 1 ) − v ( s t ) ] ( 1 ) v(s_t)=v(s_t)+\alpha_t(s_t)[r_{t+1}+\gamma v(s_{t+1})-v(s_t)]\qquad(1) v(st)=v(st)+αt(st)[rt+1+γv(st+1)v(st)](1)
Note:

  1. s t s_t st是当前状态, s t + 1 s_{t+1} st+1是跳转到的下一个状态,这里需要用到 v ( s t + 1 ) v(s_{t+1}) v(st+1)(本身也是一个估计值);
  2. 我们可以看到,TD方法在每个时间步都会进行更新,不需要得到整个episode结束才更新;
  3. 这个算法被称为TD(0)

a t ( s t ) a_t(s_t) at(st)取常量 α \alpha α时,下面给出 v π ( s ) v_{\pi}(s) vπ(s)估计的伪代码:

截屏2024-04-27 10.09.34

2 推导

TD(0)的迭代格式为什么是这样的呢?和前面介绍随机近似中的RM算法似乎有点像,事实上它可以看作是求解Bellman方程的一种特殊的随机近似算法。我们回顾贝尔曼方程中介绍的:
v π ( s ) = E [ G t ∣ S t = s ] = E [ R t + γ G t + 1 ∣ S t = s ] = E [ R t + γ v π ( S t + 1 ) ∣ S t = s ] ( 2 ) \begin{aligned} v_{\pi}(s)&=\mathbb{E}[G_t|S_t=s]\\ &=\mathbb{E}[R_t+\gamma G_{t+1}|S_t=s]\\ &=\mathbb{E}[R_t+\gamma v_{\pi}(S_{t+1})|S_t=s]\\ \end{aligned} \qquad(2) vπ(s)=E[GtSt=s]=E[Rt+γGt+1St=s]=E[Rt+γvπ(St+1)St=s](2)
下面我们用Robbins-Monro算法来求解方程(2),对于状态$s_t, $,我们定义一个函数为
g ( v π ( s t ) ) ≐ v π ( s t ) − E [ R t + 1 + γ v π ( S t + 1 ) ∣ S t = s t ] . g(v_\pi(s_t))\doteq v_\pi(s_t)-\mathbb{E}\big[R_{t+1}+\gamma v_\pi(S_{t+1})|S_t=s_t\big]. g(vπ(st))vπ(st)E[Rt+1+γvπ(St+1)St=st].
那么方程(2)等价于
g ( v π ( s t ) ) = 0. g(v_\pi(s_t))=0. g(vπ(st))=0.
显然我们可以用RM算法来求解上述方程的根,就能得到 v π ( s t ) v_{\pi}(s_t) vπ(st)。因为我们可以通过采样获得 r t + 1 r_{t+1} rt+1 s t + 1 s_{t+1} st+1,它们是 R t + 1 R_{t+1} Rt+1 S t + 1 S_{t+ 1} St+1的样本,我们可以获得的$g( v_\pi ( s_{t}) ) $的噪声观测是
g ~ ( v π ( s t ) ) = v π ( s t ) − [ r t + 1 + γ v π ( s t + 1 ) ] = ( v π ( s t ) − E [ R t + 1 + γ v π ( S t + 1 ) ∣ S t = s t ] ) ⏟ g ( v π ( s t ) ) + ( E [ R t + 1 + γ v π ( S t + 1 ) ∣ S t = s t ] − [ r t + 1 + γ v π ( s t + 1 ) ] ) ⏟ η . \begin{aligned}\tilde{g}(v_{\pi}(s_{t}))&=v_\pi(s_t)-\begin{bmatrix}r_{t+1}+\gamma v_\pi(s_{t+1})\end{bmatrix}\\&=\underbrace{\left(v_\pi(s_t)-\mathbb{E}\big[R_{t+1}+\gamma v_\pi(S_{t+1})|S_t=s_t\big]\right)}_{g(v_\pi(s_t))}\\&+\underbrace{\left(\mathbb{E}\big[R_{t+1}+\gamma v_\pi(S_{t+1})|S_t=s_t\big]-\big[r_{t+1}+\gamma v_\pi(s_{t+1})\big]\right)}_{\eta}.\end{aligned} g~(vπ(st))=vπ(st)[rt+1+γvπ(st+1)]=g(vπ(st)) (vπ(st)E[Rt+1+γvπ(St+1)St=st])+η (E[Rt+1+γvπ(St+1)St=st][rt+1+γvπ(st+1)]).
因此,求解 g ( v π ( s t ) ) = 0 g(v_{\pi}(s_{t}))=0 g(vπ(st))=0的RM算法为
v t + 1 ( s t ) = v t ( s t ) − α t ( s t ) g ~ ( v t ( s t ) ) = v t ( s t ) − α t ( s t ) ( v t ( s t ) − [ r t + 1 + γ v π ( s t + 1 ) ] ) , ( 3 ) \begin{aligned}v_{t+1}(s_{t})&=v_t(s_t)-\alpha_t(s_t)\tilde{g}(v_t(s_t))\\&=v_t(s_t)-\alpha_t(s_t)\Big(v_t(s_t)-\big[r_{t+1}+\gamma v_\pi(s_{t+1})\big]\Big),\end{aligned}\qquad(3) vt+1(st)=vt(st)αt(st)g~(vt(st))=vt(st)αt(st)(vt(st)[rt+1+γvπ(st+1)]),(3)
其中 v t ( s t ) v_t(s_t) vt(st) v π ( s t ) v_\pi(s_t) vπ(st)在$t, 时间点的估计, 时间点的估计, 时间点的估计,\alpha _t( s_t) $是学习率。

Note:

  1. (3)中的算法与(1)中的TD(0)具有相似的表达式,唯一的区别是(3)的右侧包含 v π ( s t + 1 ) v_{\pi}(s_{t+1}) vπ(st+1),而(1)包含 v t ( s t + 1 ) v_t(s_{t+1}) vt(st+1),这是因为(3)的设计是通过假设其他状态值已知来估计 s t s_t st的动作值。
  2. 如果我们想估计所有状态的状态值,则右侧的 v π ( s t + 1 ) v_{\pi}(s_{t+1}) vπ(st+1)应替换为 v t ( s t + 1 ) v_t(s_{t+1}) vt(st+1),那么(3)与(1)完全相同。并且我们可以证明这样的替换能保证所有 v t ( s ) v_t(s) vt(s)都收敛到 v π ( s ) v_{\pi}(s) vπ(s),这里就不再展开。

3 分析

我们再来看一下TD(0)的迭代格式:
v t + 1 ( s t ) ⏟ new estimate = v t ( s t ) ⏟ current estimate − α t ( s t ) [ v t ( s t ) − ( r t + 1 + γ v t ( s t + 1 ) ⏟ TD target  v ˉ t ) ⏞ TD error  δ t ] , ( 4 ) \underbrace{v_{t+1}(s_t)}_{\text{new estimate}}=\underbrace{v_t(s_t)}_{\text{current estimate}}-\alpha_t(s_t)\Big[\overbrace{v_t(s_t)-\Big(\underbrace{r_{t+1}+\gamma v_t(s_{t+1})}_{\text{TD target }\bar{v}_t}\Big)}^{\text{TD error }\delta_t}\Big],\qquad (4) new estimate vt+1(st)=current estimate vt(st)αt(st)[vt(st)(TD target vˉt rt+1+γvt(st+1)) TD error δt],(4)
其中
v ˉ t ≐ r t + 1 + γ v t ( s t + 1 ) ( 5 ) \bar{v}_t\doteq r_{t+1}+\gamma v_t(s_{t+1})\qquad(5) vˉtrt+1+γvt(st+1)(5)
被称为TD target
δ t ≐ v ( s t ) − v ˉ t = v t ( s t ) − ( r t + 1 + γ v t ( s t + 1 ) ) ( 6 ) \delta_t\doteq v(s_t)-\bar{v}_t=v_t(s_t)-(r_{t+1}+\gamma v_t(s_{t+1}))\qquad(6) δtv(st)vˉt=vt(st)(rt+1+γvt(st+1))(6)
被称为TD-error.

为什么(5)被称为TD target,因为迭代格式(4)是让 v t + 1 v_{t+1} vt+1朝着 v ˉ t \bar{v}_t vˉt更新的,我们考察:
∣ v t + 1 ( s t ) − v ˉ t ∣ = ∣ [ v t ( s t ) − v ˉ t ] − α t ( s t ) [ v t ( s t ) − v ˉ t ] ∣ = ∣ [ 1 − α t ( s t ) ] ∣ ∣ [ v t ( s t ) − v ˉ t ] ∣ ≤ ∣ [ v t ( s t ) − v ˉ t ] ∣ \begin{aligned} |v_{t+1}(s_t)-\bar{v}_t|&=|\begin{bmatrix}v_t(s_t)-\bar{v}_t\end{bmatrix}-\alpha_t(s_t)\big[v_t(s_t)-\bar{v}_t\big]|\\ &=|[1-\alpha_t(s_t)]||\big[v_t(s_t)-\bar{v}_t\big]|\\ &\leq|\big[v_t(s_t)-\bar{v}_t\big]| \end{aligned} vt+1(st)vˉt=[vt(st)vˉt]αt(st)[vt(st)vˉt]=[1αt(st)]∣∣[vt(st)vˉt][vt(st)vˉt]
显然当 0 < α t ( s t ) < 2 0<\alpha_t(s_t)<2 0<αt(st)<2时,上式的不等式成立,这意味着 v t + 1 v_{t+1} vt+1 v t v_t vt v ˉ t \bar{v}_t vˉt更近,所以 v ˉ t \bar{v}_t vˉt被称为TD target

TD-error则衡量了在 t t t时间步估计值 v t v_t vt v ˉ t \bar{v}_t vˉt 的差异,显然我们可以想象当 v t v_t vt估计值是准确的 v π v_{\pi} vπ时,TD-error的期望值应该为0,事实上确实如此:
E [ δ t ∣ S t = s t ] = E [ v π ( S t ) − ( R t + 1 + γ v π ( S t + 1 ) ) ∣ S t = s t ] = v π ( s t ) − E [ R t + 1 + γ v π ( S t + 1 ) ∣ S t = s t ] = v π ( s t ) − v π ( s t ) = 0. \begin{aligned} \mathbb{E}[\delta_t|S_t=s_t]& =\mathbb{E}\big[v_\pi(S_t)-(R_{t+1}+\gamma v_\pi(S_{t+1}))|S_t=s_t\big] \\ &=v_\pi(s_t)-\mathbb{E}\big[R_{t+1}+\gamma v_\pi(S_{t+1})|S_t=s_t\big] \\ &=v_\pi(s_t)-v_\pi(s_t)\\ &=0. \end{aligned} E[δtSt=st]=E[vπ(St)(Rt+1+γvπ(St+1))St=st]=vπ(st)E[Rt+1+γvπ(St+1)St=st]=vπ(st)vπ(st)=0.
TD-error趋于0时, 那么(1)也得到不到什么新的信息了,迭代也就收敛了。

4 TD(0)与蒙特卡洛方法的对比

TD learningMonte Carlo Methods
TD learning每得到一个样本就能更新 v ( s ) v(s) v(s)或者 q ( s , a ) q(s,a) q(s,a),这种算法被称为online的.MC每次更新必须等到一个epsisode结束,这种算法被称为offline的.
TD可以处理连续性任务和episodic任务.MC只能处理episodic任务.
TD被称为bootstraping方法,因为 v ( s ) v(s) v(s)/ q ( s , a ) q(s,a) q(s,a)动作的更新依赖于其他状态值先前的估计值.因此,TD需要给定一个初始值.MC是Non-Bootstraping的.

三、Sarsa

如果我们要得到最优策略,无论是用策略迭代还是值迭代算法,我们都需要 q ( s , a ) q(s,a) q(s,a),所以我们可以用TD learning直接来估计 q ( s , a ) q(s,a) q(s,a),给定策略 π \pi π,假设某个episode采样得到如下序列:
( s 0 , a 0 , r 1 , s 1 , a 1 , . . . , s t , a t , r t + 1 , s t + 1 , a t + 1 , . . . ) . (s_0, a_0, r_1, s_1, a_1, . . . , s_t , a_t , r_{t+1}, s_{t+1}, a_{t+1}, . . .). (s0,a0,r1,s1,a1,...,st,at,rt+1,st+1,at+1,...).
那么TD learning对 q ( s , a ) q(s,a) q(s,a)的估计如下:
q t + 1 ( s t , a t ) = q t ( s t , a t ) − α t ( s t , a t ) [ q t ( s t , a t ) − ( r t + 1 + γ q t ( s t + 1 , a t + 1 ) ) ] , ( 7 ) q_{t+1}(s_t,a_t)=q_t(s_t,a_t)-\alpha_t(s_t,a_t)\Big[q_t(s_t,a_t)-(r_{t+1}+\gamma q_t(s_{t+1},a_{t+1}))\Big],\qquad(7) qt+1(st,at)=qt(st,at)αt(st,at)[qt(st,at)(rt+1+γqt(st+1,at+1))],(7)
Note:

  1. 和对状态值的估计(1)对比,我们发现(7)就是把(1)中的 v ( s ) v(s) v(s)替换为 q ( s , a ) q(s,a) q(s,a),其实就是用RM算法求解关于 q ( s , a ) q(s,a) q(s,a)的贝尔曼方程,所以得到的迭代格式类似.
  2. 其中 s t + 1 s_{t+1} st+1为转移的下一个状态, a t + 1 a_{t+1} at+1是在状态 s t + 1 s_{t+1} st+1下采取的动作,这里是根据策略 π \pi π得到.(因为我们采样的序列就是根据 π \pi π得到的)
  3. 所以如果 s t + 1 s_{t+1} st+1是终止状态,显然就没有 a t + 1 a_{t+1} at+1,此时我们定义 q ( s t + 1 , a t + 1 ) = 0 q(s_{t+1},a_{t+1})=0 q(st+1,at+1)=0.
  4. 这个算法每次更新会用到 ( s t , a t , r t + 1 , s t + 1 , a t + 1 ) (s_t, a_t, r_{t+1}, s_{t+1}, a_{t+1}) (st,at,rt+1,st+1,at+1)(SARSA),所以这个算法被称为SARSA.
  5. 当我们有 q ( s , a ) q(s,a) q(s,a)的估计值后,我们可以使用greedy或者 ε \varepsilon ε-greedy来更新策略。可以证明如果步长 a t ( s t , a t ) a_t(s_t,a_t) at(st,at)满足RM算法收敛的条件要求,只要所有的状态-动作对被访问无限次,Sarsa以概率1收敛到最优的策略 π ∗ \pi^* π和最优的动作-价值函数 q ∗ ( s , a ) q^*(s,a) q(s,a).

同TD(0)类似,Sarsa可以看作是用RM算法求解如下贝尔曼方程得到的迭代格式:
q π ( s , a ) = E [ R + γ q π ( S ′ , A ′ ) ∣ s , a ] , for all  ( s , a ) . q_\pi(s,a)=\mathbb{E}\left[R+\gamma q_\pi(S',A')|s,a\right],\quad\text{for all }(s,a). qπ(s,a)=E[R+γqπ(S,A)s,a],for all (s,a).

下面给出Sarsa完整的伪代码:

截屏2024-04-27 11.31.17

Sarsa是一种on-policy算法,因为在估计 q t q_t qt值时,会用到依据 π t \pi_t πt产生的样本,更新 q t q_t qt后,我们又会依据新的 q t q_t qt来更新策略得到 π t + 1 \pi_{t+1} πt+1,然后用 π t + 1 \pi_{t+1} πt+1产生样本继续更新 q t + 1 q_{t+1} qt+1,这样交替进行,最后得到最优策略。在这个过程中我们发现产生样本的策略和得到的最优策略是同一个策略,所以是on-policy算法。

四、Expected Sarsa

给定策略 π \pi π,其动作值可以用Sarsa的一种变体Expected-Sarsa来估计。Expected-Sarsa的迭代格式如下:
q t + 1 ( s t , a t ) = q t ( s t , a t ) − α t ( s t , a t ) [ q t ( s t , a t ) − ( r t + 1 + γ E [ q t ( s t + 1 , A ) ] ) ] = q t ( s t , a t ) − α t ( s t , a t ) [ q t ( s t , a t ) − ( r t + 1 + γ ∑ a π ( a ∣ s t + 1 ) q t ( s t + 1 ) , a ) ] \begin{aligned} q_{t+1}(s_t,a_t)&=q_t(s_t,a_t)-\alpha_t(s_t,a_t)\Big[q_t(s_t,a_t)-(r_{t+1}+\gamma\mathbb{E}[q_t(s_{t+1},A)])\Big]\\ &=q_t(s_t,a_t)-\alpha_t(s_t,a_t)\Big[q_t(s_t,a_t)-(r_{t+1}+\gamma\sum_a\pi(a|s_{t+1})q_t(s_{t+1}),a)\Big] \end{aligned} qt+1(st,at)=qt(st,at)αt(st,at)[qt(st,at)(rt+1+γE[qt(st+1,A)])]=qt(st,at)αt(st,at)[qt(st,at)(rt+1+γaπ(ast+1)qt(st+1),a)]
同Sarsa类似,Expected-Sarsa可以看作是用RM算法求解如下贝尔曼方程得到的迭代格式:
q π ( s , a ) = E [ R t + 1 + γ E [ q π ( S t + 1 , A t + 1 ) ∣ S t + 1 ] ∣ S t = s , A t = a ] = E [ R t + 1 + γ v π ( S t + 1 ) ∣ S t = s , A t = a ] . \begin{aligned} q_\pi(s,a)&=\mathbb{E}\Big[R_{t+1}+\gamma\mathbb{E}[q_\pi(S_{t+1},A_{t+1})|S_{t+1}]\Big|S_t=s,A_t=a\Big]\\ &=\mathbb{E}\Big[R_{t+1}+\gamma v_\pi(S_{t+1})|S_t=s,A_t=a\Big]. \end{aligned} qπ(s,a)=E[Rt+1+γE[qπ(St+1,At+1)St+1] St=s,At=a]=E[Rt+1+γvπ(St+1)St=s,At=a].
虽然Expected Sarsa的计算复杂度比Sarsa高,但它消除了随机选择 a t + 1 a_{t+1} at+1所带来的方差。在相同的采样样本条件下,Expected Sarsa的表现通常比Sarsa更好。

五、Q-learning

接下来我们介绍强化学习中经典的Q-learning算法,Sarsa算法和Expected-Sarsa都是估计 q ( s , a ) q(s,a) q(s,a),如果我们想要得到最优策略还需要policy-improvement,而Q-learning算法则是直接估计 q ∗ ( s , a ) q^*(s,a) q(s,a),如果我们能得到 q ∗ ( s , a ) q^*(s,a) q(s,a)就不用每一步还执行policy-improvement了。Q-learning的迭代格式如下:
q t + 1 ( s t , a t ) = q t ( s t , a t ) − α t ( s t , a t ) [ q t ( s t , a t ) − ( r t + 1 + γ max ⁡ a ∈ A ( s t + 1 ) q t ( s t + 1 , a ) ) ] , ( 7.18 ) q_{t+1}(s_t,a_t)=q_t(s_t,a_t)-\alpha_t(s_t,a_t)\left[q_t(s_t,a_t)-\left(r_{t+1}+\gamma\max_{a\in\mathcal{A}(s_{t+1})}q_t(s_{t+1},a)\right)\right],\quad(7.18) qt+1(st,at)=qt(st,at)αt(st,at)[qt(st,at)(rt+1+γaA(st+1)maxqt(st+1,a))],(7.18)
Q-learning也是一种随机近似算法,用于求解以下方程:
q ( s , a ) = E [ R t + 1 + γ max ⁡ a q ( S t + 1 , a ) ∣ S t = s , A t = a ] . q(s,a)=\mathbb{E}\left[R_{t+1}+\gamma\max_aq(S_{t+1},a)\Big|S_t=s,A_t=a\right]. q(s,a)=E[Rt+1+γamaxq(St+1,a) St=s,At=a].
这是 q ( s , a ) q(s,a) q(s,a)贝尔曼最优方程,所以Q-learning本质就是求解贝尔曼最优方程的随机近似算法,其伪代码如下:

截屏2024-04-27 12.58.51

显然Q-learning是一种Off-policy算法,因为 q t ( s , a ) q_t(s,a) qt(s,a)在更新的时候,用的数据可以是一个给定 ϵ \epsilon ϵ-greedy策略 π a \pi_a πa产生的,但是直接学习到 q ∗ ( s , a ) q^*(s,a) q(s,a),我们可以通过 q ∗ ( s , a ) q^*(s,a) q(s,a)得到一个greedy策略 π b ∗ \pi_b^* πb.

即使Q-learning是off-policy的,但我们也可以按on-policy的方式来实现,下面给出这两种实现,我们可以更清楚地看到off-policy和on-policy的区别:

截屏2024-04-27 13.33.45

截屏2024-04-27 13.34.03

六、参考资料

  1. Zhao, S… Mathematical Foundations of Reinforcement Learning. Springer Nature Press and Tsinghua University Press.
  2. Sutton, Richard S., and Andrew G. Barto. Reinforcement learning: An introduction. MIT press, 2018.

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

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

相关文章

软件游戏丢失XINPUT1_4.dll文件的多种解决方法分享

当玩家在尝试启动某款游戏时&#xff0c;遇到了系统提示“游戏找不到XINPUT1_4.dll”&#xff0c;这个错误通常发生在玩家尝试启动游戏时&#xff0c;游戏无法找到所需的XINPUT1_4.dll文件&#xff0c;呆滞无法正常启动运行。但是幸运的是&#xff0c;有一些简单的修复方法可以…

软件测试与管理:黑盒测试-因果图法和场景法

知识思维导图&#xff1a; ​​​​​​​ 例题1&#xff1a;运用因果图法设计测试用例 有一个处理单价为5角钱的饮料的自动售货机软件测试用例的设计。其规格说明如下&#xff1a; 若投入5角钱或1元钱的硬币&#xff0c;按下〖橙汁〗或〖啤酒〗的按钮&#xff0c;则相应的饮料…

[方法] Unity 实现仿《原神》第三人称跟随相机 v1.1

参考网址&#xff1a;【Unity中文课堂】RPG战斗系统Plus 在Unity游戏引擎中&#xff0c;实现类似《原神》的第三人称跟随相机并非易事&#xff0c;但幸运的是&#xff0c;Unity为我们提供了强大的工具集&#xff0c;其中Cinemachine插件便是实现这一目标的重要工具。Cinemachi…

4步快速配置Java和MySQL环境

每次入职一家新公司或者用一台其他的临时电脑或者新电脑时都要重新配置Java开发环境&#xff0c;很麻烦&#xff0c;因此我在这里记录一下快速配置环境的方式&#xff0c;四步搞定&#xff01;此处以win为操作系统进行讲解。 第一步&#xff1a;下载链接 下载链接&#xff1a…

04.1.添加多个监控同步其他主机

添加多个监控&同步其他主机 1.首先在agent配置文件中存在Include的&#xff0c;也就是说明&#xff0c;可以配置多个监控项并且同步到其他主机上的进行使用&#xff1b; 2.主机之间互相推送配置文件即可&#xff1b; 开始测试 我这里实在agent节点上直接在路径/etc/zabbi…

Go实现树莓派控制舵机

公式说明 毫秒&#xff08;ms&#xff09;是时间的单位&#xff0c;赫兹&#xff08;Hz&#xff09;是频率的单位&#xff0c;而DutyMax通常是一个PWM&#xff08;脉冲宽度调制&#xff09;信号中表示最大占空比的值。以下是它们之间的关系和一些相关公式&#xff1a; 频率&…

设计模式之建造者模式BuilderPattern(七)

一、建造者模式 建造者模式&#xff08;Builder Pattern&#xff09;使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式&#xff0c;它提供了一种创建对象的最佳方式。 二、代码实例 1、OrderItem类 Data&#xff1a;这是Lombok中提供的Ge…

ADS过孔---过孔建模自动化

当前快速建模的方法有两类&#xff1a;一是脚本自动化&#xff0c;也就是今天要分享的方法&#xff0c;但该方法需要工程师有基本的脚本编辑能力&#xff0c;然后根据自己的需要去修改&#xff0c;难度较大一点点&#xff1b;二是参数化建模&#xff0c;也就是在GUI界面输入相应…

百度语音识别开发笔记

目录 简述 开发环境 1、按照官方文档步骤开通短语音识别-普通话 2、创建应用 3、下载SDK 4、SDK集成 5、相关接口简单说明 5.1权限和key 5.2初始化 5.3注册回调消息 5.4开始转换 5.5停止转换 6、问题 简述 最近想做一些语音识别的应用&#xff0c;对比了几个大厂…

华为手机连接电脑后电脑无反应、检测不到设备的解决方法

本文介绍华为手机与任意品牌电脑连接时&#xff0c;出现连接后电脑无反应、检测不到手机连接情况的解决方法。 最近&#xff0c;因为手机的存储空间愈发紧缺&#xff0c;所以希望在非华为电脑中&#xff0c;将华为手机内的照片、视频等大文件备份、整理一下。因此&#xff0c;需…

aardio爬虫) 实战篇:逆向有道翻译web接口

前言 之前的文章把js引擎(aardio封装库) 微软开源的js引擎(ChakraCore))写好了&#xff0c;这篇文章整点js代码来测一下bug。测试网站&#xff1a;https://fanyi.youdao.com/index.html#/ 逆向思路 逆向思路可以看有道翻译js逆向&#xff08;MD5加密&#xff0c;AES加密&…

cmake进阶:定义函数的内部变量

一. 简介 前一篇文章学习 cmake中的定义函数基本用法。文章如下&#xff1a; cmake进阶&#xff1a;定义函数的使用方法-CSDN博客 本文继续学习 cmake中的定义函数&#xff0c;主要学习函数的内部变量。 二. cmake进阶&#xff1a;定义函数的内部变量 上一篇文章说过&…

Elasticsearch:理解人工智能相似性搜索

理解相似性搜索&#xff08;也称为语义搜索&#xff09;的指南&#xff0c;这是人工智能最新阶段的关键发现之一。 最新阶段人工智能的关键发现之一是根据相似性搜索和查找文档的能力。相似性搜索是一种比较信息的方法&#xff0c;其基于含义而非关键字。 相似性搜索也被称为语…

Stable Diffusion学习记录

文章目录 前言电脑配置推荐环境搭建下载地址安装步骤步骤一&#xff0c;打开下载的秋叶整合包&#xff0c;路径秋叶整合包/sd-wenui-aki步骤二&#xff0c;打开下载好的sd-webui-aki-v4.8.7解压包 Stable Diffusion软件配置&#xff0c;插件安装&#xff0c;模型下载Stable Dif…

Codeforces Round 943 (Div. 3) C-G

C. Assembly via Remainders 思路&#xff1a; 我们可以注意到&#xff0c;数组的长度只有 500 500 500 &#xff0c;并且每个数的大小都在 500 500 500 以内&#xff0c;再看向这题&#xff0c;容易知道&#xff0c;当第一个数确定之后&#xff0c;之后所有的数字都会确定下…

leetcode-没有重复项的全排列-97

题目要求 思路 1.递归&#xff0c;如果num和n的元素个数一样就可以插入res中了&#xff0c;这个作为递归的结束条件 2.因为这个题是属于排列&#xff0c;并非组合&#xff0c;两者的区别是排列需要把之前插入的元素在回退会去&#xff0c;而组合不需要&#xff0c;因此会存在一…

14【PS作图】像素画尺寸大小

【背景介绍】本节介绍像素图多大合适 下图是160*144像素大小,有一个显示文本的显示器,还有一个有十几个键的键盘 像素画布尺寸 电脑16像素,但还有一个显示屏 下图为240*160 在场景素材,和对话素材中,用的是不同尺寸的头像,对话素材中的头像会更清楚,尺寸会更大 远处…

【软考高项】三十三、质量管理

一、管理基础 质量定义 国际标准&#xff1a;反映实体满足主体明确和隐含需求的能力的特性总和。 国家标准&#xff1a;一组固有特性满足要求的程度。固有特性是指在某事或某物中本来就有的&#xff0c;尤其是那种永久的可区分的特征。 ➢ 对产品来说&#xff0c;例如…

查看微信小程序主包大小

前言 略 查看微信小程序主包大小 在微信开发者工具右上角找到“详情->基本信息” 查看微信小程序主包构成 通过微信开发者工具中的“代码依赖分析”工具查看

Unity 性能优化之光照优化(七)

提示&#xff1a;仅供参考&#xff0c;有误之处&#xff0c;麻烦大佬指出&#xff0c;不胜感激&#xff01; 文章目录 前言一、测试目的一、实时光源是什么&#xff1f;二、开始测试1.场景中只有一个光照的数值情况2.添加4个点光源后4.结果 总结 前言 实时光源数量越多&#x…