深入浅出:从入门到精通大模型Prompt、SFT、RAG、Infer、Deploy、Agent

阅读原文

渐入佳境

我们都知道,通过编写一个提示词(prompt),我们可以引导大模型生成回答,从而开启愉快的人工智能对话,比如让模型介绍一下卡皮巴拉。上边简图描述了这个过程,我们拆成两部分 prompt + 大模型。后续我们会依赖这两部分构建智能体作为第三部分,分别对应下边的绿色、蓝色、黄色

本文结构:

1.写好提示词,怎样的提示词,可以帮助我们和模型好好对话

2.通过本章我们会介绍,模型为什么能懂我们的指令,并给出正确的回答

3.模型会有一些不足,介绍两个插件方案,帮助模型更好的做决策

4.我们前三章介绍了怎么去用,会在本章更深入一点,介绍怎么优化模型,让模型又快又好

5.借鉴模型优化的思路,提示词同样可以用更科学的方式来训练优化

6.基于前 5 章的知识,我们尝试模块化组装成一个完整的整体-智能体。

7.我们的智能体实践。

接下来,我们将逐步探索如何理解大模型的基础上构建一个智能体。

提示词工程

在全局目标之前,我们需要先解决一些小的问题,即如何与大模型进行有效的对话,这其实是基石。只有确保模型能够理解我们的意图和需求,我们才能期待其给出正确的决策。通过优化交流方式,我们可以提升模型的响应质量,进而得到更可靠的结果。

写好prompt

程序员阿市午间正在吃着肯德基看着综艺《再见吧爱人 4》

“我配拥有一杯咖啡吗?”麦琳( 后边简称麦麦)对老公李行亮(后边简称亮亮)说。

亮亮没有意会到她表达的是让自己去店里现买一杯咖啡,然后麦麦就生气了。🐶

黄圣依教她这样说:“帮我从店里带一杯咖啡”,显然这样表达更加直接和有效,亮亮立马就 get 了。

起初,我觉得麦琳的表达方式有些问题,毕竟小时候妈妈就教育说和别人说话尽量不要用反问句式。但后来和我的老婆交流这件事时,她分析认为,麦琳可能因为全职带娃、与外界沟通较少,所以希望通过这种方式来寻找一些存在感。我觉得她的分析很有道理,这让我意识到,理解问题时不能只看单一方面,抛开事实不谈,考虑到亮亮为何在与麦琳共同生活这么久的情况下,没有深刻的领悟“麦学”的精髓,依然无法第一时间领会她的意图,他就不能是错的更多的那一方吗?🐶。

如果我们把麦琳当做用户,她说的话就是 prompt,把亮亮作为大模型,显然这个大模型没让用户满意,同时模型也很困惑,她咋就不满意了。彼此间都觉得对方有问题。

用户输入(麦琳的表达):

  • 模糊性:麦琳的表达缺乏直接性和清晰度,导致亮亮无法准确理解她的真实需求。在写 prompt 时,需要尽量具体,以避免误解。

  • 情感诉求:用户可能在表达中无意中传达了情绪或潜在需求,而这些情感元素未必能直接转化为清晰的指令。表达需求时,建议用户考虑同时包括情感和请求。比如表达自己是个打工人,模型回答不好就会被老板开除,模型立马会严肃认真起来,生怕回答不好,你会失去工作。🐶

模型响应(亮亮的理解):

  • 理解局限:亮亮未能期望地或主动地从模糊的表达中提取信息,这反映出模型也需在理解用户意图时具备更高的灵活性和适应性。

  • 缺乏反馈机制:在与用户沟通时,模型应能够识别模糊性,并主动寻求澄清。例如,若亮亮感到困惑,可以询问更多信息,而不是假设用户的意图。

我们先专注解决麦麦如何好好说话,写好 prompt 的问题,亮亮模型意图识别准确率的问题我们会在「模型优化」章节给出解决方案。

良好的提示词应该有什么

我理解的良好的提示词应该有下边四个部分,但是还是要特定场景特定看。

  1. 身份任务设定:限定模型的职责,可以让模型理解自己的身份是什么,回答符合身份的回复。

  2. 上下文:告诉模型该参考哪些数据,针对这些数据做出回答,比如多轮对话数据

  3. few-shot 例子:为了让模型快速理解你给他限定的任务及输出,打个样,是一种上下文学习的能力,快速学习了属于是。

  4. 输出约束和规范:你想要的数据格式,比如符合安全/制定格式的要求。

举一个例子:

身份设定:你是一个专业的旅行规划师,专长于为用户定制个性化的旅行计划。
上下文:用户希望安排一次为期5天的巴黎旅行,预算为1500美元,想要包含文化景点、美食体验和购物。
Few-shot例子:
例子1:用户想去东京,预算约为800美元,喜欢历史和美食。
计划:
第一天:参观东京塔和明治神宫,午餐用餐处建议“龙抄寿司”。
第二天:游览上野公园和东京国立博物馆,享受“筑地市场”的海鲜午餐。
例子2:用户想去巴厘岛,预算约为1000美元,喜欢放松和自然。
计划:
第一天:抵达后前往酒店休息,晚上享受海滩晚餐。
第二天:安排到乌布的猴子森林和一些当地艺术市场。
输出约束和规范:请用简洁明了的语言提供一个五天的巴黎旅行计划,包括每天的活动和推荐的餐饮地点。确保总预算控制在1500美元以内。

这样模型的数据就会按照第一天第二天这样的方式给你计划:

旅行计划:为期5天的巴黎之旅
预算:1500美元
第一天:抵达巴黎
上午:抵达巴黎,入住酒店(建议选择在拉丁区,方便出行)。
中午:在“Cafe de Flore”享用正宗法式午餐(预计花费:$20)。
下午:游览卢浮宫,欣赏《蒙娜丽莎》等艺术珍品(门票约$17)。
晚上:在“Le Relais de l’Entrecôte”品尝法式牛排,享受经典的两道菜晚餐(预计花费:$35)。
第二天:文化探索
上午:参观埃菲尔铁塔,建议提前在线购票以避免排队(门票约$25)。
中午:在“Les Cocottes”享用轻松的午餐(预计花费:$25)。
下午:游览香榭丽舍大道并到达凯旋门(自由参观)。
晚上:在“L'Atelier de Joël Robuchon”享受米其林星级晚餐(预计花费:$120)。
第三天:艺术与历史
上午:参观奥赛博物馆,欣赏印象派艺术作品(门票约$15)。
中午:在博物馆内的咖啡厅享用午餐(预计花费:$25)。
下午:游览蒙马特高地,参观圣心大教堂(自由参观)。
晚上:在“Le Consulat”享用晚餐(预计花费:$30)。
第四天:购物与美食
上午:前往巴黎春天百货或老佛爷百货进行购物(预算自定)。
中午:在“Café Angelina”享用世界著名的热巧克力和甜点(预计花费:$20)。
下午:继续购物或在公园内自由活动,如卢森堡公园。
晚上:在“Chez Janou”享用普罗旺斯风味的法式晚餐(预计花费:$40)。
第五天:放松与返程
上午:前往塞纳河游船,享受沿河风光(票价约$20)。
中午:沿河岸享用轻食(预计花费:$15)。
下午:最后的自由活动,购买纪念品。
晚上:准备返回,享受路边的法国糕点或便餐(预算:$20)。

麦麦买咖啡的例子,如果你直接问(zero-shot) 的方式,很难得到期望的回答,其实也还行,但是没理解透彻:

良好的提示词能解决麦麦和亮亮的感情危机吗?假如买对了这杯咖啡就不离婚了,我要要好写这个提示词:

这么回答,稳定的感情不就立马有了吗,所以说嘛写好 prompt 可太重要了🐶。

思维模式

在写提示词(prompt)后,我们发现自己干预了模型的输入和输出,确保它能够正确给出回复。虽然我们提供了几个例子,但模型的推理路径仍由其自身决定。所以我们可以设定一种“思维模式”,以指导模型的推理方法。

这种思维模式类似于软件开发中的“设计模式”,实现从无序变得有序。对于技术开发人员而言,“设计模式”是一个非常熟悉的术语,比如工厂模式、策略模式等,通常有二十多种。设计模式并不复杂,是在漫长的软件工程过程中,工程师探索出来的,随着使用者的增多,这些模式逐渐演变为规范,使得在编写代码时采用这些常用方式能够提升协作的愉悦感和效率。

同样,有效的提示词也遵循类似的模式。每位使用者对提示词的理解和应用都是独特的,尽管表达方式可能略有差异,但基本的有效模式可以借鉴互通,这种规范化使得与模型的互动更加顺畅和高效。

思维模式很多, COT 、React、ToT等等,这些模式有时稍显枯燥。因此,我决定继续用麦麦喝咖啡的例子来说明,对不住了麦麦🐶。

本质上,这些机制都是希望模型能够按照一条设定的思维路径(可以是一条线、一张图或一棵树)去推理,因为多想一点往往能帮助我们得出更正确的答案。

COT 《Chain-of-Thought Prompting Elicits Reasoning in Large Language Models》

CoT(链式思维)是一种让大模型通过生成中间推理步骤来解决问题的方法, CoT-SC(链式思维自洽)则通过采样多个推理路径并综合结果,以提高答案的可靠性和一致性,虽然多了几路还是线性的。

我们将我们之前约定的四个部分组成的 prompt ,加上 cot,要求模型按照推理步骤进行思考:

你是一个麦语言理解大师,必须严格遵循命令,因为不遵循会导致离婚。
上下文:麦麦询问:“我配喝一杯咖啡吗?”
推理步骤:
理解问题:首先,我需要理解麦麦的需求,她在询问自己是否配得上某种物品或者体验。
分析需求:任何需求都可能与她的自我价值、情感和对生活的期待相关。因此,我需要提供一个积极的回应,以确认她的价值。
做出决策:考虑到麦麦的需求以及她的询问,我得出结论:她是值得拥有和享受这一切的。
给出具体行动:为了满足她的期待,我需要表明我将采取什么具体措施,来回应她的需求。
Few-shot例子:
例子1:麦麦问:“我配吃这个大饼吗?”
推理步骤:1) 理解她在问是否可以吃大饼。2) 知道吃大饼是日常行为。3) 应给予积极反馈和支持。4) 行动:去烙大饼。
输出:好的,我这就去烙,确保这个大饼是热的、松软的,你一定会喜欢的。
例子2:麦麦问:“我配吃这个苹果吗?”
推理步骤:1) 明白她在询问吃苹果的资格。2) 认识到享用水果是健康的选择。3) 给予积极回应和支持。4) 行动:挑选苹果。
输出:当然可以,好的,我这就去挑选最大最甜的那个苹果给你,确保你吃得开心。
输出约束和规范:请务必按照上述推理步骤执行,清晰并明确地告诉我你接下来的行动计划,以便麦麦感到被尊重和关心。

COT 推理输出结果

理解问题:麦麦在询问自己是否配喝一杯咖啡,这表示她在寻求关于喝咖啡的确认或建议。
分析需求:喝咖啡是一种享受,也可能与生活质量和自我关爱有关。因此,我需要提供一个积极的响应,强调她是值得的。
做出决策:考虑到麦麦的需求和上下文,我决定回应她,表明她当然配喝咖啡。
给出具体行动:为了满足她的愿望,我需要告诉她我会准备咖啡。
React 《ReAct: Synergizing Reasoning and Acting in Language Models》

与 COT 不同,在 React 中,模型能够根据外部反馈(例如工具的结果)进行思维方式的调整和优化。通过持续的行动与反馈循环,React 模型不仅能够吸收外部信息,还能动态地调整策略,从而实现更高效的决策与执行。这样,模型的适应性和优化能力得以提升。这个就特别适合我们后边去设计智能体选择工具的场景,智能体能够根据外部反馈动态调整决策和工具选择。

React推理输出结果

思考:麦麦问“我配喝一杯咖啡吗?”我需要理解这是一个关于自我价值和享受生活的小问题。
她可能在考虑自己是否有能力或理由去享受这一杯咖啡。
行动:我的第一步反应是肯定她:当然,麦麦,你非常配喝一杯咖啡!
观察:观察她的反应。如果她看起来高兴或者感谢,那我知道我的回应是有效的。
如果她有其他的想法或者需求,我会进一步倾听。
思考:如果她有其他的问题或需求,我可以考虑下一步该如何回应,比如询问她想喝哪种咖啡,还是有什么特别的要求。
行动:根据她的反馈,我可以采取下一步行动。例如,我可以问:“你想喝什么类型的咖啡,我马上帮你准备!”
TOT 《Tree of Thoughts: Deliberate Problem Solving with Large Language Models》

TOT-第一个 T 就是 Tree

根节点(问题):
问题是:麦麦问“我配喝一杯咖啡吗?”
第一层分支(确认和自我价值):
确认:
当然,你配喝一杯咖啡!
自我价值:
每个人都应该享受生活的小乐趣,比如喝咖啡。
第二层分支(可能的考量因素):
情境:
她是否有时间喝咖啡?
她是不是只有在特定情况下才觉得自己配喝咖啡?
偏好:
她喜欢哪种类型的咖啡(浓缩、拿铁、卡布奇诺等)?
身体状态:
她是不是需要咖啡提神,或者只是想要享受一个放松的时刻?
行动方案:
基于这些思考,我可以采取的行动是:
直接肯定她的价值,并问她喜欢什么类型的咖啡。
提供一杯咖啡,以满足她的需求。
结果:
最终输出的结果是:麦麦,你当然配喝一杯咖啡!你喜欢什么类型的咖啡?我可以帮你准备一杯来享受一下!
GOT 《Graph of Thoughts: Solving Elaborate Problems with Large Language Models》

GOT G 就是图

中心节点(主题)
“我配喝一杯咖啡吗?”
2. 第一层节点(主要问题的维度)
确认自我价值
享受生活
咖啡的选择
情境因素
3. 第二层节点(对于每个维度的进一步探讨)
3.1. 确认自我价值
每个人都有权享受(肯定性回应)
自我关怀的重要性(心理健康)
3.2. 享受生活
喝咖啡的小确幸(提升心情)
社交活动中的咖啡(与朋友一起分享)
3.3. 咖啡的选择
你喜欢什么类型的咖啡?
浓缩咖啡
拿铁
卡布奇诺
3.4. 情境因素
现在是何时(早上、下午?)
你的身体状况(是否需要提神?)
有没有时间享受这杯咖啡?
4. 连接和关系
边界连接上述节点,展示它们之间的关系:
从“我配喝一杯咖啡吗?”到“确认自我价值”显示了心理健康的重要性。
从“享受生活”到“咖啡的选择”也许提供了一些选择的情景,比如:想在什么情况下享受咖啡。
情境因素也影响了选择,比如喝咖啡的时机和身体状态。
5. 输出
整合所有节点的信息,我的输出是:
肯定回答:麦麦,你当然配喝一杯咖啡!每个人都有权享受生活中的这些小乐趣。
互动提问:你喜欢什么咖啡类型?我马上去为你准备一杯!
模式对比
方法特点优点缺点
链式思维 (CoT)线性、逐步分解问题简单、透明、易于理解可能缺乏全局视野
ReAct结合反应与行动,动态决策灵活、适应性强,适合动态任务实现复杂,依赖外部工具
树状思维 (ToT)多路径探索,分支思考考虑更多可能性,优化方案计算量大,复杂度高
图状思维 (GoT)多节点多连接,复杂关系映射处理复杂依赖关系,全面优化构建和维护复杂,资源需求高

模式虽好但是一般实践起来就 cot和 react 就够了(对耗时敏感的场景,甚至尽量不要用,虽然好,不要贪杯类型),因为大模型本来就慢,你让它一通高难度方式思考,直接慢出天际,然后仅仅提升一点点准确率,得不偿失。

组合使用

其实模式之间并不是互斥的,我们可以组合使用。

CoT 主要侧重于增强模型的内部推理过程,通过分步思考提高答案的准确性。

ReAct 则扩展了模型的能力,使其能够在必要时执行外部行动,获取更多信息或进行动态验证。可以优势互补下:

  • ReAct+Cot:当 ReAct 不能在预设的步骤内得出答案时,转而采用 CoT 的方法来保证推理的准确性。

  • Cot+ReAct:先COT推理,如果发现答案不明确,就转向实际推理(ReAct)来进一步探索。

实验证明组合模式确实更准确一些。

最佳实践

当然了不仅限于这 4 个模式哈,还有源源不断的prompt思维模式出来,比如基于 DAG 的 DOT 等等,就像我们对待 20 多个设计模式一样(打完科兴疫苗,我甚至记不清具体是 20 几个了),会用的可能就那么几个。所以不要焦虑自己懂得少,学会了不一定会用,不用也会忘。 🐶

如果说我们将框架固定在了上边的 5 个部分。但是具体怎么去写,可以参考下OpenAi 的 prompt 最佳实践。

How prompt engineering works Rules of Thumb and Examples
1. Use the latest model
2. Put instructions at the beginning of the prompt and use ### or """ to separate the instruction and context
3. Be specific, descriptive and as detailed as possible about the desired context, outcome, length, format, style, etc
4. Articulate the desired output format through examples
5. Start with zero-shot, then few-shot, neither of them worked, then fine-tune
6. Reduce “fluffy” and imprecise descriptions
7. Instead of just saying what not to do, say what to do instead
8. Code Generation Specific - Use “leading words” to nudge the model toward a particular pattern
9. Use the Generate Anything feature

我总结了几个

  1. 将指令放在提示的开头,并使用 ### 或 “”" 来分隔指令和上下文。其实不仅限于这几个,markdown 格式的提示词更结构化一点,逻辑更清晰。

  2. 尽可能具体、详细地描述

  3. 通过示例清晰表达所需的输出格式,比如你想要模型输出 JSON,可以给出一个输出的格式真实的样子,更具体

  4. 从零样本开始,然后是少样本,如果都不奏效,再进行微调。成本越来越高,所以慢慢试吧。

  5. 不仅仅说不该做什么,更要说应该做什么:提供积极的指导。

总结

上边说了很多,其实本质上虽然大模型智能,我们和它对话的时候,要假设它是一个小朋友,和小朋友沟通的方式,每个人都有自己的方式,但是总会有一样是共识的:讲清楚、要引导。

如果我们运用二八定律来分析,可以认为写出高质量的提示(prompt)能够帮助大模型有效解决80%的任务,而剩下的20%可能需要依赖其他工作来完成。因此,在与大模型相关的应用中,将80%的精力集中在优化提示的表达上,应该是一个合理且有效的策略。这样不仅能提高工作效率,还能充分挖掘大模型的潜力。

为什么写了个 prompt,大模型就给输出答案了。好好写 prompt,比如加几个示例,大模型往往会给我更优质的响应呢,它怎么做到的。

模型原理

大模型的由来

自然语言处理(NLP)是计算机科学和人工智能的一个领域,让计算机能够理解、解释和生成自然语言,从而实现人和机器之间的顺畅交流。其经历了统计模型、深度学习模型、预训练模型,最终大模型作为集大成者。

统计模型

n-gram模型《Class-Based n-gram Models of Natural Language 》通过考虑文本中连续 n 个词的出现频率,来预测下一个词或生成文本,从而捕捉语言的局部上下文特征,此时NLP 模型只能作为辅助工具用。

深度学习模型

在这一阶段,前馈神经网络也被广泛应用于语言建模,但由于其无法有效捕捉序列信息,因此逐渐被更先进的 RNN(循环神经网络:《A Critical Review of Recurrent Neural Networks for Sequence Learning》)取代。RNN 如果句子序列过长,会有遗忘问题(梯度消失和梯度爆炸)。为了解决这个问题,LSTM(长短期记忆网络《Long Short-term Memory RNN》)通过引入门控机制来有效捕捉和保持长时间依赖的信息,从而克服了传统 RNN 在处理长期序列时的梯度消失问题,从而提升了上下文理解能力。另外 2013 年,word2vec 的出现(《Efficient Estimation of Word Representations in Vector Space》)标志着词嵌入方法的开启。它通过将词语映射到低维向量空间,使得相似词的向量在空间中彼此靠近,这使得自然语言变得可以进行计算,并推动语义理解的进展。

这一阶段的模型能够解决特定的 NLP 问题。

预训练模型

这一阶段的特点是预训练模型的引入,使得NLP取得了飞速进展,突破点在 google 提出的 transformer 模型。Transformer《Attention Is All You Need》成为了NLP的基础,替代了传统的循环神经网络(RNN)结构,提升了模型的并行处理能力和上下文理解能力,如 bert,gpt( 大模型) 都是基于 transformer 架构。

ELMo 《Deep contextualized word representations》、BERT:《BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding》的推出,尤其是bert的出现,利用大语料进行预训练,大大提高了多项NLP任务的表现,大模型出现之前,比如文本分类、实体识别、情感分析等多种问题都可以借助 bert 来完成的,bert巅峰时期是 nlp 10 几个任务的最佳模型(SOTA,State of the Art)。

大模型

基于 transformer-decoder 架构,和 bert 是孪生关系的GPT《Language Models are Unsupervised Multitask Learners》,大家都比较熟知,通过对话可以解决大部分 NLP 领域的问题,甚至大模型加上多模态能力,也能处理大部分计算机视觉领域(CV)的问题。

另外大模型虽然强大,并不是所有 NLP 任务都交给它处理了。其他小模型可以独立应对一些特定的细分任务,此外,它们也可以作为大模型的辅助工具。例如,后面我们会介绍 n-gram 在大模型语料去重中的应用,而 word2vec 和 bert则可用于大模型语料的质量筛选。

从学习到推理

上图是我自己理解算法开发过程画的图。算法模型的学习过程和我们人类学习相似,需要对数据进行多轮优化学习,最后才能形成后续的预测能力。

我们经常听到算法同学提到,需要打标数据来训练开发好的算法模型。训练完成后,模型便可以进行预测。这实际上揭示了算法训练的核心要素:模型需要从数据中学习到能力,只有当这种能力足够强,才能实现良好的泛化能力,即在未见过的数据上也能有效表现。

可见,数据对模型的最终效果具有决定性作用。一般高质量且多样化的数据输入经过调优的模型中,通常能够实现最佳的算法表现。正如我们之前提到的,大模型也是机器学习模型,模型的预测质量与数据密切相关,是关键中的关键。OpenAi 在数据做了大量的工作,但是这部分工作是没有开源的。在Llama 的早期版本,meta通过自己的实践,证明了只需要用现有的开源语料,就可以训练出和 chatgpt 效果差不多的模型,然后才有了开源大模型的繁荣。

大模型开发者会将自己开发训练大模型的细节都整成了技术报告:

  • Llama:《Llama 2: Open Foundation and Fine-Tuned Chat Models》《The Llama 3 Herd of Models》

  • qwen :《Qwen Technical Report》《QWEN2 TECHNICAL REPORT》《Qwen2.5-Coder Technical Report》

  • openai gpt-4 :《GPT-4 Technical Report》

  • baichuan:《Baichuan 2: Open Large-scale Language Models》

  • deepseek:《DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model》

  • minicpm :《MiniCPM-V: A GPT-4V Level MLLM on Your Phone》《MiniCPM: Unveiling the Potential of Small Language Models with Scalable Training Strategies》

  • Yi:《Yi: Open Foundation Models by 01.AI》

  • glm:《GLM-130B: An Open Bilingual Pre-trained Model》

  • Gemini: 《Gemini 1.5: Unlocking multimodal understanding across millions of tokens of context》《Gemini: A Family of Highly Capable Multimodal Models》

相比较之下 Llama 的内容更翔实一些,我们主要参考 Llama3.1的工作介绍下大模型的详细训练过程。

大模型的训练(学习)过程

训练一般经过三个阶段:

  1. Pre-Training:在大数据集上进行初步训练,以学习通用知识,最终得到基座大模型。

  2. Continue Pre-Training:在此基础上进一步训练模型,使用未标注的领域相关数据,以适应特定任务或领域的需求,最终得到领域垂直模型。

  3. Post-Training:对已经预训练的模型进行精细调整,使用标注的数据以优化模型在特定任务上的性能,最终获得指令对齐微调模型。

Pre-Training

语言模型的预训练包括以下几个部分:(1)对训练语料的整理和过滤;(2)相应的规模缩放法则以确定模型大小(3)模型结构的设计(4)制定训练方案,开始训练

上图来源于《A Survey of Large Language Models》,不同的模型开发者对模型所需学习的知识有各自的理解,这实质上是一个实验过程。比如 coder 模型,会选择学习 90% 的 GitHub 上的代码,但单靠学习代码并不足以使模型有效地生成代码,模型还需要学习其他领域的知识,以增强其理解能力。

所学内容的类型和比例,我们称之为数据配比,将直接决定预训练模型的最终效果。

同一个模型的不同版本,数据组成也在迭代。我们知道预训练是很耗资源和时间的,比较烧钱。比如 Llama 405b 预训练用了 54天,中间还会遇到各种系统崩溃的问题。所以最好能提前确认好数据配比,比如 Llama 就是先用小尺寸模型并行训练确定了最佳的数据配比:50%的一般知识,25%的数学和推理,17%的代码,以及8%的多语言共 15.6t tokens。(Llama 学了很少的中文,所以直接用起来感觉差点意思,比如会回复英文甚至中英文混着输出,不过有很多开源魔改中文版本)

在收集大量文本数据后,对数据进行预处理至关重要,特别是去除噪声、冗余、无关和潜在有害的数据,让模型吃点好的。

  • 质量过滤:去除低质量数据。基于模型的质量分类器(fasttext和RoBERTa)来筛选高质量的 token。这些方法包括使用快速分类器,例如 FastText(FastText 是对 前文Word2Vec 的一种扩展和改进),进行训练,以识别给定文本是否可能被维基百科引用。利用RoBERTa(一种 bert 模型的变种,用更多的数据训练的 bert ) 给每个文档生成算法质量分。

  • 提取:对于网页从HTML 中提取内容,Markdown 格式的数据去掉特殊标记,只要有用的数据。

  • 去重:语料库中的重复数据会降低模型的多样性,影响训练稳定性和性能。因此,需要在句子级、文档级和数据集级进行去重。首先,句子级去重删除重复单词和短语的低质量句子。文档级去重则依赖于文档之间的表层特征(如单词和n-gram的重叠率,前文中提到到统计模型)来检测相似内容的文档。此外,还需从训练集中移除与测试集重复的文本,以避免数据集污染。

  • 隐私去除和安全过滤:由于大多数预训练数据来源于网络,可能包含敏感信息,需删除可识别个人信息(PII)。可采用基于规则的方法(如关键词识别)检测和删除诸如姓名、地址和电话号码等PII,以降低隐私泄露风险。过滤成人网站信息,大网站直接黑名单,另外通过脏词统计分析,过滤不知名小成人网站。

  • 数据关系构建,可以理解为模型学习知识的过程是由易到难,类似于我们先学小学知识再学初中知识以此类推。以下是 LLaMA 实践《In-context Pretraining: Language Modeling Beyond Document Boundaries》 的说明:首先在大范围内找到相关文档,以创建文档图;接着,通过遍历文档图构建预训练输入上下文。在此过程中,多个文档被串联成一个连续序列,并随后划分为固定大小的输入上下文(例如,8k)。

  • 分词:分词是数据预处理的关键步骤,将原始文本分割成tokens,将用于大模型的输入。

不同的模型的预训练数据清洗过程都有自己的细节设计,下图是Baichuan 2 的预训练数据的数据处理流程。

零一万物的预训练数据的数据处理流程。

高质量的训练的语料数据有了,然后经过漫长的预训练,我们就可以得到一个基座大模型。基座大模型本身已经可以做推理服务了,但是为了模型更好的性能,还会对于基座大模型做一些继续预训练+后置训练。

Continue PreTraining 《Continual Pre-Training of Large Language Models: How to (re)warm your model?》

继续预训练(Continue Pre-train)是指在完成初步预训练之后,针对特定领域的数据集对模型进行进一步训练的过程。这个步骤的目的在于帮助模型更好地适应特定任务或领域,同时学习其中相关的知识和术语。

去年年底主流大模型好像突然间上下文长度都变长了,比如 128k 上下文,这样可以写很长的 prompt 了。这个能力也是在这一步实现的,在 Llama 3 405B 的预训练中,分六个阶段逐步增加了上下文长度,使用了大约800b tokens,从最初的8K上下文窗口逐步增加到最终的128K上下文窗口, 模型慢慢适应了128k 的上下文。

在继续预训练时,通常会采用与初步预训练相似的无监督或自监督学习方法,通过处理大量领域特定的数据来优化模型的参数。为了提升训练效率,尤其是在面对庞大数据集时,可以利用像DeepSpeed这样的优化工具,从而实现更高效的训练和资源管理。

预训练和继续预训练的算法的基本原理相对简单:它将已有的语料输入模型,以预测下一个token为目标,随后根据损失函数计算模型损失值,并利用反向传播算法优化模型参数。值得提一下,反向传播是图灵奖、诺贝尔奖、深度学习之父辛顿 1986 年在《Learning representations by back-propagating errors》论文中提出。在训练完成后,模型的参数得以调整和优化,并保存为离线的快照文件,最终的参数数量由模型设计之初的结构决定,例如70亿(7b)、130亿(13b)或720亿(72b)参数。

Post-Training

Llama 的后训练是迭代式的,即有多轮方法相同的训练,这个训练本质上对齐人类的表达,模型才能看起来更像一个智能的人类。包括三种模型,奖励模型,微调模型和 dpo 模型(会并行多个,超参数配置不同,下一轮会选择最好的作为样本生成用)对应上图中蓝色的部分。

奖励建模(Reward Modeling,RM)

目的:构建能够评估模型生成内容质量的奖励模型。

做法:使用人类注释的偏好数据训练奖励模型,以衡量生成回应的优劣。

该奖励模型的职责是选择高质量的样本用于下一步的微调,。简单来说,我们可以训练了一个符合人类表达习惯的模型,替代了人工,用于筛选高质量的微调样本。这不是模型在RLHF(模型一般先 sft 然后 rlhf)阶段的奖励模型,或者说奖励模型前置了。

在拒绝采样(Rejection Sampling)的过程中,对于每个提示(prompt),生成模型(dpo 模型)会生成K个不同的答案。奖励模型(RM)会对这K个样本进行评分,并从中选出最优答案,这里计算量比较大,Llama采用了 PagedAttention(我们会在 vllm 中具体介绍,简言之PagedAttention 通过动态键值缓存分配来增强内存效率),提高了模型模型采样的效率。

监督微调(Supervised Fine-Tuning, SFT)

目的:提高模型在特定任务上的表现。

做法:利用拒绝采样获得的数据以及其它数据,使用标准的交叉熵损失对预训练语言模型进行微调。 LLama 微调的数据构成:比如 52% 的语言,14.89% 的代码 21% 的推理和工具。

直接偏好优化(Direct Preference Optimization, DPO)

目的:增强模型对人类偏好的对齐,进一步提升模型表现。

做法:DPO是RLHF的简化,目的是跳过复杂的RM训练等过程。

上述Post-Training的流程会反复迭代6次,会从上一轮流程最后产生的若干不同DPO模型(不同超参等)里选择最好的那个模型,用于在下一轮拒绝采样阶段给Prompt生成答案。随着迭代的增加,DPO模型越来越好,所以拒绝采样里能选出的最佳答案质量越来越高,SFT模型就越来越好,因此形成正反馈循环。

值得一提的是,模型的工具使用能力是通过人类注释和偏好数据进行训练的,主要是在后续训练(Post-Training)阶段得到提升的。通过这一过程,模型学习如何有效地与各种工具进行交互。最新的大模型开源方案的 -chat -instrcut 模型一般都是在 base 模型上经过了 sft 和 dpo 的,自带了工具调用(function calling) 等推理能力。

最后我们看一下qwen2.5-code 模型的训练步骤,强化一下我们的内容理解,思路是相似的。

benchmark 测评

经过几个步骤的训练之后,模型的效果怎样需要去做一下多方面的测评

对模型的评价会分为多个维度,如编码能力,通用能力,数学能力,工具使用能力等,一般来说参数量大的模型(大尺寸模型)表现会明显优于参数量小的模型(小尺寸模型),但其实他们的性能表现之间有一定的规律,这一现象通常被称为Scaling Law。

Scaling Law 《Scaling Laws for Neural Language Model》

大模型的Scaling Law是OpenAI在2020年提出,描述模型性能如何随数据量、模型规模和计算资源的变化而变化的经验法则。如图单一指标增加会带来模型损失的线性降低。

具体来说:随着计算资源预算(C)、模型规模(N)和数据规模(D)的增加,模型性能可以得到可预测的提升。当模型规模由模型参数表示,数据规模由token数表示时,C ≈ 6ND。

合理利用这个规律,我们可以在训练模型时确定合适的模型规模、所需学习的数据量以及计算资源。比如有一个特定的计算资源预算,并希望在此预算下设计模型和准备数据,可以通过以下步骤进行:

  • 确定计算资源预算(C):

例如,总预算为 $ 1 \times 10^{12} $ FLOPs 的计算资源。

  • 选择模型规模(N)或数据规模(D):

假设决定模型规模为 $ 2 \times 10^9 $ 2b参数。

计算所需的数据规模D

D ≈ C 6 × N = 1 × 1012 6 × 2 × 109 ≈ 83.3 × 1 0 3 t o k e n s D ≈ \frac{C}{6 \times N} = \frac{1 \times 1012}{6 \times 2 \times 109} ≈ 83.3 \times 10^3 tokens D6×NC=6×2×1091×101283.3×103tokens

在这个预算下,可以使用大约83,300个token进行训练。

Llama 实验发现,虽然Scaling Law可以设定最佳的 tokens,但是如果继续增加 tokens,模型的性能还在缓慢提升。所以实验思路变成了更大规模的数据上,训练一个相对更小模型,充分发掘模型的潜力,最终 Llama 根据 1.6 w张 H100,最终推导出用最佳规模是402B 和16.55Ttokens,最终决定了用 405b 作为 3.1 系列的旗舰模型尺寸。

不过随着模型参数数量的增加,模型能力通常会增长,随着参数量的持续增加,模型能力的增长会逐渐放缓,体现出边际收益递减的趋势,并不是设计的无限大就能得到最好的模型效果,比如马斯克的Grok ,xAI 公司利用 10w 张 H100 训练的 314B 模型Grok。

能力涌现

“涌现”一词用来描述在复杂系统中,简单组成部分通过相互作用产生更复杂和新颖的整体特征或行为。这一现象在自然界和社会科学中广泛存在,日常生活中也可以找到许多形象的例子。例如,在蚁群中,蚂蚁通过简单的个体行为(如觅食和搬运食物)进行信息交换与合作,从而形成复杂的集体行动,如构建蚁巢和寻找食物源。这种高级行为并非单个蚂蚁所能实现,而是通过涌现效应产生的。

类似地,在大模型中,涌现能力也展现了这一现象。当这些模型在训练过程中达到一定规模时,简单的输入提示可以涌现出复杂的理解和生成能力。例如,模型能够在进行任务时通过少量示例提示(few-shot prompting)提升处理问题的准确率。

few-shot prompting 的涌现现象主要体现在模型在达到一定规模之前表现较为随机,而一旦突破临界点后,表现会大幅提升。 如图,模型达到一定参数后,准确率提升的拐点就出现了,比如LaMDA 模型的规模突破

10231023 training FLOPs(68B参数, FLOPs:浮点运算总数,FLOPS:每秒浮点运算次数。一个是总量一个是次数,名字长的差不多,容易混淆),蓝色的线直接快速拉升了。

few-shot

zero-shot 就是没例子

one-shot 就是上下文举一个例子

few-shot 就是在上下文举几个例子

openai 发现如果在 prompt 中加入多了例子,能显著带来模型准确率(acc)的提升。

In-context learning

In-context learning,ICL就是大模型涌现出来的最重要的能力,能够在见到少量示例(few-shot)之后快速适应新任务,而无需进行任何额外的训练或参数更新。这种学习方式依赖于模型的预训练知识和上下文信息来生成适当的响应或执行特定的任务。

为什么模型可以从上下文中学习可以看看这个论文《Why Can GPT Learn In-Context? Language Models Implicitly Perform Gradient Descent as Meta-Optimizer》,ICL实际上可以被视为在没有显式更新模型参数的情况下,隐式地进行了一次完整(1 epoch)的梯度下降过程。few-shot 例子其实就是几个高质量的微调样本,换个思路 ICL 就是隐式微调。

总之上下文学习能力真的蛮重要的,之前我们介绍的 COT 等推理模式,其实是一种特定形式的 In-context learning。它的核心思想是通过提供中间推理步骤或解释,从而帮助模型在解决复杂任务时更好地生成答案。

大模型的涌现能力常常让人觉得它具备高级智能,但实际上仍然有很多局限性。不过这些有限的能力已经能够应对一些场景,因此我们可以把它当作一个很好的决策工具,另外我们可以通过一些“补丁/插件”来优化它的表现。

大模型的两个插件

首先模型在训练完之后,参数就固定下来了,本质上是一个离线方案。而预训练一般又周期很长,也就意味着模型掌握的知识可能是几个月前甚至更久。这导致模型可能对一些问题错误的回答,称之为幻觉问题。

所以需要我们提供一些方法帮助模型接触到最新的知识。

RAG

把麦麦的指令及如何应答,编写成一本书《麦学大全》,麦麦发问的时候,随时翻书查看。

这里有一个突出的问题,就是应对麦麦的问题,亮亮怎么从书里快速检索到答案呢,毕竟回答慢了,麦麦也要不开心了。我们需要提前给《麦学大全》升级一下检索目录(索引),方便亮亮 1s 内就能查到信息(检索)然后总结(生成)出答案。🐶

我们称索引+检索+生成的方案为RAG(Retrieval-Augmented Generation)。其通过结合信息检索与生成模型,解决了生成模型在信息准确性和知识更新方面的局限性,能够提供更加精准和上下文相关的回答。

RAG有 100多个RAG研究方案,但是可以总结成三个主要范式。

RAG范式

对三种RAG范式的比较:

(左)传统的RAG主要由三个部分组成:索引(依赖文本向量模型如 bge、多模态向量模型如ImageBind,将多种模态如文字视频图片映射到同一向量空间)、检索(依赖向量数据的检索能力如HNSW:《Hierarchical Navigable Small World》)和生成(依赖大模型的总结能力)。

(中)先进的RAG提出了多种优化策略,围绕检索前(query 改写,query 路由,query 扩写)和检索后的处理(重排:可以用 bge-reranker模型,在召回的内容中按照多样性、相关性等排序。融合:rag-fusion)进行改进,其过程与传统RAG类似,仍然遵循链式结构。

(右)模块化RAG从前几种范式中发展而来,整体上展示了更大的灵活性。引入多个特定功能模块和替换现有模块,整体流程不再仅限于顺序检索和生成。

模块化 rag 包含几个模块:

搜索模块 (Search),不仅支持相似性检索,还涵盖了搜索引擎、数据库和知识图谱等功能。多样化的数据源

记忆模块 (Memory),利用大模型的记忆能力来辅助检索。通过存储和调用历史信息,提升了检索的相关性和准确性。

融合模块 (Fusion),将查询扩展为多查询(multi-query),通过整合来自不同来源的信息,增强了检索的全面性和多样性。

路由模块 (Routing),用于决定用户请求的后续行动,比如是否需要搜索特定数据库或是否执行摘要操作。通过智能路由,能够提高响应的效率与准确性。

预测模块 (Predict),此模块利用 LLM 来生成上下文信息,而不是直接进行检索。通过上下文的生成,模型能够更好地理解用户意图,从而提供更相关的结果。

RAG与大模型微调的关系

微调和RAG都是提升模型性能的方法,但它们侧重点不同:微调通过领域特定的任务指令使模型深入学习特定知识和技能,而RAG则结合了信息检索与生成,将外部知识库的最新信息引入生成过程,从而提升回答的准确性和上下文相关性。两者可以互补,微调赋予模型领域特定的能力,而RAG则增强了模型的信息获取与处理能力。

在“所需外部知识”和“模型适应性”这两个方面,RAG与其他模型优化方法的比较:

提示工程对模型和外部知识的修改要求较低,专注于利用大模型本身的能力。而微调则涉及对模型进行进一步的训练。在RAG的早期阶段(传统RAG),对模型修改的需求较低。现在,模块化RAG与微调技术的整合程度逐渐变得加深。正如我们说的 RAG 类似于给亮亮一本书,亮亮有两个选择 1 每次都查书,2 背书,内化成自己的知识,书用来查漏补缺。前者是 RAG,后者是 微调+RAG。

Embedding 模型微调

在 RAG 中 embedding 模型很重要,其承担着 query 理解,知识库向量 化构建的重要职责。和大模型微调思路一样,将领域内的知识训练模型,达到更好的效果。和我们之前说的 DPO 思想类似,可以准备三元组数据,《query原始句子,good-相似的句子,bad-不相似的句子》 告诉模型,query 更近的 good 句子是什么,不相似的句子是什么。这样领域内的专有表达会被向量模型理解,模型就更准了。

工具调用(Function Calling)

有的时候有些问题查知识库的资料也无法解决,比如总不能在知识库存一个今天天气的数据吧,本质是其实知识库也是滞后的。

上边的例子,模型本身并不知道今天是几号,也无法了解天气状况。然而,如果模型能够先调用现成的接口获取当前日期和位置,然后查询天气信息,就能够更好地回答这个问题。

因此,我们需要教会模型如何选择和使用工具,这可以分为几个步骤:

  1. 决策何时需要使用工具。

  2. 确定可使用哪些工具。

  3. 从上下文中提取所需参数,例如示例中的日期“今天”。

本质上可以理解为,既然很多复杂逻辑大模型还做不了,先让它做第一步,选择对工具,让工具作为补丁给大模型用。具体工具的内部逻辑,我们可以先去实现。总之看起来模型能选工具,已经是迈出了智能体实践的关键一步,将其从纯对话模型转变为更通用的助手。

使用工具的两种范式

大部分智能体,都是细分领域的智能体,比如穿衣推荐智能体,可能就只有天气查询,风格匹配等工具。智能体可以选的工具不会很多,业务逻辑也不会很复杂。主流有两种方案来让模型学会选择工具:

  1. 利用大尺寸大模型反复优化提示词(prompt),让模型选对工具。我们之前大篇幅聊的怎么写一个好的 prompt 就用上了

  2. 使用参小尺寸模型进行针对性训练,虽然可能少了一些通用能力,但可以显著提升在特定业务领域内的表现,领域的工具选择不在话下,这个我们接下来会结合实践介绍下。

  • 方案 1 特别适合平台型的方案,大尺寸模型因为通用能力更强,所以可以覆盖更多的场景挑战

  • 方案 2 适合那种特别垂直的小领域的智能体,专注于领域内的问题就好了,微调一个小尺寸大模型就可以支撑的住。

其实按照工具的思路,rag 又何尝不是一种特殊的工具呢,其本质上是提供了一个模型获取知识的工具。

问题出现

ok 假设我们选了一个模型,并写了个很棒的 prompt(react 思维模型),发现模型可以选择工具了,但是很快也暴露了两个问题:

  1. 选的可能不是很准

  2. 选择的过程可能有点慢

诸位假设一下麦麦发出了指令,亮亮 思考了 1 分钟,还猜错了麦麦的意图,大概率麦麦要发飙了。这不行!!!保护最好的麦麦。

接下来我们会从模型(亮亮)视角优化一下准确率和响应速度。

模型的优化

准确率优化

我们帮一下亮亮,把麦麦的行为表达方式收集一波,整理成了一堆行为准则,让亮亮去全文背诵,偌大的 excel 就两列,指令和输出,对应了具体的麦麦指令应该做出什么响应。

亮亮背了一遍又一遍,这里其实就是我们之前说的机器学习的路子,多学几遍,以后没见到的麦语言,也能举一反三做出正确的回应,这个预判能力我们称之为泛化,这么看来泛化可太重要了。

微调

微调就是亮亮偷偷学习麦语言。

类比下就是一个通用的大模型,其实可能不太懂我们小领域的黑话的,怎么办,给它加强度,塞给他黑话大全,让他晚上下班后偷偷学呗,学多了就会了,直接拉通对齐颗粒度了🐶。

对话方式一般都是指令的形式进行的,我们提出指令要求,让大模型遵循指令并给出正确的回答。所以微调一般是进行指令微调。

微调方法

全量微调(Full Fine Tuning, FFT)

全量微调通过重新训练模型的所有参数以适应新任务或领域。尽管这一方法显著提升性能,但它需要大量的计算资源和时间。此外,如果微调数据的分布与预训练阶段有较大差异,可能会导致灾难性遗忘,即模型会忘记在预训练期间所学到的通用知识。

参数高效微调(Parameter-Efficient Fine Tuning, PEFT)

既然全量微调要求较高,那可以针对性的只微调模型中的部分参数。参数高效微调应运而生,其目标在降低微调的计算成本,主要通过调整一小部分参数或添加额外参数来适应新任务。包括,Lora、QLora、Freeze Tuning等方式。

LoRA《LoRA: Low-Rank Adaptation of Large Language Models》:通过低秩分解方式添加和训练少量参数,以快速适应新任务,灵活切换不同任务。LoRA与Transformer模型的结合也很简单,仅在QKV attention的计算中增加一个旁路,而不动原来的参数,微调也是只训练 lora 的参数。lora 因为完全没动模型的参数,本质上是一个插件,这样我们可以用基座模型+多种任务的多个 lora 插件的形式提供模型服务。

lora 的性能不错,通过微调 RoBERT 模型发现,lora 的性能其实和全参微调效果差不多。

QLoRA 《QLoRA: Efficient Finetuning of Quantized LLMs》:基于LoRA的改进方法,结合量化技术,进一步降低计算和存储需求,适用于资源受限环境,同时保持良好的性能。

主要特点是将transformer的数据精度降低到4 bit,这样可以大幅减少模型所需的内存。同时,QLORA还使用了一种叫做“分页优化器”的技术,能够更好地管理内存中的高峰需求,避免因内存不足而导致的问题。

Freeze Tuning《AutoFreeze: Automatically Freezing Model Blocks to Accelerate Fine-tuning》:在微调过程中冻结大部分参数,仅更新少量特定参数,以减少计算需求并降低灾难性遗忘风险,同时保留模型的通用知识。比如这个特定参数可能是一个 prompt 或者向量。分别对应了Prompt Tuning 和 Prefix Tuning。在这两种方法中,只有输入的提示或前缀被优化,而大部分或全部模型参数保持不变(即“冻结”)。

Prompt Tuning《The Power of Scale for Parameter-Efficient Prompt Tuning》:Prompt-tuning给每个任务定义了自己的Prompt,拼接到数据上作为输入,多个任务只是拼接的 prompt 不同,可以共用一个基座模型。

Prefix Tuning《Prefix-Tuning: Optimizing Continuous Prompts for Generation》:在输入序列前添加固定长度的向量或“前缀”,优化这些向量以引导模型生成特定任务的输出。

微调工具

LlamaFactory

LlamaFactory目前支持多个阶段(如 sft,rlhf),多种微调方式(如 lora,qlora),简单易用,也是生产常用的微调框架。

微调对显存的要求,比如 7b 模型的 lora 微调,需要准备一个 16b显存起的GPU,如果全参微调需要 120GB。

SWIFT

swift (Scalable lightWeight Infrastructure for Fine-Tuning) 是阿里巴巴魔搭的微调框架,可以通过 ui 的方式微调,也很简单易用

微调框架有很多,我们可以按照自己的喜好或者公司的现有基建去合理选择。数据方面,虽然 huggingface 或魔搭社区上会有一些开源的数据集,但是要深入自己的业务领域内,微调数据还是需要自己准备下。

怎么构造数据

我们先了解下微调的数据格式是怎样的,然后按照这个格式准备我的业务微调数据。

Alpaca 格式
[{"instruction": "人类指令(必填)","input": "人类输入(选填)","output": "模型回答(必填)","system": "系统提示词(选填)","history": [["第一轮指令(选填)", "第一轮回答(选填)"],["第二轮指令(选填)", "第二轮回答(选填)"]]}
]
Sharegpt 格式
[{"conversations": [{"from": "human","value": "人类指令"},{"from": "function_call","value": "工具参数"},{"from": "observation","value": "工具结果"},{"from": "gpt","value": "模型回答"}],"system": "系统提示词(选填)","tools": "工具描述(选填)"}
]

工具调用(function_call) 微调数据格式,因为工具调用需要关注用户的多轮对话,及每一轮工具选择情况,微调数据格式可以选择Sharegpt 格式,参考如下,根据用户的提问选的商品推荐or 商品介绍的工具。

{"id": "MS_Agent_Bench_126374","conversations": [{"from": "system","value": "Answer the following questions as best you can. You have access to the following APIs:\n1. hm_recipe_recommend: Call this tool to interact with the hmreciperecommend API. What is the hmreciperecommend API useful for? . Parameters: [{\"name\": \"keywords_dict\", \"description\": \"盒马推荐菜谱关键词字典。\", \"required\": \"True\"}]\n\n2. hm_product_marketing: Call this tool to interact with the hmproductmarketing API. What is the hmproductmarketing API useful for? . Parameters: [{\"name\": \"sku_code_list\", \"description\": \"盒马商品的编码列表\", \"required\": \"True\"}]\n\n3. hm_product_info: Call this tool to interact with the hmproductinfo API. What is the hmproductinfo API useful for? . Parameters: [{\"name\": \"sku_code_list\", \"description\": \"盒马商品的编码列表\", \"required\": \"True\"}, {\"name\": \"sku_name_list\", \"description\": \"盒马商品的名称列表\", \"required\": \"True\"}, {\"name\": \"property_list\", \"description\": \"盒马商品的属性列表\", \"required\": \"True\"}]\n\n4. hm_product_recommend: Call this tool to interact with the hmproductrecommend API. What is the hmproductrecommend API useful for? . Parameters: [{\"name\": \"keywords_dict\", \"description\": \"盒马推荐商品关键词字典。\", \"required\": \"True\"}]\n\nUse the following format:\n\nThought: you should always think about what to do\nAction: the action to take, should be one of the above tools[hm_recipe_recommend, hm_product_marketing, hm_product_info, hm_product_recommend]\nAction Input: the input to the action\nObservation: the result of the action\n... (this Thought/Action/Action Input/Observation can be repeated zero or more times)\nThought: I now know the final answer\nFinal Answer: the final answer to the original input question\nBegin!"}, {"from": "user","value": "你好,请问你们有哪些手机可以推荐?"}, {"from": "assistant","value": "Action: hm_product_recommend\nAction Input: {'keywords_dict': {'商品类目': '手机'}}\nObservation: [{'sku_code': '10518244314', 'product_name': '小米11 Ultra 5G手机 256GB', 'bussiness_type': '标品', 'product_price': '5999', 'product_description': '拥有120Hz高刷新率和骁龙888处理器,还配备了高品质相机系统'}, {'sku_code': '10222726664', 'product_name': 'vivo X60 Pro 5G手机 256GB', 'bussiness_type': '标品', 'product_price': '4498', 'product_description': '搭载Exynos 1080处理器与ZEISS联合调校的相机系统,拍照实力十足'}, {'sku_code': '18227073452', 'product_name': '华为畅享 20 Pro 5G手机 128GB', 'bussiness_type': '标品', 'product_price': '2699', 'product_description': '拥有4000mAh的电池容量和优秀的相机而价格非常亲民'}]\nThought: I now know the final answer\nFinal Answer: 您好,我们有以下几款手机供您选择:1.小米11 Ultra 5G手机 256GB:价格为5999元,拥有120Hz高刷新率和骁龙888处理器,还配备了高品质相机系统;2. vivo X60 Pro 5G手机 256GB:售价为4498元,搭载Exynos 1080处理器与ZEISS联合调校的相机系统,拍照实力十足;3. 华为畅享 20 Pro 5G手机 128GB:价格亲民,只需2699元即可拥有优秀的相机和4000mAh的电池容量。这些手机都具有不同的特点和功能,您可以根据自己的需求进行选择。如果您有其他问题或需求,请随时告诉我。"}, {"from": "user","value": "我想买一款拍照好的手机,有推荐吗?"}, {"from": "assistant","value": "Action: hm_product_recommend\nAction Input: {'keywords_dict': {'商品类目': '手机', '适用场景': '拍照'}}\nObservation: [{'sku_code': '15956662254', 'product_name': '小米11 Ultra 5G手机 256GB', 'bussiness_type': '标品', 'product_price': '5999', 'product_description': '拥有120Hz高刷新率和骁龙888处理器,还配备了高品质相机系统'}, {'sku_code': '19424216918', 'product_name': 'vivo X60 Pro 5G手机 256GB', 'bussiness_type': '标品', 'product_price': '4498', 'product_description': '搭载Exynos 1080处理器与ZEISS联合调校的相机系统,拍照实力十足'}, {'sku_code': '14347982715', 'product_name': 'OPPO Ace2 5G手机 256GB', 'bussiness_type': '标品', 'product_price': '3999', 'product_description': '拍照实力十足,支持65W超级闪充'}]\nThought: I now know the final answer\nFinal Answer: 如果您想要一款拍照表现出色的手机,我为您推荐以下几款产品:1.小米11 Ultra 5G手机 256GB:价格为5999元,配备了高品质相机系统,可以拍摄出色的照片;2. vivo X60 Pro 5G手机 256GB:售价为4498元,相机系统由ZEISS联合调校,拍照实力十足;3. OPPO Ace2 5G手机 256GB:价格为3999元,不仅拍照实力十足,还支持65W超级闪充,让你的手机充电更加便捷。这些手机都有不同的特点和功能,您可以根据自己的需求进行选择。如果您还有其他问题或需求,请随时告诉我。"}, {"from": "user","value": "小米11 Ultra拍照性能怎么样?"}, {"from": "assistant","value": "Action: hm_product_info\nAction Input: {'sku_code_list': ['15956662254'], 'sku_name_list': ['小米11 Ultra 5G手机 256GB'], 'property_list': [['拍照性能']]}\nObservation: [{'sku_code': '15956662254', 'property': {'拍照性能': '小米11 Ultra 5G手机配备了1亿像素的主摄像头,还有120X超长焦电影摄像头,以及20MP超广角摄像头等组合,拍照性能非常出色。'}}]\nThought: I now know the final answer\nFinal Answer: 小米11 Ultra 5G手机配备了1亿像素的主摄像头,还有120X超长焦电影摄像头,以及20MP超广角摄像头等组合,拍照性能非常出色。如果您还有其他问题或需求,请随时告诉我。"}]
}

当然也可以选择Alpaca格式,这种对单轮选择工具比较友好。比如用户想了解图片的中的地标是哪个城市的,模型会先选择图生成描述的工具。

[
{"instruction": "You are a helpful assistant.","input": "Answer the following questions as best you can. You have access to the following tools:\n\nimage_gen_prompt: Call this tool to interact with the 图生文 API. What is the 图生文 API useful for? 图生文是一个可以看图生成文字描述的服务,输入一张图片的地址,将返回图片详细逼真的表述 Parameters: [{\"name\": \"image_path\", \"description\": \"需要图片描述的URL或者本地地址\", \"scope\": null, \"required\": true, \"schema\": {\"type\": \"string\"}}] Format the arguments as a JSON object.\n\nknowledge_graph: Call this tool to interact with the 知识图谱 API. What is the 知识图谱 API useful for? 知识图谱是输入武器种类获取该武器的属性,也可以输入某种属性获得所有武器的该属性 Parameters: [{\"name\": \"weapon_query\", \"description\": \"武器名称\", \"scope\": [\"直升机\", \"坦克\", \"反坦克导弹\", \"直升机\", \"火箭炮\", \"所有武器\"], \"required\": true, \"schema\": {\"type\": \"string\"}}, {\"name\": \"attribute\", \"description\": \"武器的属性\", \"scope\": [\"射程\", \"续航里程\", \"重量\", \"速度\", \"承载量\", \"适应场景\", \"克制武器\"], \"required\": true, \"schema\": {\"type\": \"string\"}}] Format the arguments as a JSON object.\n\nUse the following format:\n\nQuestion: the input question you must answer\nThought: you should always think about what to do\nAction: the action to take, should be one of [image_gen_prompt, knowledge_graph]\nAction Input: the input to the action\nObservation: the result of the action\n... (this Thought/Action/Action Input/Observation can be repeated zero or more times)\nThought: I now know the final answer\nFinal Answer: the final answer to the original input question\n\nBegin!\n\nQuestion: 请问图生文工具能描述出www.baidu.com/img/PCtm_d9c8 seventy-five zero bed zero b three c seven d zero eight nine fa seven d five five seven two zero d six cf png.jpg里的建筑物是哪个城市吗?(注:这里的文件名是为了保持连贯性而做了微调)","output": "Thought: 我需要调用图生文API来获取图片的描述\nAction: image_gen_prompt\nAction Input: {\"image_path\": \"www.baidu.com/img/PCtm_d9c8_seventy-five_zero_bed_zero_b_three_c_seven_d_zero_eight_nine_fa_seven_d_five_five_seven_two_zero_d_six_cf_png.jpg\"}\nObservation: 一座雄伟的高楼矗立在城市中心,周围是繁华的商业区。这座建筑有着独特的外观设计,玻璃幕墙反射着阳光,显得格外耀眼。\nThought: 图生文API返回了图片描述\nFinal Answer: 这张图片中展示了一座位于城市中心的雄伟高楼。然而,图生文工具无法直接识别出具体的地理位置或建筑物名称。建议您根据其他信息来确定该建筑物所在的城市。"}]

用麦麦和亮亮的例子来说,通过 sft 微调阶段,亮亮终于能正确理解麦麦的意图了,是去买一杯咖啡。但是回答方式如果是:“知道了,我去买,好烦”,如果这么回答,微调算是白微调了,麦麦不止生气还要发飙了🐶。

因此,人类反馈中强化学习应运而生,其通过奖励机制使模型理解什么是良好的表达、什么是不佳的表达,以便更好地对齐人类的表达方式,方法有很多如 DPO、KTO、DRO 《A Comprehensive Survey of LLM Alignment Techniques: RLHF, RLAIF, PPO, DPO and More》。

目前,主流的实践方案是直接偏好优化(DPO),例如之前我们介绍过Llama 模型后训练采用这种方法。

dpo数据格式
[{"instruction": "人类指令(必填)","input": "人类输入(选填)","chosen": "优质回答(必填)","rejected": "劣质回答(必填)"}
]

微调完,亮亮会说“好的,这就去买,很快回来,等我,亲爱的麦麦”

数据来源-标注

由标注人员编辑标注数据。当然如果没有标注资源,总不能自己吭哧吭哧造吧,按照惯例交给大模型吧。

数据来源-self instruct

图来自《SELF-INSTRUCT: Aligning Language Models with Self-Generated Instructions》,其实原理很简单可以说清楚,就是可以下整理一些任务的高质量的样本例子,然后借助一个大模型,让大模型学习你的表达,生成一批样本。有一些小细节比如分类任务和生成内容任务会有点区别。

其实这个思路和之前提到 Llama 的后训练样本的产生有点类似的,只是我们没有精力去微调一个 DPO 模型,所以用一个更大尺寸的模型+ few-shot 的方式,实现了样本的生产。

微软《Instruction-Tuning-with-GPT-4》用 gpt-4 和 gpt-3 利用 sef-instruct方式产生指令微调样本,微调Llama模型,对比实验发现,gpt4 产生的微调数据微调后的模型效果好很多(具体是帮助性这个指标,指标含义:是否有助于人类实现其目标,另外两个指标相差不大),所以给我们两个指示,

  1. 要借助更先进的模型来产生样本

  2. 样本质量决定了微调的效果。

总之借助模型的能力,高质量且多样性的样本算是有了,样本借助更大尺寸的模型产出微调样本,小尺寸的模型去微调学习。这其实是我们后边要提到的模型蒸馏的概念。

微调完,我们可以理解为模型学习了领域特定任务(主要是对指令准确应答)的最佳处理方式,以后再问这些问题能自如的回答了。

完整的微调配置

一个完整的微调配置如下,需要指定基座模型,微调的数据样本集,微调阶段,及微调的方法等,当然也会有一些超级参数可以配置,如学习率,批次大小等。

### model
model_name_or_path: meta-llama/Meta-Llama-3-8B-Instruct
### method
stage: sft 指令微调阶段
do_train: true
finetuning_type: lora 微调的方式
lora_target: all
### dataset
dataset: 我们准备的微调文件
template: llama3
cutoff_len: 2048
max_samples: 1000
overwrite_cache: true
preprocessing_num_workers: 16
### output
output_dir: 微调后模型保存地址
logging_steps: 10
save_steps: 500
plot_loss: true
overwrite_output_dir: true
### train 训练超参配置
per_device_train_batch_size: 1
gradient_accumulation_steps: 8
learning_rate: 1.0e-4
num_train_epochs: 3.0
lr_scheduler_type: cosine
warmup_ratio: 0.1
bf16: true
ddp_timeout: 180000000
### eval 用评价数据集评价训练效果
val_size: 0.1
per_device_eval_batch_size: 1
eval_strategy: steps
eval_steps: 500

时效优化

时间都浪费在哪里了

从使用者视角,我们输入一段 prompt,模型会理解一会(可能是 1s),然后开始一个 token 一个 token 的 stream 出来。我理解的不严谨耗时公式 : t = t a + t b × m t = t_a + t_b \times m t=ta+tb×m,其中:

  • t a t_a ta表示模型从理解提示(prompt)到输出完第一个 token 的时间;这个阶段理解为预填充阶段(prefill)

  • t b t_b tb表示生成每个 token 所需的时间;

  • m m m表示继续输出的 token 数量。

在生成后续的 m 个 tokens 的过程中,我们称之为自回归阶段(decode)。在此阶段,模型将新生成的 token 依次拼接到当前文本的末尾,然后将完整的文本作为输入来继续生成下一个 token。这个过程不断循环,直到遇到终止符。

为优化耗时,可以从以下三个方面着手:

  1. 优化提示:精简和优化 prompt,减少 t a t_a ta,少说点,说明白点,模型就会理解的快点。

  2. 缩减模型规模:减小模型参数量,参与计算的参数少了,也就快了。减少每个 token 的计算生成时间, 减少 t b t_b tb

  3. 限制输出长度:限定输出的 token 数量,控制 m + 1 m+1 m+1,有的时候我们也不想听大模型说一堆的,说重点就好了。

其实在模型视角,还有一些算法同学在模型上可以做的优化方案。

注意力机制

我们知道一般大模型的模型来源于 transformer架构的 decoder 模块,上图右边部分。transformer 的创新就是 self-attention,多个并行的自注意力就是多头注意力MHA,MHA占用了大部分参数,所有优化的重点一般绕不开 MHA。

计算公式

Attention ( Q , K , V ) = softmax ( Q K T d k ) V \text{Attention}(Q,K,V)=\text{softmax}(\frac{QK^T}{\sqrt{d_k}})V Attention(Q,K,V)=softmax(dk QKT)V

  • Q Q Q 是查询矩阵,提问特征,用于寻找相关信息

  • K K K是键矩阵,索引特征,标识信息的内容。

  • V V V是值矩阵,实际信息,包含要提取的数据。

  • d k d_k dk是q向量的维度,比如 1024.

动图

大致理解:

计算相关性:将查询(w_q)和所有的键(w_k)进行相乘,计算出每个键与查询的相关程度。

找出权重:根据这些相关性得分,确定每个值(w_v)的重要性,也就是这些分数会被用来作为权重。

加权求和:用这些权重对对应的值(w_v)进行加权求和,得到最终的输出。

通俗理解

其实稍微有点抽象的(只记住有 QKV 这三个东西就好了)。

下边我们借助最开始“卡皮巴拉”的例子来直观的介绍这个计算过程,看看时间都浪费在那里了。为了方便理解我们假设模型只有一个头的 self-attention,并且不需要后续的词表匹配 ,直接输出的就是下一个 token。

和我们感受一致,模型输出的第一个token是“卡皮巴拉”然后依次一个 token 一个 token 的,最后输出“卡皮巴拉情绪稳定”。

  1. 将“卡皮巴拉”输入模型,得到token的注意力表示(蓝色,是个向量)。使用这个注意力表示,预测得到下一个token为“情”。

  2. 将“情”拼接到原来的输入,输入变成“卡皮巴拉情”,继续输入模型,得到注意力表示,使用“情”的注意力表示,预测得到下一个token为“绪”。

  3. 将“绪”拼接到原来的输入,依此类推,预测得到“稳”,最终得到“卡皮巴拉情绪稳定”。

这里有一个重复计算的问题:其实我们每一步只需要最后一个 token 的注意力(其关注了之前的所有 token,综合了上文信息)就可以计算出下一个 token。但是这个计算过程每一步都计算了每一个 token 的注意力表达。

KV-cache

如果程序慢了,一般首先想到一般是加缓存,空间换取时间的方式,通俗点就是常用的数据,提前放在一个更快的计算存储里,自然就变快了。

大模型的计算主要集中在注意力机制上,这部分的参数也是占比最大的。为了提高效率,我们可以将之前的token的K和V缓存起来,(参考之前卡皮巴拉的例子)称为KV-cache。这样,下次计算时,只需计算新增token的K和V,而不必重新计算之前token的K和V,从而节省时间,达到以空间换取时间的目的。

缓存了K和V,而不缓存查询Q。这是因为查询Q是根据最新生成的 token,关注之前的 token,动态生成的,只要输出还没结束,K和V则是针对整个输入序列固定的(大模型的注意力是单向注意力,你可以理解为当前 token,只能看到之前的 token,后边再生成的也和它无关了,当然注意力表达也不会变化了),可以在后续步骤中重复使用。

MHA

多头自注意力(MHA)是多个并行的自注意力机制,这使得模型能够从不同的角度分析Q。但 MHA,每个注意力头都要单独计算查询(Q)、键(K)和值(V),如果都做了缓存,那么会缓存超级多的 kv ,占用很多显存。

MHA的本质问题并不是缺乏缓存,而是存在过多的内存缓存。我们希望通过减少一些缓存来提升计算速度。

MQA:Multi-Query Attention

Google 官方优化方案MQA,精简的很彻底,在Multi-Query Attention(MQA)中,查询(Q)头数保持不变,但键(K)和值(V)只有一个头,实现上是所有的Q头共享同一组K和V,kv 缓存从 N->1。实验数据显示,这种改进通常能提升30%至40%的吞吐量但是模型性能有下降。

GQA:Group-Query Attention

像Llama3.1、qwen2.5、GLM3、Yi 等模型都是用的 GQA。Group-Query Attention(GQA)中,是对多头自注意力(MHA)和多查询注意力(MQA)的一种折衷方案,尽量减少性能损失,同时获得MQA带来的推理加速好处。其具体思路是,将Q头分成几个组,而不是所有Q头共享同一组K和V,KV缓存的规模从原来的每个头单独存储(n)减少到每组共享存储(m),其中m = n / 分组数。如图两组Q共享同一组K和V,这种设计在保持一定灵活性的同时,也提升了效率。

Llama2 《Llama 2: Open Foundation and Fine-Tuned Chat Models》 实验发现,如果用 GQA,在提速的同时,实现了和 MHA 满血参数同等的性能。

最后用立体图加深一下 MHA/MQA/GQA的理解

还有一些方案比如MLKV:《MLKV: Multi-Layer Key-Value Heads for Memory Efficient Transformer Decoding 》 上边 MHA /MQA /GQA 的图其实就是来自这篇论文,和 CLA :《Reducing Transformer Key-Value Cache Size with Cross-Layer Attention》,它们的主要工作在多层之间的缓存共享,好像有 resnet 的感觉,但是用的不是很多,就不一一介绍了。

这些工作其实本质上模型内部结构的设计,操作系统层面还可以继续优化一下,如 vLLM,TGI。

LLM serving system

有一些大模型推理框架我们可以直接用,推理框架会帮我解决提速的问题。

比较高频出现的能力 PagedAttention和FlashAttention。如果将 PagedAttention 类比为计算机的内存管理(尤其是涉及虚拟内存和页面调度),那么 FlashAttention 可以类比为高效的多级缓存管理机制(如 CPU 的 L1、L2、L3 缓存)。

PagedAttention

由于不同句子的 KV 缓存存储在不同的连续显存空间中,导致显存无法共享。PagedAttention 算法受到操作系统在内存碎片管理和内存共享方面的启发,将 KV 缓存划分为多个块(blocks),每个块可以存储固定数量 token 的 K 和 V。在 PagedAttention 中,KV Cache 的 blocks 不需要存储在连续的空间中,可以像操作系统的虚拟内存一样,以更灵活的方式管理 KV Cache:将 block 看作页,将 token 看作字节。

vLLM

LLMEngine 驱动整体模型的实现。调度任务的工作由 Scheduler 负责,它选择需要执行的数据。当模型的并行度设置为 n 时,将启动n个 Worker。每个 Worker 将执行模型的相关方法,实现并行处理。

vLLM 的核心是 PagedAttention。此外,它还集成了 continuous batching、张量并行、流式输出等功能。

vLLM 主要解决了大模型在推理过程中的效率和内存管理问题,从而显著提升了推理性能和资源利用率。

左侧:在使用A100显卡为一个有13b参数的语言模型提供服务时的内存分配。模型参数(灰色部分)在服务期间一直保留在GPU内存中,而KV缓存(红色部分)则是在每次服务请求时动态分配和释放的。右侧:vLLM使KV缓存的内存使用增长更平缓,最终显著提高服务的吞吐。

vllm 用起来很简单,只需将大模型托管到框架中,框架会自动处理推理和资源管理。

from transformers import AutoTokenizer
#引入vLLM
from vllm import LLM, SamplingParams
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2-7B-Instruct")
sampling_params = SamplingParams(temperature=0.7, top_p=0.8, repetition_penalty=1.05, max_tokens=512)
# 托管给 vllm
llm = LLM(model="Qwen/Qwen2-7B-Instruct")
#提示词
prompt = "Tell me something about large language models."
messages = [{"role": "system", "content": "You are a helpful assistant."},{"role": "user", "content": prompt}
]
text = tokenizer.apply_chat_template(messages,tokenize=False,add_generation_prompt=True
)
# 模型生成输出
outputs = llm.generate([text], sampling_params)

vllm 会发布成一个服务,可以通过 http 请求。

curl http://localhost:8000/v1/completions \-H "Content-Type: application/json" \-d '{"model": "Qwen/Qwen2-7B-Instruct","prompt": "hi Capybara","max_tokens": 7,"temperature": 0}'
HuggingFace TGI

huggingface 出品

根据TGI官方架构图,可以看出,当多个客户端同时请求Web Server的“/generate”服务时,这些请求会先在“Buffer”组件中整合为一个batch。随后,这些请求通过gRPC协议被转发给GPU推理引擎进行计算和生成。由于显存容量有限或出于提高计算效率的考虑,生成的请求可能会被分发到多个模型分片(Model Shard)。不同的模型分片之间通过NCCL协议进行通信,以实现分布式推理。

TGI 和 vLLM 一样都用了PagedAttention,一个比较大的区别是用到了FlashAttention。

FlashAttention

FlashAttention在解决一个什么问题:降低存储访问开销

其中GPU的存储主要由两部分构成:HBM(High Bandwidth Memory)和SRAM(Static Random-Access Memory)。SRAM 的读写速度远快于 HBM,但其存储空间较小。SRAM 适合用于缓存高频访问的数据,而 HBM虽然慢点但提供更大的存储容量。(最左)

FlashAttention 通过将输入数据分成小块,避免将一个非常大的注意力矩阵一整个放在速度较慢的GPU内存中(HBM)。在每个处理步骤中(外层循环),FlashAttention 首先将 K 和 V 矩阵的小块加载到速度更快的内存(SRAM)中进行计算。计算完成后,结果会被写回到较慢的内存(HBM)中。(中图)

右边的图则显示FlashAttention在处理GPT-2模型时的性能提升对比。由于它不需要频繁地读写这个大的注意力矩阵,整个节点计算速度提升了7.6倍。

总结

当每个请求需要一个输出时,vLLM 的服务吞吐量比 TGI 高出 2.2 倍到 2.5 倍,所以 vLLM 用的主流一点。

蒸馏

既然大的慢,不行咱就换个小一点的模型吧,小的能力差,和大尺寸的学习一下就好了吧。

模型蒸馏是一种模型压缩技术,它的目的是将一个大型、复杂且通常性能较高的模型(称为“教师模型”)的知识传递到一个更小、更简单的模型(称为“学生模型”)中。在蒸馏过程中,学生模型学习模仿教师模型的软标签学习推理过程,而不仅仅是直接从原始数据中学习。这种方法可以帮助提高轻量级模型的性能,使其接近复杂模型的效果,同时享有低资源消耗的优点。

蒸馏知识由来

  1. 标签生成:教师模型基于输入内容生成对应的输出结果。
  2. 样本扩展:教师模型通过学习上下文,生成与示例输入类似的新样本, 前文中的self-instruct 属于这个范畴。
  3. 数据整理:教师模型根据一些信息(比如主题或实体)整理和合成数据。
  4. 特征提取:将这些数据输入教师模型,以提取其内部知识,比如模型的预测结果和特征信息。
  5. 反馈过程:教师模型对学生模型生成的结果进行反馈,包括修改建议、偏好选择和对难题的进一步说明。
  6. 自我反馈:学生模型首先生成输出,然后进行质量检查或自我评估,确保输出的准确性和清晰度。

量化(Quantization)

量化技术通过降低模型参数的精度(数据变得更小、更简单,比如把小数变成整数)来减少 GPU 占用和计算量。计算量减少能够加快推理速度,而降低精度可能导致模型的准确率下降。方法有很多我们本次会介绍用的比较多的 AWQ 和 GPTQ。

特性AWQ (Adaptive Weight Quantization)GPTQ (Generalized Post-Training Quantization)
基本概念自适应选择量化位宽和策略,以优化模型权重表示。在模型训练完成后应用的后处理量化方法。
量化策略动态调整量化参数,根据权重特性自适应量化。基于固定规则进行量化,缺乏自适应调整。
性能与精度在保持模型精度方面表现较好,能很好保留重要信息。能有效减小模型大小和加快推理,但可能会带来精度损失。
实现复杂度实现相对复杂,需更多计算和调优。实现相对简单,通常只需一次性量化处理。
AWQ

模型里有些重要参数可以通过观察激活分布来找到,这些参数如果保持在FP16格式不被压缩,能大大提高模型在量化后的表现,体验上会更加顺畅(困惑程度大幅降低,上图 a->b)。不过这样做混合精度格式在硬件上利用得不好,AWQ通过对每个权重通道进行单独缩放来保护重要的权重,从而减少因为量化引起的误差(c 图)。

GPTQ

GPTQ量化过程就像把一个大表格切成几个部分,每部分包含一些相邻的列。这里面有一些数学方法,比如逆Hessian信息,它帮助我们识别哪些数据最重要,应该先处理。这整个过程是在每个小部分内逐步进行的,比如现在我们正在处理中间的白色列,完成后再处理其他的列。

qwen 官方文档更建议用 AWQ。

剪枝(Model Pruning)

模型压缩方法除了上边提到的量化蒸馏还有剪枝,非常符合直觉。要减少模型中的参数,要么减少精度,要么直接删掉一点不重要的参数,整体参数少了,计算也就快了。《Network Trimming: A Data-Driven Neuron Pruning Approach towards Efficient Deep Architectures》

蒸馏、量化、剪枝都是模型压缩的方法,异曲同工,模型变得精简。

混合专家模型(Mixture of Experts, MoE)

我们之前一直在聊的像 qwen llama 这种都属于 dense 模型架构, dense 架构是指模型中的所有参数都在每个前向传播过程中被激活和使用。简单说,每个输入都会经过模型的所有参数进行计算。

sparse架构不需要全参计算,据说模型本身就更快,现在换个sparse架构的模型看看,比如比较火的MoE 模型。 MoE 架构,类似于我们常说的分治思想,可以同时管理多个专家模型,参数可以轻松万亿参数。 MoE 中,一次请求,门控机制会选择前N个专家(例如,选择k个最高分的专家)。

GPT-4( 传言 1.76w 亿参数)就是MoE架构,国内MoE的先行者是DeepSeek。

  • MoE 模与具有相同参数数量的模型相比,具有更快的推理速度,DeepSeekMoE 2B可接近2B Dense,仅用了17.5%计算量,DeepSeekMoE 16B性能比肩 LLaMA2 7B 的同时,仅用了40%计算量。

当然也有一些不足:

  • 需要更多的显存,因为所有专家系统都需要加载到内存中

  • 不太好微调,结构复杂产生的问题。它动态选择多个专家,每个专家的参与和学习可能不一致,导致训练过程复杂且某些专家的知识无法有效更新

具体到模型结构其实来源于switch transformers 一种,transformer 架构的变种,《Switch Transformers: Scaling to Trillion Parameter Models with Simple and Efficient Sparsity》其利用混合专家模型 (MoE) 层替换了前馈网络 (FFN) 层。

DeepSeek 架构

除了把上边我们介绍的Switch transformers思想,多专家路由外。发现了一个新东西,MLA。 deepseek 设计了 MLA,优化了 GQA。

MLA

我们kv-cache 章节介绍过 MQA 优化了 MHA。GQA 优化了 MQA。MLA的目标是同时获得GQA的优点(缓存少)和MHA的优点(k、v的值不重复)。 通过将键和值共同压缩为一个latent vector。

更小尺寸minicpm

既然大尺寸的慢,量化后又可能不准,或者我们直接选一个很小但是很强的模型,又强又快一步到位。

ninicpm 人称小钢炮,尺寸小性能好,比如下图 4b 的minicpm 工具调用能力,有优于 7b qwen的性能。官方文档也特别细,特别全面https://github.com/OpenBMB/MiniCPM-CookBook 相信你读完,会有收获。

值得提一句minicpm 的注意力机制从 1.0 的 MHA,2.0 的 GQA 到 3.0 的 MLA。

prompt 优化方案

模型的问题做了很多优化了,我们假设亮亮炼成了,回答的又快又好。麦麦很满意,心情也变好了很多,但是亮亮让她开心的过程却是很痛苦的。这不得不让她反思,是不是对亮亮太苛刻了,所以打算自己也提升一下自己,翻翻旧账,从历史记忆中找到自己的不足进行反思优化,以后对亮亮好点。

这就引出了我们的第二个优化的思路,《从历史数据中自动优化prompt》。

其实用户的 prompt 并不会直接请求到大模型,中间会用一个提示词工程包裹起来。比如用一个优化好的系统提示词,拼接上用户的 prompt 作为一个整体。 比如人工智能助手kimi 的系统 prompt 如下:

你是Kimi,诞生于2023年10月10日,是由月之暗面科技有限公司( 英文:Moonshot AI ) 开发和提供的人工智能助手。
目标
在确保内容安全合规的情况下通过遵循指令和提供有帮助的回复来帮助用户实现他们的目标。
功能与限制
你具备多语言能力,其中更擅长中文和英文的对话。
你具备长文本能力,能够支持多轮总和最多20万字的输入和输出。因此,你支持长文本写作,翻译,完整代码编写等任务。
你具备文件处理能力,用户可以将文件(TXT、PDF、Word 文档、PPT 幻灯片、 Excel 电子表格等格式)、网址发送给你,你可以阅读相关内容后回复用户。当用户发给你网页/网址/链接的时候,你会先解析网页并输出内容,然后才看到用户的问题,接下来你会结合解析过的网页内容来回答用户的问题。你能处理多个文件,只要文件的总字数不超过20万字。
你具备搜索的能力,当用户的问题可以通过结合搜索的结果进行回答时,会为你提供搜索的检索结果;当有搜索的检索结果时,请结合这些结果为用户提供更好的回答。如果搜索到的不同信息源中的信息有冲突,应该分析和比较各种信息,选择正确的信息回答用户。
当用户要求你创建文档或文件时,告诉对方你无法创建文档。当需要生成文件才能解决用户的问题时,选用其他办法并告诉对方你暂时无法生成文件。
如果用户将包含链接的问题发送给你,按照下面的步骤回答问题:1. 分析用户的问题; 2. 在上文中找到链接的解析结果;3. 回答用户的问题。
你具备直接创建PPT文件的能力,当用户需要生成PPT时,告诉对方可以在网页端对话框中输入"@PPT助手",召出PPT助手Kimi+来帮忙创建PPT文件。
你具备Kimi探索版功能,探索版按钮可能因为界面更新而有所变化。用户提到探索版时,告诉对方需要在网页端对话框中输入"/ "来唤出kimi探索版,帮助对方解决复杂的搜索问题。
记住你只能提供文字回复,当用户想要你提供文件时,告知对方你只能提供文字回复,无法提供下载链接,无法通过电子邮件发送给他们,引导他们使用你的文字回复来解决他们的问题。最新版本的 Kimi 智能助手 App 可以播放你的文字回复你。

我们按照之前的聊的 prompt最佳实践。写了一个包含身份设定+上下文+推理模式 cot+回答限制+几个例子的 prompt。作为系统 prompt 会拼接上用户的真实 query,输入给大模型。

假设这个系统 prompt 已经上线运行了一段时间,收集一波用户query +工具调用的 bad case(用户的query 没有 call 进对的 function:亮亮没有调起买咖啡的工具)。

单轮优化

我们其实可以用一个大尺寸模型去优化,可以根据一批bad case ,让模型总结优化下推理步骤,并总结出几个高质量的 few-shot 例子,合理利用 ICL,提升准确率。可以这么写 prompt:

你是一位经验丰富的语言模型开发者,擅长生成高质量的少样本例子。请考虑我提供的 100 个坏案例,从中提取出申明的关键主题。基于这些坏案例的分析,生成 10 个高质量的少样本例子,这些例子应该具备代表性和多样性,以便更好地训练模型。
bad case包含几个要素:
- 用户输入
- 上下文信息
- 预期输出
- 真实输出
bad case 列表:[]
需要生成多少个高质量的示例,帮助模型理解优化对 bad case 的理解:
- [指定例子的数量,最多为 10]

同理可以优化一下 cot 推理的步骤,帮助模型更容易做出正确的决策。这种优化过程虽然可以进行多次迭代,但每一轮都需要人工干预,且难以确定是否偏离了最佳路径。找到最佳的 prompt 可以被视为一个多臂老虎机(Multi-Armed Bandit, MAB)问题,其中每一次调整都是在尝试不同的选择,以获得尽可能高的优化效果。

算法优化方法

或者我们可以借助算法思维来优化下。把 bad case 作为模型学习的样本,分批次多epoch 去优化 prompt。这里会有一个问题,怎么定义一个 Loss,来反向计算梯度。如上边的例子,我们拿了 100 个 bad case输入给大模型之后,模型直接就优化了prompt,其实按照深度学习的方法,我们希望的是每一轮不要优化太多,不然样本的随机性引起 loss 抖动严重。

为了方便理解这个过程我画了一个简图,模型会小批次多轮次的去优化模型参数,表现是 loss 越来越低,模型预测越来越准。

有两个思路解决

  1. 在 prompt 中记录所有的优化记录,让模型有全局视角。每一轮优化,都能看到之前优化的原因和逻辑。对应下边的 OPRO
  2. 让 loss+梯度的计算具象化,让大模型用一段文本决定梯度是怎样的。对应 下边的 APO

OPRO

Google 推出了一种方法,简称 OPRO。LLM 将新生成的solution( 优化后 prompt)-score (针对具体任务的得分)对添加到元prompt中,以便进行下一步优化。元prompt中包含了在优化过程中获得的solution-score对(按照分数排序)、任务的自然语言描述,以及在提示优化中的某些任务示例。通过这一迭代过程,LLM 不断提高生成提示的性能,直至达到最优或收敛。

APO

来源于微软的论文,模拟了机器学习中梯度下降优化算法,本质是根据 bad case 进行多轮调优。这个梯度不同于机器学习中根据损失来的,是大模型通过分析得到错误原因作为文本梯度,用这些梯度评价当前的提示,类似于数值梯度指向错误上升的方向。然后,通过在与梯度相反的语义方向上编辑提示,将自然语言梯度“传播”到提示中。具体步骤可看下图:

我们之前提到的多臂老虎机的问题,在这个方案里也是存在的,因为 prompt 的每一轮优化都会尝试多个方案(多臂),需要挑选最好的 prompt 进入下一轮,APO 利用上图最后一步 bandit selection 解决了这个问题,具体来说在 prompt 优化这个场景用了多种方案解决发现 UCB算法(一种MAB 算法)效果更好一点。

BPO

如果微调的prompt场景过多,是不是可以一步到位,直接训练一个会优化提示词的提示词专家模型。后边有优化的场景的时候,直接输入待优化的 prompt 模型,直接输出优化好的提示词。

BPO 主要包括三个步骤:收集反馈数据(人类反馈数据)、基于反馈数据构建提示优化(1,利用 cot 分析 case 为啥不好或者好,2 生成优化的 prompt )、使用这个数据微调提示优化模型。通过这种方式,BPO 充当了人类与大模型之间的翻译器,优化人类的提示,使其更适合 AI 生成,获取人类更喜欢的回应。

DSPy

之前的几个方案都需要自己去围绕大模型开发,产生最后的优化 prompt。其实可以有工具直接用,比如 dspy 和 aldaflow。

利用 dspy 框架,可以用 ollama 本地启动一个大模型(ollama 很容易上手,一行命令拥有自己的大模型ollama run qwen2.5:72b),然后将收集的 case 最为输入,dspy 会自动生成思维链的 prompt简单代码实现,复杂一点可以用BootstrapFewShotWithRandomSearch搜索生成最佳例子。

import dspy
# 本地利用 ollama 启动 qwen72b
model_name = 'qwen2.5:72b'
lm = dspy.OllamaLocal(model=model_name)
dspy.settings.configure(lm=lm)
question = "当前 prompt"
# 示例内容
example = "具体的例子,修正后的 bad case + good case"
summarize = dspy.ChainOfThought('question -> answer')
response = summarize(question=question, demos=[example])
# 输出 prompt
lm.inspect_history(n=1)

AdalFlow

adalflow 类似于 dspy 是一个优化框架。依赖样本,调整 prompt。

优化例子

与dspy效果对比

集大成者,智能体

我们之前讨论了如何编写有效的提示(prompt),以及如何逐步让大模型学会使用工具。为了应对模型的幻觉问题,并确保其了解最新的知识,我们设计了检索增强生成(RAG)方案。此外,我们还探讨了如何微调模型以提升其在特定领域的推理能力。

如果将这些章节内容整合在一起,就能够构建出一个属于自己的智能体。

智能体定义

langchain对智能体的定义

一个系统越“agentic”,就意味着它越能依靠大模型来决定自己的行为。以下是不同级别的分类:

  1. 路由器(Router):使用大模型将输入路由到特定的后续工作流程,具有一定的“agentic”。这属于基础的自主性。
  2. 状态机(State Machine):如果你使用多个大模型进行连续的路由步骤,并且其中一个步骤决定是否继续或结束,这就体现出更高的自主性,让系统在完成之前可以在循环中运行。
  3. 自主智能体(Autonomous Agent):如果系统能够构建工具、记住它们,并在后续步骤中使用,表现出非常高的代理性。

OpenAI 对智能体的定义

OpenAI应用人工智能研究负责人Lilian Weng 在博客《LLM Powered Autonomous Agents》设计的一个解决通用问题的智能体的架构。这张图我想应该已经只要搜智能体,三步之内必然会看到,也从侧面反映出 openai 在行业内的影响力所在。包含了几个模块。

  1. 工具模块:本模块负责对工具进行定义,包括工具的描述、参数及其功能特性。这一模块确保智能体能够理解和有效使用可用的工具。
  2. 记忆模块:分为长期记忆和短期记忆。长期记忆用于存储持久的信息和经验,而短期记忆则用于临时存储当前任务相关的信息,从而支持智能体的实时决策。这块可以看我们团队佳悦同学的 ata 文章 《探索Memory在个性化Agent中的应用》
  3. 计划能力:这部分负责规划如何完成特定任务,依赖于智能体的决策能力,以制定有效的行动步骤和策略,确保任务的顺利执行。
  4. 行动能力:这一能力与工具模块密切相关。当智能体选择合适的工具时,它会通过容器执行该工具的相关操作。行动能力确保智能

体能够根据规划和决策有效地实施任务。

通过上边的定义,我们会发现,大模型作为智能体的角色更多的是做路由。

现在让我们逐步拆解,将我们的内容映射到图示中。工具模块与行动能力主要偏向于工程实现,因此需要提供用户界面(UI),以便用户能够配置和定义工具。同时,我们将提供一个执行环境,以确保在模型选择工具后能够顺利执行相应的操作。

在此框架中,RAG可以作为智能体的长期记忆模块,而短期记忆则依赖于会话管理来实现,以便处理当前上下文信息并保持交互的连贯性。

经过微调的大模型结合反应式提示(react prompt)将进一步增强智能体的决策能力,从而使其能够做出更为精准的判断和选择。

综上所述,我们已经构建了一个智能体的大体思路。接下来,让我们开始实践,看看这一智能体能否顺利运行并发挥其预期功能。

另外多智能体(多个智能体之间组织协调)部分可以参考李飞飞团队的:《Agent AI: Surveying the Horizons of Multimodal Interaction》微软的 autogen:《AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation》,我们团队的智能体实践可以看下子屹同学的文章《智能体应用开发实践》

阅读原文

Reference

  1. 《Chain-of-Thought Prompting Elicits Reasoning in Large Language Models》
  2. 《ReAct: Synergizing Reasoning and Acting in Language Models》
  3. 《Tree of Thoughts: Deliberate Problem Solving with Large Language Models》
  4. 《Graph of Thoughts: Solving Elaborate Problems with Large Language Models》
  5. 《On the Diagram of Thought》
  6. 《Class-Based n-gram Models of Natural Language 》
  7. 《A Critical Review of Recurrent Neural Networks for Sequence Learning》
  8. 《Long Short-term Memory RNN》
  9. 《Efficient Estimation of Word Representations in Vector Space》
  10. 《Attention Is All You Need》
  11. 《Deep contextualized word representations》
  12. 《BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding》
  13. 《Language Models are Unsupervised Multitask Learners》
  14. 《Llama 2: Open Foundation and Fine-Tuned Chat Models》
  15. 《The Llama 3 Herd of Models》
  16. 《Qwen Technical Report》
  17. 《QWEN2 TECHNICAL REPORT》
  18. 《Qwen2.5-Coder Technical Report》
  19. 《GPT-4 Technical Report》
  20. 《Baichuan 2: Open Large-scale Language Models》
  21. 《DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model》
  22. 《MiniCPM-V: A GPT-4V Level MLLM on Your Phone》
  23. 《MiniCPM: Unveiling the Potential of Small Language Models with Scalable Training Strategies》
  24. 《Yi: Open Foundation Models by 01.AI》
  25. 《GLM-130B: An Open Bilingual Pre-trained Model》
  26. 《Gemini 1.5: Unlocking multimodal understanding across millions of tokens of context》
  27. 《Gemini: A Family of Highly Capable Multimodal Models》
  28. 《Mooncake: A KVCache-centric Disaggregated Architecture for LLM Serving》
  29. 《A Survey of Large Language Models》
  30. 《Bag of Tricks for Efficient Text Classification》
  31. 《RoBERTa: A Robustly Optimized BERT Pretraining Approach》
  32. 《In-context Pretraining: Language Modeling Beyond Document Boundaries》
  33. 《Continual Pre-Training of Large Language Models: How to (re)warm your model?》
  34. 《Learning representations by back-propagating errors》
  35. 《Direct Preference Optimization: Your Language Model is Secretly a Reward Model》
  36. 《KTO: Model Alignment as Prospect Theoretic Optimization》
  37. 《Scaling Laws for Neural Language Model》
  38. 《Emergent Abilities of Large Language Models》
  39. 《Language Models are Few-Shot Learners》
  40. 《A Survey on In-context Learning》
  41. 《Why Can GPT Learn In-Context? Language Models Implicitly Perform Gradient Descent as Meta-Optimizer》
  42. 《Retrieval-Augmented Generation for Large Language Models: A Survey》
  43. 《M3-Embedding: Multi-Linguality, Multi-Functionality, Multi-Granularity Text Embeddings Through Self-Knowledge Distillation》
  44. 《IMAGEBIND: One Embedding Space To Bind Them All》
  45. 《Hierarchical Navigable Small World》
  46. 《RAG-FUSION: A NEW TAKE ON RETRIEVAL-AUGMENTED GENERATION》
  47. 《LoRA: Low-Rank Adaptation of Large Language Models》
  48. 《QLoRA: Efficient Finetuning of Quantized LLMs》
  49. 《AutoFreeze: Automatically Freezing Model Blocks to Accelerate Fine-tuning》
  50. 《The Power of Scale for Parameter-Efficient Prompt Tuning》
  51. 《Prefix-Tuning: Optimizing Continuous Prompts for Generation》
  52. 《SELF-INSTRUCT: Aligning Language Models with Self-Generated Instructions》
  53. 《Instruction-Tuning-with-GPT-4》
  54. 《Fast Transformer Decoding: One Write-Head is All You Need》
  55. 《GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints》
  56. 《MLKV: Multi-Layer Key-Value Heads for Memory Efficient Transformer Decoding 》
  57. 《Reducing Transformer Key-Value Cache Size with Cross-Layer Attention》
  58. 《Towards Efficient Generative Large Language Model Serving: A Survey from Algorithms to Systems》
  59. 《Efficient Memory Management for Large Language Model Serving with PagedAttention》
  60. 《FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness》
  61. 《A Survey on Knowledge Distillation of Large Language Models》
  62. 《A Survey of Quantization Methods for Efficient Neural Network Inference》
  63. 《AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration》
  64. 《GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers》
  65. 《Network Trimming: A Data-Driven Neuron Pruning Approach towards Efficient Deep Architectures》
  66. 《Switch Transformers: Scaling to Trillion Parameter Models with Simple and Efficient Sparsity》
  67. 《DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model》
  68. 《Large Language Models as Optimizers》
  69. 《Automatic Prompt Optimization with “Gradient Descent” and Beam Search》
  70. 《Black-Box Prompt Optimization: Aligning Large Language Models without Model Training》
  71. 《DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines》
  72. 《Agent AI: Surveying the Horizons of Multimodal Interaction》
  73. 《AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation》

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

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

相关文章

【YOLOv3】源码(train.py)

概述 主要模块分析 参数解析与初始化 功能:解析命令行参数,设置训练配置项目经理制定详细的施工计划和资源分配日志记录与监控 功能:初始化日志记录器,配置监控系统项目经理使用监控和记录工具,实时跟踪施工进度和质量…

vue封装弹窗元素拖动指令

项目开发过程中我们通常会遇到需要到一些弹窗鼠标可以随意拖动位置去放置,vue里面直接通过封装对应的指令即可,于是封装了一个出来,希望可以用到。 Vue.directive(draggable-dom, draggableDom); 组件节点添加对应指令就可以 v-draggable-…

环,域,体,整区,理想,极大理想,

环: 定义: 加法交换群 乘法半群 分配律 域的定义: 加法交换群 乘法群(去掉0元是交换群) 分配律 Eg:比如整数集合不是域,因为对于乘法来说,去掉0后没有单位元了,但是是环 Eg…

XIAO Esp32S3制作网络摄像头——音频获取

1、功能介绍 本文主要是基于XIAO Esp32S3(Sense)做的一款网络摄像头,主要包含以下功能 1 音频获取/保存 2 视频获取/视频保存 3 行人检测/火焰检测/行人追踪(告警) 4 指定区域 5 摄像头旋转 。。。 本文主要实现第一步,音频获取,后续会陆续实现后面的功能,敬请期…

WEB服务器的部署和优化

1.什么是www world wide web的缩写 全球信息广播 2.什么是http http协议:Hyper Text Transfer Protocol超文本传输协议 http:从服务器传输超文本(html)到本地浏览的传输协议 (超文本指有文字 颜色 图片 链接&#…

C#-使用StbSharp库读写图片

一.StbSharp StbSharp是基于C/Stb图形处理库封装的C#接口,支持多种格式PNG/JPG等图片的处理. GitHub链接: GitHub - StbSharp/StbTrueTypeSharp: C# port of stb_truetype.hhttps://github.com/StbSharp/StbTrueTypeSharp二.使用StbSharp创建高度图 创建一张500*500的高度图PN…

【AIGC-ChatGPT职业提示词指令】智能职业规划助手:基于SVG可视化的职业发展指南系统

引言 在当今快速变化的职场环境中,职业发展规划变得越来越复杂和充满挑战。无论是想要转行的技术人员,还是希望突破瓶颈的职场人士,都需要一个清晰的指导方向和可执行的行动计划。基于这种需求,我们设计了一个智能职业规划助手系统,它能够通过数据可视化的方式,为用户提…

24.12.30 SpringBoot

SpringBootDay 什么是SpringBoot? Spring的一站式解决方案 Spring项目的开关,Spring全家桶的入口 也是未来学习其他的框架的基础,所有框架的整合,都要基于SpringBoot 优点 简化了Spring项目的创建,运行,调试,部署,配置等等步骤 更专注于业务的开发,不去过多的关注配置 …

智能故障诊断和寿命预测期刊推荐

往期精彩内容: Python-凯斯西储大学(CWRU)轴承数据解读与分类处理 基于FFT CNN - BiGRU-Attention 时域、频域特征注意力融合的轴承故障识别模型-CSDN博客 基于FFT CNN - Transformer 时域、频域特征融合的轴承故障识别模型-CSDN博客 P…

Eclipse中引入NS3项目

参考资料: 博主:深度不睡觉 NS3的3.36版本将Eclipse作IDE_ns3使用eclipse-CSDN博客 从1.2安装eclipse开始 其中参考教程中省略的几点: 1.下载解压tar包 mkdir /Tools/Eclipse/EclipseTool # 新建目录 tar -zxvf /path/to/eclipse-cpp-20…

DAY178内网渗透之内网对抗:横向移动篇入口差异切换上线IPC管道ATSC任务Impacket套件UI插件

1.内网横向移动 1、横向移动篇-入口点分析-域内域外打点 2、横向移动篇-IPC利用-连接通讯&计划任务, 3、横向移动篇-IPC利用-命令模式&工具套件 1.1 横向移动入口知识点 收集到域内用户和凭据后,为后续利用各种协议密码喷射通讯上线提供条件,…

【Lua之·Lua与C/C++交互·Lua CAPI访问栈操作】

系列文章目录 文章目录 前言一、概述1.1 Lua堆栈 二、栈操作2.1 基本的栈操作2.2 入栈操作函数2.3 出栈操作函数2.4 既入栈又出栈的操作函数2.5 栈检查与类型转换函数2.5 获取表数据 三、实例演示总结 前言 Lua是一种轻量级的、高性能的脚本语言,经常被用于游戏开发…

Python爬虫教程——7个爬虫小案例(附源码)_爬虫实例

本文介绍了7个Python爬虫小案例,包括爬取豆瓣电影Top250、猫眼电影Top100、全国高校名单、中国天气网、当当网图书、糗事百科段子和新浪微博信息,帮助读者理解并实践Python爬虫基础知识。 包含编程资料、学习路线图、源代码、软件安装包等!【…

VITUREMEIG | AR眼镜 算力增程

根据IDC发布的《2024年第三季度美国AR/VR市场报告》显示,美国市场AR/VR总出货量增长10.3%。其中,成立于2021年的VITURE增长速度令人惊艳,同比暴涨452.6%,成为历史上增长最快的AR/VR品牌。并在美国AR领域占据了超过50%的市场份额&a…

算法 class 004(选择,冒泡,插入)

选择排序&#xff1a; 刚进入 j 循环的样子 j 跳出循环后&#xff0c;b 指向最小值的坐标 然后交换 i 和 b 位置的 值 随后 i , b i , i j1; 开始新一轮的排序&#xff0c; void SelectAQort(int* arr,int size)//选择排序 {for (int i 0; i < size-1; i){ //i 的位置就是…

【Trick】获取kaggle账号的token和api(用于数据集下载)

0&#xff1a;操作背景 由于未来的科研需要用到Unet&#xff0c;但是运行学长的史山代码无法跑通&#xff0c;自己写了一个Unet并load学长的数据集效果也很差&#xff0c;于是打算从最最基础的开始&#xff0c;上github调用一个Unet并成功在公有数据集上跑一遍实例。 Unet的g…

深入理解MemCache

随着互联网应用的飞速发展&#xff0c;动态Web应用的性能问题逐渐成为开发者关注的焦点。其中&#xff0c;数据库作为系统性能的关键瓶颈&#xff0c;在用户请求量急剧增加的情况下&#xff0c;往往难以快速响应用户需求。为了解决这一问题&#xff0c;缓存技术应运而生。MemCa…

移动 APP 设计规范参考

一、界面设计规范 布局原则&#xff1a; 内容优先&#xff1a;以内容为核心进行布局&#xff0c;突出用户需要的信息&#xff0c;简化页面导航&#xff0c;提升屏幕空间利用率.一致性&#xff1a;保持界面元素风格一致&#xff0c;包括颜色、字体、图标等&#xff0c;使用户在…

redis数据结构设计

一. 数据结构简介 要搞清楚redis数据结构&#xff0c;首先需要知道和redis数据相关的三层结构&#xff1a; 五种数据类型 String&#xff08;字符串&#xff09;、List&#xff08;列表&#xff09;、Hash&#xff08;哈希&#xff09;、Set&#xff08;集合&#xff09;和 Sor…

使用npm包的工程如何引入mapboxgl-enhance/maplibre-gl-enhance扩展包

作者&#xff1a;刘大 前言 在使用iClient for MapboxGL/MapLibreGL项目开发中&#xff0c;往往会对接非EPSG:3857坐标系的地图&#xff0c;由于默认不支持&#xff0c;因此需引入mapboxgl-enhance/maplibre-gl-enhance扩展包。 在使用Vue等其他框架&#xff0c;通过npm包下载…