拆解大语言模型RLHF中的PPO

news2024/12/15 18:29:47

**

拆解大语言模型RLHF中的PPO

**
在这里插入图片描述
参考链接:https://zhuanlan.zhihu.com/p/645225982
为什么大多数介绍RLHF的文章,一讲到PPO算法的细节就戛然而止了呢?要么直接略过,要么就只扔出一个PPO的链接。然而LLM PPO跟传统的PPO还是有些不同的呀。

其实在ChatGPT推出后的相当一段时间内,我一直在等一篇能给我讲得明明白白的文章,但是一直未能如愿。我想大概是能写的人都没时间写吧。

前几个月,自己在工作中遇到要用到PPO的场景了。我心想,干脆自己啃算了。
于是我找到了InstructGPT引用的OpenAI自家的大语言模型RLHF论文《fine-tuning language models from human preferences》和《learning to summarize from human feedback》的源码,逐行阅读。然后用近似但不完全相同的风格复现了一遍。后来又和同事一起把自己的实现和微软的DeepSpeed-Chat的实现相互印证,才算是理解了。

既然已经有了一些经验,为何不将它分享出来呢?就当是抛砖引玉吧。万一写的不对,也欢迎大家一起交流讨论。

由于本文以大语言模型RLHF的PPO算法为主,所以希望你在阅读前先弄明白大语言模型RLHF的前两步,即SFT Model和Reward Model的训练过程。另外因为本文不是纯讲强化学习的文章,所以我在叙述的时候不会假设你已经非常了解强化学习了。只是如果完全没有了解过,你可能会觉得有些操作看上去没有那么显然。但只要你非常了解语言模型和深度学习,应该不会影响你把整个流程给捋顺。
接下来,我会把大语言模型RLHF中的PPO分成三部分逐一介绍。这三部分分别是采样、反馈和学习。

在开始之前,我先用一段伪代码把三部分的关系简要说明一下(先建立一个印象,看不懂也没关系,后面自然会看懂):

policy_model = load_model()

for k in range(20000):
    # 采样(生成答案)
    prompts = sample_prompt()
    data = respond(policy_model, prompts)
    
    # 反馈(计算奖励)
    rewards = reward_func(reward_model, data)
    
    # 学习(更新参数)
    for epoch in range(4):
        policy_model = train(policy_model, prompts, data, rewards)

对于其中的每部分我都会用计算图 来辅助描述,然后还会根据我的描述更新这段伪代码。
好了,让我们开始这趟旅程吧~

大语言模型的RLHF,实际上是模型先试错再学习的过程。
我们扮演着老师的角色,给出有趣的问题,而模型则会像小学生一样,不断尝试给出答案。模型会对着黑板写下它的答案,有时候是正确的,有时候会有错误。我们会仔细检查每一个答案,如果它表现得好,就会给予它高声赞扬;如果它表现不佳,我们则会给予它耐心的指导和反馈,帮助它不断改进,直到达到令人满意的水平。

采样
采样就是学生回答问题的过程,是模型根据提示(prompt)输出回答(response)的过程,或者说是模型自行生产训练数据的过程。
例如:

promptresponse
请告诉我三种常见的动物。猫,狗,鹦鹉。
詹姆斯和库里谁更伟大?他们都很伟大,我无法比较。

PPO在这一部分做了什么呢?
先明确一个概念——策略(policy),它就是RLHF中的“学生”。policy由两个模型组成,一个叫做演员模型(Actor),另一个叫做评论家模型(Critic)。它们就像是学生大脑中的两种意识,一个负责决策,一个负责总结得失。
其中演员就是我们想要训练出来的大模型。在用PPO训练它之前,它就是RLHF的第一步训练出来的SFT(Supervised Fine-Tuning)model。输入一段上下文,它将输出下一个token的概率分布 p(⋅|context) 。评论家是强化学习的辅助模型,输入一段上下文,它将输出下一个token的“收益”。
什么是“收益”呢?简单来说就是从下一个token开始,模型能够获得的总奖励(浮点数标量 )。这里说的奖励包括Reward Model给出的奖励。奖励是怎么给的,以及收益有什么用,这些内容我们后面会详细介绍。
在这里插入图片描述

从实现上说,评论家就是将演员模型的倒数第二层连接到一个新的全连接层上。除了这个全连接层之外之外,演员和评论家的参数都是共享的(如上图)。
(更新:上面提到的模型结构是较早期的版本,后续不共享参数的实现方式也有很多)
现在我们来看看PPO的采样过程中有哪些模型和变量。如下图,矩形表示模型,椭圆表示变量。
在这里插入图片描述
图中的“old_policy”矩形就是刚刚说的policy(为啥有个“old”前缀呢?后面我会详细解释)。
采样指的是old_policy从prompt池中抽出M个prompt后,对每个prompt进行语言模型的token采样:

  • 计算response的第1个token的概率分布,然后从概率分布中采样出第1个token

  • 根据第1个token,计算response的第2个token的概率分布,然后从概率分布中采样出第2个token

  • ……

  • 根据前N-1个token,计算response的第N个token的概率分布,然后从概率分布中采样出第N个token
    在这里插入图片描述
    语言模型的token采样然后就得到了三个输出。假设对每个prompt,policy生成的token的个数为N,那么这三个输出分别是

  • response:M个字符串,每个字符串包含N个token

  • old_log_probs:演员输出的 M×N 的张量,包含了response中token的对数概率 log⁡(p(token|context))

  • old_values:评论家输出的 M×N 的张量,包含了每次生成token时评论家预估的收益

得到这三个输出后,采样阶段就就结束了。这三个输出都是后续阶段重要的输入数据。
我们先将采样部分的伪代码更新一下:

采样

prompts = sample_prompt()
responses, old_log_probs, old_values = respond(policy_model, prompts)

就像是一场考试,学生已经完成了答题环节,他们在黑板上留下了答案。但这只是整个学习过程的一个环节,接下来是关键的反馈步骤。

反馈

反馈就是老师检查答案的过程,是奖励模型(Reward Model)给response打分的过程,或者说是奖励模型给训练数据X标上Y值的过程。打出的分数衡量了response的正确性,它也可以被视为prompt和response的匹配程度。
例如:

prompt	                 response	  score
请告诉我三种常见的动物。	猫,狗,鹦鹉。	1
请告诉我三种常见的动物。	海豹,猫头鹰。	0.5
请告诉我三种常见的动物。	咖啡和芝士蛋糕。	0

Reward Model可以被比作班级里成绩最好的学生,他能够辅助老师批改作业。就像老师先教会这个学生如何批改作业,之后这个学生就能独立完成作业批改一样,Reward Model通过学习和训练,也能够独立地完成任务并给出正确的答案。

网上有很多资料介绍Reward Model的训练过程,这也不是本文的重点,我就不再赘述了。
PPO拿训练好的Reward Mode做了什么呢?我们接着看图说话:
在这里插入图片描述

奖励流程(转载须引用)从图中我们可以看出,左上角的绿色矩形reward model拿到prompt和response,然后输出了分数score。实际上发生的事情是,prompt和response被拼接成一个字符串,接着被送入到reward model中,最后reward model计算出了匹配分数。
你也许发现了,在图中,score并不是最终的奖励。它和最终的奖励rewards之间还隔着一个reward function函数。
这是因为score只能衡量结果的对错,不能衡量过程的合理性。怎么衡量过程的合理性呢?一种简单粗暴的方法是:循规蹈矩,即为合理。

当年爱因斯坦的相对论理论首次发表时,遭遇了许多质疑。后来,该理论被证明并得到了应有的认可。大家的目光可能都聚焦于爱因斯坦是如何坚定不移地坚持自己的理念并获得成功的。
然而,你有没有想过,那些反对和质疑其实也是必要的。
在相对论理论出现之前,已经有一个相对完整的物理系统。当时,一个年轻人突然出现挑战这个系统。在不知道他的路数的情况下,有必要基于现有的经验给予适当的质疑。因为并非每个人都是伟人啊。如果他的理论真的得到验证,那么就是给予肯定和荣誉的时候了。
语言模型也是一样,在我们给予最终奖励之前,最好也对它的“标新立异”给予少量的惩罚(即刚刚说的质疑)。

怎么做呢?我们给它立一个规矩,只要它按照这个规矩来,就能获得少量奖励。而这个规矩就是我们在SFT阶段已经训练好的语言模型ref_policy(图中右下角的绿色矩形),或者说是完全还没经过强化学习训练的语言模型。

过程合理性奖励的计算方式是这样的。ref_policy拿到prompt,然后给old_policy生成的response的每个token计算对数概率,得到一个二维张量 ref_log_prob。现在我们来看old_policy的演员模型为第i个response生成的第j个token,生成这个token应该获得的奖励为
在这里插入图片描述
来理解一下这个式子:

  • ref_log_prob[i, j]越高,ref_policy越认可old_policy的输出,说明old_policy更守规矩,因此该获得更高的奖励
  • old_log_prob[i, j]越高,old_policy获得的奖励反而越低。old_log_prob[i, j]作为正则项,保证了概率分布的多样性

有了这两个直觉上的解释,我们说式(1)是比较合理的。顺便说一句,熟悉信息论的人也许注意到了,式(1)是KL的简化版本。实际上式(1)完全可以改成计算两个token的概率分布的KL散度。这是另一个话题,就不延伸了。

最终,我们将过程合理性奖励和结果正确性奖励合并起来,就得到了最终奖励的计算方式。
注意,我们只在最后一个token上应用结果正确性奖励(reward_model的输出)。也就是说,第i个response的第j个token的奖励的计算方式为:
在这里插入图片描述
式(2)就是图中“reward function”的计算内容。
通俗来说,整个reward function的计算逻辑是典型的霸总逻辑:除非你能拿到好的结果,否则你就得给我守规矩。

注意,我们只对response计算奖励。另外在整个反馈阶段,reward_model和ref_policy是不更新参数的。
一旦给出reward,就完成了反馈阶段。现在我们将反馈部分的伪代码更新一下:

# 采样
prompts = sample_prompt()
responses, old_log_probs, old_values = respond(policy_model, prompts)

# policy_model的副本,不更新参数
ref_policy_model = policy_model.copy()

# 反馈
scores = reward_model(prompts, responses)
ref_log_probs = analyze_responses(ref_policy_model, prompts, responses)
rewards = reward_func(scores, old_log_probs, ref_log_probs)

这就像是老师在检查学生的答案并给出评价后,学生们就可以了解他们的表现如何,并从中学习和进步。然而,获得反馈并不是结束,而是新的开始。正如学生需要用这些反馈来进行复习和改进一样,模型也需要通过学习阶段来优化其性能和预测能力。

学习
“学习“就是学生根据反馈总结得失并自我改进的过程,或者说是强化优势动作的过程。
如果说前两步分别是在收集数据X,以及给数据打上标签Y。那么这一步就是在利用数据(X, Y)训练模型。
"强化优势动作"是PPO学习阶段的焦点。在深入探讨之前,我们首先要明确一个关键概念——优势。
此处,我们将优势定义为“实际获得的收益超出预期的程度”。

为了解释这个概念,请允许我举一个例子。假设一个高中生小明,他在高一时数学考试的平均分为100分,在此之后,大家对他的数学成绩的预期就是100分了。到了高二,他的数学平均分提升到了130分。在这个学期,小明的数学成绩显然是超出大家的预期的。
表现是可用分数量化的,故表现超出预期的程度也是可以用分数差来量化的。我们可以认为,在高二阶段,小明超出预期的程度为30分(130 - 100)。根据优势的定义我们可以说,在高二阶段,小明相对于预期获得了30分的优势。
在这个例子中,实际已经给出了PPO计算优势的方法:优势 = 实际收益 - 预期收益。
对于语言模型而言,为第i个response生成第j个token的实际收益就是:从生成第j个token开始到生成第N个token为止,所能获得的所有奖励的总和。我们用return来表示实际收益,它的计算方式如下:
在这里插入图片描述
(写给熟悉RL的人:简单起见,在这里我们既不考虑贴现也不计算广义优势估计GAE)

预期收益又该如何计算呢?记得我们在“采样”阶段提到过,policy包含演员模型和评论家模型,其中后者是用来预估收益的。其实,当时说的收益old_values就是现在我们想要计算的预期收益。评论家会为response中的每个token计算一个预期收益,第i个response的第j个token的预期收益记为values[i, j](它预估的是刚才提到的 return[i,j]=∑k=jNreward[i,k] )。
现在,我们可以这样计算为第i个response生成第j个token的优势a(这里我们使用采样阶段计算出来的old_values):
在这里插入图片描述
好的,我们已经理解了优势的含义了。现在终于可以揭开这个关键主题的面纱——在PPO学习阶段,究竟什么是"强化优势动作"。
所谓“强化优势动作”,即强化那些展现出显著优势的动作。
在上面的小明的例子中,这意味着在高三阶段,小明应该持续使用高二的学习方法,因为在高二阶段,他的学习策略展示出了显著的优势。

在语言模型中,根据上下文生成一个token就是所谓的“动作”。"强化优势动作"表示:如果在上下文(context)中生成了某个token,并且这个动作的优势很高,那么我们应该增加生成该token的概率,即增加 p(token|context) 的值。
由于policy中的演员模型建模了 p(token|context) ,所以我们可以给演员模型设计一个损失函数,通过优化损失函数来实现“强化优势动作”:
在这里插入图片描述
别被这个双重和式给吓住。它只是在用两个矩阵计算元素乘法,得到一个新矩阵,然后计算新矩阵中所有元素的均值。最后加上一个负号,仅此而已。

我们分析一下它是怎么“强化优势动作”的:

  • 当优势大于0时,概率越大,loss越小;因此优化器会通过增大概率(即强化优势动作)来减小loss
  • 当优势小于0时,概率越小,loss越小;因此优化器会通过减小概率(即弱化劣势动作)来减小loss
    这很像巴浦洛夫的狗不是吗?
    在这里插入图片描述

巴浦洛夫的狗另外还有两个点值得注意:

  • 优势的绝对值越大,loss的绝对值也就越大
  • 优势是不接收梯度回传的
    实际上,式5只是一个雏形。PPO真正使用的演员的损失函数是这样的:
    在这里插入图片描述
    (写给熟悉RL的人:简单起见,在这里我们既不考虑损失的截断,也不考虑优势的白化)
    式子6相比式5子多了一个分母 pold 。在式子6里, pold 表示p的一个较老的版本。因为它不接收梯度回传,所以我们可以将 pold(token[i, j]|context) 当作常量,或者说,把它当成p的学习率的一部分。我们来分析一下它的作用。以优势大于0的情况为例,对任意i,当 pold(token[i, j]|context) 有较大的值的时候,p的参数的学习率更小。

直观来说,当生成某个token的概率已经很大了的时候,即便这个动作的优势很大,也不要再使劲增大概率了。或者更通俗地说,就是步子不要迈得太大。

现在的问题就是,我们应该使用p的哪个老版本。还记得我们在本文开头时给出的伪代码吗(后来在介绍“采样”和“反馈”阶段时又各更新了一次),我们对着代码来解释:

policy_model = load_model()
ref_policy_model = policy_model.copy()

for k in range(20000):
    # 采样(已更新)
    prompts = sample_prompt()
    responses, old_log_probs, old_values = respond(policy_model, prompts)

    # 反馈(已更新)
    scores = reward_model(prompts, responses)
    ref_log_probs = analyze_responses(ref_policy_model, prompts, responses)
    rewards = reward_func(reward_model, scores, old_log_probs, ref_log_probs)
    
    # 学习
    for epoch in range(4):
        policy_model = train(policy_model, prompts, responses, old_log_probs, old_values, rewards)

简单来说,这段代码做的事情是:迭代2万次。在每次迭代中,通过采样和反馈得到一份数据,然后在学习阶段使用数据微调语言模型。每份数据我们都拿来训练4个epoch。
那 pold 使用2万次迭代开始之前的演员模型的参数可以吗?不行,那个版本过于老了(实际上就是SFT,我们已经在奖励阶段中的ref_policy中用过了)。不妨使用同一次迭代的还未进入学习阶段的演员模型吧。如果是这样的话,仔细一看,pold(token|context) 不就是采样阶段得到的old_log_probs吗?只是少了一个对数而已。
这就是为什么我们在采样阶段,对所有的模型和参数都使用“old”前缀,就是为了区分模型和变量的版本。
(补充:前面提到的old_policy指的是上面伪代码中采样出old_log_probs的那个时刻的policy_model)
而对于 p(token|context) 我们可以使用实时的演员模型的参数计算出来,然后用log_prob来表示它。于是,我们可以将式子6改写成以下形式:
在这里插入图片描述
至此,我们完整地描述了PPO的学习阶段中“强化优势动作”的方法。就像下面的计算图展示的那样(policy与前面的图中的old_policy不一样,是实时版本的模型)。
在这里插入图片描述

等等,似乎还没完。图中还有一个叫critic_loss的没提到过的东西。
当然了,负责决策的演员需要学习,难道总结得失的评论家就不需要学习了?评论家也是需要与时俱进的嘛,否则画评家难道不怕再次错过梵高那样的天才?
前面我们提到过,评论家会为response中的每个token计算一个预期收益,第i个response的第j个token的预期收益记为values[i, j],它预估的是 returns[i,j]=∑k=jNreward[i,k] 。
既然如此,就设计一个损失函数来衡量评论家预期收益和真实收益之间的差距。
PPO用的是均方差损失(MSE):
在这里插入图片描述
(写给熟悉RL的人:由于我们不考虑GAE,所以returns的计算也做了相应的简化)
最终优化policy时用的loss是演员和评论家的loss的加权和:
在这里插入图片描述
这才算是真正完事儿了。现在我们将整个PPO的伪代码都更新一下:

policy_model = load_model()
ref_policy_model = policy_model.copy()

for k in range(20000):
    # 采样
    prompts = sample_prompt()
    responses, old_log_probs, old_values = respond(policy_model, prompts)

    # 反馈
    scores = reward_model(prompts, responses)
    ref_log_probs, _ = analyze_responses(ref_policy_model, prompts, responses)
    rewards = reward_func(scores, old_log_probs, ref_log_probs)
    
    # 学习
    advantages = advantage_func(rewards, old_values)
    for epoch in range(4):
        log_probs, values = analyze_responses(policy_model, prompts, responses)
        actor_loss = actor_loss_func(advantages, old_log_probs, log_probs)
        critic_loss = critic_loss_func(rewards, values)
        loss = actor_loss + 0.1 * critic_loss
        train(loss, policy_model.parameters())

总结
到这里,大语言模型RLHF中PPO算法的完整细节就算介绍完了。掌握这些细节之后,我们可以做的有趣的事情就变多了。例如:

  • 你可以照着伪代码从头到尾自己实现一遍,以加深理解。相信我,这是非常有趣且快乐的过程
  • 你可以以此为契机,把强化学习知识系统性地学一遍。你会发现很多强化学习的概念一下变得具象化了
  • 你可以在你的产品或者研究方向中思考PPO是否可以落地
  • 你也许会发现PPO算法的不合理之处,那么就深入研究下去,直到做出自己的改进
  • 你可以跟周围不熟悉PPO的小伙伴吹牛,顺便嘲讽对方(大误)
    总之,希望我们都因为掌握了知识变得更加充实和快乐~

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

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

相关文章

arcGIS使用笔记(无人机tif合并、导出、去除黑边、重采样)

无人机航拍建图之后,通过大疆智图软件可以对所飞行的区域的进行拼图,但是如果需要对拼好的图再次合并,则需要利用到arcGIS软件。下面介绍arcGIS软件在这个过程中常用的操作。 1.导入tif文件并显示的方法:点击“”图标进行导入操作…

利用代理IP爬取Zillow房产数据用于数据分析

引言 最近数据分析的热度在编程社区不断攀升,有很多小伙伴都开始学习或从事数据采集相关的工作。然而,网站数据已经成为网站的核心资产,许多网站都会设置一系列很复杂的防范措施,阻止外部人员随意采集其数据。为了解决这个问题&a…

免费送源码:Java+B/S+MySQL 多元化智能选课系统的设计与实现 计算机毕业设计原创定制

摘 要 多元化智能选课系统使用Java语言的Springboot框架,采用MVVM模式进行开发,数据方面主要采用的是微软的Mysql关系型数据库来作为数据存储媒介,配合前台技术完成系统的开发。 论文主要论述了如何使用JAVA语言开发一个多元化智能选课系统&…

(九)机器学习 - 多项式回归

多项式回归(Polynomial Regression)是一种回归分析方法,它将自变量 xx 和因变量 yy 之间的关系建模为 nn 次多项式。多项式回归的目的是找到一个 nn 次多项式函数,使得这个函数能够最好地拟合给定的数据点。 多项式回归的数学表达…

XX服务器上的npm不知道咋突然坏了

收到同事的V,说是:182上的npm不知道咋突然坏了,查到这里了,不敢动了。 咱一定要抓重点:突然坏了。这里的突然肯定不是瞬间(大概率是上次可用,这次不可用,中间间隔了多长时间&#x…

Vizcom:AI驱动的草图到3D设计革命

Vizcom是一家领先的AI技术公司,专注于为工业设计师提供工具,将手绘草图快速转化为可制造的3D模型,从而加速产品迭代和创新。 公司背景与愿景 成立于2021年的Vizcom由前Nvidia工业设计师Jordan Taylor创立。Taylor凭借其深厚的创意设计背景和技术敏锐度,看到了生成对抗网络…

html自带的input年月日(date) /时间(datetime-local)/星期(week)/月份(month)/时间(time)控件

年月日期控件 type"date" <input type"date" id"StartDate" valueDateTime.Now.ToString("yyyy-MM-dd") /> //设置值 $("#StartDate").val("2024-12-12"); //获取值 var StartDate$("#StartDate&quo…

【51单片机】独立按键快速上手

51单片机独立按键是单片机控制系统中常用的一种输入方式&#xff0c;它相当于一种电子开关&#xff0c;按下时开关接通&#xff0c;松开时开关断开。 开关功能‌&#xff1a;独立按键内部通常包含一个有弹性的金属片&#xff0c;当按键被按下时&#xff0c;金属片与触点接触&a…

SpringCloud和Nacos的基础知识和使用

1.什么是SpringCloud ​ 什么是微服务&#xff1f; ​ 假如我们需要搭建一个网上购物系统&#xff0c;那么我们需要哪些功能呢&#xff1f;商品中心、订单中心和客户中心等。 ​ 当业务功能较少时&#xff0c;我们可以把这些功能塞到一个SpringBoot项目中来进行管理。但是随…

手机实时提取SIM卡打电话的信令声音--社会价值(一、方案解决了什么问题)

手机实时提取SIM卡打电话的信令声音 --社会价值(一、方案解决了什么问题) 一、前言 这段时间&#xff0c;我们在技术范围之外陷入了一个自证或者说下定义的怪圈&#xff0c;即要怎么样去介绍或者描述&#xff1a;我们是一个什么样的产品。它在当前这个世界上&#xff0c;处于…

使用navicat新旧版本,连接PostgreSQL高版本报错问题图文解决办法

使用navicat新旧版本&#xff0c;连接PostgreSQL高版本报错问题图文解决办法 一、问题现象&#xff1a;二、出现原因三、解决方法&#xff1a;1、升级Navicat版本&#xff1a;2、使用低版本的postgreSQL&#xff1a;3、修改Navicat的dll二进制文件&#xff1a;navicat版本15nav…

12.1【JAVA EXP4】next项目

next项目构建问题 详解一下这个页面 什么是Node选项&#xff1f; Node选项是指在运行Node.js应用程序时可以传递给Node.js进程的一系列命令行参数。这些选项可以让开发者控制Node.js的行为&#xff0c;例如设置内存限制、启用或禁用某些功能、指定调试端口等 --inspect 和 --i…

【操作系统】实验九:设备驱动程序

实验9 设备驱动程序 在钻研Linux内核的人当中&#xff0c;大多数人都是在写设备驱动程序。尽管由于设备的特殊性&#xff0c;使得每个驱动程序都不一样。但是编写设备驱动程序的许多原则和基本技巧都是一样的&#xff0c;甚至Windows下的设备驱动程序从原理上讲也与之相通。在…

腾讯云COS跨域访问CORS配置

腾讯云COS跨域访问CORS配置方法如下&#xff0c;参考以下截图&#xff1a; 参考文章&#xff1a; 跨域及CORS-Nginx配置CORS

从EXCEL表格到WEB TABLE的实践

前言 EXCEL管理数据 Bootstrap Bootstrap 是一个流行的开源前端框架&#xff0c;它由 Twitter 的员工开发&#xff0c;用于快速开发响应式和移动设备优先的网页和应用程序。 jQuery jQuery 是一个快速、小巧且功能丰富的 JavaScript 库。它简化了 HTML 文档的遍历、事件处理…

python中向量指的是什么意思

一、向量是什么 在数学中&#xff0c;向量&#xff08;也称为欧几里得向量、几何向量、矢量&#xff09;&#xff0c;指具有大小&#xff08;magnitude&#xff09;和方向的量。它可以形象化地表示为带箭头的线段。箭头所指&#xff1a;代表向量的方向&#xff1b;线段长度&am…

高数 导数

文章目录 一&#xff0c;导数的知识点 二&#xff0c;单侧导数 三&#xff0c;可导和连续的关系 四&#xff0c;复合函数求导 五&#xff0c;参数方程求导 六&#xff0c;高阶导数求导 七&#xff0c;隐函数求导 八&#xff0c;微分基础 一&#xff0c;导数常用的知识点 …

基于Spring Boot的同城宠物照看系统的设计与实现

一、摘要 在快节奏的现代生活中&#xff0c;宠物已成为许多家庭不可或缺的一部分。然而&#xff0c;宠物照看服务的需求也随之增长。为了满足这一需求&#xff0c;我们设计并实现了一款同城宠物照看系统&#xff0c;该系统利用Java技术和MySQL数据库&#xff0c;为用户提供一个…

光伏逆变器负载的维护和保养方法有哪些?

光伏逆变器是光伏发电系统中的关键设备&#xff0c;它将太阳能电池板产生的直流电转换为交流电&#xff0c;为家庭和工业用电提供稳定的电力。为了保证光伏逆变器的正常运行和延长其使用寿命&#xff0c;我们需要对其进行定期的维护和保养。以下是一些建议&#xff1a; 清洁&a…

离开花少6后的周雨彤,还会不会好了

花儿与少年&#xff0c;这档著名的旅行综艺&#xff0c;从丝路季的9.3分&#xff0c;一路狂跌至第六季的3.9分&#xff0c;有人说是因为节目里太过抓马&#xff0c;导致这季分数太低&#xff0c;然而以最强抓马著称的花少2都有7.1分的高分。 花少6难看是真的&#xff0c;导演组…