vankey commited on
Commit
be48c35
·
verified ·
1 Parent(s): dfcf905

Upload inference.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. inference.py +260 -0
inference.py ADDED
@@ -0,0 +1,260 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ import argparse
3
+ import os
4
+ import torch
5
+
6
+ from qwen_vl_utils import process_vision_info
7
+ from transformers import (
8
+ AutoProcessor,
9
+ AutoTokenizer,
10
+ AutoModelForImageTextToText,
11
+ )
12
+
13
+
14
+ DEFAULT_SYSTEM_PROMPT = (
15
+ "你是一个图像鉴伪专家,擅长结合视觉,文字结合伪造特征分析手段鉴别输入图像的真假。"
16
+ "分析过程中,你会逐步分析,抽丝剥茧,找到图像伪造的蛛丝马迹,"
17
+ "最终给出专业的鉴别结果及分析。"
18
+ )
19
+
20
+ DEFAULT_USER_PROMPT = (
21
+ "请分析这张文档图片是否存在伪造或篡改风险,并输出一份专业、精炼、准确的防伪分析报告。"
22
+ )
23
+
24
+
25
+ def build_messages(image_path: str, system_prompt: str, user_prompt: str):
26
+ return [
27
+ {
28
+ "role": "system",
29
+ "content": [
30
+ {
31
+ "type": "text",
32
+ "text": system_prompt,
33
+ }
34
+ ],
35
+ },
36
+ {
37
+ "role": "user",
38
+ "content": [
39
+ {
40
+ "type": "image",
41
+ "image": image_path,
42
+ },
43
+ {
44
+ "type": "text",
45
+ "text": user_prompt,
46
+ },
47
+ ],
48
+ },
49
+ ]
50
+
51
+
52
+ def parse_args():
53
+ parser = argparse.ArgumentParser()
54
+
55
+ parser.add_argument(
56
+ "--model-name",
57
+ type=str,
58
+ default="vankey/DocShield-9B",
59
+ )
60
+ parser.add_argument(
61
+ "--image",
62
+ type=str,
63
+ required=True,
64
+ help="Input image path.",
65
+ )
66
+ parser.add_argument(
67
+ "--prompt",
68
+ type=str,
69
+ default=DEFAULT_USER_PROMPT,
70
+ )
71
+ parser.add_argument(
72
+ "--system-prompt",
73
+ type=str,
74
+ default=DEFAULT_SYSTEM_PROMPT,
75
+ )
76
+
77
+ thinking_group = parser.add_mutually_exclusive_group()
78
+ thinking_group.add_argument(
79
+ "--thinking",
80
+ action="store_true",
81
+ help="Enable Qwen3.5 thinking mode.",
82
+ )
83
+ thinking_group.add_argument(
84
+ "--no-thinking",
85
+ action="store_true",
86
+ help="Disable Qwen3.5 thinking mode.",
87
+ )
88
+
89
+ parser.add_argument(
90
+ "--max-new-tokens",
91
+ type=int,
92
+ default=1024,
93
+ )
94
+ parser.add_argument(
95
+ "--temperature",
96
+ type=float,
97
+ default=0.0,
98
+ )
99
+ parser.add_argument(
100
+ "--top-p",
101
+ type=float,
102
+ default=0.8,
103
+ )
104
+ parser.add_argument(
105
+ "--top-k",
106
+ type=int,
107
+ default=20,
108
+ )
109
+ parser.add_argument(
110
+ "--do-sample",
111
+ action="store_true",
112
+ help="Use sampling. If not set, greedy decoding is used.",
113
+ )
114
+ parser.add_argument(
115
+ "--device",
116
+ type=str,
117
+ default="cuda",
118
+ )
119
+ parser.add_argument(
120
+ "--dtype",
121
+ type=str,
122
+ default="bf16",
123
+ choices=["bf16", "fp16", "fp32"],
124
+ )
125
+
126
+ return parser.parse_args()
127
+
128
+
129
+ def get_torch_dtype(dtype: str):
130
+ if dtype == "bf16":
131
+ return torch.bfloat16
132
+ if dtype == "fp16":
133
+ return torch.float16
134
+ return torch.float32
135
+
136
+
137
+ def main():
138
+ args = parse_args()
139
+
140
+ if not os.path.exists(args.image):
141
+ raise FileNotFoundError(f"Image not found: {args.image}")
142
+
143
+ enable_thinking = False
144
+ if args.thinking:
145
+ enable_thinking = True
146
+ if args.no_thinking:
147
+ enable_thinking = False
148
+
149
+ torch_dtype = get_torch_dtype(args.dtype)
150
+
151
+ print("=" * 100)
152
+ print("Model:", args.model_name)
153
+ print("Image:", args.image)
154
+ print("Prompt:", args.prompt)
155
+ print("Enable thinking:", enable_thinking)
156
+ print("Max new tokens:", args.max_new_tokens)
157
+ print("dtype:", args.dtype)
158
+ print("=" * 100)
159
+
160
+ tokenizer = AutoTokenizer.from_pretrained(
161
+ args.model_name,
162
+ use_fast=True,
163
+ trust_remote_code=True,
164
+ )
165
+
166
+ processor = AutoProcessor.from_pretrained(
167
+ args.model_name,
168
+ trust_remote_code=True,
169
+ )
170
+
171
+ model = AutoModelForImageTextToText.from_pretrained(
172
+ args.model_name,
173
+ torch_dtype=torch_dtype,
174
+ trust_remote_code=True,
175
+ device_map="auto",
176
+ )
177
+
178
+ model.eval()
179
+
180
+ messages = build_messages(
181
+ image_path=args.image,
182
+ system_prompt=args.system_prompt,
183
+ user_prompt=args.prompt,
184
+ )
185
+
186
+ text = processor.apply_chat_template(
187
+ messages,
188
+ tokenize=False,
189
+ add_generation_prompt=True,
190
+ enable_thinking=enable_thinking,
191
+ )
192
+
193
+ print("\n" + "=" * 100)
194
+ print("Rendered prompt preview:")
195
+ print(text[:2000])
196
+ print("=" * 100 + "\n")
197
+
198
+ image_inputs, video_inputs = process_vision_info(messages)
199
+
200
+ inputs = processor(
201
+ text=[text],
202
+ images=image_inputs,
203
+ videos=video_inputs,
204
+ padding=True,
205
+ return_tensors="pt",
206
+ )
207
+
208
+ inputs = inputs.to(model.device)
209
+
210
+ print("input_ids shape:", inputs["input_ids"].shape)
211
+ if "pixel_values" in inputs:
212
+ print("pixel_values shape:", inputs["pixel_values"].shape)
213
+ if "image_grid_thw" in inputs:
214
+ print("image_grid_thw:", inputs["image_grid_thw"])
215
+
216
+ generation_kwargs = {
217
+ "max_new_tokens": args.max_new_tokens,
218
+ }
219
+
220
+ if args.do_sample:
221
+ generation_kwargs.update(
222
+ {
223
+ "do_sample": True,
224
+ "temperature": args.temperature,
225
+ "top_p": args.top_p,
226
+ "top_k": args.top_k,
227
+ }
228
+ )
229
+ else:
230
+ generation_kwargs.update(
231
+ {
232
+ "do_sample": False,
233
+ }
234
+ )
235
+
236
+ with torch.no_grad():
237
+ generated_ids = model.generate(
238
+ **inputs,
239
+ **generation_kwargs,
240
+ )
241
+
242
+ generated_ids_trimmed = [
243
+ out_ids[len(in_ids):]
244
+ for in_ids, out_ids in zip(inputs["input_ids"], generated_ids)
245
+ ]
246
+
247
+ output_text = processor.batch_decode(
248
+ generated_ids_trimmed,
249
+ skip_special_tokens=False,
250
+ clean_up_tokenization_spaces=False,
251
+ )[0]
252
+
253
+ print("\n" + "=" * 100)
254
+ print("Model output:")
255
+ print(output_text)
256
+ print("=" * 100)
257
+
258
+
259
+ if __name__ == "__main__":
260
+ main()