自动微分:对一个标量输出函数求梯度,替代手推公式或数值差分。机器学习训练循环里的「反向传播」在这里只是一次函数调用。
f_grad = jax.grad(loss)
JAX 是 Google 主导的开源 Python 库:把大家熟悉的 NumPy 数值计算接口、自动微分[1]和 XLA 编译器捏合在一起,让同一段科学计算代码既能自动求梯度,又能编译到 GPU/TPU 上高速执行。它不提供 Keras 式的「层与模型」抽象,而是给四个可以互相组合的函数变换——这正是它在科研圈站稳脚跟的原因。
PyTorch 的世界观是「张量 + 原地修改」,JAX 的世界观则是「数学函数」。你按 NumPy 的写法定义一个从输入到损失的纯函数——不修改全局状态、不做副作用——然后 JAX 就可以对它做各种代数层面的操作:求导、编译、批量化、并行化,全部通过包装函数完成,你的业务代码一行不用改。
这套设计换来的直接好处是组合性:jit(grad(...))、vmap(jit(...)) 这样的嵌套写法是合法且常见的,每个变换只管自己那一件事。代价是习惯了命令式写法的工程师需要一点函数式思维的适应期,比如 JAX 数组是不可变的,「原地更新参数」要写成返回新值的风格。
自动微分:对一个标量输出函数求梯度,替代手推公式或数值差分。机器学习训练循环里的「反向传播」在这里只是一次函数调用。
f_grad = jax.grad(loss)
即时编译:把 Python 函数交给 XLA 融合优化后整体编译,消除解释器开销与小算子碎片的浪费,速度常有数倍提升。
fast_loss = jax.jit(loss)
自动向量化:把「处理单个样本」的函数自动变成「处理一批样本」,不用手写 batch 维度的广播逻辑。
batch_fn = jax.vmap(loss, in_axes=(None, 0, 0))
跨设备并行:把数据切分到多块 GPU/TPU 上同时计算再汇总,是早期 JAX 做大规模并行的入口(新代码也可关注更新的 shard_map 等方案)。
para_fn = jax.pmap(step, axis_name='devices')
JAX 的报错信息对老手友好、对新兵凶狠,而大多数挫败感其实来自同一件事:它假设你写的每个函数都「纯」。下面这三条是社区里出现频率最高的疑问,提前知道能省掉一个晚上的排障时间。
JAX 在学术圈的口碑不是营销出来的:Google Research 与 DeepMind 的许多工作把它当作首选实验平台,DeepMind 公开的 AlphaFold 2 实现就是基于 JAX 生态的 Haiku 构建[7];大量论文复现仓库选择 JAX,看中的正是「算法表达接近数学原文 + 编译后性能可靠」这两点。当然也要客观说:它的工业部署生态与岗位数量仍小于 PyTorch,选型时别只看论文热度。
框架本体保持克制,上层能力交给社区项目分层补齐,这是 JAX 生态的组织方式:
| 维度 | JAX | PyTorch | TensorFlow |
|---|---|---|---|
| 编程风格 | 函数式,纯函数 + 不可变数组,靠函数变换扩展能力 | 命令式动态图,所见即所得,调试直观 | 静态图血统 + Keras 高层封装,声明式色彩浓 |
| 性能路线 | jit/XLA 全图编译,适合整段计算加速[2] | eager 执行为主,配 torch.compile 等编译选项 | 图模式与 XLA 服务化体系成熟 |
| 生态重心 | 科研论文复现、大规模 TPU 实验、概率建模 | 社区与工业界事实标准,模型库最全[4] | 端侧与服务化部署链路完整[5] |
| 学习曲线 | 会 NumPy 入门快,函数式思维需适应期 | Python 工程师迁移成本最低 | Keras 上手平缓,底层机制较重 |
| 适合谁 | 追求数学表达与极致编译性能的研究者 | 绝大多数工程项目与教学场景的首选 | 存量 TF 系统、端侧部署需求为主的团队 |
下面这段代码把四个变换串在同一个最小回归任务里:先定义损失函数,再依次拿到梯度版本、编译版本和批量化版本。装好 pip install -U jax jaxlib 后即可运行(CPU 亦可)。
import jax
import jax.numpy as jnp
# 一个普通的“纯函数”:输入参数与数据,输出标量损失
def loss(w, x, y):
pred = x @ w
return ((pred - y) ** 2).mean()
grad_loss = jax.grad(loss) # 变换一:自动求梯度
fast_loss = jax.jit(loss) # 变换二:XLA 编译加速
batch_loss = jax.vmap(loss, in_axes=(None, 0, 0)) # 变换三:批量向量化
key = jax.random.PRNGKey(0)
w = jnp.ones(3)
x = jax.random.normal(key, (64, 3))
y = x @ jnp.array([1.0, 2.0, 3.0])
# jit + grad 组合:编译过的梯度下降单步更新
step = jax.jit(jax.grad(loss))
w = w - 0.1 * step(w, x, y)
print(w)
严格说它是通用数值计算框架:自动微分、编译和向量化服务于一切数学计算。搭神经网络通常要叠加 Flax、Equinox 这类上层库,而不是像 PyTorch 那样自带 nn.Module 全家桶。
API 高度兼容,绝大多数 NumPy 数组操作换成 jax.numpy 就能跑在 GPU/TPU 上;区别在于 JAX 数组不可变,且部分随机数等行为有自己的约定,迁移时需按文档核对。
不是。CPU 和 NVIDIA GPU 都是 JAX 的一等公民,笔记本上也能跑本文的示例;TPU 只是它优势放大的场景,而非门槛。
研究者看重三点:函数式写法贴近论文里的数学表达;grad 等变换让新算法的原型验证很快;jit 编译后的实验吞吐稳定。这些属于定性观察,具体效率因课题而异。
有公司在生产中使用它,尤其大规模模型服务场景;但其部署工具链与人才储备相对 PyTorch 小众,工程团队选型前应评估自身运维能力,相关支持情况以官方文档为准。
分两段:会 NumPy 的话,第一段(基本数组运算与 grad)很平缓;第二段是函数式习惯与编译器报错的排障,需要一些耐心,官方文档的错误指南值得通读一遍。