Skip to content

LocateAnything 3B - #46300

Open
SangbumChoi wants to merge 47 commits into
huggingface:mainfrom
SangbumChoi:locateanything
Open

LocateAnything 3B#46300
SangbumChoi wants to merge 47 commits into
huggingface:mainfrom
SangbumChoi:locateanything

Conversation

@SangbumChoi

@SangbumChoi SangbumChoi commented May 30, 2026

Copy link
Copy Markdown
Contributor

CI

What does this PR do?

Adds native Transformers support for NVIDIA LocateAnything 3B, including configuration, image processor, processor, PyTorch modeling code, AutoClass registration, documentation, and focused tests.

This is currently draft/WIP because the required maintainer or issue coordination has not been linked yet, and several source files still carry restrictive NVIDIA license headers that need a clean licensing path before review.

Coordination and duplicate-work status

  • Coordination/approval issue or forum link: missing. This must be added before requesting review.
  • Duplicate PR search run: gh pr list --repo huggingface/transformers --state open --search "LocateAnything OR Locate Anything OR nvidia/LocateAnything" --limit 20. The only direct LocateAnything PR found was this PR (LocateAnything 3B #46300).
  • Issue search run: gh issue list --repo huggingface/transformers --state open --search "LocateAnything OR Locate Anything OR nvidia/LocateAnything" --limit 20. No matching open issue was found.

Tests and checks run

  • make style
  • make typing
  • PYTHONPATH=src python utils/check_repo.py
  • make check-repo
  • PYTHONPATH=src pytest tests/models/locateanything/test_modeling_locateanything.py tests/models/locateanything/test_image_processing_locateanything.py -q
  • PYTHONPATH=src python - <<'PY' from transformers import AutoProcessor processor = AutoProcessor.from_pretrained("nvidia/LocateAnything-3B", trust_remote_code=False) print(type(processor).__name__) print(type(processor.image_processor).__name__) PY

AI assistance disclosure

AI assistance was used to draft and iterate on this patch. The human submitter is responsible for reviewing every changed line and validating the change end-to-end before moving this PR out of draft.

Before submitting

  • This is not a pure code-agent PR.
  • I have read the contributor guidelines.
  • This was discussed/approved via a GitHub issue or forum thread, linked above.
  • Documentation was added/updated.
  • Tests were added/updated.

@SangbumChoi
SangbumChoi force-pushed the locateanything branch 13 times, most recently from fcba31c to f78d383 Compare May 31, 2026 13:53
@SangbumChoi
SangbumChoi marked this pull request as draft May 31, 2026 13:54
claude added 12 commits June 1, 2026 01:27
Introduce modular_locateanything.py as the single source of truth and generate
modeling_locateanything.py from it. Fold the MoonViT vision tower and the Parallel
Box Decoding generation helpers into the model file and remove the separate
modeling_qwen2.py, modeling_vit.py, generate_utils.py, mask_magi_utils.py and
mask_sdpa_utils.py modules.

The language model now uses the library Qwen2 via AutoModelForCausalLM.from_config
instead of a vendored copy, and the custom generation loop runs on the standard
decoder + DynamicCache: the MTP block-diffusion window mask is built by
build_window_attention_mask and the speculative window is rolled back with
DynamicCache.crop. Drop the training-only PEFT LoRA wrappers and use @auto_docstring.
Add LocateAnythingCausalLMOutputWithPast (CausalLMOutputWithPast + image_hidden_states)
and return the projected MoonViT features in it, matching the multimodal output-dataclass
convention used across the VLM families.
Follow the canonical VLM structure: LocateAnythingModel holds the MoonViT vision
tower, the MLP projector and the language-model backbone (AutoModel) and returns
LocateAnythingModelOutputWithPast (last_hidden_state + image_hidden_states);
LocateAnythingForConditionalGeneration wraps self.model + self.lm_head.

A _checkpoint_conversion_mapping remaps the published nvidia checkpoint layout
(vision_model.* / mlp1.* / language_model.model.* / language_model.lm_head.*) onto
the new module names, and _tied_weights_keys ties lm_head to the backbone embeddings.
The PBD generate() now runs on the backbone + lm_head. Tests updated for the new
submodule locations.
On current Transformers the checkpoint relayout is driven by conversion_mapping.py
(WeightRenaming) keyed by model_type, not a class attribute. Register the
locateanything renames (language_model.model -> model.language_model,
language_model.lm_head -> lm_head, vision_model/mlp1 -> model.*) so the published
nvidia checkpoint loads onto the new Model/ForConditionalGeneration layout.
Implement _get_num_multimodal_tokens (returns MultiModalData with num_image_tokens /
num_image_patches, replicating the image processor's resize+patchify token count) and
support return_mm_token_type_ids in __call__ (0=text, 1=image, 2=video), per the VLM
processor contribution checklist.
Replace the runtime remote-vs-local comparison (the original trust_remote_code module
does not import on current Transformers) with assertions that the ported model reproduces
the outputs captured from the original model on the same inputs, for two documented
examples in pure auto-regressive ("slow") decoding.
The published config ships _attn_implementation='magi' (the original block-diffusion
training attention). MoonViT and the Qwen2 backbone are standard PreTrainedModels that
reject 'magi', so loading the model the normal way (without an explicit attn override)
failed. Resolve 'magi' to flash_attention_2 (falling back to sdpa) for both the vision
tower and the language backbone.
MoonViT packs all patches into one sequence; without flash-attention the sdpa fallback
materializes an O(L^2) attention matrix, which OOMs on very large images. Keep the slow
integration test to a single moderate image (coco_sample).
- Register LocateAnythingModel as the base AutoModel mapping (FCG stays the
  image-text-to-text mapping), and add it to the test all_model_classes + model docs.
- Move the get_placeholder_mask autodoc entry to LocateAnythingModel (it now lives there).
- Accept **kwargs in MoonViTPreTrainedEncoder.forward (check_models_have_kwargs).
- Slow test loads via LocateAnythingForConditionalGeneration (AutoModel now returns the
  backbone) and drops the unused import.
use_backbone_lora / use_llm_lora are training-only flags retained for checkpoint config
compatibility; they are not used by the inference modeling code.
Run utils/add_dates.py for locateanything; the 'added to Transformers' date was stale
after the branch rebase. Fixes the check_repository_consistency (Model dates) CI failure.
processing_locateanything and image_processing_locateanything import torchvision (and PIL)
at module top level. Without a backend declaration they were eagerly imported by
`from transformers import *`, which fails in the torch-only (no torchvision) CI import
check. Add @requires(backends=("torchvision",)) so they are dummied when torchvision is
absent.
@SangbumChoi
SangbumChoi marked this pull request as ready for review June 1, 2026 14:57
@github-actions
github-actions Bot requested a review from ArthurZucker June 1, 2026 14:57
claude and others added 5 commits July 13, 2026 23:56
Replace the hand-rolled VL_VISION_ATTENTION_FUNCTIONS (multihead/sdpa/eager triplet) with
the standard attention-interface dispatch (ALL_ATTENTION_FUNCTIONS.get_interface +
eager_attention_forward), mirroring the Qwen2.5-VL vision encoder. Flash attention uses
cu_seqlens directly; sdpa/eager attend per image chunk (block-diagonal by construction),
which also avoids materializing an O(L^2) mask over the packed sequence. The layer now
carries its config and the interface bookkeeping (scaling, num_key_value_groups, is_causal).
The direct flash-attn varlen call was dropped when MoonViT moved to
ALL_ATTENTION_FUNCTIONS (the framework's flash interface handles it); is_flash_attn_2_available
is still used for the attn-implementation fallback.
Rewrite the test suite on the common harness: a LocateAnythingVisionText2TextModelTester
(packed 2x2-grid pixel inputs) + ModelTesterMixin/ConfigTester test class, replacing the
hand-rolled unittest.TestCase. all_generative_model_classes is empty because generate()
is the custom Parallel Box Decoding loop.

To satisfy the common get_image_features contract, MoonViT now follows the Qwen2-VL vision
pattern: attention projections move into a MoonVitAttention module (recorded via
_can_record_outputs together with per-layer hidden states), the encoder forward is wrapped
with @capture_outputs and returns BaseModelOutputWithPooling (packed pre-merge
last_hidden_state + merged pooler_output), and get_image_features returns that output with
the projected features as pooler_output. The wqkv/wo relocation is covered by two
leaf-scoped WeightRenaming entries in the conversion registry. Weight init for the vision
tower's custom modules moves onto MoonViTPreTrainedEncoder._init_weights, and the stale
rope_theta back-fill is dropped from the config (v5 Qwen2 uses rope_parameters).
@SangbumChoi
SangbumChoi marked this pull request as ready for review July 16, 2026 03:46
@SangbumChoi

Copy link
Copy Markdown
Contributor Author

@molbap @merveenoyan soft ping if you have time to review

@github-actions

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.

@IMvision12

Copy link
Copy Markdown
Contributor

@SangbumChoi it will be good to have a colab gist with inference

@molbap

molbap commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

@IMvision12 Or a snippet is already good, plain copy-able snippets are great for verifiability!
@SangbumChoi see also my comment on the other PR. Not much bandwidth on either right now

SangbumChoi and others added 8 commits July 22, 2026 22:35
* upstream/main: (39 commits)
  Remove deprecated training args and `is_fast` property (huggingface#46917)
  Consistent output shape from `get_image_features` (huggingface#46405)
  Fix multi-device mxfp4 dequantization race in `_convert_moe_packed_tensors` (huggingface#47423)
  fix failed test cases for qwen3_omni_moe model (huggingface#47449)
  Fix Hunyuan-VL PIL image resize parity with reference preprocessing (huggingface#47233)
  Move `value` padding into the attention interfaces that need it (huggingface#47451)
  Simplify function dispatch for linear attention (huggingface#47450)
  [cache] Allow sliding window layers to be roll-backed for speculative decoding (huggingface#47447)
  Fix double-shifted training loss in GitForCausalLM (huggingface#47395)
  Fix CohereASR training-loss double-shift (same as Moonshine fix huggingface#46784) (huggingface#46895)
  Warn when `group_by_length` is silently ignored for iterable datasets (huggingface#47379)
  Update bug report list (huggingface#46607)
  Fix shape mismatch in KyutaiSpeechToText `generate()` last window (huggingface#46952)
  Optimize flash attention max seqlen computation in vision attention (huggingface#47170)
  fix: remove unreachable return in special token builder (huggingface#47420)
  Add Harry to slow CI (huggingface#47454)
  BLT: vectorize patch length processing (huggingface#47385)
  Fix `TrackioCallback` fails to log evaluation metrics after training ends (huggingface#46935)
  [Kimi] add integration tests (huggingface#47383)
  Fix typo in `MusicgenForCausalLM.generate()` (huggingface#46974)
  ...
* upstream/main:
  [Qwen3ASR] Add hotword parsing, and fix language parsing and training. (huggingface#47111)
@SangbumChoi

Copy link
Copy Markdown
Contributor Author

Thanks, here is a plain Colab-copyable native inference snippet. It is pinned to the current PR head and model revision, and does not use trust_remote_code.

%pip install -q "git+https://github.com/SangbumChoi/transformers.git@0aff35412bdea44d9c140a6b2d4728f3857d1fb6"

import requests
import torch
from PIL import Image
from transformers import AutoProcessor, LocateAnythingForConditionalGeneration

assert torch.cuda.is_available(), "Select a GPU runtime first."

model_id = "nvidia/LocateAnything-3B"
model_revision = "c32291ca5e996f5a7a485845b4f57a233936bba0"
dtype = torch.bfloat16 if torch.cuda.is_bf16_supported() else torch.float16

processor = AutoProcessor.from_pretrained(model_id, revision=model_revision)
model = LocateAnythingForConditionalGeneration.from_pretrained(
    model_id,
    revision=model_revision,
    dtype=dtype,
    attn_implementation="sdpa",
).to("cuda").eval()

response = requests.get(
    "https://images.cocodataset.org/val2017/000000039769.jpg",
    stream=True,
    timeout=30,
)
response.raise_for_status()
image = Image.open(response.raw).convert("RGB")

question = "Locate all the instances that matches the following description: cat."
messages = [
    {
        "role": "user",
        "content": [
            {"type": "image", "image": image},
            {"type": "text", "text": question},
        ],
    }
]
prompt = processor.apply_chat_template(messages, add_generation_prompt=True, tokenize=False)
inputs = processor(images=image, text=[prompt], return_tensors="pt").to("cuda")

with torch.inference_mode():
    generated = model.generate(**inputs, do_sample=False, max_new_tokens=64)

answer = processor.decode(
    generated[0, inputs["input_ids"].shape[-1] :],
    skip_special_tokens=False,
)
print(answer)

Expected decoded output:

<ref>cat</ref><box><0><115><494><988></box><|im_end|>

@github-actions

Copy link
Copy Markdown
Contributor

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

run-slow: auto, locateanything

@github-actions

Copy link
Copy Markdown
Contributor

CI recap

Dashboard: View test results in Grafana
Latest run: 30056000146:2
Result: success | Jobs: 16 | Tests: 171,810 | Failures: 0 | Duration: 15h 44m

@SangbumChoi

Copy link
Copy Markdown
Contributor Author

I also uploaded a native Transformers training example without changing this PR branch:

%pip install -q \
  "git+https://github.com/SangbumChoi/transformers.git@38b9bd8d87cd52ffca787490de353004a71de1c1" \
  "peft>=0.17.0" requests pillow

!wget -q \
  https://raw.githubusercontent.com/SangbumChoi/transformers/codex/locateanything-training-demo/examples/pytorch/locateanything/locateanything_lora_train.py

# Processor and assistant-only label validation (no model weights):
!python locateanything_lora_train.py --dry-run

# One LoRA optimizer step and adapter save:
!python locateanything_lora_train.py --steps 1 --output-dir locateanything-warehouse-lora

The default is the harder warehouse/industrial integration case (forklift, pallets, stacked boxes, and aisle). It limits preprocessing to 8,192 vision patches, yielding 2,226 total tokens and 62 supervised assistant tokens. I validated exact prompt-prefix masking and target decoding, plus a tiny LocateAnything LoRA forward/backward pass with finite loss and gradients on all trainable adapter tensors; make style also passes.

Scope: this exercises standard autoregressive NTP SFT in native Transformers. It does not reproduce NVIDIA's custom PBD/MTP continual-SFT stack; the full pipeline remains in the official Eagle training guide. The full 3B optimizer step has not been run from this environment because Hugging Face Jobs is not authenticated here, so an A10G/L4/A100/H100 GPU run is still required for end-to-end verification.

@SangbumChoi

Copy link
Copy Markdown
Contributor Author

@IMvision12 Would you willing to review the code?

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.

4 participants