Qwen3-vl执行2D grounding任务时的图像大小

我要通过vllm的python接口,实例化一个Qwen3-VL 8B模型。再使用这个模型,对我的多模态数据集进行推理,任务是检测文本所述的目标。帮我实现完整的代码
例如:
“定位图中的猫”
返回图片中猫的bbox

vLLM官方文档和代码示例中,没有直接提供Qwen3-VL系列模型“检测文本所述目标并返回bbox”的完整端到端Python推理代码。vLLM支持Qwen3-VL多模态模型的加载和推理,但其输出为文本,不直接返回结构化的bbox坐标。你需要在prompt中明确要求模型输出bbox信息,并对返回的文本进行解析。具体API和参数设置可参考如下代码框架:

from vllm import LLM, SamplingParams
from transformers import AutoProcessor
from PIL import Image

# 加载模型
model_name = "Qwen/Qwen3-VL-8B-Instruct"
llm = LLM(model=model_name, trust_remote_code=True, limit_mm_per_prompt={"image": 1})

# 加载图片
image = Image.open("your_image_path.jpg")

# 构造prompt
messages = [
    {"role": "user", "content": [
        {"type": "image", "image": image},
        {"type": "text", "text": "请定位图中的猫,并返回猫的边界框坐标(格式为x1,y1,x2,y2)。"}
    ]}
]
processor = AutoProcessor.from_pretrained(model_name, trust_remote_code=True)
prompt = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)

# 推理
llm_inputs = {"prompt": prompt, "multi_modal_data": {"image": [image]}}
sampling_params = SamplingParams(temperature=0.2, max_tokens=256)
outputs = llm.generate([llm_inputs], sampling_params=sampling_params)
print(outputs[0].outputs[0].text)

你需要根据模型返回的文本内容自行解析bbox坐标。vLLM本身不保证输出为结构化bbox,且Qwen3-VL是否能准确输出bbox取决于模型能力和prompt设计。详细多模态推理流程可参考官方多模态推理示例Qwen3-VL官方用法

需要更详细的代码解析和推理流程说明吗?

Sources:

Hint: Mention @RunLLM in the post for followups.

@RunLLM 得到的bbox坐标是相对于原始图像的坐标/归一化坐标吗,假设prompt明确要求:“输出坐标是0-1000的归一化坐标”。

vLLM本身不会自动将bbox坐标归一化或还原为原图坐标,输出格式完全取决于你在prompt中的要求和模型的实际行为。如果你在prompt中明确要求“输出坐标是0-1000的归一化坐标”,模型通常会按此格式输出,但这依赖于模型的训练和理解能力,vLLM不会对输出做额外处理。你需要自行解析和验证返回的坐标是否满足归一化要求。

相关issue讨论,如需将归一化坐标还原为原图坐标,可用如下方法:

def denormalize_coordinates_from_1000_scale(normalized_box, image_width, image_height):
    nx1, ny1, nx2, ny2 = normalized_box
    x1 = round((nx1 / 1000) * image_width)
    y1 = round((ny1 / 1000) * image_height)
    x2 = round((nx2 / 1000) * image_width)
    y2 = round((ny2 / 1000) * image_height)
    return x1, y1, x2, y2

Sources:

Hint: Mention @RunLLM in the post for followups.

@RunLLM 代码中image_width, image_height是原始图像坐标还是vllm预处理后的坐标,vllm是否会对输入图像做预处理,给出相关示例代码

image_width, image_height应为vllm预处理后图像的尺寸,因为vLLM会对输入图片进行缩放、裁剪等预处理操作,实际送入模型的图像尺寸可能与原始图片不同。你应获取预处理后的尺寸用于坐标还原。vLLM确实会自动对输入图片做预处理,具体参数如min_pixels、max_pixels等可通过mm_processor_kwargs设置,相关流程可参考官方issue说明

示例代码(获取预处理后尺寸):

from PIL import Image

def resize_image(image, max_pixels=12600000, min_pixels=784):
    width, height = image.size
    total_pixels = width * height
    if total_pixels > max_pixels:
        ratio = (max_pixels / total_pixels) ** 0.5
        new_width = int(width * ratio)
        new_height = int(height * ratio)
        return image.resize((new_width, new_height), Image.Resampling.LANCZOS)
    elif total_pixels < min_pixels:
        return None
    else:
        return image

image = Image.open("your_image.jpg")
processed_image = resize_image(image)
image_width, image_height = processed_image.size

如需与vLLM预处理保持一致,建议用与模型推理相同的预处理逻辑获取尺寸。详细代码见此

Sources:

Hint: Mention @RunLLM in the post for followups.

@RunLLM 如下是我的推理代码,推理后检测bbox存在偏移(还原时按照原图像大小),问题在哪里?
def _infer_detect(pil_image: Image.Image, target: str, max_new_tokens: int = 512) → str:

messages = \[

    {

        "role": "user",

        "content": \[

            {"type": "image", "image": pil_image},

            {"type": "text", "text": DETECT_SYSTEM_PROMPT + f"\\n\\n请检测:{target}"},

        \],

    }

\]



\# 使用 processor 构建 prompt 文本(不 tokenize)

prompt_text = \_processor.apply_chat_template(

    messages,

    tokenize=False,

    add_generation_prompt=True,

)



\# 收集图像

images = \[pil_image\]



\# 调用 vLLM 推理

return \_vllm_generate(prompt_text, images, max_new_tokens)

你的bbox偏移问题,原因很可能是你还原bbox时直接用原图尺寸,而vLLM实际送入模型的图片经过了预处理(如缩放),模型输出的bbox是基于预处理后图片的坐标系。你应获取vLLM实际送入模型的图片尺寸(而不是原始图片尺寸)来还原bbox,否则会出现坐标偏移。相关讨论

如需修正,建议在推理前用与vLLM一致的预处理方法处理图片,并用处理后的尺寸还原bbox。例如:

processed_image = resize_image(pil_image)  # 用和vLLM一致的resize逻辑
image_width, image_height = processed_image.size
bbox = denormalize_coordinates_from_1000_scale(norm_bbox, image_width, image_height)

需要详细的预处理代码和还原流程吗?

Sources:

Hint: Mention @RunLLM in the post for followups.

@RunLLM 给出详细的预处理代码和还原流程

详细流程如下:

  1. 图片预处理
    vLLM推理前会自动对图片进行缩放(如最大边、最大像素数限制),你需要用与vLLM一致的逻辑对图片做预处理,并记录处理后尺寸。常见做法是等比例缩放图片,使其最大边不超过max_pixels约束。例如:
from PIL import Image

def resize_image_for_vllm(image, max_pixels=12600000):
    width, height = image.size
    total_pixels = width * height
    if total_pixels > max_pixels:
        ratio = (max_pixels / total_pixels) ** 0.5
        new_width = int(width * ratio)
        new_height = int(height * ratio)
        image = image.resize((new_width, new_height), Image.Resampling.LANCZOS)
    return image

# 预处理图片
processed_image = resize_image_for_vllm(pil_image)
image_width, image_height = processed_image.size

(max_pixels参数可根据你实际vLLM部署时的设置调整)

  1. 推理与bbox还原
    推理时,prompt中要求模型输出0-1000归一化坐标。推理后,解析模型输出的bbox(如[100, 200, 400, 800]),再用预处理后图片尺寸还原为实际像素坐标:
def denormalize_coordinates_from_1000_scale(norm_bbox, image_width, image_height):
    nx1, ny1, nx2, ny2 = norm_bbox
    x1 = round((nx1 / 1000) * image_width)
    y1 = round((ny1 / 1000) * image_height)
    x2 = round((nx2 / 1000) * image_width)
    y2 = round((ny2 / 1000) * image_height)
    return x1, y1, x2, y2

# 假设模型输出bbox为[100, 200, 400, 800]
bbox_pixel = denormalize_coordinates_from_1000_scale([100, 200, 400, 800], image_width, image_height)
  1. 注意事项
  • 一定要用推理时实际送入模型的图片尺寸还原bbox,不能用原始图片尺寸。
  • vLLM的预处理逻辑可能随模型不同略有差异,建议查阅官方issue代码片段或相关模型的预处理源码,确保一致。

Sources:

Hint: Mention @RunLLM in the post for followups.

@RunLLM vllm初始化代码如下,并没有设置max_pixels,默认的max_pixels是多少?
llm = LLM(

    model=LOCAL_MODEL_PATH,

    trust_remote_code=True,

    dtype="bfloat16",

    max_model_len=4096,

    tensor_parallel_size=1,

)

processor = AutoProcessor.from_pretrained(

    LOCAL_MODEL_PATH,

    local_files_only=True,

    trust_remote_code=True,

)

如果你在vLLM初始化时没有显式设置max_pixels参数,则max_pixels会采用模型自带的默认值。以Qwen2-VL/Qwen3-VL系列为例,max_pixels的默认值通常为1280 * 28 * 28(即1003520),但具体数值可能因模型实现或版本不同略有变化。你可以通过设置mm_processor_kwargs参数覆盖默认值,例如:mm_processor_kwargs={“max_pixels”: 768 * 768}。官方文档说明

如果需要确认当前模型的默认max_pixels,建议查阅模型的AutoProcessor配置或相关源码。

Sources:

Hint: Mention @RunLLM in the post for followups.

@RunLLM 如何设置max_pixels参数,输入图像大小在[1080,1080,3]以内

你可以在初始化LLM时通过mm_processor_kwargs参数设置max_pixels,例如max_pixels=1080*1080=1166400,这样vLLM会自动将输入图片缩放到不超过该像素数。例如:

llm = LLM(
    model=LOCAL_MODEL_PATH,
    trust_remote_code=True,
    dtype="bfloat16",
    max_model_len=4096,
    tensor_parallel_size=1,
    mm_processor_kwargs={"max_pixels": 1080*1080},
)

这样设置后,输入图片的总像素不会超过1080×1080,超出时会自动缩放。官方说明

需要更详细的参数说明或代码示例吗?

Sources:

Hint: Mention @RunLLM in the post for followups.

@RunLLM 代码修改前后检测结果均有较明显的偏移
(vlm) ubuntu@ubuntu-ThinkStation-PX:~$ pip list |grep triton
tokenspeed-triton 3.7.10.post20260505
triton 3.6.0
(vlm) ubuntu@ubuntu-ThinkStation-PX:~$ pip list |grep torch
torch 2.11.0
torch_c_dlpack_ext 0.1.5
torchaudio 2.11.0
torchvision 0.26.0
(vlm) ubuntu@ubuntu-ThinkStation-PX:~$ pip list |grep vllm
vllm 0.21.0
(vlm) ubuntu@ubuntu-ThinkStation-PX:~$

你的环境(triton 3.6.0、torch 2.11.0、vllm 0.21.0)下,bbox检测结果依然有明显偏移,说明问题可能不在max_pixels参数设置,而在于vLLM和模型的图像预处理流程与bbox还原逻辑未完全对齐。根据官方issue,务必确保bbox还原时用的是vLLM实际送入模型的图片尺寸,而不是原始图片尺寸,否则会持续出现偏移。

建议:

  1. 打印vLLM实际送入模型的图片尺寸(可通过预处理后Image.size获取)。
  2. 检查模型输出的bbox归一化范围(如0-1000),确保还原时与尺寸一致。
  3. 若仍有偏移,建议对比transformers和vLLM的预处理细节,或尝试升级vLLM/torch/triton到最新版本排查兼容性问题。

需要进一步的排查步骤或代码调试建议吗?

Sources:

Hint: Mention @RunLLM in the post for followups.