我自己的原文哦~ https://blog.51cto.com/whaosoft/13793156
#Meta Movie Gen
Meta又给OpenAI一记重击,视频生成Movie Gen震撼登场,甚至可以配音、编辑
视频生成领域真是越来越卷且越来越迈向实用性!
在 OpenAI Sora 难产的时候,Meta 首次公开展示了自家的「用于媒体的突破性生成式 AI 研究」:Meta Movie Gen。
Meta 在相应博客中使用了「premiere」一词,也就是初次展示,因此手痒的用户可能还得再等上一段时间。
Meta 表示:「无论是希望在好莱坞大展身手的电影制作人,还是爱好为观众制作视频的创作者,我们相信每个人都应该有机会使用有助于提高创造力的工具。」
根据 Meta 的描述,Movie Gen 的功能包括:文本生成视频和音频、编辑已有视频、图片生视频。并且人类评估表明,Movie Gen 在这些任务上的表现均优于行业内类似模型。
具体的效果如何,我们先来看几个示例。
可以看到,小女孩在奔跑的过程中衣服的褶皱就已经吊打很多视频生成应用了。
prompt:一个女孩正在海滩上奔跑,手里拿着一只风筝。她穿着牛仔短裤和黄色 T 恤,阳光洒在她身上。
在转头、正视前方、微笑的几个动作中,人物面部依然可以保持稳定状态,克服了形变。怪不得 Meta 在博客中还谈到,这是能够用来分享日常生活的可贵技术。
prompt:一名女子正坐在南瓜田的草地上。她围着围巾,手里拿着一个杯子。背景中是一排排南瓜。
生成动物对 Movie Gen 来说也是小菜一碟。动物的毛发、动作都十分逼真。仔细看这只猴子的尾巴,在遮挡后依然能够遵循遮挡前的运动轨迹。背景生成结果也十分贴合 prompt。水面的波动、倒映都栩栩如生。不过水下折射的生成效果看起来还有些进步空间。
prompt:一只红脸白毛的猴子正在天然温泉中沐浴。猴子在玩水面上的一艘微型帆船,这艘帆船由木头制成,配有白色的帆和小舵。温泉周围环绕着郁郁葱葱的绿植,有岩石和树木点缀其间。
视频时间长一些,Movie Gen 也能有稳定的表现。人物大幅度动作的展现也比较逼真。但每一帧定格下来,还会有些瑕疵。不过这是视频生成一贯的难题,Meta 或许会在未来进行改进。
prompt:镜头位于一名男子的身后。男子赤裸上身,腰间系着绿色布料,赤脚站立。他的双手各持一个燃烧的物体,做出大幅度的圆周动作。背景是一片平静的海面,火舞营造出迷人的氛围。
Sora 刚刚问世时,往往还需要 Elevenlabs 这样的音频生成应用来辅助。而 Movie Gen 显然更加便捷,除了视频生成,配备相应的音乐、音效也是拿手好戏。
面对一整个视频的场景,合适的背景音乐能够贯穿全程。不仅如此,音效的适配度也很高。这个瀑布倾泻的水声就十分逼真。
,时长00:10
prompt:雨水倾泻在悬崖和人身上,有背景音乐。
更让人惊讶的是,音效还能够精准地与视频内容匹配。它能够通过视频中的动作节点来把握音效出现的时机,让画面和声音相辅相成,给我们呈现出完整的生成效果。
,时长00:10
prompt:车轮飞速旋转,滑板落在水泥地上发出砰的一声。
无论是视频,还是音频 Movie Gen 看起来都表现优异。
如果 Meta 所言非虚,那么 Movie Gen 也真算得上是目前最先进和最沉浸式的「讲故事模型套件(storytelling suite of models)」。
Meta 表示训练使用的数据集都是公开数据集或已获得授权的数据集。下面将简要介绍各项能力以及背后的技术,更多详情请参阅原论文。
- 论文名称:MovieGen: A Cast of Media Foundation Models
- 论文链接:https://ai.meta.com/static-resource/movie-gen-research-paper
- 更多演示:https://ai.meta.com/research/movie-gen/
Meta 在博客中简单回顾了自己的视频生成之旅。他们的第一波生成式 AI 研究始于 Make-A-Scene 系列模型,这些模型可以生成图像、音频、视频和 3D 动画。
随着扩散模型的出现,他们又基于 Llama 基础模型做出了第二波研究,成功实现了更高质量的图像和视频生成以及图像编辑。
Movie Gen 则是 Meta 的第三波研究。他们将以上所有模态都组合到了一起,并能以前所未有的方式为用户提供进一步的细粒度控制。
下面详细介绍 Movie Gen 的各项能力。
视频生成
给定文本提示词,Movie Gen 会使用一个针对文生图和文生视频任务优化过的联合模型来创建高质量和高清晰度的图像和视频。这个 30B 参数的 Transformer 模型有能力生成长度最多 16 秒帧率为 16 FPS 的视频。Meta 表示还发现这些模型可以推理物体运动、主客体交互和相机运动,并且它们还能学习各种概念的合理运动 —— 这也使它们成为了同类中的 SOTA 模型。
具体流程如下图所示,他们先通过一个时间自动编码器模型(TAE)训练了一个时空压缩的隐空间,然后再基于此训练了一个生成模型。
模型架构上,他们采用了 Transformer,整体位于 Llama 3 的设计空间中。下表展示了其 30B 参数基础模型的各个超参数。值得注意的是,这里的 30B 参数指的是 Transformer 本身的参数量,并不包含文本嵌入模型、TAE 等。
为了训练这个模型,Meta 使用了多达 6144 台 H100 GPU,每一台的热设计功耗为 700W,并且都配备了 80GB 的 HBM3。
下图展示了 Movie Gen Transformer 骨干网络的整体结构以及所使用的模型并行化机制。具体来说包括张量并行化(TP))、序列并行化(SP)、上下文并行化(CP)和全共享式数据并行(FSDP)。
训练流程上,他们采用了一种多阶段训练方法,该方法分为三个阶段:
- 在文生图(T2I)任务上进行初始训练,之后再在文生图和文生视频(T2V)任务上进行联合训练;
- 逐步从低分辨率 256 像素的数据扩展成 768 像素的高分辨率数据;
- 在计算和时间限制上,使用改进过的数据集和已优化的训练方法进行持续训练。
之后自然也会执行微调。
而在推理阶段,Meta 的一个创新思路是首先使用 Llama 3 对用户输入的提示词进行重写,将其扩展成更加详细的版本。实践表明该方法确实有助于提升生成结果的质量。此外,Meta 还在提升推理效率方面引入了一些新思路。
效果上,下表展示了 Movie Gen Video 模型与之前相关研究的胜率情况。注意这里的数值是 Movie Gen 的获胜百分比减去落败百分比,因此可知 Movie Gen 的整体表现胜过之前的模型。
个性化视频
基于上述基础模型,Meta 还开发出了个性化视频功能。用户只需提供人物图像输入和对应的文本提示词,就能生成包含该人物以及文本描述的细节的视频。Meta 表示 Movie Gen 生成的个性化视频在保留人类身份和运动方面做到了 SOTA。
下图展示了个性化 Movie Gen Video 模型(PT2V)的架构和推理流程。
具体来说,首先使用 Movie Gen Video 模型的权重对该模型进行初始化,然后添加额外的可学习参数来基于参考图像实现条件化编辑。
训练过程先是进行预训练(分为身份注入、长视频生成、提升自然度三个阶段),然后执行监督式微调。
结果上看,在经过微调之后,PT2V 模型在身份和人脸一致性上的表现都相当卓越。
下图展示了两个与 ID-Animator 的对比示例:
精确的视频编辑
还是基于同样的基础模型,Meta 也做出了视频编辑功能,并且可以做到非常精确的编辑 —— 可仅操作相关像素!具体来说,给定一段视频和文本提示词,模型可以生成符合要求的经过修改的输出,其中包括一些非常高阶的编辑功能,比如添加、移除和替换元素,修改背景和风格等全局要素。
如果后面实际效果真如 Meta 描述那么好,那么这项功能可能会成为一大利器。
为了做到这一点,Meta 团队同样采用了一种多阶段方法:首先执行单帧编辑,然后进行多帧编辑,之后再整体编辑视频。
为此,他们对前述的视频生成模型进行了一番修改。首先,通过向图块嵌入工具添加额外的输入通道而实现了对输入视频的调节,从而可沿通道维度将隐含的视频输入与有噪声的输出隐视频连接起来,并将连接后的隐视频提供给模型。
此外,按照 Emu Edit 的做法,他们还加入了对特定编辑任务(例如添加对象、更改背景等)的支持。具体来说,该模型会对每个任务学习一个任务嵌入向量。对于给定的任务,模型对相应的任务嵌入应用线性变换,产生四个嵌入,这些嵌入与文本编码器的隐藏表示连接在一起。我们还对任务嵌入应用了第二个线性变换,并将得到的向量添加到时间步嵌入中。另外,为了完全保留模型的视频生成功能,他们将所有新添加的权重设置为零,并基于预训练的文生视频模型初始化剩余的权重。
该方法的效果非常显著,在两个数据集上的人类和自动评估结果基本都优于其它对比方法。顺带一提,Movie Gen Edit Bench 是 Meta 提出的一个新基准,用于评估「下一代视频编辑模型的视频编辑能力」。
音频生成
此外,他们还训练了一个 13B 参数的音频生成模型 Movie Gen Audio。该模型可以基于视频和可选的文本提示词生成长达 45 秒的高质量高保真音频,包括环境声音、音效(Foley)和背景音乐 —— 所有这些都与视频内容同步。
,时长00:10
下面是 Movie Gen Audio 的模型示意图,可以看到其采用了基于流匹配(flow-matching 生成模型和扩散 Transformer(DiT)的模型架构。此外,还添加了一些条件化模块来实现对模型的控制。
此外,他们还提出了一种音频扩展技术,可以为任意长度的视频生成连贯的音频。下面是该技术的示意图。其目标是一次生成 30 秒长度的音频,然后利用该扩展延展至任意长度。
总体而言,他们在音频质量、视频到音频对齐和文本到音频对齐方面实现了 SOTA。
结语
Meta 在架构、训练目标、数据处理方法、评估协议和推理优化等多个技术方面做出了创新突破。下图展示了 Movie Gen 四项能力的人类 A/B 评估对比结果。正净胜率表示人类相较于其他行业模型,更加偏爱 Movie Gen。
Meta 这一次展示自己在视频生成方面的研究成果确实出人意料,这也使其成为了这片越来越拥挤的战场的又一强力竞争者,并且我们也还不清楚 Meta 是否会像发布 Llama 系列模型那样完全免费发布 Movie Gen,让自己在真・OpenAI 之路上继续前进。总之,网友们已经在期待了。
最后,例行惯例,还是得向 OpenAI 问一句:Sora?
#Molmo
号称击败Claude 3.5 Sonnet,媲美GPT-4o,开源多模态模型Molmo挑战Scaling law
Molmo,开源多模态模型正在发力!
虽然大家一直在期待谷歌、OpenAI 等等拥有无限资金储备和顶尖人才的大厂做出新的 Sota 模型。不过,一家默默耕耘的创业公司 Ai2 发布了一款多模态人工智能模型 Molmo。
在下面展示的视频中,我们可以看到 Molmo 就像钢铁侠的「贾维斯」一样万能。想卖自行车,咨询一下 Molmo 的建议,仅靠一张照片,Molmo 就能把自行车的颜色、品牌和二手售价搞清楚,并且帮你写出一句顺口的广告语。
,时长02:15
它也可以从虚拟世界帮你解决现实世界的问题,说一句:「Molmo,帮我买杯星巴克的南瓜拿铁。」剩下的就不用动手了,打开外卖网页、点餐、付款,Molmo 一气呵成。你所要做的,就是坐在家中,静候咖啡送到你的手中。
也尝试了一下他们在线发布的 Demo 模型。相较于宣传视频,其功能还很有限,所以我们让其执行了图像描述任务,可以看到 Molmo 在细节描述和准确度上的表现确实很不错,它甚至能注意到猫背上的小玩具:「玩具看起来像一只绿色的老鼠,鼻子是粉红色的,尾巴是蓬松的,羽毛色彩缤纷。」
但遗憾的是,Molmo 的汉语输出能力非常有限,即使我们明确要求其输出汉语,它也未能办到:
除了 Demo,从数据来看,Molmo 的表现也足够惊艳。在人类测评和一系列测试集中,Molmo 的得分击败了 Claude 3.5 Sonnet、GPT4V 等一众顶尖模型,甚至可以媲美 GPT4o。
不过,Molmo 的体量更小,却能「以小搏大」,性能超越了比它的参数量大十倍的其他模型。据 Ai2 首席执行官 Ali Farhadi 称,Molmo 的体积小到可以在本地运行,它无需 API、无需订阅、更无需成本高昂的液冷 GPU 集群。
更重要的是 Molmo 完全免费且开源,所有的权重、代码、数据和评估流程都即将公布。
部分模型权重、推理代码和一个基于 Molmo-7B-D 模型的公开演示已经可以使用。
体验链接:https://huggingface.co/collections/allenai/molmo-66f379e6fe3b8ef090a8ca19
Ai2 又是如何做到「四两拨千金」的呢?答案在 Ai2 公布的技术报告和论文中,这个秘诀就是:数据。
论文链接:https://molmo.allenai.org/paper.pdf
目前,最先进的多模态模型大多是闭源的,即使有一些开源的模型表现不错,但它们通常依赖于专有模型生成的合成数据。因此,如何从零开始构建高性能 VLM,对于开源社区来说,种种基础知识都很难获得。
各大多模态模型的开源程度
如上图所示,Ai2 的研究团队统计了目前 VLM 的开源程度,除了直接看模型的权重、数据和代码是否公开,他们还考虑了模型是否依赖于其他闭源模型。如果一个模型在训练中用了其他专有模型生成的数据,那它就被标记为「蒸馏」,这意味着它无法完全独立再现。
针对「闭源」的瓶颈,Ai2 使用语音描述收集了一个高细节度的图像描述数据集,这个数据集完全由人工标注,并可以公开访问。
该团队认为提升模型性能的诀窍是使用更少但质量更好的数据。面对数十亿张图像,不可能仅靠人力完成筛选、精细标注和去重的工作,因此,他们没有选择 scaling law,而是精心挑选并注释了 60 万张图像。
数据集链接:https://docs.google.com/forms/u/0/d/e/1FAIpQLSdML1MhNNBDsCHpgWG65Oydg2SjZzVasyqlP08nBrWjZp_c7A/formResponse?pli=1
为了让 Molmo 能处理更多任务,Ai2 还引入了一个多样化的数据混合对模型进一步微调,其中就包括一种独特的二维「指向」数据。
因为现在市面上的多模态模型的工作原理是把图片、声音、文字等多种模态转换成自然语言的表示,而基于「指向」数据的 Molmo 更进一步,它可以用非语言的方式(如指向物体)进行解答。
比如,向 Molmo 提问:「你可以指出这块白板上的哪个模型的训练时间最短吗?」它不仅能用语音准确回答,还能直接用箭头「指向」它是从哪些数据中得到答案的。
Molmo 用红色的波纹标出了自己识别的对象。
要求 Molmo 数图中有多少只狗,它的计数方法是在每只狗的脸上画一个点。如果要求它数狗狗舌头的数量,它会在每只舌头上画一个点。
「指向」让 Molmo 能够在零样本的情况下执行更广泛的任务,同时,无需查看网站的代码,它可以懂得如何浏览页面、提交表单。
这种能力也让 Molmo 更自然地连接现实世界和数字世界,为下一代应用程序提供全新的互动方式。
PixMo:数据质量胜过数量
通常而言,要训练一个大型 VLM,需要数以十亿计的图像 - 文本对数据。而这些数据往往取自网络,因此噪声很高。模型就需要在训练过程中分离信号与噪声。有噪声文本还会导致模型输出出现幻觉。
基于这样的考虑,该团队采用了不同的方法来获取数据。他们将数据质量放在了更重要的位置,结果发现,使用少于 1M 的图像 - 文本对就足以训练出强大的模型 —— 这比许多其它同类方法少了 3 个数量级。
Molmo 系列模型之所以能取得成功,最关键的要素莫过于 PixMo——Molmo 的训练数据。
Pixmo 包含两大类数据:(1) 用于多模式预训练的密集描述数据和 (2) 用于实现各种用户交互的监督式微调数据,包括问答、文档阅读和指向等行为。
该团队表示,在收集这些数据时,主要限制是避免使用已有的 VLM,因为「我们希望从头构建一个高性能 VLM」,而不是蒸馏某个已有的系统(但注意,他们也确实会使用仅语言的 LLM,但并不会把图像输入这些模型)。
在实践中,要让人类来标注大量数据是非常困难的。而且人类编写的图像描述往往仅会提及一些突出的视觉元素,而缺乏细节。如果强制要求最低字数,标注者要么需要花费太长时间,使收集过程成本高昂,要么就会从专有 VLM 复制粘贴响应,这又会违背避免蒸馏模型的目标。
因此,开放研究社区一直在努力,在不依赖专有 VLM 的合成数据的前提下,创建这样的数据集。
该团队提出了一种简单但有效的数据收集方法,可以避免这些问题:让标注者用语音描述图像 60 到 90 秒,而不是要求他们打字。他们让标注者详细描述他们看到的一切,包括空间定位和关系的描述。
从结果上看,该团队发现,通过这种模态切换「技巧」,标注者可以在更短的时间内提供更详细的描述,并且对于每个描述都有对应的录音,可证明未使用 VLM。
总的来说,他们收集了 71.2 万幅图像的详细音频描述,涵盖 50 个高层级主题。
他们的混合微调数据包含了标准的学术数据集以及一些新收集的数据集,这些新数据集也将会公开发布。学术数据集主要用于使模型在基准测试数据上表现良好,而新收集的数据集则能赋予模型大量重要功能,包括在与用户聊天时能够回答关于图像的一般性问题(超出学术基准数据范围)、提升 OCR 相关任务(如读取文档和图表)、精准识别模拟时钟的时间,以及在图像中指向一个或多个视觉元素。
指向功能可为图像中的像素提供自然的解释,从而带来 Molmo 全新且更强大的能力。该团队认为,指向将成为 VLM 和智能体之间重要的交流方式。例如,一个机器人可以查询具有指向功能的 VLM 以获得路径点或要拾取物体的位置,而一个网页智能体可以查询 VLM 以定位需要点击的用户界面元素。这组系列数据集也分为以下六个:
PixMo-Cap:用于预训练 VLM 的数据集,可让其理解图像细节,其中包含 71.2 万张不同图像和大约 130 万个密集图像描述。
PixMo-AskModelAnything:其设计目标是让 AI 模型可回答有关图像的不同问题。其中包含 16.2 个问答对,涉及 7.3 万图像。其中问题由人类标注者编写,答案则来自一个语言模型。
PixMo-Points:其中的图像描述数据是关于图像中物体的位置。该数据集包含 230 万个问题 - 位置点对,涉及 42.8 万张图像。
PixMo-CapQA:包含 21.4 万个问答对,涉及 16.5 万个使用语言模型生成的图像描述。
PixMo-Docs:包含 25.5 万张带有大量文本和图表(表格、文档、图表)的图像,还有语言模型生成的相应代码。另有 230 万对基于生成的代码生成的问答。
PixMo-Clocks:这是一个合成数据集,其中包含 82.6 万张不同款式的模拟时钟图像,以及有关相应时间的问答。
基准评估和大规模人类偏好排名
为了进行全面的评估,该团队既使用了学术基准评测,也执行了人类评估以根据用户偏好对模型进行排名。
从结果上看,学术基准评测结果与人类评估结果高度一致。唯一的例外是 Qwen VL2,其在学术基准上表现很好,但在人类评估中表现相对较差。
该团队总结得到了一些关键结果,并表示「Small is the new big, less is the new more」,详情如下:
- Molmo 系列模型中最高效的是 MolmoE-1B,其基于完全开放的 OLMoE-1B-7B 混合专家 LLM,在学术基准和人类评估上的表现接近 GPT-4V。
- 在学术基准和人类评估基准上,两个 Molmo-7B 模型的表现大概在 GPT-4V 和 GPT-4o 之间,并且在这两个基准上均显著优于近期发布的 Pixtral 12B 模型。
- 表现最好的 Molmo-72B 在学术基准上取得了最高分,但人类评估基准上则仅次于 GPT-4o,居于第二。
- 表现最好的 Molmo-72B 也胜过当前最佳的一些专有系统,包括 Gemini 1.5 Pro 和 Flash 以及 Claude 3.5 Sonnet。
在接受 TechCrunch 的采访时, Ai2 首席执行官 Ali Farhadi 表示,人工智能界有条定律 ——「越大越好」,训练数据越多,模型中的参数就越多,需要的算力也就越多。但发展到一定阶段时,「scaling law」就会遇到瓶颈,根本无法继续扩大模型规模了:没有足够的数据、或者计算成本和时间变得太高,以至于弄巧成拙。你只能利用现有的资源,或者更好的办法是,用更少的资源做更多的事情。
Ai2 首席执行官 Ali Farhadi模型架构
Molmo 的模型架构采用了简单的标准设计,也就是将一个语言模型和一个图像编码器组合起来。其包含 4 个组件:
- 预处理器,其作用是将输入图像转换为一组多尺寸和经过不同裁剪的图像;
- ViT 图像编码器,其作用是将每一张图像都独立映射成一组视觉 token;
- 连接器,其作用是使用 MLP 将视觉 token 投影成语言模型的输入维度,然后汇集视觉 token 以减少其数量;
- 仅解码器 Transformer LLM。
该团队基于这一模板构建了一个模型系列。通过选择不同的视觉编码器和 LLM 可以为其赋予不同的参数。在这些选择基础上,所有模型的后续训练数据和方案都一样。
对于视觉编码器,他们发布的所有模型均使用 OpenAI 的 ViT-L/14 336px CLIP 模型,该模型的效果好且质量稳定。
对于 LLM,他们采用不同的规模,基于不同的开放程度训练了模型:OLMo-7B-1024 的权重和数据完全开放的(使用了 2024 年 10 月的预发布权重,其将于晚些时候公布)、高效的 OLMoE-1B-7B-0924 也是完全开放权重和数据,Qwen2 7B、Qwen2 72B、Mistral 7B、Gemma2 9B 则是仅开放权重。新发布的是该系列的 4 个样本。
他们的训练过程也很简单,首先从已经独立完成预训练的视觉编码器和 LLM 开始,接下来分为两个阶段:
- 多模态预训练,以使用他们新收集的描述数据生成描述;
- 使用上述混合数据集进行监督式微调。
这两个阶段都会对所有参数进行更新,并且过程中不使用 RLHF。
发布计划
该团队首次发布就分量十足,包含一个演示模型、推理代码、一份简要的技术报告和以下模型权重:
- MolmoE-1B,由 1B(活跃参数量)的专家模型构成的混合专家模型,共 7B
- Molmo-7B-O,最开放的 7B 模型
- Molmo-7B-D,演示版本的模型
- Molmo-72B,表现最佳的模型
未来两个月,该团队还将陆续发布以下研究成果:
- 一份详细的技术报告
- PixMo 系列数据集
- 更多模型权重和检查点
- 训练和评估代码
更多研究细节,可访问原博客。
参考链接:https://x.com/reach_vb/status/1838938439267258840https://techcrunch.com/2024/09/25/ai2s-molmo-shows-open-source-can-meet-and-beat-closed-multimodal-models/https://molmo.allenai.org/bloghttps://molmo.allenai.org/paper.pdf
#Chat Edit 3D
像ChatGPT一样,聊聊天就能实现三维场景编辑
论文《Chat Edit 3D: Interactive 3D Scene Editing via Text Prompts》的作者包括来自北京航空航天大学博士生方双康、北京航空航天大学副研究员王玉峰,谷歌AI技术主管Tsai Yi-Hsuan,旷视高级研究员杨弋,北京航空航天大学研究员丁文锐,旷视首席科学家周舒畅,加州大学默塞德分校和谷歌DeepMind研究科学家Yang Ming-Hsuan教授。
- 项目地址:https://sk-fun.fun/CE3D/
- 代码:https://github.com/Fangkang515/CE3D/tree/main
- 论文:https://arxiv.org/abs/2407.06842
- 机构:北航 & 谷歌 & 旷视
1. 一句话概括
本文设计了一种由大语言模型驱动的、可集成任意数量视觉模型的交互式三维场景编辑框架,其文本形式不再受限、编辑能力不再单一。
,时长00:24
(对话式 3D 场景编辑过程示例视频)
2. 引言
现有的文本驱动 3D 场景编辑方法通常局限于固定的文本输入形式和受限的编辑能力。用户需要使用固定形式的文本指令或单一的 diffusion 多模态模型来实现所需的效果。比如 InstructNeRF2NeRF 只能使用 “指令式文本” 且编辑能力受限于 InstructPix2Pix 模型。然而,实际应用中,用户的语言是及其丰富的,用户的编辑需要也是多种多样的,现有方法的设计范式均无法满足用户的诉求。
为了突破这些限制,本文提出了一种全新的 3D 场景编辑新范式 —CE3D。该方法将 3D 场景的编辑变成在 2D 空间上图集的编辑,实现对现有方法的 “降维打击”。降维后可利用大规模语言模型实现灵活且高效的任意模型的集成,大大丰富了文本对话能力和场景编辑能力。
3. 本文方法 CE3D
CE3D,即 Chat-Edit-3D。其核心思想是通过大规模语言模型解析用户的任意文本输入,并自主调用相应的视觉模型来完成 3D 场景的编辑。为了实现任意视觉模型的集成,本文先设计 Hash-Atlas 的映射网络,将对 3D 场景的编辑转换为对 2D 空间内的图集编辑操作,从而实现了 2D 多视角编辑与 3D 场景重建过程的完全解耦,因此,本文将无需固定的 3D 表示形式和 2D 编辑方法。用户想用什么视觉模型就可以用什么视觉模型。
3.1 Hash-Atlas 网络
Hash-Atlas 网络将 3D 场景的不同视图映射到 2D 图集中,从而将 3D 场景编辑过程转移到 2D 空间中执行。为了实现适配已有 2D 多模态编辑模型,映射后的图集需要满足以下条件:(1)防止图集中出现过多的扭曲和倾斜,以维持视觉模型的理解能力;(2)前景和背景图集应大致对齐,以确保精确编辑;(3)需要更快、更精确的映射,以便于高效编辑。为了满足这些条件,本研究设计了一个基于哈希结构的网络,如图所示:
图 1 Hash-Atlas 网络示意图
假设场景中有 T 个视图,点
在第 t 个视图中被函数
映射到两个不同的 UV 坐标:
其中
表示在两个 UV 空间中的坐标。参数
在 0 到 1 之间,表示前景图集中像素值权重。然后使用
预测在 UV 坐标中对应的前景和背景图集的 RGB 值:
其中
采用哈希结构来捕捉图像中的纹理细节,并实现更快的模型训练和推理。在图集中获得像素值
后,可以按如下方式重建场景视图中点P的原始像素:
当图集被编辑后,可以通过上式还原带有编辑效果的 3D 场景的每个视图,而无需重新训练哈希图集网络。为了确保得到的图集更加自然以及避免物体过度倾斜和扭曲,在模型训练的早期阶段,仅使用来自第 0 个视图的
,此时预训练位置损失定义如下:
此损失函数鼓励坐标映射后场景在第 0 个视图中的位置变化最小。此外,
的预训练涉及初步通过 VQA 模型确定场景的前景及其对应的掩码,通过分割模型获得假设前景掩码为
,则
的预训练损失定义如下:
其中 CE 表示交叉熵损失,等式右侧第二项则鼓励
和前景图集的稀疏性,这有助于前景和背景图集内容的明确分离。完成预训练后,可以通过监督图集重建视图来训练整个模型。但直接进行训练会导致背景图集中明显的区域遗漏,影响了后续的编辑任务。为了解决这个问题,本文引入了修补损失。具体而言,利用 ProPainter 模型对遮罩背景进行初步修补,生成一组新的修补视图。假设原始视图中的点 P 在修补视图中对应于
,则重建损失可以表示如下:
其中
表示从场景的原始视图或修补视图中获得的真实值。此外在场景上引入刚性和流动约束:其中
的目的是保持不同点之间的相对空间位置不发生剧烈变化。与此同时
鼓励将不同视图的对应点映射到图集上的同一位置。因此,总损失可以表示如下:
其中
仅在初始训练阶段使用。
完成 3D 场景映射到 2D 图集后,可以在图集上完成场景的编辑,然而直接编辑两个图集再将其映射回场景视图,通常不会得到令人满意的编辑结果,这主要是因为单个图集包含的场景信息不完整,尤其是在稀疏的前景图集中。这一限制使得编辑模型无法获得完整的场景语义,从而无法始终实现可靠的编辑。因此,本研究设计了一种合并 - 拆分策略来编辑图集。在此过程中,首先利用 ChatGPT 的解析功能和 VQA 模型来识别编辑区域,如果这些区域涉及前景内容,则将前景图集覆盖在背景图集上,作为实际的编辑图集。随后使用原始的前景掩码和新的对象掩码将编辑后的图集分离开来。
3.2 基于大语言模型的对话框架: CE3D
图 2 交互式编辑方法 CE3D 示意图
如图所示,CE3D 的基本流程如下:(1)根据用户的文本查询,ChatGPT 解释文本并确定是否需要在此次对话中使用视觉工具;(2)当需要视觉工具时,ChatGPT 将从模型库中调用所需的工具并为它们提供相应的参数;(3)后端进一步查询要调用的图集和其他文件。如果图集不存在,后端首先使用 Hash-Atlas 网络获取它们;(4)执行器执行视觉工具以编辑图集,并将新的状态反馈给 ChatGPT 以便后续操作。编辑后的图集通过 Hash-Atlas 网络映射回 3D 场景视图,以进行后续的场景重建;(5)由于一次对话可能需要多次模型调用,ChatGPT 重复上述过程,直到确定不再需要视觉工具。然后前端将编辑结果和 ChatGPT 的输出回复给用户。
作为一种语言模型,ChatGPT 无法直接访问文本以外的信息。然而,由于编辑过程中涉及的文件众多,不可能将所有文件作为文本输入 ChatGPT。因此,本研究中用格式为 “xxx.scn” 的字符串来表示所涉及的文件。这个字符串是唯一且无意义的,以防止 ChatGPT 编造场景名称。尽管这个场景名称并不是一个真正可读的文件,但前端和后端的进一步处理使得 CE3D 能够有效处理真实文件。前端将编辑结果和 ChatGPT 的输出整理成用户回复,而后端分发编辑过程中涉及的真实场景文件,并管理新场景的名称和文件。
在面对用户输入时,ChatGPT 模拟一个思考过程:“我需要使用视觉工具吗?”→“我需要哪些工具?”→“工具的具体输入应该是什么?”。因此,需要预先向 ChatGPT 注入每个视觉专家的相关信息,以完成这个推理过程。本方法为每个视觉工具标注了四个类别:工具的名称、在什么情况下使用、所需参数和具体输入示例。具体可阅读开源代码。
4. 代码使用展示
在多轮对话编辑案例中,CE3D 能够处理各种类型的编辑请求,例如精准对象移除或替换、基于文本或图像的风格迁移、深度图预测、基于文本和深度图条件的场景再生、人体 Pose 预测、场景超分、场景分割等。此外,它还可以完成与场景相关的视觉问答任务和基本的文本对话。总之,因为能任意扩展视觉模型,因此编辑能力无上限!
功能太多,且能轻松扩展,代码已经开源。
,时长00:34
与其他方法的对比 (视频对比可参看 Project Website):
图 3. 与其它方法对比,CE3D 能实现更丰富的编辑能力
图 4. 与 InstructNeRF2NeRF 相比,CE3D 的多轮对话能力和编辑能力超强!
5. 总结和展望
CE3D 打破现有 3D 场景编辑方法的范式,实现了多模态编辑模型和 3D 场景表示模型间的完全解耦,因此可以兼容任意的 2D 和 3D 的视觉模型。进一步通过大语言模型的逻辑推理和语言理解能力,来实现对用户文本查询的解析和模型的自主调用管理,以实现对话式的 3D 场景编辑框架 CE3D。不过,虽然 CE3D 在 3D 场景编辑方面取得了显著进展,但该技术在处理 360 度场景时会遇到一些挑战,还有进一步研究的空间。
#斯隆奖得主弟子亲身讲述经验
AI博士如何做出有影响力的研究?
写论文?那只是其中的一小步。
在研究生期间,很多人经常会迷茫于如何构建自身的研究。我们应该如何开展研究,才能在已经相当拥挤的人工智能领域有所作为?
太多人认为,长期的项目、适当的代码发布和深思熟虑的基准测试无法产生足够的激励作用 —— 有时候这可能是你快速而内疚地完成的事情,然后又要回去做「真正的」研究。
最近,斯坦福大学 NLP 组在读博士 Omar Khattab 发布了一篇博文,讨论了顶级 AI 学者们有关做有影响力研究的思考。
让我们看看他是怎么说的:
科研的影响力有多种形式,我将只关注通过开源工作(例如模型、系统、框架或基准测试)对人工智能产生的研究影响来衡量。因为我的目标部分是完善自己的想法,记录具体的建议,并收集反馈,所以我会做出较为简洁的陈述。如果你有其他的想法,欢迎在评论区讨论。
首先,以下是指导原则:
- 着眼于项目,而不是论文。
- 选择合适的、具有较大发挥空间的问题,可以「挖坑」。
- 提前思考两步并快速迭代。
- 将你的工作公之于众,并推广你的想法。
- 找到方法激励自己:这是关于发展开源研究的提示。
- 通过新论文继续投资你的项目。
- 第五点「关于发展开源研究的提示」值得单独写一篇更长的文章。我可能会在下一篇文章中写到。
着眼项目
而不是论文
这是一个至关重要的思维,其他的一切都基于此。
刚入门的学生会非常重视发表他们的前几篇论文。这是合理的:这是你学习进行研究、探索初始方向和证明早期进展的方式。但这是一个你最终必须离开的阶段:从长远来看,你的成就和成长不太会取决于单纯的论文数量,而更多地取决于你的影响力和你传达的总体研究脉络。
不幸的是,太多的博士生认为大多数可能产生影响的行为都是「不激励的」。这让我很困惑,直到我意识到他们的意思是这些行为可能会减慢你发表下一篇论文的能力。但你如此迅速地发表下一篇论文的能力并不那么重要。
我建议你不要把你的工作看作一系列孤立的论文,而是问问自己:你将要领导的更大愿景,那么其中子领域或范式是什么?你的工作想要带来什么不同?因此,你将发表单篇论文来探索并建立基准,而更大的愿景应该是你有意迭代的东西。它需要比论文所承载的大得多,而且肯定是尚未完全解决的问题。
要想实现这一点,一种方法是围绕你在开源领域中维护的连贯工件(如模型、系统、框架或基准)构建一些研究论文。这种策略比「进行一些实验,并发布一个转瞬即逝的快速仓库」成本更高,但它会迫使你找到一个具有真正影响的问题,并有助于确保你所做的新研究实际上是连贯且有用的:你不会花费力气引入一个对自己一直在开发和维护的工件无用的小功能或技巧。
选择合适的、具有较大发挥空间的问题
可以「挖坑」
并不是你撰写的每篇论文都是值得无限期投资的。许多论文都是一次性的探索性论文。要找到可以转变为更大项目的方向,所以请使用以下标准。
首先,问题必须是前沿的。你可以用多种方式定义它,但在人工智能领域中行之有效的一种策略是 —— 寻找一个将在 2-3 年内「热门」但尚未成为主流的问题空间。
其次,问题必须具有较大的挖坑潜力,即对许多下游问题的潜在影响。基本上,这些问题的结果可能会使足够多的人受益或感兴趣。研究者和人们关心什么可以帮助他们实现目标,因此你的问题可能是帮助他人构建事物或实现研究或生产目标等东西。你可以应用此过滤器来研究理论基础、系统基础设施、新基准、新模型和许多其他事物。
第三,问题必须留有较大的余地。如果你告诉人们他们的系统可以快 1.5 倍或更有效 5%,这可能没什么意思。在我看来,你需要找到这样的问题:至少在经过多年的努力之后,你有非零的希望让事情变得更快,比如快 20 倍或更有效 30%。当然,你不需要一路走到那一步才算成功,你也不应该等到完全走到那一步后才发表第一篇论文或发布第一件作品。
我不想说得太抽象,还是用 ColBERT 来说明吧。2019 年底,应用 BERT 进行检索的研究非常流行,但这些方法非常昂贵。人们自然会问,我们是否能大幅提高这种方法的效率?是什么让这成为一个好问题呢?
首先,它很前言。我们可以正确地预计,到 2021 年(1.5 年后),许多研究者将寻求基于 BERT 的高效检索架构。其次,它有很大的发展空间。新的 ML 范式往往会这样,因为大多数此类工作一开始都会忽略效率。事实上,最初的方法可能需要 30 秒才能回答一个查询,而现在 30 毫秒就能完成更高质量的检索,速度快了 1000 倍。第三,它有很大的 Fanout。可扩展检索是一个很好的「基础」问题:每个人都需要在检索器之上构建一些东西,但却很少有人愿意去构建它们。
提前思考两步
并快速迭代
既然你已经有了一个好问题,就不要急于选择眼前的低挂果实作为你的方法!在某些时候,至少最终会有很多人在考虑这种「显而易见」的方法。
相反,至少提前两步思考。当这个及时出现的问题最终成为主流时,确定大多数人可能采取的途径。然后,找出这条道路本身的局限性,并着手了解和解决这些局限性。
在实践中会是什么样子呢?让我们重温一下 ColBERT 案例。利用 BERT 构建高效检索器的明显方法是将文档编码成向量。有趣的是,到 2019 年底,只有有限的 IR 工作做到了这一点。例如,该类别中被引用次数最多的工作(DPR)在 2020 年 4 月才发布了第一份预印本。
有鉴于此,你可能会认为,2019 年要做的正确事情是通过 BERT 建立一个伟大的单矢量 IR 模型。与此相反,如果只提前两步思考,就会提出这样的问题:每个人迟早都会建立单矢量方法,那么这种单矢量方法会从根本上卡在哪里呢?事实上,这个问题导致了后期交互范式和广泛使用的模型。
再举一个例子,我们可以使用 DSPy。2022 年 2 月,随着提示功能变得越来越强大,人们显然希望通过提示来进行基于检索的质量保证,而不是像以前那样进行微调。为此,我们自然要建立一种方法。再往前走两步,我们会问:这样的方法会在哪里卡住?归根结底,「先检索后生成」(或称 RAG)方法可能是涉及 LM 的最简单的方法。
出于人们会对它感兴趣的同样原因,他们显然会对以下方面越来越感兴趣:(i) 表达更复杂的模块组合;(ii) 通过对底层 LM 的自动提示或微调,弄清楚应该如何监督或优化由此产生的复杂 pipeline。这就是 DSPy。
这条准则的后半部分是「快速迭代」。这也许是我的导师 Matei Zaharia(斯隆奖得主、Apache Spark 创始人)在我攻读博士学位的第一周给我的第一条研究建议:通过确定一个可以快速迭代并获得反馈(如延迟或验证分数)的问题版本,可以大大提高你解决难题的机会。如果你要提前两步思考问题,这一点就尤为重要,因为这已经足够困难和不确定了。
将你的作品公之于众
让你的想法深入人心
此时,你已经发现了一个好问题,然后不断迭代,直到你发现了一些很酷的东西,并写出了一篇有见地的文章。不要继续写下一篇论文。相反,要专注于将你的工作成果公之于众,并寻求与人们进行真正的互动,不仅仅是关于你的一次论文发布,而是关于你正在积极研究的全局。或者更好的做法是,让人们了解你正在构建和维护的有用的开源工具,它捕捉到了你的关键想法。
常见的第一步是在 arXiv 上发布论文预印本,然后发布「帖子」宣布你的论文发布。这样做时,请确保你的帖子是以具体、充实、易懂的主张开头。这样做的目的不是告诉人们你发布了一篇论文,那并不具有内在价值,目标是以一种直接而又吸引人的方式传达你的关键论点。(是的,我知道这很难,但这是必要的)。
也许更重要的是,整个过程不会在第一次「发布」后结束,发布只是开始。鉴于你现在投入的是项目,而不仅仅是论文,你的想法和科学交流将持续一年之久,远远超过孤立的论文发布。
当我帮助研究生在「推特」上介绍他们的工作时,他们最初发布的文章并没有像希望的那样受到关注,这种情况并不少见。学生们通常会认为这验证了他们对发布研究成果的恐惧,并认为这是另一个信号,表明他们应该继续写下一篇论文。显然,这种想法是不正确的。
大量的个人经验、二手经验和观察结果都表明,在这件事上坚持不懈是非常有意义的(顺便说一句,能坚持的人不多)。也就是说,除了极少数例外情况,好想法的牵引需要你在不同的环境中多次告诉人们关键的东西,并不断改进你的想法和你对想法的传达,直到社区能够随着时间的推移吸收这些想法,或者直到该领域发展到更容易理解这些想法的正确阶段。
汇聚兴奋点
发布开源研究的技巧
让人们对你的研究成果感到兴奋固然是件好事,但通过发布、贡献和发展开源工具,将你的想法传递给相关的下游应用,往往能产生更大的影响。
要做到这一点并不容易:仅仅将代码文件连同 README 上传到 GitHub 是不够的。一个好的资源库将是你项目的「故乡」,比你发表的任何一篇论文都更重要。
优秀的开源研究需要具备两个几乎独立的特质。首先,它必须是好的研究,新颖、及时、范围明确、准确。其次,它需要有明确的下游效用和低摩擦。
这是最重要的部分:人们会因为各种「错误」的原因,总是反复回避(而其他人也会反复使用)你的开放源码软件成果。举例来说,你的研究可能是客观的「最新技术」,但人们十有八九会优先考虑摩擦更小的替代方案。反过来说,对于研究生来说,往往不能抓住人们使用你工具原因的重点,比如,因为他们没有充分利用你最有创意的部分。这并不是什么值得抵制的事情,而是值得理解,必须要为此改进的事情。
基于此,我想列出在研究成果开源方面需要注意的几个里程碑。
里程碑 0:让发布的内容可用
发布一个无人能运行的代码是毫无意义的。在你的研究领域,这些人想复制你的运行结果,也许他们会超越过你的工作并引用你的研究结果。这些人比其他类型的用户更有耐心。尽管如此,你还是会发现,根据代码是否容易修补的情况,它在学术影响力方面也存在巨大差异。
里程碑 1:让发布的内容有用
除了在你的细分领域的人,你应该确保你的发布对想要实际使用该项目来构建其他东西的受众有用。在人工智能研究中,这个里程碑很少会自然而然地到来。你应该分配大量时间来思考人们试图解决的(研究、生产等)问题,而你的人工智能成果可以在这些问题上提供帮助。如果你能正确地做到这一点,那么从项目设计到公开的应用程序接口以及展示的文档 / 示例,都会体现出它的很多作用。
里程碑 2:让发布通俗易懂
这对人工智能研究者来说很难,但我们应该意识到,一个有用的版本,在技术上所有的东西可用且是某种程度上可解释,并不等于你的大多数潜在用户会觉得这个版本通俗易懂,足以让他们投入学习或尝试。
知名 AI 学者 Andrej Karpathy 写过一篇关于这个问题的文章:「你建造东西,然后你需要建造坡道通往它」。Ben Clavie 也撰写了大量有关这方面的文章,他将我们在 ColBERT 上所做的工作加以改进,使其变得更加平易近人了,这在很大程度上证明了这一点。
来源:https://www.youtube.com/watch?v=c3b-JASoPi0
里程碑 3:找出显而易见的替代方案失败的原因,并保持耐心
我们一开始就讨论了提前两步思考的问题。在我看来,这一点至关重要,但也意味着大多数人都不会理解,为什么他们需要采用一种解决方案来解决他们还无法明显观察到的问题。我认为,随着时间的推移,你的工作之一就是要建立一个案例。收集证据,并以易于理解的方式说明为什么显而易见的替代方案(一次只思考一个步骤)会失败。
里程碑 4:了解用户的类型,并利用这一点实现增长
当我创办 ColBERT 和 DSPy 时,我最初寻找的受众是研究者和专业的 ML 工程师。随着时间的推移,我学会了放弃这一点,并明白你可以接触到更多的受众,但他们需要的是不同的东西。在做任何事情之前,都不要间接甚至直接屏蔽不同类别的潜在用户。这种情况比人们想象的要普遍得多。
其次,在寻找用户时,要在两类用户之间寻求平衡。一方面,拥有高级用例的专家级构建者可能需要你投入大量资金,但往往会在研究意义上推动某些用例的发展,这可能会带来回报。另一方面,公众构建者通常不是 ML 专家,但他们经常在公众场合构建并分享他们的学习成果,在大规模增长中占据更大的比例,并会让你对自己最初的假设有更多的了解。两者都是你需要的。
里程碑 5:将兴趣转化为不断壮大的社区
OSS 工作的真正成功在于社区的存在,以及不依赖于你的努力而持续增长。一般来说,一个好的社区应该是有机的,但你需要积极努力帮助它形成,例如欢迎贡献和讨论,并寻找机会将兴趣转化为贡献或某种论坛(例如 Discord 或 GitHub)。可去开发板商城申请测试设备,can,35114网关等
里程碑 6:将兴趣转化为活跃、协作和模块化的下游项目
很有可能,你的 OSS 项目在早期阶段并没有解决最初愿景中的所有问题。一个设计精良的项目通常会有多个模块化部分,可以让你发起研究合作(或其他努力),让新的团队成员不仅能推进项目,还能拥有项目的重要部分,从而更快或更大程度地影响他们的想法,同时大幅改进项目。例如,DSPy 目前由不同的团队分别领导及时优化、编程抽象和强化学习方面的研发工作。ColBERT 的外部应用程序接口、底层检索基础架构和核心建模等组件主要由不同项目中的不同人员负责推进。
来,总结一下。开源研究的采用需要好的研究和好的开源成果。这种平衡很难把握,但一旦把握得当,就会收获颇丰。就我个人而言,我花了很长时间才掌握并内化了这一点。这要归功于我的博士生导师 Chris Potts 和 Matei Zaharia 的反复反馈,以及 Heather Miller 和 Jeremy Howard 的宝贵意见。
评估研究的标准是与先前知识相比的「增量」,但在人们能够有意义地利用「增量」之前,软件本身必须是有效的。要使软件有效,其文档也必须有效:除非你向人们展示,否则人们不会看到他们应该使用软件的所有下游方法。也就是说,直到这些任务可以由一个独立的社区来开发。
说了这么多,本节最重要的技巧就是「发布」,真正发布且经常发布,并从中学习。
发表新论文
继续投入自己的项目
当你读到第五条准则时,很自然会产生这样的疑问:研究生哪里有这么多时间花在开放源码软件上?什么时候才能做真正的研究?
实际的答案是,花在开源上的大部分时间都可以用来进行新的、令人兴奋的研究。这两者并不像表面上看起来那么割裂。为什么这么说呢?
首先,处于这种开放源码软件工作的前沿,你可以极早地凭直觉识别新问题。与其他方式相比,你对问题的理解会更加本能。另外,你所建立的社区通常会对自己的方法原型提供直接反馈,并让你有机会接触到了解问题重要性的优秀合作者。你还可以获得有用的「分发渠道」,确保自己在这一领域发表的每一篇新论文都能得到受众的关注,并巩固现有的平台。
举例来说,「ColBERT」不仅仅是 2020 年初的一篇论文。它现在可能有十篇左右的后续相关论文,投资于改进的训练、更低的内存占用、更快的检索基础架构、更好的领域适应性以及与下游 NLP 任务更好的匹配。同样地,DSPy 也不是一篇论文,而是关于编程摘要、提示优化和下游程序的论文集合。这些论文中有很多都是由不同的优秀作者撰写的,他们的工作都产生了巨大的影响,其中一部分是通过开放源码软件渠道创造了大量的受众。
所以说,一个好的开放源码工具可以创造出模块化的作品,供新的研究者和贡献者探索、拥有和发展。
参考原文:https://github.com/okhat/blog/blob/main/2024.09.impact.md
#从头开始,用Llama 2构建Llama 3.2
Sebastian Raschka最新博客
十天前的 Meta Connect 2024 大会上,开源领域迎来了可在边缘和移动设备上的运行的轻量级模型 Llama 3.2 1B 和 3B。两个版本都是纯文本模型,但也具备多语言文本生成和工具调用能力。Meta 表示,这些模型可让开发者构建个性化的、在设备本地上运行的通用应用 —— 这类应用将具备很强的隐私性,因为数据无需离开设备。
近日,机器学习研究员 Sebastian Raschka 光速发布长篇教程《Converting Llama 2 to Llama 3.2 From Scratch》。
- 博文链接:https://github.com/rasbt/LLMs-from-scratch/blob/main/ch05/07_gpt_to_llama/converting-llama2-to-llama3.ipynb
本文是《 Converting a From-Scratch GPT Architecture to Llama 2》的后续,更新的内容是如何将 Meta 的 Llama 2 架构模型逐步转换为 Llama 3、Llama 3.1 和 Llama 3.2。为了避免不必要的冗长,本文特意将解释部分缩至最短,并将重点放在主代码上。
对文章内容进行了不改变原意的编译:
1 逐步转换 Llama 模型实现
如果你是初次实施 LLM 架构,建议从《Build a Large Language Model From Scratch》(https://github.com/rasbt/LLMs-from-scratch/blob/0972ded5309c25dc5eecc98b62897d677c6c36c4/ch04/01_main-chapter-code/ch04.ipynb)的第 4 章开始,那部分内容将逐步指导你实施原始 GPT 架构。
然后可参考《Converting a From-Scratch GPT Architecture to Llama 2》(https://github.com/rasbt/LLMs-from-scratch/blob/0972ded5309c25dc5eecc98b62897d677c6c36c4/ch05/07_gpt_to_llama/converting-gpt-to-llama2.ipynb),将实现 Llama 特有的组件,如 RMSNorm 层、SiLU 和 SwiGLU 激活、RoPE(旋转位置嵌入)和 SentencePiece tokenizer。
本笔记本采用 Llama 2 架构,并通过以下方式将其转换为 Llama 3 架构:
- 修改旋转嵌入
- 实现分组查询注意力
- 使用定制版的 GPT-4 tokenizer
随后,我们将 Meta 共享的原始 Llama 3 权重加载到架构中:
1.1 复用 Llama 2 的组件
Llama 2 实际上与 Llama 3 非常相似,如上文所述和本文开头的图片所示。
这意味着我们可以使用以下代码从 Llama 2 笔记本中导入多个构建模块:
import os
import sys
import io
import nbformat
import types
def import_from_notebook():
def import_definitions_from_notebook(fullname, names):
current_dir = os.getcwd()
path = os.path.join(current_dir, fullname + ".ipynb")
path = os.path.normpath(path)
# Load the notebook
if not os.path.exists(path):
raise FileNotFoundError(f"Notebook file not found at: {path}")
with io.open(path, "r", encoding="utf-8") as f:
nb = nbformat.read(f, as_versinotallow=4)
# Create a module to store the imported functions and classes
mod = types.ModuleType(fullname)
sys.modules[fullname] = mod
# Go through the notebook cells and only execute function or class definitions
for cell in nb.cells:
if cell.cell_type == "code":
cell_code = cell.source
for name in names:
# Check for function or class definitions
if f"def {name}" in cell_code or f"class {name}" in cell_code:
exec(cell_code, mod.__dict__)
return mod
fullname = "converting-gpt-to-llama2"
names = ["precompute_rope_params", "compute_rope", "SiLU", "FeedForward", "RMSNorm", "MultiHeadAttention"]
return import_definitions_from_notebook(fullname, names)
imported_module = import_from_notebook()
# We need to redefine precompute_rope_params
# precompute_rope_params = getattr(imported_module, "precompute_rope_params", None)
compute_rope = getattr(imported_module, "compute_rope", None)
SiLU = getattr(imported_module, "SiLU", None)
FeedForward = getattr(imported_module, "FeedForward", None)
RMSNorm = getattr(imported_module, "RMSNorm", None)
# MultiHeadAttention only for comparison purposes
MultiHeadAttention = getattr(imported_module, "MultiHeadAttention", None)
1.2 修改后的 RoPE
Llama 3 使用的 RoPE 与 Llama 2 相似,可参阅 RoPE 论文(https://arxiv.org/abs/2104.09864)。
不过,二者 RoPE 设置有一些细微差别。Llama 3 现在支持多达 8192 个 token,是 Llama 2(4096)的两倍。
RoPE 的基础值(见下文公式),从 10000(Llama 2)增加到 50000(Llama 3),公式如下(改编自 RoPE 论文):
这些值是一组预定义的参数,用于确定旋转矩阵中的旋转角度,其中的维数是嵌入空间的维数。
将基数从 10000 增加到 50000,频率(或旋转角度)在各维度上的衰减速度会更慢,这意味着维度越高,角度越大(本质上,这是对频率的解压缩)。
此外,我们还在下面的代码中引入了一个 freq_config 部分,用于调整频率;不过,在 Llama 3(只有 Llama 3.1 和 Llama 3.2)中并不需要它,所以稍后会重新访问这个 freq_config(默认设置为「无」并被忽略)。
import torch
def precompute_rope_params(head_dim, theta_base=10000, context_length=4096, freq_cnotallow=None):
assert head_dim % 2 == 0, "Embedding dimension must be even"
# Compute the inverse frequencies
inv_freq = 1.0 / (theta_base ** (torch.arange(0, head_dim // 2) / (head_dim // 2)))
################################ NEW ###############################################
# Frequency adjustments
if freq_config is not None:
low_freq_wavelen = freq_config["original_context_length"] / freq_config["low_freq_factor"]
high_freq_wavelen = freq_config["original_context_length"] / freq_config["high_freq_factor"]
wavelen = 2 * torch.pi / inv_freq
inv_freq_llama = torch.where(
wavelen > low_freq_wavelen, inv_freq / freq_config["factor"], inv_freq
)
smooth_factor = (freq_config["original_context_length"] / wavelen - freq_config["low_freq_factor"]) / (
freq_config["high_freq_factor"] - freq_config["low_freq_factor"]
)
smoothed_inv_freq = (
(1 - smooth_factor) * (inv_freq / freq_config["factor"]) + smooth_factor * inv_freq
)
is_medium_freq = (wavelen <= low_freq_wavelen) & (wavelen >= high_freq_wavelen)
inv_freq_llama = torch.where(is_medium_freq, smoothed_inv_freq, inv_freq_llama)
inv_freq = inv_freq_llama
####################################################################################
# Generate position indices
positions = torch.arange(context_length)
# Compute the angles
angles = positions[:, None] * inv_freq[None, :] # Shape: (context_length, head_dim // 2)
# Expand angles to match the head_dim
angles = torch.cat([angles, angles], dim=1) # Shape: (context_length, head_dim)
# Precompute sine and cosine
cos = torch.cos(angles)
sin = torch.sin(angles)
return cos, sin
总之,与 Llama 2 相比,Llama 3 的新功能是「上下文长度」和 theta 基底参数:
# Instantiate RoPE parameters
llama_2_context_len = 4096
llama_3_context_len = 8192
llama_2_theta_base = 10_000
llama_3_theta_base = 50_000
在 Llama 2 中,用法与以前相同:
# Settings
batch_size = 2
num_heads = 4
head_dim = 16
# Instantiate RoPE parameters
cos, sin = precompute_rope_params(
head_dim=head_dim,
theta_base=llama_3_theta_base,
context_length=llama_3_context_len
)
# Dummy query and key tensors
torch.manual_seed(123)
queries = torch.randn(batch_size, llama_3_context_len, num_heads, head_dim)
keys = torch.randn(batch_size, llama_3_context_len, num_heads, head_dim)
# Apply rotary position embeddings
queries_rot = compute_rope(queries, cos, sin)
keys_rot = compute_rope(keys, cos, sin)
1.3 分组查询注意力
本节将用一种名为分组查询注意力(GQA)的替代机制来取代多头注意力(MHA)。简而言之,可以将 GQA 视为计算和参数效率更高的 MHA 版本。
在 GQA 中,通过在多个注意力头之间共享来减少键和值投影的数量,每个注意力头仍有其独特的查询,但这些查询关注同一组键和值。
下面是具有 2 个 key-value 组的 GQA 示例:
GQA 的主要思想是减少与键值对相关的唯一查询组的数量,从而在不显著降低建模性能的情况下,减少 MHA 中某些矩阵乘法的大小和参数的数量。
简而言之,GQA 的主要变化是每个查询组都需要重复,以匹配与之相关的头数量,具体实现如下:
import torch.nn as nn
class GroupedQueryAttention(nn.Module):
def __init__(
self, d_in, d_out, context_length, num_heads,
num_kv_groups, # NEW
rope_base=10_000, # NEW
rope_cnotallow=None, # NEW
dtype=None
):
super().__init__()
assert d_out % num_heads == 0, "d_out must be divisible by num_heads"
assert num_heads % num_kv_groups == 0, "num_heads must be divisible by num_kv_groups"
self.d_out = d_out
self.num_heads = num_heads
self.head_dim = d_out // num_heads
############################# NEW #############################
# self.W_key = nn.Linear(d_in, d_out, bias=False, dtype=dtype)
# self.W_value = nn.Linear(d_in, d_out, bias=False, dtype=dtype)
self.W_key = nn.Linear(d_in, num_kv_groups * self.head_dim, bias=False, dtype=dtype)
self.W_value = nn.Linear(d_in, num_kv_groups * self.head_dim, bias=False, dtype=dtype)
self.num_kv_groups = num_kv_groups
self.group_size = num_heads // num_kv_groups
################################################################
self.W_query = nn.Linear(d_in, d_out, bias=False, dtype=dtype)
self.out_proj = nn.Linear(d_out, d_out, bias=False, dtype=dtype)
self.register_buffer("mask", torch.triu(torch.ones(context_length, context_length), diagnotallow=1))
cos, sin = precompute_rope_params(
head_dim=self.head_dim,
theta_base=rope_base, # NEW
freq_cnotallow=rope_config, # NEW
context_length=8192
)
self.register_buffer("cos", cos)
self.register_buffer("sin", sin)
def forward(self, x):
b, num_tokens, d_in = x.shape
queries = self.W_query(x) # Shape: (b, num_tokens, d_out)
keys = self.W_key(x) # Shape: (b, num_tokens, num_kv_groups * head_dim)
values = self.W_value(x) # Shape: (b, num_tokens, num_kv_groups * head_dim)
# Reshape queries, keys, and values
queries = queries.view(b, num_tokens, self.num_heads, self.head_dim)
##################### NEW #####################
# keys = keys.view(b, num_tokens, self.num_heads, self.head_dim)
# values = values.view(b, num_tokens, self.num_heads, self.head_dim)
keys = keys.view(b, num_tokens, self.num_kv_groups, self.head_dim)
values = values.view(b, num_tokens, self.num_kv_groups, self.head_dim)
################################################
# Transpose keys, values, and queries
keys = keys.transpose(1, 2) # Shape: (b, num_heads, num_tokens, head_dim)
values = values.transpose(1, 2) # Shape: (b, num_heads, num_tokens, head_dim)
queries = queries.transpose(1, 2) # Shape: (b, num_query_groups, num_tokens, head_dim)
# Apply RoPE
keys = compute_rope(keys, self.cos, self.sin)
queries = compute_rope(queries, self.cos, self.sin)
##################### NEW #####################
# Expand keys and values to match the number of heads
# Shape: (b, num_heads, num_tokens, head_dim)
keys = keys.repeat_interleave(self.group_size, dim=1) # Shape: (b, num_heads, num_tokens, head_dim)
values = values.repeat_interleave(self.group_size, dim=1) # Shape: (b, num_heads, num_tokens, head_dim)
# For example, before repeat_interleave along dim=1 (query groups):
# [K1, K2]
# After repeat_interleave (each query group is repeated group_size times):
# [K1, K1, K2, K2]
# If we used regular repeat instead of repeat_interleave, we'd get:
# [K1, K2, K1, K2]
################################################
# Compute scaled dot-product attention (aka self-attention) with a causal mask
# Shape: (b, num_heads, num_tokens, num_tokens)
attn_scores = queries @ keys.transpose(2, 3) # Dot product for each head
# Original mask truncated to the number of tokens and converted to boolean
mask_bool = self.mask.bool()[:num_tokens, :num_tokens]
# Use the mask to fill attention scores
attn_scores.masked_fill_(mask_bool, -torch.inf)
attn_weights = torch.softmax(attn_scores / keys.shape[-1]**0.5, dim=-1)
assert keys.shape[-1] == self.head_dim
# Shape: (b, num_tokens, num_heads, head_dim)
context_vec = (attn_weights @ values).transpose(1, 2)
# Combine heads, where self.d_out = self.num_heads * self.head_dim
context_vec = context_vec.reshape(b, num_tokens, self.d_out)
context_vec = self.out_proj(context_vec) # optional projection
return context_vec
参数节省的情况,请参考以下来自 GPT 和 Llama 2 代码的多头注意力示例:
# Settings
batch_size = 1
context_len = 3000
max_context_len = 8192
embed_dim = 4096
num_heads = 32
example_batch = torch.randn((batch_size, context_len, embed_dim))
mha = MultiHeadAttention(
d_in=embed_dim,
d_out=embed_dim,
context_length=max_context_len,
num_heads=num_heads
)
mha(example_batch)
print("W_key:", mha.W_key.weight.shape)
print("W_value:", mha.W_value.weight.shape)
print("W_query:", mha.W_query.weight.shape)
W_key: torch.Size([4096, 4096])
W_value: torch.Size([4096, 4096])
W_query: torch.Size([4096, 4096])
现在,如果改用分组查询注意力,并使用 8 个 kv 组(Llama 3 8B 使用了 8 个 kv 组),可以看到 key 和 value 矩阵的行数减少了 4 倍(因为 32 个注意力头除以 8 个 kv 组就是 4):
gqa = GroupedQueryAttention(
d_in=embed_dim,
d_out=embed_dim,
context_length=max_context_len,
num_heads=num_heads,
num_kv_groups=8,
rope_base=llama_3_theta_base
)
gqa(example_batch)
print("W_key:", gqa.W_key.weight.shape)
print("W_value:", gqa.W_value.weight.shape)
print("W_query:", gqa.W_query.weight.shape)
W_key: torch.Size([1024, 4096])
W_value: torch.Size([1024, 4096])
W_query: torch.Size([4096, 4096])
顺便提一下,为了使分组查询注意力等同于标准的多头注意力,可以将查询组的数量(num_kv_groups)设置为与头的数量(num_heads)相等。
最后,比较一下下面的参数数量:
print("Total number of parameters:")
mha_total_params = sum(p.numel() for p in mha.parameters())
print(f"MHA: {mha_total_params:,}")
gqa_total_params = sum(p.numel() for p in gqa.parameters())
print(f"GQA: {gqa_total_params:,}")
Total number of parameters:
MHA: 67,108,864
GQA: 41,943,040
# Free up memory:
del mha
del gqa
1.4 更新 TransformerBlock 模块
接下来,更新 Transformer 块。在这里,只需将 MultiHeadAttention 与 GroupedQueryAttention 互换,并添加新的 RoPE 设置:
class TransformerBlock(nn.Module):
def __init__(self, cfg):
super().__init__()
self.att = GroupedQueryAttention( # MultiHeadAttention(
d_in=cfg["emb_dim"],
d_out=cfg["emb_dim"],
context_length=cfg["context_length"],
num_heads=cfg["n_heads"],
num_kv_groups=cfg["n_kv_groups"], # NEW
rope_base=cfg["rope_base"], # NEW
rope_cnotallow=cfg["rope_freq"], # NEW
dtype=cfg["dtype"]
)
self.ff = FeedForward(cfg)
self.norm1 = RMSNorm(cfg["emb_dim"], eps=1e-5)
self.norm2 = RMSNorm(cfg["emb_dim"], eps=1e-5)
def forward(self, x):
# Shortcut connection for attention block
shortcut = x
x = self.norm1(x)
x = self.att(x.to(torch.bfloat16)) # Shape [batch_size, num_tokens, emb_size]
x = x + shortcut # Add the original input back
# Shortcut connection for feed-forward block
shortcut = x
x = self.norm2(x)
x = self.ff(x.to(torch.bfloat16))
x = x + shortcut # Add the original input back
return x
1.5 定义模型类
幸运的是,在设置模型类时,我们不需要做太多,只需将名称更新为 Llama3Model
# class Llama2Model(nn.Module):
class Llama3Model(nn.Module):
def __init__(self, cfg):
super().__init__()
self.tok_emb = nn.Embedding(cfg["vocab_size"], cfg["emb_dim"], dtype=cfg["dtype"])
self.trf_blocks = nn.Sequential(
*[TransformerBlock(cfg) for _ in range(cfg["n_layers"])])
self.final_norm = RMSNorm(cfg["emb_dim"], eps=1e-5)
self.out_head = nn.Linear(cfg["emb_dim"], cfg["vocab_size"], bias=False, dtype=cfg["dtype"])
def forward(self, in_idx):
batch_size, seq_len = in_idx.shape
tok_embeds = self.tok_emb(in_idx)
x = tok_embeds
x = self.trf_blocks(x)
x = self.final_norm(x)
logits = self.out_head(x.to(torch.bfloat16))
return logits
2 初始化模型
现在,我们可以定义一个 Llama 3 配置文件(为便于比较,显示的是 Llama 2 配置文件):
LLAMA2_CONFIG_7B = {
"vocab_size": 32_000, # Vocabulary size
"context_length": 4096, # Context length
"emb_dim": 4096, # Embedding dimension
"n_heads": 32, # Number of attention heads
"n_layers": 32, # Number of layers
"hidden_dim": 11_008, # Size of the intermediate dimension in FeedForward
"dtype": torch.bfloat16 # Lower-precision dtype to save memory
}
LLAMA3_CONFIG_8B = {
"vocab_size": 128_256, # NEW: Larger vocabulary size
"context_length": 8192, # NEW: Larger context length
"emb_dim": 4096, # Embedding dimension
"n_heads": 32, # Number of attention heads
"n_layers": 32, # Number of layers
"hidden_dim": 14_336, # NEW: Larger size of the intermediate dimension in FeedForward
"n_kv_groups": 8, # NEW: Key-Value groups for grouped-query attention
"rope_base": 50_000, # NEW: The base in RoPE's "theta" was increased to 50_000
"rope_freq": None, # NEW: Additional configuration for adjusting the RoPE frequencies
"dtype": torch.bfloat16 # Lower-precision dtype to save memory
}
使用这些设置,我们现在可以初始化 Llama 3 8B 模型。
请注意,这需要约 34 GB 内存(作为对比,Llama 2 7B 需要约 26 GB 内存)
model = Llama3Model(LLAMA3_CONFIG_8B)
total_params = sum(p.numel() for p in model.parameters())
print(f"Total number of parameters: {total_params:,}")
Total number of parameters: 8,030,261,248
如上图所示,模型包含 80 亿个参数。此外,我们还可以使用下面的代码计算该模型的内存需求:
def model_memory_size(model, input_dtype=torch.float32):
total_params = 0
total_grads = 0
for param in model.parameters():
# Calculate total number of elements per parameter
param_size = param.numel()
total_params += param_size
# Check if gradients are stored for this parameter
if param.requires_grad:
total_grads += param_size
# Calculate buffer size (non-parameters that require memory)
total_buffers = sum(buf.numel() for buf in model.buffers())
# Size in bytes = (Number of elements) * (Size of each element in bytes)
# We assume parameters and gradients are stored in the same type as input dtype
element_size = torch.tensor(0, dtype=input_dtype).element_size()
total_memory_bytes = (total_params + total_grads + total_buffers) * element_size
# Convert bytes to gigabytes
total_memory_gb = total_memory_bytes / (1024**3)
return total_memory_gb
print(f"float32 (PyTorch default): {model_memory_size(model, input_dtype=torch.float32):.2f} GB")
print(f"bfloat16: {model_memory_size(model, input_dtype=torch.bfloat16):.2f} GB")
float32 (PyTorch default): 68.08 GB
bfloat16: 34.04 GB
最后,如果适用,我们还可以将模型转移到 NVIDIA 或 Apple Silicon GPU 上:
if torch.cuda.is_available():
device = torch.device("cuda")
elif torch.backends.mps.is_available():
device = torch.device("mps")
else:
device = torch.device("cpu")
model.to(device);
3 加载 tokenizer
在本节中,我们将为模型加载 tokenizer。
Llama 2 使用了谷歌的 SentencePiece tokenizer ,而不是 OpenAI 基于 Tiktoken 库的 BPE tokenizer 。然而,Llama 3 恢复使用 Tiktoken 的 BPE tokenizer;具体来说,它使用的是具有扩展词汇的 GPT-4 tokenizer。我们可以在 Meta AI 的官方 Llama 3 存储库中找到最初的 Tiktoken 适配程序。
下面重写了 tokenizer 的代码,使其更易读,更适合本笔记本使用(但表现应该是相似的):
import os
from pathlib import Path
import tiktoken
from tiktoken.load import load_tiktoken_bpe
class Tokenizer:
def __init__(self, model_path):
assert os.path.isfile(model_path), f"Model file {model_path} not found"
mergeable_ranks = load_tiktoken_bpe(model_path)
num_base_tokens = len(mergeable_ranks)
self.special_tokens = {
"<|begin_of_text|>": 128000,
"<|end_of_text|>": 128001,
"<|start_header_id|>": 128006,
"<|end_header_id|>": 128007,
"<|eot_id|>": 128009,
}
self.special_tokens.update({
f"<|reserved_{i}|>": 128002 + i for i in range(256) if (128002 + i) not in self.special_tokens.values()
})
self.model = tiktoken.Encoding(
name=Path(model_path).name,
pat_str=r"(?i:'s|'t|'re|'ve|'m|'ll|'d)|[^\r\n\p{L}\p{N}]?\p{L}+|\p{N}{1,3}| ?[^\s\p{L}\p{N}]+[\r\n]*|\s*[\r\n]+|\s+(?!\S)|\s+",
mergeable_ranks=mergeable_ranks,
special_tokens=self.special_tokens
)
def encode(self, text, bos=False, eos=False, allowed_special=set(), disallowed_special=()):
if bos:
tokens = [self.special_tokens["<|begin_of_text|>"]]
else:
tokens = []
tokens += self.model.encode(text, allowed_special=allowed_special, disallowed_special=disallowed_special)
if eos:
tokens.append(self.special_tokens["<|end_of_text|>"])
return tokens
def decode(self, tokens):
return self.model.decode(tokens)
Meta AI 在 Hugging Face Hub 上共享了 Llama 3 模型的原始权重和 tokenizer 词库。
我们将首先从 Hub 下载 tokenizer 词库,并将其加载到上述代码中。请注意,Meta AI 要求你在下载文件前接受 Llama 3 许可条款;为此必须创建一个 Hugging Face Hub 账户,并访问 meta-llama/Meta-Llama-3-8B 存储库以接受条款。
接下来,需要创建一个访问 token;要生成一个具有「读取」权限的访问 token,请点击右上角的个人资料图片,然后点击「设置」。
然后,创建并复制访问 token,以便复制并粘贴到下一个代码单元中:
from huggingface_hub import login
import json
with open("config.json", "r") as config_file:
config = json.load(config_file)
access_token = config["HF_ACCESS_TOKEN"]
login(token=access_token)
The token has not been saved to the git credentials helper. Pass `add_to_git_credential=True` in this function directly or `--add-to-git-credential` if using via `huggingface-cli` if you want to set the git credential as well.
Token is valid (permission: read).
Your token has been saved to /root/.cache/huggingface/token
Login successful
通过访问 token 登录(这是验证我们是否接受 Llama 3 许可条款所必需的)后,就可以下载 tokenizer 词库了:
from huggingface_hub import hf_hub_download
tokenizer_file_path = hf_hub_download(
repo_id="meta-llama/Meta-Llama-3-8B",
filename="original/tokenizer.model",
local_dir="llama3-files"
)
请注意,在使用 Llama 3 文件时,我们可能需要 blobfile 软件包,它用于处理存储在云存储解决方案(如 Google Cloud Storage (GCS)、Azure Blob Storage 或 Amazon S3)中的数据集或模型。
可以通过取消注释并执行下面的 pip 命令来安装此依赖包:
# pip install blobfile
tokenizer = Tokenizer(tokenizer_file_path)
现在,我们可以使用生成函数让 Llama 3 模型生成新文本:
from previous_chapters import generate, text_to_token_ids, token_ids_to_text
torch.manual_seed(123)
token_ids = generate(
model=model,
idx=text_to_token_ids("Every effort", tokenizer).to(device),
max_new_tokens=30,
context_size=LLAMA3_CONFIG_8B["context_length"],
top_k=1,
temperature=0.
)
print("Output text:\n", token_ids_to_text(token_ids, tokenizer))
Output text:
Every effort_dead aeros Ingredients başında.extension clangmissions.esp 사진 Ek Pars til DoctorsDaoеньostivan normal Ekized � Ekized � Ek rdr tık%,orgen>',
当然,正如我们在上面看到的,这段文字是毫无意义的,因为我们还没有训练过 Llama 3 模型。在下一节中,我们将从 Meta AI 中加载预训练的权重,而不是自己训练模型,因为这将花费数万至数十万美元。
4 加载预训练权重
我们将加载下面的「meta-llama/Meta-Llama-3-8B 」base 模型,它是微调前的简单文本补全模型。
或者,你也可以加载经过指令微调和对齐的「meta-llama/Meta-Llama-3-8B-Instruct」模型,方法是相应修改下一个代码单元中的字符串。加起来,权重文件大约有 16 GB 大。
from safetensors.torch import load_file
combined_weights = {}
for i in range(1, 5):
weights_file = hf_hub_download(
repo_id="meta-llama/Meta-Llama-3-8B",
filename=f"model-0000{i}-of-00004.safetensors",
local_dir="llama3-files"
)
current_weights = load_file(weights_file)
combined_weights.update(current_weights)
model-00001-of-00004.safetensors: 0%| | 0.00/4.98G [00:00<?, ?B/s]
model-00002-of-00004.safetensors: 0%| | 0.00/5.00G [00:00<?, ?B/s]
model-00003-of-00004.safetensors: 0%| | 0.00/4.92G [00:00<?, ?B/s]
model-00004-of-00004.safetensors: 0%| | 0.00/1.17G [00:00<?, ?B/s]
权重包含以下张量(为简单起见,只显示前 15 个张量):
list(combined_weights.keys())[:15]
['model.embed_tokens.weight',
'model.layers.0.input_layernorm.weight',
'model.layers.0.mlp.down_proj.weight',
'model.layers.0.mlp.gate_proj.weight',
'model.layers.0.mlp.up_proj.weight',
'model.layers.0.post_attention_layernorm.weight',
'model.layers.0.self_attn.k_proj.weight',
'model.layers.0.self_attn.o_proj.weight',
'model.layers.0.self_attn.q_proj.weight',
'model.layers.0.self_attn.v_proj.weight',
'model.layers.1.input_layernorm.weight',
'model.layers.1.mlp.down_proj.weight',
'model.layers.1.mlp.gate_proj.weight',
'model.layers.1.mlp.up_proj.weight',
'model.layers.1.post_attention_layernorm.weight']
下面的函数仿照《Build a Large Language Model From Scratch》第 5 章(https://github.com/rasbt/LLMs-from-scratch/blob/0972ded5309c25dc5eecc98b62897d677c6c36c4/ch05/01_main-chapter-code/ch05.ipynb)中的 load_weights_into_gpt 函数,将预训练好的权重加载到 Llama 3 模型中:
def assign(left, right, tensor_name="unknown"):
if left.shape != right.shape:
raise ValueError(f"Shape mismatch in tensor '{tensor_name}'. Left: {left.shape}, Right: {right.shape}")
if isinstance(right, torch.Tensor):
return torch.nn.Parameter(right.clone().detach())
else:
return torch.nn.Parameter(torch.tensor(right))
def load_weights_into_llama(model, param_config, params):
model.tok_emb.weight = assign(model.tok_emb.weight, params["model.embed_tokens.weight"], "model.embed_tokens.weight")
for l in range(param_config["n_layers"]):
# Load attention weights
model.trf_blocks[l].att.W_query.weight = assign(
model.trf_blocks[l].att.W_query.weight,
params[f"model.layers.{l}.self_attn.q_proj.weight"],
f"model.layers.{l}.self_attn.q_proj.weight"
)
model.trf_blocks[l].att.W_key.weight = assign(
model.trf_blocks[l].att.W_key.weight,
params[f"model.layers.{l}.self_attn.k_proj.weight"],
f"model.layers.{l}.self_attn.k_proj.weight"
)
model.trf_blocks[l].att.W_value.weight = assign(
model.trf_blocks[l].att.W_value.weight,
params[f"model.layers.{l}.self_attn.v_proj.weight"],
f"model.layers.{l}.self_attn.v_proj.weight"
)
model.trf_blocks[l].att.out_proj.weight = assign(
model.trf_blocks[l].att.out_proj.weight,
params[f"model.layers.{l}.self_attn.o_proj.weight"],
f"model.layers.{l}.self_attn.o_proj.weight"
)
model.trf_blocks[l].norm1.weight = assign(
model.trf_blocks[l].norm1.weight,
params[f"model.layers.{l}.input_layernorm.weight"],
f"model.layers.{l}.input_layernorm.weight"
)
# Load FeedForward weights
model.trf_blocks[l].ff.fc1.weight = assign(
model.trf_blocks[l].ff.fc1.weight,
params[f"model.layers.{l}.mlp.gate_proj.weight"],
f"model.layers.{l}.mlp.gate_proj.weight"
)
model.trf_blocks[l].ff.fc2.weight = assign(
model.trf_blocks[l].ff.fc2.weight,
params[f"model.layers.{l}.mlp.up_proj.weight"],
f"model.layers.{l}.mlp.up_proj.weight"
)
model.trf_blocks[l].ff.fc3.weight = assign(
model.trf_blocks[l].ff.fc3.weight,
params[f"model.layers.{l}.mlp.down_proj.weight"],
f"model.layers.{l}.mlp.down_proj.weight"
)
model.trf_blocks[l].norm2.weight = assign(
model.trf_blocks[l].norm2.weight,
params[f"model.layers.{l}.post_attention_layernorm.weight"],
f"model.layers.{l}.post_attention_layernorm.weight"
)
# Load output layer weights
model.final_norm.weight = assign(model.final_norm.weight, params["model.norm.weight"], "model.norm.weight")
if "lm_head.weight" in params.keys():
model.out_head.weight = assign(model.out_head.weight, params["lm_head.weight"], "lm_head.weight")
else:
model.out_head.weight = assign(model.out_head.weight, params["model.embed_tokens.weight"], "model.embed_tokens.weight")
print("Model uses weight tying.")
load_weights_into_llama(model, LLAMA3_CONFIG_8B, combined_weights)
model.to(device);
del combined_weights # free up memory
接下来,我们就可以使用该模型生成文本了:
torch.manual_seed(123)
token_ids = generate(
model=model,
idx=text_to_token_ids("Every effort", tokenizer).to(device),
max_new_tokens=25,
context_size=LLAMA3_CONFIG_8B["context_length"],
top_k=1,
temperature=0.
)
print("Output text:\n", token_ids_to_text(token_ids, tokenizer))
Output text:
Every effort has been made to trace copyright holders and to obtain their permission for the use of copyright material. The publisher apologizes for any
5 使用指令微调模型
上面我们使用的是经过预训练的基础模型,如果你想使用一个能够遵循指令的模型,请使用「meta-llama/Llama-3-8b-Instruct」模型,如下所示:
# to free up memory
import gc
del model
gc.collect() # Run Python garbage collector
if torch.cuda.is_available():
torch.cuda.empty_cache()
combined_weights = {}
for i in range(1, 5):
weights_file = hf_hub_download(
repo_id="meta-llama/Meta-Llama-3-8B-Instruct",
filename=f"model-0000{i}-of-00004.safetensors",
local_dir="llama3-files"
)
current_weights = load_file(weights_file)
combined_weights.update(current_weights)
model = Llama3Model(LLAMA3_CONFIG_8B)
load_weights_into_llama(model, LLAMA3_CONFIG_8B, combined_weights)
model.to(device)
del combined_weights # free up memory
model-00001-of-00004.safetensors: 0%| | 0.00/4.98G [00:00<?, ?B/s]
model-00002-of-00004.safetensors: 0%| | 0.00/5.00G [00:00<?, ?B/s]
model-00003-of-00004.safetensors: 0%| | 0.00/4.92G [00:00<?, ?B/s]
model-00004-of-00004.safetensors: 0%| | 0.00/1.17G [00:00<?, ?B/s]
请注意,Llama 3 模型最好与微调时使用的正确提示模板一起使用。
下面是一个基于 Meta AI 的 Llama 3 专用 ChatFormat 代码的 tokenizer wrapper 类,用于构建提示模板:
class ChatFormat:
def __init__(self, tokenizer):
self.tokenizer = tokenizer
def encode_header(self, message):
tokens = []
tokens.append(self.tokenizer.special_tokens["<|start_header_id|>"])
tokens.extend(self.tokenizer.encode(message["role"], bos=False, eos=False))
tokens.append(self.tokenizer.special_tokens["<|end_header_id|>"])
tokens.extend(self.tokenizer.encode("\n\n", bos=False, eos=False))
return tokens
def encode(self, text):
message = {
"role": "user",
"content": text
}
tokens = self.encode_header(message)
tokens.extend(
self.tokenizer.encode(message["content"].strip(), bos=False, eos=False)
)
tokens.append(self.tokenizer.special_tokens["<|eot_id|>"])
return tokens
def decode(self, token_ids):
return self.tokenizer.decode(token_ids)
chat_tokenizer = ChatFormat(tokenizer)
用法如下:
token_ids = chat_tokenizer.encode("Hello World!")
print(token_ids)
[128006, 882, 128007, 271, 9906, 4435, 0, 128009]
tokenizer.decode(token_ids)
'<|start_header_id|>user<|end_header_id|>\n\nHello World!<|eot_id|>'
现在,让我们来看看 Llama 3 教学模式的实际应用:
import re
torch.manual_seed(123)
token_ids = generate(
model=model,
idx=text_to_token_ids("What do llamas eat?", chat_tokenizer).to(device),
max_new_tokens=150,
context_size=LLAMA3_CONFIG_8B["context_length"],
top_k=1,
temperature=0.
)
output_text = token_ids_to_text(token_ids, tokenizer)
def clean_text(text, header_end="assistant<|end_header_id|>\n\n"):
# Find the index of the first occurrence of "<|end_header_id|>"
index = text.find(header_end)
if index != -1:
# Return the substring starting after "<|end_header_id|>"
return text[index + len(header_end):].strip() # Strip removes leading/trailing whitespace
else:
# If the token is not found, return the original text
return text
print("Output text:\n", clean_text(output_text))
Output text:
Llamas are herbivores, which means they primarily eat plants and plant-based foods. Here are some of the things llamas like to eat:
1. Grass: Llamas love to graze on grass, especially in the spring and summer months.
2. Hay: Hay is a staple in a llama's diet. They like to eat timothy hay, alfalfa hay, and other types of hay.
3. Grains: Llamas may also be fed grains like oats, barley, and corn. However, grains should not make up more than 10% of a llama's diet.
4. Fruits and vegetables: Llamas may enjoy fruits and vegetables as treats, such as apples,
Llama 3.1 8B
在 Llama 3 发布几个月后,Meta AI 又推出了 Llama 3.1 模型套件(详见 Llama 3.1 官方介绍)。
方便的是,我们可以重复使用之前的 Llama 3 代码来实现 Llama 3.1 8B:
结构完全相同,唯一的变化是重新调整了 RoPE 频率,如下配置文件所示:
LLAMA3_CONFIG_8B = {
"vocab_size": 128_256, # Vocabulary size
"context_length": 8192, # Context length
"emb_dim": 4096, # Embedding dimension
"n_heads": 32, # Number of attention heads
"n_layers": 32, # Number of layers
"hidden_dim": 14_336, # Size of the intermediate dimension in FeedForward
"n_kv_groups": 8, # Key-Value groups for grouped-query attention
"rope_base": 50_000, # The base in RoPE's "theta"
"rope_freq": None, # Additional configuration for adjusting the RoPE frequencies
"dtype": torch.bfloat16 # Lower-precision dtype to save memory
}
LLAMA31_CONFIG_8B = {
"vocab_size": 128_256, # Vocabulary size
"context_length": 8192, # Context length
"emb_dim": 4096, # Embedding dimension
"n_heads": 32, # Number of attention heads
"n_layers": 32, # Number of layers
"hidden_dim": 14_336, # Size of the intermediate dimension in FeedForward
"n_kv_groups": 8, # Key-Value groups for grouped-query attention
"rope_base": 50_000, # The base in RoPE's "theta"
"dtype": torch.bfloat16, # Lower-precision dtype to save memory
"rope_freq": { # NEW: RoPE frequency scaling
"factor": 8.0,
"low_freq_factor": 1.0,
"high_freq_factor": 4.0,
"original_context_length": 8192,
}
}
正如我们之前在代码中看到的,RoPE 方法使用正弦函数(正弦和余弦)将位置信息直接嵌入注意力机制中。
在 Llama 3.1 中,通过附加配置,我们对反向频率计算进行了额外调整。这些调整会影响不同频率成分对位置嵌入的贡献。
让我们在实践中试试 Llama 3.1 模型;首先,我们清除旧模型,以释放一些 GPU 内存:
# free up memory
del model
gc.collect() # Run Python garbage collector
if torch.cuda.is_available():
torch.cuda.empty_cache()
接下来,我们下载 tokenizer。
请注意,由于 Llama 3.1 系列与 Llama 3 系列不同,、必须访问 meta-llama/Llama-3.1-8Brepository,并确认许可条款,这样 Hugging Face 访问 token 才能在下载时起作用。
简单起见,我们在下面只加载 base 模型,但也有一个经过指令微调的版本,你可以将「meta-llama/Llama-3.1-8B」替换为「meta-llama/Llama-3.1-8B-Instruct」。
tokenizer_file_path = hf_hub_download(
repo_id="meta-llama/Llama-3.1-8B",
filename="original/tokenizer.model",
local_dir="llama3-files"
)
tokenizer = Tokenizer(tokenizer_file_path)
model = Llama3Model(LLAMA31_CONFIG_8B)
total_params = sum(p.numel() for p in model.parameters())
print(f"Total number of parameters: {total_params:,}")
Total number of parameters: 8,030,261,248
combined_weights = {}
for i in range(1, 5):
weights_file = hf_hub_download(
repo_id="meta-llama/Llama-3.1-8B",
filename=f"model-0000{i}-of-00004.safetensors",
local_dir="llama3-files"
)
current_weights = load_file(weights_file)
combined_weights.update(current_weights)
load_weights_into_llama(model, LLAMA31_CONFIG_8B, combined_weights)
model.to(device);
model-00001-of-00004.safetensors: 0%| | 0.00/4.98G [00:00<?, ?B/s]
model-00002-of-00004.safetensors: 0%| | 0.00/5.00G [00:00<?, ?B/s]
model-00003-of-00004.safetensors: 0%| | 0.00/4.92G [00:00<?, ?B/s]
model-00004-of-00004.safetensors: 0%| | 0.00/1.17G [00:00<?, ?B/s]
torch.manual_seed(123)
token_ids = generate(
model=model,
idx=text_to_token_ids("Every effort", tokenizer).to(device),
max_new_tokens=25,
context_size=LLAMA31_CONFIG_8B["context_length"],
top_k=1,
temperature=0.
)
print("Output text:\n", token_ids_to_text(token_ids, tokenizer))
Output text:
Every effort has been made to trace copyright holders and to obtain their permission for the use of copyright material. The publisher apologizes for any
Llama 3.2 1B
截至本文撰写之时,Meta AI 的最新模型是此处公布的 Llama 3.2 模型。
Llama 3.2 文本模型的代码与 Llama 3.1 相似,只是缩小了模型的大小(有 1B 和 3B 版本)。
另一个效率上的调整是,他们又增加了权重绑定(GPT-2 架构中最初使用的概念);在这里,他们在输入(token)嵌入层和输出层中重复使用相同的权重参数值。
Llama 3.2 1B 的模型体积小,甚至可以在许多移动设备上运行,因此非常方便。
Llama 3.1 8B 和 Llama 3.2 1B 在结构上的差异如下图所示:
从上图可以看出,Llama 3.1 8B 和 Llama 3.2 1B 架构的主要区别在于各自的尺寸。
一个小的额外变化是增加了 RoPE rescaling 系数,这反映在下面的配置文件中:
LLAMA31_CONFIG_8B = {
"vocab_size": 128_256, # Vocabulary size
"context_length": 8192, # Context length
"emb_dim": 4096, # Embedding dimension
"n_heads": 32, # Number of attention heads
"n_layers": 32, # Number of layers
"hidden_dim": 14_336, # Size of the intermediate dimension in FeedForward
"n_kv_groups": 8, # Key-Value groups for grouped-query attention
"rope_base": 50_000, # The base in RoPE's "theta"
"dtype": torch.bfloat16, # Lower-precision dtype to save memory
"rope_freq": { # RoPE frequency scaling
"factor": 8.0,
"low_freq_factor": 1.0,
"high_freq_factor": 4.0,
"original_context_length": 8192,
}
}
LLAMA32_CONFIG_1B = {
"vocab_size": 128_256, # Vocabulary size
"context_length": 8192, # Context length
"emb_dim": 2048, # NEW: Half the embedding dimension
"n_heads": 32, # Number of attention heads
"n_layers": 16, # NEW: Half the number of layers
"hidden_dim": 8192, # NEW: Almopst half the size of the intermediate dimension in FeedForward
"n_kv_groups": 8, # Key-Value groups for grouped-query attention
"rope_base": 50_000, # The base in RoPE's "theta"
"dtype": torch.bfloat16, # Lower-precision dtype to save memory
"rope_freq": { # RoPE frequency scaling
"factor": 32.0, # NEW: Adjustment of the rescaling factor
"low_freq_factor": 1.0,
"high_freq_factor": 4.0,
"original_context_length": 8192,
}
}
下面,我们可以重复使用 Llama 3.1 8B 部分的代码来加载 Llama 3.2 1B 模型。
同样,由于 Llama 3.2 系列有别于 Llama 3.1 系列,因此必须访问 meta-llama/Llama-3.2-1B 软件源并确认许可条款。
简单起见,我们只在下面加载基本模型,但也有一个经过指令微调的版本,可以用 「meta-llama/Llama-3.2-1B-Instruct」替换「meta-llama/Llama-3.2-1B」。
# free up memory
del model
gc.collect() # Run Python garbage collector
if torch.cuda.is_available():
torch.cuda.empty_cache()
tokenizer_file_path = hf_hub_download(
repo_id="meta-llama/Llama-3.2-1B",
filename="original/tokenizer.model",
local_dir="llama32-files"
)
tokenizer = Tokenizer(tokenizer_file_path)
model = Llama3Model(LLAMA32_CONFIG_1B)
total_params = sum(p.numel() for p in model.parameters())
print(f"Total number of parameters: {total_params:,}")
# Account for weight tying
total_params_normalized = total_params - model.tok_emb.weight.numel()
print(f"\nTotal number of unique parameters: {total_params_normalized:,}")
Total number of parameters: 1,498,482,688
Total number of unique parameters: 1,235,814,400
weights_file = hf_hub_download(
repo_id="meta-llama/Llama-3.2-1B",
filename=f"model.safetensors",
local_dir="llama32-files"
)
current_weights = load_file(weights_file)
load_weights_into_llama(model, LLAMA32_CONFIG_1B, current_weights)
model.to(device);
Model uses weight tying.
print("Weight tying:", torch.equal(model.tok_emb.weight, model.out_head.weight))
Weight tying: True
torch.manual_seed(123)
token_ids = generate(
model=model,
idx=text_to_token_ids("Every effort", tokenizer).to(device),
max_new_tokens=25,
context_size=LLAMA32_CONFIG_1B["context_length"],
top_k=1,
temperature=0.
)
print("Output text:\n", token_ids_to_text(token_ids, tokenizer))
Output text:
Every effort is made to ensure that the information on this website is accurate. However, we cannot guarantee that the information is accurate, complete
原文链接:
#MagPy
Python程序到计算图一键转化,详解清华开源深度学习编译器MagPy
张晨,清华大学计算机系高性能所博士生,导师为翟季冬老师,主要研究方向为面向人工智能和量子计算的高性能异构计算系统。在OSDI、SC、ATC、ICS会议上发表一作论文,并获得 ICS21 最佳学生论文。曾获得 SC19, SC20, ISC21 国际超级计算机竞赛冠军。获清华大学本科生特等奖学金、国家奖学金、北京市优秀毕业生、北京市优秀毕业设计等荣誉。
2024 年 7 月,清华大学计算机系 PACMAN 实验室发布开源深度学习编译器 MagPy,可一键编译用户使用 Python 编写的深度学习程序,实现模型的自动加速。
尽管目前存在大量高性能的深度学习编译器,但是这些编译器均以计算图作为输入,需要由用户将编写的 Python 程序手动转化为计算图。为了避免这种不便性,该团队设计了 MagPy,直接面向用户编写的 Python+PyTorch 程序,自动将其转化为适用于深度学习编译器的计算图表示,从而充分发挥深度学习编译器的优化能力,避免用户使用复杂 Python 语法带来的性能下降,为用户带来易用性和效率的双丰收。
该工作同时于系统领域重要国际会议 USENIX ATC’24 发表长文,第一作者清华大学博士生张晨、通讯作者为翟季冬教授。PACMAN 实验室在机器学习系统领域持续深入研究。MagPy 是继 PET、EINNET 等工作后在深度学习编译器上的又一次探索。欲了解更多相关成果可查看翟季冬教授首页:https://pacman.cs.tsinghua.edu.cn/~zjd
- 论文地址:https://www.usenix.org/system/files/atc24-zhang-chen.pdf
- 项目地址:https://github.com/heheda12345/MagPy
研究背景:深度学习计算图提取技术
近年来,深度学习在生物科学、天气预报和推荐系统等多个领域展示了其强大能力。为了简化编程过程,用户倾向于使用 Python 编写深度学习模型,并在需要进行张量操作时调用如 PyTorch 等的张量库。此时,用户程序会在调用张量库时立即执行张量操作,如此不加优化地直接执行程序性能较差。另一方面,为了提升深度学习模型的运行速度,深度学习编译器倾向于使用以算子图的格式表示的深度学习模型作为输入,在计算图上进行图级优化,如图替换和算子融合。当可以获取到模型的计算图时,代表性的深度学习编译器 TorchInductor 和 XLA 可以在 PyTorch 的基础上平均加速模型 1.47 倍和 1.40 倍。
具体结果如图 1 所示,标记为 Fullgraph-Inductor 和 Fullgraph-XLA。然而,实现这种加速的前提是用户手动将程序转换为计算图格式,这对许多模型开发者来说是困难的。尤其是随着深度学习的广泛应用,越来越多的模型是由化学、生物和天文学等领域的非专业程序员开发的。因此,迫切需要一种自动化方法将用户编写的 Python 程序转换为编译器友好的图格式来加速程序,这被称为计算图提取技术。
由于 Python 程序具有极强的动态性,加之用户程序存在行为的不确定性,现有的计算图提取技术在处理较复杂的用户程序时无法取得最优的性能,如图 1 中的 TorchDynamo-Inductor(使用 TorchDynamo 提取计算图,使用 TorchInductor 编译)、 LazyTensor-XLA(使用 LazyTensor 追踪计算图,使用 XLA 编译)所示。
图 1 :深度学习编译器可以显著提升模型运行效率,但现有的图提取技术阻碍了这一点。图中 Eager 表示直接执行 PyTorch 程序,Fullgraph-Inductor 与 Fullgraph-XLA 分别表示 Inductor、XLA 对模型的计算图进行编译后的加速,TorchDynamo-Inductor 与 LazyTensor-XLA 分别表示使用 TorchDynamo 和 LazyTensor 技术从用户 Python 程序中提取计算图再进行编译的性能。
MagPy 的解决方案
MagPy 的核心思想是分析 Python 解释器中的执行状态信息,从而让编译器能够更好的理解用户程序。Python 解释器能够准确支持所有 Python 特性,并在运行时保留了高层次的执行状态信息,如各个变量的类型和值等等。通过有效利用解释器提供的信息,能够更全面地了解程序的行为,从而更好地提取程序计算图。
MagPy 的设计基于以下几点观察:
首先,大多数深度学习程序的动态性是有限的。尽管这些程序是用 Python 编写的,具有数据类型、控制流逻辑和运行时函数调度等潜在的动态特性,但其计算图结构在不同批次间通常保持不变。ParityBench 是一个从 Github 上自动爬取超过 100 颗星的 PyTorch 深度学习程序组成的基准测试集,它的 1421 个程序中,83% 的程序(1191 个)均满足有限动态性的性质。对于这些程序,可以通过在程序执行过程中监控张量操作,较为简便地获取其计算图。根据这个性质,MagPy 将计算图提取问题从分析 “计算图是什么” 简化为分析 “得到的计算图何时会发生变化”。
其次,只有外部值能影响程序行为。利用这一特性,可以更简易地检测出会导致计算图发生变化的因素。这里的 “程序行为” 包括计算图的结构和所有程序副作用(side effect)。只要程序从外部读取的所有值(如输入参数和全局变量)保持不变,且调用的函数的输出结果不具有随机性,程序行为就不会发生变化。因此,MagPy 只需验证所有从外部读取的值都不变,即可保证计算图结构不变。例如,尽管图 2 中的程序使用了许多复杂的 Python 特性,但只要所有从外部读取的值(如 x、dims、self.scale 和 self.dim,标记为粗体)与之前运行一致,计算图就保持不变。MagPy 会首先运行一个 “守卫函数” 对于这些值是否发生变化进行检查(Guards),当检查通过时,MagPy 将会运行一个 “模拟函数”(mock code),用以调用经过深度学习编译器编译的计算图及模拟程序的所有副作用(如示例中的对 x 进行赋值)。
第三,守卫函数和模拟函数都可以通过分析程序执行状态来确定。守卫函数的作用是验证新一次执行的输入状态是否与之前运行匹配,模拟函数的目的是重现之前运行的最终状态。这两个部分仅基于运行时状态,而不是用户程序的逻辑。Python 解释器在解释执行程序的过程中,保留了所有需要的执行状态信息,因此不再需要具体分析 Python 复杂而动态的执行逻辑。守卫函数和模拟函数需要关注的变量包括显式读取或写入外部的值(如 self)以及被它们引用的值(如 self.dim)。因此,MagPy 设计了引用关系图来记录和分析程序行为。
基于上述观察,MagPy 提出了引用关系图(Reference Graph,简写为 RefGraph)来记录程序执行期间的程序状态。MagPy 定义了执行状态接口,用于在程序执行期间收集运行时信息,并使用基于标注的图更新规则来维护 RefGraph。MagPy 还提出了在 RefGraph 上进行遍历生成守卫函数和模拟函数的算法。具体细节可以阅读论文。
实验
MagPy 具有极高的 Python 语言特性覆盖率,其在对 ParityBench 中 1191 个静态的真实用户程序进行测试时,成功将 93.40% 的程序转化为完整的操作符图,大幅高于现有工作 TorchScript(35%)和 TorchDynamo(77.2%)
由于更完整的计算图导出,MagPy 在端到端测试中,也表现出具有竞争力的性能。下图展示了对于图像处理、自然语言处理等典型深度学习模型,MagPy 取得的加速。MagPy 可取得最高 2.88 倍,平均 1.55 倍的提升。实验在单张 A100 上进行,X-Y 表示使用图导出技术 X 和图层编译器 Y。
#Mirage
告别CUDA无需Triton!Mirage零门槛生成PyTorch算子,人均GPU编程大师?
近日,来自 CMU 的 Catalyst Group 团队发布了一款 PyTorch 算子编译器 Mirage,用户无需编写任何 CUDA 和 Triton 代码就可以自动生成 GPU 内核,并取得更佳的性能。
随着 GPU 加速器的不断发展以及以大语言模型为代表的生成式 AI 应用的不断推广,通过开发高性能 GPU 内核来优化 PyTorch 程序的计算效率变得越来越重要。目前,这项任务主要由专门的 GPU 专家来完成。在 NVIDIA CUDA 或 AMD ROCm 中编写高性能 GPU 内核需要高水平的 GPU 专业知识和大量的工程开发经验。目前的机器学习编译器(如 TVM、Triton 和 Mojo)提供了一些高级编程接口,以简化 GPU 编程,使用户可以使用 Python 而非 CUDA 或 ROCm 来实现 GPU 内核。
然而,这些语言仍然依赖用户自行设计 GPU 优化技术以达到更高的性能。例如,在 Triton 中实现一个 FlashAttention 内核大约需要 700 行 Python 代码(在 CUDA 中需要大约 7,000 行 C++ 代码)。在这些程序中,用户需要手动划分线程块之间的工作负载,组织每个线程块内的计算,并管理它们之间的同步与通信。
用 Triton 实现的 FlashAttention 算子
能否在不使用 CUDA/Triton 编程的情况下就获得高效的 GPU 内核呢?基于这一动机,来自卡内基梅隆大学的 Catalyst Group 团队发布了 Mirage 项目,基于 SuperOptimization 技术(https://arxiv.org/abs/2405.05751),为 PyTorch 自动生成高效 GPU 内核算子。例如,对于一个 FlashAttention 算子,用户只需编写几行 Python 代码来描述注意力(Attention)的计算过程而无需了解 GPU 编程细节,如下所示:
# Use Mirage to generate GPU kernels for attention
import mirage as mi
graph = mi.new_kernel_graph ()
Q = graph.new_input (dims=(64, 1, 128), dtype=mi.float16)
K = graph.new_input (dims=(64, 128, 4096), dtype=mi.float16)
V = graph.new_input (dims=(64, 4096, 128), dtype=mi.float16)
A = graph.matmul (Q, K)
S = graph.softmax (A)
O = graph.matmul (S, V)
optimized_graph = graph.superoptimize ()
Mirage 会自动搜索可能的 Attention GPU 内核实现,搜索空间不仅包括现有的手动设计的注意力内核(如 FlashAttention 和 FlashDecoding),还包括在某些场景中比目前的手写版本快多达 3.5 倍的其他实现。Mirage 生成的 GPU 内核可以直接在 PyTorch 张量上操作,并可以在 PyTorch 程序中直接调用。
import torch
input_tensors = [
torch.randn (64, 1, 128, dtype=torch.float16, device='cuda:0'),
torch.randn (64, 128, 4096, dtype=torch.float16, device='cuda:0'),
torch.randn (64, 4096, 128, dtype=torch.float16, device='cuda:0')
]
# Launch the Mirage-generated kernel to perform attention
output = optimized_graph (input_tensors)
Why Mirage?
与使用 CUDA/Triton 编程相比,Mirage 提供了一种新的编程范式,包含三个主要优势:
更高的生产力:随着 GPU 架构日新月异,现代 GPU 编程需要持续学习大量的专业知识。Mirage 的目标是提高机器学习系统工程师的生产力 —— 他们只需在 PyTorch 层面描述所需的计算,Mirage 便会自动生成适用于各种 GPU 架构的高性能实现。因此,程序员不再需要手动编写 CUDA/Triton 或特定架构的低级代码。
更好的性能:目前手动设计的 GPU 内核由于无法充分探索和利用各种 GPU 优化技术,往往只能达到次优性能。Mirage 可以自动搜索与输入的 PyTorch 程序功能等价的潜在 GPU 实现,探索并最终发现性能最优的内核。在多个 LLM/GenAI 基准测试中的测试结果显示,Mirage 生成的内核通常比 SOTA 的专家人工编写或编译器生成的替代方案快 1.2 至 2.5 倍。
更强的正确性:手动实现的 CUDA/Triton GPU 内核容易出错,而且 GPU 内核中的错误难以调试和定位,而 Mirage 则利用形式化验证(Formal Verification)技术自动验证生成的 GPU 内核的正确性。
LLaMA-3-8B 和 Chameleon-7B 端到端推理延迟对比(NVIDIA A100,batch size=1,context length=4K),相比于 CUDA/Triton 的实现,Mirage 可以实现 15-20% 的加速
GPU 架构与 Mirage 中的
GPU 计算的内核函数以单程序多数据(SPMD)方式在多个流处理器(SM)上同时运行。GPU 内核(Kernel)借助由线程块(Thread Block)组成的网格结构来组织其计算,每个线程块在单个 SM 上运行。每个块进一步包含多个线程(Thread),以对单独的数据元素进行计算。GPU 还拥有复杂的内存层次结构,以支持这种复杂的处理结构。每个线程都有自己的寄存器文件(Register File),以便快速访问数据。线程块内的所有线程可以访问一个公共的共享内存(Shared Memory),这有助于它们之间高效的数据交换和集体操作。最后,内核内的所有线程可以访问分配给整个 GPU 的大型设备内存(Device Memory)。
GPU 计算架构和编程抽象示意图
Mirage 使用
来描述 GPU 内核,
包含多个层次,代表内核、线程块和线程级别的计算。大体上,Kernel Graph、Thread Block Graph 和 Thread Graph 分别代表整个 GPU、一个流处理器(SM)和一个 CUDA/tensor 核心上的计算。
对
细节感兴趣的读者可以参考:
Mirage 工作流示意图
上图展示了 Mirage 的工作流程:对于输入的 PyTorch 程序,Mirage 的
生成器自动搜索与输入程序功能等价的其他
,搜索空间涵盖了内核、线程块和线程级别的各种 GPU 优化。所有生成的
都被发送到等价性验证器,该验证器自动检查每个
是否与所需程序等价。最后,
转译器将所有经过验证的
转译为 CUDA 内核。最后,Mirage 会从中返回性能最佳的 CUDA 内核。
- 项目成员:Mengdi Wu (CMU), Xinhao Cheng (CMU), Shengyu Liu (PKU), Chuan Shi (PKU), Jianan Ji (CMU), Oded Padon (VMWare), Xupeng Miao (Purdue), Zhihao Jia (CMU)
- 项目地址:https://github.com/mirage-project/mirage
为什么 Mirage 生成的内核更高效?
在多个 LLM/GenAI 基准测试中的测试结果显示,Mirage 生成的内核通常比现有的手写或编译器生成的内核快 1.2 至 2.5 倍。接下来,本文以 LLM 中的 Transformer 架构为例,展示现有系统中缺失的几项 GPU 程序优化技术:
Transformer 架构示意图
Case 1: Normalization + Linear
归一化(Normalization)操作,如 LayerNorm、RMSNorm、GroupNorm 和 BatchNorm,广泛应用于当今的机器学习模型。当前的机器学习编译器通常在独立的内核中启动归一化层,因为归一化涉及到归约和广播,难以与其他计算融合。然而,Mirage 发现,大多数归一化层可以通过进行适当的代数变换,与后续的线性层(如 MatMul)融合。
Normalization + Linear 现有内核 v.s. Mirage 发现的内核
Mirage 发现的自定义内核利用了 RMSNorm 中的除法和 MatMul 中的乘法的可交换性,将除法移到 MatMul 之后。这一变换保持了功能等价性,同时避免了中间张量 Y 的实例化。该内核的性能比单独运行这两个操作快 1.5 到 1.7 倍。
Normalization + Linear 内核性能对比
Case 2: LoRA + Linear
LoRA 广泛用于预训练模型的微调场景,以适配到特定领域和任务。这些 LoRA 适配器通常会被插入到模型的线性层中,引入额外的矩阵乘法。现有系统通常为原始矩阵乘法和 LoRA 中的两个矩阵乘法启动独立的内核,从而导致较高的内核启动开销。
LoRA+Linear 现有内核 v.s. Mirage 发现的内核
如上图所示,Mirage 发现了一个将三个矩阵乘法和随后的加法融合为单个内核的内核。这是通过将计算重组为两个线程块级别的矩阵乘法实现的,利用了以下代数变换:W×X+B×A×X=(W|B)×(X|(A×X)),其中的两个拼接操作不涉及任何计算,而是通过在 GPU 共享内存中更新张量偏移量来完成。Mirage 发现的内核比现有系统中使用的内核快 1.6 倍。
LoRA+Linear 内核性能对比
Case 3: Gated MLP
Gated MLP 层目前在许多 LLM 中使用(如 LLAMA-2、LLAMA-3 及其变体),它的输入张量 X 与两个权重矩阵相乘,输出结果被组合以产生最终结果。Mirage 发现了一个内核,该内核执行两个矩阵乘法、SiLU 激活以及随后的逐元素乘法,从而减少了内核启动开销和对设备内存的访问。
Gated MLP 现有内核 v.s. Mirage 发现的内核
Gated MLP 内核性能对比
Case 4: Attention Variants
如今的大多数 LLM 基于注意力及其变体,虽然现有系统通常提供高度优化的注意力实现,如 FlashAttention、FlashInfer 和 FlexAttention,但支持注意力变体通常需要新的自定义内核。下面用两个例子来展示 Mirage 如何为非常规注意力计算发现自定义 GPU 内核。
Case 4.1: Attention with Query-Key Normalization
许多最近的 LLM 架构(包括 Chameleon、ViT-22B 等)在 LLaMA 架构中引入了 QK-Norm 来缓解训练过程中的数值发散问题。QK-Norm 在注意力之前对 Query 和 Key 向量应用 LayerNorm 层。现有注意力实现中并不支持这些额外的归一化层,并且它们还需要作为独立内核启动。
QK-Norm 注意力现有内核 v.s. Mirage 发现的内核
对于在注意力之前和 / 或之后引入计算的注意力变体,这些计算可以与注意力融合以提高 GPU 性能,而这需要自定义内核。对于带有 QK-Norm 的注意力,Mirage 发现了上述内核来融合计算,从而避免在 GPU 设备内存中实例化中间结果。这个自定义内核还对注意力进行了现有的 GPU 优化,实现了 1.7 至 2.5 倍的性能提升。
QK-Norm 注意力内核性能对比
Case 4.2: Multi-Head Latent Attention
MLA 的现有内核 v.s. Mirage 发现的内核
另一个常用的注意力变体是 MLA(Multi-Head Latent Attention),它将注意力的 KV Cache 压缩为一个向量,以减少存储 KV Cache 的内存开销。这一变化还在注意力之前引入了两个线性层,如下图所示。与 QK-Norm 类似,现有注意力实现中并不支持这些额外的归一化层,同样需要作为独立内核启动,而 Mirage 可以将线性层和注意力融合为一个单独的自定义内核。
长期愿景
Mirage 项目的长期目标是希望能够让未来的 AI 开发者无需学习 CUDA 或者 Triton 等复杂的 GPU 编程语言,只需指定所需的数学操作,就能在 GPU 上轻松实现 AI 模型。通过利用 Mirage 的 SuperOptimization 技术,各种计算任务可以自动转换为高度优化的 GPU 实现。随着 LLM 和其他生成式 AI 应用的飞速发展,在各种实际部署场景都需要高效的 GPU 支持,降低 GPU 编程门槛并提高程序效率也愈发重要。
#Meta版Sora——Movie Gen
Meta版Sora深夜横空出世,小扎放出16秒高清大片!92页论文曝光技术细节,Llama 3架构立功
Meta版Sora,就在刚刚惊艳来袭。Movie Gen可生成1080p、16秒、每秒16帧的高清长视频,还能生成音效、编辑视频、上传图像生成个性化视频。甚至Meta还放出了92页论文,模型架构、训练细节一并公开,干货满满!
毫无预兆地,Meta版Sora——Movie Gen,就在刚刚抢先上线了!
Meta将其称为「迄今最先进的媒体基础模型」。
全新上线的大杀器Movie Gen Video,是一个30B参数的Transformer模型,可以从单个文本提示,生成高质量的高清图像和视频,视频为1080P、16秒、每秒16帧。
,时长00:30
一同推出的还有Movie Gen Audio。这是一个13B参数的Transformer模型。通过视频输入和文本提示,它就可以可控性生成和视频同步的高保真音频,时长最长45秒。
最惊人的是,这次Meta一并连论文都发布了。
论文中,详细介绍了Movie Gen的架构、训练方法和实验结果。
论文地址:https://ai.meta.com/static-resource/movie-gen-research-paper/?utm_source=twitter&utm_medium=organic_social&utm_cnotallow=thread&utm_campaign=moviegen
从论文可以看出,Movie Gen Video沿用了Transformer的设计,尤其借鉴了Llama 3。而研究人员引入的「流匹配」(Flow Matching),让视频在精度和细节表现上,都优于扩散模型。
稍显遗憾的是,这次Meta发的也是「期货」,产品预计明年才正式向公众开放。
不出意外的,围观群众给出亮眼点评:「Meta居然抢着OpenAI之前发布了Sora,呵呵」。
就在昨天,Sora负责人Tim Brooks选择离职,Meta这个时间点放出Movie Gen,也真是够扎心的。
而HuggingFace工程师也直接贴出Meta开源主页,在线催更模型开源。
也有人期待,Meta版Sora的这次发布,或许或激出其他家的下一个王炸级产品。
一键视频生成,赶超Sora
凭借开源Movie Gen,Meta正式进军AI视频领域。
可以说,Movie Gen在编辑、个性化功能方面,站在了一个新阶段。而且,最令人印象深刻的,便是把一张个人照,转换成个性化视频。
小扎在社交平台上以身试法,将自己照片作为输入,Movie Gen为其配上了健身的视频。14
文本生成视频
现在,只要使用简单的文本输入,就能生成自定义的视频了。
从官网放出的Demo可以看出,Meta所言不虚,Movie Gen的确可以说「为沉浸式AI内容」树立了新标准。
更为瞩目的是,Movie Gen可以创建不同宽高比的高清长视频。在业内,这属于首次!
这个「雷声大作,伴随着管弦乐曲」的视频,对于山石地貌和电闪雷鸣的刻画惊人的逼真,配乐更是恢弘激昂。
Thunder cracks loudly, with an orchestral music track.
一个小女孩拿着风筝跑过海滩,仿佛电影中的场景。
戴着粉色太阳镜躺在甜甜圈游泳圈上的树懒,视频中光影和水波都很自然。
在冒着热气的温泉中玩着小木船的白毛红脸猴,无论是热气、水面、猴子毛发还是水中怪石,都看不出破绽。
在海边耍着火圈的男人,视频完全符合prompt的要求,镜头、光影和氛围的刻画,已经达到了大片级画质。
各种超现实的场景,Movie Gen都能完美生成,比如这只毛茸茸的冲浪考拉。
文本编辑视频
而只要使用文本输入,就可以编辑现有视频。
Movie Gen可以支持非常精确的视频编辑,无论是样式、过渡,还是精细编辑。
通过文字输入,就能让小女孩向空中放飞的灯笼,变成一个气泡。
在沙地上跑步的男子,手中可以加上蓝色绒球,周围环境可以换成仙人掌沙漠,甚至可以让男子换上一身恐龙套装。
在观众席上观影的一对男女,可以让他们戴上3D眼镜、背景换成游乐园,甚至加上下雨的特效。
南极冰原上的企鹅可以穿上维多利亚式的衣服,背景可以加上遮阳伞和沙滩床,甚至整幅画面都能变成铅笔素描画。
个性化视频
并且,Movie Gen还有一个Sora没有的亮点——个性化视频!
只要上传我们想要的图像,它就可以由此生成个性化视频,保留人物的身份和动作。
输入这个女孩的照片,给出prompt,就能让她在南瓜地上戴着围巾喝咖啡。
让这名男子化身科学家,穿上实验服开始做实验。
一张照片,就能生成自己和爱犬在露台上的自拍视频。
甚至让自己在西部世界小镇中化身骑马的女牛仔,身后就是落基山脉。一秒走进大片不是梦!
音效和配乐
Movie Gen还可以将视频、文本作为输入,并为视频生成音频。
它可让你创建和扩展视频音效、背景音乐或整个配乐。
比如,下面企鹅戏水的画面中,配上了AI生成的优美的管弦乐曲。10
文本输入:A beautiful orchestral piece that evokes a sense of wonder
AI生成的烟花音效,也是如此地逼真。
文本输入:Whistling sounds, followed by a sharp explosion and loud crackling.
倾泻而下的瀑布和和雨水,站在高处遥望远方顿感壮观。
文本输入:Rain pours against the cliff and the person, with music playing in the background.
一条蛇在草地里缓慢前进,给人一种危机四伏的赶脚。
文本输入:Rustling leaves and snapping twigs, with an orchestral music track.
AI生成的背景音,很有山地摩托摩托竞赛那味儿了。
文本输入:ATV engine roars and accelerates, with guitar music.
还有溜滑板,配着动作,给出不同节奏的音效。
文本输入:Wheels spinning, and a slamming sound as the skateboard lands on concrete.
92页技术报告,同用Llama 3架构
Movie Gen发布同时,Meta还祭出了92页的技术报告。值得一提的是,这次团队也被命名为「Movie Gen team」。
Pytorch之父Soumith Chintala表示,其中很多细节将会推动AI视频领域的发展。
接下来,一起看看Movie Gen得以实现的技术要点吧。
研究人员表示,Movie Gen主要是基于两种基础模型打造的,一个是Movie Gen Video,另一个是Movie Gen Audio。
Movie Gen Video
Movie Gen Video参数有300亿,基础架构细节如下图所示。
它能够联合文本到图像和文本到视频的生成。
Movie Gen Video可以遵循文本提示,生成长达16秒、16帧每秒高清视频。
它也是通过预训练微调完成,在骨干网络架构上,它继续沿用了Transformer的设计,尤其是借鉴的Llama3的设计。
而且,该模型有强大的适应性,可生成不同纵横比、分辨率和时长的高质量图像和视频。
预训练阶段,在大约1亿个视频和10亿张图像上进行了联合预训练。
它是通过「看」视频,来学习视觉世界。
实验结果发现,Movie Gen Video模型能够理解物理世界——
可以推理物体运动、主-客体交互、几何关系、相机运动、物理规律,以及各种概念的合理运动。
在微调阶段,研究人员精选了一部分视频,对模型在美学、运动质量方面完成了微调。
为了提高训练、推理效率,研究人员在时空压缩的潜在空间(Latent Space)中进行生成。
为此,他们训练了一个单一的时间自编码器(TAE),用于将RGB图像和视频映射到潜在空间。
然后,再使用预训练文本编码器,来编码用户提供的文本提示,并获得文本提示嵌入,这些嵌入用作模型的条件。
流匹配,击败扩散损失
值得一提的是,研究人员还引入「流匹配」(Flow Matching)来训练生成模型,这使得视频生成效果在精度、细节表现上,都优于扩散模型。
「流匹配」是一种新兴的生成模型训练方法,其核心思想是——直接学习样本从初始噪声状态向目标数据分布转化的过程。
而且,模型只需通过估计如何在每个时间步中演化样本,即可生成高质量的结果。
与扩散模型相比,「流匹配」训练效率更高、计算成本更低、并且在时间维度保持连续性和一致性。
有网友对此总结道,在质量和文本对齐上,人类评估都强烈倾向于流匹配,而不是扩散。
此外,Movie Gen Video在技术上也引入了很多创新:
他们引入了创新的位置编码方法——「因子化可学习编码」,能够独立对高度、宽度、时间三个维度进行编码,然后将其相加。
基于这种灵活设计,让模型不仅能够适应不同宽高比,还能处理任意长度的视频。
另外,为了解决模型推理效率问题,研究人员采用了一种「线性-二次时间步长」的策略。
如下图所示,仅需50步,就能实现接近1000步采样效果,大幅提升了推理速度。
与此同时,Movie Gen Video还采用了一种巧妙的「时间平铺」方法,进一步提升生成效率。
具体来说,这种方法将输入的视频,在时间维度上切分成多个小片段,然后对每个片对独立进行编码和解码,最后再将所有处理好的片段,重新拼接成完成视频。
这种分而治之策略,不仅显著降低内存需求,还提高了整体推理效率。
为了确保最终生成的视频质量,团队在解码阶段采用了精心设计的重叠和混合技术。
最后微调得到的Movie Gen Video模型,与当前最先进的模型相比,大幅超越LuamaLabs的Dream Machine,还有Gen-3。
它仅小幅超越了Sora、Kling 1.5。
如下是,生成图像质量的对比。总的来说,Movie Gen Video在画面一致性、质量等方面,均取得了最优表现。
提示中袋鼠走路细节,在Sora中到最后并没有展现。
Movie Gen Audio
音频模型参数共有130亿,能够生成48kHz的高质量电影音效和音乐。
而且,这些AI音频与输入视频,实现同步。
值得一提的是,Movie Gen Audio可以原生处理不同长度音频生成。
这一过程是通过TAE完成解码与编码。
而且,通过音频延伸技术,能够为长达几分钟视频,制作出连贯长音频。
研究人员在大约100万小时音频上,对模型进行了预训练。
得到的预训练模型,不仅学会了物理关联,还学会了视觉世界和音频世界之间的心理关联。
另外,模型还可以生成,与视觉场景匹配的非画面「内环境」声音,即便是声源没有出现在画面中。
最后,模型还可以生成支持情绪,并与视觉场景动作相匹配的非画面内音乐。
而且,它还能与专业地混合音效和背景音乐。
通过评估,与当前先进的音频模型ElevenLabs等相比,Movie Gen Audio结果如下所示。
参考资料:
https://x.com/AIatMeta/status/1842188252541043075
#速通LLM & VLM
LLaMA-Factory快速入门指南
1. 项目背景
开源大模型如LLaMA,Qwen,Baichuan等主要都是使用通用数据进行训练而来,其对于不同下游的使用场景和垂直领域的效果有待进一步提升,衍生出了微调训练相关的需求,包含预训练(pt),指令微调(sft),基于人工反馈的对齐(rlhf)等全链路。但大模型训练对于显存和算力的要求较高,同时也需要下游开发者对大模型本身的技术有一定了解,具有一定的门槛。
LLaMA-Factory项目的目标是整合主流的各种高效训练微调技术,适配市场主流开源模型,形成一个功能丰富,适配性好的训练框架。项目提供了多个高层次抽象的调用接口,包含多阶段训练,推理测试,benchmark评测,API Server等,使开发者开箱即用。同时借鉴 Stable Diffsion WebUI相关,本项目提供了基于gradio的网页版工作台,方便初学者可以迅速上手操作,开发出自己的第一个模型。
2. 本教程目标
以Meta-Llama-3-8B-Instruct 模型 和 Linux + RTX 4090 24GB环境,LoRA+sft训练阶段为例子,帮助开发者迅速浏览和实践本项目会涉及到的常见若干个功能,包括
- 原始模型直接推理
- 自定义数据集构建
- 基于LoRA的sft指令微调
- 动态合并LoRA的推理
- 批量预测和训练效果评估
- LoRA模型合并导出
- 一站式webui board的使用
- API Server的启动与调用
- 大模型主流评测 benchmark
- 导出GGUF格式,使用Ollama推理
本教程大部分内容都可以通过LLaMA-Factory下的 README.md, data/README.md,examples文件夹下的示例脚本得到,遇到问题请先阅读项目原始相关资料。
关于全参训练,flash-attention加速, deepspeed,rlhf,多模态模型训练等更高阶feature的使用,后续会有额外的教程来介绍
3. 前置准备
训练顺利运行需要包含4个必备条件
- 机器本身的硬件和驱动支持(包含显卡驱动,网络环境等)
- 本项目及相关依赖的python库的正确安装(包含CUDA, Pytorch等)
- 目标训练模型文件的正确下载
- 训练数据集的正确构造和配置
3.1 硬件环境校验
显卡驱动和CUDA的安装,网络教程很多,不在本教程范围以内
使用以下命令做最简单的校验
nvidia-smi
预期输出如图,显示GPU当前状态和配置信息
那多大的模型用什么训练方式需要多大的GPU呢,可参考 https://github.com/hiyouga/LLaMA-Factory?tab=readme-ov-file#hardware-requirement
新手建议是3090和4090起步,可以比较容易地训练比较主流的入门级别大模型 7B和8B版本。
3.2 CUDA和Pytorch环境校验
请参考项目的readme进行安装
https://github.com/hiyouga/LLaMA-Factory?tab=readme-ov-file#dependence-installation
2024年51期间系统版本有较大升级,2024-06-07 号的安装版本命令如下,请注意conda环境的激活。
git clone https://github.com/hiyouga/LLaMA-Factory.git
conda create -n llama_factory pythnotallow=3.10
conda activate llama_factory
cd LLaMA-Factory
pip install -e '.[torch,metrics]'
上述的安装命令完成了如下几件事
- 新建一个LLaMA-Factory 使用的python环境(可选)
- 安装LLaMA-Factory 所需要的第三方基础库(requirements.txt包含的库)
- 安装评估指标所需要的库,包含nltk, jieba, rouge-chinese
- 安装LLaMA-Factory本身,然后在系统中生成一个命令 llamafactory-cli(具体用法见下方教程)
安装后使用以下命令做简单的正确性校验
校验1
import torch
torch.cuda.current_device()
torch.cuda.get_device_name(0)
torch.__version__
预期输出如图
如果识别不到可用的GPU,则说明环境准备还有问题,需要先进行处理,才能往后进行。
校验2
同时对本库的基础安装做一下校验,输入以下命令获取训练相关的参数指导, 否则说明库还没有安装成功
llamafactory-cli train -h
3.3 模型下载与可用性校验
项目支持通过模型名称直接从huggingface 和modelscope下载模型,但这样不容易对模型文件进行统一管理,所以这里笔者建议使用手动下载,然后后续使用时使用绝对路径来控制使用哪个模型。 以Meta-Llama-3-8B-Instruct为例,通过huggingface 下载(可能需要先提交申请通过)
git clone https://huggingface.co/meta-llama/Meta-Llama-3-8B-Instruct
modelscope 下载(适合中国大陆网络环境)
git clone https://www.modelscope.cn/LLM-Research/Meta-Llama-3-8B-Instruct.git
或者
#模型下载
from modelscope import snapshot_download
model_dir = snapshot_download('LLM-Research/Meta-Llama-3-8B-Instruct')
按网友反馈,由于网络环境等原因,文件下载后往往会存在文件不完整的很多情况,下载后需要先做一下校验,校验分为两部分,第一先检查一下文件大小和文件数量是否正确,和原始的huggingface显示的做一下肉眼对比
第二步是跑一下官方raedme里提供的原始推理demo,验证模型文件的正确性和transformers库等软件的可用
import transformers
import torch
# 切换为你下载的模型文件目录, 这里的demo是Llama-3-8B-Instruct
# 如果是其他模型,比如qwen,chatglm,请使用其对应的官方demo
model_id = "/media/codingma/LLM/llama3/Meta-Llama-3-8B-Instruct"
pipeline = transformers.pipeline(
"text-generation",
model=model_id,
model_kwargs={"torch_dtype": torch.bfloat16},
device_map="auto",
)
messages = [
{"role": "system", "content": "You are a pirate chatbot who always responds in pirate speak!"},
{"role": "user", "content": "Who are you?"},
]
prompt = pipeline.tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
terminators = [
pipeline.tokenizer.eos_token_id,
pipeline.tokenizer.convert_tokens_to_ids("<|eot_id|>")
]
outputs = pipeline(
prompt,
max_new_tokens=256,
eos_token_id=terminators,
do_sample=True,
temperature=0.6,
top_p=0.9,
)
print(outputs[0]["generated_text"][len(prompt):])
3.4 数据集部分放到后面一起说明4. 原始模型直接推理
在进行后续的环节之前,我们先使用推理模式,先验证一下LLaMA-Factory的推理部分是否正常。LLaMA-Factory 带了基于gradio开发的ChatBot推理页面, 帮助做模型效果的人工测试。在LLaMA-Factory 目录下执行以下命令
本脚本参数参考自 LLaMA-Factory/examples/inference/llama3.yaml at main · hiyouga/LLaMA-Factory
CUDA_VISIBLE_DEVICES=0 llamafactory-cli webchat \
--model_name_or_path /media/codingma/LLM/llama3/Meta-Llama-3-8B-Instruct \
--template llama3
CUDA_VISIBLE_DEVICES=0 是指定了当前程序使用第0张卡,是指定全局变量的作用, 也可以不使用
llamafactory-cli webchat \
--model_name_or_path /media/codingma/LLM/llama3/Meta-Llama-3-8B-Instruct \
--template llama3
需要注意的是,本次及后续所有的程序的入口都是 llamafactory-cli, 通过不同的参数控制现在是实现什么功能,比如现在是想使用网页版本直接推理,所以第一个参数设置为webchat, 所有的可选项包括
另外两个关键参数解释如下,后续的基本所有环节都会继续使用这两个参数
当然你也可以提前把相关的参数存在yaml文件里,比如LLaMA-Factory/examples/inference/llama3.yaml at main · hiyouga/LLaMA-Factory, 本地位置是 examples/inference/llama3.yaml ,内容如下
model_name_or_path: /media/codingma/LLM/llama3/Meta-Llama-3-8B-Instruct
template: llama3
这样就可以通过如下命令启动,其效果跟上面是一样的,但是更方便管理
llamafactory-cli webchat examples/inference/llama3.yaml
效果如图,可通过 http://localhost:7860/ 进行访问
注意:这里的localhost:7860 指的是程序启动机器自身的7860端口,云上的用户可能无法通过本地的笔记本电脑直接访问,需要找云厂商获取域名和端口号的一些配置关系进行配置
比如阿里云用户需要做一下如下环境变量的配置才能正常运行gradio,然后再通过阿里云给的域名映射访问
export GRADIO_ROOT_PATH=/${JUPYTER_NAME}/proxy/7860/
5. 自定义数据集构建
数据集的格式要求在不同的阶段是不同的,本教程以sft阶段的数据集需求,将以系统自带的identity数据集和将自定义的一个商品文案生成数据集为例,介绍数据集的使用。更多详情可以在 https://github.com/hiyouga/LLaMA-Factory/blob/main/data/README_zh.md 中找到相关解释。
系统目前支持 alpaca 和sharegpt两种数据格式,以alpaca为例,整个数据集是一个json对象的list,具体数据格式为
[
{
"instruction": "用户指令(必填)",
"input": "用户输入(选填)",
"output": "模型回答(必填)",
"system": "系统提示词(选填)",
"history": [
["第一轮指令(选填)", "第一轮回答(选填)"],
["第二轮指令(选填)", "第二轮回答(选填)"]
]
}
]
例子比如单轮(alpaca_data_zh_51k.json 中的例子, 数据集在data/dataset_info.json中注册为alpaca_zh)
{
"instruction": "写一个有效的比较语句",
"input": "篮球和足球",
"output": "篮球和足球都是受欢迎的运动。"
}
和多轮 (oaast_sft_zh.json 中的例子, 数据集在data/dataset_info.json中注册为oaast_sft_zh)
{
"instruction": "谢谢",
"input": "",
"output": "不用谢! 很高兴我提供的信息能够帮助到你! 如果还有什么其他问题也可以向我提问。",
"history": [
[
"请你给我写一个面试准备计划,我想要去面试微软的程序员岗位",
"首先,你可以去微软官网寻找招聘信息并申请面试。\n其次,您可以在社交媒体平台寻找微软公司对程序员的面试问题,并做好准备。\n最后,您可以自己对面试过程进行模拟,熟悉话题并减少紧张感。\n我希望你能面试成功。"
]
]
}
所以我们训练的数据最好也转换成这种格式,然后在 data/dataset_info.json中进行注册(如果不做字段名称转换,则需要在注册的时候在 columns字段中做两个数据的映射配置)
接下来,我们使用两个具体的例子来说明数据集的使用
第一个是系统自带的identity.json数据集(已默认在data/dataset_info.json 注册为identity),对应文件已经在data目录下,我们通过操作系统的文本编辑器的替换功能,可以替换其中的NAME 和 AUTHOR ,换成我们需要的内容。如果是linux系统,可以使用sed 完成快速替换。比如助手的名称修改为PonyBot, 由 LLaMA Factory 开发
sed -i 's/{{name}}/PonyBot/g' data/identity.json
sed -i 's/{{author}}/LLaMA Factory/g' data/identity.json
替换前
{
"instruction": "Who are you?",
"input": "",
"output": "Hello! I am {{name}}, an AI assistant developed by {{author}}. How can I assist you today?"
}
替换后
{
"instruction": "Who are you?",
"input": "",
"output": "I am PonyBot, an AI assistant developed by LLaMA Factory. How can I assist you today?"
}
第二个是一个商品文案生成数据集,原始链接为 https://cloud.tsinghua.edu.cn/f/b3f119a008264b1cabd1/?dl=1
原始格式如下,很明显,训练目标是输入content (也就是prompt), 输出 summary (对应response)
{
"content": "类型#裤*版型#宽松*风格#性感*图案#线条*裤型#阔腿裤",
"summary": "宽松的阔腿裤这两年真的吸粉不少,明星时尚达人的心头爱。毕竟好穿时尚,谁都能穿出腿长2米的效果宽松的裤腿,当然是遮肉小能手啊。上身随性自然不拘束,面料亲肤舒适贴身体验感棒棒哒。系带部分增加设计看点,还让单品的设计感更强。腿部线条若隐若现的,性感撩人。颜色敲温柔的,与裤子本身所呈现的风格有点反差萌。"
}
想将该自定义数据集放到我们的系统中使用,则需要进行如下两步操作
- 复制该数据集到 data目录下
- 修改 data/dataset_info.json 新加内容完成注册, 该注册同时完成了3件事
- 自定义数据集的名称为adgen_local,后续训练的时候就使用这个名称来找到该数据集
- 指定了数据集具体文件位置
- 定义了原数据集的输入输出和我们所需要的格式之间的映射关系
6. 基于LoRA的sft指令微调
在准备好数据集之后,我们就可以开始准备训练了,我们的目标就是让原来的LLaMA3模型能够学会我们定义的“你是谁”,同时学会我们希望的商品文案的一些生成。
这里我们先使用命令行版本来做训练,从命令行更容易学习相关的原理。
本脚本参数改编自 LLaMA-Factory/examples/train_lora/llama3_lora_sft.yaml at main · hiyouga/LLaMA-Factory
CUDA_VISIBLE_DEVICES=0 llamafactory-cli train \
--stage sft \
--do_train \
--model_name_or_path /media/codingma/LLM/llama3/Meta-Llama-3-8B-Instruct \
--dataset alpaca_gpt4_zh,identity,adgen_local \
--dataset_dir ./data \
--template llama3 \
--finetuning_type lora \
--output_dir ./saves/LLaMA3-8B/lora/sft \
--overwrite_cache \
--overwrite_output_dir \
--cutoff_len 1024 \
--preprocessing_num_workers 16 \
--per_device_train_batch_size 2 \
--per_device_eval_batch_size 1 \
--gradient_accumulation_steps 8 \
--lr_scheduler_type cosine \
--logging_steps 50 \
--warmup_steps 20 \
--save_steps 100 \
--eval_steps 50 \
--evaluation_strategy steps \
--load_best_model_at_end \
--learning_rate 5e-5 \
--num_train_epochs 5.0 \
--max_samples 1000 \
--val_size 0.1 \
--plot_loss \
--fp16
关于参数的完整列表和解释可以通过如下命令来获取
llamafactory-cli train -h
这里我对部分关键的参数做一下解释,model_name_or_path 和template 上文已解释
注意:精度相关的参数还有bf16 和pure_bf16,但是要注意有的老显卡,比如V100就无法支持bf16,会导致程序报错或者其他错误
训练过程中,系统会按照logging_steps的参数设置,定时输出训练日志,包含当前loss,训练进度等
训练完后就可以在设置的output_dir下看到如下内容,主要包含3部分
- adapter开头的就是 LoRA保存的结果了,后续用于模型推理融合
- training_loss 和trainer_log等记录了训练的过程指标
- 其他是训练当时各种参数的备份
关于loss是什么等,这块不在本教程讨论内容范围之内,只需要记住loss在 正常情况下会随着训练的时间慢慢变小,最后需要下降到1以下的位置才会有一个比较好的效果,可以作为训练效果的一个中间指标。
7. 动态合并LoRA的推理
本脚本参数改编自 LLaMA-Factory/examples/inference/llama3_lora_sft.yaml at main · hiyouga/LLaMA-Factory
当基于LoRA的训练进程结束后,我们如果想做一下动态验证,在网页端里与新模型对话,与步骤4的原始模型直接推理相比,唯一的区别是需要通过finetuning_type参数告诉系统,我们使用了LoRA训练,然后将LoRA的模型位置通过 adapter_name_or_path参数即可。
CUDA_VISIBLE_DEVICES=0 llamafactory-cli webchat \
--model_name_or_path /media/codingma/LLM/llama3/Meta-Llama-3-8B-Instruct \
--adapter_name_or_path ./saves/LLaMA3-8B/lora/sft \
--template llama3 \
--finetuning_type lora
效果如下,可以看到,模型整个已经在学习了新的数据知识,学习了新的身份认知和商品文案生成的格式。
作为对比,如果删除LoRA相关参数,只使用原始模型重新启动测试,可以看到模型还是按照通用的一种回答。
如果不方便使用webui来做交互,使用命令行来做交互,同样也是可以的。
本脚本改编自 LLaMA-Factory/examples/inference/llama3_lora_sft.yaml at main · hiyouga/LLaMA-Factory
CUDA_VISIBLE_DEVICES=0 llamafactory-cli chat \
--model_name_or_path /media/codingma/LLM/llama3/Meta-Llama-3-8B-Instruct \
--adapter_name_or_path ./saves/LLaMA3-8B/lora/sft \
--template llama3 \
--finetuning_type lora
效果如下
8. 批量预测和训练效果评估
当然上文中的人工交互测试,会偏感性,那有没有办法批量地预测一批数据,然后使用自动化的bleu和 rouge等常用的文本生成指标来做评估。指标计算会使用如下3个库,请先做一下pip安装
pip install jieba
pip install rouge-chinese
pip install nltk
本脚本参数改编自 https://github.com/hiyouga/LLaMA-Factory/blob/main/examples/train_lora/llama3_lora_predict.yaml
CUDA_VISIBLE_DEVICES=0 llamafactory-cli train \
--stage sft \
--do_predict \
--model_name_or_path /media/codingma/LLM/llama3/Meta-Llama-3-8B-Instruct \
--adapter_name_or_path ./saves/LLaMA3-8B/lora/sft \
--eval_dataset alpaca_gpt4_zh,identity,adgen_local \
--dataset_dir ./data \
--template llama3 \
--finetuning_type lora \
--output_dir ./saves/LLaMA3-8B/lora/predict \
--overwrite_cache \
--overwrite_output_dir \
--cutoff_len 1024 \
--preprocessing_num_workers 16 \
--per_device_eval_batch_size 1 \
--max_samples 20 \
--predict_with_generate
与训练脚本主要的参数区别如下两个
最后会在output_dir下看到如下内容
其中 generated_predictions.jsonl 文件 输出了要预测的数据集的原始label和模型predict的结果
predict_results.json给出了原始label和模型predict的结果,用自动计算的指标数据
这里给相关的指标做一下进一步的解释
9. LoRA模型合并导出
如果想把训练的LoRA和原始的大模型进行融合,输出一个完整的模型文件的话,可以使用如下命令。合并后的模型可以自由地像使用原始的模型一样应用到其他下游环节,当然也可以递归地继续用于训练。
本脚本参数改编自 LLaMA-Factory/examples/merge_lora/llama3_lora_sft.yaml at main · hiyouga/LLaMA-Factory
CUDA_VISIBLE_DEVICES=0 llamafactory-cli export \
--model_name_or_path /media/codingma/LLM/llama3/Meta-Llama-3-8B-Instruct \
--adapter_name_or_path ./saves/LLaMA3-8B/lora/sft \
--template llama3 \
--finetuning_type lora \
--export_dir megred-model-path \
--export_size 2 \
--export_device cpu \
--export_legacy_format False
10. 一站式webui board的使用
到这里,恭喜你完成了LLaMA-Efficent-Tuning训练框架的基础使用,那还有什么内容是没有介绍的呢?还有很多!这里介绍一个在提升交互体验上有重要作用的功能, 支持模型训练全链路的一站式WebUI board。一个好的产品离不开好的交互,Stable Diffusion的大放异彩的重要原因除了强大的内容输出效果,就是它有一个好的WebUI。这个board将训练大模型主要的链路和操作都在一个页面中进行了整合,所有参数都可以可视化地编辑和操作
通过以下命令启动
注意:目前webui版本只支持单机单卡和单机多卡,如果是多机多卡请使用命令行版本
CUDA_VISIBLE_DEVICES=0 llamafactory-cli webui
如果要开启 gradio的share功能,或者修改端口号
CUDA_VISIBLE_DEVICES=0 GRADIO_SHARE=1 GRADIO_SERVER_PORT=7860 llamafactory-cli webui
如图所示,上述的多个不同的大功能模块都通过不同的tab进行了整合,提供了一站式的操作体验。
当各种参数配置好后,在train页面,可以通过预览命令功能,将训练脚本导出,用于支持多gpu训练
点击开始按钮, 即可开始训练,网页端和服务器端会同步输出相关的日志结果
训练完毕后, 点击“刷新适配器”,即可找到该模型历史上使用webui训练的LoRA模型文件,后续再训练或者执行chat的时候,即会将此LoRA一起加载。
11. API Server的启动与调用
训练好后,可能部分同学会想将模型的能力形成一个可访问的网络接口,通过API 来调用,接入到langchian或者其他下游业务中,项目也自带了这部分能力。
API 实现的标准是参考了OpenAI的相关接口协议,基于uvicorn服务框架进行开发, 使用如下的方式启动
本脚本改编自 https://github.com/hiyouga/LLaMA-Factory/blob/main/examples/inference/llama3_lora_sft.yaml
CUDA_VISIBLE_DEVICES=0 API_PORT=8000 llamafactory-cli api \
--model_name_or_path /media/codingma/LLM/llama3/Meta-Llama-3-8B-Instruct \
--adapter_name_or_path ./saves/LLaMA3-8B/lora/sft \
--template llama3 \
--finetuning_type lora
项目也支持了基于vllm 的推理后端,但是这里由于一些限制,需要提前将LoRA 模型进行merge,使用merge后的完整版模型目录或者训练前的模型原始目录都可。
CUDA_VISIBLE_DEVICES=0 API_PORT=8000 llamafactory-cli api \
--model_name_or_path megred-model-path \
--template llama3 \
--infer_backend vllm \
--vllm_enforce_eager
服务启动后,即可按照openai 的API 进行远程访问,主要的区别就是替换 其中的base_url,指向所部署的机器url和端口号即可。
import os
from openai import OpenAI
from transformers.utils.versions import require_version
require_version("openai>=1.5.0", "To fix: pip install openai>=1.5.0")
if __name__ == '__main__':
# change to your custom port
port = 8000
client = OpenAI(
api_key="0",
base_url="http://localhost:{}/v1".format(os.environ.get("API_PORT", 8000)),
)
messages = []
messages.append({"role": "user", "content": "hello, where is USA"})
result = client.chat.completions.create(messages=messages, model="test")
print(result.choices[0].message)
12. 进阶-大模型主流评测 benchmark
虽然大部分同学的主流需求是定制一个下游的垂直模型,但是在部分场景下,也可能有同学会使用本项目来做更高要求的模型训练,用于大模型刷榜单等,比如用于评测mmlu等任务。当然这类评测同样可以用于评估大模型二次微调之后,对于原来的通用知识的泛化能力是否有所下降。(因为一个好的微调,尽量是在具备垂直领域知识的同时,也保留了原始的通用能力)
本项目提供了mmlu,cmmlu, ceval三个常见数据集的自动评测脚本,按如下方式进行调用即可。
说明:task 目前支持 mmlu_test, ceval_validation, cmmlu_test
本脚本改编自 https://github.com/hiyouga/LLaMA-Factory/blob/main/examples/train_lora/llama3_lora_eval.yaml
如果是chat版本的模型
CUDA_VISIBLE_DEVICES=0 llamafactory-cli eval \
--model_name_or_path /media/codingma/LLM/llama3/Meta-Llama-3-8B-Instruct \
--template llama3 \
--task mmlu_test \
--lang en \
--n_shot 5 \
--batch_size 1
输出如下, 具体任务的指标定义请参考mmlu,cmmlu, ceval等任务原始的相关资料, 和llama3的官方报告基本一致
Average: 63.64
STEM: 50.83
Social Sciences: 76.31
Humanities: 56.63
Other: 73.31
如果是base版本的模型,template改为fewshot即可
CUDA_VISIBLE_DEVICES=0 llamafactory-cli eval \
--model_name_or_path /media/codingma/LLM/llama3/Meta-Llama-3-8B \
--template fewshot \
--task mmlu \
--split validation \
--lang en \
--n_shot 5 \
--batch_size 1
13. 进阶-导出GGUF,部署Ollama
GGUF 是 lllama.cpp 设计的大模型存储格式,可以对模型进行高效的压缩,减少模型的大小与内存占用,从而提升模型的推理速度和效率。Ollama框架可以帮助用户快速使用本地的大型语言模型,那如何将LLaMA-Factory项目的训练结果 导出到Ollama中部署呢?需要经过如下几个步骤
- 将lora模型合并
- 安装gguf库
- 使用llama.cpp的转换脚本将训练后的完整模型转换为gguf格式
- 安装Ollama软件
- 注册要部署的模型文件
- 启动Ollama
1-3 步是准备好 gguf格式的文件,这也是Ollama所需要的标准格式。
4-6 步就是如何在Ollama环境中启动训练后的模型。
1. lora模型合并
参考上文的第9步,这里笔者合并后的完整模型目录的绝对位置假设为 /home/codingma/code/LLaMA-Factory/megred-model-path
注意:合并后可以在该目录下获取 转换好ollama需要的 Modelfile 文件
2. 安装gguf库
笔者发现直接 pip 安装 gguf,并不是最新的版本,和最新的转换脚本会不兼容,所以还是推荐从源码安装
git clone https://github.com/ggerganov/llama.cpp.git
cd llama.cpp/gguf-py
pip install --editable .
3. 格式转换
返回 llama.cpp 项目根目录,会有一个官方提供的 convert-hf-to-gguf.py 脚本,用于完成huggingface格式到gguf格式的转换.
cd ..
python convert-hf-to-gguf.py /home/codingma/code/LLaMA-Factory/megred-model-path
转换成功可在megred-model-path路径下得到如下的gguf文件
4. Ollama安装
本文是linux环境,所以用了对应的下载和安装方式,如果是其他系统的用户可以按照 https://ollama.com/download 的说明完成下载安装
curl -fsSL https://ollama.com/install.sh | sh
5. 注册要部署的模型文件
Ollama 对于要部署的模型需要提前完成本地的配置和注册, 和 Docker的配置很像, 在刚才的LoRA合并后目录可以找到
ollama create llama3-chat-merged -f /home/codingma/code/LLaMA-Factory/megred-model-path/Modelfile
6. 启动Ollama
上面注册好后,即可通过ollma 命令 + 模型名称的方式,完成服务的启动
ollama run llama3-chat-merged
启动后即可通过交互式完成问答,输入 /bye 即可退出
#盘古Ultra
不用英伟达GPU!HuaWei盘古Ultra来了:昇腾原生、135B稠密通用大模型
终于,huawei盘古大模型系列上新了,而且是昇腾原生的通用千亿级语言大模型。
我们知道,如今各大科技公司纷纷发布百亿、千亿级模型。但这些大部分模型训练主要依赖英伟达的 GPU。
而现在的情形下,国内研究团队很难获得足够的计算资源,这也制约了国内大模型技术的快速发展。
我们看到华为盘古发布的这篇新研究,证明了基于全国产的昇腾也可以实现领先的大规模语言模型的研究与开发。
- 技术报告标题:Pangu Ultra: Pushing the Limits of Dense Large Language Models on Ascend NPUs
- 技术报告地址:https://github.com/pangu-tech/pangu-ultra/blob/main/pangu-ultra-report.pdf
研究称华为盘古团队成功开发出基于昇腾算力训练的千亿级通用语言大模型 Pangu Ultra。在效果上,Pangu Ultra 在多个领域和评测上超越之前 Llama 405B 和 Mistral Large 2 等稠密模型,并可以与 DeepSeek-R1 等更大规模的稀疏模型一较高下。
Pangu Ultra 是一个拥有 94 层架构、总参数量达 135B 的超大稠密模型。针对超深千亿级大模型的训练稳定性问题,研究团队提出了新的稳定性架构和初始化方法,成功实现了在 13.2T 高质量数据上的全流程无 loss 突刺长稳训练。同时,在系统实现层面,团队通过一系列系统优化策略,在 8192 张昇腾 NPU 构建的大规模集群上将算力利用率(MFU)提升至 50%。
接下来,让我们从模型架构、模型训练等方面,详细了解下 Pangu Ultra 的技术细节。
模型架构
基础架构信息:Pangu Ultra 包含 1350 亿参数、采用了 94 层的 Transformer 结构。其中 FFN 采用 SwiGLU 激活。注意力层采用 GQA 降低 KV 缓存占用。
Pangu Ultra 针对大规模极深模型的训练稳定性问题提出了 Depth-scaled sandwich-norm 和 TinyInit 初始化两项技术。
Depth-scaled sandwich-norm:与混合专家模型(MoE)侧重在宽度上扩展不同,大规模稠密模型通常采用更深的层数。然而,深度增加会加剧训练稳定性的挑战。考虑到预训练的巨大成本,保证大模型的稳定训练至关重要。
Pre-LN 在基于 Transformer 的大语言模型架构中被广泛应用,但采用 Pre-LN 的模型中,各子层输出尺度的波动容易导致训练不稳定。为解决此问题,Sandwich-Norm 在残差连接前对每个子层输出额外施加 layer norm。虽然 Sandwich-Norm 能保持单个子层输出的尺度稳定性,但跨越多层的残差连接仍会导致输出范数逐渐累积,进而引发训练不稳定。
为此,Pangu Ultra 提出 Depth-Scaled Sandwich-Norm(DSSN)。该技术通过对每个子层输出的 layer norm 的 gamma 参数来调控各层输出尺度,通过把 gamma 参数初始化为与网络深度的平方根倒数成比例。下图展示了 Depth-Scaled Sandwich-Norm 与 Pre-LN 架构的差异。实验结果表明所提出方法相比基准方法在稳定性和收敛性都具有较大优势(见模型结果与分析)。
Pre-LN 与 DSSN 架构对比。相比 Sandiwich norm,DSSN 对 layer norm 系数做了特殊的 re-scale
TinyInit: 模型初始化对训练稳定性和性能具有关键影响。基于 Transformer 的大语言模型普遍采用 small init 策略,即所有权重初始化为标准差为
的正态分布。另外有工作将残差层权重在初始化时缩放
倍。
Pangu 提出了同时根据模型深度和宽度缩放的参数初始化策略 TinyInit,所有权重初始化标准差
,能加速 loss 收敛并提升下游任务性能。TinyInit 能使模型各部分的参数尺度更加一致,从而有利于优化和收敛(见模型结果与分析)。
Pangu Tokenizer:在 Pangu Ultra 的中,作者优化了分词器(Tokenizer)。传统方法在构建词汇表时,常因数据分布导致通用文本占比过高,而代码、数学等专业领域的词元代表性不足。为解决此问题,Pangu Ultra 采用了「领域感知」的分词词表策略:
- 对通用中文、通用英文、代码、数学等多个关键领域的数据独立进行词频分析,生成领域专属词汇表。
- 随后,将这些词汇表合并与去重,形成了一个包含 153376 词元的分词词表。
这种方法提升了词汇表在不同领域间的均衡性,确保了模型在处理文本、代码、数学等多样化任务时,都能获得更精准、高效的理解基础,同时保持了良好的整体压缩效率。
各领域词在 Pangu 词表中的分布
模型训练
预训练策略与数据:Pangu Ultra 的预训练过程的三个阶段:12T tokens 的通用能力训练、0.8T tokens 的推理能力增训以及 0.4T tokens 的退火阶段。
Pangu Ultra 预训练各个阶段的数据配比
Pangu Ultra 模型的预训练语料覆盖了高质量、多样化的 13.2T tokens,如上表所示,整个预训练过程分为三个阶段:通用阶段(General)、推理阶段(Reasoning)和退火阶段(Annealing)。
通用阶段(12T)旨在帮助模型积累知识和语言表达能力,推理阶段(0.8T)旨在强化模型推理技能,而退火阶段(0.4T)则进一步教会模型如何运用已学到的知识和推理技能。
团队为训练语料打了质量与难度的标签分数,并在上述三个阶段中采用课程式的数据采样策略,即完成一个从易到难的学习过程:
- 通用阶段覆盖了大量的书籍、网页、百科、多语言以及各行各业的语料,实际训练中分成了两个子阶段,训练量分别为 7.4T 和 4.6T tokens;
- 推理阶段重点提高泛数学、理科以及代码数据的比重,强推理数据占比超过 60%;
- 退火阶段将指令类数据占比提高到 20%,旨在激发模型更好的应用知识和推理技能。团队设计了大量的指令类问答对,并且包含长、短思维链,这些推理路径经过精心优化,以确保内容清晰且逻辑连贯。
数据质量评估是提升模型训练效果的核心环节,Pangu Ultra 结合规则筛选与 AI 评估优化数据质量。团队设计人工标注数据,微调盘古系列模型作为质量评估器,从数据干净度、流畅性、教育价值和信息密度四个维度,对超过 10T 语料进行打分,并且赋予高质量语料更高的采样概率。
团队基于 Pangu 26 亿参数的代理模型进行了大量的消融实验,结果表明基于低质量数据训练的模型需要多 1.6 倍训练量才能达成基于高质量数据的同等效果,进一步印证了数据质量对于提升训练效率的关键价值。
长序列扩展:Pangu Ultra 模型通过两阶段长度扩展训练将可支持的输入 token 数增加到 128K,可以输入约 10 万英语单词或者 17 万中文汉字。针对长序列训练中 RoPE 基础频率这一重要参数,在训练前首先在目标扩展长度的特定验证集上对不同的参数进行评测来搜索出最优的参数,保证了长度扩展的效果。
后训练策略与数据:在模型后训练阶段,通过两阶段优化实现能力跃升:首先采用监督微调(SFT)建立基础指令跟随能力,随后引入基于结果的强化学习(RL)框架,显著提升模型的复杂推理、价值对齐和指令执行能力。为充分发挥昇腾算力优势,研究团队特别设计了具有延迟容忍特性的强化学习框架,配合融合确定性信号与模型评估的混合奖励系统,在数学推导、代码生成和通用问题解决三大领域构建精准反馈机制,确保大规模策略优化的效率与稳定性。
模型在 AIME 2024、MATH-500、GPQA Diamond 和 LiveCodeBench 等核心推理基准上取得了理想的性能,验证了后训练架构的有效性,这既得益于预训练阶段 0.8T 规模的专项推理数据积累,也源于强化学习阶段对模型潜力的深度激发。同时模型仍保持强大的通用语言理解能力(MMLU-pro 和 ArenaHard),彰显了技术路径的均衡性,结果见模型结果与分析部分。
系统优化
Pangu Ultra 135B 的训练环境是一个配备了 8192 个昇腾 NPU 的大规模计算集群。团队通过混合并行策略、细粒度负载均衡调优、高效融合算子、子序列切分以及数据缓存共享等技术手段,在 8192 卡规模的集群中实现了超过 50% 的 MFU(Model FLOPs Utilization)。
并行策略:为了扩展 Pangu Ultra 的训练规模并提升集群线性度,团队采用了混合并行策略。在 8192 卡规模的集群中,使用了 128 路数据并行(Data Parallelism)、8 路张量并行(Tensor Parallelism)和 8 路流水线并行(Pipeline Parallelism),同时结合了 ZeRO 和序列并行(Sequence Parallelism),以降低模型参数、优化器状态和激活值的显存占用。由于 batch-size 的限制,大规模集群训练中每个数据并行(DP)组的批次较小,导致较高的流水线空泡率。为解决这一问题,团队引入了 6 路虚拟流水线(Virtual Pipeline)调度算法,将训练空泡率从 30.45% 降低至 6.8%。通过一系列精细的负载均衡优化,在 BF16 训练精度下实现了 43% 的 MFU。
系统优化:为了进一步提升大规模集群的训练效率,团队从多个方面进行了系统优化,将 8192 卡训练的 MFU 从 43% 提升至 52%。关键优化技术包括:
- MC2(Merged Compute and Communication)通算融合
通过将训练中的矩阵乘法(MatMul)计算与张量并行(TP)切分引入的通信操作细粒度拆分,并对计算和通信操作进行深度流水线编排,实现了通信与矩阵乘法的高效重叠,显著提升了资源利用率和训练效率。
- NPU Fusion Attention(NFA)
针对昇腾 NPU 优化的自注意力(Self-Attention)融合算子,支持 Attention Mask 压缩,避免了显式构造 Attention Mask 带来的计算和显存开销。在 Pangu Ultra 训练中,根据每个样本的结束标记(EOD)计算出实际序列长度(actual_seq_len),并将其传入 NFA。NFA 内部使用一个 2048×2048 的下三角矩阵作为素材库,根据 actual_seq_len 动态构造训练时的 Attention Mask,从而在重置 Attention Mask 的场景下实现高效的自注意力计算。
- 其他融合算子
除了 MC2 和 NFA,训练还采用了 RMSNorm、SwiGLU、RoPE 融合算子、梯度累加融合以及 PP send/recv 融合等技术,进一步提升了系统性能。
- 子序列切分
上下文并行(Context Parallelism,CP)是长序列训练中常用的优化方法。为了实现 CP 切分下的负载均衡,Megatron-LM 将序列切分为 2×CP 个子序列,每个设备负责计算上下两个 chunk 的数据(见图 1.(b))。然而,这种切分方式在重置 Attention Mask 的场景下仍会导致负载不均(见图 1.(c))。Pangu Ultra 采用了改进的子序列切分并行方式,针对每个样本中的子序列采用负载均衡的切分策略,每个节点负责计算子序列中的两个 chunks(见图 1.(d))。
图 1. 子序列切分的序列并行方式
- 显存优化
允许同一计算设备上的不同 vpp stage 之间共享 attention mask/actual_seq_len,RoPE sin/cos, position embedding 等数据。避免重复的计算和显存开销。
模型结果与分析
Pangu Ultra 实现了昇腾近万卡大集群上约 13T 数据的长稳训练,DSSN 和 TinyInit 保障训练全程没有出现任何 loss 突刺,如下图:
Pangu Ultra 预训练 Loss,全流程无 loss 突刺
Pangu Ultra 的预训练基座模型测评结果如下。对比稠密架构的代表 Qwen2.5-72B 和 Llama 405B 以及 MoE 架构的代表 DeepSeek V3。Pangu Ultra 在大多数 benchmark 上取得了最好的效果,和同为稠密架构的模型对比优势更加明显。
Pangu Ultra Base 测评结果,粗体表明最好结果,下划线表明该模型在 dense 中最好
经过后训练之后,Pangu Ultra 在主要的 Reasoning benchmark 上的表现如下所示。
Pangu Ultra 在 Reasoning Benchmarks 上的表现
Pangu Ultra 在 AIME24,MATH-500,GPQA,MMLU-Pro 等指标上超越 DeepSeek R1。关于盘古后训练使用的相关技术将在之后的报告中发布。
针对训练稳定性,团队发现 DSSN 和常见的 Pre-Norm(Pre-LN)架构对比能够完全杜绝训练中的 loss 突刺现象。在 gradient norm 上,使用 DSSN 的模型也更加平稳,突刺更少。经过测评,DSSN 架构的模型效果也超出 Pre-LN 架构,说明避免训练突刺的重要性。
DSSN 与 Pre-LN 的训练对比
DSSN 架构和 Pre-LN 架构的测评效果对比
使用 Sandwich-Norm 架构时,RMSNorm 的 affine 参数 \gamma 初始化非常重要,该研究提出的 DSSN 方案与普通 Sandwich-Norm 架构对比训练 loss 也更加平稳,且收敛更快,如下图所示。
DSSN 对比普通 Sandwich-Norm
关于 TinyInit,团队在 135B 的模型规模上训练了约 100B tokens,和经典基线初始化方案相比取得了较为明显的优势。
TinyInit 对比普通初始化的模型测评效果
#冷静看待推理模型的进展
强化学习带来的改进只是「噪音」,最新研究预警:
「推理」已成为语言模型的下一个主要前沿领域,近期学术界和工业界都取得了突飞猛进的进展。
在探索的过程中,一个核心的议题是:对于模型推理性能的提升来说,什么有效?什么无效?
DeepSeek - R1 论文曾提到:「我们发现将强化学习应用于这些蒸馏模型可以获得显著的进一步提升」。3 月 20 日,论文《Reinforcement Learning for Reasoning in Small LLMs: What Works and What Doesn't》再次验证了 RL 对于蒸馏模型是有效的。
尽管这些论文的结论统统指向了强化学习带来的显著性能提升,但来自图宾根大学和剑桥大学的研究者发现,强化学习导致的许多「改进」可能只是噪音。
- 论文标题:A Sober Look at Progress in Language Model Reasoning: Pitfalls and Paths to Reproducibility
- 论文链接:https://arxiv.org/pdf/2504.07086
「受推理领域越来越多不一致的经验说法的推动,我们对推理基准的现状进行了严格的调查,特别关注了数学推理领域评估算法进展最广泛使用的测试平台之一 HuggingFaceH4,2024;AI - MO。」
论文指出,在 AIME24 等小型基准测试中,结果极不稳定:仅仅改变一个随机种子就足以使得分发生几个百分点的变化。 当在更可控和标准化的设置下评估强化学习模型时,其收益会比最初报告的要小得多,而且通常不具有统计显著性。
然而,一些使用强化学习训练的模型确实表现出了适度的改进,但这些改进通常比监督微调所取得的成果更弱,而且它们通常不能很好地推广到新的基准。
研究者系统分析了造成这种不稳定性的根本原因,包括采样差异、解码配置、评估框架和硬件异质性。我们表明,如果不仔细控制,这些因素会严重扭曲结论。与此同时,研究者提出了一套最佳实践,旨在提高推理基准的可重复性和严谨性。
AI 研究者 Sebastian Raschka 表示:「尽管强化学习在某些情况下可能有助于改进较小的蒸馏模型,但它的好处被夸大了,需要更好的评估标准来了解哪些方法真正有效。此外,这不仅仅是强化学习和推理模型的问题,我认为 LLM 研究整体上都受到了影响。」
探索推理的设计空间:什么最重要?
最近的以推理为重点的语言模型是在非常不同的条件下进行评估的,包括评估框架和硬件、随机种子数量、温度和核采样参数(top_p)的差异(见表 1)。
虽然此前的研究已经考察了采样参数在多选题和编码任务中的影响,但这些选择对开放式推理模型(特别是那些用强化学习训练的模型)的影响仍未得到充分探索。
本文的研究者系统地评估了这些设计选择如何影响性能,并强调了对结果可靠性影响最大的变异来源。
评估中的种子方差
研究者首先分析了评估过程中使用的随机种子所引起的方差,这是基准测试实践中经常被忽视的一个方面。近期的工作尽管要求统计的严谨性(如使用误差棒和多次运行),但评估经常依赖于单种子运行,从而掩盖了潜在的变异性。本文评估了九种模型中,每种模型在 20 次独立评估运行中种子引起的变异。结果如图 2 所示。
可以看到,Pass@1 值的标准偏差出奇地高,各种子的标准偏差从 5 个百分点到 15 个百分点不等。这一问题在 AIME'24 和 AMC'23 中尤为严重,这两个考试分别只有 30 和 40 个测试样本。仅一个问题的变化就会使 Pass@1 偏移 2.5 - 3.3 个百分点。
硬件和软件因素造成的差异
硬件和评估框架等非显而易见的因素也会造成性能差异,但这一点很少得到承认。模型通常在异构系统上进行测试,并使用不同的工具链进行评估。
- 硬件差异
研究者在五个不同的计算集群上对同一模型进行了评估,每个集群的 GPU 类型和内存配置各不相同。
如图 8 所示,在 AIME'24 上,OpenRS - 1.5B 的性能差异高达 8%,DeepSeek - R1 - Distill - 7B 的性能差异为 6%,在 AMC'23 上也观察到了类似的趋势。众所周知,vLLM 等推理引擎对硬件差异非常敏感,而 PyTorch 或 CUDA 中的底层优化可能会引入非确定性,但结果表明,即使对多个种子进行平均,这些影响也会对基准精度产生显著影响。
- 不同 Python 框架下的评估
为了评估这种影响,研究者对 lighteval 和 evalchemy 进行了比较,同时保持所有其他变量固定不变:模型、数据集、硬件、解码参数和随机种子(每个模型 3 个)。
为了进行公平比较,研究者在单个 GPU 上以默认温度和 top_p 参数值对 DeepSeek - R1 - Distill - 1.5B 和 S1.1 - 7B 这两个模型进行了评估。为了提高鲁棒性,本文给出了三个种子的平均结果。
如表 2 所示,框架引起的差异通常很小(1 - 2pp),但在紧密聚类的情况下仍会影响模型排名。
Prompt 格式和上下文长度的影响
最大输出 token。如图 9 所示,减少 max_new_tokens 会降低性能,尤其是在长表单问题上。这种敏感度因模型和数据集而异。虽然减少这一设置可以降低成本,但可能会导致过早停止,从而导致错误答案。
Prompt 格式。提示格式对准确性有显著影响。如图 10 所示,模型在使用数学特定 Prompt 及其本地聊天模板时表现最佳。省略模板会导致性能下降,特别是对于经过指令调优的模型。
(一级)怎么解决?答案是「评估的标准化」
在本节中,研究者将对评估框架进行标准化,并对现有方法进行全面评估。关键结论如下:
- 大多数通过强化学习(RL)训练的 DeepSeek R1 - Distill 模型的变体未能显著提高性能(DeepscaleR 除外),这表明仍缺乏可靠和可扩展的强化学习训练方案。
- 尽管通过强化学习训练的方法通常能显著改善基础模型的性能,但指令调优依然优于强化学习训练的方法(Open Reasoner Zero 除外),这再次表明仍缺乏可靠和可扩展的强化学习训练方案。
- 在较大模型的推理轨迹上进行监督微调可在基准测试中获得显著且可推广的提升,且随着时间推移进展得以成功复制——这突显了其作为训练范式的稳健性和成熟性。
- 当前基于强化学习的方法非常容易过拟合,强调了需要更严格的异域基准测试。相比之下,SFT(监督微调)模型表现出更强的泛化能力和韧性。
- 较长的响应与较高的错误概率相关联,响应长度在 consensus@k 中是识别低置信度或失败生成的一种实用启发式思路。
- 准解码策略似乎足以捕捉模型在有效推理路径上的完整分布,反驳了多样性坍缩假说。
清醒的观察:结果
表 3 展示了实验结果,并对结果的不同方面进行了分析。
研究者在标准化评估环境中,对六个数学推理基准测试进行了模型评估,并针对这些模型的 Pass@1 准确率(均值 ± 标准差)进行了报告。在 AIME 和 AMC 基准测试中,结果采用了十个随机种子的平均值,而其他基准测试则使用了三个随机种子的平均值。研究者采用了 LightEval 框架,并为每种方法调试了最佳超参数。
需要指出的是,除了数学模型的上下文长度为 4096 之外,其他模型的上下文长度均设定为 32768,并使用了适宜的提示模板。同时,基于强化学习(RL)和监督微调(SFT)的模型变体分别针对各自的基础模型或指令调优模型进行了评估。
主要结论如下:
- 通过强化学习训练的方法未能显著提升性能。
- 在推理路径上,SFT 展现了显著的泛化能力。
发现的现象是否可复现?详细分析
研究者进一步调查了最近注意到的两种现象,以验证它们是否在实验中得以复现:
- 响应长度与性能之间的关系。
- 以推理为重点的训练后,响应的多样性是否有所下降。
1、错误响应是否更长?
较长的响应是否意味着错误答案的可能性更高?他们比较了在六个数据集(AIME24、AIME25、AMC23、MATH500、Minerva 和 OlympiadBench)中正确和错误答案的响应长度分布,并在每个模型的随机种子上进行了平均。
图 11 展示了按响应长度分组的每个种子的平均响应数量直方图。
数据显示了一个明显趋势:较短的响应更可能是正确的,而较长的响应则逐渐表现出更高的错误率。这一模式在所有种子中都保持一致,特别是在超过 10000 个 token 的响应中表现得最为显著。研究者就此提出两个关键问题:
Q1:这一模式是否同时适用于基于 RL 和 SFT 训练的模型?
分析结果表明,这一趋势在 RL 和 SFT 训练的模型中均存在。具体而言:
- RL 训练模型(左侧显示)中这一效应更为显著
- SFT 训练模型(右侧显示)中这一效应相对较弱
- Qwen 2.5 Math 基础模型也表现出轻微的长度相关性,但这种相关性在 R1 - distill 及后续的 RL 训练模型中更为突出
Q2. 这种现象是否主要由截断或不完整的响应导致?
尽管接近 32000 token 限制的响应几乎总是错误的(由上下文长度限制所致),但即便是较短的完整响应,这一趋势依然存在——较长的响应与较高的错误概率相关。
2、在推理训练中是否存在多样性坍缩?
为了验证这些主张,研究者比较了 RL 训练模型在所有数据集中的 Pass@k 性能(对于 k∈1, 5, 10)与其相应的基础模型(如 DeepSeek - R1 - Distill - Qwen - 1.5B)。表 4 呈现了各方法的 Pass@k 相对于基础模型的变化情况。
结果显示,并未观察到一致的多样性坍缩现象。Pass@1 的提升通常伴随着 Pass@k 的整体改善,尽管不同指标的提升幅度存在差异。在 Pass@k 性能下降的情况下,这种下降往往与 Pass@1 的偶发性下降同时出现,而非独立发生,这一发现并不支持多样性坍缩的假设。
#MegaMath
3710亿数学tokens,全面开放!史上最大高质量开源数学预训练数据集MegaMath发布
在大模型迈向推理时代的当下,数学推理能力已成为衡量语言模型智能上限的关键指标。
近日,LLM360 推出了 MegaMath:全球目前最大的开源数学推理预训练数据集,共计 3710 亿(371B)tokens,覆盖网页、代码和高质量合成数据三大领域。
- 报告标题:MegaMath: Pushing the Limits of Open Math Corpora
- 技术报告:https://arxiv.org/abs/2504.02807
- 数据集地址:https://hf.co/datasets/LLM360/MegaMath
- GitHub 代码:https://github.com/LLM360/MegaMath
这不仅是首次在规模上超越 DeepSeek-Math Corpus(120B)的开源数据集,更代表从「只靠网页」到「面向推理」的重大跨越。短短数日时间,数据集下载量已经来到 3 万余次,并且持续在 Hugging Face 趋势榜上名列前茅。
MegaMath数据集总览
为什么我们需要 MegaMath?
在现有主流闭源数学语料如 Qwen-2.5-Math(1T)和 DeepSeekMath(120B)持续展现卓越数学能力的同时,开源研究社区长期缺乏等量级、等质量的数学数据。当前可用的开源数据集(如 OpenWebMath、FineMath)规模过小,无法支撑更大规模的模型训练;过滤过度,导致数学样本量缺失多样性不足。
MegaMath和其他数据集的统计数据对比
为解决这一痛点,MegaMath 团队本着「做困难而正确的事情」为目标,以规模 × 质量 × 多样性为核心设计,历时 9 个月时间,构建了全面开放的数学推理数据底座。
MegaMath 数据集共计 3710 亿 tokens,是之前经典开源数学数据,如 OpenWebMath 的约 20 倍。数据集共分为三大部分:
- 2790 亿 tokens:数学密集网页数据(Math-rich Web)
- 281 亿 tokens:数学相关代码(Math Code)
- 640 亿 tokens:高质量合成数据(Synthetic Data)
每部分数据均经过多轮筛选、清洗并通过下游预训练实验充分验证,以确保实用性与泛化能力并存。
构建 MegaMath 的秘方
如何构建这样一个庞大的推理数据集呢?作者将他们主要分为 3 块内容,并精心设计了不同的数据「流水线」,确保高效、高质量的数据开发。
高质量的网页数据构建
MegaMath的网页数据处理流程
为了彻底优化数学文本的处理流程,作者重新下载处理了 2014–2024 年间所有的 99 个 Common Crawl 文件包,并对互联网的数学文本提取进行一系列大量的工程优化来确保数据质量:
- 当前常用的开源文本抽取工具对 HTML 中数学的元素并没有很好地处理,团队因此开发了一套 HTML 结构优化的脚本,在抽取前就提取和优化 LaTeX、KaTeX、mathml 等元素中的公式信息进行重构,以确保在抽取时充分保留文本中的数学符号、公式和定理。
- 由于不同抽取器的处理速度有区别,团队创新地采用了两段式提取方法,第一阶段注重效率,用快速的抽取器进行抽取 + 筛除非数学样本;第二阶段注重精度,用包含更多规则的处理器进一步移除文本噪音和精细筛选出和数学强相关的数据。这使得 MegaMath 最终保留出数学强相关、且更干净的大规模数学文本数据。
- 对于如何训练稳健而准确的文本分类器,团队也发现了因为种子数据收集带来的分布偏移问题,因此在第一阶段的粗筛之后通过重新收集种子数据训练分类器来进行二阶段筛选。
- 考虑到目前研究社区对于续训练(Continual Pre-training)、中期训练(Mid-Training)的广泛需求,作者还利用语言模型对文本的教育价值进行动态打分,再次过滤得到包含极高教育价值的数学子集,并进一步用 LLM 进行精炼,得到了远超开源任何数据集质量的子集;在和现存最高质量的数据 FineMath 进行一对一公平对比时,也能显著超过 4% 的下游性能。
这一系列的工程优化和技术迭代最终形成了:
- MegaMath-Web:包含 263B tokens 的最大规模互联网数学语料
- MegaMath-Web-Pro:包含 15B tokens 的 LLM 优化后的超高质量数学语料
精确的数学代码数据召回
MegaMath-Code的多步召回流程
代码数据被广泛验证,有利于提升模型的数学表现、提升模型利用「生成代码 + 执行求解」范式进行解题的能力。
因此,这是一份宝贵的数据领域。MegaMath 在现存最大的代码预训练数据集 Stack v2 中挖掘了数学相关代码块,同时结合团队之前提出的 Programming Every Example(ProX)方法,利用(1)大模型评分(LLM scoring);(2)微调小模型快速筛选(SLM filtering)的方式,高效清洗出了包括科学计算、符号推理、逻辑程序等领域的代码数据,形成 MegaMath-Code,一个包含 28.1B tokens 的数学相关语料,包含了共 11 种编程语言,进一步加强了数据集的丰富程度。
大规模数学数据合成
MegaMath-Synth的三种大规模合成方法
近年来,合成数据已经成为大模型训练不可缺失的一部分数据;尤其是当传统的数据已经被大量发掘和利用的情况下,合成数据代表了一类可持续被开发的高质量数据源。这在之前的开源预训练数据集中,通常是没有被探索的。
MegaMath 团队积极拥抱合成数据,并开源了预训练规模的高质量文本,包含(1)Q&A 问答形式(解决数学题);(2)合成代码(跨语言转为 Python);(3)文本 + 代码交错数据(更贴近真实解题场景);所有样本都经过质量检测(包括代码块的可执行性校验)。团队通过不断优化 Prompt、简化工程设计,达到在消融实验中表现全面优于现有合成的基线。
效果如何,表现说话
MegaMath-Llama-3.2 1B / 3B的表现在CoT和PAL测试上均提升显著。
MegaMath 不是单纯地「堆数据」拼大小,而是对每一步都进行了严谨验证以确保数据质量。
这包括:(1)文本抽取流程验证;(2)去重策略对比(在机器承受范围内寻求最优的 MinHash 去重策略);(3)fastText 过滤阈值、训练策略调优;(4)代码数据比重 & SLM 召回率消融;(5)合成策略的迭代。
为了检验这些策略,所有的实验都在足够大的尺度下进行了预训练 + 下游评测的验证实验,用来为最终的方案和策略提供足够显著的实验信号。
最终,MegaMath 共进行了超过 50 次的预训练验证,并最终在 Llama-3.2(1B & 3B)上进行了 100B 的预训练。
实验表明,MegaMath 能够在 GSM8K、MATH 等数 10 个标准数学任务上取得 15–20% 的绝对提升。这些数字实打实地说明了 MegaMath 数据集在数学推理上的显著效果。
作者的愿景
作者希望,MegaMath 的发布,能在一定程度上推动开源数学预训练数据集在规模、质量与多样性上的进一步发展,也希望 MegaMath 能成为构建更强数学语言模型的一个坚实起点,激发更多来自学术界与工业界的合作与创新。
在迈向更强推理能力与更高智能上限的过程中,MegaMath 只是初步阶段的尝试。作为一个致力于开放科学与开源研究的团队,团队深知这项工作的挑战与局限,也非常感激开源社区给予的诸多启发与帮助。
特别感谢 Hugging Face、DeepSeek、Qwen 等优秀开源团队长期以来提供的模型、工具和数据方案,让团队有机会站在巨人的肩膀上持续打磨和完善这个工作。
#只因论文「碰瓷」,ICLR 2025区域主席直接拒稿
最强rebuttal,赢回荣耀
1%合成数据,就能让AI模型瞬间崩溃!如此颠覆性发现,只因未引用他人论文,ICLR区域主席直接拒稿,好在作者成功rebuttal,论文最终选为Spotlight。而背后,竟是一桩图灵奖得主Yann Lecun关注的学界争议!
ICLR 2025,公开审稿,多级反转!
只因没有引用COLM 2024会议的一篇论文,区域主席根据公开评论,竟建议拒绝投稿论文!
虽然最终论文《强模型崩溃》(Strong Model Collapse)被接受,并选为亮点论文(Spotlight),但过程可谓危险至极!
去年,该论文在Arxiv上公开,动摇了对合成数据的认知,迎来了大波关注。
来自Meta等研究机构证实:1%合成数据,就能让模型瞬间崩溃。
作者将文章投稿ICLR 2025后,审稿人对这篇论文的评价一致为正面。
区域主席(Area Chair),基于公开评论建议拒绝该论文,只因缺少对COLM 2024论文的引用。
即便在OpenReview上的私下讨论(公众无法查看)中,审稿人最终决定,缺少这篇引用不能成为拒绝的唯一依据。
但区域主席推翻了审稿人的意见,建议拒绝了此论文。
收到投诉后,ICLR决定审查此案。
调查后,一致决定支持审稿人的意见,因此最终接受了这篇论文。
任何平均得分高于阈值的论文,将自动考虑作为亮点论文。
评审意见主页:https://openreview.net/forum?id=et5l9qPUhm
公开评审:李鬼倒打李逵?
对ICLR论文提出疑问的斯坦福大学CS博士生Rylan Schaeffer,他是COLM 2024下列论文的作者。
他强调,ICLR 2025的论文《强模型崩溃》作者,故意不引用COLM 2024论文:
1.他们明确知晓有一篇先前的已发布工作,直接与他们的叙述和科学主张相矛盾;
2.他们使用了该先前工作中提出的方法论,而同时又侮辱了该工作并未给予应有的致谢。
他坚持认为ICLR 2025投稿论文是故意压制矛盾证据,混淆对模型崩溃(潜在)危害的理解。
ICLR的作者就是赤裸裸的学术不端,是科学界的耻辱!
特别是对于ICLR没有引用他写作的COLM 2024论文,他认为这无法忍受。
我们恳请评审专家和区域主席要求《强模型崩溃》的作者解决以下问题:
1.此项工作与现有关于避免模型崩溃文献的关系,
2.如何解释看似矛盾的结论产生的不同建模假设,以及哪种假设最能反映现实场景。
评估哪些假设最符合现实场景对于评估这项工作的实际影响至关重要。
在去年,Rylan Schaeffer就表示,如果对模型崩溃(model collapse)有兴趣,强烈要求阅读他们的COLM 2024论文。
反驳:Rylan Schaeffer才是抄袭者
在得到会议程序委员会及历任主席一致认同后,ICLR论文一作Elvis Dohmatob,在X上公开回应了Rylan Schaeffer的指责,认为Rylan Schaeffer存在严重的不当行为:
抄袭我们的先前工作,
论文内容主要由人工智能生成(是的,作者将我们的论文输入到LLM中生成了另一篇论文),
违反伦理审查委员会(IRB)规定等。
在长时间的双方沟通中,这些问题逐步被揭露出来。
在帖子后,ICLR 2025官方账号,澄清了提交论文4488评审的过程,真如开头所言。
NYU教授还原全过程
去年,《强模型崩溃》的作者Julia Kempe和「李鬼」Rylan Schaeffer多次沟通,公开了论文其他作者的道歉邮件。
特别是,模型崩溃、混合原始数据与合成数据等领域已有很多优秀论文的情况下(包括在《自然》杂志上发表的文章),当Gerstgrasser等人首次向发送他们《模型崩溃是不可避免的吗?》的v1版本时,很少有对一发表论文的相关讨论。
甚至有Rylan Schaeffer的合著者表示论文粗制滥造, 就是赶鸭子上架:
他们斯坦福的导师跟他们来往并不密切。
学生赶在截止日期前,马上提交论文。我们对论文粗制滥造的关切,几乎被漠视了。
可悲的是,这已经成为他们的文化的一部分。
至于没有引用相关论文的原因,我直到现在仍然不明白。
更加惊讶的是,「李鬼」Rylan Schaeffer所谓的「模型坍塌必读理论」,是Julia Kempe之前定理的一个微不足道的推论,而且Rylan Schaeffer的论文还具有误导性。
但奇怪的是,这些公式化的表述与论文中的语言相似,符号也古怪地相似:
左:「李逵」的论文符号,右:「李鬼」的论文符号
然而,随后Julia Kempe等明白了!
在指出了最明显的遗漏后,「李鬼」论文的作者等人发送了一份报告,暗示Julia Kempe等人的反馈,被AI用来合成论文。
Julia Kempe等人被当作免费劳动力使用,这令Julia Kempe大开眼界!
但可悲的是,Rylan Schaeffer等人的论文虽被COLM 2024接受,但仍然包含误导性结论。
在涉及到个人学术声誉的斗争中,Julia Kempe也得到了同事的支持,甚至得到了图灵奖得主、AI大佬Yann Lecun的关注和支持!
模型崩溃与合成数据
双方的焦点在于「模型崩溃」。
第1点:关于Gerstgrasser等人的论文与先前工作的科学矛盾。
Gerstgrasser等人的论文,并没有以任何有意义的方式避免模型崩溃。
正方Julia Kempe等人,在ICLR 2025论文中,明确将「模型崩溃」定义为「AI模型性能的重大下降」。
避免模型崩溃意味着:缩小使用真实数据和合成数据训练时的性能差距。
反方Rylan Schaeffer、Gerstgrasser等人,将避免模型崩溃定义为:「在多次训练模型时,防止发生递归性退化」。
该论文承认,尽管当样本逐渐积累时,性能退化是有界的,但仍然存在性能损失。
这一定义仅代表了缩小真实数据和合成数据之间差距的部分条件。从这个意义上讲,Gerstgrasser等人并未解决或缓解模型崩溃问题。
在关于模型崩溃的大多数文献中,主流观点认为,缩小性能差距是避免模型崩溃的主要标准。
从实际角度来看,缩小真实数据与合成数据之间的差距,是避免模型崩溃的更具操作性和相关性的定义。
仅仅确保性能不出现发散,仍然可能导致模型无法匹配合成数据生成器的质量,从而使合成数据对性能造成损害。
只有当性能差距完全缩小时,合成数据的负面影响才能完全减轻。
由于定义和理由上的差异,考虑到缩小性能差距是正确的定义,通过这一广泛接受的视角,正方Julia Kempe等人已经重新审视了所有关于模型崩溃的相关工作。
第二点:与Gerstgrasser等人的先前互动
不幸的是,公开评论似乎破坏了审稿过程的匿名性。
正反双方的确有过互动。
以下是该互动的简要总结:
- 技术上不足:Gerstgrasser等人的论文只是增量性的技术贡献,而且非常薄弱。它不过是对已有论文的已有设定和论点的轻微修改。其结果是已有定理的简单推论。
- 误导性/不准确的结论:Gerstgrasser等人的论文并未以任何合理的方式解决模型崩溃问题(请参见上文关于定义的讨论)。
不幸的是,Gerstgrasser等人,基本上忽视了互动的建设性批评,甚至将评论仅作为脚注,附在论文的末尾。
因此,在目前的状态下,正方仍然认为Gerstgrasser等人的论文,在科学上并不成立,因此没有觉得有必要引用。
最终的论文结果,说明荣耀应该归于Julia kempe等人。
这也与此前领域内专家的意见一致。
参考资料:
https://x.com/dohmatobelvis/status/1911107171078615088
https://x.com/KempeLab/status/1817135401124934089
https://x.com/RylanSchaeffer/status/1911153029509992859
#OceanBase首届AI黑客松广发英雄帖
10万奖金×认知升级!你敢来么?
从 ChatGPT 引发认知革命到 GPT-4o 实现多模态跨越,AI 技术的每次跃迁都在印证一个底层逻辑 —— 数据质量决定智能高度。而今,这场 AI 浪潮正在反哺数据库领域,推动其从幕后走向台前,完成智能时代的华丽转身。
在 DB+AI 的舞台上,作为分布式数据库的领军者, OceanBase 正凭其一体化架构重新定义 AI 原生数据库。例如,HTAP 打破 TP 与 AP 的次元壁,既能高速支持海量交易,又能实时解析数据背后的商业密码。SQL + AI 一体化,使得数据库既能以 SQL 语言精准执行指令,还能理解自然语言背后的业务意图。
当数据库遇上 AI,OceanBase 看到的不是终点,而是新世界的起点 —— 未被发掘的可能性仍如星海般璀璨。技术的温度在于共享,未来的高度源于共创。这个春天,OceanBase 诚邀大家用代码书写 "DB+AI" 的全新方程式,用 AI 玩转 OceanBase。
4 月 10 日,OceanBase 与蚂蚁开源联合主办、协办的 AI 黑客松大赛已经开启报名。这是一场属于所有技术探索者的盛宴 —— 无论你是经验丰富的 "老炮",还是初出茅庐的 "AI 新锐",10 万奖池与无限可能,都在这个舞台等你来战!
今晚,也将直播 OceanBase 首届AI黑客松大赛启动仪式,讲解比赛规则,速来预约直播间了解相关内容。
观看直播
OceanBase AI 黑客松
一、赛题及作品要求
为了激发开发者无限潜能、深入挖掘 OceanBase 与 AI 技术深度融合全新可能,打造出具有卓越实际应用价值的产品或解决方案,本次黑客松以 AI 为核心主题,重点设置以下赛题。参赛者可以任选方向或自由发挥,展开创新探索!
方向一:使用 OceanBase 数据库作为 DATA 基座构建你的 AI 应用
如:利用 OceanBase 数据库作为数据基座,存储用户行为和语义向量,拓展 OceanBase 的智能化能力,实现自动化数据治理、智能交互和高效检索,推动数据库技术的创新应用。
方向二:「技术开放 + 生态共创」,探索 OceanBase+AI 的更多可能
如:和 CAMEL AI、FastGPT、OpenDAL 等项目共建生态,构建围绕 OceanBase 及其周边生态的问答系统、诊断系统、语义搜索和文档分类等 AI 应用,探索 OceanBase+AI 的无限可能。
二、把握赛程节点
三、重磅奖项设置
- 特别激励:成功提交有效代码的团队 ——
每位成员均可获得 OceanBase 社区的 100 积分(积分将于黑客松结束后统一发放)。
获官方联合推广资源:如开发者大会线下展示机会、成为 OceanBase 认证讲师、专享博客专栏。
- 注意事项
各奖项中的奖金为团队奖,由团队实际人数确认最终的人均获奖额度。
用户获得的奖励依法需代扣代缴相应税款,OceanBase 将根据税务法律法规要求,向税务机关提供必要的税务申报信息(包括您的身份信息、现金奖励金额等税务机关要求的信息),并由 OceanBase 依法为您完成相应税款的代扣代缴。
四、报名及评审方式
个人和团队均可报名参与首届 OceanBase AI 黑客松大赛。比赛期间,导师团全程在线答疑。最终获奖作品将亮相 2025 OceanBase 开发者大会颁奖盛典,并在展区展示。
1、如何报名?
扫描下方二维码:
或浏览器中复制以下链接报名:
https://open.oceanbase.com/ai-hackathon?activityCode=4923294&officerId=4180
2、谁可以报名?
个人 / 团队均可报名,导师团全程助力,技术专家在线答疑,还有机会与 AI 领域权威专家、技术负责人面对面交流。
3、报名时间:
2025 年 4 月 10 日 - 2025 年 5 月 7 日
4、参赛方式
- 单独参赛或组队参赛:每队人数为 1-5 人,组队参赛需指定 1 名队长。
- 注册与审核:所有参赛者需在 OceanBase 官网注册账户,报名截止后将对报名资料进行审核,请确保信息真实准确。
5、作品提交
初赛作品提交需包括 RFC、演示视频和 PPT,具体如下:
6、评审标准
本次评委团将从创新性、价值和影响力、功能完整性、设计、技术挑战、演示质量等对开发者提交的作品进行评审,初赛获胜者名单将在 5 月 13 日公布。
(后续公布重磅评委团队,敬请期待!)
五、沟通与支持
大赛专属微信群:请务必加入,以便招募队友、交流想法、接收赛事通知并参与答疑。
技术支持:OceanBase 提供专属技术支持,问题请发布在论坛专属板块:
https://ask.oceanbase.com/c/competition/88-category/88
学习资源
👉 OceanBase 官方文档:
https://www.oceanbase.com/docs/oceanbase-database-cn
👉 OceanBase GitHub:
https://github.com/oceanbase
👉 OceanBase AI workshop:
https://github.com/oceanbase-devhub/ai-workshop-2024
👉 OceanBase 快速上手:
https://open.oceanbase.com/quickStart
👉 OceanBase AI 助手:
https://www.oceanbase.com/obi
👉 CAMEL AI GitHub:
https://github.com/camel-ai
👉 FastGPT GitHub:
https://github.com/labring/FastGPT
👉 OpenDAL GitHub:
https://github.com/apache/opendal
#更长思维并不等于更强推理性能,强化学习可以很简洁
今天早些时候,著名研究者和技术作家 Sebastian Raschka 发布了一条推文,解读了一篇来自 Wand AI 的强化学习研究,其中分析了推理模型生成较长响应的原因。
他写到:「众所周知,推理模型通常会生成较长的响应,这会增加计算成本。现在,这篇新论文表明,这种行为源于强化学习的训练过程,而并非更高的准确度实际需要更长的答案。当模型获得负奖励时,强化学习损失函数就倾向于生成较长的响应,我认为这能解释纯强化学习训练为什么会导致出现顿悟时刻和更长思维链。」
也就是说,如果模型获得负奖励(即答案是错的),PPO 背后的数学原理会导致响应变长,这样平均每个 token 的损失就更小一些。因此,模型会间接地收到鼓励,从而使其响应更长。即使这些额外的 token 对解决问题没有实际帮助,也会出现这种情况。
响应长度与损失有什么关系呢?当使用负奖励时,更长的响应可以稀释每个 token 的惩罚,从而让损失值更低(即更好 —— 即使模型仍然会得出错误的答案。
因此,模型会「学习」到:即使较长的回答对正确性没有帮助,也能减少惩罚。
此外,研究人员还表明,第二轮强化学习(仅使用一些有时可解的问题)可以缩短回答时间,同时保持甚至提高准确度。这对部署效率具有重大意义。
以下是该论文得到的三大关键发现:
- 简洁性与准确度之间的相关性:该团队证明,在推理和非推理模型的推断(inference)过程中,简洁的推理往往与更高的准确度密切相关。
- 对 PPO 损失函数的动态分析:该团队通过数学分析,建立了响应正确性与 PPO 损失函数之间的联系。具体而言,研究表明,错误的答案往往会导致响应较长,而正确的答案则倾向于简洁。
- 有限的数据:该团队通过实验证明,即使在非常小的数据集上,强化学习的后训练阶段仍然有效,这一结果与文献中的当前趋势相悖,并且强化学习后训练在资源受限的场景下也是可行的。
有研究者认为这项研究揭示了强化学习存在的一个普遍问题:训练的目标只是为了获得奖励,而并非是解决问题。
下面我们就来具体看看这篇论文。
- 论文标题:Concise Reasoning via Reinforcement Learning
- 论文地址:https://arxiv.org/abs/2504.05185
响应更长≠性能更好
下表展示了使用不同模型在不同基准测试上,答案正确或错误时的平均响应长度。蓝色小字表示用于计算所得平均值的样本数。
由此可知,更长响应不一定能带来更好的性能。
于是问题来了:使用 RL 训练的 LLM 倾向于在什么时候增加响应长度?原因又是为何?
每个推理问题都是一个 MDP
从根本上讲,每个推理问题(例如,数学问题)都构成了一个马尔可夫决策过程 (MDP),而不仅仅是一个静态样本。
MDP 由状态空间 S、动作空间 A、转换函数 T、奖励函数 R、初始状态分布 P_0 和折扣因子 γ 组成。
在语言建模中,每个 token 位置 k 处的状态由直到 k 为止并包括 k 的所有 token(或其嵌入)组成,另外还包括上下文信息(例如问题陈述)。动作空间对应于可能 token 的词汇表。转换函数可确定性地将新的 token 附加到序列中。除了最后一步之外,所有步骤的奖励函数都为零。在最后一步,正确性根据最终答案和格式进行评估。初始状态取决于提示词,其中可能包含问题陈述和指令(例如,「逐步求解并将最终答案放入方框中」)。强化学习的目标是最大化预期回报,预期回报定义为根据 γ 折扣后的未来奖励之和。在 LLM 的后训练中,通常将 γ 设置为 1。
为了在仅提供最终答案的情况下解决问题,需要一个能够偶尔得出正确答案的基础模型。在对多个问题进行训练时,整体 MDP 由多个初始状态和更新的奖励函数组成。添加更多问题会修改 P_0 和 R,但会保留基本的 MDP 结构。
这会引入两个重要的考虑因素:(1) 更大的问题集会增加 MDP 的复杂性,但这可能会使所学技术具有更高的泛化能力。(2) 原理上看,即使是单个问题(或一小组问题)也足以使强化学习训练生效,尽管这可能会引发过拟合的问题。
过拟合是监督学习中的一个问题,因为模型会记住具体的例子,而不是进行泛化。相比之下,在线强化学习则不会受到这个问题的影响。与依赖静态训练数据的监督学习不同,在线强化学习会持续生成新的响应轨迹,从而使模型能够动态地改进其推理能力。此外,在线强化学习不仅仅是模仿预先定义的解答;它还会主动探索各种推理策略,并强化那些能够得出正确答案的策略。
两种关键机制促成了这种稳健性:(1) 采样技术(例如非零温度)可确保生成的响应具有变化性;(2) 训练期间持续的模型更新会随着时间的推移引入新的响应分布,从而防止训练停滞和过拟合。
这能解释在小规模问题集上进行强化学习训练会保持有效性的原因。该团队表示,之前还没有人报告过将强化学习训练应用于极小数据集的研究,这也是本研究的贡献之一。
除了数据大小的考虑之外,需要强调的是,强化学习的唯一目标是最小化损失,这也就相当于最大化预期回报。从这个角度来看,强化学习训练过程中响应长度的任何显著变化都必然是由损失最小化驱动的,而非模型进行更广泛推理的固有倾向。
为了进一步研究这一点,该团队基于 DeepSeek-R1-Distill-Qwen-1.5B 基础模型,使用近端策略优化 (PPO) 算法进行了强化学习训练。训练数据是从 OlympiadBench 数据集中选择的四个问题。
之所以特意选择这些问题,是因为即使进行了广泛的采样,基础模型也始终无法解决这些问题,导致终端奖励恒定为 -0.5。其上下文大小限制为 20K token,该团队绘制了策略损失与响应长度的关系图(参见图 1)。
结果清楚地表明,响应长度和损失之间存在很强的相关性:随着响应长度的增加,损失持续下降。这直接证明:损失最小化(而非模型产生更长响应的内在趋势)才是驱动响应长度增长的主要动力。
对于 PPO 对响应长度的影响,该团队也从数学角度进行了解释。详见原论文。
一种两阶段强化学习策略
该团队的分析突出了几个要点。
- 当在极其困难的问题训练时,响应长度往往会增加,因为较长的响应更有可能受到 PPO 的青睐,因为模型难以获得正回报。
- 当在偶尔可解的问题上训练时,响应长度预计会缩短。
- 在大规模训练场景中,响应长度的动态会变得非常复杂,并会受到底层问题难度的巨大影响。
该团队认为,由于大多数问题至少偶尔可解,因此平均响应长度最终会减少。值得注意的是,该团队目前的分析不适用于 GRPO,对此类方法的精确分析还留待未来研究。尽管如此,由于简洁性与更高准确度之间的相关性,该团队推测:如果训练持续足够长的时间,这种增长最终可能会停止并开始逆转。
如果数据集包含过多无法解决的问题,那么从「鼓励响应更长」到「鼓励简洁性」的转变可能会大幅延迟且成本高昂。
为了解决这个问题,该团队提出了一种新方法:通过一个后续强化学习训练阶段来强制实现简洁性,该阶段使用了偶尔可解问题的数据集。于是,就能得到一种两阶段的强化学习训练方法:
在第一阶段,用高难度问题训练模型。此阶段的目标是增强模型解决问题的能力,由于 PPO 主要会遇到负奖励,从而促使模型产生更长的响应,因此响应长度预计会增加。值得注意的是,第一阶段也可被视为现有推理模型的强化学习训练。
在第二阶段,使用非零 p_a(偶尔可解)的问题继续训练。此阶段能在保持甚至提高准确度的同时提升简洁性。值得注意的是,正如后面将看到的,它还能显著提高模型对降低温度值的稳健性 —— 即使在有限的采样量下也能确保卓越的性能。
从 MDP 的角度,该团队得到了一个关键洞察:即使问题集很小,也可以实现有效的强化学习训练,尽管这可能会降低泛化能力。尤其要指出,在训练的第二阶段 —— 此时模型已经具备泛化能力,即使仅有只包含少量问题的极小数据集也可使用 PPO。
实验结果
该团队也通过实验检验了新提出的两阶段强化学习训练方法。
问题难度如何影响准确度-响应长度的相关性
图 2 给出了准确度和响应长度随训练步数的变化。
可以看到,在所有问题集中,准确度的提高与响应长度的缩短相一致 —— 这表明随着模型准确度的提高,其响应长度也随之缩短。此外,对于更简单的问题集,响应长度缩短得更快。最后,对于最难的数据集,由于问题很少能够解决,因此响应长度有所增加。
响应长度减少
图 3 展示了在不同的测试数据集(AIME 2024、AMC 2023 和 MATH-500)上,经过后训练的 1.5B 和 7B 模型的准确度和响应长度随训练步数的变化情况。
可以看到,新提出的两阶段强化学习训练方法会让响应长度显著下降,同时准确度会保持稳定。而右图在 MMLU_STEM 上的结果更是表明:仅使用 8 个样本,强化学习后训练也能带来准确度提升。
性能和稳健性的提升
前面的实验结果已经证明:进一步的强化学习后训练可以在保持准确度的同时缩短响应长度。该团队进一步研究发现:进一步的强化学习后训练也能提升模型的稳健性和性能。
为了评估模型的稳健性,该团队检查了它们对温度设置的敏感性。将温度设置为零会大幅降低 R1 等推理模型的准确度。然而,诸如 pass@1 之类的标准指标依赖于非零温度下的多个样本,这通常会掩盖在小型数据集上进行二次强化学习后训练的优势。
该团队使用 0 和 0.6 的温度值进行了实验,结果见表 3。
可以看到,当温度设置为 0 时,经过后训练的模型的表现显著优于基线模型,这表明经过后训练的模型与基线模型相比更加稳健。
该团队还表明,在有限数量的样本上进行进一步的强化学习训练可以显著提升准确度。这种效果取决于先前在类似(甚至相同)问题上进行过的强化学习训练程度。如果模型已经进行过大量强化学习训练,可能就更难以进一步提升准确度。
为了探究这一点,该团队基于 Qwen-Math-v2.5 使用了在线强化学习进行实验,训练样本是来自 MATH 数据集的 4 个样本。不同于 R1,该模型之前并没有经过强化学习训练,而是仅在大量数学数据上进行了 token completion 训练。结果见表 4。
可以看到,提升很惊人!在 1.5B 模型上,提升高达 30%。这表明,就算仅使用 4 个问题进行强化学习后训练,也能得到显著的准确度提升,尤其是当模型之前未进行过强化学习推理优化训练时。
参考链接https://x.com/rasbt/status/1911494805101986135
#GenPRM
过程奖励模型也可以测试时扩展?清华、上海AI Lab 23K数据让1.5B小模型逆袭GPT-4o
赵俭,北京邮电大学本科三年级,研究方向为大语言模型。刘润泽,清华大学硕士二年级,师从李秀教授,研究方向为大语言模型与强化学习,特别关注大模型推理能力增强与测试时间扩展,在 NeurIPS、ICML、ICLR、AAAI 等顶级学术会议发表多篇论文,个人主页:ryanliu112.github.io。
随着 OpenAI o1 和 DeepSeek R1 的爆火,大语言模型(LLM)的推理能力增强和测试时扩展(TTS)受到广泛关注。然而,在复杂推理问题中,如何精准评估模型每一步回答的质量,仍然是一个亟待解决的难题。传统的过程奖励模型(PRM)虽能验证推理步骤,但受限于标量评分机制,难以捕捉深层逻辑错误,且其判别式建模方式限制了测试时的拓展能力。
那么,是否有办法通过测试时拓展提升过程奖励模型的过程监督推理能力呢?
为此,清华大学联合上海 AI Lab 提出生成式过程奖励模型 ——GenPRM,将生成式思维链推理(CoT)与代码验证相结合,并引入测试时拓展机制,为过程监督推理提供了新思路。与 DeepSeek 近期发布的逐点生成奖励模型(GRM)类似,GenPRM 也通过生成式建模和测试时扩展增强奖励模型的推理能力,但 GenPRM 更专注于过程奖励模型,弥补了 GRM 在过程监督方面的不足。
- 论文标题:GenPRM: Scaling Test-Time Compute of Process Reward Models via Generative Reasoning
- 论文链接:http://arxiv.org/abs/2504.00891
- 项目链接:https://ryanliu112.github.io/GenPRM
- GitHub:https://github.com/RyanLiu112/GenPRM
- HuggingFace:https://huggingface.co/GenPRM
在 ProcessBench 等数学推理基准的测试中,GenPRM 展现出惊人实力:仅 1.5B 参数的模型通过测试时扩展超越 GPT-4o,而 7B 参数版本更是击败 72B 参数的 Qwen2.5-Math-PRM-72B,同时表现出强大的步骤级批评能力。
GenPRM:从评分到推理,再到测试时扩展
现有过程奖励模型依赖分类器式的标量评分,这种 “黑箱” 机制导致两个核心问题:一是无法解释错误根源,仅能判断步骤 “对错”,却无法解释 “为何错”,二是无法通过增加模型测试时间计算资源提升判断精度。
生成式过程奖励模型
为了突破这些瓶颈,GenPRM 引入生成式设计,彻底革新过程监督范式:
- 思维链推理:GenPRM 模拟人类解题时的逻辑推导,对每一步推理进行自然语言分析,提供透明、可解释的步骤评估。
- 代码验证:为确保推理的可靠性,GenPRM 还会生成并执行对应数学运算的 Python 代码,将文字推导与实际计算结果交叉验证。例如,在求解三角函数表达式时,模型先分析角度转换的合理性,再通过代码计算具体数值,避免 “符号推导正确但计算失误” 的情况。
其奖励推理过程可以表示为:
其中 s_t 为当前状态,a_t 为当前步骤,v_1:t−1 和 f_1:t-1 分别为之前步骤的推理过程和代码执行反馈,v_t 和 f_t 为当前步骤的推理与反馈。这种 “先解释、再验证” 的机制不仅能判断对错,还能提供步骤级别的批评改进建议和严谨准确的反馈,大幅提升了过程监督的深度和实用性。
测试时扩展
在推理阶段,GenPRM 通过并行采样 N 条推理路径,综合多条路径的奖励值并取平均,得到最终奖励:
这种策略充分利用额外计算资源,进一步提升评估精度,使小模型也能在复杂任务中表现出色。
数据高效:23K 样本背后的合成秘密
GenPRM 的另一个亮点是仅使用 23K 训练样本就取得了优异的性能,远少于许多模型动辄数十万级的数据量(如 PRM800K 需 80 万人工标注),其高效性源于独特的数据合成方法,结合相对进步估计(RPE)和代码验证,生成高质量的过程监督数据。
通过相对进步估计改进硬估计
传统过程奖励模型通过蒙特卡罗(MC)分数进行硬估计,研究者观察到尽管许多步骤的 MC 分数大于 0,但这些步骤是却存在错误。RPE 通过比较当前状态和上一状态的 MC 分数,用 “进步幅度” 评估每步质量,比传统硬标签更准确。其形式化如下:
其中,MC (s_t, a_t) 表示当前步骤的蒙特卡罗分数,MC (s_t) 表示上一步骤的蒙特卡罗分数。若进步幅度低于阈值(ϵ=0.8),则判定步骤无效;若首步错误(MC 为 0),后续步骤分数归零。这种方法显著提升标签准确性,避免了硬估计的误判。
代码验证驱动的数据合成
研究者利用 QwQ-32B 模型合成 CoT 和代码验证推理数据,通过在 Python 环境中真实执行代码重复检验 CoT 推理过程。使用共识过滤(过滤率 51%),保留高质量过程监督数据,最终得到 23K 训练数据集。
测试时扩展:小模型的逆袭
在 ProcessBench 过程监督基准测试中,GenPRM 展现出显著优势:
- 仅用 23K 训练数据的 1.5B GenPRM,通过多数投票(Maj@8)的测试时计算扩展策略,其 F1 分数超越 GPT-4o;
- 7B 版本的 GenPRM 以 80.5% 的 F1 分数一举超过 72B 参数的 Qwen2.5-Math-PRM-72B。
这一结果证明,测试时扩展能有效放大过程奖励模型的能力,使小模型实现性能飞跃。
此外,GenPRM 同样适用于策略模型测试时扩展。通过 Best-of-N 实验,GenPRM-7B 展现出相比于基线方法更加优异的筛选能力,并可通过测试时扩展进一步增强过程监督能力。
从验证器到批评者:过程奖励模型新范式
GenPRM 不仅能当 “裁判”,作为验证器(Verifier)筛选答案,还能当 “教练”,作为步骤级别的批评模型(Critic)指导策略模型迭代优化原始回答。实验表明,GenPRM 通过 3 轮反馈将策略模型的回答准确率从 45.7% 提升至 51.5%,性能提升达到基线方法的 3.4 倍。
这种 “生成 - 批评 - 反思” 的闭环,验证了 GenPRM 不仅可以作为验证器验证答案的准确性,还可以作为批评者,为模型完善自身输出提供逐步关键指导,为大语言模型的自我改进提供了可解释的技术路径。
研究者已开源代码、模型及 23K 训练数据集。该工作为大语言模型的可解释过程监督提供了新思路,未来可扩展至代码生成、多模态推理等领域。
#Curr_REFT
中科大、中兴提出新后训练范式:小尺寸多模态模型,成功复现R1推理
本文第一作者为邓慧琳,中国科学技术大学硕博连读四年级,研究方向为多模态模型视觉理解、推理增强(R1强化学习)、异常检测。在TAI、TASE、ICCV等期刊和顶会发表论文。
近年来,随着大型语言模型(LLMs)的快速发展,多模态理解领域取得了前所未有的进步。像 OpenAI、InternVL 和 Qwen-VL 系列这样的最先进的视觉-语言模型(VLMs),在处理复杂的视觉-文本任务时展现了卓越的能力。
然而,这些成就主要依赖于大规模模型扩展(>32B 参数),这在资源受限的环境中造成了显著的部署障碍。因此,如何通过有效的后训练(post-training)范式来缩小小规模多模态模型与大规模模型之间的性能差距,是亟待解决的问题。
目前,VLM 的主流训练方法是监督微调(SFT),即使用人工标注或 AI 生成的高质量数据对模型进行有监督训练。但这种方法在小模型上存在两个关键问题:
域外泛化能力不足(Out-of-Domain generalization collapse):容易过拟合训练数据,在未见过的场景时性能显著下降。
- 推理能力有限(shallow reasoning abilities):倾向于浅层模式匹配,而非真正的理解和推理。这导致模型虽能应对相似问题,但难以处理需要深度思考的复杂问题。
图 1. 实验结果分析。 (a) SFT 与 RL 方法性能对比:通过对比域内和域外性能,实验证实了强化学习方法在各类视觉任务中具有更强的 OOD 泛化能力。 (b) "砖墙"现象分析:在小规模 VLMs 中观察到:面对复杂样本时出现训练不稳定性,模型最终收敛到次优解。我们提出的课程强化学习方法采用难度感知的奖励设计,确保模型能力从基础任务到复杂推理任务的稳步提升。
通过系统实验,我们发现基于强化学习的训练方法在提升模型域外泛化性方面具有独特优势。
然而,在实践中我们观察到一个显著的「砖墙」(Brick Wall)现象:小规模模型在简单任务上快速进步,但在复杂任务上遇到瓶颈,甚至导致已掌握能力的退化。这种现象表现为训练过程的剧烈震荡,最终导致模型收敛到次优解。
为突破这一瓶颈,我们从课程学习(Curriculum Learning, CL)中汲取灵感。课程学习是一种将模型逐步暴露于递增复杂任务的训练策略。我们提出了课程式强化学习后训练范式(Curr-ReFT),确保模型能力从基础任务到复杂推理任务的稳步提升。
这一创新方法能够帮助小型 VLMs 突破性能瓶颈,在保持部署友好性的同时,实现与大规模模型相媲美的推理能力。
- 论文标题: Boosting the Generalization and Reasoning of Vision Language Models with Curriculum Reinforcement Learning
- 论文链接:https://arxiv.org/pdf/2503.07065
- 开源链接:
- https://github.com/ding523/Curr_REFT(代码)https://huggingface.co/datasets/ZTE-AIM/Curr-ReFT-data(数据)https://huggingface.co/ZTE-AIM/3B-Curr-ReFT(模型权重)https://huggingface.co/ZTE-AIM/7B-Curr-ReFT(模型权重)
工作概述
在中小尺寸多模态大模型上,我们成功复现了 R1,并提出了一种创新的后训练范式 Curr-ReFT。通过结合课程强化学习和基于拒绝采样的自我改进方法,我们显著提升了视觉语言模型(VLM)的推理能力和泛化能力。
理论与实验分析
- 强化学习的重塑能力:我们证明了基于规则的强化学习能够有效重塑多模态/CV 任务的训练方案,从传统的精调转向强化精调。
- 提升推理与泛化能力:实验结果显示,强化学习方法显著提升了 VLM 在分布外数据上的表现。
创新框架
- Curr-ReFT:我们提出了一种新型后训练范式,结合课程强化学习和自我改进策略。在 Qwen2.5-VL-3B 和 Qwen2.5-VL-7B 模型中验证了其有效性。
全面评估
在多个自建数据集和权威基准测试上进行对比实验,验证了模型的通用表现,结果表明 7B 模型甚至超越了最新的 InternVL2.5-26B 和 38B 模型。
具体方法
图 2. 所提出的 Curr-ReFT 后训练范式整体框架。Curr-ReFT 包含两个连续的训练阶段:1.课程强化学习:通过与任务复杂度匹配的奖励机制,逐步提升任务难度。2.基于拒绝采样的自我改进:维持 LLM 模型的基础能力。
Curr-ReFT 包含两个连续的训练阶段:
- 课程强化学习:通过难度感知的奖励设计确保模型能力的稳步提升,从基础的视觉感知逐步过渡到复杂的推理任务。
- 基于拒绝采样的自我改进:通过从高质量的多模态和语言样本中进行选择性学习,维持 VLMs 的基础能力。
图 3. 训练数据组织架构图。 (a) 课程强化学习的三阶段渐进式响应格式示例。展示了任务从简单到困难的递进过程,呈现不同阶段的响应格式变化。 (b) 拒绝采样 SFT 阶段使用的数据来源分布。
Stage1:课程强化学习(Curriculum Reinforcement Learning)
课程学习(Curriculum Learning,CL)作为一种教学式训练策略,其核心思想是让模型循序渐进地接触复杂度递增的任务。
针对强化学习中普遍存在的训练不稳定性和收敛性问题,我们创新性地将课程学习与 GRPO 相结合,突破了传统基于样本难度评估的局限,转而关注任务层面的渐进式学习。
本研究的关键创新点在于设计了难度感知的奖励机制,该机制与任务的自然进阶路径相匹配,具体包括三个递进阶段:
- 二元决策阶段(Binary Decision)
- 多项选择阶段(Multiple Choice)
- 开放式回答阶段(Open-ended Response)
这一课程强化学习(Curr-RL)框架通过精确校准任务复杂度对应的奖励机制,成功实现了视觉感知和数学推理任务的稳定优化过程。
Stage2:拒绝采样自我增强(Rejected Sample based Self-improvement)
数据准备过程涉及对综合数据集的系统采样。我们使用 GPT-4-O 作为奖励模型,从多个维度评估生成的响应,评估标准包括:准确性、逻辑一致性、格式规范性、语言流畅度。
所有响应在 0-100 分范围内进行量化评估。得分超过 85 分的响应及其对应的问题会被纳入增强数据集。最终整理的数据集包含 1,520 个高质量样本,涵盖多个领域:数学、科学、通用场景的通用知识。数据分布如下:
1、数学领域(共 700 条数据):
- 多模态数据(300 条):
- Geometry3K_MathV360K(100 条)
- Geo170k_qa(100 条)
- Geomverse(100 条)
- 纯文本数据:
- SK1.1 数学题(400 条)
2、科学领域(共 320 条数据):
- 多模态数据(220 条):
- Scienceqa_cauldron(100 条)
- Scienceqa_nona_context(120 条)
- 纯文本数据:
- SK1.1 科学题(100 条)
3、通识领域(共 500 条多模态数据):
- Illava_cot_100k(300 条)
- Visual7w(100 条)
- VSR(100 条)
实验结果
为了验证我们的模型在多模态数学推理任务中的表现,我们进行了广泛的实验,并在多个基准数据集上进行了测试。以下是实验部分的详细介绍:
实验设置
1、 Visual Datasets
我们构建了一个全面的评估框架,涵盖视觉检测、视觉分类和多模态数学推理三个主要任务,以评估强化学习对视觉语言模型的有效性和泛化能力。
- 视觉检测:使用 RefCOCO 和 RefGta 数据集。
- 视觉分类:采用 RefCOCO、RefCOCOg 和 Pascal-VOC 数据集。
- 多模态数学推理:结合 Math360K、Geo170K 和 CLEVER-70k-Counting 数据集。
2、Benchmarks
我们在多个权威基准数据集上评估了模型的表现,包括:
- MathVisa:综合数学基准。
- MATH:高中竞赛级别数学问题。
- AI2D:小学科学图表及相关问题。
- MMVet 和 MMBench:复杂推理和多模态能力评估。
实验结果
我们展示了使用课程强化微调(Curr-ReFT)训练的模型在多模态任务上的显著性能提升,特别是在跨领域泛化能力和复杂推理任务方面。
与传统的监督微调(SFT)方法相比,我们的方法不仅提高了准确率,还增强了模型处理未见过的数据的能力。以下表格展示了不同训练方法在域内和域外数据集上的性能对比。具体包括传统监督微调(SFT)和强化学习(RL)两种方法:
通过这些实验结果可以看出,强化学习训练(RL)方法在提高模型的域内和域外表现方面具有显著优势,尤其是在处理未见过的数据时,能够保持较高的准确率。
Visual Datasets 上不同方法模型的测试结果如下:
为了验证 Curr-ReFT 的泛化性以及使用后不会削弱模型在其他领域的推理能力,我们在多模态领域多个 Benchmark 数据集上进行验证。Benchmarks 上不同方法模型的测试结果如下(评测集裁判模型使用 GPT-3.5):
总结
本研究聚焦于提升小规模视觉-语言模型(VLMs)在推理能力和域外(OOD)泛化性能两个关键方面的表现。通过实证研究,我们发现强化学习不仅能有效提升模型的推理能力,更在视觉任务中展现出超出预期的泛化性能提升。
基于这一重要发现,我们提出了创新性的课程式强化学习微调(Curr-ReFT)后训练范式。该方法巧妙地融合了渐进式课程学习与拒绝采样策略。Curr-ReFT 通过两个关键机制:
- 任务复杂度的渐进式提升
- 高质量样本的选择性学习 成功实现了模型性能的显著提升。
#DeepSeek公布了推理引擎开源路径
OpenAI也将开始连续一周发布
今天下午,DeepSeek 默默地在自己的 open-infra-index 库中发布了一份题为「开源 DeepSeek 推理引擎的路径」的文档,宣布将开源自己的内部推理引擎(internal inference engine)并与开源社区建立更广泛的合作。有意思的是,该文档发布之后不久就经历了两次修改,对一些措辞和表述进行了更加中立和宽泛的处理。
在其中一次修改中,DeepSeek 提到了与 SGLang 和 vLLM 项目的合作关系,但这两个具体的项目名称在新版本中被替换成了「现有的开源项目」。修改原因是为了强调「未来的开源合作是面向整个开源社区的,不局限于具体某些项目。」因此,DeepSeek 与 SGLang 和 vLLM 这两大开源项目的合作关系应该是已经确定了。
不得不说,DeepSeek 非常 GOAT(Greatest of All Time)!
而就在不久前,Sam Altman 才宣布 OpenAI 将开始一轮发布周。犹记得上一次,在 OpenAI 一连 12 个工作日的连续发布中,o1 满血版、Sora、强化微调技术、Canvas 更新、o3-mini 等产品和服务纷纷问世。不知道,这一次,OpenAI 又将发布什么东西?
事实上,各路网友已经开始根据各种草蛇灰线的线索开始猜测这一周将会发布的东西了。说实在的,有一些颇具说服力,而且还有证据。
下面我们首先将介绍「开源 DeepSeek 推理引擎的路径」,然后将简单盘点一番网友对 OpenAI 这周发布内容的预测。
开源 DeepSeek 推理引擎的路径
文档地址:https://github.com/deepseek-ai/open-infra-index/blob/main/OpenSourcing_DeepSeek_Inference_Engine/README.md
以下为 DeepSeek 发布的文档的原文译本:
几周前,在开源周期间,我们开源了多个库。社区的反响非常积极 —— 激发了鼓舞人心的合作、富有成效的讨论以及宝贵的错误修复。受此鼓舞,我们决定更进一步:将我们的内部推理引擎回馈给开源社区。
我们非常感谢开源生态系统,没有它,我们不可能在通用人工智能 (AGI) 方面取得进展。我们的训练框架依赖于 PyTorch,我们的推理引擎基于 vLLM,这两者都对加速 DeepSeek 模型的训练和部署起到了重要作用。
鉴于部署 DeepSeek-V3 和 DeepSeek-R1 等模型的需求日益增长,我们希望尽己所能回馈社区。在我们起初考虑将完整的内部推理引擎开源时,我们发现了一些挑战:
- 代码库差异:我们的引擎基于 vLLM 一年多前的一个早期分支。虽然结构相似,但我们针对 DeepSeek 模型对其进行了大量定制化处理,因此难以扩展到更广泛的用例。
- 基础设施依赖:该引擎与我们的内部基础设施(包括集群管理工具)紧密耦合,如果不进行重大修改,就无法进行公开部署。
- 维护带宽有限:作为一个专注于开发更优质模型的小型研究团队,我们缺乏维护大型开源项目的带宽。
考虑到这些挑战,我们决定采用一种更可持续的替代方案:与现有的开源项目合作。
展望未来,我们将在以下方面与现有的开源项目紧密合作:
- 提取出分立的功能:将可复用的组件模块化并作为独立的软件库贡献出来。
- 共享优化:直接贡献设计改进和实现细节。
我们衷心感谢开源运动 —— 从操作系统和编程语言到机器学习框架和推理引擎。能够为这个蓬勃发展的生态系统做出贡献,并看到我们的模型和代码受到社区的广泛欢迎,我们深感荣幸。让我们携手突破通用人工智能 (AGI) 的界限,并确保其造福全人类。
注:需要说明,本文仅概述了我们开源 DeepSeek-Inference-Engine 代码库的路径。对于未来的模型发布,我们将对开源社区和硬件合作伙伴保持开放和协作的态度。我们承诺在新模型发布之前主动同步与推理(inference)相关的工程工作,目标是使社区能够从第一天起就获得 SOTA 级支持。我们的最终目标是建立一个同步的生态系统,使尖端的 AI 功能能够在模型正式发布后无缝地应用于各种硬件。
OpenAI 将发布什么?
看了 DeepSeek 振奋人心的开源路径,再来看看 OpenAI 是否有可能给我们带来类似的震撼。
o3、o4-mini、GPT-4.1 系列模型
对于 OpenAI 这次发布周,目前最可信的信息还是来自 OpenAI 自己,其已经在自家的 CDN(内容分发网络)上发布了一些图标,几乎明示了即将发布的一系列模型。从目前网友们收集到的数据看,OpenAI 这一次一共公布了至少 5 个图标:
但从这些图标看,OpenAI 有可能在今晚开始的发布周中发布至少 5 个模型,包括 o3 满血版与 o4-mini 两个推理模型以及 GPT-4.1 系列模型(包括满血版、mini 以及 nano)版。
开源模型
此外,还有人猜测 OpenAI 可能会开源一个可与 DeepSeek-R1 比肩的开源模型,而且这个模型很可能就是已经在 OpenRouter 上线且可免费使用的 Optimus Alpha。该模型支持 100 万上下文长度,网友实测其编程性能非常好。
地址:https://openrouter.ai/openrouter/optimus-alpha
理由之一是如果用户让 Optimus Alpha 介绍自己,他会自称是来自 OpenAI 并且基于 GPT-4 架构。
智能体软件工程师
OpenAI CFO Sarah Friar 近日在高盛举办的一次活动上透露,该公司正在开发一款名叫 Agentic Software Engineer(A-SWE)的产品,即智能体软件工程师 / 自主式软件工程师。不同于编程助手(Copilot),A-SWE 可以自己完成构建应用、处理拉取请求、进行质量保证、修复错误和编写文档等任务。
,时长00:43
视频由 𝕏 用户 @slow_developer 剪辑
在此之前,OpenAI 已经发布了 Operator 和 Deep Research 这两款智能体,分别面向计算机控制和深度研究两个应用方向,而 A-SWE 很显然会是一个面向编程任务的智能体。
除了以上传言,还有网友猜测 OpenAI 可能还会发布一个新的图像生成模型,并且其性能可能胜过因吉卜力风格生成而大火的 GPT-4o。不过关于此传言的切实信息并不多。
你期待在 OpenAI 这次发布周上看到什么呢?
参考链接
https://github.com/deepseek-ai/open-infra-index/tree/main
https://x.com/sama/status/1911490401221120284
https://cdn.openai.com/API/docs/images/model-page/model-icons/gpt-4.1-mini.png
https://x.com/ImperialistsL/status/1911677033404612659
#AccVideo
合成数据助力视频生成提速8.5倍,上海AI Lab开源AccVideo
虽然扩散模型在视频生成领域展现出了卓越的性能,但是视频扩散模型通常需要大量的推理步骤对高斯噪声进行去噪才能生成一个视频。这个过程既耗时又耗计算资源。例如,HunyuanVideo [1] 需要 3234 秒才能在单张 A100 上生成 5 秒、720×1280、24fps 的视频。
为了解决上述问题,上海AI Lab提出了一种创新性的高效蒸馏方法 AccVideo,旨在利用合成数据集加速视频扩散模型。AccVideo 相比于教师模型(HunyuanVideo)[1] 提升了 8.5 倍的生成速度并保持相当的性能。此外,通过使用合成数据集,AccVideo 显著提升训练效率并减少数据需求。仅需 8 块 A100 显卡,使用 3.84 万条合成数据训练 12 天,即可生成高质量 5s、720×1280、24fps 的视频。
,时长00:13
- 开源链接:https://github.com/aejion/AccVideo
- 项目主页:https://aejion.github.io/accvideo
- 论文链接:https://arxiv.org/abs/2503.19462
该模型受到包括 Reddit 等在内的社区广泛关注,目前已经集成 ComfyUI,并且支持 Lora。
- Reddit 讨论链接:https://www.reddit.com/r/StableDiffusion/comments/1jnb5rt/accvideo_85x_faster_than_hunyuan/
研究动机
作者首先在 1D toy 实验上对现有蒸馏扩散模型的方法进行了细致的分析。如图 1 所示,现有的方法在通常需要前向扩散来计算蒸馏数据点,但是由于数据集不匹配(教师模型和学生模型训练时使用的数据集不匹配)或者高斯噪声不匹配(高斯噪声和真实数据的不匹配)的问题,计算出来的数据点可能是无用的。这会导致教师模型为学生模型提供不可靠的指导(如图 1 红框所示),从而影响模型的蒸馏效率以及生成结果。
图 1. 1D toy 实验图,展示了现有蒸馏方法在蒸馏时会使用无用数据点的问题。e) 无用数据点的频率会随着数据集不匹配的程度大幅增长
方法概述
本文方法旨在通过蒸馏预训练视频扩散模型(HunyuanVideo)来减少推理步数,从而加速视频生成。基于上面的分析,作者尝试在蒸馏过程中避免了无效数据点的使用。具体而言,作者首先构建了一个合成视频数据集 SynVid,该数据集利用教师模型生成高质量合成视频及其去噪轨迹。随后,作者提出了一种基于轨迹的少步指导机制和一种对抗训练策略,从而以更少推理步数生成视频并充分利用 SynVid 所捕获的每个扩散时间步的数据分布特性,进一步提升模型性能。图 2 展示了本方法的总览图。
图 2. AccVideo 方法总览图
(1)合成视频数据集,SynVid
作者采用 HunyuanVideo 作为生成器来构建合成数据,如图 3 所示。作者构建的合成数据集
包含高质量的合成视频
、潜在空间中的去噪轨迹
以及它们对应的文本提示
,其中
表示数据数量,n=50表示推理步数,
表示推理扩散时间步。文本提示
通过使用 InternVL2.5 标注互联网上的高质量视频获得。对于高斯噪声
,去噪轨迹可以通过以下方式求解:
合成视频
可以通过 VAE 解码干净的潜在编码
得到。值得注意的是,
中的数据点是通向正确视频的中间结果,因此它们都是有效且有意义的。这有助于高效蒸馏并显著减少对数据量的需求。
图 3. 合成视频数据集 SynVid 构建图
(2)基于轨迹的少步指导机制
视频扩散模型通常需要大量的推理步骤来生成视频。为了加速生成过程,作者设计了一个学生模型
,该学生模型从预训练视频扩散模型(即教师模型)生成的去噪轨迹中学习,能以更少的推理步数生成视频。具体而言,作者提出了一种基于轨迹的损失函数,以 m 步学习教师模型的去噪过程。该损失选择m+1个关键扩散时间步
,并在每条去噪轨迹上获取它们对应的潜在编码
,并通过这些关键潜在编码学习高斯噪声到视频的映射关系:
其中
。这些关键潜在编码构建了一条从高斯噪声到视频潜在编码的更短路径,通过学习这个更短路径,学生模型显著减少了推理步数。在实验中,作者m=5设置,与教师模型相比,推理步骤数量减少了 10 倍,从而大大加速了视频生成过程。
(3)对抗训练策略
除了高斯噪声与视频潜在编码之间的一对一映射外,SynVid 还包含每个扩散时间步
的许多潜在编码
,这些潜在编码隐式地代表了在这个扩散时间步下的数据分布
。为了充分释放合成数据集中的知识并提升学生模型
的性能,作者提出了一种对抗训练策略,以最小化对抗散度
,其中
表示学生模型
在扩散时间步
生成的数据分布。训练目标遵循标准的生成对抗网络:
其中D表示判别器。由于判别器需要区分不同扩散时间步的噪声潜在编码,作者设计的判别器D包含一个噪声感知的特征提取器和m个扩散时间步感知的投影头
需要注意的是,该对抗训练策略避免了现有方法中常用的前向扩散操作,从而防止了对无用数据点进行蒸馏。这确保了教师模型能够为学生模型提供准确的指导。此外,基于轨迹的少步指导机制提升了对抗学习的稳定性,无需复杂的正则化设计。
实验结果
,时长00:49
视频展示了 AccVideo 在不同分辨率下和 VideoCrafter2 [2]、T2V-Turbo-V2 [3]、LTX-Video [4]、CogVideoX [5]、PyramidFlow [6] 以及 HunyuanVideo [1] 的定性对比结果。AccVideo 生成的视频伪影更少(例如小女孩的手部细节)。相比 CogVideoX1.5,本方法生成的视频具有更高保真度的画面和更优质的背景效果。与 HunyuanVideo 相比,本方法的结果能更好地匹配文本描述(例如复古 SUV 的呈现效果)。
总结
在本文中,作者首先系统分析了现有扩散蒸馏方法因使用无效数据点而导致的关键问题。基于这一发现,作者提出了一种高效蒸馏新方法以加速视频扩散模型。具体而言:1)构建了包含有效蒸馏数据点的合成视频数据集 SynVid;2)提出基于轨迹的少步指导机制,使学生模型仅需 5 步即可生成视频,较教师模型实现显著加速;3)设计了利用合成数据集分布特性的对抗训练策略以提升视频质量。实验表明,AccVideo 在保持性能相当的前提下,生成速度较教师模型提升 8.5 倍。
参考文献
[1] Kong, Weijie, et al. "Hunyuanvideo: A systematic framework for large video generative models." arXiv preprint arXiv:2412.03603 (2024).
[2] Chen, Haoxin, et al. "Videocrafter2: Overcoming data limitations for high-quality video diffusion models." CVPR. 2024.
[3] Li, Jiachen, et al. "T2v-turbo-v2: Enhancing video generation model post-training through data, reward, and conditional guidance design." ICLR. 2025.
[4] HaCohen, Yoav, et al. "Ltx-video: Realtime video latent diffusion." arXiv preprint arXiv:2501.00103 (2024).
[5] Yang, Zhuoyi, et al. "Cogvideox: Text-to-video diffusion models with an expert transformer." ICLR. 2025.
[6] Jin, Yang, et al. "Pyramidal flow matching for efficient video generative modeling." ICLR. 2025.