mlx

框架

ml-explore/mlx

MLX 是用于Apple芯片的机器学习数组框架。

项目简介

MLX 是由 Apple 机器学习研究团队开发的数组框架,专为 Apple 芯片设计,提供类似 NumPy 和 PyTorch 的 API。支持可组合函数变换、惰性计算、动态图构建以及 CPU 和 GPU 的统一内存。旨在高效训练和部署机器学习模型。

README 预览

# MLX\n\n[**Quickstart**](#quickstart) | [**Installation**](#installation) |\n[**Documentation**](https://ml-explore.github.io/mlx/build/html/index.html) |\n[**Examples**](#examples)\n\n[](https://circleci.com/gh/ml-explore/mlx)\n\nMLX is an array framework for machine learning on Apple silicon,\nbrought to you by Apple machine learning research.\n\nSome key features of MLX include:\n\n- **Familiar APIs**: MLX has a Python API that closely follows NumPy. MLX\n   also has fully featured C++, [C](https://github.com/ml-explore/mlx-c), and\n   [Swift](https://github.com/ml-explore/mlx-swift/) APIs, which closely mirror\n   the Python API. MLX has higher-level packages like `mlx.nn` and\n   `mlx.optimizers` with APIs that closely follow PyTorch to simplify building\n   more complex models.\n\n- **Composable function transformations**: MLX supports composable function\n  transformations for automatic differentiation, automatic vectorization,\n  and computation graph optimization.\n\n- **Lazy computation**: Computations in MLX are lazy. Arrays are only\n  materialized when needed.\n\n- **Dynamic graph construction**: Computation graphs in MLX are constructed\n  dynamically. Changing the shapes of function arguments does not trigger\n  slow compilations, and debugging is simple and intuitive.\n\n- **Multi-device**: Operations can run on any of the supported devices\n  (currently the CPU and the GPU).\n\n- **Unified memory**: A notable difference from MLX and other frameworks\n  is the *unified memory model*. Arrays in MLX live in shared memory.\n  Operations on MLX arrays can be performed on any of the supported\n  device types without transferring data.\n\nMLX is designed by machine learning researchers for machine learning\nresearchers. The framework is intended to be user-friendly, but still efficient\nto train and deploy models. The design of the framework itself is also\nconceptually simple. We intend to make it easy for researchers to extend and\nimprove MLX with the 

常见问题 (5)

故障排除
如何修复在 M5 Max 上,当行数超过 32,768 且不是 64 的倍数时,使用 sorted_indices=True 的 mx.gather_qmm 结果错误的问题?

将 MLX 升级到 0.32.3 或更高版本;该 bug 已在 PR #3922 中修复:

pip install --upgrade mlx

通过以下方式验证:

import mlx.core as mx
print(mx.__version__)

如果无法升级,请使用 sorted_indices=False,或将行数填充为 64 的倍数并丢弃填充的输出行。该问题影响 Apple M5 Max/macOS 27 上的 MLX 0.31.2;M4 Pro 不受影响。

来源 Issue #4632
故障排除
为什么 mx.fast.gated_delta_update 在 MLX 中对 bf16 激活会损失精度,以及如何修复?

mx.fast.gated_delta_update 在运行 kernel 之前,会先将衰减参数 g 和 beta 转换为 q 的 dtype(通常为 bf16)。由于 bf16 在略低于 1 的范围内步长为 1/256,像 0.9995 这样的衰减值会被舍入为恰好 1.0,导致 Gated DeltaNet 的状态在这些 token 处完全停止衰减。该问题已在 PR #4760 中修复:g 和 beta 现在以 float32 传入 kernel(与 flash-linear-attention 和 vLLM 的行为一致),相对于 float64 参考值,输出误差从约 4.8e-2 降至约 2.4e-3。请升级到包含该修复的 MLX 版本。在旧版本上,唯一的变通方法是将 q、k 和 v 也以 float32 传入,但这样会慢约 30%。

来源 Issue #4725
故障排除
为什么 MLX Metal 推理在空闲几秒钟后会变慢 4–5 倍,即使使用了 set_wired_limit?

这是由 macOS 在 GPU 进入空闲状态后不久撤销 MLX 的 wired-memory 驻留所导致的;MLX 0.32.x 只请求一次驻留,且不会续期。将 MLX 升级到包含 PR #4633 的版本即可修复该问题,该 PR 会通过心跳机制重新请求驻留。作为临时解决方案,请运行:

sudo sysctl iogpu.disable_wired_collector=1

使用以下命令验证:

sysctl iogpu.disable_wired_collector

该设置会在重启后被清除。或者,可以大约每秒执行一次极小的 MLX 操作以保持 GPU 处于活跃状态;测试表明 3 秒的间隔并不足够。此问题影响 macOS 26+ 上的 MLX 0.32.x,包括 Ollama 的 Apple Silicon MLX runner。

来源 Issue #4609
故障排除
在面向 macOS 14 时,如何修复 Apple Silicon 上 MLX CPU Float16 sigmoid 或比较结果不正确的问题?

这是由 MLX issue #4601 引起的:Float16 NEON 比较的回退实现只读取 lane 0,并将该掩码广播到所有 lane。在 mlx/backend/cpu/simd/neon_fp16_simd.h 中,诸如 return Simd<uint16_t, N>(*(uint16_t*)(&out)); 这样的代码必须修改为保留完整的 NEON 向量,通常改为 return Simd<uint16_t, N>(out);。将此修改应用到所有 Float16 比较重载以及逻辑取反重载,然后干净地重新构建(clean-rebuild)MLX 和你的目标。修复后,复现程序报告 sigmoid(1) = 0.731445,接近期望的 0.731059,而不是 0.268799。如果无法立即应用补丁,可以用 Float32 计算激活函数再转换回来,例如 sigmoid(x.astype(float32)).astype(float16),或者使用包含上游修复的 MLX 发布版本。

来源 Issue #4601
故障排除
如何修复在 MLX 中对大型张量的非最后一个轴进行归约时 mx.sum 返回全零的问题?

这是由 MLX 的列/非末轴归约内核中的 32 位 Metal 网格溢出所导致的。当内部归约步长为 2^29 时,启动大小变为 256 * ceil(2^29 / 32) = 2^32,溢出了调度维度,从而产生全零或部分为零的输出。它会影响在 MLX 0.32.0.dev20260609+cc3f3e60 上对诸如 (1, 32, 4096, 131072) 这类形状的 mx.sum(x, axis=1);末轴归约使用不同的代码路径,因此工作正常。

即时变通方法:将被归约的轴移动到最后一轴,并在该轴上归约:

y = mx.sum(mx.moveaxis(x, 1, -1), axis=-1)
mx.eval(y)

对于任意轴:

y = mx.sum(mx.moveaxis(x, axis, -1), axis=-1)

或者,显式地累加切片:

y = None
for i in range(x.shape[1]):
    block = x[:, i:i+1]
    y = block if y is None else y + block
mx.eval(y)

永久修复:升级到包含针对 issue #3784 的 "Fix Metal column reduction grid overflow" 修复的 MLX 版本,或者从包含该 PR 的提交构建 MLX。

来源 Issue #3784