Skip to content

Feature/qwen3 vl - #133

Closed
coder0143 wants to merge 74 commits into
jax-ml:mainfrom
coder0143:feature/qwen3-vl
Closed

Feature/qwen3 vl#133
coder0143 wants to merge 74 commits into
jax-ml:mainfrom
coder0143:feature/qwen3-vl

Conversation

@coder0143

@coder0143 coder0143 commented Jan 20, 2026

Copy link
Copy Markdown
Contributor

Resolves #93

Reference
Ported Qwen3-VL model. Some things to be discussed @chapman20j @jenriver :

  1. Add support for FP8 format set of models (if possible).
  2. Add sharding (mainly for 8B and 32B models).
  3. Looking into bigger size image / video inputs.
    (vision features are variable, don't know if we have to manually setup jit compilation (using jax.lax api), also, jit compilation is quite expensive with vision inputs).
  4. Integrating into Sglang-jax.

Checklist

  • I have read the Contribution Guidelines and used pre-commit hooks to format this commit.
  • I have added all the necessary unit tests for my change. (run_model.py for model usage, test_outputs.py and/or model_validation_colab.ipynb for quality).
  • (If using an LLM) I have carefully reviewed and removed all superfluous comments or unneeded, commented-out code. Only necessary and functional code remains.
  • I have signed the Contributor License Agreement (CLA).

Comment thread bonsai/models/qwen3_vl/modeling.py Outdated
Comment on lines +439 to +441
x = self.linear_fc1(x, out_sharding=P(None, None))
x = nnx.gelu(x, approximate=True)
return self.linear_fc2(x, out_sharding=P(None, None))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will always remove the sharding on the outputs of the layers. Could you update this to have appropriate shardings?

)
self.num_grid_per_side = int(config.num_position_embeddings**0.5)
self.blocks = nnx.List([Qwen3VLVisionBlock(config, rngs=rngs) for _ in range(config.depth)])
self.merger = Qwen3VLPatchMerger(config, use_postshuffle_norm=False, rngs=rngs)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you make the use_postshuffle_norm part of the config? This would allow the user to change this through the config.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could also remove it as an input to the Qwen3VLPatchMerger layer because it would be accessible through the config.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have inspected this, the issue is that the merger has use_postshuffle_norm=False but the deepstack_merger_list has it true, so its better to keep it this way

EOS_TOKEN_ID = 151643


def generate(model, cache, input_ids, max_new_tokens: int = 50):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally Bonsai's convention is to define the actual model functions in the model's __call__ function, and wrap it in jitted forward (example [gemma3]), and run the forward function in run_model example.

Could you update to follow this pattern?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, let's omit the performance measuring parts to make the code more simple. gemma3 is a good example.

Comment thread bonsai/models/qwen3_vl/modeling.py Outdated
k = k.transpose(0, 2, 1, 3)
v = v.transpose(0, 2, 1, 3)

attn_weights = jnp.matmul(q, k.transpose(0, 1, 3, 2)) * self.scale

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure to specify an outsharding here.

image_grid_thw: Array,
token_type_ids: Array,
) -> Tuple[Array, Cache]:
"""Forward pass with vision inputs (not JIT - vision has data-dependent shapes)."""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think jit should still be used for this function. We can pre-process images to have the same shapes.

@jenriver jenriver left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this contribution, this is a really great addition!

One thing we could do later is to add jit to forward_vision after setting a default shape and padding, but we can leave it as a TODO for later.

@coder0143

Copy link
Copy Markdown
Contributor Author

Cool, if some small change has to be made, do inform before merging, thanks for reviewing @jenriver .

@jenriver

jenriver commented Feb 7, 2026

Copy link
Copy Markdown
Member

Hey! We just updated our contribution standards to keep the repo as lean as possible. Since this is already in great shape, could you do one quick final pass to squash your changes into a single commit and prune any extra comments or boilerplate?

We’re moving to the convention detailed here: #159. Thanks for the help!

@coder0143

Copy link
Copy Markdown
Contributor Author

On it!

@coder0143

Copy link
Copy Markdown
Contributor Author

I ran the command git rebase -i and it gave this output:

>git rebase -i
Successfully rebased and updated refs/heads/feature/qwen3-vl.

@coder0143

Copy link
Copy Markdown
Contributor Author

Hello @jenriver can you test and merge?

@chapman20j

Copy link
Copy Markdown
Collaborator

Hi @coder0143. If your main branch is up to date, you could try git reset --soft main. This will stage all of the changes. Then you can make a new commit. This will be a single commit. Then just use git push -f to push your changes.

@coder0143

Copy link
Copy Markdown
Contributor Author

Cool, will stage changes then commit and open a new PR.

@coder0143 coder0143 mentioned this pull request Feb 11, 2026
4 tasks
from jax._src.mesh import AxisType
from jax.sharding import PartitionSpec as P

jax.config.update("jax_platform_name", "cpu")

@vfdev-5 vfdev-5 Feb 13, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding this line and os.environ["XLA_FLAGS"] = "--xla_force_host_platform_device_count=8" only changes the runtime before any array allocation and this configuration remains until we exit the python interpreter. If this code is run first, then we will run other tests on cpu as well (which may be unwanted) and if another code was run first on an accelerator then this line wont have any effect:

>>> import jax
>>> print(jax.numpy.array([1]).device)
cuda:0
>>> jax.config.update("jax_platform_name", "cpu")
>>> print(jax.numpy.array([1]).device)
cuda:0

I would say a better way to run sharding tests can be like here:

@chapman20j

Copy link
Copy Markdown
Collaborator

Closing since we merged in the other qwen3vl with fewer commits.

@chapman20j chapman20j closed this Feb 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Qwen2.5-VL

6 participants