EnzymeAD / EnzymeAD/Enzyme-JAX

Miscompiles for VJP when using jax.lax.associative_scan

Open
#1,664 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
MLIR
Stars
131
Forks
53
Avg merge
1d 10h
Merged PRs (30d)
193

Description

I was playing around with `enzyme_jax_ir` and found some compile errors which come up when using `jax.lax.associative_scan` where either the whole scan or the scan body is annotated with `enzyme_jax_ir`:

```python
import jax
import jax.numpy as jnp
from enzyme_ad.jax import enzyme_jax_ir

def linear_rnn_cell_companion_op(x, y):
a1, b1 = x
a2, b2 = y
return a1 * a2, a2 * b1 + b2

def linear_rnn(a, x):
_, out = jax.lax.associative_scan(linear_rnn_cell_companion_op, (a, x), axis=-1)
return out

@enzyme_jax_ir()
def fused_linear_rnn_cell_companion_op(x, y):
a1, b1 = x
a2, b2 = y
return a1 * a2, a2 * b1 + b2

@enzyme_jax_ir()
def fused_linear_rnn(a, x):
_, out = jax.lax.associative_scan(linear_rnn_cell_companion_op, (a, x), axis=-1)
return out

def linear_rnn_fused_op(a, x):
_, out = jax.lax.associative_scan(
fused_linear_rnn_cell_companion_op, (a, x), axis=-1
)
return out

def make_vjp_fn(fn):
@jax.jit
def _vjp_fn(g, *args):
_, vjp = jax.vjp(fn, *args)
return vjp(g)

return _vjp_fn

key = jax.random.PRNGKey(0)
B, C = 8, 4

T = 512
a = jax.random.uniform(key, (B, C, T), minval=0, maxval=1.0)
x = jax.random.normal(key, (B, C, T))
g = jnp.ones_like(x)

# works
y = linear_rnn(a, x)
g = jnp.ones_like(y)
vjp_fn = make_vjp_fn(linear_rnn)
print(vjp_fn.lower(g, a, x).as_text())

# works
y = fused_linear_rnn_cell_companion_op((a, x), (a, x))[0]
g = jnp.ones_like(y)
vjp_fn = make_vjp_fn(lambda x, y: fused_linear_rnn_cell_companion_op(x, y)[0])
print(vjp_fn.lower(g, (a, x), (a, x)).as_text())

# works
y = fused_linear_rnn_cell_companion_op((a, x), (a, x))[1]
g = jnp.ones_like(y)
vjp_fn = make_vjp_fn(lambda x, y: fused_linear_rnn_cell_companion_op(x, y)[1])
print(vjp_fn.lower(g, (a, x), (a, x)).as_text())

# TODO: breaks - 'arith.addf' op requires the same type for all operands and results
y = fused_linear_rnn(a, x)
g = jnp.ones_like(y)
vjp_fn = make_vjp_fn(fused_linear_rnn)
print(vjp_fn.lower(g, a, x).as_text())

# TODO: breaks - Dialect `tensor' not found for custom op 'tensor.empty'
y = linear_rnn_fused_op(a, x)
g = jnp.ones_like(y)
vjp_fn = make_vjp_fn(linear_rnn_fused_op)
print(vjp_fn.lower(g, a, x).as_text())

```

```
loc("x"): error: 'arith.addf' op requires the same type for all operands and results
Traceback (most recent call last):
File "/home/falkaer/projects/latent-features/jax_poc.py", line 80, in
print(vjp_fn.lower(g, a, x).as_text())
File "/home/falkaer/projects/latent-features/jax_poc.py", line 40, in _vjp_fn
_, vjp = jax.vjp(fn, *args)
jax._src.source_info_util.JaxStackTraceBeforeTransformation: ValueError: Failed to parse pipeline
Pipeline failed:
'arith.addf' op requires the same type for all operands and results
```

```
Traceback (most recent call last):
File "/home/falkaer/projects/latent-features/jax_poc.py", line 84, in
y = linear_rnn_fused_op(a, x)
File "/home/falkaer/projects/latent-features/jax_poc.py", line 31, in linear_rnn_fused_op
_, out = jax.lax.associative_scan(
File "/home/falkaer/projects/latent-features/.devenv/state/venv/lib/python3.11/site-packages/enzyme_ad/jax/primitives.py", line 1818, in wrapped
out_flat = ffi_call(
File "/home/falkaer/projects/latent-features/.devenv/state/venv/lib/python3.11/site-packages/enzyme_ad/jax/primitives.py", line 1296, in ffi_call
return _enzyme_primal_p.bind(
jax._src.source_info_util.JaxStackTraceBeforeTransformation: jaxlib.mlir._mlir_libs._site_initialize..MLIRError: Unable to parse module assembly:
error: "-":7:10: Dialect `tensor' not found for custom op 'tensor.empty'
note: "-":7:10: Registered dialects: arith, builtin, cf, chlo, func, gpu, llvm, math, memref, mhlo, nvgpu, nvvm, scf, sdy, stablehlo, vector ; for more info on dialect registration see https://mlir.llvm.org/getting_started/Faq/#registered-loaded-dependent-whats-up-with-dialects-management
```

Contributor guide

No contributing guide indexed for this repository

Research direction

Run the provided reproducer in jax_poc.py, focusing on the two failing VJP cases using jax.lax.associative_scan and enzyme_jax_ir. Inspect enzyme_ad/jax/primitives.py around ffi_call and _enzyme_primal_p.bind, then verify that both examples lower without the arith.addf type error or missing tensor dialect error.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
compilers, machine-learning
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.