metal-flash-attention

GitHub
596 38 较难 1 次阅读 6天前MIT图像语言模型
AI 解读 由 AI 自动生成,仅供参考

metal-flash-attention 是将高效的 FlashAttention 算法移植到 Apple Silicon 芯片(如 M1、M4 系列)的开源项目。它旨在解决苹果硬件在运行大规模注意力机制时面临的内存带宽瓶颈和寄存器压力问题,让大模型在 Mac 设备上跑得更快、更省显存。

该项目特别适合需要在苹果硬件上进行大模型推理优化、算法研究或底层开发的工程师与研究人员。与普通用户直接使用的封装软件不同,metal-flash-attention 提供了核心算法的源码实现,便于开发者深入理解并定制注意力机制。

其技术亮点在于针对 Apple 硬件特性做了深度优化:首先,它完全采用运行时即时编译(JIT),摆脱了对特定 Xcode 版本的依赖;其次,重新设计了反向传播算法,虽增加了少量计算量,但实现了行列维度的 100% 并行效率,且内存占用比官方原版更低;最后,为克服大维度下的寄存器限制,创新性地引入了沿维度 D 的分块策略和智能寄存器溢出机制。实测显示,该方案在 M1 Max 上能稳定达到每秒 4400 亿条指令的处理速度,ALU 利用率高达 83%,即便在无限序列长度下也能保持高性能表现。

使用场景

一位 iOS 开发者正在 Apple Silicon 设备上部署并优化一个长文本生成的本地大语言模型应用。

没有 metal-flash-attention 时

  • 显存爆炸导致崩溃:处理长序列(如万字文档)时,标准 Attention 机制需要分配巨大的中间缓存,极易触发 M1/M2 芯片的内存上限导致应用闪退。
  • 推理速度缓慢:由于缺乏针对 Metal 后向传播的深度优化,反向计算时带宽受限,生成每个 token 的延迟极高,用户等待时间过长。
  • 寄存器压力瓶颈:在处理高维头(Head Dimension 256+)时,数据无法完全放入寄存器,频繁的内存读写导致算力利用率低下,ALU 闲置严重。
  • 开发维护困难:旧方案依赖嵌入 Xcode 的可执行文件,难以动态调整或集成自定义的稀疏注意力模块,迭代新功能成本高昂。

使用 metal-flash-attention 后

  • 无限序列长度支持:通过优化的分块算法和更低的反向传播内存占用,即使在“无限”序列长度下也能稳定运行,彻底消除长文本处理的显存焦虑。
  • 极致算力释放:在 M1 Max 上实现了每秒 4400 亿条指令的稳定输出,ALU 利用率高达 83%,显著降低了长文本生成的延迟。
  • 智能寄存器溢出管理:针对大维度头设计了特殊的第三维分块策略,以最小的带宽代价处理寄存器溢出,确保高维计算依然高效流畅。
  • 运行时灵活编译:所有代码均在运行时即时编译(JIT),无需依赖特定 Xcode 版本,让开发者能轻松添加块稀疏性等自定义功能。

metal-flash-attention 通过重构底层并行策略与内存管理,让 Apple 设备上的长上下文大模型推理从“不可用”变为“高性能且稳定”。

运行环境要求

操作系统
  • macOS
GPU

必需 Apple Silicon GPU (M1, M2, M3, M4 系列等),不支持 NVIDIA CUDA

内存

未说明

依赖
notes该项目是 FlashAttention 的 Metal 移植版,专为 Apple Silicon 芯片设计。主要使用 Swift 语言开发,需在 macOS 上通过 Xcode 或 Swift 包管理器编译运行(建议使用 `-Ounchecked` 优化选项)。不支持 Linux 或 Windows,也不依赖 Python 或 CUDA。代码在运行时进行 JIT 编译,针对大头部维度(如 D=256)进行了寄存器溢出优化。
python不适用 (基于 Swift)
Xcode 14.2+
Swift 编译器
Metal
metal-flash-attention hero image

快速开始

FlashAttention(Metal移植版)

本仓库将 FlashAttention 的官方实现移植到了 Apple 芯片上。它是一组极简且易于维护的源文件,完整复现了 FlashAttention 算法。

文档

目前仅支持单头注意力机制,以便聚焦于不同注意力算法的核心瓶颈问题(寄存器压力、并行度)。在基础算法正确实现的基础上,添加诸如块稀疏等自定义功能应当相对简单。

所有代码都在运行时进行即时编译(JIT)。这与之前的实现形成对比——后者依赖于内嵌在 Xcode 14.2 中的可执行文件。

反向传播所需的内存占用低于 Dao-AILab/flash-attention。官方实现会为原子操作和部分求和分配临时工作空间。然而,Apple 硬件并不原生支持 FP32 原子操作(metal::atomic<float> 是通过模拟实现的)。在尝试绕过这一硬件限制的过程中,我们发现了 FlashAttention-2 反向核函数中存在的带宽和并行化瓶颈。为此,我们设计了一种计算开销更高的替代反向传播方案:使用 7 次 GEMM 替代原来的 5 次 GEMM。该方案能够在注意力矩阵的行和列两个维度上均达到 100% 的并行效率。更重要的是,它的代码更简洁易读,也更便于维护。

为了克服寄存器压力带来的瓶颈,我们采取了许多非常规的优化手段。当头维度较大时(例如 256),任何矩阵分块都无法完全放入寄存器中,甚至连累加器也无法容纳。因此,我们采用了有意识的寄存器溢出策略,但进行了更为优化的设计。我们在注意力算法中引入了第三个分块维度,并沿 D 维度进行分块。同时,我们大幅调整了注意力矩阵分块的长宽比,以最小化寄存器溢出带来的带宽开销。例如,在并行化方向上设置为 16–32,而在遍历方向上设置为 80–128。此外,我们还提供了一个大型参数配置文件,用于指定 D 维度的大小,并据此决定哪些操作数可以放入寄存器中,从而选择一个能够平衡多种竞争性瓶颈的分块尺寸。

最终结果是在 M1 Max 上实现了稳定的每秒 44000 亿次指令执行速度(ALU 利用率为 83%),并且支持无限序列长度和无限头维度。前提是混合精度计算中使用 BF16 模拟运算(Metal 的 bfloat 实现遵循 IEEE 规范的舍入规则,这在不支持硬件 BF16 的旧款芯片上会造成较大的性能开销)。

M1_Max_Image.png

M4_Image.png

原始数据:https://docs.google.com/spreadsheets/d/1Xf4jrJ7e19I32J1IWIekGE9uMFTeZKoOpQ6hlUoh-xY/edit?usp=sharing

量化性能

在人工智能领域,性能通常以每秒十亿次浮点运算(GFLOPS)来报告。这一指标反映了一种简化的性能模型,即所有指令都在 GEMM 中执行。随着硬件从早期的 FPU 发展到现代的向量处理器,最常见的浮点运算已被融合为一条单独的指令——融合乘加(FMA)。当对两个 100×100 的矩阵进行相乘时,会发出 100 万条 FMA 指令。那么,为什么我们要将这条 FMA 指令视为两条独立的指令呢?

这个问题与注意力机制密切相关,因为并非所有的浮点运算都是一样的。在 softmax 过程中的指数运算可以在一个时钟周期内完成,前提是大多数其他指令都被送往 FMA 单元。然而,softmax 过程中的一些乘法和加法操作无法与附近的加法或乘法操作融合。我们是否应该把这些操作也当作 FMA 来对待,并假装硬件只是以两倍的速度执行 FMA 呢?目前尚不清楚 GEMM 性能模型如何解释我的着色器是否有效地利用了 ALU 硬件。

因此,我改用每秒十亿次指令(GINSTRS)来衡量着色器的性能表现,因为它更直接地对应于算法本身。例如,一次 GEMM 计算需要 N^3 条 FMA 指令。前向注意力机制执行两次矩阵乘法,即 2 * D * N^2 条 FMA 指令。而后向注意力机制(由 Dao-AILab/flash-attention 实现)则需要 5 * D * N^2 条 FMA 指令。不妨将这张表与 Flash1、Flash2 或 Flash3 论文中的屋顶模型进行对比。

操作 工作量
正方形 GEMM N^3
前向注意力 (2D + 5) * N^2
后向朴素注意力 4D * N^2
后向 FlashAttention (5D + 5) * N^2
前向 + 后向合并 (7D + 10) * N^2

由于 FP32 原子操作的复杂性,MFA 在后向传播中采用了不同的方法,这导致更高的计算开销。它将后向传播拆分为两个独立的内核:dQdK/dV。下拉菜单中展示了伪代码,可以将其与 Flash1、Flash2 或 Flash3 论文中的一种算法进行比较。

操作 工作量
前向 (2D + 5) * N^2
后向 dQ (3D + 5) * N^2
后向 dK/dV (4D + 5) * N^2
前向 + 后向合并 (9D + 15) * N^2
算法伪代码
// 前向
//   for c in 0..<C {
//     加载 K[c]
//     S = Q * K^T
//     (m, l, P) = softmax(m, l, S * 缩放因子)
//
//     O *= 校正系数
//     加载 V[c]
//     O += P * V
//   }
//   O /= l
//
//   L = m + logBaseE(l)
//
// 后向查询
//   D = dO * O
//
//   for c in 0..<C {
//     加载 K[c]
//     S = Q * K^T
//     P = exp(S - L)
//
//     加载 V[c]
//     dP = dO * V^T
//     dS = P * (dP - D) * 缩放因子
//
//     加载 K[c]
//     dQ += dS * K
//   }
//
// 后向键值
//   for r in 0..<R {
//     加载 Q[r]
//     加载 L[r]
//     S^T = K * Q^T
//     P^T = exp(S^T - L)
//
//     加载 dO[r]
//     dV += P^T * dO
//
//     加载 dO[r]
//     加载 D[r]
//     dP^T = V * dO^T
//     dS^T = P^T * (dP^T - D) * 缩放因子
//
//     加载 Q[r]
//     dK += dS^T * Q
//   }

性能是通过计算总的计算工作量,再除以时间(秒)来衡量的。最终结果就是“每秒十亿次指令”。接下来,我们需要一个屋顶模型。下表显示了基于 GINSTRS 的屋顶线,其数值为 GFLOPS 的一半。ALU 利用率等于实际每秒十亿次指令数除以理论上的每秒十亿次指令数。例如,M1 Max 在混合精度下通常能达到 80% 的 ALU 利用率。

不过,这种模型也有局限性。在 M3 芯片上,当头维度较小时,该模型就会失效。不同的计算单元可能会同时被利用,从而导致 apparent 利用率超过 100%。尽管如此,总体而言,该基准测试仍能较为准确地反映出系统还有多少性能潜力尚未被挖掘。

var operations: Int
switch benchmarkedKernel {
case .forward:
  operations = 2 * headDimension + 5
case .backwardQuery:
  operations = 3 * headDimension + 5
case .backwardKeyValue:
  operations = 4 * headDimension + 5
}
operations *= (sequenceDimension * sequenceDimension)
operations *= dispatchCount

// 将总工作量除以延迟时间,得到吞吐量。
let instrs = Double(operations) / Double(latencySeconds)
let ginstrs = Int(instrs / 1e9)
硬件 GFLOPS GINSTRS
M1 Max 10616 5308
M4 3580 1790

Metal 版本与官方 FlashAttention 仓库相比,性能如何呢?假设我采用了“原子 dQ”算法并达到了 100% 的性能,随后切换到实际的 MFA 仓库,却发现模型训练速度慢了四倍。这意味着我只发挥了官方仓库屋顶线的 25%。要计算这个百分比,只需将三个内核的平均 ALU 利用率乘以 7 / 9 即可。虽然针对 Apple 硬件的统计使用了更为精细的模型,但大致思路就是这样。

为了计算 Nvidia 硬件的利用率,我使用了 FP16/BF16 ALU 的 GFLOPS 数据。我将论文中每张图给出的最高 GFLOPS 数值分别除以 A100 SXM 的 312000 和 H100 SXM 的 989000。需要注意的是,对于较大的头维度和寄存器密集型的内核(如后向传播),并未报告任何基准测试结果。我确认他们并未解决无限头维度下的寄存器压力问题。例如,累加器始终保存在寄存器中。截至撰写本文时,我尚未看到 D=256 的后向梯度能够正确执行的具体证据。

GFLOPS

A100, Flash2, FP16 D = 64 D = 128 D = 256
前向 192000 223000 0
后向 170000 196000 0
前向 + 后向 176000 203000 0
H100, Flash3, FP16 D = 64 D = 128 D = 256
前向 497000 648000 756000
后向 474000 561000 0
前向 + 后向 480000 585000 0
H100, Flash3, FP8 D = 64 D = 128 D = 256
前向 613000 1008000 1171000
后向 0 0 0
前向 + 后向 0 0 0

计算利用率

A100, Flash2, FP16 D = 64 D = 128 D = 256
前向传播 62% 71% 0%
前向传播 + 反向传播 56% 65% 0%
H100, Flash3, FP16 D = 64 D = 128 D = 256
前向传播 50% 66% 76%
前向传播 + 反向传播 48% 59% 0%
M1 架构, FP16 D = 64 D = 128 D = 256
前向传播 86% 85% 86%
前向传播 + 反向传播 62% 63% 64%
M3 架构, FP16 D = 64 D = 128 D = 256
前向传播 94% 91% 82%
前向传播 + 反向传播 71% 69% 61%

并排对比

2020 年生产的硬件 D = 64 D = 128 D = 256
A100 56% 65% 0%
M1–M2 架构 62% 63% 64%
2023 年生产的硬件 D = 64 D = 128 D = 256
H100(使用 FP8 GFLOPS) 24% 30% 0%
H100(使用 FP16 GFLOPS) 48% 59% 0%
M3–M4 架构 71% 69% 61%

尽管发出的计算量更多,但苹果硬件在训练 Transformer 模型时的速度比执行相同任务的英伟达硬件更快。这一比较已根据不同 GPU 的规模差异进行了归一化处理,仅关注 GPU 的利用效率。

或许主仓库应该尝试一种避免 FP32 原子操作、并在寄存器无法容纳于 GPU 核心时主动溢出的算法。不过这种可能性不大,因为他们已经为一小部分可能的问题规模硬编码了支持。其动机似乎是支持最常见的模型,即 D 为 2 的幂且小于 128 的情况。对于其他情况,用户需要依赖替代的回退实现(例如 MFA 仓库),而这些实现可能会采用完全不同的底层算法。

使用方法

设置工作流程

在 macOS 上,下载 Swift 包并使用 -Xswiftc -Ounchecked 进行编译。此编译选项对性能敏感的 CPU 代码至关重要。不能使用 Release 模式,因为它会在每次有哪怕一处改动时,强制从头重新编译整个代码库。在 Finder 中导航到 Git 仓库并双击 Package.swift,应会弹出一个 Xcode 窗口。左侧应显示文件层级结构。如果无法展开该结构,则说明设置出现了问题。

git clone https://github.com/philipturner/metal-flash-attention
swift build -Xswiftc -Ounchecked # 是否能成功编译?
swift test -Xswiftc -Ounchecked # 测试套件是否能在约 10 秒内完成?

或者,可以使用 SwiftUI 模板创建一个新的 Xcode 项目,将默认的 "Hello, world!" 字符串替换为调用一个返回 String 的函数。该函数将执行你选择的脚本,然后调用 exit(0),使应用在渲染任何内容之前崩溃。你可以通过 Xcode 控制台输出来获取代码反馈。此工作流程同时适用于 macOS 和 iOS。

通过 项目 > 你的项目名称 > 构建设置 > Swift 编译器 - 代码生成 > 优化级别 添加 -Xswiftc -Ounchecked 选项。表格的第二列显示你的项目名称。点击下拉菜单中的 其他,并在出现的面板中输入 -Ounchecked。接下来,将此仓库添加为 Swift 包依赖项。浏览一下 Tests/FlashAttention 下的一些测试,将其中一个测试的原始源代码复制到你的项目中,并从上一段提到的函数中调用该测试,检查控制台输出的内容。

要修改 Metal 代码生成(例如添加多头或掩码支持),可将原始 Swift 代码复制到你的 Xcode 项目中。你可以选择在单独的文件夹中使用 git clone,或直接从 GitHub 下载 ZIP 格式的原始文件。此外,还可以链接到你自己的 metal-flash-attention 分支,并自动将更改保存到云端,但这种方式设置起来较为复杂。移除上一段中的 Swift 包依赖项,然后重新运行你选择的测试。它能否成功编译并在控制台显示内容?

编辑源代码

在以下任一文件夹中找到一个多行字符串字面量:

Sources/FlashAttention/Attention/AttentionKernel
Sources/FlashAttention/GEMM/GEMMKernel

向其中任意一个添加随机文本,然后再次编译并运行项目。此时应该会出现严重错误,例如 Metal 编译器抛出异常。如果未发生这种情况,请尝试修改其他地方的代码行。若测试仍能通过,则说明 Xcode 并未识别你的更改。

接下来可以继续开发 块稀疏性 或其他功能,以验证代码是否有效、运行速度如何以及在各种问题规模下是否都能保持高效。最后,将原始源代码集成到你的应用中,或将其转换为其他编程语言。

版本历史

v1.0.12023/07/28
v1.0.02023/07/27
v0.2.0-alpha2023/07/08
v0.1.0-alpha2023/07/06

常见问题

相似工具推荐

stable-diffusion-webui

stable-diffusion-webui 是一个基于 Gradio 构建的网页版操作界面,旨在让用户能够轻松地在本地运行和使用强大的 Stable Diffusion 图像生成模型。它解决了原始模型依赖命令行、操作门槛高且功能分散的痛点,将复杂的 AI 绘图流程整合进一个直观易用的图形化平台。 无论是希望快速上手的普通创作者、需要精细控制画面细节的设计师,还是想要深入探索模型潜力的开发者与研究人员,都能从中获益。其核心亮点在于极高的功能丰富度:不仅支持文生图、图生图、局部重绘(Inpainting)和外绘(Outpainting)等基础模式,还独创了注意力机制调整、提示词矩阵、负向提示词以及“高清修复”等高级功能。此外,它内置了 GFPGAN 和 CodeFormer 等人脸修复工具,支持多种神经网络放大算法,并允许用户通过插件系统无限扩展能力。即使是显存有限的设备,stable-diffusion-webui 也提供了相应的优化选项,让高质量的 AI 艺术创作变得触手可及。

162.1k|★★★☆☆|今天
开发框架图像Agent

everything-claude-code

everything-claude-code 是一套专为 AI 编程助手(如 Claude Code、Codex、Cursor 等)打造的高性能优化系统。它不仅仅是一组配置文件,而是一个经过长期实战打磨的完整框架,旨在解决 AI 代理在实际开发中面临的效率低下、记忆丢失、安全隐患及缺乏持续学习能力等核心痛点。 通过引入技能模块化、直觉增强、记忆持久化机制以及内置的安全扫描功能,everything-claude-code 能显著提升 AI 在复杂任务中的表现,帮助开发者构建更稳定、更智能的生产级 AI 代理。其独特的“研究优先”开发理念和针对 Token 消耗的优化策略,使得模型响应更快、成本更低,同时有效防御潜在的攻击向量。 这套工具特别适合软件开发者、AI 研究人员以及希望深度定制 AI 工作流的技术团队使用。无论您是在构建大型代码库,还是需要 AI 协助进行安全审计与自动化测试,everything-claude-code 都能提供强大的底层支持。作为一个曾荣获 Anthropic 黑客大奖的开源项目,它融合了多语言支持与丰富的实战钩子(hooks),让 AI 真正成长为懂上

139k|★★☆☆☆|今天
开发框架Agent语言模型

ComfyUI

ComfyUI 是一款功能强大且高度模块化的视觉 AI 引擎,专为设计和执行复杂的 Stable Diffusion 图像生成流程而打造。它摒弃了传统的代码编写模式,采用直观的节点式流程图界面,让用户通过连接不同的功能模块即可构建个性化的生成管线。 这一设计巧妙解决了高级 AI 绘图工作流配置复杂、灵活性不足的痛点。用户无需具备编程背景,也能自由组合模型、调整参数并实时预览效果,轻松实现从基础文生图到多步骤高清修复等各类复杂任务。ComfyUI 拥有极佳的兼容性,不仅支持 Windows、macOS 和 Linux 全平台,还广泛适配 NVIDIA、AMD、Intel 及苹果 Silicon 等多种硬件架构,并率先支持 SDXL、Flux、SD3 等前沿模型。 无论是希望深入探索算法潜力的研究人员和开发者,还是追求极致创作自由度的设计师与资深 AI 绘画爱好者,ComfyUI 都能提供强大的支持。其独特的模块化架构允许社区不断扩展新功能,使其成为当前最灵活、生态最丰富的开源扩散模型工具之一,帮助用户将创意高效转化为现实。

107.7k|★★☆☆☆|2天前
开发框架图像Agent

NextChat

NextChat 是一款轻量且极速的 AI 助手,旨在为用户提供流畅、跨平台的大模型交互体验。它完美解决了用户在多设备间切换时难以保持对话连续性,以及面对众多 AI 模型不知如何统一管理的痛点。无论是日常办公、学习辅助还是创意激发,NextChat 都能让用户随时随地通过网页、iOS、Android、Windows、MacOS 或 Linux 端无缝接入智能服务。 这款工具非常适合普通用户、学生、职场人士以及需要私有化部署的企业团队使用。对于开发者而言,它也提供了便捷的自托管方案,支持一键部署到 Vercel 或 Zeabur 等平台。 NextChat 的核心亮点在于其广泛的模型兼容性,原生支持 Claude、DeepSeek、GPT-4 及 Gemini Pro 等主流大模型,让用户在一个界面即可自由切换不同 AI 能力。此外,它还率先支持 MCP(Model Context Protocol)协议,增强了上下文处理能力。针对企业用户,NextChat 提供专业版解决方案,具备品牌定制、细粒度权限控制、内部知识库整合及安全审计等功能,满足公司对数据隐私和个性化管理的高标准要求。

87.6k|★★☆☆☆|今天
开发框架语言模型

ML-For-Beginners

ML-For-Beginners 是由微软推出的一套系统化机器学习入门课程,旨在帮助零基础用户轻松掌握经典机器学习知识。这套课程将学习路径规划为 12 周,包含 26 节精炼课程和 52 道配套测验,内容涵盖从基础概念到实际应用的完整流程,有效解决了初学者面对庞大知识体系时无从下手、缺乏结构化指导的痛点。 无论是希望转型的开发者、需要补充算法背景的研究人员,还是对人工智能充满好奇的普通爱好者,都能从中受益。课程不仅提供了清晰的理论讲解,还强调动手实践,让用户在循序渐进中建立扎实的技能基础。其独特的亮点在于强大的多语言支持,通过自动化机制提供了包括简体中文在内的 50 多种语言版本,极大地降低了全球不同背景用户的学习门槛。此外,项目采用开源协作模式,社区活跃且内容持续更新,确保学习者能获取前沿且准确的技术资讯。如果你正寻找一条清晰、友好且专业的机器学习入门之路,ML-For-Beginners 将是理想的起点。

85k|★★☆☆☆|今天
图像数据工具视频

ragflow

RAGFlow 是一款领先的开源检索增强生成(RAG)引擎,旨在为大语言模型构建更精准、可靠的上下文层。它巧妙地将前沿的 RAG 技术与智能体(Agent)能力相结合,不仅支持从各类文档中高效提取知识,还能让模型基于这些知识进行逻辑推理和任务执行。 在大模型应用中,幻觉问题和知识滞后是常见痛点。RAGFlow 通过深度解析复杂文档结构(如表格、图表及混合排版),显著提升了信息检索的准确度,从而有效减少模型“胡编乱造”的现象,确保回答既有据可依又具备时效性。其内置的智能体机制更进一步,使系统不仅能回答问题,还能自主规划步骤解决复杂问题。 这款工具特别适合开发者、企业技术团队以及 AI 研究人员使用。无论是希望快速搭建私有知识库问答系统,还是致力于探索大模型在垂直领域落地的创新者,都能从中受益。RAGFlow 提供了可视化的工作流编排界面和灵活的 API 接口,既降低了非算法背景用户的上手门槛,也满足了专业开发者对系统深度定制的需求。作为基于 Apache 2.0 协议开源的项目,它正成为连接通用大模型与行业专有知识之间的重要桥梁。

77.1k|★★★☆☆|2天前
Agent图像开发框架