devin-lai's picture
Release v0.4.0: selective MLX model downloads
3da88e3 verified
Raw History Blame Contribute Delete
3.23 kB
"""Dense Metal attention and explicit BF16 rounding boundaries."""
from __future__ import annotations
import mlx.core as mx
def silu(x):
# PyTorch evaluates SiLU in its accumulation dtype, then rounds once.
y = x.astype(mx.float32)
return (y * mx.sigmoid(y)).astype(x.dtype)
def rms_norm(x, weight=None, eps=1e-5, *, rounded=False):
# Qwen explicitly rounds before the affine multiply. ATen nn.RMSNorm
# (DiT/VAE) multiplies its affine in FP32 before rounding. MLX's low
# precision fast RMSNorm implements Qwen's order, so upcast for ATen.
if rounded:
normalized = mx.fast.rms_norm(x, None, eps)
return normalized if weight is None else normalized * weight
return mx.fast.rms_norm(
x.astype(mx.float32), None if weight is None else weight.astype(mx.float32), eps
).astype(x.dtype)
def rotate(x, cos, sin):
n = cos.shape[-1]
a = x[..., :n]
half = n // 2
rotated = mx.concatenate((-a[..., half:], a[..., :half]), axis=-1)
out = a * cos.astype(x.dtype) + rotated * sin.astype(x.dtype)
return mx.concatenate((out, x[..., n:]), axis=-1)
def attention(q, k, v, *, causal=False, query_chunk=0):
"""Inputs [batch, sequence, heads, dim]; GQA without materializing repeated KV."""
q, k, v = (a.transpose(0, 2, 1, 3) for a in (q, k, v))
if not query_chunk or q.shape[2] <= query_chunk:
out = mx.fast.scaled_dot_product_attention(
q, k, v, scale=q.shape[-1] ** -0.5, mask="causal" if causal else None
)
else:
rows = []
for start in range(0, q.shape[2], query_chunk):
qq = q[:, :, start : start + query_chunk]
mask = None
if causal:
mask = (
mx.arange(start, start + qq.shape[2])[:, None]
>= mx.arange(k.shape[2])[None]
)
rows.append(
mx.fast.scaled_dot_product_attention(
qq, k, v, scale=q.shape[-1] ** -0.5, mask=mask
)
)
mx.eval(rows[-1])
out = mx.concatenate(rows, axis=2)
return out.transpose(0, 2, 1, 3)
def modulate(
x, norm_weight, shift, scale, indices, eps=1e-5, *, kernel="native", threads=256
):
if (
kernel == "metal-exact"
and x.ndim == 2
and x.shape[1] == 5376
and x.dtype == mx.bfloat16
):
from .tuning import norm_modulate_exact, supported_device
if supported_device() and 4096 <= x.shape[0] <= 9216:
return norm_modulate_exact(x, norm_weight, shift, scale, indices, eps)
if kernel in ("metal", "metal-qk"):
from .kernels import norm_modulate
return norm_modulate(x, norm_weight, shift, scale, indices, eps, threads)
h = rms_norm(x, norm_weight, eps)
return h * (mx.array(1, x.dtype) + scale[indices]) + shift[indices]
def gated_add(x, other, gate, indices):
return x + gate[indices] * other
def swiglu(x):
a, b = mx.split(x, 2, axis=-1)
return silu(a) * b
def layer_norm(x, weight, bias, eps=1e-5):
return mx.fast.layer_norm(
x.astype(mx.float32), weight.astype(mx.float32), bias.astype(mx.float32), eps
).astype(x.dtype)