深度强化学习:PPO

深度强化学习算法:PPO

1. Importance Sampling

先说一下什么是采样:对于一个随机变量,我们通常用概率密度函数来描述该变量的概率分布特性。具体来说,给定随机变量的一个取值,可以根据概率密度函数来计算该值对应的概率(密度)。反过来也可以根据概率密度函数提供的概率分布信息来生成随机变量的一个取值,这就是采样

现在假设需要对一个变量 X 的值进行估计,这个变量在真实环境中有一个分布 p ;那么在这个分布下可以获取到它的采样值 x i {x_i} xi ,由于 x i 和 X x_i和X xiX是同分布的,即 E [ x i ] = E [ X ] E[x_i]=E[X] E[xi]=E[X] ,则可以利用大数定理来求解变量X的估计值:
E [ x i ] = 1 2 ∑ i = 1 n x i = E [ X ] (1) E[x_i] = \frac{1}{2}\sum^n_{i=1}x_i = E[X] \tag{1} E[xi]=21i=1nxi=E[X](1)
当获取的采样值数量n增加,估计值越来越趋近于真实值。蒙特卡洛也会这样不是吗。

但是现在有一个新的情况,假如变量 X 的分布为 p ,而获取的采样值的分布为 q ,则此时 E [ x i ] ≠ E [ X ] E[x_i] \neq E[X] E[xi]=E[X] ,那么便无法通过大数定理来估计了。但是现在的情况是我们不能从分布 p 采样数据,只能从分布 q 采样数据,q可以是任何分布。这时候就要用到重要性采样了。
E x ∼ p [ f ( x ) ] = E x ∼ q [ f ( x ) p ( x ) q ( x ) ] (2) E_{x \sim p}[f(x)] = E_{x \sim q}[f(x) \frac{p(x)}{q(x)}] \tag{2} Exp[f(x)]=Exq[f(x)q(x)p(x)](2)
我们从 q 里面采样 x ,再计算 f ( x ) p ( x ) q ( x ) f(x) \frac{p(x)}{q(x)} f(x)q(x)p(x) ,再取期望值。所以就算我们不能从 p 里面采样数据,但只要从 q 里面采样数据,就可以计算从 p 采样 x 代入 f 之后的期望值了。这里需要乘上一个重要性权重 p ( x ) q ( x ) \frac{p(x)}{q(x)} q(x)p(x) 来修正这两个分布的差异。 q ( x ) q(x) q(x) 可以是任何分布,唯一的限制就是 q ( x ) q(x) q(x) 的概率是 0 的时候, p ( x ) p(x) p(x) 的概率不为 0 ,不然会没有定义。

尽管上面提到分布 q 可以是任何分布,但是仍有限制,就是分布 q 不能和分布 p 的差距太多,两个分布需要差不多的,只有这样两个分布的方差( V a r x ∼ p [ f ( x ) ] 和 V a r x ∼ p [ f ( x ) p ( x ) q ( x ) ] Var_{x \sim p}[f(x)] 和 Var_{x \sim p}[f(x)\frac{p(x)}{q(x)}] Varxp[f(x)]Varxp[f(x)q(x)p(x)])才会没有太多的差距。

分别把 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) 代入方差的公式 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,可得
V a r x ∼ p [ f ( x ) ] = E x ∼ p [ f ( x ) 2 ] − ( E x ∼ p [ f ( x ) ] ) 2 V a r x ∼ q [ f ( x ) p ( x ) q ( x ) ] = E x ∼ q [ ( f ( x ) p ( x ) q ( x ) ) 2 ] − ( E x ∼ q [ f ( x ) p ( x ) q ( x ) ] ) 2 = E x ∼ q [ f ( x ) 2 p ( x ) q ( x ) ] − ( E x ∼ p [ f ( x ) ] ) 2 (3) Var_{x \sim p}[f(x)] = E_{x \sim p}[f(x)^2] - (E_{x \sim p}[f(x)])^2 \tag{3}\\ Var_{x \sim q}[f(x)\frac{p(x)}{q(x)}]=E_{x\sim q}[(f(x)\frac{p(x)}{q(x)})^2] - (E_{x \sim q}[f(x)\frac{p(x)}{q(x)}])^2\\ =E_{x\sim q}[f(x)^2\frac{p(x)}{q(x)}] - (E_{x \sim p}[f(x)])^2 Varxp[f(x)]=Exp[f(x)2](Exp[f(x)])2Varxq[f(x)q(x)p(x)]=Exq[(f(x)q(x)p(x))2](Exq[f(x)q(x)p(x)])2=Exq[f(x)2q(x)p(x)](Exp[f(x)])2(3)
可以看到两者方差的差别在第一项, V a r x ∼ q [ f ( x ) p ( x ) q ( x ) ] Var_{x\sim q}[f(x)\frac{p(x)}{q(x)}] Varxq[f(x)q(x)p(x)] 的第一项多乘了 p ( x ) q ( x ) \frac{p(x)}{q(x)} q(x)p(x) 。如果两个分布的差距较大,那么这个概率估计就会有问题。

如上图所示,如果我们要计算 f ( x ) f(x) f(x) 的期望,从分布 p ( x ) p(x) p(x) 采样数据,那么 E x ∼ p [ f ( x ) ] E_{x \sim p}[f(x)] Exp[f(x)] 是负的,这是由于左边区域 p ( x ) p(x) p(x) 的概率很高,所以采样更倾向于在这个区域,而 f ( x ) f(x) f(x) 在这个区域是负的,所以理论上这一项算出来会是负的。

如果从分布 q ( x ) q(x) q(x) 中采样,由于 q ( x ) q(x) q(x) 在右边区域的概率比较高,所以更倾向于在右侧这个区域采样,那么 E x ∼ q [ f ( x ) p ( x ) q ( x ) ] E_{x \sim q}[f(x)\frac{p(x)}{q(x)}] Exq[f(x)q(x)p(x)] 就可能是正的。虽然左侧概率很低,但是也有可能被采样到。如果 f ( x ) f(x) f(x) 好不容易采样到了左边的的点,在左边区域 p ( x ) p(x) p(x) 很大, q ( x ) q(x) q(x) 很小,,也就是 f ( x ) f(x) f(x) 采样到一个负的点,这个负值来之不易,这个负值就应该乘上一个非常大的权重,这样就可以平衡其他采样到的正的值,那么最终得到的 f ( x ) f(x) f(x) 的期望值还是负的。

那么之前的同策略(式(4))就换成了异策略(式(5))。
∇ R θ ˉ = E τ ∼ p θ ( τ ) [ R ( τ ) ∇ log ⁡ p θ ( τ ) ] (4) \nabla \bar{R_\theta} = E_{\tau \sim p_\theta(\tau)}[R(\tau)\nabla \log p_\theta(\tau)] \tag{4} Rθˉ=Eτpθ(τ)[R(τ)logpθ(τ)](4)

∇ R θ ˉ = E τ ∼ p θ ′ ( τ ) [ p θ ( τ ) p θ ′ R ( τ ) ∇ log ⁡ p θ ( τ ) ] (5) \nabla \bar{R_\theta} = E_{\tau\sim p_{\theta^{'}(\tau)}}[\frac{p_\theta (\tau)}{p_{\theta^{'}}}R(\tau) \nabla \log p_\theta (\tau)] \tag{5} Rθˉ=Eτpθ(τ)[pθpθ(τ)R(τ)logpθ(τ)](5)

于是可得
E ( s t , a t ) ∼ π θ ′ [ p θ ( a t ∣ s t ) p θ ′ ( a t ∣ s t ) A θ ′ ( s t , a t ) ∇ log ⁡ p θ ( a t n ∣ s t n ) ] (6) E_{(s_t,a_t)\sim\pi_{\theta^{'}}}[\frac{p_\theta(a_t|s_t)}{p_{\theta^{'}}(a_t|s_t)}A^{\theta^{'}}(s_t,a_t) \nabla \log p_\theta(a_t^n|s_t^n)] \tag{6} E(st,at)πθ[pθ(atst)pθ(atst)Aθ(st,at)logpθ(atnstn)](6)
那么基于重要性采样的目标函数为:
J θ ′ ( θ ) = E ( s t , a t ) ∼ π θ ′ [ p θ ( a t , s t ) p θ ′ ( a t ∣ s t ) A θ ′ ( s t , a t ) ] (7) J^{\theta^{'}}(\theta) = E_{(s_t,a_t)\sim \pi_{\theta^{'}}}[\frac{p_\theta(a_t,s_t)}{p_{\theta^{'}}(a_t|s_t)}A^{\theta^{'}}(s_t,a_t)] \tag{7} Jθ(θ)=E(st,at)πθ[pθ(atst)pθ(at,st)Aθ(st,at)](7)
上式中 J θ ′ ( θ ) J^{\theta^{'}}(\theta) Jθ(θ) 中的 θ \theta θ 是我们要去优化的参数, θ ′ \theta^{'} θ 是我们用来做示范,也就是真正与环境交互的策略。 A A A 是优势函数。

2. Proximal Policy Optimization

在重要性采样中有一个关键性问题: p θ ( a t ∣ s t ) p_\theta(a_t|s_t) pθ(atst) p θ ′ ( a t ∣ s t ) p_{\theta^{'}}(a_t|s_t) pθ(atst)不能相差太多,否则重要性采样的结果就会不好。至于如何做到这一点,就要用到 PPO 了。

要使得 p θ ′ ( a t ∣ s t ) p_{\theta^{'}}(a_t|s_t) pθ(atst) 不能相差太多,就应该加上一个约束,这个约束可以是 θ \theta θ θ ′ \theta^{'} θ 输出动作的 KL 散度 (KL divergence),这一项用来衡量两个策略的相似程度。两个策略越相似越好,如果不相似,那么最后的结果就会不太好。
J P P O θ ′ ( θ ) = J θ ′ ( θ ) − β K L ( θ , θ ′ ) (8) J_{PPO}^{\theta^{'}}(\theta)=J^{\theta^{'}}(\theta) - \beta KL(\theta, \theta^{'}) \tag{8} JPPOθ(θ)=Jθ(θ)βKL(θ,θ)(8)
其中的 J θ ′ ( θ ) J^{\theta^{'}}(\theta) Jθ(θ) 就是式(7) 。

需要注意的是,虽然 PPO 的优化目标涉及到了重要性采样,但是只用到了上一轮策略 θ ′ \theta^{'} θ 的数据。PPO 目标函数中加入了 KL 散度的约束,行为策略 θ ′ \theta^{'} θ 和目标策略 θ \theta θ 非常相近,所以 PPO 的行为策略和目标策略可认为是同一个策略,因此 PPO 是同策略算法。

这时候可能会有疑问:重要性采样用的是两个策略,但是 PPO 又是同策略,那为什么还要用重要性策略呢?这时可以再想想重要性采样的作用是什么,其要解决的问题又是什么。在重要性采样中我们用 θ ′ \theta^{'} θ 采样,解决 θ \theta θ 的问题,不需要再像之前那样采集一次数据学习一次,而是可以从另一个分布中采样数据进行学习,并且这些数据可以多次利用,也就是 θ \theta θ 可以进行多次更新,一直到 θ \theta θ 训练到一定的程度之后再让 θ ′ \theta^{'} θ 重新采样,这样训练就会更有效率。

PPO 源自信任区域策略优化(Trust Region Policy Optimization, TRPO), TRPO 可表示为:
J T R P O θ ′ ( θ ) = E ( s t , a t ) ∼ π θ ′ [ p θ ( a t ∣ s t ) p θ ′ ( a t ∣ s t ) A θ ′ ( s t , a t ) ] , K L ( θ , θ ′ ) < δ (9) J_{TRPO}^{\theta^{'}}(\theta) = E_{(s_t,a_t) \sim \pi_{\theta^{'}}}[\frac{p_\theta(a_t|s_t)}{p_{\theta^{'}}(a_t|s_t)}A^{\theta^{'}}(s_t,a_t)], KL(\theta,\theta^{'}) < \delta \tag{9} JTRPOθ(θ)=E(st,at)πθ[pθ(atst)pθ(atst)Aθ(st,at)],KL(θ,θ)<δ(9)
TRPO 的核心思想是,当策略网络是深度模型时,直接沿着策略梯度更新参数可能会导致策略更新幅度过大,从而显著降低策略的性能,影响训练效果。为了避免这种情况, TRPO 在更新参数时引入了信任区域的概念,通过限制新旧策略之间的KL 散度,使策略更新控制在一个安全范围内,从而保证更新后的策略不会偏离得太远。这种做法有效提高了训练的稳定性。但是 TRPO 需要求解一个带约束的优化问题(通常通过共轭梯度法实现),实现较为复杂且对超参数敏感。 PPO 对此进行了改进,通过引入**裁剪(Clipping)**策略或者额外的 KL 散度惩罚项,简化了约束优化过程,同时保留了对策略更新幅度的限制。

通过式(8) 和式(9) 两个目标函数可以看到 TRPO 与 PPO 不一样的地方是约束所在的位置不一样,PPO 直接将约束放到要优化的式子里面,这样就可以用梯度上升的方法去最大化式(8)。 而 TRPO 是把 KL 散度当作约束,其希望 θ \theta θ θ ′ \theta^{'} θ 的 KL 散度小于 δ \delta δ

上面提到 PPO 通过引入裁剪或 KL 散度惩罚简化了约束优化过程,接下来就看一下 PPO 算法的这两个变种:近端策略优化惩罚(PPO-penalty) 和 近端策略优化裁剪(PPO-clip)

3. PPO-Penalty

近端策略优化惩罚算法使用拉格朗日乘数法将 KL 散度的约束转换为目标函数中的惩罚项,变成了一个无约束的优化问题。在目标函数中加入 KL 散度惩罚项后,算法会在迭代过程中动态调整惩罚系数(KL 散度前的系数,比如式(8)中的 β \beta β) ,以控制策略更新幅度。如果 KL 散度过大,增大惩罚系数,从而限制更新幅度;如果 KL 散度过小,则减小惩罚系数,允许更积极地更新。这样即保留了 PPO 的更新稳定性,又显著简化了优化过程。

具体实现是,先初始化一个策略的参数 θ 0 \theta^{0} θ0 。在每一个迭代里面,我们用前一个训练的迭代得到的演员的参数 θ k \theta^{k} θk 与环境交互,采样到大量状态-动作对。根据 θ k \theta^{k} θk 交互的结果,我们估测 A θ k ( s t , a t ) A^{\theta^k}(s_t,a_t) Aθk(st,at) 。这里使用 PPO 的优化公式,但与原来的策略梯度不一样,原来的策略梯度只能更新一次参数,更新完以后,我们就要重新采样数据。但是现在不同,我们用 θ k \theta^k θk 与环境交互,采样到这组数据以后,我们可以让 θ \theta θ 更新很多次,并最大化目标函数。

此外还有一个自适应 KL 散度(adaptive KL divergence) 。这里的自适应要解决的问题是 β \beta β 应该设置为多少。这里可以动态调整,先设一个可以接受的 KL 散度的最大值。如果优化完式(8) 之后, KL 散度的值太大,这就代表后面惩罚的项 β K L ( θ , θ k ) \beta KL(\theta, \theta^{k}) βKL(θ,θk) 没有发挥作用,此时需要将 β \beta β 增大,另外,再设一个 KL 散度的最小值。如果做完目标函数优化之后,KL 散度的值比最小值还要小,那么就说明后面这一项的效果太强了,担心优化时只优化后一项使得 θ \theta θ θ k \theta^k θk 一样,所以需要减小 β \beta β 。由于 β \beta β 是可以动态调整的,所以称之为自适应KL惩罚(adaptive KL penalty)

  • 如果 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 β

近端策略惩罚优化可表示为
J P P O θ k ( θ ) = J θ k ( θ ) − β K L ( θ , θ k ) J θ k ( θ ) ≈ ∑ ( s t , a t ) p θ ( a t ∣ s t ) p θ k ( a t ∣ s t ) A θ k ( s t , a t ) (10) J_{PPO}^{\theta^{k}}(\theta)=J^{\theta^{k}}(\theta) - \beta KL(\theta, \theta^{k}) \\ J^{\theta^k}(\theta) \approx \sum_{(s_t,a_t)}\frac{p_\theta(a_t|s_t)}{p_{\theta^k}(a_t|s_t)}A^{\theta^k}(s_t,a_t) \tag{10} JPPOθk(θ)=Jθk(θ)βKL(θ,θk)Jθk(θ)(st,at)pθk(atst)pθ(atst)Aθk(st,at)(10)

4. PPO-Clip

近端策略优化裁剪的目标函数中没有 KL 散度,其要最大化的目标函数为
J P P O − c l i p θ k ( θ ) ≈ ∑ ( s t , a t ) m i n ( p θ ( a t ∣ s t ) p θ k ( a t ∣ s t ) A θ k ( s t , a t ) , c l i p ( p θ ( a t ∣ s t ) p θ k ( a t ∣ s t ) , 1 − ϵ , 1 + ϵ ) A θ k ( s t , a t ) ) (11) J^{\theta^{k}}_{PPO-clip}(\theta) \approx \sum_{(s_t,a_t)}min \Big(\frac{p_\theta(a_t|s_t)}{p_{\theta^k}(a_t|s_t)}A^{\theta^k}(s_t,a_t), clip(\frac{p_\theta(a_t|s_t)}{p_{\theta^k}(a_t|s_t)},1-\epsilon,1+\epsilon)A^{\theta^k}(s_t,a_t)\Big) \tag{11} JPPOclipθk(θ)(st,at)min(pθk(atst)pθ(atst)Aθk(st,at),clip(pθk(atst)pθ(atst),1ϵ,1+ϵ)Aθk(st,at))(11)

  • $\epsilon $ 是一个超参数

PPO-Clip 直接在目标函数中进行限制,确保新旧策略差距不会过大,其核心思想是通过裁剪(clipping)的方式限制策略更新的幅度,从而在提高性能的同时,避免策略更新过渡导致的不稳定性。

p θ ( a t ∣ s t ) p θ k ( a t ∣ s t ) \frac{p_\theta(a_t|s_t)}{p_{\theta^k}(a_t|s_t)} pθk(atst)pθ(atst) 这一项是重要性采样,可以将它看作优势函数 A θ k ( s t , a t ) A^{\theta^k}(s_t,a_t) Aθk(st,at) 的比例因子 r θ r_\theta rθ ,它反映了前后两个策略在某个动作上的相对变化。裁剪操作会限制 r θ r_\theta rθ 的范围,防止某个动作的概率发生过大的相对变化。这种局部限制有助于间接控制新旧策略在整体分布上的差异幅度,从而避免策略更新过度导致训练不稳定,裁剪(clip)操作的具体实现为:
clip ⁡ ( r θ , 1 − ϵ , 1 + ϵ ) = { 1 − ϵ i f r θ < 1 − ϵ , r θ i f 1 − ϵ ≤ r θ ≤ 1 + ϵ , 1 + ϵ i f r θ > 1 + ϵ . (12) \operatorname{clip}(r_\theta,1-\epsilon,1+\epsilon)= \begin{cases} 1-\epsilon & \mathrm{if} \ r_\theta<1-\epsilon, \\ r_\theta & \mathrm{if} \ 1-\epsilon\leq r_\theta\leq1+\epsilon, \\ 1+\epsilon & \mathrm{if} \ r_\theta>1+\epsilon. & \end{cases} \tag{12} clip(rθ,1ϵ,1+ϵ)= 1ϵrθ1+ϵif rθ<1ϵ,if 1ϵrθ1+ϵ,if rθ>1+ϵ.(12)
从式(11)中可以看出 PPO-clip 中的目标函数的关键是 m i n min min 操作:
m i n ( r θ A θ k ( s t , a t ) , c l i p ( r θ , 1 − ϵ , 1 + ϵ ) A θ k ( s t , a t ) ) (13) min\Big(r_\theta A^{\theta^k}(s_t,a_t), clip(r_\theta,1-\epsilon,1+\epsilon)A^{\theta^k}(s_t,a_t)\Big) \tag{13} min(rθAθk(st,at),clip(rθ,1ϵ,1+ϵ)Aθk(st,at))(13)
r θ A θ k ( s t , a t ) r_\theta A^{\theta^k}(s_t,a_t) rθAθk(st,at) 是未加限制的目标,直接用重要性采样因子 r θ r_\theta rθ 来放大或缩小优势函数的作用;
c l i p ( r θ , 1 − ϵ , 1 + ϵ ) A θ k ( s t , a t ) clip(r_\theta,1-\epsilon,1+\epsilon)A^{\theta^k}(s_t,a_t) clip(rθ,1ϵ,1+ϵ)Aθk(st,at) 是经过裁剪的版本,来限制 r θ r_\theta rθ 的变化范围,防止策略更新幅度过大。

如上图(a)所示,如果 A>0 ,取最小的结果,即红色的线;如上图(b)所示,如果 A<0 ,取最小的结果也就是取 r θ r_\theta rθ 最大的结果,即红色的线。

优势函数 A 表示在某个状态下某个动作相对基线的好坏,如果 A>0 ,也就是该状态-动作对是好的,那么就可以增大这个状态-动作对的概率,也就是让 p θ ( a t ∣ s t ) p_\theta(a_t|s_t) pθ(atst) 越大越好,一直大到 1 + ϵ 1+\epsilon 1+ϵ 最大;如果 A<0 ,也就是该状态-动作对是不好的,那么就应该减小 p θ ( a t ∣ s t ) p_\theta(a_t|s_t) pθ(atst) ,一直减到 1 − ϵ 1-\epsilon 1ϵ 最小。

相比于 PPO-penalty ,PPO-clip 不需要动态调整 KL 散度的惩罚系数 β \beta β ,而是直接通过裁剪实现对策略更新幅度的控制,所以其计算效率更高,仅需要简单的比较运算,而 PPO-penalty 需要动态监控 KL 散度大小并调整惩罚系数。

在具体实现时优势函数可以使用 广义优势估计(GAE)。

参考:
1.李宏毅老师的课程的文字整理《强化学习教程》
2.张伟楠老师的书《动手学强化学习》

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

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

相关文章

Flink底层架构与运行流程

这张图展示了Flink程序的架构和运行流程。 主要组件及功能&#xff1a; Flink Program&#xff08;Flink程序&#xff09;&#xff1a; 包含Program code&#xff08;程序代码&#xff09;&#xff0c;这是用户编写的业务逻辑代码。经过Optimizer / Graph Builder&#xff08…

嵌入式知识点总结 C/C++ 专题提升(一)-关键字

针对于嵌入式软件杂乱的知识点总结起来&#xff0c;提供给读者学习复习对下述内容的强化。 目录 1.C语言宏中"#“和"##"的用法 1.1.(#)字符串化操作符 1.2.(##)符号连接操作符 2.关键字volatile有什么含意?并举出三个不同的例子? 2.1.并行设备的硬件寄存…

mysql精简单机版,免登录,可复制,不启动服务与本机mysql无冲突

突然有了个需要在本地使用的mysql需求&#xff0c;要求不用安装,随拷随用,不影响其他mysql服务,占用空间小.基于这种需求做了个精简版的mysql 首先下载mysql的zip安装包 > windows 64位 > https://repo.huaweicloud.com/mysql/Downloads/MySQL-5.7/mysql-5.7.36-winx64…

俄语画外音的特点

随着全球媒体消费的增加&#xff0c;语音服务呈指数级增长。作为视听翻译和本地化的一个关键方面&#xff0c;画外音在确保来自不同语言和文化背景的观众能够以一种真实和可访问的方式参与内容方面发挥着重要作用。说到俄语&#xff0c;画外音有其独特的特点、挑战和复杂性&…

【vitePress】基于github快速添加评论功能(giscus)

一.添加评论插件 使用giscus来做vitepress 的评论模块&#xff0c;使用也非常的简单&#xff0c;具体可以参考&#xff1a;giscus 文档&#xff0c;首先安装giscus npm i giscus/vue 二.giscus操作 打开giscus 文档&#xff0c;如下图所示&#xff0c;填入你的 github 用户…

python麻辣香锅菜品推荐

1.推荐算法概述 推荐算法出现得很早,最早的推荐系统是卡耐基梅隆大学推出的Web Watcher浏览器导航系统&#xff0c;可以根据当的搜索目标和用户信息,突出显示对用户有用的超链接。斯坦福大学则推出了个性化推荐系统LIRA.AT&T实验室于1997年提出基于协作过滤的个性化推荐系统…

Android系统开发(六):从Linux到Android:模块化开发,GKI内核的硬核科普

引言&#xff1a; 今天我们聊聊Android生态中最“硬核”的话题&#xff1a;通用内核镜像&#xff08;GKI&#xff09;与内核模块接口&#xff08;KMI&#xff09;。这是内核碎片化终结者的秘密武器&#xff0c;解决了内核和供应商模块之间无尽的兼容性问题。为什么重要&#x…

UE 像素流Pixel Streaming笔记

参考 UE 像素流Pixel Streaming基本介绍和使用方法 UE4-PixelStreaming&#xff08;虚幻引擎4-像素流&#xff09;笔记 UE 像素流常用回调 UE 像素流通信 这链接能学到不少像素流的东西 使用 1.像素流连接成功&#xff08;On New Connection&#xff09; 必须使用GetPixe…

Java 资源管理教程:掌握 close 方法、Cleaner 类与 Runtime.addShutdownHook

在 Java 编程中&#xff0c;高效地管理资源是至关重要的&#xff0c;特别是当你处理文件、数据库连接、网络连接等有限资源时。为了确保这些资源得到正确释放&#xff0c;Java 提供了多种机制。本教程将深入探讨 close 方法、Cleaner类以及 Runtime.addShutdownHook 方法&#…

ASP.NET Blazor部署方式有哪些?

今天我们来说说Blazor的三种部署方式&#xff0c;如果大家还不了解Blazor&#xff0c;那么我先简单介绍下Blazor Blazor 是一种 .NET 前端 Web 框架&#xff0c;在单个编程模型中同时支持服务器端呈现和客户端交互性&#xff1a; ● 使用 C# 创建丰富的交互式 UI。 ● 共享使用…

微信小程序使用上拉加载onReachBottom。页面拖不动。一直无法触发上拉的事件。

1&#xff0c;可能是原因是你使用了scroll-view的标签&#xff0c;用onReachBottom触发加载事件。这两个是有冲突的。没办法一起使用。如果页面的样式是滚动的是无法去触发页面的onReachBottom的函数的。因此&#xff0c;你使用overflow:auto.来使用页面的某些元素滚动&#xf…

学习ASP.NET Core的身份认证(基于JwtBearer的身份认证9)

测试数据库中只有之前记录温湿度及烟雾值的表中数据较多&#xff0c;在该数据库中增加AppUser表&#xff0c;用于登录用户身份查询&#xff0c;数据库表如下所示&#xff1a;   项目中安装SqlSugarCore包&#xff0c;然后修改控制器类的登录函数及分页查询数据函数&#xff…

【人工智能】:搭建本地AI服务——Ollama、LobeChat和Go语言的全方位实践指南

前言 随着自然语言处理&#xff08;NLP&#xff09;技术的快速发展&#xff0c;越来越多的企业和个人开发者寻求在本地环境中运行大型语言模型&#xff08;LLM&#xff09;&#xff0c;以确保数据隐私和提高响应速度。Ollama 作为一个强大的本地运行框架&#xff0c;支持多种先…

Flutter:carousel_slider 横向轮播图、垂直轮播公告栏实现

安装依赖 carousel_slider: ^5.0.01、垂直滚动公告栏 import package:carousel_slider/carousel_options.dart;// 垂直滚动公告栏Widget _buildNotice() {return <Widget>[<Widget>[TDImage(assetUrl: "assets/img/home11.png",width: 60.w,height: 60.w…

图像去雾数据集的下载和预处理操作

前言 目前&#xff0c;因为要做对比实验&#xff0c;收集了一下去雾数据集&#xff0c;并且建立了一个数据集的预处理工程。 这是以前我写的一个小仓库&#xff0c;我决定还是把它用起来&#xff0c;下面将展示下载的路径和数据处理的方法。 下面的代码均可以在此找到。Auo…

C++ 面向对象(继承)

三、继承 3.1 继承的概念 基于一个已有的类 去重新定义一个新的类&#xff0c;这种方式我们叫做继承 关于继承的称呼 一个类B 继承来自 类 A 我们一般称呼 A类&#xff1a;父类 基类 B类: 子类 派生类 B继承自A A 派生了B 示例图的语法 class vehicle // 车类 {}class …

若依报错:无法访问com.ruoyi.common.annotation

无法访问com.ruoyi.common.annotation 若依的父工程的pom文件中设置了jdk为1.8&#xff0c;将idea的jdk也改为1.8即可。

< OS 有关 > 阿里云:轻量应用服务器 的使用 安装 Tailscale 后DNS 出错, 修复并替换 apt 数据源

VPS 配置 主机&#xff1a;vCPU x2, 512MB, 20GB位置&#xff1a;阿里云&#xff0c;日本.东京OS&#xff1a; ubuntu24.20 原因&#xff1a; 这篇是操作过程的记录文章。 2 个月前&#xff0c; 在阿里云买了台 vps 。当时本想放到韩国&#xff0c;因为它离北京近。 但最便…

小企业品牌塑造之困-中小企实战运营和营销工作室博客

小企业品牌塑造之困-中小企实战运营和营销工作室博客 在商业的广袤天地中&#xff0c;小企业如点点繁星&#xff0c;怀揣着成长为璀璨星辰的梦想。品牌塑造&#xff0c;无疑是它们迈向成功的关键路径。然而&#xff0c;现实却布满荆棘&#xff0c;众多小企业在品牌塑造的征程中…

HTML5 Canvas和JavaScript的3D粒子星系效果

HTML部分 基本结构包括<html>, <head>, 和 <body>标签。<title>标签设置了页面标题为“优化版3D粒子星系”。<style>块定义了一些基本样式&#xff1a; body&#xff1a;无边距&#xff0c;隐藏滚动条&#xff0c;黑色背景&#xff0c;禁用触摸…