Skip to content

Commit 1f8daee

Browse files
authored
tests: reduce processor test memory usage by using tiny Hub checkpoints (#47213)
* tests/kimi_k25: add tiny_model_id to speed up processor tests Use hf-internal-testing/tiny-processor-kimi_k25 (75KB tokenizer vs 19MB full) so most tests load the tiny processor instead of the full one. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * tests/llama4: add tiny_model_id, remove _setup_tokenizer hook Use hf-internal-testing/tiny-processor-llama4 (500 vocab vs 200k) so tests load the tiny processor instead of the full one. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * tests/deepseek_ocr2,got_ocr2: add tiny_model_id, remove _setup_tokenizer - deepseek_ocr2: tiny-processor-deepseek_ocr2 (500 vocab vs 102k) - got_ocr2: tiny-processor-got_ocr2 (500 vocab vs 32k); add _setup_image_processor() to preserve default 384x384 size; update test_ocr_queries expected input_ids shapes for tiny tokenizer Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix * Add analyze_mem.py and memory_tracker_plugin from debug_mem Brings memory profiling tooling into fix_slow_processor branch: - analyze_mem.py: runs processor tests and aggregates memory usage - memory_tracker_plugin.py: pytest plugin for per-test memory tracking - conftest.py: integrate memory tracker plugin Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Fix processor test failures for florence2, granite4_vision, pp_chart2table - florence2: skip 6 tests that check max_length/padding; processor always produces ~585 tokens (256 image tokens + task prompt) and does not forward tokenizer padding kwargs - granite4_vision: add _setup_image_processor with LlavaNextImageProcessor (returns required image_sizes key); add num_additional_image_tokens=1 to prepare_processor_dict to match tiny repo config - pp_chart2table: skip test_model_input_names (image processor declares original_image_size in model_input_names but does not return it); fix test_ocr_queries token count assertion 325→324 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Fix granite4_vision test_image_token_filling expected token count num_additional_image_tokens=1 adds 1 to base features: 405 - 1 (CLS) = 404. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Fix Florence2 processor tests: use image_seq_length=2 instead of skipping Add _setup_image_processor hook that loads image processor from tiny repo but sets image_seq_length=2, keeping output sequences short enough for the standard max_length/padding tests to pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * tests/pp_chart2table: fix test_model_input_names instead of skipping Add _setup_image_processor returning PPChart2TableImageProcessor() (default, model_input_names=['pixel_values']) so the Hub config's extra 'original_image_size' entry doesn't cause the assertion to fail. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * tests/kimi_k25: use tiny_video_320x240.mp4 instead of 4K source video The previous video (raushan-testing-hf/tiny_video.mp4) was 3840x2160 (4K), causing ~150 MB of memory just to decode frames before resizing to 28x28. Switch to hf-internal-testing/test-videos/tiny_video_320x240.mp4 (320x240, same 11 frames) which is 144x cheaper to decode. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * tests: reduce memory in deepseek_ocr2 and audioflamingo3 processor tests - deepseek_ocr2: use (769,577) image instead of (3264,2448) — same 2×3 tiling grid (ar≈0.75 matches 2×3 canvas best), same 1121 token count, 18× smaller tensor - audioflamingo3: use tiny processor + small public audio fixture instead of full nvidia/audio-flamingo-3-hf model + nvidia/AudioSkills wav in test_apply_transcription_request_single Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * tests: eliminate full-model downloads in audioflamingo3 processor tests Replace self.checkpoint (nvidia/audio-flamingo-3-hf) with tiny_model_id in test_can_load_various_tokenizers, test_save_load_pretrained_default, test_tokenizer_integration, and test_chat_template. For tokenizer_integration, drop hardcoded golden tokens and just assert slow==fast parity. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * tests: fix kimi_k25 slow setup and stale video assertions - Remove model_id (RaushanTurganbay/kimi2.7-processor): no test calls get_processor(use_tiny_ckpt=False), so the full-model download in setUpClass was purely wasted time - Replace hardcoded pixel_values_videos length assertions (written for 4K video) with video_grid_thw-based checks; also verify num_frames vs fps give different token counts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * tests: reduce memory in sam3, qwen3_asr, vibevoice_asr processor tests - sam3: add _setup_image_processor reducing default size from 1008×1008 to 64×64 (mask_size 288×288 → 16×16); default sizes allocate ~100 MB of tensors - qwen3_asr: replace self.checkpoint (Qwen/Qwen3-ASR-0.6B-hf) with tiny_model_id in test_can_load_various_tokenizers, test_save_load_pretrained_default, and get_processor() in test_chat_template, test_apply_transcription_request_with_language, test_decode_formats; use small public audio fixture instead of bezzam dataset - vibevoice_asr: same pattern — tiny_model_id for load tests, get_processor() for transcription/decode tests, replace bezzam wav with small public audio fixture Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * tests: eliminate full-model downloads in musicflamingo processor tests Replace self.checkpoint (nvidia/music-flamingo-2601-hf) with tiny_model_id in test_can_load_various_tokenizers, test_save_load_pretrained_default; use get_processor() in test_chat_template and test_transcription_helpers_not_supported; simplify test_tokenizer_integration to slow==fast parity check with tiny tokenizer. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(glmasr): use tiny_model_id in test_can_load_various_tokenizers and test_save_load_pretrained_default Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(vibevoice_asr): mock batch_decode in test_decode_output_formats to avoid tiny tokenizer vocab mismatch Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(vibevoice_asr): add comment explaining mock in test_decode_output_formats Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(vibevoice_asr): use real decoded string in test_decode_output_formats mock Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(vibevoice_asr): clarify mock comment in test_decode_output_formats Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(vibevoice_asr): mock tokenizer.decode to avoid tiny-tokenizer JSON parse failure test_decode_output_formats hardcoded Qwen token IDs that the tiny tokenizer decodes to garbage, breaking json.loads(). Mock tokenizer.decode with the real decoded string from the full processor (microsoft/VibeVoice-ASR-HF) prior to PR #47213, which is what this test was always validating. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * ci: trigger processor tests via test_processing_common.py touch Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * ci: restrict test fetcher to processor tests only for this PR Temporarily limit JOB_TO_TEST_FILE to tests_processors so CI only runs processor tests, avoiding unrelated modeling/tokenization jobs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * format * format * fix(ovis2): add _setup_image_processor and image_token to prepare_processor_dict - max_patches=1 ensures each image produces exactly 1 tile so len(pixel_values)==batch_size as _test_apply_chat_template expects - image_token='<IMG_ATOM>' in prepare_processor_dict prevents mismatch in test_processor_from_pretrained_vs_from_components when the tokenizer lacks an image_token attribute (defaults to '<image>' without the kwarg) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * revert(qwen3_asr): restore original test until checkpoints are updated Eric will update the Qwen3 ASR checkpoints; the tiny-processor-qwen3_asr switch will be re-applied once the new checkpoint is available. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * revert: remove analyze_mem, memory_tracker_plugin, conftest changes These memory profiling tools are not part of the processor test speed-up scope for PR #47213. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * revert: restore tests_fetcher.py and test_processing_common.py to main Both were temporary CI-triggering changes not meant for the PR. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test: add @slow test_tokenizer_full_integration for audioflamingo3 and musicflamingo Preserves the original golden-token assertions (EXPECTED_OUTPUT) against the full Hub checkpoints as a slow test, while the fast test_tokenizer_integration uses the tiny repo for a quick slow/fast parity check. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fixup: use self.checkpoint in test_tokenizer_full_integration Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * processor tests: add source comments, remove unused checkpoints, document setup hooks - Add `# Tiny processor created with make_tiny_processor.py from "<repo>"` comment on every `tiny_model_id` class attribute (14 files) - Remove unused `checkpoint = ...` class attributes from glmasr and vibevoice_asr (neither file ever references `self.checkpoint`) - Add explanatory comments on all `_setup_image_processor` / `_setup_video_processor` hooks that lacked them, explaining why each custom setup is needed Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: ydshieh <ydshieh@users.noreply.github.com>
1 parent d47a534 commit 1f8daee

21 files changed

Lines changed: 217 additions & 151 deletions

tests/models/audioflamingo3/test_processing_audioflamingo3.py

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,22 @@
2525
AutoTokenizer,
2626
WhisperFeatureExtractor,
2727
)
28-
from transformers.testing_utils import require_librosa, require_torch
28+
from transformers.testing_utils import require_librosa, require_torch, slow
2929

3030
from ...test_processing_common import MODALITY_INPUT_DATA, ProcessorTesterMixin
3131

3232

3333
class AudioFlamingo3ProcessorTest(ProcessorTesterMixin, unittest.TestCase):
3434
processor_class = AudioFlamingo3Processor
35+
# Tiny processor created with make_tiny_processor.py from "nvidia/audio-flamingo-3-hf"
36+
tiny_model_id = "hf-internal-testing/tiny-processor-audioflamingo3"
37+
checkpoint = "nvidia/audio-flamingo-3-hf"
3538

3639
@classmethod
3740
@require_torch
3841
def setUpClass(cls):
39-
cls.checkpoint = "nvidia/audio-flamingo-3-hf"
4042
cls.tmpdirname = tempfile.mkdtemp()
41-
42-
processor = AudioFlamingo3Processor.from_pretrained(cls.checkpoint)
43+
processor = AudioFlamingo3Processor.from_pretrained(cls.tiny_model_id)
4344
processor.save_pretrained(cls.tmpdirname)
4445

4546
@require_torch
@@ -60,14 +61,14 @@ def tearDownClass(cls):
6061

6162
@require_torch
6263
def test_can_load_various_tokenizers(self):
63-
processor = AudioFlamingo3Processor.from_pretrained(self.checkpoint)
64-
tokenizer = AutoTokenizer.from_pretrained(self.checkpoint)
64+
processor = AudioFlamingo3Processor.from_pretrained(self.tiny_model_id)
65+
tokenizer = AutoTokenizer.from_pretrained(self.tiny_model_id)
6566
self.assertEqual(processor.tokenizer.__class__, tokenizer.__class__)
6667

6768
@require_torch
6869
def test_save_load_pretrained_default(self):
69-
tokenizer = AutoTokenizer.from_pretrained(self.checkpoint)
70-
processor = AudioFlamingo3Processor.from_pretrained(self.checkpoint)
70+
tokenizer = AutoTokenizer.from_pretrained(self.tiny_model_id)
71+
processor = AudioFlamingo3Processor.from_pretrained(self.tiny_model_id)
7172
feature_extractor = processor.feature_extractor
7273

7374
processor = AudioFlamingo3Processor(tokenizer=tokenizer, feature_extractor=feature_extractor)
@@ -82,6 +83,21 @@ def test_save_load_pretrained_default(self):
8283

8384
@require_torch
8485
def test_tokenizer_integration(self):
86+
slow_tokenizer = AutoTokenizer.from_pretrained(self.tiny_model_id, use_fast=False)
87+
fast_tokenizer = AutoTokenizer.from_pretrained(self.tiny_model_id, from_slow=True, legacy=False)
88+
89+
prompt = (
90+
"<|im_start|>system\nAnswer the questions.<|im_end|>"
91+
"<|im_start|>user\n<sound>What is it?<|im_end|>"
92+
"<|im_start|>assistant\n"
93+
)
94+
95+
# Verify slow and fast tokenizers produce the same output (parity test)
96+
self.assertEqual(slow_tokenizer.tokenize(prompt), fast_tokenizer.tokenize(prompt))
97+
98+
@slow
99+
@require_torch
100+
def test_tokenizer_full_integration(self):
85101
slow_tokenizer = AutoTokenizer.from_pretrained(self.checkpoint, use_fast=False)
86102
fast_tokenizer = AutoTokenizer.from_pretrained(self.checkpoint, from_slow=True, legacy=False)
87103

@@ -118,7 +134,7 @@ def test_tokenizer_integration(self):
118134

119135
@require_torch
120136
def test_chat_template(self):
121-
processor = AutoProcessor.from_pretrained(self.checkpoint)
137+
processor = self.get_processor()
122138
expected_prompt = (
123139
"<|im_start|>system\nYou are a helpful assistant.<|im_end|>\n"
124140
"<|im_start|>user\n<sound>What is surprising about the relationship between the barking and the music?<|im_end|>\n"
@@ -146,9 +162,11 @@ def test_chat_template(self):
146162

147163
@require_torch
148164
def test_apply_transcription_request_single(self):
149-
processor = AutoProcessor.from_pretrained(self.checkpoint)
165+
processor = self.get_processor()
150166

151-
audio_url = "https://huggingface.co/datasets/nvidia/AudioSkills/resolve/main/assets/t_837b89f2-26aa-4ee2-bdf6-f73f0dd59b26.wav"
167+
audio_url = (
168+
"https://huggingface.co/datasets/raushan-testing-hf/audio-test/resolve/main/f2641_0_throatclearing.wav"
169+
)
152170
helper_outputs = processor.apply_transcription_request(audio=audio_url)
153171

154172
conversation = [

tests/models/colpali/test_processing_colpali.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626

2727
if is_vision_available():
28-
from transformers import ColPaliProcessor, GemmaTokenizer
28+
from transformers import ColPaliProcessor, GemmaTokenizer, SiglipImageProcessor
2929

3030
SAMPLE_VOCAB = get_tests_dir("fixtures/test_sentencepiece.model")
3131

@@ -40,8 +40,9 @@ def _setup_tokenizer(cls):
4040

4141
@classmethod
4242
def _setup_image_processor(cls):
43-
image_processor_class = cls._get_component_class_from_processor("image_processor")
44-
image_processor = image_processor_class.from_pretrained("google/siglip-so400m-patch14-384")
43+
# Use 64×64 instead of the default 384×384 from google/siglip-so400m-patch14-384 to avoid
44+
# large tensors. image_seq_length=0 matches the processor attribute so token-count tests pass.
45+
image_processor = SiglipImageProcessor(size={"height": 64, "width": 64})
4546
image_processor.image_seq_length = 0
4647
return image_processor
4748

@@ -85,7 +86,7 @@ def test_process_images(self):
8586

8687
# Assertions
8788
self.assertIn("pixel_values", batch_feature)
88-
self.assertEqual(batch_feature["pixel_values"].shape, torch.Size([1, 3, 384, 384]))
89+
self.assertEqual(batch_feature["pixel_values"].shape, torch.Size([1, 3, 64, 64]))
8990

9091
@require_torch
9192
@require_vision

tests/models/deepseek_ocr2/test_processing_deepseek_ocr2.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,19 @@
2525
@require_vision
2626
class DeepseekOcr2ProcessorTest(ProcessorTesterMixin, unittest.TestCase):
2727
processor_class = DeepseekOcr2Processor
28+
# Tiny processor created with make_tiny_processor.py from "deepseek-community/DeepSeek-OCR-2"
29+
tiny_model_id = "hf-internal-testing/tiny-processor-deepseek_ocr2"
2830

2931
@classmethod
3032
def _setup_image_processor(cls):
33+
# Small size (64×64) reduces the number of tiles produced by the tiling logic,
34+
# keeping token counts low. tile_size=512 is a safe sentinel above the image size.
3135
image_processor_class = cls._get_component_class_from_processor("image_processor")
3236
image_processor = image_processor_class()
3337
image_processor.size = {"height": 64, "width": 64}
3438
image_processor.tile_size = 512
3539
return image_processor
3640

37-
@classmethod
38-
def _setup_tokenizer(cls):
39-
tokenizer_class = cls._get_component_class_from_processor("tokenizer")
40-
tokenizer = tokenizer_class.from_pretrained("deepseek-community/DeepSeek-OCR-2")
41-
return tokenizer
42-
4341
@classmethod
4442
def _setup_test_attributes(cls, processor):
4543
cls.image_token = processor.image_token
@@ -73,8 +71,8 @@ def test_image_token_expansion_large_image(self):
7371
processor.image_processor.size = {"height": 1024, "width": 1024}
7472
processor.image_processor.tile_size = 768
7573

76-
# Large image: max(2448, 3264) > 768 → local patches
77-
image = torch.randint(0, 256, (3, 3264, 2448), dtype=torch.uint8)
74+
# Large image: max(769, 577) > 768 → local patches; same 2×3 grid as 3264×2448 (ar≈0.75)
75+
image = torch.randint(0, 256, (3, 769, 577), dtype=torch.uint8)
7876
prompt = "<image>\nFree OCR."
7977

8078
inputs = processor(images=image, text=prompt, return_tensors="pt")

tests/models/florence2/test_processing_florence2.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,19 @@
3030
@require_vision
3131
class Florence2ProcessorTest(ProcessorTesterMixin, unittest.TestCase):
3232
processor_class = Florence2Processor
33+
# Tiny processor created with make_tiny_processor.py from "microsoft/Florence-2-base"
34+
tiny_model_id = "hf-internal-testing/tiny-processor-florence2"
3335

3436
@classmethod
3537
def _setup_image_processor(cls):
38+
# Florence2Processor reads image_processor.image_seq_length at construction time
39+
# (processing_florence2.py line 99) to set num_image_tokens. Use a small value (2)
40+
# to avoid large token sequences in tests.
3641
image_processor_class = cls._get_component_class_from_processor("image_processor")
37-
image_processor = image_processor_class.from_pretrained("florence-community/Florence-2-base")
42+
image_processor = image_processor_class.from_pretrained(cls.tiny_model_id)
3843
image_processor.image_seq_length = 2
3944
return image_processor
4045

41-
@classmethod
42-
def _setup_tokenizer(cls):
43-
tokenizer_class = cls._get_component_class_from_processor("tokenizer")
44-
tokenizer = tokenizer_class.from_pretrained("florence-community/Florence-2-base")
45-
tokenizer.image_token = "<image>"
46-
tokenizer.image_token_id = tokenizer.encode(tokenizer.image_token, add_special_tokens=False)[0]
47-
return tokenizer
48-
4946
@classmethod
5047
def _setup_test_attributes(cls, processor):
5148
# override: Florence shouldn't have any image-token in input text

tests/models/glmasr/test_processing_glmasr.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@
3131

3232
class GlmAsrProcessorTest(ProcessorTesterMixin, unittest.TestCase):
3333
processor_class = GlmAsrProcessor
34+
# Tiny processor created with make_tiny_processor.py from "zai-org/GLM-ASR-Nano-2512"
35+
tiny_model_id = "hf-internal-testing/tiny-processor-glmasr"
3436

3537
@classmethod
3638
@require_torch
3739
def setUpClass(cls):
38-
cls.checkpoint = "zai-org/GLM-ASR-Nano-2512"
3940
cls.tmpdirname = tempfile.mkdtemp()
40-
41-
processor = GlmAsrProcessor.from_pretrained(cls.checkpoint)
41+
processor = GlmAsrProcessor.from_pretrained(cls.tiny_model_id)
4242
processor.save_pretrained(cls.tmpdirname)
4343

4444
@require_torch
@@ -59,14 +59,14 @@ def tearDownClass(cls):
5959

6060
@require_torch
6161
def test_can_load_various_tokenizers(self):
62-
processor = GlmAsrProcessor.from_pretrained(self.checkpoint)
63-
tokenizer = AutoTokenizer.from_pretrained(self.checkpoint)
62+
processor = GlmAsrProcessor.from_pretrained(self.tiny_model_id)
63+
tokenizer = AutoTokenizer.from_pretrained(self.tiny_model_id)
6464
self.assertEqual(processor.tokenizer.__class__, tokenizer.__class__)
6565

6666
@require_torch
6767
def test_save_load_pretrained_default(self):
68-
tokenizer = AutoTokenizer.from_pretrained(self.checkpoint)
69-
processor = GlmAsrProcessor.from_pretrained(self.checkpoint)
68+
tokenizer = AutoTokenizer.from_pretrained(self.tiny_model_id)
69+
processor = GlmAsrProcessor.from_pretrained(self.tiny_model_id)
7070
feature_extractor = processor.feature_extractor
7171

7272
processor = GlmAsrProcessor(tokenizer=tokenizer, feature_extractor=feature_extractor)

tests/models/got_ocr2/test_processing_got_ocr2.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,14 @@
2323
@require_vision
2424
class GotOcr2ProcessorTest(ProcessorTesterMixin, unittest.TestCase):
2525
processor_class = GotOcr2Processor
26+
# Tiny processor created with make_tiny_processor.py from "stepfun-ai/GOT-OCR-2.0-hf"
27+
tiny_model_id = "hf-internal-testing/tiny-processor-got_ocr2"
2628

2729
@classmethod
28-
def _setup_tokenizer(cls):
29-
tokenizer_class = cls._get_component_class_from_processor("tokenizer")
30-
tokenizer = tokenizer_class.from_pretrained("stepfun-ai/GOT-OCR-2.0-hf")
31-
return tokenizer
30+
def _setup_image_processor(cls):
31+
# Instantiate directly to avoid loading the full 384×384 image processor from Hub.
32+
image_processor_class = cls._get_component_class_from_processor("image_processor")
33+
return image_processor_class()
3234

3335
@unittest.skip("GotOcr2Processor pop the image processor output 'num_patches'")
3436
def test_image_processor_defaults(self):
@@ -38,27 +40,27 @@ def test_ocr_queries(self):
3840
processor = self.get_processor()
3941
image_input = self.prepare_image_inputs()
4042
inputs = processor(image_input, return_tensors="pt")
41-
self.assertEqual(inputs["input_ids"].shape, (1, 286))
43+
self.assertEqual(inputs["input_ids"].shape, (1, 324))
4244
self.assertEqual(inputs["pixel_values"].shape, (1, 3, 384, 384))
4345

4446
inputs = processor(image_input, return_tensors="pt", format=True)
45-
self.assertEqual(inputs["input_ids"].shape, (1, 288))
47+
self.assertEqual(inputs["input_ids"].shape, (1, 328))
4648
self.assertEqual(inputs["pixel_values"].shape, (1, 3, 384, 384))
4749

4850
inputs = processor(image_input, return_tensors="pt", color="red")
49-
self.assertEqual(inputs["input_ids"].shape, (1, 290))
51+
self.assertEqual(inputs["input_ids"].shape, (1, 329))
5052
self.assertEqual(inputs["pixel_values"].shape, (1, 3, 384, 384))
5153

5254
inputs = processor(image_input, return_tensors="pt", box=[0, 0, 100, 100])
53-
self.assertEqual(inputs["input_ids"].shape, (1, 303))
55+
self.assertEqual(inputs["input_ids"].shape, (1, 341))
5456
self.assertEqual(inputs["pixel_values"].shape, (1, 3, 384, 384))
5557

5658
inputs = processor([image_input, image_input], return_tensors="pt", multi_page=True, format=True)
57-
self.assertEqual(inputs["input_ids"].shape, (1, 547))
59+
self.assertEqual(inputs["input_ids"].shape, (1, 595))
5860
self.assertEqual(inputs["pixel_values"].shape, (2, 3, 384, 384))
5961

6062
inputs = processor(image_input, return_tensors="pt", crop_to_patches=True, max_patches=6)
61-
self.assertEqual(inputs["input_ids"].shape, (1, 1826))
63+
self.assertEqual(inputs["input_ids"].shape, (1, 1872))
6264
self.assertEqual(inputs["pixel_values"].shape, (7, 3, 384, 384))
6365

6466
def test_processor_text_has_no_visual(self):

tests/models/granite4_vision/test_processing_granite4_vision.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
import torch
1919

20-
from transformers import Granite4VisionProcessor
20+
from transformers import Granite4VisionProcessor, LlavaNextImageProcessor
2121
from transformers.testing_utils import require_vision
2222

2323
from ...test_processing_common import ProcessorTesterMixin
@@ -26,21 +26,24 @@
2626
@require_vision
2727
class Granite4VisionProcessorTest(ProcessorTesterMixin, unittest.TestCase):
2828
processor_class = Granite4VisionProcessor
29+
# Tiny processor created with make_tiny_processor.py from "ibm-granite/granite-vision-4.1-4b"
30+
tiny_model_id = "hf-internal-testing/tiny-processor-granite4_vision"
2931
# Image token expansion with downsample_rate="1/2" produces more tokens than the defaults
3032
image_text_kwargs_max_length = 300
3133
image_text_kwargs_override_max_length = 280
3234
image_unstructured_max_length = 260
3335

3436
@classmethod
35-
def _setup_tokenizer(cls):
36-
tokenizer_class = cls._get_component_class_from_processor("tokenizer")
37-
tokenizer = tokenizer_class.from_pretrained("huggyllama/llama-7b")
38-
tokenizer.add_special_tokens({"additional_special_tokens": ["<image>"]})
39-
if not tokenizer.pad_token:
40-
tokenizer.pad_token = "[PAD]"
41-
if tokenizer.pad_token_id is None:
42-
tokenizer.pad_token_id = 0
43-
return tokenizer
37+
def _setup_image_processor(cls):
38+
# Must use LlavaNextImageProcessor (not CLIPImageProcessor from the tiny repo) because
39+
# processing_granite4_vision.py calls iter(image_inputs["image_sizes"]), which requires
40+
# the image_sizes key that only LlavaNextImageProcessor produces. Small sizes keep
41+
# tensor allocations minimal.
42+
return LlavaNextImageProcessor(
43+
size={"shortest_edge": 64},
44+
crop_size={"height": 64, "width": 64},
45+
image_grid_pinpoints=[[64, 64]],
46+
)
4447

4548
@classmethod
4649
def _setup_test_attributes(cls, processor):
@@ -52,6 +55,7 @@ def prepare_processor_dict():
5255
"chat_template": "{% for message in messages %}{% if message['role'] != 'system' %}{{ message['role'].upper() + ': '}}{% endif %}{# Render all images first #}{% for content in message['content'] | selectattr('type', 'equalto', 'image') %}{{ '<image>\n' }}{% endfor %}{# Render all text next #}{% if message['role'] != 'assistant' %}{% for content in message['content'] | selectattr('type', 'equalto', 'text') %}{{ content['text'] + ' '}}{% endfor %}{% else %}{% for content in message['content'] | selectattr('type', 'equalto', 'text') %}{% generation %}{{ content['text'] + ' '}}{% endgeneration %}{% endfor %}{% endif %}{% endfor %}{% if add_generation_prompt %}{{ 'ASSISTANT:' }}{% endif %}",
5356
"patch_size": 14,
5457
"vision_feature_select_strategy": "default",
58+
"num_additional_image_tokens": 1,
5559
"downsample_rate": "1/2",
5660
} # fmt: skip
5761

@@ -97,10 +101,10 @@ def test_image_token_filling(self):
97101
# aspect: 316/503 = 0.628, 12/24 = 0.5 -> orig > current -> new_height = round(503*(12/316)) = 19
98102
# padding = (24-19)//2 = 2, current_height = 24 - 4 = 20
99103
# unpadded = 20*12 = 240, newline = 20
100-
# base = 12*12 + 0 = 144
101-
# total = 240 + 20 + 144 = 404
102-
# with "default" strategy: 404 - 1 = 403
103-
expected_image_tokens = 403
104+
# base = 12*12 + num_additional_image_tokens(1) = 145
105+
# total = 240 + 20 + 145 = 405
106+
# with "default" strategy: 405 - 1 = 404
107+
expected_image_tokens = 404
104108

105109
messages = [
106110
{

0 commit comments

Comments
 (0)