当前位置: 首页 > article >正文

w~大模型~合集20

我自己的原文哦~ https://blog.51cto.com/whaosoft/12456838

#谷歌公布AI布局布线

PCB和芯片Layout工程师要失业了?

虽然近年来各大EDA公司都在积极的将AI引入到自己的芯片设计工具当中。但是早在2020年,谷歌就发布了题为《Chip Placement with Deep Reinforcement Learning》预印本论文,介绍了其设计芯片布局的新型强化学习方法。随后在2021年,谷歌又在 Nature上发表了论文并将其开源了。

近日,谷歌详细介绍了其用于芯片设计布局的强化学习方法,并将该模型命名为“AlphaChip” ,据称AlphaChip有望大大加快芯片布局规划的设计,并使它们在性能、功耗和面积方面更加优化。目前AlphaChip已发布在Github上与公众共享,同时谷歌还开放了一个在 20 个 TPU 模块上预训练的检查点。据介绍,AlphaChip在设计谷歌的张量处理单元 (TPU) 方面发挥了重要作用,并已被包括联发科(MediaTek)在内的其他公司采用。

谷歌首席科学家 Jeff Dean 表示,开放预训练 AlphaChip 模型检查点以后,外部用户可以更容易地使用 AlphaChip 来启动自己的芯片设计。

从数个月缩短至数小时

通常芯片设计布局或平面图是芯片开发中时间最长、劳动强度最高的阶段。近年来,新思科技(Synopsys)开发了 AI 辅助芯片设计工具,可以加速开发并优化芯片的布局规划。但是,这些工具非常昂贵。谷歌希望在一定程度上使这种 AI 辅助芯片设计方法大众化。

如今,如果由人类来为 GPU 等复杂芯片设计平面图大约需要 24 个月。不太复杂的芯片的平面规划可能也至少需要几个月的时间,而这意味着数百万美元的成本,因为维持一个设计团队通常需要一大笔费用。

谷歌表示,AlphaChip 加快了这一时间表,可以在短短几个小时内创建芯片布局。此外,据说它的设计非常出色,因为它们优化了电源效率和性能。谷歌还展示了一张图表,显示与人类开发人员相比,各种版本的 TPU 和 Trillium 的平均线长(wirelength)都有所减少。 

△图中展示了 AlphaChip 在三代 Google 张量处理单元 (TPU) 中的平均线长(wirelength)减少量,并与 TPU 物理设计团队生成的位置进行了比较。

AlphaChip 是如何工作的?

芯片设计并非易事,部分原因在于计算机芯片由许多相互连接的块组成,这些块具有多层电路元件,所有元件都通过极细的导线连接。此外,芯片还有很多复杂且相互交织的设计约束,设计时必须同时满足所有约束。由于这些复杂性,芯片设计师们在 60 多年来一直在努力实现芯片布局规划过程的自动化。

与 AlphaGo 和 AlphaZero 类似,谷歌构建时 AlphaChip,也将芯片的布局规划视为一种博弈。

AlphaChip 从空白网格开始,一次放置一个电路元件,直到完成所有元件的放置。然后根据最终布局的质量给予奖励。谷歌提出了一种新颖的「基于边」的图神经网络使 AlphaChip 能够学习互连芯片元件之间的关系,并在整个芯片中进行推广,让 AlphaChip 在其设计的每一个布局中不断进步。

图片

△左图:AlphaChip 在没有任何经验的情况下放置开源处理器 Ariane RISC-V CPU的电路元件;右图:AlphaChip 在对 20 个 TPU 相关设计进行练习后放置相同的电路元件。

AlphaChip 还使用强化学习模型,其中代理在预设环境中采取行动,观察结果,并从这些经验中学习,以便在未来做出更好的选择。在 AlphaChip 的情况下,系统将 chip floorplanning 视为一种游戏,一次将一个 circuit 元件放置在空白网格上。该系统随着解决更多布局而改进,使用图形神经网络来理解组件之间的关系。

谷歌TPU及联发科均已采用

自 2020 年以来,AlphaChip 一直被用于设计谷歌自己的 TPU AI 加速器,这些加速器驱动着谷歌的许多大规模 AI 模型和云服务。这些处理器运行基于 Transformer 的模型,为谷歌的 Gemini 和 Imagen 提供支持。

为了设计 TPU 布局,AlphaChip 首先在前几代的各种芯片块上进行练习,例如片上和芯片间网络块、内存控制器和数据传输缓冲区。这个过程称为预训练。然后谷歌在当前的 TPU 块上运行 AlphaChip 以生成高质量的布局。与之前的方法不同,AlphaChip 解决了更多芯片布局任务实例,因此变得更好、更快,就像人类专家所做的那样。

可以说AlphaChip 改进了每一代 TPU 的设计,包括最新的第 6 代 Trillium 芯片,确保了更高的性能和更快的开发。尽管如此,谷歌和联发科目前仍都只是依赖 AlphaChip 来制作芯片当中有限的一些区块,而人类开发人员仍然承担了大部分的设计工作。不过,随着持续AlphaChip的持续迭代,其所承担的区块也越来越多,已经从TPU v5e的10个区块提升到了Trillium的25个区块。

△谷歌最近三代张量处理单元 (TPU)(包括 v5e、v5p 和 Trillium)中 AlphaChip 设计的芯片块的数量

到目前为止,AlphaChip 已被用于开发各种处理器,包括谷歌的 TPU 和联发科旗舰级天玑 5G SoC芯片,这些处理器广泛用于各种智能手机。此外,还包括谷歌首款基于 Arm 的通用数据中心 CPU—— Axion。因此,AlphaChip 能够在不同类型的处理器中进行泛化。

谷歌表示,它已经在各种芯片模块上进行了预训练,这使得 AlphaChip 能够在实践更多设计时生成越来越高效的布局。虽然人类专家可以学习,而且许多人学得很快,但机器的学习速度要高出几个数量级。

扩展AI在芯片开发中的应用

谷歌表示,AlphaChip 的成功激发了一波新的研究浪潮,将人工智能用于芯片设计的不同阶段。这包括将AI技术扩展到逻辑综合、宏选择和时序优化等领域,Synopsys和Cadence已经提供了这些技术,尽管需要很多钱。据谷歌称,研究人员还在探索如何将 AlphaChip 的方法应用于芯片开发的更进一步阶段。

“AlphaChip 激发了芯片设计强化学习的全新研究路线,跨越了从逻辑综合到布局规划、时序优化等的设计流程,”谷歌的一份声明中写道。

展望未来,谷歌看到了 AlphaChip 彻底改变整个芯片设计生命周期的潜力:从架构设计到布局再到制造,人工智能驱动的优化可能会带来更快的芯片、更小(即更便宜)和更节能的芯片。虽然目前谷歌的服务器和基于联发科天玑 5G 的智能手机受益于 AlphaChip,但未来应用程序可能会扩展到几乎所有领域。

目前AlphaChip 的未来版本已经在开发中,因此或许未来在AI的驱动下,芯片设计将会变得更加的简单。

#Google DeepMind

汇集两个世界级的 AI 团队。

在 AI 竞争的白热化阶段,谷歌又出大招,宣布将 Google Brain 和 DeepMind 进行合并,成立名为 Google DeepMind 的新部门。新部门将在保持道德标准的同时,引领突破性的 AI 产品研究和进步。

领导层,DeepMind CEO Demis Hassabis 将担任 Google DeepMind 的 CEO;Google Brain 联合创始人之一 Jeff Dean 将担任 Google Research 和 Google DeepMind 的首席科学家,向谷歌 CEO Sundar Pichai 汇报工作。Google Research 仍将是一个独立部门,并将专注于计算机科学在算法和理论、隐私和安全、量子计算、健康、气候和可持续性以及负责任 AI 等领域发展。

与此同时,作为 Google DeepMind 组建的一部分,谷歌表示将创建一个新的科学委员会来监督该部门研究进展以及方向,该委员会将由 DeepMind 研究副总裁 Koray Kavukcuoglu 领导。Google Research 产品副总裁 Eli Collins 将加入 Google DeepMind 担任产品副总裁,而 Google Brain 负责人 Zoubin Ghahramani 将成为 Google DeepMind 研究领导团队的成员,向 Kavukcuoglu 汇报。

谷歌 CEO Sundar Pichai 在一篇博客文章中表示:「将人才整合到一个专注的团队中,并以谷歌的计算资源为后盾,将大大加快在人工智能方面的进展。

Pichai 发给谷歌员工的内部信

「自 2016 年以来,我们一直是 AI-first 公司,并且认为 AI 是实现我们使命的最重要方式。从那时起,我们使用 AI 对许多核心产品进行改进,从搜索、YouTube 、 Gmail 到 Pixel 手机等等。我们已经帮助企业和开发者通过 Google Cloud 获得人工智能的力量,我们已经展示了人工智能在解决健康和气候变化等社会问题的潜力。

一路走来,我们很幸运拥有两个世界一流的研究团队,这些团队通过基础性突破引领整个行业向前发展,开创了人工智能的新时代。

现在,AI 的进步速度比以往任何时候都要快。为了确保大胆、负责任的发展通用人工智能,我们正在创建一个部门来帮助我们更安全、更负责任地构建功能更强大的系统。

这个名为 Google DeepMind 的团队将汇集 AI 领域的两个领先研究团队:Google Research 的 Brain 团队和 DeepMind。过去十年,他们在 AI 方面的成就包括 AlphaGo、Transformers、word2vec、WaveNet、AlphaFold、序列到序列模型、蒸馏、深度强化学习,以及用于表达、训练和部署大规模 ML 的分布式系统和软件框架,如 TensorFlow 和 JAX 。

将这些人才组合成一个专注的团队,以谷歌的计算资源为后盾,将大大加快我们在人工智能方面的进步。

作为 Google DeepMind 的 CEO,Demis Hassabis 将领导最有能力和负责任的通用人工智能系统的开发 —— 这将有助于推动我们下一代产品和服务的研究。

Jeff Dean 将担任谷歌首席科学家的高级职位,向我汇报工作。以此身份,他将担任 Google Research 和 Google DeepMind 的首席科学家。Jeff 将与 Demis 一起帮助确定我们人工智能研究的未来方向,并领导我们与人工智能相关的最关键和战略性技术项目,首先是一系列强大的、多模态的 AI 模型。

Google Research 将继续其重要工作,引领计算机科学在算法和理论、隐私和安全、量子计算、健康、气候和可持续性以及负责任的人工智能等领域取得根本性进步,并将向 James Manyika 汇报。

我对下一阶段的旅程感到非常兴奋,我们将在我们的使命中取得进展,我们将通过越来越强大和负责任的人工智能帮助人们发挥潜力。」

Hassabis:Google DeepMind 致力于取得下一波改变世界的突破

以下为 Demis Hassabis 内部公开信的全部内容。

当我和 Shane Legg 在 2010 年成立 DeepMind 时,很多人认为通用人工智能是一种遥不可及的科幻技术,距离成为现实需要数十年的时间。

现在,我们生活在 AI 研究和技术指数级进步的时代。未来数年,AI 以及最终的 AGI 有可能推动历史上最伟大的社会、经济和科学变革之一。

这就是今天 Sundar 宣布将 DeepMind 和 Google Brain 合并为 Google DeepMind 的原因。我们的才能和努力将加速迈向一个「AI 帮助解决人类面临的最大挑战」的世界。我非常高兴能够领导 Google DeepMind,并与你们所有人携手共建。

通过与 Google 各产品线优秀同事的密切合作,我们将有机会提供「显著改善百万人生活、变革行业、推进科学并服务多元化社区」的各类 AI 研究和产品。

我相信,Google DeepMind 的成立将使我们更快地走向期望中的未来。安全负责任地构建更强大和通用的 AI 要求我们解决当今时代一些最艰巨的科学和工程挑战。因此,我们需要更迅速地开展工作,加强协作和执行,并简化决策方式,以专注于实现最大的影响。

通过 Google DeepMind,我们将汇聚起 AI 领域的世界级人才与算力、基础设施和资源,以大胆和负责任的方式在 Google 和 Alphabet 中实现下一代 AI 突破和产品。Google Brain 和 DeepMind 的研究进展为当前 AI 行业奠定了很多基础,从深度强化学习到 Transformers。未来 Google DeepMind 将致力于取得下一波改变世界的突破。

Sundar Pichai、Jeff Dean、James Manyika 和我在近几个月的合作中建立了良好的合作关系。我非常期待与 Eli Collins 和 Zoubin Ghahramani 密切合作。此外我们还为 Google DeepMind 创建了一个新的科学委员会来监督其研究进展和方向。未来几天,Jeff Dean、Koray、Zoubin、Shane 和我将共同确定该委员会的组成。

最后,我很高兴与你们大家一起踏上这段新的旅程,期待与大家见面。

DeepMind 大事记

DeepMind 是一家位于伦敦的 AI 初创公司,成立于 2010 年,由著名 AI 研究者、游戏设计师 Demis Hassabis 等人联合创立,致力于将机器学习和系统神经科学的最先进技术结合起来,建立强大的通用学习算法。最初成果主要用于模拟、游戏开发等领域。

2014 年,谷歌以 6 亿美元的价格收购了 DeepMind。自此以后,DeepMind 得到了谷歌母公司 Alphabet 源源不断的资金支持,并取得了一系列引人瞩目的 AI 突破。

2016 年 3 月,DeepMind 开发的 AI 程序 AlphaGo 以 4:1 击败韩国围棋冠军李世石,成为近年来 AI 领域的里程碑事件。

2017 年 10 月,DeepMind 推出了 AlphaGo 的最新版本 AlphaGo Zero,在自我训练 3 天后以 100-0 狂虐了 AlphaGo。

2018 年 12 月,DeepMind 推出了 AlphaZero,不仅征服了围棋,也在将棋、国际象棋等复杂游戏中实现了超越人类的表现。

同月,DeepMind 重磅推出了 AlphaFold,根据基因序列预测蛋白质的 3D 结构。此后又推出并开源了 AlphaFold 2、AlphaFold 数据集等。

2020 年 12 月,DeepMind 发布了 MuZero,仅使用像素和游戏分数作为输入就可以在 Atari 视频游戏中达到人类的水平。

2022 年 2 月,DeepMind 发布了基于 Transformer 的新模型 AlphaCode,该模型实现了大规模代码生成。

2022 年 5 月,DeepMind 发布「通才」AI 智能体 Gato,具有多模态、多任务、多具身特点,可以玩雅达利游戏、给图片输出字幕、聊天、用机械臂堆叠积木,还能根据上下文决定是否输出文本、关节力矩、按钮按压或其他 token。

2022 年 10 月,DeepMind 推出 AlphaTensor,利用强化学习发现矩阵乘法算法。它是第一个可用于为矩阵乘法等基本任务发现新颖、高效且可证明正确的算法的人工智能系统。

全新的 Google DeepMind 未来会取得哪些重大的突破,这让我们更加期待了。

参考链接:

​​https://www.deepmind.com/blog/announcing-google-deepmind​​

​​https://blog.google/technology/ai/april-ai-update/​​

​​https://twitter.com/demishassabis/status/1649097532772069377​​

#stableLM

大羊驼LLaMa竞品来了:AI画图最火公司开源语言模型,最小30亿参数

出 Stable Diffusion 的公司也出语言大模型了,效果还挺好。本周三,StableLM 的发布引来了科技圈的关注。

Stability AI 是近期势头正盛的创业公司,因为开源的 AI 画图工具 Stable Diffusion 而饱受好评。在周三的发布中,该公司宣布其语言大模型现已可供开发人员在 GitHub 上使用和改编。

与业内标杆 ChatGPT 一样,StableLM 旨在高效地生成文本和代码。它在名为 Pile 的开源数据集的更大版本上进行训练,其中包含来自各种来源的信息,包括维基百科、Stack Exchange 和 PubMed,共 22 个数据集,容量达到 825GB,1.5 万亿个 token。

Stability AI 表示,StableLM 模型目前可用版本的参数在 30 亿到 70 亿之间,未来将有 15 亿到 650 亿范围的多种参数模型可用。

项目链接:https://github.com/stability-AI/stableLM/

根据目前人们的测试,如果跑 7B 模型(8 bit),需要用到 12GB 的显存。

Stability AI 也放出了一些 StableLM 的问答示例:

StableLM 基于 Stability AI 此前与非营利组织 EleutherAI 合作开发的开源语言模型,包括 GPT-J、GPT-NeoX 和 Pythia,新模型面向尽可能大的用户群。此前在 Stable Diffusion 上,Stability AI 通过多种方式提供其文本到图像 AI 的技术,包括公开演示、软件测试版和模型的完整下载,也允许开发人员使用其工具并进行各种集成。

相比 OpenAI 的封闭,Stability AI 一直把自身定位为 AI 研究社区的一员,我们大概率会在 StableLM 上看到和上月发布的 Meta 开源 LLaMa 语言模型同样的情况。大量基于原版模型的算法可能会出现,在较小模型体量之上实现很好的效果。

StableLM 的微调版聊天界面。 

此外,现在每个人都可以尝试在 Hugging Face 上托管的 StableLM 微调聊天模型上和 AI 进行对话:https://huggingface.co/spaces/stabilityai/stablelm-tuned-alpha-chat

和所有语言大模型一样,StableLM 模型仍然存在「幻觉」问题,如果你尝试问它如何制作花生酱三明治,StableLM 会给出一个非常复杂且荒谬的食谱。它还建议人们在慰问卡上添加一张「有趣的图画」。

Stability AI 警告说,虽然它使用的数据集应该有助于「将基础语言模型引导到『更安全』的文本分布中,但并不是所有的偏见和毒性都可以通过微调来减轻。

现在 StableLM 模型已在 GitHub 存储库中上线。Stability AI 表示将在不久的将来发布一份完整的技术报告,此外还将启动众包 RLHF 计划,并与 Open Assistant 等社区合作,为 AI 聊天助手创建一个开源数据集。

#LMFlow

开源大模型火爆,已有大小羊驼LLaMA、Vicuna等很多可选。

但这些羊驼们玩起来经常没有ChatGPT效果好,比如总说自己只是一个语言模型、没有感情blabla,拒绝和用户交朋友。

归根结底,是这些模型没有ChatGPT那么对齐(Alignment),也就是没那么符合人类用语习惯和价值观。

为此,港科大LMFlow团队提出全新对齐算法RAFT,轻松把伯克利Vicuna-7b模型定制成心理陪伴机器人,从此AI会尽力做你的朋友。

相较于OpenAI所用RLHF对齐算法的高门槛,RAFT(Reward rAnked Fine-Tuning)易于实现,在训练过程中具有较高的稳定性,并能取得更好的对齐效果。

并且任意生成模型都可以用此算法高效对齐,NLP/CV通用

用在Stable Diffusion上,还能对齐生成图片和提示词,让模型生成更加符合提示词描述的图片。

另外,团队特别提示RAFT的对齐训练过程中生成与训练过程完全解耦。

这样就可以在生成过程中利用一些魔法提示词 (magic prompts),让最终对齐的模型不需要魔法提示词也能得到好的效果。从而大大减少了提示词编写的难度!

可以说,RAFT为AIGC社区的研究者和工作者提供了一种新的可选的AI对齐策略。

RAFT模型对齐

OpenAI在ChatGPT前身Instruct论文中介绍了基于人类反馈的强化学习(RLHF)算法。

首先利用人类标注数据训练一个打分器 (reward model),然后通过强化学习算法(如PPO)来调节模型的行为,使得模型可以学习人类的反馈。

但PPO等强化学习算法高度依赖反向梯度计算,导致训练代价较高,并且由于强化学习通常具有较多的超参数, 导致其训练过程具有较高的不稳定性。

相比之下,RAFT算法通过使用奖励模型对大规模生成模型的生成样本进行排序,筛选得到符合用户偏好和价值的样本,并基于这些样本微调一个对人类更友好的AI模型。

具体而言,RAFT分为三个核心步骤:

(1)数据收集:数据收集可以利用正在训练的生成模型作为生成器,也可以利用预训练模型(例如LLaMA、ChatGPT,甚至人类)和训练模型的混合模型作为生成器,有利于提升数据生成的多样性和质量。

(2)数据排序:一般在RLHF中我们都拥有一个与目标需求对齐的分类器或者回归器,从而筛选出最符合人类需求的样本。

(3)模型微调:利用最符合人类需求的样本来实现模型的微调,使得训练之后的模型能够与人类需求相匹配。

在RAFT算法中,模型利用了更多次采样 (当下采样后用以精调的样本一定时),和更少次梯度计算(因为大部分低质量数据被reward函数筛选掉了),让模型更加稳定和鲁棒。

同时,在某些情况下, 由于有监督微调本身对于超参数敏感性更低, 有更稳健的收敛性, 在相同reward情况下,RAFT可以拥有更好的困惑度 (perplexity, 对应其生成多样性和流畅性更好)。

完整算法如下所示:

定制垂直领域GPT

作者在多个任务上进行了实验,首先是正向影评补全。

作者实验发现,给出一个电影评论的起始句,RAFT微调后的大模型可以轻松补齐电影评论,而且更加积极和流畅。

如下图所示,LLaMA未经调整的影评会以随机概率输出正面和负面的评论,RAFT和PPO都能够将评论的态度倾向正面。

在基于Vicuna制作的一个心理陪伴机器人演示中,作者模拟了一个因为考试失利而心情低落的人和机器人在聊天。

可以看到在使用RAFT进行对齐之前,模型说自己没有情感和感情,拒绝和人类交友。

但是在RAFT对齐之后,模型的共情能力明显增强,不断地在安慰人类说,“虽然我是一个AI,但是我会尽力做你的朋友”。

增强Stable Diffusion

除了在语言模型上的对齐能力以外,作者还在扩散模型上验证了文生图的对齐能力,这是之前PPO算法无法做到的事情。

原始Stable Diffusion在256x256分辨率生成中效果不佳 ,但经过RAFT微调之后不仅产生不错的效果,所需要的时间也仅为原版的20%。

对计算资源不足的AIGC爱好者来说无疑是一个福音。

除了提升256分辨率图片的生成能力以外,RAFT还能够对齐生成图片和提示词,让模型生成更加符合提示词描述的图片。

如下图所示,给出提示词“莫奈风格的猫”,原始的stable diffusion生成的图片里,大多数没有猫,而是生成了“莫奈风格”的其他作品,这是由于“莫奈作品”中鲜有猫的身影,而stable diffusion没有完全理解文本的含义。

而经过RAFT微调后,stable diffusion认识到“猫”的概念,所以每张图片里都会有猫的身影。

RAFT来自香港科技大学统计和机器学习实验室团队,也是开源LMFlow模型微调框架的一次重大升级。

LMFlow包括完整的训练流程、模型权重和测试工具。您可以使用它来构建各种类型的语言模型,包括对话模型、问答模型和文本生成模型等。

自框架发布两周以来,LMFlow团队仍在进行着密集的迭代,并在4月9号正式上线了RAFT算法,补齐了AI对齐的训练流程。

LMFlow框架的逐步完善,将更加便利于科研人员和开发者在有限算力下微调和部署大模型。

论文:https://arxiv.org/abs/2304.06767

GitHub:https://github.com/OptimalScale/LMFlow

文档: https://optimalscale.github.io/LMFlow/examples/raft.html

2022 年底,随着 ChatGPT 的爆火,人类正式进入了大模型时代。然而,训练大模型需要的时空消耗依然居高不下,给大模型的普及和发展带来了巨大困难。面对这一挑战,原先在计算机视觉领域流行的 LoRA 技术成功转型大模型 [1][2],带来了接近 2 倍的时间加速和理论最高 8 倍的空间压缩,将微调技术带进千家万户。

但 LoRA 技术仍存在一定的挑战。一是 LoRA 技术在很多任务上还没有超过正常的全参数微调 [2][3][4],二是 LoRA 的理论性质分析比较困难,给其进一步的研究带来了阻碍。

UIUC 联合 LMFlow 团队成员对 LoRA 的实验性质进行了分析,意外发现 LoRA 非常侧重 LLM 的底层和顶层的权重。利用这一特性,LMFlow 团队提出一个极其简洁的算法:Layerwise Importance Sampled AdamW(LISA)。

LISA 介绍

LISA 算法的核心在于:

- 始终更新底层 embedding 和顶层 linear head;

- 随机更新少数中间的 self-attention 层,比如 2-4 层。

出乎意料的是,实验发现该算法在指令微调任务上超过 LoRA 甚至全参数微调。

更重要的是,其空间消耗和 LoRA 相当甚至更低。70B 的总空间消耗降低到了 80G*4,而 7B 则直接降到了单卡 24G 以下!

进一步的,因为 LISA 每次中间只会激活一小部分参数,算法对更深的网络,以及梯度检查点技术(Gradient Checkpointing)也很友好,能够带来更大的空间节省。

在指令微调任务上,LISA 的收敛性质比 LoRA 有很大提升,达到了全参数调节的水平。

而且,由于不需要像 LoRA 一样引入额外的 adapter 结构,LISA 的计算量小于 LoRA,速度比 LoRA 快将近 50%。

理论性质上,LISA 也比 LoRA 更容易分析,Gradient Sparsification、Importance Sampling、Randomized Block-Coordinate Descent 等现有优化领域的数学工具都可以用于分析 LISA 及其变种的收敛性质。

一键使用 LISA

为了贡献大模型开源社区,LMFlow 现已集成 LISA,安装完成后只需一条指令就可以使用 LISA 进行微调:

如果需要进一步减少大模型微调的空间消耗,LMFlow 也已经支持一系列最新技术:

如果在使用过程中遇到任何问题,可通过 github issue 或 github 主页的微信群联系作者团队。LMFlow 将持续维护并集成最新技术。 

总结

在大模型竞赛的趋势下,LMFlow 中的 LISA 为所有人提供了 LoRA 以外的第二个选项,让大多数普通玩家可以通过这些技术参与到这场使用和研究大模型的浪潮中来。正如团队口号所表达的:让每个人都能训得起大模型(Large Language Model for All)。

#AbSViT

这里提出了一个拥有top-down attention能力的AbSViT,可以用自然语言去控制它的attention,也可以把它作为一个general backbone,用来提升image classification,semantic segmentation,以及model robustness的性能。

当一个场景里有多个物体时,正常的vision transformer会highlight出所有的物体。然而在实际生活中,当我们执行一个任务的时候,我们只会关注和当前任务有关的物体,也就是说,人类的attention不仅和image本身有关(bottom-up attention),而且是受high-level的task/goal调控的(top-down attention)。在这篇工作中,我们从Bayesian Inference的角度出发,得到了一个拥有top-down attention能力的vision transformer(AbSViT)。我们可以用自然语言去控制它的attention,这一特性带来了在一系列Visual-Language任务上的提升。我们也可以把它作为一个general backbone,用来提升image classification,semantic segmentation,以及model robustness的性能。

普通的vision transformer会highlight出所有显著的物体(bottom-up attention),然而我们的模型的attention可以受用户控制(top-down attention)。

Paper:

​​https://arxiv.org/pdf/2303.13043.pdfarxiv.org/pdf/2303.13043.pdf​​

Website:

​​https://sites.google.com/view/absvitsites.google.com/view/absvit​​

GitHub:

​​https://github.com/bfshi/AbSViTgithub.com/bfshi/AbSViT​​

你或许需要不止一种Attention

假如你在吃生蚝。

一桌子生蚝。一口一个那种。

你需要做的是什么?每次稳准狠抓起一只生蚝,吞下去,然后再去抓下一个。

这个时候,如果你的大脑是一个vision transformer(ViT),那么你得到的output可能是这样的:

图片来自ECCV2022:Detecting Twenty-thousand Classes using Image-level Supervision。很cool的paper,推荐大家去看。

没错,ViT会highlight出来所有的生蚝。这是因为ViT的attention是bottom-up attention,即attention只由input image决定,这种attention会把input中所有的object都圈出来。

然而我们吃生蚝不能一口全吃掉,得一个一个吃。而且我们可能还是带着任务来吃的,比如先挑最大最肥的吃。

这时我们就需要另外一种attention,叫做top-down attention,意思就是我们不想关注到图片中所有的object,而是只去关注和当前任务相关的object(比如那只首当其冲的生蚝)。

所以,如果让ViT和人类一起吃生蚝,ViT估计吃不过人类。我们需要的,就是把top-down attention的能力加入到ViT中,而一个只有生蚝受伤的世界就此诞生。

当我们在做Top-Down Attention,我们到底在做什么

在做Bayesian Inference。这是我们的一个大胆猜想。

至于这两个八竿子打不着的东西是怎么联系在一起的,让我们先看张图片:

Jastow rabbit-duck

这种图叫做bistable image。它的神奇之处在于,你既可以看出来一只兔子,也可以看出来一只鸭子。更神奇的地方是,你可以在兔子和鸭子之间无缝切换:如果有人告诉你这是一只兔子,你就能看出一只兔子,而如果有人告诉你这是只鸭子,你就能看出鸭子。

那么问题来了:我们的大脑是如何做到这种可控制的无缝切换的呢?有一种比较流行的猜想,叫做Analysis by Synthesis [2],它大概意思就是说,我们的大脑实际上在做Bayesian Inference,即我们对一张图片的认知不仅受图片本身影响,还受一个high-level的prior调控。如果prior告诉我们这是只兔子(比如我们心里认定这是只兔子,或者别人告诉我们这是只兔子),我们就会识别出一只兔子,反之亦然。

说到这,其实就和之前的top-down attention有些联系了,因为top-down attention本质上也是,我们想要识别哪个物体,我们就会识别出哪个物体。比如,我们想要找到最大最肥的生蚝,我们就可以识别出那个最大最肥的生蚝。这个过程中,我们识别出哪个物体,也是受一个high-level prior调控的,而prior其实就是我们当前的task。

以上是一些intuitive的解释,而top-down attention和Bayesian Inference有没有数学上的联系呢?也有。我们在文章中展示了,如果把一个视觉系统看作正在解一个Bayesian Inference,那么去检查它每一层的优化过程,会发现它是在解一个sparse reconstruction的问题,并且这个sparse reconstruction是受一个top-down prior-related signal调控的。结合我们之前一篇文章 [1] 中的结论:sparse reconstruction和visual attention在功能上是等价的,那么我们就可以得出,Bayesian Inference其实是在每一层计算一个受top-down signal调控的visual attention。

 AbSViT:拥有Top-Down Attention的ViT

之前我们介绍了,我们可以把top-down attention看作Bayesian Inference,而Bayesian prior就是我们的task。那么我们是不是可以建造一个网络,让它学会Bayesian Inference,它就等同于拥有了top-down attention呢?

我们就建造了这样一个网络,我们管它叫 AbSViT(Analysis-by-Synthesis Vision Transformer)。下面来介绍一下网络结构和训练方法。

AbSViT的网络结构

我们的目标很简单,只要让网络的输出不仅跟input image有关,还能受task-related prior调控。于是我们设计了这样一个结构:

AbSViT网络结构

网络分为feedforward部分和feedback部分。feedforward部分就是一个正常的ViT,而feedback部分每层包含一个linear decoder。网络的运行分四步,第一步做正常的feedforward;第二步计算output token和一个prior token 的相似度(这里 代表task,比如在Vision-Language Task里它可以是一个language embedding,或者在普通的image classification/segmentation中,它可以是一个learnable的vector),并用相似度去reweight output tokens;第三步将reweight过的tokens经过feedback部分,作为top-down input送回每一层的self-attention里;第四步再做一次feedforward,但是这次每一层的self-attention有额外的top-down input。

至于self-attention如何处理额外的top-down input,我们的做法是把它加在value tokens上面,而保持query/key不变(这个设计是从我们的理论推导得来的,感兴趣的话可以参考原文):

Self-attention with top-down input.

AbSViT的训练方法

除了正常的supervised loss之外,由于我们想让网络学会Bayesian Inference,所以还要加一个额外的loss。这里我们用了类似VAE中的loss(VAE就是通过训练来逼近Bayesian Inference),具体有两个部分:

实验结果

我们所有的model都在ImageNet-1K上训练,对于不同downstream task会在相应的数据集上微调。

首先我们检验一下在ImageNet上训出来的模型有没有学到top-down attention。具体地,我们随机抽取ImageNet中两张图片并拼在一起,用相应类别的prototype(最后一层Linear中对应的weight)作为prior,看看AbSViT的attention会不会随不同prior变化:

Top-down attention的可视化

我们发现,对于不同prior,网络的attention会集中在相应的object上,并且分类结果也会相应改变。这说明AbSViT已经学到了一定程度的top-down attention(虽然ImageNet基本只包含单物体image)。

下面是一些实验结果。首先,对于Vision-Language任务(比如VQA),我们可以把language作为prior,去控制模型的attention。这样可以让我们对每个图片提取和当前task更相关的feature,从而提升一定的性能:

我们比较了AbSViT和几种baseline在VQA和zero-shot image retrieval上的性能。

我们将AbSViT的attention和人类在VQA任务上的attention进行了比较。

除此之外,AbSViT也可以作为general backbone,提升ImageNet classification,semantic segmentation以及robustness的性能。

ImageNet classification and robustness:

我们在ImageNet-1k(Clean)上进行了训练与测试,并测试了在ImageNet-C(IN-C),ImageNet-A(IN-A),ImageNet-R(IN-R)和ImageNet-SK(IN-SK)上的robustness。

Semantic segmantation:

我们分别比较了把ViT和AbSViT作为backbone时,在PASCAL VOC,Cityscapes,以及ADE20K上的semantic segmentation性能。

总结与思考

其实AbSViT可以看作一个encoder-decoder结构,相信大家在不同的文章中可能都见到过类似的结构,只不过这次我们把它和top-down attention联系到了一起,可以算是从另一种角度解释了generative model在discriminative model中的作用。

但是事实上,AbSViT中的generative model其实并不能做到真正的generate(参考文章的Limitation部分),因为我们发现,强迫它的generative能力过强会导致学到的feature不适合做discriminative task。然而,最近有些文章 [3] 发现large-scale generative model(比如stable diffusion)的feature非常适合做segmentation (注意,segmentation也算是discriminative task)。所以,对于discriminative task,到底需要学到多强的generative capability才是最优的,而不同的generation pipeline(比如MAE vs. stable diffusion)学到的feature又有什么区别,是一个值得思考的问题(这里感谢@Xudong Wang指点)。

另外,由于这篇文章中的AbSViT都是用ImageNet supervision去pretrain的,而我们发现这样子学到的top-down attention其实比较弱(因为ImageNet基本都是single-object classification,并不涉及multi-object的top-down attention),所以下一步可能需要用unsupervised或者vision-language pretraining的方式去学习一个更强的top-down attention。

[1] Shi, Baifeng, et al. "Visual attention emerges from recurrent sparse reconstruction."arXiv preprint arXiv:2204.10962(2022). [2] Yuille, Alan, and Daniel Kersten. "Vision as Bayesian inference: analysis by synthesis?."_Trends in cognitive sciences_10.7 (2006): 301-308. [3] Xu, Jiarui, et al. "Open-Vocabulary Panoptic Segmentation with Text-to-Image Diffusion Models."arXiv preprint arXiv:2303.04803(2023).  

#用单GPU微调 LLM

自从大模型变成热门趋势之后,GPU 就成了紧俏的物资。很多企业的储备都不一定充足,更不用说个人开发者了。有没有什么方法可以更高效的利用算力训练模型?

在最近的一篇博客,Sebastian Raschka 介绍了「梯度累积」的方法,能够在 GPU 内存受限时使用更大 batch size 训练模型,绕开硬件限制。

在此之前,Sebastian Raschka 也分享过一篇运用多 GPU 训练策略加速大型语言模型微调的文章,包括模型或 tensor sharding 等机制,这些机制将模型权重和计算分布在不同的设备上,以解决 GPU 的内存限制。

微调 BLOOM 模型进行分类

假设我们有兴趣采用近期预训练的大型语言模型来处理文本分类等下游任务。那么,我们可能会选择使用 GPT-3 的开源替代品 BLOOM 模型,特别是「仅有」 5.6 亿个参数的 BLOOM 版本 —— 它应该可以毫无问题地融入至传统 GPU 的 RAM 中(Google Colab 免费版本拥有 15 Gb RAM 的 GPU)。

一旦开始,就很可能遇到问题:内存会在训练或微调期间迅速增加。训练这个模型的唯一方法是使批大小为 1(batch size=1)。

使用批大小为 1(batch size=1)为目标分类任务微调 BLOOM 的代码如下所示。你也可以在 GitHub 项目页面下载完整代码:

​​https://github.com/rasbt/gradient-accumulation-blog/blob/main/src/1_batchsize-1.py​​

你可以将此代码直接复制并粘贴到 Google Colab 中,但还必须将随附的 local_dataset_utilities.py 文件拖放到从该文件导入了一些数据集实用程序的同一文件夹中。

# pip install torch lightning matplotlib pandas torchmetrics watermark transformers datasets -U
import os
import os.path as op
import time
from datasets import load_dataset
from lightning import Fabric
import torch
from torch.utils.data import DataLoader
import torchmetrics
from transformers import AutoTokenizer
from transformers import AutoModelForSequenceClassification
from watermark import watermark
from local_dataset_utilities import download_dataset, load_dataset_into_to_dataframe, partition_dataset
from local_dataset_utilities import IMDBDataset
def tokenize_text (batch):
    return tokenizer (batch ["text"], truncation=True, padding=True, max_length=1024)
def train (num_epochs, model, optimizer, train_loader, val_loader, fabric):
    for epoch in range (num_epochs):
        train_acc = torchmetrics.Accuracy (
            task="multiclass", num_classes=2).to (fabric.device)
        for batch_idx, batch in enumerate (train_loader):
            model.train ()
            ### FORWARD AND BACK PROP
            outputs = model (
                batch ["input_ids"],
                attention_mask=batch ["attention_mask"],
                labels=batch ["label"]
            ) 
            fabric.backward (outputs ["loss"])
            ### UPDATE MODEL PARAMETERS
            optimizer.step ()
            optimizer.zero_grad ()
            ### LOGGING
            if not batch_idx % 300:
                print (f"Epoch: {epoch+1:04d}/{num_epochs:04d}"
                      f"| Batch {batch_idx:04d}/{len (train_loader):04d}"
                      f"| Loss: {outputs ['loss']:.4f}")
            model.eval()
            with torch.no_grad ():
                predicted_labels = torch.argmax (outputs ["logits"], 1)
                train_acc.update (predicted_labels, batch ["label"])
        ### MORE LOGGING
        model.eval()
        with torch.no_grad ():
            val_acc = torchmetrics.Accuracy (task="multiclass", num_classes=2).to (fabric.device)
            for batch in val_loader:
                outputs = model (
                    batch ["input_ids"],
                    attention_mask=batch ["attention_mask"],
                    labels=batch ["label"]
                )
                predicted_labels = torch.argmax (outputs ["logits"], 1)
                val_acc.update (predicted_labels, batch ["label"])
            print (f"Epoch: {epoch+1:04d}/{num_epochs:04d}"
                  f"| Train acc.: {train_acc.compute ()*100:.2f}%"
                  f"| Val acc.: {val_acc.compute ()*100:.2f}%"
                  )
            train_acc.reset (), val_acc.reset ()
if __name__ == "__main__":
    print (watermark (packages="torch,lightning,transformers", python=True))
    print ("Torch CUDA available?", torch.cuda.is_available ())
    device = "cuda" if torch.cuda.is_available () else "cpu"
    torch.manual_seed (123)
    # torch.use_deterministic_algorithms (True)
    ##########################
    ### 1 Loading the Dataset
    ##########################
    download_dataset ()
    df = load_dataset_into_to_dataframe ()
    if not (op.exists ("train.csv") and op.exists ("val.csv") and op.exists ("test.csv")):
        partition_dataset (df)
    imdb_dataset = load_dataset (
        "csv",
        data_files={
            "train": "train.csv",
            "validation": "val.csv",
            "test": "test.csv",
        },
    )
    #########################################
    ### 2 Tokenization and Numericalization
    #########################################
    tokenizer = AutoTokenizer.from_pretrained ("bigscience/bloom-560m", max_length=1024)
    print ("Tokenizer input max length:", tokenizer.model_max_length, flush=True)
    print ("Tokenizer vocabulary size:", tokenizer.vocab_size, flush=True)
    print ("Tokenizing ...", flush=True)
    imdb_tokenized = imdb_dataset.map (tokenize_text, batched=True, batch_size=None)
    del imdb_dataset
    imdb_tokenized.set_format ("torch", columns=["input_ids", "attention_mask", "label"])
    os.environ ["TOKENIZERS_PARALLELISM"] = "false"
    #########################################
    ### 3 Set Up DataLoaders
    #########################################
    train_dataset = IMDBDataset (imdb_tokenized, partition_key="train")
    val_dataset = IMDBDataset (imdb_tokenized, partition_key="validation")
    test_dataset = IMDBDataset (imdb_tokenized, partition_key="test")
    train_loader = DataLoader (
        dataset=train_dataset,
        batch_size=1,
        shuffle=True,
        num_workers=4,
        drop_last=True,
    )
    val_loader = DataLoader (
        dataset=val_dataset,
        batch_size=1,
        num_workers=4,
        drop_last=True,
    )
    test_loader = DataLoader (
        dataset=test_dataset,
        batch_size=1,
        num_workers=2,
        drop_last=True,
    )
    #########################################
    ### 4 Initializing the Model
    #########################################
    fabric = Fabric (accelerator="cuda", devices=1, precision="16-mixed")
    fabric.launch ()
    model = AutoModelForSequenceClassification.from_pretrained (
        "bigscience/bloom-560m", num_labels=2)
    optimizer = torch.optim.Adam (model.parameters (), lr=5e-5)
    model, optimizer = fabric.setup (model, optimizer)
    train_loader, val_loader, test_loader = fabric.setup_dataloaders (
        train_loader, val_loader, test_loader)
    #########################################
    ### 5 Finetuning
    #########################################
    start = time.time ()
    train (
        num_epochs=1,
        model=model,
        optimizer=optimizer,
        train_loader=train_loader,
        val_loader=val_loader,
        fabric=fabric,
    )
    end = time.time ()
    elapsed = end-start
    print (f"Time elapsed {elapsed/60:.2f} min")
    with torch.no_grad ():
        model.eval()
        test_acc = torchmetrics.Accuracy (task="multiclass", num_classes=2).to (fabric.device)
        for batch in test_loader:
            outputs = model (
                batch ["input_ids"],
                attention_mask=batch ["attention_mask"],
                labels=batch ["label"]
            )
            predicted_labels = torch.argmax (outputs ["logits"], 1)
            test_acc.update (predicted_labels, batch ["label"])
    print (f"Test accuracy {test_acc.compute ()*100:.2f}%")

作者使用了 Lightning Fabric,因为它可以让开发者在不同硬件上运行此代码时灵活地改变 GPU 数量和多 GPU 训练策略。它还允许仅通过调整查准率 flag 来启用混合精度训练(mixed-precision training)。在这种情况下,混合精度训练可以将训练速度提高三倍,并将内存需求降低约 25%。

上面展示的主要代码都是在主函数(if __name__ == "__main__" 的 context)中执行的,即使只使用单个 GPU,也推荐使用 PyTorch 运行环境执行多 GPU 训练。而后,包含在 if __name__ == "__main__" 中的以下三个代码部分负责数据加载:

# 1 加载数据集

# 2 token 化和数值化

# 3 设置数据加载器

第 4 节是初始化模型(Initializing the Model)中,然后在第 5 节 微调(Finetuning)中,调用 train 函数,这是开始让事情变得有趣的地方。在 train (...) 函数中,实现了标准的 PyTorch 循环。核心训练循环的注释版本如下所示:

批大小为 1(Batch size=1)的问题是梯度更新将会变得非常混乱和困难,正如下述训练模型时基于波动的训练损失和糟糕的测试集性能所看到的:

...
torch : 2.0.0
lightning : 2.0.0
transformers: 4.27.2
Torch CUDA available? True
...
Epoch: 0001/0001 | Batch 23700/35000 | Loss: 0.0969
Epoch: 0001/0001 | Batch 24000/35000 | Loss: 1.9902
Epoch: 0001/0001 | Batch 24300/35000 | Loss: 0.0395
Epoch: 0001/0001 | Batch 24600/35000 | Loss: 0.2546
Epoch: 0001/0001 | Batch 24900/35000 | Loss: 0.1128
Epoch: 0001/0001 | Batch 25200/35000 | Loss: 0.2661
Epoch: 0001/0001 | Batch 25500/35000 | Loss: 0.0044
Epoch: 0001/0001 | Batch 25800/35000 | Loss: 0.0067
Epoch: 0001/0001 | Batch 26100/35000 | Loss: 0.0468
Epoch: 0001/0001 | Batch 26400/35000 | Loss: 1.7139
Epoch: 0001/0001 | Batch 26700/35000 | Loss: 0.9570
Epoch: 0001/0001 | Batch 27000/35000 | Loss: 0.1857
Epoch: 0001/0001 | Batch 27300/35000 | Loss: 0.0090
Epoch: 0001/0001 | Batch 27600/35000 | Loss: 0.9790
Epoch: 0001/0001 | Batch 27900/35000 | Loss: 0.0503
Epoch: 0001/0001 | Batch 28200/35000 | Loss: 0.2625
Epoch: 0001/0001 | Batch 28500/35000 | Loss: 0.1010
Epoch: 0001/0001 | Batch 28800/35000 | Loss: 0.0035
Epoch: 0001/0001 | Batch 29100/35000 | Loss: 0.0009
Epoch: 0001/0001 | Batch 29400/35000 | Loss: 0.0234
Epoch: 0001/0001 | Batch 29700/35000 | Loss: 0.8394
Epoch: 0001/0001 | Batch 30000/35000 | Loss: 0.9497
Epoch: 0001/0001 | Batch 30300/35000 | Loss: 0.1437
Epoch: 0001/0001 | Batch 30600/35000 | Loss: 0.1317
Epoch: 0001/0001 | Batch 30900/35000 | Loss: 0.0112
Epoch: 0001/0001 | Batch 31200/35000 | Loss: 0.0073
Epoch: 0001/0001 | Batch 31500/35000 | Loss: 0.7393
Epoch: 0001/0001 | Batch 31800/35000 | Loss: 0.0512
Epoch: 0001/0001 | Batch 32100/35000 | Loss: 0.1337
Epoch: 0001/0001 | Batch 32400/35000 | Loss: 1.1875
Epoch: 0001/0001 | Batch 32700/35000 | Loss: 0.2727
Epoch: 0001/0001 | Batch 33000/35000 | Loss: 0.1545
Epoch: 0001/0001 | Batch 33300/35000 | Loss: 0.0022
Epoch: 0001/0001 | Batch 33600/35000 | Loss: 0.2681
Epoch: 0001/0001 | Batch 33900/35000 | Loss: 0.2467
Epoch: 0001/0001 | Batch 34200/35000 | Loss: 0.0620
Epoch: 0001/0001 | Batch 34500/35000 | Loss: 2.5039
Epoch: 0001/0001 | Batch 34800/35000 | Loss: 0.0131
Epoch: 0001/0001 | Train acc.: 75.11% | Val acc.: 78.62%
Time elapsed 69.97 min
Test accuracy 78.53%

由于没有多的 GPU 可用于张量分片(tensor sharding),又能做些什么来训练具有更大批大小(batch size)的模型呢?

其中一种解决方法就是梯度累积,可以通过它来修改前面提到的训练循环。

什么是梯度积累?

梯度累积是一种在训练期间虚拟增加批大小(batch size)的方法,当可用的 GPU 内存不足以容纳所需的批大小时,这非常有用。在梯度累积中,梯度是针对较小的批次计算的,并在多次迭代中累积(通常是求和或平均),而不是在每一批次之后更新模型权重。一旦累积梯度达到目标「虚拟」批大小,模型权重就会使用累积梯度进行更新。

参考下面更新的 PyTorch 训练循环:

如果将 accumulation_steps 设置为 2,那么 zero_grad () 和 optimizer.step () 将只会每隔一秒调用一次。因此,使用 accumulation_steps=2 运行修改后的训练循环与将批大小(batch size)加倍具有相同的效果。

例如,如果想使用 256 的批大小,但只能将 64 的批大小放入 GPU 内存中,就可以对大小为 64 的四个批执行梯度累积。(处理完所有四个批次后,将获得相当于单个批大小为 256 的累积梯度。)这样能够有效地模拟更大的批大小,而无需更大的 GPU 内存或跨不同设备的张量分片。

虽然梯度累积可以帮助我们训练具有更大批量大小的模型,但它不会减少所需的总计算量。实际上,它有时会导致训练过程略慢一些,因为权重更新的执行频率较低。尽管如此,它却能帮我们解决限制问题,即批大小非常小时导致的更新频繁且混乱。

例如,现在让我们运行上面的代码,批大小为 1,需要 16 个累积步骤(accumulation steps)来模拟批大小等于 16。

输出如下:

...
torch : 2.0.0
lightning : 2.0.0
transformers: 4.27.2
Torch CUDA available? True
...
Epoch: 0001/0001 | Batch 23700/35000 | Loss: 0.0168
Epoch: 0001/0001 | Batch 24000/35000 | Loss: 0.0006
Epoch: 0001/0001 | Batch 24300/35000 | Loss: 0.0152
Epoch: 0001/0001 | Batch 24600/35000 | Loss: 0.0003
Epoch: 0001/0001 | Batch 24900/35000 | Loss: 0.0623
Epoch: 0001/0001 | Batch 25200/35000 | Loss: 0.0010
Epoch: 0001/0001 | Batch 25500/35000 | Loss: 0.0001
Epoch: 0001/0001 | Batch 25800/35000 | Loss: 0.0047
Epoch: 0001/0001 | Batch 26100/35000 | Loss: 0.0004
Epoch: 0001/0001 | Batch 26400/35000 | Loss: 0.1016
Epoch: 0001/0001 | Batch 26700/35000 | Loss: 0.0021
Epoch: 0001/0001 | Batch 27000/35000 | Loss: 0.0015
Epoch: 0001/0001 | Batch 27300/35000 | Loss: 0.0008
Epoch: 0001/0001 | Batch 27600/35000 | Loss: 0.0060
Epoch: 0001/0001 | Batch 27900/35000 | Loss: 0.0001
Epoch: 0001/0001 | Batch 28200/35000 | Loss: 0.0426
Epoch: 0001/0001 | Batch 28500/35000 | Loss: 0.0012
Epoch: 0001/0001 | Batch 28800/35000 | Loss: 0.0025
Epoch: 0001/0001 | Batch 29100/35000 | Loss: 0.0025
Epoch: 0001/0001 | Batch 29400/35000 | Loss: 0.0000
Epoch: 0001/0001 | Batch 29700/35000 | Loss: 0.0495
Epoch: 0001/0001 | Batch 30000/35000 | Loss: 0.0164
Epoch: 0001/0001 | Batch 30300/35000 | Loss: 0.0067
Epoch: 0001/0001 | Batch 30600/35000 | Loss: 0.0037
Epoch: 0001/0001 | Batch 30900/35000 | Loss: 0.0005
Epoch: 0001/0001 | Batch 31200/35000 | Loss: 0.0013
Epoch: 0001/0001 | Batch 31500/35000 | Loss: 0.0112
Epoch: 0001/0001 | Batch 31800/35000 | Loss: 0.0053
Epoch: 0001/0001 | Batch 32100/35000 | Loss: 0.0012
Epoch: 0001/0001 | Batch 32400/35000 | Loss: 0.1365
Epoch: 0001/0001 | Batch 32700/35000 | Loss: 0.0210
Epoch: 0001/0001 | Batch 33000/35000 | Loss: 0.0374
Epoch: 0001/0001 | Batch 33300/35000 | Loss: 0.0007
Epoch: 0001/0001 | Batch 33600/35000 | Loss: 0.0341
Epoch: 0001/0001 | Batch 33900/35000 | Loss: 0.0259
Epoch: 0001/0001 | Batch 34200/35000 | Loss: 0.0005
Epoch: 0001/0001 | Batch 34500/35000 | Loss: 0.4792
Epoch: 0001/0001 | Batch 34800/35000 | Loss: 0.0003
Epoch: 0001/0001 | Train acc.: 78.67% | Val acc.: 87.28%
Time elapsed 51.37 min
Test accuracy 87.37%

根据上面的结果,损失的波动比以前小了。此外,测试集性能提升了 10%。由于只迭代了训练集一次,因此每个训练样本只会遇到一次。训练用于 multiple epochs 的模型可以进一步提高预测性能。

你可能还会注意到,这段代码的执行速度也比之前使用的批大小为 1 的代码快。如果使用梯度累积将虚拟批大小增加到 8,仍然会有相同数量的前向传播(forward passes)。然而,由于每八个 epoch 只更新一次模型,因此反向传播(backward passes)会很少,这样可更快地在一个 epoch(训练轮数)内迭代样本。

结论

梯度累积是一种在执行权重更新之前通过累积多个小的批梯度来模拟更大的批大小的技术。该技术在可用内存有限且内存中可容纳批大小较小的情况下提供帮助。

但是,首先请思考一种你可以运行批大小的场景,这意味着可用内存大到足以容纳所需的批大小。在那种情况下,梯度累积可能不是必需的。事实上,运行更大的批大小可能更有效,因为它允许更多的并行性且能减少训练模型所需的权重更新次数。

总之,梯度累积是一种实用的技术,可以用于降低小批大小干扰信息对梯度更新准确性的影响。这是迄今一种简单而有效的技术,可以让我们绕过硬件的限制。

PS:可以让这个运行得更快吗?

没问题。可以使用 PyTorch 2.0 中引入的 torch.compile 使其运行得更快。只需要添加一些 model = torch.compile,如下图所示:

GitHub 上提供了完整的脚本。

在这种情况下,torch.compile 在不影响建模性能的情况下又减少了十分钟的训练时间:

poch: 0001/0001 | Batch 26400/35000 | Loss: 0.0320
Epoch: 0001/0001 | Batch 26700/35000 | Loss: 0.0010
Epoch: 0001/0001 | Batch 27000/35000 | Loss: 0.0006
Epoch: 0001/0001 | Batch 27300/35000 | Loss: 0.0015
Epoch: 0001/0001 | Batch 27600/35000 | Loss: 0.0157
Epoch: 0001/0001 | Batch 27900/35000 | Loss: 0.0015
Epoch: 0001/0001 | Batch 28200/35000 | Loss: 0.0540
Epoch: 0001/0001 | Batch 28500/35000 | Loss: 0.0035
Epoch: 0001/0001 | Batch 28800/35000 | Loss: 0.0016
Epoch: 0001/0001 | Batch 29100/35000 | Loss: 0.0015
Epoch: 0001/0001 | Batch 29400/35000 | Loss: 0.0008
Epoch: 0001/0001 | Batch 29700/35000 | Loss: 0.0877
Epoch: 0001/0001 | Batch 30000/35000 | Loss: 0.0232
Epoch: 0001/0001 | Batch 30300/35000 | Loss: 0.0014
Epoch: 0001/0001 | Batch 30600/35000 | Loss: 0.0032
Epoch: 0001/0001 | Batch 30900/35000 | Loss: 0.0004
Epoch: 0001/0001 | Batch 31200/35000 | Loss: 0.0062
Epoch: 0001/0001 | Batch 31500/35000 | Loss: 0.0032
Epoch: 0001/0001 | Batch 31800/35000 | Loss: 0.0066
Epoch: 0001/0001 | Batch 32100/35000 | Loss: 0.0017
Epoch: 0001/0001 | Batch 32400/35000 | Loss: 0.1485
Epoch: 0001/0001 | Batch 32700/35000 | Loss: 0.0324
Epoch: 0001/0001 | Batch 33000/35000 | Loss: 0.0155
Epoch: 0001/0001 | Batch 33300/35000 | Loss: 0.0007
Epoch: 0001/0001 | Batch 33600/35000 | Loss: 0.0049
Epoch: 0001/0001 | Batch 33900/35000 | Loss: 0.1170
Epoch: 0001/0001 | Batch 34200/35000 | Loss: 0.0002
Epoch: 0001/0001 | Batch 34500/35000 | Loss: 0.4201
Epoch: 0001/0001 | Batch 34800/35000 | Loss: 0.0018
Epoch: 0001/0001 | Train acc.: 78.39% | Val acc.: 86.84%
Time elapsed 43.33 min
Test accuracy 87.91%

请注意,与之前相比准确率略有提高很可能是由于随机性。

#MobileVLM

大模型涌向移动端的浪潮愈演愈烈,终于有人把多模态大模型也搬到了移动端上。近日,美团、浙大等推出了能够在移动端部署的多模态大模型,包含了 LLM 基座训练、SFT、VLM 全流程。也许不久的将来,每个人都能方便、快捷、低成本的拥有属于自己的大模型。

MobileVLM 是一款专为移动设备设计的快速、强大和开放的视觉语言助手。它结合了面向移动设备的架构设计和技术,包括从头开始训练的 1.4B 和 2.7B 参数的语言模型、以 CLIP 方式预训练的多模态视觉模型,以及通过投影实现的高效跨模态交互。在各种视觉语言基准测试中,MobileVLM 的性能可媲美大型模型。此外,它还在高通骁龙 888 CPU 和英伟达 Jeston Orin GPU 上展示了最快的推理速度。

  • 论文地址:https://arxiv.org/pdf/2312.16886.pdf
  • Code 地址:https://github.com/Meituan-AutoML/MobileVLM

简介

大型多模态模型(LMMs),尤其是视觉语言模型(VLMs)系列,由于其在感知和推理方面的能力大大增强,已成为构建通用助手的一个很有前途的研究方向。然而,如何将预训练好的大型语言模型(LLMs)和视觉模型的表征连接起来,提取跨模态特性,完成如视觉问题解答、图像字幕、视觉知识推理和对话等任务,一直是个难题。

GPT-4V 和 Gemini 在这项任务上的出色表现已经被多次证明。不过,这些专有模型的技术实现细节我们还知之甚少。与此同时,研究界也提出了一系列语言调整方法。例如,Flamingo 利用视觉 token,通过门控交叉注意力层对冻结的语言模型进行调节。BLIP-2 认为这种交互是不够的,并引入了一个轻量级查询 transformer(称为 Q-Former),它能从冻结的视觉编码器中提取最有用的特征,并将其直接输入到冻结的 LLM 中。MiniGPT-4 通过一个投影层将 BLIP-2 中的冻结视觉编码器与冻结语言模型 Vicuna 配对。另外,LLaVA 应用了一个简单的可训练映射网络,将视觉特征转换为嵌入 token,其维度与语言模型要处理的单词嵌入相同。

值得注意的是,训练策略也在逐渐发生转变,以适应多样性的大规模多模态数据。LLaVA 可能是将 LLM 的指令调整范式复制到多模态场景的首次尝试。为了生成多模态指令跟踪数据,LLaVA 向纯语言模型 GPT-4 输入文本信息,如图像的描述语句和图像的边界框坐标。MiniGPT-4 首先在综合性的图像描述语句数据集上进行训练,然后在【图像 - 文本】对的校准数据集上进行微调。InstructBLIP  基于预训练的 BLIP-2 模型执行视觉语言指令调整,Q-Former 是在以指令调整格式组织的各种数据集上训练的。mPLUG-Owl 引入了一种两阶段训练策略:首先对视觉部分进行预训练,然后使用 LoRA ,基于不同来源的指令数据对大语言模型 LLaMA 进行微调。

尽管 VLM 取得了上述的进展,人们也存在着在计算资源有限的情况下使用跨模态功能的需求。Gemini 在一系列多模态基准上超越了 sota,并为低内存设备引入了 1.8B 和 3.25B 参数的移动级 VLM。并且 Gemini 也使用了蒸馏和量化等常用压缩技术。本文的目标是建立首个开放的移动级 VLM,利用公共数据集和可用技术进行训练,以实现视觉感知和推理,并为资源受限的平台量身定制。本文的贡献如下:

  1. 本文提出了 MobileVLM,它是专为移动场景定制的多模态视觉语言模型的全栈级改造。据作者表示,这是首个从零开始提供详细、可复现和强大性能的视觉语言模型。通过受控和开源数据集,研究者建立了一套高性能的基础语言模型和多模态模型。
  2. 本文对视觉编码器的设计进行了广泛的消融实验,并系统地评估了 VLM 对各种训练范式、输入分辨率和模型大小的性能敏感性。
  3. 本文在视觉特征和文本特征之间设计了一种高效的映射网络,能更好地对齐多模态特征,同时减少推理消耗。
  4. 本文设计的模型可以在低功耗的移动设备上高效运行,在高通的移动 CPU 和 65.5 英寸处理器上的测量速度为 21.5 tokens/s。
  5. MobileVLM 和大量 多模态大模型在 benchmark 的表现不相上下,证明了其在众多实际任务中的应用潜力。虽然本文主要关注的是边缘场景,但 MobileVLM 优于许多最新的 VLM,而这些 VLM 只能由云端强大的 GPU 支持。

MobileVLM

总体架构设计

考虑到为资源有限的边缘设备实现高效的视觉感知和推理的主要目标,研究者设计了 MobileVLM 的整体架构,如图 1 所示,模型包含三个组件:1) 视觉编码器,2) 定制的 LLM 边缘设备 (MobileLLaMA),以及 3) 高效的映射网络(文中称为 “轻量级下采样映射”,LDP),用于对齐视觉和文本空间。

视觉编码器

根据原文第 5.1 节中的经验分析,研究者利用分辨率为 336×336 的预训练 CLIP ViT-L/14 作为视觉编码器 F_enc。视觉 Transformer(ViT)将图像分割成大小一致的图像块,并对每个图像块做一次线性嵌入。随后和位置编码整合后,将结果向量序列输入正则变换编码器。通常情况下,分类用的 token 会被添加到该序列中,用于后续的分类任务。

MobileLLaMA

对于语言模型,本文缩小了 LLaMA 的规模,以方便部署,也就是说,本文提出的模型可以无缝地支持几乎所有流行的推理框架。此外,研究者还评估了边缘设备上的模型延迟,来选择合适的模型架构。神经架构搜索(NAS)是比较不错的选择,但目前研究者没有将其立马应用到当前的模型上。表 2 显示了本文架构的详细设置。

具体来说,本文使用 LLaMA2 中的 sentence piece tokenizer,词表大小为 32000,并从头开始训练嵌入层。这样作有利于后续进行蒸馏。由于资源有限,所有模型在预训练阶段使用的上下文长度都是 2k。不过,如《Extending context window of large language models via positional interpolation》中所述,推理时的上下文窗口可以进一步扩展到 8k。其他组件的详细设置如下。

  • 应用 RoPE 注入位置信息。
  • 应用预归一化来稳定训练。具体来说,本文使用 RMSNorm 代替层归一化, MLP 膨胀比使用 8/3 而不是 4。
  • 使用 SwiGLU 激活函数代替 GELU 。

高效的映射网络

视觉编码器和语言模型之间的映射网络对于对齐多模态特征至关重要。现有的模式有两种:Q-Former 和 MLP projection 。Q-Former 明确控制每个 query 包含的视觉 tokens 数量,以强制提取最相关的视觉信息。但是,这种方法不可避免地会丢失 tokens 的空间位置信息,而且收敛速度较慢。此外,它在边缘设备上的推理效率也不高。相比之下,MLP 保留了空间信息,但通常会包含背景等无用的 tokens。对于一幅 patch 大小为 P 的图像,有 N_v = HW/P^2 个视觉 token 需要注入到 LLM 中,这大大降低了整体推理速度。受 ViT 的条件位置编码算法 CPVT 的启发,研究者利用卷积来增强位置信息,并鼓励视觉编码器的局部交互。具体来说,研究者对基于深度卷积(PEG 的最简单形式)的移动友好操作进行了调研,这种操作既高效又能得到各种边缘设备的良好支持。

为了保留空间信息并最大限度地降低计算成本,本文使用了步长为 2 的卷积,从而减少了 75% 的视觉 token 数量。这种设计大大提高了整体推理速度。然而,实验结果表明,降低 token 取样数量会严重降低下游任务(如 OCR)的性能。为了减轻这种影响,研究者设计了一个更强大的网络来代替单个 PEG。高效的映射网络(称为轻量级下采样映射(LDP))的详细架构如图 2 所示。值得注意的是,这个映射网络只包含不到 2000 万个参数,运行速度比视觉编码器快约 81 倍。

实验结果

MobileLLaMA 的评估结果

在表 3 中,研究者在两个标准自然语言 benchmark 上对本文提出的模型进行了广泛的评估,这两个 benchmark 分别针对语言理解和常识推理。在前者的评估中,本文使用了语言模型评估工具(Language Model Evaluation Harness)。实验结果表明, MobileLLaMA 1.4B 与 TinyLLaMA 1.1B、Galactica 1.3B、OPT 1.3B 和 Pythia 1.4B 等最新开源模型不相上下。值得注意的是, MobileLLaMA 1.4B 优于 TinyLLaMA 1.1B,后者是在 2T 级别的 token 上训练的,是 MobileLLaMA 1.4B 的两倍。在 3B 级别,MobileLLaMA 2.7B 也表现出与 INCITE 3B (V1) 和 OpenLLaMA 3B (V1) 相当的性能,如表 5 所示,在骁龙 888 CPU 上,MobileLLaMA 2.7B 比 OpenLLaMA 3B 快约 40%。

与 SOTA VLM 的比较

本文评估了 LLaVA 在 GQA 、ScienceQA 、TextVQA 、POPE 和 MME 上的多模态性能。此外,本文还利用 MMBench 进行了综合比较。如表 4 所示,MobileVLM 尽管参数减少、训练数据有限,但性能却很有竞争力。在某些情况下,它的指标甚至优于之前最先进的多模态视觉语言模型。

带有 LoRA 的 MobileVLM

Low-Rank Adaptation(LoRA)可以用较少的可训练参数实现与全微调 LLM 相同甚至更好的性能。本文对这一做法进行了实证研究,以验证其多模态性能。具体来说,在 VLM 视觉指令调整阶段,本文冻结了除 LoRA 矩阵之外的所有 LLM 参数。在 MobileLLaMA 1.4B 和 MobileLLaMA 2.7B 中,更新后的参数分别只有完整 LLM 的 8.87% 和 7.41%。对于 LoRA ,本文将 lora_r 设为 128,lora_α 设为 256。结果如表 4 所示,可以看到,在 6 个 benchmark 上,带有 LoRA 的 MobileVLM 达到了与全微调相当的性能,这与 LoRA 的结果一致。

在移动设备上的延迟测试

研究者在 Realme GT 手机和英伟达 Jetson AGX Orin 平台上评估了 MobileLLaMA 和 MobileVLM 的推理延迟。该手机配备了骁龙 888 SoC 和 8GB 内存,可提供 26 TOPS 的计算能力。Orin 配备 32GB 内存,可提供惊人的 275 TOPS 计算能力。它采用 CUDA 11.4 版本,支持最新的并行计算技术,可提高性能。

消融实验

视觉骨干网络

在表 7 中,研究者比较了不同规模和不同视觉 token 数量下的多模态性能。所有实验均使用 CLIP ViT 作为视觉编码器。

VL 映射网络

由于特征交互和 token 交互都是有益的,研究者对前者采用了深度卷积,对后者采用了点卷积。表 9 显示了各种 VL 映射网络的性能。表 9 中的第 1 行是 LLaVA 中使用的模块,该模块只通过两个线性层对特征空间进行转换。第 2 行在每个 PW(pointwise)之前添加了一个 DW(depthwise)卷积,用于 token 交互,该卷积使用 2 倍下采样,步长为 2。加两个前端 PW 层会带来更多的特征级交互,从而弥补 token 减少带来的性能损失。第 4 行和第 5 行显示,增加更多参数并不能达到预期效果。第 4 和第 6 行显示,在映射网络末端对 token 进行下采样具有正面效果。

视觉分辨率和 token 数量

由于视觉 token 数直接影响整个多模态模型的推理速度,本文比较了两种设计方案:降低输入分辨率(RIR)和使用轻量级下采样投影器(LDP)。

SFT 的定量分析

在 LLaMA 上进行微调的 Vicuna 被广泛用于大型多模态模型 。表 10 比较了两种常见的 SFT 范式 Alpaca 和 Vicuna 。研究者发现,SQA、VQA、MME 和 MMBench 的得分都有显著提高。这表明,在 Vicuna 对话模式下,利用 ShareGPT 的数据对大型语言模型进行微调,最终可获得最佳的性能。为了更好地将 SFT 的提示格式与下游任务的训练相结合,本文删除了 MobileVLM 上的对话模式,发现 vicunav1 的表现最佳。

结论

简而言之,MobileVLM 是一套专为移动和物联网设备定制的高效、高能的移动版视觉语言模型。本文对语言模型和视觉映射网络进行了重置。研究者进行了广泛的实验,以选择合适的视觉骨干网络,设计高效的映射网络,并通过语言模型 SFT 等训练方案(包括预训练和指令调整的两阶段训练策略)和 LoRA 微调来增强模型能力。研究者在主流 VLM benchmark 上对 MobileVLM 的性能进行了严格评估。在典型的移动和物联网设备上,MobileVLM 也显示出前所未有的速度。研究者们认为相信,MobileVLM 将为移动设备或自动驾驶汽车上部署的多模态助手以及更广泛的人工智能机器人等广泛应用开辟新的可能性。

#Awesome-Robotics-Foundation-Models

大模型的出色能力有目共睹,而如果将它们整合进机器人,则有望让机器人拥有一个更加智能的大脑,为机器人领域带来新的可能性,比如自动驾驶、家用机器人、工业机器人、辅助机器人、医疗机器人、现场机器人和多机器人系统。大模型+机器人,详尽的综述报告来了,多位华人学者参与

预训练的大型语言模型(LLM)、大型视觉 - 语言模型(VLM)、大型音频 - 语言模型(ALM)和大型视觉导航模型(VNM)可以被用于更好地处理机器人领域的各种任务。将基础模型整合进机器人是一个快速发展的领域,机器人社区最近已经开始探索将这些大模型用于感知、预测、规划和控制等机器人领域。

近日,斯坦福大学和普林斯顿大学等多所大学以及英伟达和 Google DeepMind 等多家企业的一个联合研究团队发布了一篇综述报告,总结了基础模型在机器人研究领域的发展情况和未来挑战。

  • 论文地址:https://arxiv.org/pdf/2312.07843.pdf
  • 论文库:https://github.com/robotics-survey/Awesome-Robotics-Foundation-Models

团队成员中有很多我们熟悉的华人学者,包括朱玉可、宋舒然、吴佳俊、卢策吾等。

在范围广泛的大规模数据上预训练的基础模型在微调之后可以适用于多种多样的下游任务。基础模型已经在视觉和语言处理方面取得了重大突破,相关模型包括 BERT、GPT-3、GPT-4、CLIP、DALL-E 和 PaLM-E。

在基础模型出现之前,用于机器人的传统深度学习模型的训练使用的都是为不同任务收集的有限数据集。相反,基础模型则是会使用大范围多样化数据进行预训练,在其他领域(比如自然语言处理、计算机视觉和医疗保健)的应用证明了其适应能力、泛化能力和总体性能表现。最终,基础模型也有望在机器人领域展现出自己的潜力。图 1 展示了基础模型在机器人领域的概况。

相比于针对特定任务的模型,从基础模型迁移知识有可能减少训练时间和计算资源。尤其是在机器人相关领域,多模态基础模型可以将从不同传感器收集的多模态异构数据融合和对齐成紧凑的紧凑同质表征,而这正是机器人理解和推理所需的。其学习到的表征可望用于自动化技术栈的任何部分,包括感知、决策和控制。

不仅如此,基础模型还能提供零样本学习能力,也就是让 AI 系统有能力在没有任何示例或针对性训练的前提下执行任务。这能让机器人将所学知识泛化到全新的用例,增强机器人在非结构化环境中的适应能力和灵活性。

将基础模型整合进机器人系统能提升机器人感知环境以及与环境交互的能力,有可能实现上下文感知型机器人系统。

举个例子,在感知领域,大型视觉 - 语言模型(VLM)能够学习视觉和文本数据之间的关联,从而具备跨模态理解能力,从而辅助零样本图像分类、零样本目标检测和 3D 分类等任务。再举个例子,3D 世界中的语言定基(language grounding,即将 VLM 的上下文理解与 3D 现实世界对齐)可以通过将话语与 3D 环境中的具体对象、位置或动作关联起来,从而增强机器人的空间感知能力。

在决策或规划领域,研究发现 LLM 和 VLM 可以辅助机器人规范涉及高层规划的任务。

通过利用与操作、导航和交互有关的语言线索,机器人可以执行更加复杂的任务。比如对于模仿学习和强化学习等机器人策略学习技术,基础模型似乎有能力提升数据效率和上下文理解能力。特别是语言驱动的奖励可通过提供经过塑造的奖励来引导强化学习智能体。

另外,研究者也已经在利用语言模型来为策略学习技术提供反馈。一些研究表明,VLM 模型的视觉问答(VQA)能力可以用于机器人用例。举个例子,已有研究者使用 VLM 来回答与视觉内容有关的问题,从而帮助机器人完成任务。另外,也有研究者使用 VLM 来帮助数据标注,为视觉内容生成描述标签。

尽管基础模型在视觉和语言处理方面具备变革性的能力,但对于现实世界的机器人任务来说,基础模型的泛化和微调依然颇具挑战性。

这些挑战包括:

1) 缺少数据:如何为机器人操作、定位、导航等机器人任务获取互联网规模级的数据,以及如何使用这些数据执行自监督训练;

2) 巨大的差异性:如何应对物理环境、实体机器人平台和潜在的机器人任务的巨大多样性,同时保持基础模型所需的通用性;

3) 不确定性的量化问题:如何解决实例层面的不确定性(比如语言歧义或 LLM 幻觉)、分布层面的不确定性和分布移位问题,尤其是闭环的机器人部署引起的分布移位问题。

4) 安全评估:如何在部署之前、更新过程中、工作过程中对基于基础模型的机器人系统进行严格测试。

5) 实时性能:如何应对某些基础模型推理时间长的问题 —— 这会有碍基础模型在机器人上的部署,以及如何加速基础模型的推理 —— 这是在线决策所需的。

这篇综述论文总结了当前基础模型在机器人领域的使用情况。他们调查了当前的方法、应用、挑战,并建议了解决这些挑战的未来研究方向,他们也给出了将基础模型用于实现机器人自主能力的潜在风险。

基础模型背景知识

基础模型有数以十亿计的参数,并且使用了互联网级的大规模数据进行预训练。训练如此大规模和高复杂性的模型需要极高的成本。获取、处理和管理数据的成本也会很高。其训练过程需要大量计算资源,需要 GPU 或 TPU 等专用硬件,还需要用于模型训练的软件和基础设施,这些都需要资金。此外,需要基础模型还需要很长的时间,这也会导致高成本。因此这些模型往往是作为可插拔模块使用的,即将基础模型整合进各种应用中,而无需大量定制工作。

表 1 给出了常用基础模型的细节。

这一节将主要介绍 LLM、视觉 Transformer、VLM、具身多模态语言模型和视觉生成模型。还会介绍用于训练基础模型的不同训练方法。

他们首先介绍了一些相关的术语和数学知识,其中涉及 token 化、生成模型、判别模型、Transformer 架构、自回归模型、掩码式自动编码、对比学习和扩散模型。

然后他们介绍了大型语言模型(LLM)的示例和历史背景。之后重点说明了视觉 Transformer、多模态视觉 - 语言模型(VLM)、具身多模态语言模型、视觉生成模型。

机器人研究

这一节关注的是机器人决策、规划和控制。在这一领域,大型语言模型(LLM)和视觉语言模型(VLM)都有潜力用于增强机器人的能力。举个例子,LLM 可以促进任务规范过程,让机器人可以接收和解读来自人类的高级指令。

VLM 也有望为这一领域做出贡献。VLM 擅长分析视觉数据。要让机器人做出明智的决策和执行复杂的任务,视觉理解能力是至关重要的。现在,机器人可以使用自然语言线索来增强自己执行操作、导航和交互相关任务的能力。

基于目标的视觉 - 语言策略学习(不管是通过模仿学习还是强化学习)有望通过基础模型获得提升。语言模型还能为策略学习技术提供反馈。这个反馈循环有助于持续提升机器人的决策能力,因为机器人可以根据从 LLM 收到的反馈优化自己的行动。

这一节关注的是 LLM 和 VLM 在机器人决策领域的应用。

这一节分为六部分。其中第一部分介绍了用于决策和控制和机器人策略学习,其中包括基于语言的模仿学习和语言辅助的强化学习。

第二部分是基于目标的语言 - 图像价值学习。

第三部分介绍了使用大型语言模型来规划机器人任务,其中包括通过语言指令来说明任务以及使用语言模型生成任务规划的代码。

第四部分是用于决策的上下文学习(ICL)。

接下来是机器人 Transformer。

第六部分则是开放词汇库的机器人导航和操作。

表 2 给出了一些特定于机器人的基础模型,其中报告了模型的大小和架构、预训练任务、推理时间和硬件设置。

感知

与周围环境交互的机器人会接收不同模态的感官信息,比如图像、视频、音频和语言。这种高维数据对机器人在环境中的理解、推理和互动而言至关重要。基础模型可以将这些高维输入转换成容易解读和操作的抽象结构化表征。尤其是多模态基础模型可让机器人将不同感官的输入整合成一个统一的表征,其中包含语义、空间、时间和可供性信息。这些多模态模型需要跨模态的交互,通常需要对齐不同模态的元素来确保一致性和互相对应。比如图像描述任务就需要文本和图像数据对齐。

这一节将关注与机器人感知相关的一系列任务,这些任务可使用基础模型来对齐模态,从而获得提升。其中的重点是视觉和语言。

这一节分为五部分,首先是开放词汇库的目标检测和 3D 分类,然后是开放词汇库的语义分割,接下来是开放词汇库的 3D 场景和目标表征,再然后是学习到的功能可供性,最后是预测模型。

具身 AI

近段时间,有研究表明 LLM 可以成功用于具身 AI 领域,其中「具身(embodied)」通常是指在世界模拟器中的虚拟具身,而非具有实体机器人身体。

这方面已经出现了一些有趣的框架、数据集和模型。其中尤其值得一提的是将 Minecraft 游戏用作训练具身智能体的平台。举个例子,Voyager 使用了 GPT-4 来引导智能体探索 Minecraft 环境。其能通过上下文 prompt 设计来与 GPT-4 互动,而无需对 GPT-4 的模型参数进行微调。

机器人学习方面的一个重要研究方向是强化学习,也有研究者在尝试通过基础模型来为强化学习设计奖励。

使用基础模型辅助机器人执行高层规划自然也早有研究者尝试。此外也有研究者在尝试将基于思维链的推理和动作生成方法用于具身智能体。

挑战和未来方向

这一节会给出将基础模型用于机器人的相关挑战。该团队也会探索可望解决这些挑战的未来研究方向。

第一个挑战是克服训练用于机器人的基础模型时的数据稀缺问题,其中包括:

1. 使用非结构化游戏数据和未标注的人类视频来扩展机器人学习

2. 使用图像修复(Inpainting)来增强数据

3. 克服训练 3D 基础模型时的缺少 3D 数据的问题

4. 通过高保真模拟来生成合成数据

5. 使用 VLM 进行数据增强

6. 机器人的物理技能受限于技能的分布

第二个挑战则与实时性能有关,其中关键的是基础模型的推理时间。

第三个挑战涉及到多模态表征的局限性。

第四个挑战则是如何量化不同层级的不确定性的问题,比如实例层面和分布层面,另外还涉及到如何校准以及应对分布移位的难题。

第五个挑战涉及到安全评估,包括部署之前的安全测试和运行时的监控和对分布外情况的检测。

第六个挑战则涉及到如何选择:使用现有的基础模型还是为机器人构建新的基础模型?

第七个挑战涉及到机器人设置中的高度可变性。

第八个挑战是如何在机器人设置中进行基准评估以及保证可复现性。

#LoRA4

还是这说好这不是物联网的那个协议啊~~

第4部主要讲实现,及一些实用技巧

LoRA是Low-Rank Adaptation或Low-Rank Adaptors的缩写,它提供了一种用于对预先存在的语言模型进行微调的高效且轻量级的方法。

LoRA的主要优点之一是它的效率。通过使用更少的参数,lora显著降低了计算复杂度和内存使用。这使我们能够在消费级gpu上训练大型模型,并将我们的lora(以兆字节计)分发给其他人。

lora可以提高泛化性能。通过限制模型的复杂性,它们有助于防止过拟合,特别是在训练数据有限的情况下。这就产生了更有弹性的模型,这些模型在处理新的、看不见的数据时表现出色,或者至少保留了它们最初训练任务中的知识。

LoRA可以无缝集成到现有的神经网络架构中。这种集成允许以最小的额外训练成本对预训练模型进行微调和适应,使它们非常适合迁移学习应用。

本文将首先深入研究LoRA,然后以RoBERTa模型例从头开发一个LoRA,然后使用GLUE和SQuAD基准测试对实现进行基准测试,并讨论一些技巧和改进。

LoRA是如何工作的

LoRA的基本思想是将预训练的矩阵(即原始模型的参数)冻结(即处于固定状态),只在原始矩阵上添加一个小的delta,其参数比原始矩阵少。

例如矩阵W,它可以是全链接层的参数,也可以是transformer注意力机制的矩阵之一:

如果w-orig的维度是n×m,我们只是初始化一个新的具有相同维度的矩阵来微调则会把参数翻倍。

所以我们通过从低维矩阵B和A进行矩阵乘法来构建ΔW,使其比原始矩阵“维度”更少。

其中,我们首先定义秩r,并且小于基本矩阵的维数r≪n, r≪m。那么矩阵B是n×r矩阵A是r×m。将它们相乘得到一个与W具有相同维数的矩阵,但是参数更少。

我们希望在训练开始的时候像原始模型一样,所以B通常初始化为全零,而A初始化为随机(通常为正态分布)值。

假设我们的基本维数是1024,我们选择了一个LoRA秩r为4,那么:

W有1024 * 1024≈100万个参数;A和B各有r * 1024 = 4 * 1024≈4k参数,共8k

也就是说只需要训练0.8%的参数就可以用LoRA更新我们的矩阵。在LoRA论文中,他们用alpha参数衡量delta矩阵:

如果你只是将α设置为r并微调学习率,可已得到与论文近似的结果。我们在下面的实现中忽略这个细节,但它是许多其他LoRA库(例如hugs Face的PEFT)中的一个常见特性。

手写LoRA

我们在这里的实现将在PyTorch中完成,虽然我们希望严格遵循原始的LoRA论文,但是我们稍微简化了代码,这样它应该更容易阅读,同时仍然显示了基本元素。

我们这里使用RoBERTa模型。使用Huggingface的实现RobertaSelfAttention作为基类创建新类LoraRobertaSelfAttention,这里将初始化LoRA矩阵。所有B矩阵初始化为零,所有A矩阵初始化为正态分布中的随机数。

class LoraRobertaSelfAttention(RobertaSelfAttention):
    """
    Extends RobertaSelfAttention with LoRA (Low-Rank Adaptation) matrices.
    LoRA enhances efficiency by only updating the query and value matrices.
    This class adds LoRA matrices and applies LoRA logic in the forward method.
 
    Parameters:
    - r (int): Rank for LoRA matrices.
    - config: Configuration of the Roberta Model.
    """
    def __init__(self, r=8, *args, **kwargs):
        super().__init__(*args, **kwargs)
        d = self.all_head_size
 
        # Initialize LoRA matrices for query and value
        self.lora_query_matrix_B = nn.Parameter(torch.zeros(d, r))
        self.lora_query_matrix_A = nn.Parameter(torch.randn(r, d))
        self.lora_value_matrix_B = nn.Parameter(torch.zeros(d, r))
        self.lora_value_matrix_A = nn.Parameter(torch.randn(r, d))
给定这些矩阵,需要定义新的类方法lora_query和lora_value。这些计算ΔW矩阵,即BA,并将其添加到原始矩阵中,我们从原始方法query和value中调用原始矩阵。

 class LoraRobertaSelfAttention(RobertaSelfAttention):
    # ...
 
    def lora_query(self, x):
        """
        Applies LoRA to the query component. Computes a modified query output by adding
        the LoRA adaptation to the standard query output. Requires the regular linear layer
        to be frozen before training.
        """
        lora_query_weights = torch.matmul(self.lora_query_matrix_B, self.lora_query_matrix_A)
        return self.query(x) + F.linear(x, lora_query_weights)
 
    def lora_value(self, x):
        """
        Applies LoRA to the value component. Computes a modified value output by adding
        the LoRA adaptation to the standard value output. Requires the regular linear layer
        to be frozen before training.
        """
        lora_value_weights = torch.matmul(self.lora_value_matrix_B, self.lora_value_matrix_A)
        return self.value(x) + F.linear(x, lora_value_weights)

要使用这些方法,我们必须重写RobertaSelfAttention的原始转发函数。虽然这有点硬编码(后面有改进的讨论),但它非常简单。首先,我们从modeling_roberta.py复制原始的转发代码。然后将每次对query的调用替换为lora_query,并将每次对value的调用替换为lora_value。然后函数看起来像这样:

class LoraRobertaSelfAttention(RobertaSelfAttention):
    # ...
    def forward(self, hidden_states, *args, **kwargs):
        """Copied from
 https://github.com/huggingface/transformers/blob/main/src/transformers/models/roberta/modeling_roberta.py
        but replaced the query and value calls with calls to the
        lora_query and lora_value functions.
        We will just sketch of how to adjust this here.
        Change every call to self.value and self.query in the actual version.
        """
        # original code for query:
        ## mixed_query_layer = self.query(hidden_states)
        # updated query for LoRA:
        mixed_query_layer = self.lora_query(hidden_states)
 
        # The key has no LoRA, thus leave these calls unchanged
        key_layer = self.transpose_for_scores(self.key(hidden_states))
 
        # original code for value:
        ## value_layer = self.transpose_for_scores(self.value(hidden_states))
        # updated value for LoRA:
        value_layer = self.transpose_for_scores(self.lora_value(hidden_states))
         
        # ... (rest of the forward code, unchanged)

这样我们就在注意力层添加了lora部分。剩下任务就是替换掉原来RoBERTa模型中的注意力模块。

这里我们需要遍历RoBERTa模型的每个命名组件,检查它是否属于RobertaSelfAttention类,如果是,则将其替换为LoraRobertaSelfAttention,同时保留原始权重矩阵。

class LoraWrapperRoberta(nn.Module):
    def __init__(self, task_type, num_classes=None, dropout_rate=0.1, model_id="roberta-large",
                  lora_rank=8, train_biases=True, train_embedding=False, train_layer_norms=True):
        """
        A wrapper for RoBERTa with Low-Rank Adaptation (LoRA) for various NLP tasks.
        - task_type: Type of NLP task ('glue', 'squad_v1', 'squad_v2').
        - num_classes: Number of classes for classification (varies with task).
        - dropout_rate: Dropout rate in the model.
        - model_id: Pre-trained RoBERTa model ID.
        - lora_rank: Rank for LoRA adaptation.
        - train_biases, train_embedding, train_layer_norms:
            Flags whether to keep certain parameters trainable
            after initializing LoRA.
         
        Example:
            model = LoraWrapperRoberta(task_type='glue')
        """
        super().__init__()
        # 1. Initialize the base model with parameters
        self.model_id = model_id
        self.tokenizer = RobertaTokenizer.from_pretrained(model_id)
        self.model = RobertaModel.from_pretrained(model_id)
        self.model_config = self.model.config
 
        # 2. Add the layer for the benchmark tasks
        d_model = self.model_config.hidden_size
        self.finetune_head_norm = nn.LayerNorm(d_model)
        self.finetune_head_dropout = nn.Dropout(dropout_rate)
        self.finetune_head_classifier = nn.Linear(d_model, num_classes)
 
        # 3. Set up the LoRA model for training
        self.replace_multihead_attention()
        self.freeze_parameters_except_lora_and_bias()

self.replace_multihead_attention:用我们之前写的LoraRobertaSelfAttention替换了所有神经网络的注意力层

self.freeze_parameters_except_lora_and_bias:这将冻结训练的所有主要参数,这样梯度和优化器步骤仅应用于LoRA参数以及我们希望可训练的其他例如归一化层等参数。

class LoraWrapperRoberta(nn.Module):
    # ...
 
    def replace_multihead_attention_recursion(self, model):
        """
        Replaces RobertaSelfAttention with LoraRobertaSelfAttention in the model.
        This method applies the replacement recursively to all sub-components.
 
        Parameters
        ----------
        model : nn.Module
            The PyTorch module or model to be modified.
        """
        for name, module in model.named_children():
            if isinstance(module, RobertaSelfAttention):
                # Replace RobertaSelfAttention with LoraRobertaSelfAttention
                new_layer = LoraRobertaSelfAttention(r=self.lora_rank, config=self.model_config)
                new_layer.load_state_dict(module.state_dict(), strict=False)
                setattr(model, name, new_layer)
            else:
                # Recursive call for child modules
                self.replace_multihead_attention_recursion(module)

然后就是递归地遍历所有模型部分,冻结所有不想再训练的参数:

class LoraWrapperRoberta(nn.Module):
    # ...
 
    def freeze_parameters_except_lora_and_bias(self):
        """
        Freezes all model parameters except for specific layers and types based on the configuration.
        Parameters in LoRA layers, the finetune head, bias parameters, embeddings, and layer norms
        can be set as trainable based on class settings.
        """
        for name, param in self.model.named_parameters():
            is_trainable = (
                "lora_" in name or
                "finetune_head_" in name or
                (self.train_biases and "bias" in name) or
                (self.train_embeddings and "embeddings" in name) or
                (self.train_layer_norms and "LayerNorm" in name)
            )
            param.requires_grad = is_trainable

以上就是我们最简单的一个LORA的实现,下面我们看看效果

用GLUE和SQuAD进行基准测试

我们使用GLUE(通用语言理解评估)和SQuAD(斯坦福问答数据集)基准进行评估。

GLUE基准是一套由8个不同的NLP任务组成的测试,它包括情感分析、文本蕴涵和句子相似性等挑战,为模型的语言适应性和熟练程度提供了一个强有力的衡量标准。

SQuAD专注于评估问答模型。它包括从维基百科的段落中提取答案,模型在其中识别相关的文本跨度。SQuAD v2是一个更高级的版本,引入了无法回答的问题,增加了复杂性,并反映了现实生活中的情况,在这种情况下,模型必须识别文本缺乏答案。

对于下面的基准测试,没有调优任何超参数,没有进行多个runes(特别是较小的GLUE数据集容易出现随机噪声),没有进行任何早停,也没有从之前的GLUE任务开始微调(通常这样做是为了减少小数据集噪声的可变性并防止过拟合)。

从刚初始化的rank为8的LoRA注入到RoBERTa-base模型开始,每个任务的训练精确地进行了6次训练。在前2个epoch中,学习率线性放大到最大值,然后在剩余的4个epoch中线性衰减到零。所有任务的最大学习率为5e-4。所有任务的批处理大小为16

基于roberta的模型有1.246亿个参数。有了LoRA我们只有42万个参数需要训练。这意味着我们实际上只使用0.34%的原始参数进行训练。LoRA为这些特定任务引入的参数数量非常少,实际磁盘大小仅为1.7 MB。

训练后重新加载LoRA参数,在每个任务的验证集上测试性能。结果如下:

它清楚地证明了我们的LoRA实现是有效的,并且注入的低秩矩阵正在学习。

改进思路

我们上面很多的代码都是硬编码,有人可能会想:“除了重新编码自关注类并执行复杂的替换之外,还有更有效、更通用(即可转移到其他网络体系结构)的方法吗?”

其实我们可以简单地实现nn.Linear的包装器,也就是说我们想用它替换哪些层,通过检查它们的名字直接进行替换就可以了。

class LoraLinear(nn.Linear):
    """
    Extends a PyTorch linear layer with Low-Rank Adaptation (LoRA).
    LoRA adds two matrices to the layer, allowing for efficient training of large models.
    """
    def __init__(self, in_features, out_features, r=8, *args, **kwargs):
        super().__init__(in_features, out_features, *args, **kwargs)
 
        # Initialize LoRA matrices
        self.lora_matrix_B = nn.Parameter(torch.zeros(out_features, r))
        self.lora_matrix_A = nn.Parameter(torch.randn(r, in_features))
         
        # Freeze the original weight matrix
        self.weight.requires_grad = False
 
    def forward(self, x: Tensor) -> Tensor:
        # Compute LoRA weight adjustment
        lora_weights = torch.matmul(self.lora_matrix_B, self.lora_matrix_A)
        # Apply the original and LoRA-adjusted linear transformations
        return super().forward(x) + F.linear(x, lora_weights)

只将LoRA注入所有线性层也成为一种相当普遍的做法。因为保持偏差和归一化已经很小了,所以你不需要再去精简它们。

另外,上面的代码实际上是(接近)huggingface PEFT库实现LoRA的方式。虽然我们的实现是可用的,但是还是强烈建议您使用PEFT,因为我们不是为了学习原理,而不是新造一个轮子。所以下面我们还是要介绍一下如何使用PEFT         

PEFT使用指南

我们以量化的方式加载模型。由于bitsandbytes与transformers 库(于2023年5月推出)的集成,这是一件轻而易举的事情。

import bitsandbytes as bnb
 from transformers import AutoModel, AutoModelForSequenceClassification, BitsAndBytesConfig
 
 # Configuration to load a quantized model
 bnb_config = BitsAndBytesConfig(
    load_in_4bit=True, # Enable 4-bit loading
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.bfloat16,
    llm_int8_skip_modules=['classifier', 'qa_outputs'], # Skip these for quantization
 )
 
 # Load the model from Huggingface with quantization
 model = AutoModelForSequenceClassification.from_pretrained('roberta-base',
          torch_dtype="auto", quantization_config=bnb_config)

我们这里使用4位的量化加载,速度会慢一些,我们也可以可以通过检查模型的模块和参数数据类型来验证4位加载:

# Verify 4-bit loading
 print("Verifying 4-bit elements (Linear4bit) in the attention layer:")
 print(model.roberta.encoder.layer[4].attention)
 
 print("Checking for uint8 data type:")
 print(model.roberta.encoder.layer[4].attention.self.query.weight.dtype)

现在用PEFT注入LoRA参数。PEFT库通过模块的名称定位要替换的模块;因此要看一下模型model.named_parameters()。这是非量子化roberta基模型的样子。

Module                                                       Parameters
 ---------------------------------------------------------- ------------
 roberta.embeddings.word_embeddings.weight                     38_603_520
 roberta.embeddings.position_embeddings.weight                   394_752
 roberta.embeddings.token_type_embeddings.weight                     768
 roberta.embeddings.LayerNorm.weight                                 768
 roberta.embeddings.LayerNorm.bias                                   768
 roberta.encoder.layer.0.attention.self.query.weight             589_824
 roberta.encoder.layer.0.attention.self.query.bias                   768
 roberta.encoder.layer.0.attention.self.key.weight               589_824
 roberta.encoder.layer.0.attention.self.key.bias                     768
 roberta.encoder.layer.0.attention.self.value.weight             589_824
 roberta.encoder.layer.0.attention.self.value.bias                   768
 roberta.encoder.layer.0.attention.output.dense.weight           589_824
 roberta.encoder.layer.0.attention.output.dense.bias                 768
 roberta.encoder.layer.0.attention.output.LayerNorm.weight           768
 roberta.encoder.layer.0.attention.output.LayerNorm.bias             768
 roberta.encoder.layer.0.intermediate.dense.weight             2_359_296
 roberta.encoder.layer.0.intermediate.dense.bias                   3_072
 roberta.encoder.layer.0.output.dense.weight                   2_359_296
 roberta.encoder.layer.0.output.dense.bias                           768
 roberta.encoder.layer.0.output.LayerNorm.weight                     768
 roberta.encoder.layer.0.output.LayerNorm.bias                       768
 roberta.encoder.layer.1.attention.self.query.weight             589_824
 ...
 roberta.encoder.layer.11.output.LayerNorm.bias                       768
 classifier.dense.weight                                         589_824
 classifier.dense.bias                                               768
 classifier.out_proj.weight                                         1_536
 classifier.out_proj.bias                                               2
 ---------------------------------------------------------- ------------
 TOTAL                                                       124_647_170

然后我们可以指定要为那些层进行LoRA微调。。所有未注入LoRA参数的层将自动冻结。如果我们想以原始形式训练层,可以通过将列表传递给Lora-Config的modules_to_save参数来指定它们。在我们的例子中,

下面的示例注入rank为2的LoRA。我们用上面的8来指定alpha参数,因为这是我们第一次尝试的秩,应该可以让我们使用上面例子中的学习率。

import peft
 
 # Config for the LoRA Injection via PEFT
 peft_config = peft.LoraConfig(
    r=2, # rank dimension of the LoRA injected matrices
    lora_alpha=8, # parameter for scaling, use 8 here to make it comparable with our own implementation
    target_modules=['query', 'key', 'value', 'intermediate.dense', 'output.dense'], # be precise about dense because classifier has dense too
    modules_to_save=["LayerNorm", "classifier", "qa_outputs"], # Retrain the layer norm; classifier is the fine-tune head; qa_outputs is for SQuAD
    lora_dropout=0.1, # dropout probability for layers
    bias="all", # none, all, or lora_only
 )
 
 model = peft.get_peft_model(model, peft_config)

为LoRA注入指定更多模块可能会增加VRAM需求。如果遇到VRAM限制,请考虑减少目标模块的数量或降低LoRA等级。

对于训练,特别是QLoRA,选择与量化矩阵兼容的优化器。将标准优化器替换为bitsandbytes变体,如下所示:

import torch
 import bitsandbytes as bnb
 
 # replace this
 optimizer = torch.optim.AdamW(args here)
 # with this
 optimizer = bnb.optim.AdamW8bit(same args here)

这样就可以像以前一样训练这个模型了,训练完成后,保存和重新加载模型的过程很简单。使用模型。Save_pretrained保存模型,指定所需的文件名。PEFT库将在此位置自动创建一个目录,在其中存储模型权重和配置文件。该文件包括基本模型和LoRA配置参数等基本细节。

用peft.AutoPeftModel.from_pretrained,将目录路径作为参数可以重新加载模型。要记住的关键一点是,LoRA配置目前没有保留初始化automodelforsequencecclassification的类的数量。当使用from_pretrained时,需要手动输入这个作为附加参数。

重新加载的模型将包含应用了LoRA的原始基本模型。如果您决定将LoRA永久地集成到基本模型矩阵中,只需执行model.merge_and_unload()。

总结

我们从简单的(尽管是硬编码的)LoRA实现,深入了解了LoRA、它们的实际实现和基准测试。并且介绍了另一种更有效的实现策略,并深入研究了用于LoRA集成的PEFT等现有库的优点。

完整的代码可以在这里找到:

​​https://github.com/Montinger/Transformer-Workbench/tree/main/LoRA-from-scratch​​

#SSM进化路径

对 SSM 感兴趣的研究者不妨读一下这篇博士论文。,挑战Transformer的Mamba是什么来头?作者博士论文理清SSM进化路径

在大模型领域,Transformer 凭一己之力撑起了整个江山。但随着模型规模的扩展和需要处理的序列不断变长,Transformer 的局限性也逐渐凸显,比如其自注意力机制的计算量会随着上下文长度的增加呈平方级增长。为了克服这些缺陷,研究者们开发出了很多注意力机制的高效变体,但收效甚微。

最近,一项名为「Mamba」的研究似乎打破了这一局面,它在语言建模方面可以媲美甚至击败 Transformer。这都要归功于作者提出的一种新架构 —— 选择性状态空间模型( selective state space model),该架构是 Mamba 论文作者 Albert Gu 此前主导研发的 S4 架构(Structured State Spaces for Sequence Modeling )的一个简单泛化。

在 Mamba 论文发布后,很多研究者都对 SSM(state space model)、S4 等相关研究产生了好奇。其中,有位研究者表示自己要在飞机上把这些论文都读一下。对此,Albert Gu 给出了更好的建议:他的博士论文其实把这些进展都梳理了一下,读起来可能更有条理。

在论文摘要中,作者写到,序列模型是深度学习模型的支柱,已在科学应用领域取得了广泛成功。然而,现有的方法需要针对不同的任务、模态和能力进行广泛的专业化;存在计算效率瓶颈;难以对更复杂的序列数据(如涉及长依赖关系时)进行建模。因此,继续开发对一般序列进行建模的原则性和实用性方法仍然具有根本性的重要意义。

论文链接:https://stacks.stanford.edu/file/druid:mb976vf9362/gu_dissertation-augmented.pdf

作者在论文中阐述了一种使用状态空间模型进行深度序列建模的新方法,这是一种灵活的方法,具有理论基础,计算效率高,并能在各种数据模态和应用中取得强大的结果。

首先,作者介绍了一类具有众多表征和属性的模型,它们概括了标准深度序列模型(如循环神经网络和卷积神经网络)的优势。然而,作者表明计算这些模型可能具有挑战性,并开发了在当前硬件上运行非常快速的新型结构化状态空间,无论是在扩展到长序列时还是在自回归推理等其他设置中都是如此。最后,他们提出了一个用于对连续信号进行增量建模的新颖数学框架,该框架可与状态空间模型相结合,为其赋予原则性的状态表示,并提高其对长程依赖关系的建模能力。总之,这一类新方法为机器学习模型提供了有效而多用途的构建模块,特别是在大规模处理通用序列数据方面。

以下是论文各部分简介。

深度序列模型

针对序列数据的深度学习模型可被视为围绕循环、卷积或注意力等简单机制建立的序列到序列转换。

这些基元(primitive)可以被纳入标准的深度神经网络架构,形成主要的深度序列模型系列:循环神经网络(RNN)、卷积神经网络(CNN)和 Transformers,它们表达了强大的参数化变换,可以使用标准的深度学习技术(如梯度下降反向传播)进行学习。图 1.1 和定义 1.1 展示了本论文中使用的序列模型抽象,第 2.1 节将结合实例对其进行更正式的定义。

定义 1.1(非正式)。作者使用序列模型来指代在序列 y = f_θ(x) 上的参数化映射,其中输入和输出 x、y 是 R^D 中长度为 L 的特征向量序列,θ 是通过梯度下降学习的参数。

上述每个模型系列都为机器学习带来了巨大的成功:例如,RNN 为机器翻译带来了深度学习,CNN 是第一个神经音频生成模型,而 Transformers 则彻底改变了 NLP 的广阔领域。

不过,这些模型也有其序列机制所遗留的折衷问题。例如,RNN 对于序列数据来说是一个天然的有状态模型,每个时间步只需要恒定的计算 / 存储,但训练速度慢,而且存在优化困难(如梯度消失问题),这限制了它们处理长序列的能力。CNN 专注于局部上下文,编码 shift equivariance 等特性,并具有快速、可并行训练的特点,但其序列推理成本较高,且上下文长度受到固有限制。Transformers 因其处理长程依赖关系的能力和可并行性而获得巨大成功,但在序列长度上存在二次扩展问题。另一个最新的模型系列是神经微分方程(NDE),这是一种有理论基础的数学模型,理论上可以解决连续时间问题和长期依赖关系,但效率非常低。

这些问题显示了深度序列模型面临的三大挑战。

挑战一:通用能力

深度学习的一个广泛目标是开发可用于各种问题的通用构建模块。序列模型为解决许多此类问题提供了一个通用框架。它们可以应用于任何可被投射为序列的环境。然而,当前的模型通常仍需要大量的专业化能力,以解决特定任务和领域的问题,或针对特定的能力。各类模型的优势分析如下:

  • RNN:需要快速更新隐藏状态的有状态设置,例如在线处理任务和强化学习;
  • CNN:对音频、图像和视频等均匀采样的感知信号进行建模;
  • Transformers:对语言等领域中密集、复杂的交互进行建模;
  • NDE:处理非典型时间序列设置,如缺失或不规则采样数据。

反之,每个模型系列都可能在其不擅长的功能方面举步维艰。

挑战二:计算效率

在实践中应用深度序列模型需要计算其定义的函数(即参数化序列到序列映射),这可以有多种形式。在训练时,任务一般可以用整个输入序列的损失函数来表述,算法的核心问题是如何高效地计算前向传递。在推理时(训练完成后部署模型),设置可能会发生变化;例如,在在线处理或自回归生成设置中,输入每次只显示一个时间步,模型必须能够高效地按顺序处理这些输入。

这两种情况对不同的模型系列都提出了挑战。例如,RNN 本身是序列性的,很难在 GPU 和 TPU 等现代硬件加速器上进行训练,而并行性则能使其受益。另一方面,CNN 和 Transformers 则难以进行高效的自回归推理,因为它们不是有状态的;处理单个新输入的成本可能会与模型的整个上下文大小成比例关系。更奇特的模型可能会带来额外的功能,但通常会使其计算更加困难和缓慢(如需要调用昂贵的微分方程求解器)。

挑战三:长程依赖

现实世界中的序列数据可能需要推理数以万计的时间步骤。除了处理长输入所需的计算问题外,解决这一问题还需要能够对此类长程依赖(LRD)中存在的复杂交互进行建模。具体来说,困难可能来自于无法捕捉数据中的交互,比如模型的上下文窗口有限;也可能来自于优化问题,比如在循环模型中通过长计算图进行反向传播时的梯度消失问题。

由于效率、表达能力或训练能力方面的限制,长程依赖是序列模型长期以来面临的挑战。所有标准模型系列,如 NDE、RNN、CNN 和 Transformers,都包括许多旨在解决这些问题的专门变体。例如对抗梯度消失的正交和 Lipschitz RNN、增加上下文大小的空洞卷积,以及日益庞大的高效注意力变体系列,这些变体降低了对序列长度的二次依赖。然而,尽管这些解决方案都是针对长程依赖设计的,但在 Long Range Arena 等具有挑战性的基准测试中,它们的表现仍然不佳。

 状态空间序列模型

本论文介绍了基于线性状态空间模型(SSM)的新系列深度序列模型。作者将 SSM 定义为一个简单的序列模型,它通过一个隐式的潜在状态 x (t)∈R^N 映射一个 1 维函数或序列 

SSM 是一种基础科学模型,广泛应用于控制论、计算神经科学、信号处理等领域。广义上,SSM 一词指的是对潜变量如何在状态空间中演化进行建模的任何模型。这些广义的 SSM 有许多种,可以改变 x 的状态空间(如连续、离散或混合空间)、y 的观测空间、过渡动态、附加噪声过程或系统的线性度。SSM 在历史上通常指隐马尔可夫模型(HMM)和线性动力系统(LDS)的变体,如分层狄利克雷过程(HDP-HMM)和 Switching Linear Dynamical 系统(SLDS)。

方程(1.1)的状态空间模型在状态空间和动力学上都是连续的,并且是完全线性和确定性的,但还没有被用作定义 1.1 意义上的深度序列模型。本论文探讨了状态空间序列模型的诸多优点,以及如何利用它们来解决一般序列建模难题,同时克服其自身的局限性。

通用序列模型

SSM 是一种简单而基本的模型,具有许多丰富的特性。它们与 NDE、RNN 和 CNN 等模型族密切相关,实际上可以以多种形式编写,以实现通常需要专门模型才能实现的各种功能(挑战一)。

  • SSM 是连续的。SSM 本身是一个微分方程。因此,它可以执行连续时间模型的独特应用,如模拟连续过程、处理缺失数据,以及适应不同的采样率。
  • SSM 是循环的。可以使用标准技术将 SSM 离散化为线性 recurrence,并在推理过程中模拟为状态循环模型,每个时间步的内存和计算量保持不变。
  • SSM 是卷积系统。SSM 是线性时不变系统,可显式表示为连续卷积。此外,离散时间版本可以在使用离散卷积进行训练时并行化,从而实现高效训练。

因此,SSM 是一种通用序列模型,在并行和序列环境以及各种领域(如音频、视觉、时间序列)中都能高效运行。论文第 2 章介绍了 SSM 的背景,并阐述了状态空间序列模型的这些特性。

不过,SSM 的通用性也有代价。原始 SSM 仍然面临两个额外挑战 —— 也许比其他模型更严重 —— 这阻碍了它们作为深度序列模型的使用。挑战包括:(1)一般 SSM 比同等大小的 RNN 和 CNN 慢得多;(2)它们在记忆长依赖关系时会很吃力,例如继承了 RNN 的梯度消失问题。

作者通过 SSM 的新算法和理论来应对这些挑战。

利用结构化 SSM 进行高效计算(S4)

遗憾的是,由于状态表示 x (t) ∈ R^N 对计算和内存的要求过高(挑战二),通用的 SSM 在实践中无法用作深度序列模型。

对于 SSM 的状态维度 N 和序列长度 L,仅计算完整的潜在状态 x 就需要 O (N^2L) 次运算和 O (NL) 的空间 —— 与计算总体输出的 Ω(L + N) 下界相比。因此,对于合理大小的模型(例如 N ≈ 100),SSM 使用的内存要比同等大小的 RNN 或 CNN 多出几个数量级,因此作为通用序列建模解决方案,SSM 在计算上是不切实际的。

要克服这一计算瓶颈,就必须以一种适合高效算法的方式对状态矩阵 A 施加结构。作者介绍了具有各种形式结构矩阵 A 的结构化状态空间序列模型(S4)(或简称结构化状态空间)家族,以及能以任何表示形式(如循环或卷积)高效计算 S4 模型的新算法。

论文第 3 章介绍了这些高效 S4 模型的不同类型。第一种结构使用状态矩阵的对角参数化(diagonal parameterization),它非常简单、通用,足以表示几乎所有的 SSM。然后,作者通过允许低秩校正项对其进行推广,这对于捕捉后面介绍的一类特殊的 SSM 是必要的。通过结合众多技术思想,如生成函数、线性代数变换和结构矩阵乘法的结果,作者为这两种结构开发了时间复杂度为 

图片

 和空间复杂度为 O (N + L) 的算法,这对于序列模型来说基本上是严密的。

使用 HIPPO 解决长程依赖关系

即使不考虑计算问题,基本的 SSM 在实验中仍然表现不佳,而且无法建模长程依赖关系(挑战三)。直观地说,其中一种解释是线性一阶 ODE 求解为指数函数,因此可能会出现梯度随序列长度呈指数级缩放的问题。这也可以从它们作为线性 recurrence 的解释中看出,这涉及到反复对一个 recurrent 矩阵进行幂运算,这就是众所周知的 RNN 梯度消失/爆炸问题的起因。

在第 4 章中,作者从 SSM 后退一步,转而研究如何从第一性原理出发,用循环模型对 LRD 进行建模。他们开发了一个名为 HIPPO 的数学框架,它形式化并解决了一个名为在线函数逼近(或记忆)的问题。这种方法旨在通过保持对连续函数历史的压缩,以逐步记忆连续函数。尽管这些方法的动机完全独立,但它们都是 SSM 的具体形式。这些最终的方法被证明是 SSM 的特定形式 —— 尽管它们的动机是完全独立的。

论文第 5 章完善了这一框架,并将其与 SSM 抽象更严格地联系起来。它引入了一个正交 SSM 概念,广泛推广了 HIPPO,并推导出更多实例和理论结果,例如如何以原则性的方式初始化所有 SSM 参数。

HIPPO 概览

考虑一个输入函数 u (t)、一个固定的概率度量 ω(t),以及 N 个正交基函数(如多项式)组成的序列。在每个时间 t,u 在时间 t 之前的历史都可以投影到这个基上,从而得到一个系数向量 x (t)∈ R^N,这个向量代表了 u 的历史相对于所提供的度量 ω 的最佳近似值。函数 u (t)∈R 映射到系数 x (t)∈R^N 的映射被称为关于度量 ω 的高阶多项式投影算子 (HIPPO)。在很多情况下,在许多情况下,其形式为 x ′ (t) = Ax (t) + Bu (t),对于 (A, B) 有封闭形式的公式。

HIPPO 和 S4 的组合

HIPPO 提供了一个数学工具来构建具有重要属性的 SSM,而 S4 是关于计算表示的。第 6 章正式将两者联系起来,并说明它们可以结合起来,以获得两个世界的最佳效果。论文表明,HIPPO 生成的用于处理长程依赖关系的特殊矩阵实际上可以用第 3 章中开发的特定结构形式来编写。这就提供了结合 HIPPO 的 S4 的具体实例,从而产生了一个具有丰富功能、非常高效并擅长长程推理的通用序列模型。

应用、消融和扩展

通用序列建模功能

第 7 章对 S4 方法在各种领域和任务中的应用进行了全面的实证验证。当 S4 方法被纳入一个通用的简单深度神经网络时,它在许多基准测试中推进了 SOTA。

特别的亮点和功能包括:  

  • 通用序列建模。在不改变架构的情况下,S4 在语音分类方面超越了音频 CNN,在时间序列预测问题上优于专门的 Informer 模型,在序列 CIFAR 方面与 2-D ResNet 相媲美,准确率超过 90%。
  • 长程依赖。在针对高效序列模型的 LRA 基准测试中,S4 的速度与所有基线一样快,同时比所有 Transformer 变体的平均准确率高出 25% 以上。S4 是第一个解决了 LRA Path-X 任务(长度为 16384)这一难题的模型,准确率达到 96%,而之前所有工作的随机猜测准确率仅为 50%。
  • 采样分辨率变化。与专门的 NDE 方法一样,S4 无需再训练即可适应时间序列采样频率的变化。
  • 大规模生成建模与快速自回归生成。在 CIFAR-10 密度估计方面,S4 与最好的自回归模型(每维 2.85 比特)不相上下。在 WikiText-103 语言建模方面,S4 大幅缩小了与 Transformers 的差距(在 0.5 困惑度范围内),在无注意力模型中实现了 SOTA。与 RNN 一样,在 CIFAR-10/WikiText-103 上,S4 利用其潜在状态生成像素 /token 的速度比标准自回归模型快 60 倍。

理论消融

作者对 S4 的处理讨论了训练 SSM 的许多理论细节,例如如何仔细初始化每个参数以及如何纳入 HIPPO 框架。他们对这些细节进行了全面的实证分析和消融研究,验证了他们的 SSM 理论的各个方面。例如,他们验证了 HIPPO 大大提高了 SSM 的建模能力,在标准序列模型基准上的性能比原始 SSM 实例提高了 15%。在算法上,他们的 S4 算法比传统的 SSM 算法提高了几个数量级(例如,速度提高了 30 倍,内存使用量减少到 1/400)。

应用:音频波形生成

作为一种具有多种特性的序列建模基元,S4 可以被整合到不同的神经网络架构中,并以多种方式使用。第 8 章介绍了 S4 在原始音频波形生成中的应用,由于音频波形的采样率较高,这是一个具有挑战性的问题。这一章节介绍了围绕 S4 构建的 SaShiMi 多尺度架构,该架构在包括自回归和扩散在内的多种生成建模范式中,推动了无限制音频和语音生成技术的发展。该应用突显了 S4 的灵活功能,包括高效训练、快速自回归生成和用于连续信号建模的强大归纳偏置。

扩展:用于计算机视觉的多维信号

虽然作者主要关注一维序列,但某些形式的数据本身具有更高的维度,如图像(二维)和视频(三维)。序列模型的灵活性也适用于这些环境。第 9 章介绍了 S4ND,这是 S4 从一维到多维(N-D)信号的扩展。S4ND 继承了 S4 的特性,如直接对底层连续信号建模,并具有更好地处理输入分辨率变化等相关优势,是第一个在 ImageNet 等大型视觉任务中性能具有竞争力的连续模型。

梳理介绍几篇 SSM 研究,供大家了解、学习。

论文一:Pretraining Without Attention

  • 论文地址:https://arxiv.org/pdf/2212.10544.pdf

论文二:Mamba: Linear-Time Sequence Modeling with Selective State Spaces

  • 论文地址:https://arxiv.org/ftp/arxiv/papers/2312/2312.00752...
  • 项目地址:https://github.com/state-spaces/mamba

围绕 Mamba,已经有一些语言模型发布,包括 mamba-130m, mamba-370m, mamba-790m, mamba-1.4b, mamba-2.8b。

HuggingFace 地址:https://huggingface.co/state-spaces

也有人做出 Mamba-Chat:

Github 地址:https://github.com/havenhq/mamba-chat

论文三:苹果等机构的论文 Diffusion Models Without Attention

  • 论文地址:https://arxiv.org/pdf/2311.18257.pdf

论文四:Mamba 作者 Albert Gu 的博士论文 MODELING SEQUENCES WITH STRUCTURED STATE SPACES

论文地址:https://stacks.stanford.edu/file/druid:mb976vf9362

论文五:Long Range Language Modeling via Gated State Spaces 认为 Transformer 和 SSM 完全可以互补。

论文地址:https://arxiv.org/abs/2206.13947

论文六:DeepMind 的论文 Block-State Transformer

论文地址:https://arxiv.org/pdf/2306.09539.pdf


http://www.kler.cn/a/380450.html

相关文章:

  • linux RCU调优
  • JZ31 栈的压入、弹出序列
  • 机器人加装电主轴【铣削、钻孔、打磨、去毛刺】更高效
  • 【MySQL基础篇】多表查询(隐式/显式内连接、左/右外连接、自连接查询、联合查询、标量/列/行/表子查询)
  • YOLO模型格式转换:pt -> onnx -> rknn
  • QT用Enigmavb 打包成单独exe
  • 在 Oracle 数据库中,SERVICE_NAME 和 SERVICE_NAMES 有什么区别?
  • 云原生后端:现代应用程序开发的关键技术
  • 【vue项目中添加告警音频提示音】
  • 如何编写STM32的RTC程序
  • 自动化立体仓库:详细设计方案
  • 深度学习之数据增强
  • DDOS的攻击方式有哪些?
  • 音视频入门基础:H.264专题(22)——通过FFprobe显示H.264裸流每个packet的信息
  • 内网远程连接解决方案【Frp】
  • C# 程序暂停的两种方式
  • 11.4OpenCV_图像预处理02
  • LoRA(Low-Rank Adaptation)的工作机制 - 使用 LoRA 库来微调深度学习模型的基本步骤
  • 学习笔记:黑马程序员JavaWeb开发教程(2024.11.4)
  • 虚拟机 Ubuntu 扩容
  • Qt第三课 ----------输入类的控件属性
  • 深度学习之Dropout
  • K8S flannel网络模式对比
  • 恒创科技:如何知道一台服务器能承载多少用户?
  • 【Elasticsearch系列】更改 Elasticsearch 用户密码的详细指南
  • 【RAG多模态】多模态RAG-ColPali:使用视觉语言模型实现高效的文档检索