Skip to content

Add Molmo2 - #43451

Open
SangbumChoi wants to merge 171 commits into
huggingface:mainfrom
SangbumChoi:molmo2
Open

Add Molmo2#43451
SangbumChoi wants to merge 171 commits into
huggingface:mainfrom
SangbumChoi:molmo2

Conversation

@SangbumChoi

@SangbumChoi SangbumChoi commented Jan 23, 2026

Copy link
Copy Markdown
Contributor

CI

What does this PR do?

Fixes # (issue)

Before submitting

  • This PR fixes a typo or improves the docs (you can dismiss the other checks if that's the case).
  • Did you read the contributor guideline,
    Pull Request section?
  • Was this discussed/approved via a Github issue or the forum? Please add a link
    to it if that's the case.
  • Did you make sure to update the documentation with your changes? Here are the
    documentation guidelines, and
    here are tips on formatting docstrings.
  • Did you write any new necessary tests?

Who can review?

Anyone in the community is free to review the PR once the tests have passed. Feel free to tag
members/contributors who may be interested in your PR.

@merveenoyan
merveenoyan requested a review from molbap February 27, 2026 05:55
Adds AllenAI Molmo2 multimodal VLM to transformers, supporting:
- Molmo2ForConditionalGeneration (image+video+text → text)
- Molmo2TextModel / Molmo2TextForCausalLM (text-only)
- Molmo2ImageProcessor and Molmo2VideoProcessor
- Molmo2Processor

Key implementation details:
- Uses is_first_iteration (v5 API) for prepare_inputs_for_generation
- Custom Molmo2Embedding with embedding + new_embedding parameters
- Vision backbone with pooling adapter and multi-layer ViT features
- Dynamic full cache support for generation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
SangbumChoi and others added 14 commits March 27, 2026 08:56
…odel_prefix

- Replace einops.rearrange with native numpy reshape+transpose+reshape
- Add @strict decorator to all 4 config classes (Molmo2VitConfig,
  Molmo2AdapterConfig, Molmo2TextConfig, Molmo2Config) to satisfy TRF010
- Set Molmo2Model.base_model_prefix = "model" (was empty, violating TRF002)
- Fix image_mean/image_std mutable shared list (copy constants on init)
- Fix test_image_processing: use image_processing_class instead of
  image_processor_list; skip CHW torch and 4-channel unsupported tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Re-sort _toctree.yml to place Molmo2 after mllama alphabetically
- Add None guard in test_video_processor_from_dict_with_kwargs to skip
  when fast_video_processing_class is not defined

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Molmo2TextModel is an internal sub-component used by Molmo2Model and
Molmo2ForConditionalGeneration and is tested implicitly through those.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
requests is not part of the standard library and caused ImportError in
minimal environments (e.g. HuggingFace Jobs). Use urllib.request instead.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Molmo2's processor has several behaviors that are incompatible with the
default ProcessorTesterMixin assumptions:
- Chat template enforces strict user/assistant alternation (no system role)
- Processor inserts BOS token, shifting sequence length by 1
- Image processor patchifies output, so rescale_factor passthrough fails
- Video processor requires FPS metadata not provided by base tests
- Hub processor_config.json contains auto_map not preserved in save/load

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add @auto_docstring(checkpoint="allenai/Molmo2-8B") decorator to
Molmo2TextConfig and Molmo2Config with custom_args for documenting
non-standard parameters. This fixes check_config_docstrings CI check.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… date

Add parameter docstrings to Molmo2TextConfig and Molmo2Config __init__
methods so @strict-wrapped classes pass config docstring CI checks.
Update model doc date to 2026-03-28.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move top-level `import torch` and `import torchvision.transforms` behind
`is_torch_available()` / `is_torchvision_available()` guards in both
image and video processors to prevent ModuleNotFoundError when
torchvision is not installed.

Also skip test_kwargs_overrides_default_image_processor_kwargs since
Molmo2's patchifying image processor doesn't support rescale_factor
passthrough.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Convert all absolute imports (from transformers.xxx) to relative imports
(from ...xxx) in image_processing, video_processing, and processing
modules to match the convention used by all other in-library models.

Remove register_for_auto_class() calls which are only needed for custom
hub models and were causing dynamic_module_utils to incorrectly scan
local files for relative imports during save_pretrained.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…n_available

The processor's top-level imports from image_processing_molmo2 and
video_processing_molmo2 pull in PILImageResampling which requires PIL.
Guard these imports with is_vision_available() so `from transformers
import *` works when only torch is installed (no PIL/torchvision).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…L imports

Move Molmo2ImagesKwargs and Molmo2VideosKwargs definitions directly into
processing_molmo2.py instead of importing them from image/video processor
modules which require PIL. Also remove Molmo2ImageProcessor/VideoProcessor
type hints from __init__ to avoid NameError when vision is unavailable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@SangbumChoi

Copy link
Copy Markdown
Contributor Author

@molbap Hi I am still working on it since I have to make some example visualizer for this and (most of the code is generated by Claude code). However, you can start review this with brief level of code review! cc. @merveenoyan

Add integration tests for Molmo2-8B covering:
- Image generation with exact expected text verification
- Video QA (penguin identification)
- Video pointing (coordinate output)
- Multi-image comparison

All expected values derived from actual model inference on A10G.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@zucchini-nlp
zucchini-nlp self-requested a review March 30, 2026 15:23

@zucchini-nlp zucchini-nlp 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.

Hey @SangbumChoi

Great model to add to Transformers. After reviewing I see that using modular would be much better since a lot of part are copy-paste from different models. I left comments on each class about where it can be copied from. Apart from that, there are a few places where we need to clean up and align API with the rest of VLMs for consistency

If you have q, ping me on slack. I will unsubscribe myself from this PR to not get notif about each commit, so when you want another review ping me again by @

Comment thread docs/source/en/model_doc/molmo2.md Outdated
Comment thread docs/source/en/model_doc/molmo2.md Outdated
Comment thread docs/source/en/model_doc/molmo2.md Outdated
Comment thread src/transformers/models/molmo2/configuration_molmo2.py Outdated
Comment thread src/transformers/models/molmo2/configuration_molmo2.py Outdated
Comment thread tests/models/molmo2/test_processing_molmo2.py Outdated
Comment thread tests/models/molmo2/test_processing_molmo2.py Outdated
Comment thread tests/models/molmo2/test_processing_molmo2.py Outdated
Comment thread tests/models/molmo2/test_processing_molmo2.py Outdated
Comment thread tests/test_video_processing_common.py Outdated

@zucchini-nlp zucchini-nlp 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.

Hey @SangbumChoi

Great model to add to Transformers. After reviewing I see that using modular would be much better since a lot of part are copy-paste from different models. I left comments on each class about where it can be copied from. Apart from that, there are a few places where we need to clean up and align API with the rest of VLMs for consistency

If you have q, ping me on slack. I will unsubscribe myself from this PR to not get notif about each commit, so when you want another review ping me again by @

@molbap

molbap commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

run-slow: molmo2

@github-actions

Copy link
Copy Markdown
Contributor

Workflow Run ⚙️

This comment contains run-slow, running the specified jobs:

models: ["models/molmo2"]
quantizations: []

@github-actions

Copy link
Copy Markdown
Contributor

CI Results

Workflow Run ⚙️

Commit Info

Context Commit Description
RUN 506086a8 workflow commit (merge commit)
PR 45bf547b branch commit (from PR)
main 29985e67 base commit (on main)

⚠️ Model CI failed to report results

The test failure analysis could not be completed. Please check the workflow run for details.

@zucchini-nlp zucchini-nlp 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.

Adding my two cents as the model is closer to merge

Comment thread docs/source/en/model_doc/molmo2.md Outdated
add_generation_prompt=True,
return_tensors="pt",
return_dict=True,
processor_kwargs={"video_metadata": [metadata]},

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.

we dont need to load video manually tbh, video processor does it internally for us

Comment thread src/transformers/models/molmo2/configuration_molmo2.py
Comment thread src/transformers/models/molmo2/configuration_molmo2.py Outdated
Comment on lines +86 to +105
def select_tiling(height: int, width: int, patch_size: int, max_num_crops: int) -> tuple[int, int]:
"""Select the image tiling in the same height/width order as the original Molmo2 processor."""
tilings = []
for tile_height in range(1, max_num_crops + 1):
for tile_width in range(1, max_num_crops + 1):
if tile_height * tile_width <= max_num_crops:
tilings.append((tile_height, tile_width))
tilings.sort(key=lambda x: (x[0] * x[1], x[0]))

candidate_resolutions = torch.tensor(tilings, dtype=torch.int32) * patch_size
original_size = torch.tensor([height, width], dtype=torch.float32)

required_scales = candidate_resolutions.to(torch.float32) / original_size
required_scale = required_scales.amin(dim=-1, keepdim=True)

if torch.all(required_scale < 1):
return tilings[int(required_scale.argmax())]

required_scale = torch.where(required_scale < 1.0, 10e9, required_scale)
return tilings[int(required_scale.argmin())]

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.

looks same as get_optimal_tiled_canvas in cohere vision

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.

same core min-scale selection, but molmo sorts candidates by (area + height) while cohere enumerates aspect ratios sorted by area only, and returns (w, h) not (h, w). so using it changes the grid (except for near-square imags)

Comment thread src/transformers/models/molmo2/modular_molmo2.py Outdated
Comment thread tests/models/molmo2/test_modeling_molmo2.py
def test_training_gradient_checkpointing_use_reentrant_true(self):
pass

@unittest.skip(reason="VLMs have dynamic control flow in preparing inputs for generation")

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.

+1, preparing inputs for generation shouldn't be the issue since other VLMs dont skip the test

Comment thread tests/models/molmo2/test_modeling_molmo2.py
Comment thread tests/models/molmo2/test_modeling_molmo2.py Outdated
input_len = device_inputs["input_ids"].shape[1]
generated_text = self.processor.batch_decode(generated_ids[:, input_len:], skip_special_tokens=True)[0]
EXPECTED_TEXT = "Penguins appear in the video."
self.assertEqual(generated_text.strip(), EXPECTED_TEXT)

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.

quite a lot of slow tests, do we need all of them? 👁️

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.

yeah well the 3 models are quite different... maybe we can skip the 4B ones

@molbap

molbap commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Opened PRs to change chat template on hub repos: https://huggingface.co/allenai/Molmo2-O-7B/discussions/2 https://huggingface.co/allenai/Molmo2-8B/discussions/11 https://huggingface.co/allenai/Molmo2-4B/discussions/4
We can update the needed changes as we go. cc @zucchini-nlp

@guarin guarin 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.

Made a first pass :) Lots of minor things, brain is a bit fried. Will take a closer look at the logic tomorrow.

Comment on lines +38 to +39
### Image-text-to-text generation

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.

Nit: Could add hfoptions for the examples

Comment on lines +43 to +48
from transformers import Molmo2ForConditionalGeneration, Molmo2Processor
import torch

processor = Molmo2Processor.from_pretrained("allenai/Molmo2-8B")
model = Molmo2ForConditionalGeneration.from_pretrained(
"allenai/Molmo2-8B",

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.

bump

Comment on lines +71 to +72
generated_text = processor.batch_decode(
generated_ids[:, inputs["input_ids"].shape[1]:], skip_special_tokens=True

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.

Out of curiosity, why batch decode?

Comment on lines +74 to +75
print(generated_text[0])
```

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.

Nit: Would be nice to see the output text as a comment, same for the other example below

Comment on lines +80 to +81
`<points coords="...">` payload, where each coordinate group contains a timestamp followed by point ids and normalized
image coordinates.

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.

Nit: In Unlimited OCR we have a option in the decoder to parse these and return results as python dicts

Comment on lines +1657 to +1658
@can_return_tuple
def get_image_features(

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.

auto_docstring missing

pixel_values = pixel_values.reshape(-1, pixel_values.shape[-2], pixel_values.shape[-1])

# The adapter pools a concatenation of intermediate layers, so hidden states are always needed.
kwargs["output_hidden_states"] = True

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.

Shouldn't output_hidden_states be handled by decorator?

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.

one of the exceptions discussed in #46422 unfortunately

Comment on lines +1679 to +1680
@can_return_tuple
def get_video_features(

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.

auto_decorator missing

Comment on lines +1713 to +1714
@can_return_tuple
def forward(

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.

auto_decorator

Comment on lines +1809 to +1810
@can_return_tuple
def forward(

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.

auto_decorator

Co-authored-by: guarin <43336610+guarin@users.noreply.github.com>
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

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

run-slow: auto, molmo2

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

CI recap

Dashboard: View test results in Grafana
Latest run: 30943324210:2
Result: failure | Jobs: 16 | Tests: 159,843 | Failures: 1 | Duration: 15h 14m

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.

8 participants