Skip to content

JIT compilation prevents optimization of GEMM with bias #2585

Description

@zcbenz

Consider following code, which is partial code of model training:

from functools import partial

import mlx.core as mx
import mlx.nn as nn
from mlx.utils import tree_map

model = nn.Linear(1024, 3072, bias=True)
params = model.trainable_parameters()
mx.eval(params)

state = [mx.random.state]

@partial(mx.compile, inputs=state, outputs=state)
def step(x, params):
    model.update(tree_map(lambda x: x.astype(mx.bfloat16), params))
    return model(x.astype(mx.float16))

x = mx.random.uniform(shape=(4,512,1024), dtype=mx.bfloat16)
y = step(x, params)
mx.eval(y)

Which converts the Linear module's weights and bias from f32 to bf16, broadcasts the bias to (4,512,3072), and then calls addmm. And after JIT compilation the astype and broadcast would be fused together.

The problem is that with JIT compilation we would lose some optimization opportunities: if we remove the mx.compile line, the AddMM::eval_gpu would receive the bias input with data size of 3072, from which we know it is a bias vector to be added to the last dim of output, and can use a faster kernel (#2569). However with JIT compilation the bias input's data size becomes 6291456 (4 *512 *3072) because of op fusion, and we can no longer take the same optimization.

I can think of 2 solutions:

  1. Add bias epilogue as part of Matmul primitive and make addmm redirect to it. The downside is it would be relatively large change and we would also need to apply the same optimization to Metal kernels.
  2. Move the broardcasting and reshaping of bias input from addmm op to AddMM::eval_gpu, the change would be minimal and could also be a bit ugly.

And with both solutions I think the vjp/jvp would be a bit tricky to get right.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions