[model-gateway] add qwen3_vl model image processor (#14377)

This commit is contained in:
Simo Lin
2025-12-03 17:16:37 -08:00
committed by GitHub
parent 388151053d
commit d42c167bfd
8 changed files with 1272 additions and 346 deletions
@@ -46,6 +46,11 @@ MODELS = {
"processor_class": "Qwen2VLImageProcessor",
"description": "Dynamic resolution with smart resize",
},
"qwen3_vl": {
"model_id": "Qwen/Qwen3-VL-8B-Instruct",
"processor_class": "Qwen2VLImageProcessorFast",
"description": "Dynamic resolution with patch_size=16 and [0.5,0.5,0.5] normalization",
},
}
# Default test images
@@ -283,6 +288,72 @@ def save_golden(model_key: str, image_name: str, data: dict, output_dir: str):
print(f" Saved: {config_path}")
def generate_golden_qwen3_vl(image_path: str, output_dir: str) -> dict:
"""Generate golden output for Qwen3-VL.
Qwen3-VL uses dynamic resolution with smart resize similar to Qwen2-VL
but with different parameters:
- patch_size: 16 (vs 14 in Qwen2-VL)
- factor: 32 (vs 28 in Qwen2-VL)
- normalization: [0.5, 0.5, 0.5] mean/std (vs CLIP values in Qwen2-VL)
Default parameters:
- patch_size: 16
- merge_size: 2
- temporal_patch_size: 2
"""
from transformers import AutoProcessor
processor = AutoProcessor.from_pretrained(
"Qwen/Qwen3-VL-8B-Instruct", trust_remote_code=True
)
image = Image.open(image_path).convert("RGB")
original_size = image.size
# Process image using the image processor directly
outputs = processor.image_processor(images=image, return_tensors="pt")
# Convert to numpy for saving
pixel_values = outputs["pixel_values"].numpy()
image_grid_thw = outputs.get("image_grid_thw")
if image_grid_thw is not None:
image_grid_thw = image_grid_thw.numpy()
# Get config values
img_processor = processor.image_processor
patch_size = getattr(img_processor, "patch_size", 16)
merge_size = getattr(img_processor, "merge_size", 2)
temporal_patch_size = getattr(img_processor, "temporal_patch_size", 2)
# Calculate number of tokens
if image_grid_thw is not None:
grid_thw = image_grid_thw[0]
num_tokens = int(np.prod(grid_thw) / (merge_size**2))
else:
num_tokens = None
result = {
"pixel_values": pixel_values,
"original_size": original_size,
"processor_config": img_processor.to_dict(),
}
if image_grid_thw is not None:
result["image_grid_thw"] = image_grid_thw
if num_tokens is not None:
result["num_tokens"] = num_tokens
# Add debug info
result["config_info"] = {
"patch_size": patch_size,
"merge_size": merge_size,
"temporal_patch_size": temporal_patch_size,
}
return result
def generate_for_model(model_key: str, image_paths: list, output_dir: str):
"""Generate golden outputs for a specific model."""
print(f"\nGenerating golden outputs for {model_key}...")
@@ -292,6 +363,7 @@ def generate_for_model(model_key: str, image_paths: list, output_dir: str):
"llava_pad": generate_golden_llava_pad,
"llava_next": generate_golden_llava_next,
"qwen2_vl": generate_golden_qwen2_vl,
"qwen3_vl": generate_golden_qwen3_vl,
}.get(model_key)
if generator_fn is None: