强化学习Q-Learning:DQN
强化学习Q-Learning/DQN
本文是一篇学习笔记,主要参考李宏毅老师的强化学习课程。
目前主流的强化学习方法大致可以分为 policy-based 和 value-based 两大类。之前我们介绍的 policy gradient 策略梯度,就是 policy-based 的方法。本文要介绍的 Q-learning 则是 value-based 方法。不同于 policy gradient 直接优化 policy,Q-learning 是要学习一个价值网络,来估计策略的状态价值或动作状态价值,价值网络并不直接决定接下来要采取的动作,我们需要基于价值网络估计出的价值函数,制定新的 policy,并不断优化 policy。
本文将介绍如何训练模型来拟合价值函数,以及 Q-learning 如何基于价值网络不断优化 policy,最后介绍实际实现中常用的几个技巧。
价值函数
价值函数是强化学习中的重要概念,也是 value-based 类方法的基础。价值函数有关于状态 s s s 和关于状态-动作对 ( s , a ) (s,a) (s,a) 两种。这里的价值是指从这个状态 s s s 或从这个状态-动作对 ( s , a ) (s,a) (s,a) 开始,一直按照某个特定的策略进行动作,直到结束,这期间的期望回报就称为价值函数。
状态价值函数, V π ( s ) V^\pi(s) Vπ(s),是指在状态 s s s,接下来按照特定的策略 π \pi π 来进行动作,最终累积回报的期望,表示为:
V π ( s ) = E τ ∼ π [ R ( τ ) ∣ s 0 = s ] V^\pi(s)=\mathbb{E}_{\tau\sim\pi}[R(\tau)|s_0=s] \notag \\ Vπ(s)=Eτ∼π[R(τ)∣s0=s]
其中 τ \tau τ 是在状态 s s s 之后,根据策略 π \pi π 进行动作得到的轨迹, R ( τ ) R(\tau) R(τ) 即该轨迹得到的累积奖励。
动作-状态价值函数, Q π ( s , a ) Q^\pi(s,a) Qπ(s,a),是指在状态 s s s,先强制采取动作 a a a(这个动作不一定符合当前策略 π \pi π,是人为采取的),接下来按照特定的策略 π \pi π 来进行动作,最终累积回报的期望。表示为:
Q π ( s , a ) = E τ ∼ π [ R ( τ ) ∣ s 0 = s , a 0 = a ] Q^\pi(s,a)=\mathbb{E}_{\tau\sim\pi}[R(\tau)|s_0=s,a_0=a] \notag \\ Qπ(s,a)=Eτ∼π[R(τ)∣s0=s,a0=a]
从两种价值函数的定义上不难发现,二者之间存在这样的关系:
V π ( s ) = E a ∼ π [ Q π ( s , a ) ] (1) V^\pi(s)=\mathbb{E}_{a\sim\pi}[Q^\pi(s,a)] \tag{1} \\ Vπ(s)=Ea∼π[Qπ(s,a)](1)
即状态价值函数 V V V 是动作-价值函数 Q Q Q 在策略 π \pi π 下的期望。也可以更直接一点,带进去,写成:
V π ( s ) = Q π ( s , π ( s ) ) (2) V^\pi(s)=Q^\pi(s,\pi(s)) \tag{2} \\ Vπ(s)=Qπ(s,π(s))(2)
还是要强调一句,两种价值函数描述的都是针对某个特定的策略 π \pi π 的价值,对于不同的策略 π \pi π,同一个状态 s s s 的价值很可能是不同的。比如棋魂里的阿光,在刚学棋时可能驾驭不了高难度的棋招 “大飞”,此时策略(actor)“阿光” 对于 “大飞” 这个状态的价值函数估计就比较低,当阿光棋力上涨,能够驾驭这一招时,价值函数估计就比较高。即对于不同的 π \pi π,同样状态 s s s 的价值是不同的,所以价值函数都是针对特定的策略 π \pi π 来说的。
V 以前的阿光 ( 大飞 ) = low V 现在更强的阿光 ( 大飞 ) = high \begin{aligned} V^\text{以前的阿光}(大飞)&=\text{low} \\ \quad V^\text{现在更强的阿光}(大飞)&=\text{high} \end{aligned} \notag \\ V以前的阿光(大飞)V现在更强的阿光(大飞)=low=high
从 Q-learning 的思路来进行强化学习建模,需要两个步骤,首先是我们要如何训练网络来拟合价值函数 V / Q V/Q V/Q,然后是有了一个可靠的价值函数后,如何决定动作。我们接下来分别介绍这两步。
训练价值网络估计价值函数
现在我们一般是用神经网络来估计价值函数(DQN)了,我们需要价值网络是一个回归模型,输入一个状态(和动作),输出一个标量分数。那么如何训练这个神经网络呢?有两种方法,MC(Monte Carlo,蒙特卡洛) 和 TD(Temporal Difference,时序差分)。
MC 方法
MC 来训练价值网络的想法非常直觉,比如我们要估计 V π ( s ) V^\pi(s) Vπ(s),它是策略 π \pi π 在状态 s s s 之后的期望回报,那我们就让 π \pi π 把整个 episode 跑出来,记录下最终的累积回报 R ( τ ) R(\tau) R(τ),让价值网络回归这个累积回报就行了。
V ^ π ( s ) → R ( τ ) \hat{V}^\pi(s)\rightarrow R(\tau) \notag \\ V^π(s)→R(τ)
理想情况下是能遍历所有可能的状态,得到最终累积回报来给价值网络学习,但这显然不可能,因此就采样 N N N 轮来近似。
TD 方法
MC 方法非常直觉,但问题在于每次都至少要等到一整轮 episode 跑完,才能更新一次模型。在很多实际的强化学习任务(如围棋、游戏等)中,跑完一整轮 episode 通常非常久,导致训练效率不高。而 TD 的方法,在每次动作,有了 { s t , a t , r t , s t + 1 } \{s_t, a_t, r_t, s_{t+1}\} {st,at,rt,st+1} 这一组数据之后,就能进行一次更新。
具体来说,我们先改写一下 V π ( s t ) V^\pi(s_t) Vπ(st):
V π ( s t ) = V π ( s t + 1 ) + r t V^\pi(s_t)=V^\pi(s_{t+1})+r_t \notag \\ Vπ(st)=Vπ(st+1)+rt
这个式子的意思很简单:状态 s t s_t st 的价值函数 V π ( s t ) V^\pi(s_t) Vπ(st) 等于当前立即得到的奖励 r t r_t rt 加上下一个状态的价值函数 V π ( s t + 1 ) V^\pi(s_{t+1}) Vπ(st+1)。
这样,在我们有了单步的一组数据之后,就可以将 s t , s t + 1 s_t,s_{t+1} st,st+1 分别送入价值网络,得到相邻两步的价值估计值 V π ( s t ) , V π ( s t + 1 ) V^\pi(s_t),V^\pi(s_{t+1}) Vπ(st),Vπ(st+1),我们的训练目标就是希望这两个估计值的差值尽可能接近当前步的真实奖励 r t r_t rt:
V ^ π ( s t ) − V ^ π ( s t + 1 ) → r t \hat{V}^\pi(s_t)-\hat{V}^\pi(s_{t+1})\rightarrow r_t \notag \\ V^π(st)−V^π(st+1)→rt
对比 MC 和 TD
我们对比一下 MC 和 TD 彼此的优缺点。
首先,MC 需要一整轮的数据才能进行一次更新,而 TD 只需一步的数据即可进行更新,训练效率更高。其次,MC 的目标值是 R ( τ ) R(\tau) R(τ),取决于其后所有步的随机采样结果,方差会比较大,而 TD 的目标是单步采样的数据 r t r_t rt,方差比较小。
但是,毕竟 TD 的目标中 V ^ π ( s t + 1 ) \hat{V}^\pi(s_{t+1}) V^π(st+1) 也是价值网络估计出来,因此 TD 不一定准。而 MC 的 R ( τ ) R(\tau) R(τ) 都是实打实跟环境交互跑出来的,是真实的目标。
总之 MC 和 TD 看起来还是各有优劣,但是现在一般都是采用 TD 方法来训练价值网络。
更好地policy
现在我们已经可以使用 MC 或 TD 方法来训练价值网络,估计价值函数,但是价值网络毕竟只是一个打分的模型,没法直接选择执行哪个动作,在实际中,有了价值函数之后,如何进行动作呢?也就是我们基于估计的价值函数,如何实现 policy 呢?以及我们如何能够在价值网络的引导下,不断地优化 policy 呢?
Q-learning 整体的过程如下图所示。最开始我们有一个初始的策略 π \pi π,我们让它与环境互动,得到一系列经验数据,然后在这些数据上采用 TD 或 MC 的方法,来学习出这个策略 π \pi π 对应的价值函数 Q π ( s , a ) Q^\pi(s,a) Qπ(s,a)。然后根据这个价值函数,得到一个 “更好的” 策略 π ′ \pi' π′,随后再用这个 π ′ \pi' π′ 作为策略,继续上述过程,循环往复,不断地优化策略。这里所谓的 “更好”,指的是对于所有的状态 s s s,都有 V π ′ ( s ) ≥ V π ( s ) V^{\pi'}(s)\ge V^\pi(s) Vπ′(s)≥Vπ(s)。
现在的问题就是,如何根据价值函数,得到一定比现在更好的策略 π ′ \pi' π′。实际上也非常简单,就是根据学习到的关于策略 π \pi π 的价值函数,取 argmax:
π ′ ( s ) = arg max a Q π ( s , a ) \pi'(s)=\arg\max_aQ^\pi(s,a) \notag \\ π′(s)=argamaxQπ(s,a)
直觉上很好理解,每一步我们都取能让 Q Q Q 值最大的动作,最终得到的累积回报,肯定比当前按策略 π \pi π 要高。以下我们来简单证明推导一下:取 π ′ ( s ) = arg max a Q π ( s , a ) \pi'(s)=\arg\max_aQ^\pi(s,a) π′(s)=argmaxaQπ(s,a),可以使得对所有的状态 s s s,都有 V π ′ ( s ) ≥ V π ( s ) V^{\pi'}(s)\ge V^\pi(s) Vπ′(s)≥Vπ(s)。
首先我们写出 V V V 和 Q Q Q 的关系(式 2),状态价值函数 V π ( s ) V^\pi(s) Vπ(s) 相当于状态-动作价值函数 Q π ( s , a ) Q^\pi(s,a) Qπ(s,a) 取 a = π ( s ) a=\pi(s) a=π(s),即在当前步也按照策略 π \pi π 来选取动作执行。注意我们此时已知 Q Q Q 函数了,所以我们是知道当前每个动作所得到的 Q Q Q 值的,因此我们可以直接贪婪地选取一个让 Q Q Q 值最大的动作 a a a,这样肯定是大于等于按照 π \pi π 选取动作的。而这种按照 arg max Q \arg\max Q argmaxQ 来选取动作的策略,正是我们刚刚定义的策略 π ′ \pi' π′ 。
V π ( s ) = Q π ( s , π ( s ) ) ≤ max a ( Q π ( s , a ) ) = Q π ( s , π ′ ( s ) ) V^\pi(s)=Q^\pi(s,\pi(s))\le\max_a(Q^\pi(s,a))=Q^\pi(s,\pi'(s)) \notag \\ Vπ(s)=Qπ(s,π(s))≤amax(Qπ(s,a))=Qπ(s,π′(s))
这是一步的差异。而如果我们每一步都采用 π ′ ( s ) = arg max a Q π ( s , a ) \pi'(s)=\arg\max_a Q^\pi(s,a) π′(s)=argmaxaQπ(s,a) ,自然是更加优于 π \pi π,这最终能推导出 V π ( s ) ≤ V π ′ ( s ) V^\pi(s)\le V^{\pi'}(s) Vπ(s)≤Vπ′(s):
V π ( s ) ≤ Q π ( s , π ′ ( s ) ) = E [ r t + V π ( s t + 1 ) ∣ s t = s , a t = π ′ ( s t ) ] ≤ E [ r t + Q π ( s t + 1 , π ′ ( s t + 1 ) ) ∣ s t = s , a t = π ′ ( s t ) ] = E [ r t + r t + 1 + V π ( s t + 2 ) ∣ . . . ] ≤ E [ r t + r t + 1 + Q π ( s t + 2 , π ′ ( s t + 2 ) ) ∣ . . . ] = . . . ≤ . . . ≤ V π ′ ( s ) \begin{aligned} V^\pi(s)&\le Q^\pi(s,\pi'(s)) \\ &=\mathbb{E}\left[r_t+V^\pi(s_{t+1})|s_t=s,a_t=\pi'(s_t)\right] \\&\le\mathbb{E}\left[r_t+Q^\pi(s_{t+1},\pi'(s_{t+1}))|s_t=s,a_t=\pi'(s_t)\right] \\ &=\mathbb{E}\left[r_t+r_{t+1}+V^\pi(s_{t+2})|...\right] \\ &\le\mathbb{E}\left[r_t+r_{t+1}+Q^\pi(s_{t+2},\pi'(s_{t+2}))|...\right] \\ &=...\le... \\ &\le V^{\pi'}(s) \end{aligned} \notag \\ Vπ(s)≤Qπ(s,π′(s))=E[rt+Vπ(st+1)∣st=s,at=π′(st)]≤E[rt+Qπ(st+1,π′(st+1))∣st=s,at=π′(st)]=E[rt+rt+1+Vπ(st+2)∣...]≤E[rt+rt+1+Qπ(st+2,π′(st+2))∣...]=...≤...≤Vπ′(s)
至此,我们就证明了只要选择 π ′ ( s ) = arg max a Q π ( s , a ) \pi'(s)=\arg\max_a Q^\pi(s,a) π′(s)=argmaxaQπ(s,a),就能保证对所有的状态 s s s 都有 V π ′ ( s ) ≥ V π ( s ) V^{\pi'}(s)\ge V^\pi(s) Vπ′(s)≥Vπ(s),也就是 π ′ \pi' π′ 是一个比 π \pi π 更好的策略。然后我根据上图中的过程,不断循环迭代,直至收敛得到一个最终的策略。
Q-learning 常用技巧
我们已经介绍了 Q-learning 的基本思想,接下来我们介绍几个实际中一般都会用到的 tricks。
Target Network
上面提到,现在我们在训练价值网络时,一般会用 TD 方法,其训练目标(以 Q 为例)为:
Q π ( s t , a t ) → r t + Q π ( s t + 1 , a t + 1 ) Q^\pi(s_t,a_t)\rightarrow r_t+Q^\pi(s_{t+1},a_{t+1}) \notag \\ Qπ(st,at)→rt+Qπ(st+1,at+1)
会发现等式两边都有共享的、一直在更新的网络 Q π Q^\pi Qπ,因此网络的拟合目标是在一直变的,虽然看起来上没什么问题,但实际中这种情况下训练通常会非常不稳定。Target Network 的技巧是我们将其中一个网络(一般是图中右下角那个)固定住,更新另一个网络,这样该网络的拟合目标一直是固定的,比较易于训练。在更新 N N N 轮之后,同步一次固定网络的参数。
Exploration
Exploitation v.s. Exploration 是强化学习中的一个重要课题,Exploitation 指利用已有的经验获取尽可能高的累积回报,Exploration 则是指训练时不只关注短期的回报,而是也以一定概率采样其他动作,尽量地探索是否有其他能赢得更高回报的可能选择。
在之前介绍的 Policy Gradient 类算法中,策略网络 π θ \pi_\theta πθ 输出的是一个动作空间的概率分布,每次执行的动作是从该分布中采样得到,即使是概率相对较低的动作也有机会被采样到,因此 Exploration 是已经被考虑在内的。
在刚刚介绍的 Q-learning 算法中,策略 π \pi π 本身不是一个分布,而是对学习到的 Q 函数在各个动作中 argmax 得到,是一种 greedy 的策略,这就导致同一状态下除了 Q 值最高的其他动作永远不会被尝试。假设初始化后,每个动作的默认 Q 值都是 0,那么最先被采样到且获得正 Q 值的动作就会一直被选中,而其它动作无法被探索到。因此,我们需要在 Q-learning 中引入一些机制来增强其 Exploration 能力。
Q-learning 中引入 Exploration 机制的思路其实很简单,只要在训练时,除了 argmax Q 之外,也给一定概率采样到其他动作即可。一般常用的有两种方法,一是 Epsilon Greedy,二是 Boltzmann Exploration。
Epsilon Greedy 是指选择动作时大部分时候( 1 − ϵ 1-\epsilon 1−ϵ)取 argmax Q 的动作,但是也有 ϵ \epsilon ϵ 的概率不管 Q,直接随机选取一个动作:
a = { arg max a Q ( s , a ) , with probability 1 − ϵ random , others a= \begin{cases} \arg\max_a Q(s,a),&\quad \text{with probability } 1-\epsilon \\ \text{random},&\quad\text{others} \end{cases} \notag \\ a={argmaxaQ(s,a),random,with probability 1−ϵothers
ϵ \epsilon ϵ 是一个超参数,其值一般随训练过程衰减,因为我们在训练前期更希望模型多多 Explore,后期则希望稳定的获取高的回报分数。
Boltzmann Exploration 是指我们直接将各动作的 Q 值归一化为一个分布,选取动作时从其中采样
P ( a ∣ s ) = exp ( Q ( s , a ) ) ∑ a exp ( s , a ) P(a|s)=\frac{\exp(Q(s,a))}{\sum_a\exp(s,a)} \notag \\ P(a∣s)=∑aexp(s,a)exp(Q(s,a))
这两种方法都能使得 Q 值较低的动作也有一定概率选中,进行 Exploration。
Replay Buffer
在强化学习中,样本效率也是一个很重要的问题,强化学习训练过程的很大一部分耗时都花在策略 π \pi π 与环境互动收集 rollout 数据上,真正的 GPU 计算梯度反传更新模型其实是很快的。在 Q-learning 中,每个数据只会使用一次,这样的样本效率就不高。为了提高样本的利用率,我们可以将策略 π \pi π 与环境互动的经验 ( s t , a t , r t , s t + 1 ) (s_t,a_t,r_t,s_{t+1}) (st,at,rt,st+1) 保存到一个 Replay Buffer 中,每次训练时从 Replay Buffer 中 sample 一个 batch 的数据用于训练模型。Replay Buffer 技巧一来可以提高样本的利用率,二来由于 Buffer 中所存的经验样本不一定来自于同一个 policy,因此也能提高每个 batch 内样本的多样性。
总结
本文我们先介绍了强化学习中的价值函数,然后介绍如何训练价值网络来拟合价值函数,以及 Q-learning/DQN 中如何不断地优化 policy,最后介绍了 Q-learning 在实际实现中常用的几个技巧。
相关文章:
强化学习Q-Learning:DQN
强化学习Q-Learning/DQN 本文是一篇学习笔记,主要参考李宏毅老师的强化学习课程。 目前主流的强化学习方法大致可以分为 policy-based 和 value-based 两大类。之前我们介绍的 policy gradient 策略梯度,就是 policy-based 的方法。本文要介绍的 Q-learn…...
OpenCv(七)——模板匹配、打包、图像的旋转
目录 一、模板匹配 模板匹配原理 1、单模板之间的匹配 (1)读取并显示待匹配的图片和模板图片 (2)模板匹配并绘制匹配位置的外接矩形 (3)显示最终的效果 2、模板与多个对象匹配,仅匹配当前…...
汽车售后诊断 ODX 和 OTX 对比分析报告
一、引言 在汽车行业不断发展的当下,汽车售后诊断技术对于保障车辆性能、维护车主权益以及提升汽车品牌服务质量起着至关重要的作用。随着汽车电子化程度的不断提高,售后诊断所涉及的数据和流程愈发复杂,这就促使行业需要更加标准化、高效化…...
关于图卷积
深入理解神经网络中的图卷积 一、为什么需要图卷积(动机) 在图结构中,比如: 社交网络(节点是人,边是朋友关系)分子结构(节点是原子,边是化学键)知识图谱&a…...
Meta LLaMA 4:对抗 GPT-4o 与 Claude 的开源王牌
2025 年 4 月,Meta 正式发布了 LLaMA 4 系列的首批两款模型。 这两款模型模型分别是:LLaMA 4 Scout 与 LLaMA 4 Maverick,均采用了 专家混合架构(Mixture-of-Experts, MoE)。 据 Meta 表示,这是首次有 …...
如何进行SQL调优
如何进行SQL调优 SQL 调优是优化数据库查询性能的过程,目的是减少查询的执行时间,提高数据库系统的整体效率。SQL 调优的技巧和方法可以针对不同的数据库管理系统(DBMS)有所不同,但基本的原则和步骤是相似的。以下是一…...
WAF防护规则配置技巧与企业级安全实践指南
面对日益复杂的Web应用攻击,WAF规则配置直接决定防护体系的有效性。本文深度解析规则优先级编排、误报消减策略、智能学习机制等17项关键技术,结合金融行业API攻击案例与Gartner最新防御框架,为企业提供可落地的WAF优化路径。 WAF规则引擎的…...
第16届蓝桥杯单片机模拟试题Ⅱ
试题 代码 sys.h #ifndef __SYS_H__ #define __SYS_H__#include <STC15F2K60S2.H> //ds1302.c extern unsigned char time[3]; void w_ds1302(); void r_ds1302(); //iic.c float v_adc(unsigned char addr); //sys.c extern float light_v; extern float rb2_v; exte…...
机器学习——ROC曲线、PR曲线
一、ROC曲线简介 1.1 ROC曲线的构成 1.横轴(假正率,FPR): 表示负样本被错误分类为正的比例(越小越好) 2.纵轴(真正率,TPR,即召回率): 表示正样…...
Flutter之交互事件
目录: 1、点击事件标准案例1.1、效果图2.1、代码实现 1、点击事件标准案例 1.1、效果图 2.1、代码实现 class FavoriteWidget extends StatefulWidget {const FavoriteWidget({super.key});overrideState<FavoriteWidget> createState() > _FavoriteWidge…...
深入解析Spring Boot自动装配:原理、设计与最佳实践
引言 Spring Boot作为现代Java开发中的一股清流,凭借其简洁、快速和高效的特性,迅速赢得了广大开发者的青睐。而在Spring Boot的众多特性中,自动装载(Auto-configuration)无疑是最为耀眼的明珠之一。本文将深入剖析Sp…...
【责任链】模式解决流程中多个接口的流程问题
业务需求 整体流程有5步骤,每个步骤调用一个接口,每个接口成功才能进行下一步。如a->b->c->d->e, 比如入学报到 a:报班,根据名字生成学号uid b:根据学号分配班级获取班级编号cid c:…...
excel常见错误包括(#N/A、#VALUE!、#REF!、#DIV/0!、#NUM!、#NAME?、#NULL! )
目录 1. #N/A2. #VALUE!3. #REF!4. #DIV/0!5. #NUM!6. #NAME?7. #NULL!8.图表总结 在 Excel 中,可能会遇到以下常见的错误值,每个都有特定的含义和成因: 1. #N/A 含义: 表示“Not Available”(不可用)。…...
【湖南大学】2025我们该如何看待DeepSeek
大家好,我是樱木。 DeepSeek 官方网站:https://www.deepseek.com/ 一、DeepSeek 到底是什么? TA 到底厉害在哪里? 故事从 ChatGPT 说起 去年我们看到 Open AI 发布ChatGPT 后,全球的注意力到了 AI 身上。 我们来拆…...
RAG中构建个人知识库
1. 添加本地模型 1.1 查看本地模型 ollama list1.2 ragflow添加本地模型 1.3 系统模型配置 2. 构建知识库 2.1 准备知识库素材 2.2 配置知识库 2.3 知识库绑定素材文件 上传文件素材 - 解析文件 3. 构建交互系统 3.1 配置助理 3.2 完善提示词 3.3 设置模型参数 4. 体验效…...
在 Kubernetes (k8s) 中,apiserver 的 IIP和 VIP的区别
在 Kubernetes (k8s) 中,apiserver 的 IIP(Internal IP) 和 VIP(Virtual IP) 是与集群网络通信和高可用性设计相关的两个重要概念。 IIP(Internal IP) 定义: IIP 是 apiserver 所在…...
OpenCV--图像形态学
在图像处理领域,图像形态学是一种基于形状进行图像分析的有力工具,广泛应用于图像分割、特征提取、边缘检测、图像降噪等多个方面。借助 OpenCV 这个强大的计算机视觉库,我们可以轻松实现各种图像形态学操作。本文将深入探讨图像形态学的基本…...
智慧医疗数据集
WiNGPT2 更新时间:2024-11-29 访问地址: GitHub 描述: WiNGPT是一个基于GPT的医疗垂直领域大模型,旨在将专业的医学知识、医疗信息、数据融会贯通,为医疗行业提供智能化的医疗问答、诊断支持和医学知识等信息服务,…...
3D激光轮廓仪知识整理(待补充)
文章目录 1.原理和应用场景1.1 相机原理1.1.1 测量原理1.1.2 相机激光器1.1.3 沙姆镜头1.1.4 相机标定1.1.5 中心线提取 1.2 应用场景1.2.1 测量相关应用1.2.2 缺陷检测相关易用 2.相机参数介绍及选型介绍2.1 成像原理2.2 原始图成像2.3 生成轮廓图2.4 相机规格参数2.4.1 单轮廓…...
算法思想之双指针
文章目录 双指针字符串序列判定字符串所有整数最小和服务交换接口失败率分析分披萨最多团队 双指针 双指针是指在解决问题时使用两个指针,通常分别指向数组或字符串中的不同位置,通过移动这两个指针来解决问题的一种技巧。双指针技巧常用于解决数组、链…...
Windows环境下PyCharm 配置miniforge
问题描述. 目前Anconda python 环境管理软件,已非常臃肿。为了替代该软件,可以使用miniforge软件来代替。 1. 安装windows miniforge软件 (1) 下载网站:https://github.com/conda-forge/miniforge?tabreadme-ov-file 从网址下载ÿ…...
C语言基础18
内容提要 构造类型 结构体 共用体/联合体 枚举 typedef 构造类型 数据类型 基本类型/基础类型 整型 短整型:short [int] -- 2字节 基本整型:int -- 4字节 长整型:long [int] -- 32位4字节/64位8字节 长长整型:long long…...
Docker部署Jenkins服务
文章目录 1.下载Jenkins服务2.部署Java21(可选)2.1 安装Java21 3.Maven3.9.9安装4.启动Jenkins5.初始化Jenkins5.1 入门5.2 安装推荐的插件5.3 创建第一个管理员用户5.4 实例配置5.5 Jenkins已就绪5.6 开始使用Jenkins5.7 重启Jenkins 6.配置Jenkins6.1 …...
【题解-Acwing】798. 差分矩阵
题目:798. 差分矩阵 题目描述 输入一个n行m列的整数矩阵,再输入q个操作,每个操作包含五个整数 x1,y1,x2,y2,c,其中 (x1,y1)和 (x2,y2)表示一个子矩阵的左上角坐标和右下角坐标。 每个操作都要将选中的子矩阵中的每个元素的值加…...
linux环境下的硬盘分区格式化工具介绍 fdisk,gdisk,parted,cfdisk,cgdisk,sfdisk,gparted 笔记250407
linux环境下的硬盘分区格式化工具介绍 fdisk,gdisk,parted,cfdisk,cgdisk,sfdisk,gparted 笔记250407 以下是 Linux 系统中常用的 硬盘分区与格式化工具,涵盖命令行和图形界面工具,按功能分类整理: 一、分区管理工具 1. 命令行工具 工具功能…...
Ubuntu 24.04 LTS系统安装RTX 4090显卡驱动和cuda并部署ollama下载DeepSeek模型【自用详细版】
自己捣鼓玩玩哈,正好有机子 1. 安装驱动前的系统配置工作 卸载原有驱动并禁用nouveau sudo apt remove --purge nvidia*sudo cp /etc/modprobe.d/blacklist.conf /etc/modprobe.d/blacklist.conf.backup //备份文件sudo vim /etc/modprobe.d/blacklist.conf //修…...
FogFL: Fog-Assisted Federated Learning for Resource-Constrained IoT Devices
摘要 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 -在本文中,我们提出了一个支持雾的联邦学习框架–FogFL–来促进资源受限的物联网环境中延迟敏感应用的分布式学习。联邦学习(FL)是一种流行的分…...
音视频入门基础:RTCP专题(2)——RTCP协议简介(上)
一、引言 本文对RTCP协议进行简介。在简介之前,请各位先下载RTCP的官方文档《RFC 3550》。《RFC 3550》总共有89页。本文下面所说的“页数”是指在pdf阅读器中显示的页数: 二、RTCP协议简介 本段内容对应《RFC 3550》的第6节。根据《RFC 3550》第17页&…...
oklink js逆向(入口定位)
分析api请求,定位参数 X-Apikey 搜索关键字apikey,发现结果太多 结合搜索结果,搜索关键字 apikey(,只找到5个 断点后定位 可见使用了字符串混淆,所以搜索不到 x-apikey 还可以通过搜索 headers,追踪调用栈的…...
go原子操作和锁的区别是什么?
在Go语言中,原子操作和锁都是用于实现并发编程的同步机制,但它们的工作方式和适用场景有所不同。下面是它们的主要区别: 1. 原子操作(Atomic Operations) 定义:原子操作是一种不可分割的操作,…...
QtConcurrent
以下是 QtConcurrent 的一些常见用法示例: QtConcurrent::run QtConcurrent::run 是最常用的函数,用于在单独的线程中运行一个函数。 运行普通函数 #include <QtConcurrent> #include <QDebug> #include <QThread>void myFunction…...
Git 仓库在内网与 Gitee 间迁移及同步记录
Git 仓库在内网与 Gitee 间迁移及同步记录 在软件开发过程中,常常会遇到需要将代码仓库进行迁移或同步的情况。近期我就碰到了要把 Gitee 代码仓库移植到内网代码仓库,并且后续还得进行同步的需求。这里把整个过程记录下来,方便以后自己参考…...
如何保证mysql和redis的数据一致性
保证 MySQL 和 Redis 的数据一致性是分布式系统中常见的挑战,因为 Redis 作为缓存层,可能存在与底层数据库数据不一致的情况。以下是几种常用的方案及其优缺点对比: 1. 缓存更新策略 (1) Cache-Aside Pattern(旁路缓存模式&#…...
Java学习——day23(反射的对象创建与方法调用)
文章目录 1. 使用反射实例化对象1.1 利用无参构造函数创建对象1.2利用带参构造函数创建对象 2.通过反射调用对象方法2.1 调用公共方法2.2 调用私有方法(需设置访问权限)3. 访问和修改对象的属性3.1 公共属性3.2 私有属性 4. 实践任务4.1工厂类 SimpleFac…...
遇到无法连接香港服务器可能是什么原因导致的呢
遇到无法连接香港服务器的情况时,别急着重启或联系客服,先搞清楚到底是哪里断了链条。问题可能出在服务器本身,也可能是你的本地网络、路由路径、DNS、甚至运营商的“干预”。以下是常见的几个可能原因,建议你可以逐一排查&#x…...
Python----计算机视觉处理(Opencv:道路检测完整版:透视变换,提取车道线,车道线拟合,车道线显示,)
Python----计算机视觉处理(Opencv:道路检测之道路透视变换) Python----计算机视觉处理(Opencv:道路检测之提取车道线) Python----计算机视觉处理(Opencv:道路检测之车道线拟合) Python----计算机视觉处理࿰…...
javaweb自用笔记:Maven分模块设计与开发、Maven继承与聚合、Maven私服
Maven分模块设计与开发 Maven继承与聚合 继承 版本锁定 dependencies引入依赖,dependencyManagement不代表依赖被引入,如果要使用dependencyManagement下的依赖,还需要在dependencies里面定义 聚合 如果没有用聚合,将这个项目打…...
在PyCharm中出现 **全角字符与非英文符号混合输入** 的问题
在PyCharm中出现 全角字符与非英文符号混合输入 的问题(如 124345dfs$¥cvd)࿰…...
数字身份DID协议:如何用Solidity编写去中心化身份合约
本文提出基于以太坊的自主主权身份(SSI)实现方案,通过扩展ERC-734/ERC-735标准构建链上身份核心合约,支持可验证声明、多密钥轮换、属性隐私保护等特性。设计的三层架构体系将身份控制逻辑与数据存储分离,在测试网环境…...
Linux的RPM包管理详解
Linux的RPM包管理详解 引言 RPM(Red Hat Package Manager)是Linux系统中一种重要的软件包管理工具,它以“.rpm”为扩展名,广泛应用于基于Red Hat的Linux发行版,如CentOS、Fedora、openSUSE等。RPM包不仅简化了软件包…...
其它理论原则
ABC理论 假设(Assumption)影响行为(Behavior),行为最终影响结果(Consequence)。 如果产品经理认为同事是一个不讲道理的人,那么产品经理在和他交流时就会产生抵触的行为,…...
C++中的类和对象(上)
1 类的定义 1.1 类定义的格式 1 class为定义类的关键字,Stack为类的名字,{}中为类的主体,注意类定义结束时后面分号不能省 略》。类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数…...
LLaMA-Factory 数据集成从入门到精通
一、框架概述 LLaMA-Factory 框架通过Alpaca/Sharegpt双格式体系实现多任务适配,其中Alpaca专注结构化指令微调(含SFT/DPO/预训练),Sharegpt支持多角色对话及多模态数据集成。核心配置依托 dataset_info.json 实现数据源映射、格…...
高级:JVM面试题深度剖析
一、引言 在Java技术面试中,JVM(Java虚拟机)相关知识是考察重点之一。深入理解JVM的内存模型、垃圾回收机制、类加载机制等,不仅能帮助开发者优化Java应用性能,还能在面试中展现深厚的技术功底。本文将针对这些高频知…...
Spring MVC 中 @ResponseBody 注解深度使用教程
一、注解核心作用 ResponseBody 是 Spring MVC 中处理 响应体内容 的核心注解,主要功能: 跳过视图解析器:直接返回数据而非视图名称自动数据转换:根据返回值类型自动转换响应格式(JSON/XML/纯文本)RESTfu…...
数据结构第一轮复习--第七章查找(包含课程代码)
基于数组实现顺序查找代码 //顺序查找的实现 typedef struct{ //查找表的数据结构(顺序表) ElemType *elem; //指向开辟的动态数组基址 (起始地址) int TableLen; //表的长度 }SSTable; //顺序查找 int Search_Seq(SSTable ST…...
Springboot JPA 集成ShardingSphere
Spring Boot集成JPA与ShardingSphere可通过以下步骤实现分库分表功能,需重点关注依赖配置、分片规则定义及JPA适配问题: 一、依赖配置 1. 引入核心依赖 在pom.xml中添加ShardingSphere和JPA相关依赖: <!-- ShardingSphere JDBC --&…...
详细介绍javaspringboot操控redis的高级特性1. 事务支持2. 发布/订阅3. Pipeline批量操作
Spring Boot 对 Redis 的操作提供了丰富的高级特性,以下是对事务支持、发布 / 订阅、Pipeline 批量操作的详细介绍: 事务支持 原理:Redis 事务是一个单独的隔离操作,它可以包含多个命令,这些命令要么全部执行&#x…...
第一次3D打印,一个简单的小方块(Rhino)
一、建模 打开犀牛,我们选择立方体 我们点击上册的中心点 输入0,然后回车0 而后我们输长度:10,回车确认 同样的,宽度10 高度同样是10 回车确认后,我们得到一个正方形 二、导出模型 我们选择文件—>保存…...
数据分享:汽车测评数据
说明:如需数据可以直接到文章最后关注获取。 1.数据背景 Car Evaluation汽车测评数据集是一个经典的机器学习数据集,最初由 Marko Bohanec 和 Blaz Zupan 创建,并在 1997 年发表于论文 "Classifier learning from examples: Common …...