main
py 161 lines 5.27 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 from typing import cast
4
5 import torch
6 from datasets import load_dataset
7 from transformers import AutoModelForImageTextToText, AutoProcessor
8
9 import tests.ci_envs as ci_envs
10 from tests.models.utils import (
11 GenerateModelInfo,
12 TokensTextLogprobsPromptLogprobs,
13 get_vllm_extra_kwargs,
14 )
15 from vllm.logprobs import Logprob
16
17 PPL_TOL = 0.01
18
19
20 @torch.inference_mode
21 def vqa_ppl_test(
22 hf_runner,
23 vllm_runner,
24 model_info: GenerateModelInfo,
25 mm_processor_kwargs=None,
26 vllm_extra_kwargs=None,
27 tol=PPL_TOL,
28 ):
29 dataset = load_dataset("lmms-lab-encoder/llava-bench-in-the-wild", split="train")
30
31 vllm_extra_kwargs = get_vllm_extra_kwargs(model_info, vllm_extra_kwargs)
32
33 if mm_processor_kwargs is None:
34 mm_processor_kwargs = {}
35
36 processor = AutoProcessor.from_pretrained(model_info.name)
37 image_token_id = processor.image_token_id
38
39 images = []
40 prompts = []
41 for row in dataset:
42 image = row["image"]
43 images.append(image)
44
45 question = row["question"]
46 answer = row["gpt_answer"]
47
48 conversation = [
49 {
50 "role": "user",
51 "content": [
52 {
53 "type": "image",
54 },
55 {"type": "text", "text": question},
56 ],
57 },
58 {"role": "assistant", "content": answer},
59 ]
60
61 prompt = processor.apply_chat_template(conversation, add_generation_prompt=True)
62 prompts.append(prompt)
63
64 with vllm_runner(
65 model_info.name,
66 gpu_memory_utilization=0.7,
67 max_num_seqs=1,
68 max_model_len=4096,
69 mm_processor_kwargs=mm_processor_kwargs,
70 **vllm_extra_kwargs,
71 ) as vllm_model:
72 # Use max_num_seqs=1 to avoid OOM,
73 # and avoid batch different requests together.
74
75 model_config = vllm_model.llm.llm_engine.model_config
76 mm_device_do_normalize = model_config.multimodal_config.mm_device_do_normalize
77
78 # Confirm whether vllm is using the correct architecture
79 if model_info.architecture:
80 assert model_info.architecture in model_config.architectures
81
82 nll_sum = torch.tensor(0.0, dtype=torch.float32, device="cpu")
83 n_tokens = 0
84
85 outputs = vllm_model.generate_greedy_logprobs(
86 prompts=prompts,
87 images=images,
88 max_tokens=1,
89 num_logprobs=None,
90 num_prompt_logprobs=0,
91 use_tqdm=False,
92 )
93
94 for output in outputs:
95 output = cast(TokensTextLogprobsPromptLogprobs, output)
96 token_datas = cast(list[dict[int, Logprob] | None], output[3])
97
98 assert token_datas[0] is None
99 token_log_probs = []
100 for token_data in token_datas[1:]:
101 assert token_data is not None
102 assert len(token_data) == 1
103 token_id, token_log_prob = next(iter(token_data.items()))
104 if token_id == image_token_id:
105 continue
106 token_log_probs.append(token_log_prob.logprob)
107
108 neg_log_likelihood = -torch.tensor(
109 token_log_probs, dtype=torch.float32, device="cpu"
110 ).sum()
111 nll_sum += neg_log_likelihood
112 n_tokens += len(token_log_probs)
113 vllm_ppl = float(torch.exp(nll_sum / n_tokens))
114 vllm_dtype = model_config.dtype
115 head_dtype = model_config.head_dtype
116
117 # Accelerate ppl test by setting Transformers ppl score to a constant
118 if model_info.hf_ppl is None:
119 with hf_runner(
120 model_info.name,
121 dtype=ci_envs.VLLM_CI_HF_DTYPE or model_info.hf_dtype,
122 auto_cls=AutoModelForImageTextToText,
123 ) as hf_model:
124 nll_sum = torch.tensor(0.0, dtype=torch.float32, device="cpu")
125 n_tokens = 0
126
127 for prompt, image in zip(prompts, images):
128 inputs = processor(
129 text=[prompt],
130 images=[image],
131 padding=True,
132 return_tensors="pt",
133 **mm_processor_kwargs,
134 )
135 inputs = inputs.to("cuda")
136 input_ids = inputs["input_ids"]
137
138 labels = input_ids.masked_fill(input_ids == image_token_id, -100)
139 outputs = hf_model.model(**inputs, labels=labels)
140 neg_log_likelihood = outputs.loss
141 neg_log_likelihood = neg_log_likelihood.to(torch.float32).cpu()
142
143 num_loss_tokens = int((labels[:, 1:] != -100).sum())
144 nll_sum += neg_log_likelihood * num_loss_tokens
145 n_tokens += num_loss_tokens
146
147 hf_ppl = float(torch.exp(nll_sum / n_tokens))
148 hf_dtype = next(hf_model.model.parameters()).dtype
149 else:
150 hf_ppl = model_info.hf_ppl
151 hf_dtype = "Constant"
152
153 differ = (vllm_ppl - hf_ppl) / hf_ppl
154 print("Model:", model_info.name)
155 print("mm_device_do_normalize:", mm_device_do_normalize)
156 print("VLLM:", f"dtype:{vllm_dtype}", f"head_dtype:{head_dtype}", vllm_ppl)
157 print("Transformers:", hf_dtype, hf_ppl)
158 print("Difference (%):", differ * 100)
159
160 assert abs(differ) < tol
161 return vllm_ppl