Skip to content

Add llava onevision 1.5 - #47795

Open
chengzheng345 wants to merge 4 commits into
huggingface:mainfrom
chengzheng345:add-llava-onevision-1.5
Open

Add llava onevision 1.5#47795
chengzheng345 wants to merge 4 commits into
huggingface:mainfrom
chengzheng345:add-llava-onevision-1.5

Conversation

@chengzheng345

@chengzheng345 chengzheng345 commented Aug 5, 2026

Copy link
Copy Markdown

CI

What does this PR do?

Add llava_onevision1_5 to Transformers

What this PR adds

This PR introduces native Transformers support for LLaVA-OneVision-1.5 (llava_onevision1_5), including:

  • Config + model implementation (configuration, modular, generated modeling)
  • Checkpoint conversion utility (convert_llava_onevision1_5_weights_to_hf.py)
  • Model docs and integration test suite (tests/models/llava_onevision1_5/)

Target checkpoint used during integration:

  • lmms-lab/LLaVA-OneVision-1.5-4B-Instruct

Key implementation notes

During porting, two correctness issues were fixed in the modeling path:

  1. Post-load re-initialization overwrite in from_pretrained path

    • Avoided unsafe init behavior that could overwrite loaded class_embedding / class_pos_emb.
  2. RiceRotaryEmbedding.inv_freq initialization under meta-device fast loading

    • Added explicit recomputation for this non-persistent rotary buffer.

Also aligned checkpoint behavior with:

  • tie_word_embeddings=False (matches OV1.5 checkpoint behavior with independent lm_head.weight).

Validation summary

Main acceptance criterion: single-image numerical alignment

OV1.5 training is single-image-focused, so the primary parity gate is single-image alignment.

Completed checks:

  • Single-sample logits alignment against reference
  • Cross-version reference check (4.53.1 native path)
  • Single-image multi-sample verification (9+3 samples total)
  • Batch-size > 1 / left-padding checks
  • Layer-by-layer alignment (vision + 36 text layers)

Outcome:

  • No unresolved numerical divergence on valid token positions (max abs logit diff ~1e-4)
  • Consistent top-k behavior on validated single-image samples

Video and multi-image

Video and multi-image inputs were validated as smoke tests (functional path verification):

  • Video: forward + generate pass
  • Multi-image: forward + generate pass

Note: These are treated as functional smoke checks rather than strict numerical parity gates in this PR.

8B compatibility smoke

To reduce reviewer risk regarding "same architecture, larger checkpoint", an 8B functional smoke check was also performed:

  • Source checkpoint: LLaVA-OneVision-1.5-8B-Instruct
  • Validation: Video + multi-image forward + generate pass

Local checks run for this branch

make fix-repo
make style
python work_ov_local/standalone_test_check2.py
python work_ov_local/smoke_test_video_multi.py
python src/transformers/models/llava_onevision1_5/convert_llava_onevision1_5_weights_to_hf.py --input_dir <path_to_8b_checkpoint> --output_dir <path_to_converted_8b>
python work_ov_local/smoke_test_8b.py


## Code Agent Policy

The Transformers repo is currently being overwhelmed by a large number of PRs and issue comments written by
code agents. These often are low-quality, or fix extremely minor issues that occur rarely or never in practice.
As a result, we're instituting a rule that **first-time contributors should not use code agents to submit PRs or issues**.
We'd also ask autonomous "OpenClaw"-like agents not to open any PRs or issues.

Issues/PRs from first-time contributors that violate this rule will probably just be closed without review, and we
might block you, especially if you open more than one or appear to be deliberately ignoring this. We especially do not
want new contributors to jump in on random issues to contribute an agent-written fix. This creates lots of noise
for reviewers and other users and will almost certainly get you blocked.

For more information, please read [`CONTRIBUTING.md`](https://github.com/huggingface/transformers/blob/main/CONTRIBUTING.md).

- [ ] (First-time contributors only): I confirm that this PR description and code is not written by an LLM or code agent

## Before submitting
- [ ] This PR fixes a typo or improves the docs (you can dismiss the other checks if that's the case).
- [x] Did you read the [contributor guideline](https://huggingface.co/docs/transformers/contributing) and the
      [Pull Request](https://huggingface.co/docs/transformers/pr_checks) checks?
- [x] Was this discussed/approved via a Github issue or the [forum](https://discuss.huggingface.co/)? Please add a link
      to it if that's the case.
- [x] Did you make sure to update the documentation with your changes according to the [guidelines](https://github.com/huggingface/transformers/tree/main/docs)?
- [x] Did you write any new necessary [tests](https://huggingface.co/docs/transformers/testing)?


## Who can review?

Tagging multimodal maintainers for review:
@zucchini-nlp @ArthurZucker

xytlktlkbl and others added 3 commits August 5, 2026 09:21
Adds LlavaOnevision1_5Config/Model/ForConditionalGeneration: a Qwen3
text backbone with a custom RICE vision encoder (patch embed + per-image
CLS token + 2D rotary + block-diagonal attention + patch merger),
wired together Llava-style (masked_scatter, plain 1D position ids,
no M-RoPE).

- configuration_llava_onevision1_5.py: text/vision/top-level configs
- modular_llava_onevision1_5.py -> modeling_llava_onevision1_5.py:
  vision tower built from qwen2_vl primitives, text model reuses
  Qwen3Model, multimodal wiring reuses LlavaModel/LlavaForConditionalGeneration
- convert_llava_onevision1_5_weights_to_hf.py: converts the original
  trust_remote_code checkpoint (remaps visual.* / model.* keys; the
  checkpoint's lm_head.weight is untied from embed_tokens.weight)
- Registers the model in the auto classes (AutoModel/AutoConfig family)
  and reuses Qwen2VLImageProcessor + Qwen2_5_VLProcessor for preprocessing
- Adds docs page and model tests

Verified end-to-end parity against the original implementation
(lmms-lab/LLaVA-OneVision-1.5-4B-Instruct): max abs logit diff ~1e-4
(float32 numerical noise), identical top-5 token ranking, and
AutoProcessor + AutoModelForImageTextToText.from_pretrained + generate
all work correctly on the converted checkpoint.
Matches the convention used by LlavaModel (and the most recently added
VLM, Inkling) for torch.compile/export-safe assertions, instead of a
raw if/raise ValueError.
Copilot AI lite review requested due to automatic review settings August 5, 2026 10:20
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Thank you for your contribution 🤗!

CI Security Gate — automatic approval blocked

This PR was not automatically approved for CI because the security gate failed.

Possible reasons:

  • The PR touches 50 or more files — only PRs with fewer than 50 changed files are automatically approved
  • A changed file is outside the allowed directories (src/, tests/, docs/, utils/), has a disallowed extension (only .py, .txt, .md permitted outside tests/ and docs/), or is not .md/.yml inside docs/
  • A new high-severity security issue was detected in the changed Python files (Bandit check)

See the workflow run for the exact violations.

A maintainer can review and manually approve CI if a finding is a false positive.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR adds native Hugging Face Transformers support for the LLaVA-OneVision-1.5 family (llava_onevision1_5), including configs, model implementation (modular + generated modeling), auto-mappings, docs, a conversion script, and an initial test suite.

Changes:

  • Introduces LlavaOnevision1_5*Config and the full PyTorch model stack (vision, text, composite, conditional generation) under src/transformers/models/llava_onevision1_5/.
  • Registers the new model/configs into Transformers auto-mappings (modeling + processing + image/video processing) and repo consistency checks.
  • Adds model documentation and a basic modeling test.

Reviewed changes

Copilot reviewed 16 out of 18 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
utils/check_repo.py Exempts new text/vision submodules from standalone test expectations.
utils/check_config_attributes.py Allows temporal_patch_size as an intentional extra vision-config attribute.
tests/models/llava_onevision1_5/test_modeling_llava_onevision1_5.py Adds initial modeling tests for the new model (incl. mismatch image-token error).
tests/models/llava_onevision1_5/init.py Adds the new test package marker.
src/transformers/models/llava_onevision1_5/modular_llava_onevision1_5.py Adds modular source for the new model (authoritative implementation for generation).
src/transformers/models/llava_onevision1_5/modeling_llava_onevision1_5.py Adds generated modeling file produced from the modular definition.
src/transformers/models/llava_onevision1_5/convert_llava_onevision1_5_weights_to_hf.py Adds checkpoint conversion utility from original safetensors layout to HF format.
src/transformers/models/llava_onevision1_5/configuration_llava_onevision1_5.py Adds vision/text/composite config definitions for OV1.5.
src/transformers/models/llava_onevision1_5/init.py Adds lazy import structure for the new model package.
src/transformers/models/auto/video_processing_auto.py Registers llava_onevision1_5 video processor mapping.
src/transformers/models/auto/processing_auto.py Registers llava_onevision1_5 processor mapping.
src/transformers/models/auto/modeling_auto.py Registers the new model classes for AutoModel dispatch (base + conditional generation).
src/transformers/models/auto/image_processing_auto.py Registers llava_onevision1_5 image processor mapping.
src/transformers/models/auto/auto_mappings.py Registers config mappings and links text/vision sub-config model types to the base model family.
src/transformers/models/init.py Exposes the new model package at the transformers.models level.
docs/source/en/model_doc/llava_onevision1_5.md Adds model documentation page and usage snippet.
docs/source/en/_toctree.yml Adds the new doc page to the sidebar TOC.
.gitignore Ignores a local scratch directory used during porting.
Suppressed comments (4)

src/transformers/models/llava_onevision1_5/modular_llava_onevision1_5.py:225

  • max_grid_size = grid_thw[:, 1:].max() is a scalar tensor, but LlavaOnevision1_5RiceRotaryEmbedding.forward expects an int seqlen (it passes the value to torch.arange). Convert the scalar to a Python int to avoid type errors.
        max_grid_size = grid_thw[:, 1:].max()
        rotary_pos_emb_full = self.rotary_pos_emb(max_grid_size)
        rotary_pos_emb = rotary_pos_emb_full[pos_ids].flatten(1)

src/transformers/models/llava_onevision1_5/modular_llava_onevision1_5.py:290

  • After inserting one [CLS] token per segment, the code that removes the [CLS] tokens uses hidden_states[seg_start + 1 : seg_end + 1], which does not account for the per-segment offset introduced by earlier insertions. This will include a segment’s [CLS] token in the output for all but the first segment and drop the last patch of each segment.
        for i in range(1, num_segments + 1):
            seg_start = cu[i - 1].item()
            seg_end = cu[i].item()
            new_hidden[seg_start:seg_end] = hidden_states[seg_start + 1 : seg_end + 1]
        hidden_states = new_hidden

src/transformers/models/llava_onevision1_5/modeling_llava_onevision1_5.py:367

  • (Generated file) max_grid_size is a scalar tensor but is passed into self.rotary_pos_emb(...), whose forward uses torch.arange(seqlen, ...) and expects an int. Convert with .item() to avoid type errors. Please apply the fix in the modular file and regenerate.
        max_grid_size = grid_thw[:, 1:].max()
        rotary_pos_emb_full = self.rotary_pos_emb(max_grid_size)
        rotary_pos_emb = rotary_pos_emb_full[pos_ids].flatten(1)

src/transformers/models/llava_onevision1_5/modeling_llava_onevision1_5.py:432

  • (Generated file) After inserting one [CLS] token per segment, the removal step does not account for the per-segment offset, so later segments will copy the wrong slice (includes [CLS], drops last patch). Please apply the fix in the modular file and regenerate.
        for i in range(1, num_segments + 1):
            seg_start = cu[i - 1].item()
            seg_end = cu[i].item()
            new_hidden[seg_start:seg_end] = hidden_states[seg_start + 1 : seg_end + 1]
        hidden_states = new_hidden

Comment on lines +200 to +222
pos_ids = []
for t, h, w in grid_thw:
hpos_ids = torch.arange(h).unsqueeze(1).expand(-1, w)
hpos_ids = hpos_ids.reshape(
h // self.spatial_merge_size,
self.spatial_merge_size,
w // self.spatial_merge_size,
self.spatial_merge_size,
)
hpos_ids = hpos_ids.permute(0, 2, 1, 3)
hpos_ids = hpos_ids.flatten()

wpos_ids = torch.arange(w).unsqueeze(0).expand(h, -1)
wpos_ids = wpos_ids.reshape(
h // self.spatial_merge_size,
self.spatial_merge_size,
w // self.spatial_merge_size,
self.spatial_merge_size,
)
wpos_ids = wpos_ids.permute(0, 2, 1, 3)
wpos_ids = wpos_ids.flatten()
pos_ids.append(torch.stack([hpos_ids, wpos_ids], dim=-1).repeat(t, 1))
pos_ids = torch.cat(pos_ids, dim=0)
Comment on lines +342 to +364
pos_ids = []
for t, h, w in grid_thw:
hpos_ids = torch.arange(h).unsqueeze(1).expand(-1, w)
hpos_ids = hpos_ids.reshape(
h // self.spatial_merge_size,
self.spatial_merge_size,
w // self.spatial_merge_size,
self.spatial_merge_size,
)
hpos_ids = hpos_ids.permute(0, 2, 1, 3)
hpos_ids = hpos_ids.flatten()

wpos_ids = torch.arange(w).unsqueeze(0).expand(h, -1)
wpos_ids = wpos_ids.reshape(
h // self.spatial_merge_size,
self.spatial_merge_size,
w // self.spatial_merge_size,
self.spatial_merge_size,
)
wpos_ids = wpos_ids.permute(0, 2, 1, 3)
wpos_ids = wpos_ids.flatten()
pos_ids.append(torch.stack([hpos_ids, wpos_ids], dim=-1).repeat(t, 1))
pos_ids = torch.cat(pos_ids, dim=0)
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

[For maintainers] Suggested jobs to run (before merge)

run-slow: auto, llava_onevision1_5

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

CI recap

Dashboard: View test results in Grafana
Latest run: 31001141086:2
Result: failure | Jobs: 16 | Tests: 178,086 | Failures: 40 | Duration: 16h 29m

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.

3 participants