Views
No views yet

🧪 The current Viper-L1 (1.2B parameters) was trained on ~4 million images using 2× H100 GPUs for 2 days.
| Benchmark | Task | Split | Metric | Viper-L1 (CoT) |
|---|---|---|---|---|
| RealWorldQA | VQA | Test | Accuracy | 33.73% |
| Other results | VQA | Test | Accuracy | On going |
infer_viper.sh1import os
2import argparse
3import torch
4from PIL import Image
5from transformers import AutoTokenizer, AutoProcessor
6from model import ViperLMForCausalLM # your local class
7IMAGE_TOKEN_ID = 64400
8def build_messages(question: str, include_image: bool = True):
9 # Mirror CCDataset._format_prompt()
10 user_content = ("<image> " if include_image else "") + (question or "")
11 return [
12 {"role": "user", "content": user_content},
13 # assistant turn is left empty; apply_chat_template(add_generation_prompt=True) will add assistant prefix
14 ]
15
16@torch.inference_mode()
17def generate_answer(
18 ckpt_dir: str,
19 tokenizer_path: str,
20 processor_path: str,
21 image_path: str,
22 question: str,
23 device: str = "cuda",
24 dtype: str = "bf16",
25 max_new_tokens: int = 128,
26 temperature: float = 0.2,
27 top_p: float = 0.9,
28 repetition_penalty: float = 1.05,
29):
30 # --- device / dtype ---
31 device = torch.device(device if torch.cuda.is_available() else "cpu")
32 use_bf16 = (dtype.lower() == "bf16")
33 use_fp16 = (dtype.lower() == "fp16")
34 amp_dtype = torch.bfloat16 if use_bf16 else (torch.float16 if use_fp16 else torch.float32)
35
36 # --- tokenizer / processor ---
37 tokenizer = AutoTokenizer.from_pretrained(tokenizer_path, use_fast=True)
38 if tokenizer.pad_token_id is None:
39 tokenizer.pad_token = tokenizer.eos_token
40 # optional but common for generation with left context
41 if not hasattr(tokenizer, "padding_side") or tokenizer.padding_side != "left":
42 tokenizer.padding_side = "left"
43
44 processor = AutoProcessor.from_pretrained(processor_path)
45
46 # --- model ---
47 model = ViperLMForCausalLM.from_pretrained(
48 ckpt_dir,
49 torch_dtype=amp_dtype if device.type == "cuda" else torch.float32,
50 ).to(device)
51 model.eval()
52 if getattr(model.config, "pad_token_id", None) is None:
53 model.config.pad_token_id = tokenizer.pad_token_id
54
55 # expose image token id if your forward expects it; keep it consistent with training
56 image_token_id = getattr(model.config, "image_token_id", None)
57 if image_token_id is None and "<image>" in tokenizer.get_vocab():
58 image_token_id = tokenizer.convert_tokens_to_ids("<image>")
59
60 # --- text input with the SAME chat template as training ---
61 messages = build_messages(question=question, include_image=True)
62 enc = tokenizer.apply_chat_template(
63 messages,
64 add_generation_prompt=True, # adds assistant header the model expects before generation
65 tokenize=True,
66 return_tensors="pt",
67 )
68 if isinstance(enc, torch.Tensor):
69 input_ids = enc
70 attention_mask = torch.ones_like(enc, dtype=torch.long)
71 else:
72 input_ids = enc["input_ids"]
73 attention_mask = enc.get("attention_mask")
74 if attention_mask is None:
75 attention_mask = torch.ones_like(input_ids, dtype=torch.long)
76
77 input_ids = input_ids.to(device)
78 attention_mask = attention_mask.to(device)
79
80 # --- image preprocessing (match training) ---
81 img = Image.open(image_path).convert("RGB")
82 proc = processor(images=[img], return_tensors="pt") # list, like training
83 pixel_values = proc.get("pixel_values", None)
84 if pixel_values is None:
85 raise ValueError("Processor did not return 'pixel_values'. Check processor_path.")
86 pixel_values = pixel_values.to(device) # (1, 3, H, W)
87
88 # --- generate ---
89 gen_kwargs = {
90 "max_new_tokens": max_new_tokens,
91 "do_sample": temperature > 0.0,
92 "temperature": max(temperature, 1e-6),
93 "top_p": top_p,
94 "repetition_penalty": repetition_penalty,
95 "eos_token_id": tokenizer.eos_token_id,
96 "pad_token_id": tokenizer.pad_token_id,
97 "image_inputs": pixel_values,
98 # IMPORTANT: use the same argument names your model.forward saw in training # not "image_inputs"
99 "image_token_id": image_token_id, # if your forward uses it
100 "use_cache": False,
101 }
102
103 if device.type == "cuda" and (use_bf16 or use_fp16):
104 with torch.autocast(device_type="cuda", dtype=amp_dtype):
105 out = model.generate(
106 input_ids=input_ids,
107 attention_mask=attention_mask,
108 **gen_kwargs
109 )
110 else:
111 out = model.generate(
112 input_ids=input_ids,
113 attention_mask=attention_mask,
114 **gen_kwargs
115 )
116
117 # --- decode only new tokens ---
118 generated = out[0]
119 prompt_len = input_ids.size(1)
120 new_tokens = generated[prompt_len:]
121 answer = tokenizer.decode(new_tokens, skip_special_tokens=True)
122 return answer.strip()
123
124if __name__ == "__main__":
125 ckpt_dir = ""
126 tokenizer_path = ""
127 processor_path = ""
128 image_path = ""
129 question = ""
130 device = ""
131 ans = generate_answer(
132 ckpt_dir=ckpt_dir,
133 tokenizer_path=tokenizer_path,
134 processor_path=processor_path,
135 image_path=image_path,
136 question=question,
137 device=device,
138 dtype="bfloat16",
139 max_new_tokens=128,
140 temperature=0.7,
141 top_p=0.8,
142 repetition_penalty=1
143 )
144 print("\n ======Answer===== \n")
145 print(ans)
146