File size: 5,360 Bytes
7325252
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
"""HPD-Parsing throughput (TPS) benchmark on vLLM.

Batched offline inference over an image folder; reports TPS metrics and dumps
the raw predictions consumed by hpd_to_markdown.py (model is run once).

    MAX_PATCHES_WITH_RESIZE=true python eval/benchmark_tps.py
"""
import os

os.environ.setdefault("MAX_PATCHES_WITH_RESIZE", "true")  # before importing vLLM

import base64
import json
import time
from typing import Any, Dict

from vllm import LLM, SamplingParams
from vllm.sampling_params import RepetitionDetectionParams

PRED_OUT = "batch_512_pred_HPD-Parsing.json"

llm = None
sampling_params = None


def encode_image_to_base64(image_path: str) -> str:
    with open(image_path, "rb") as f:
        return base64.b64encode(f.read()).decode("utf-8")


def batch_predict_vllm(tasks, batch_size=512):
    all_outputs = []
    records = []
    for start in range(0, len(tasks), batch_size):
        batch_tasks = tasks[start:start + batch_size]
        messages_list = [
            [{
                "role": "user",
                "content": [
                    {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{img_b64}"}},
                    {"type": "text", "text": question},
                ],
            }]
            for question, img_b64, _ in batch_tasks
        ]
        outputs = llm.chat(messages=messages_list, sampling_params=sampling_params)
        all_outputs.extend(outputs)
        for j, out in enumerate(outputs):
            records.append({
                "index": start + j,
                "img_path": batch_tasks[j][-1],
                "pred": out.outputs[0].text,
            })
    return all_outputs, records


def parse_ckpt_name(model_path: str) -> str:
    parts = model_path.rstrip('/').split('/')
    return '_'.join(p for p in parts if p and p not in ['checkpoints', 'output', 'rank_0'])


def record_metrics(model_path: str, metrics: Dict[str, Any], output_dir: str = "./records"):
    os.makedirs(output_dir, exist_ok=True)
    output_file = os.path.join(output_dir, f"{parse_ckpt_name(model_path)}.txt")
    with open(output_file, 'w', encoding='utf-8') as f:
        f.write(f"Model Path: {model_path}\n")
        f.write(f"Checkpoint: {parse_ckpt_name(model_path)}\n")
        f.write("=" * 50 + "\n")
        for key, value in metrics.items():
            f.write(f"{key}: {value}\n")
    print(f"Metrics saved to: {output_file}")


if __name__ == '__main__':
    model_path = "PaddlePaddle/HPD-Parsing/"
    model_path_medusa = "PaddlePaddle/HPD-Parsing/P-MTP/"
    root = "OmniDocBench_1_6/images/"
    prompt = "document parsing with fork."
    batch_size = 512

    llm = LLM(
        model=model_path,
        tensor_parallel_size=1,
        gpu_memory_utilization=0.9,
        enable_prefix_caching=True,
        attention_backend="FLASHINFER",
        trust_remote_code=True,
        max_model_len=24000,
        max_num_seqs=512,
        speculative_config={"method": "medusa", "model": model_path_medusa, "num_speculative_tokens": 6},
    )
    sampling_params = SamplingParams(
        temperature=0,
        max_tokens=8000,
        stop=None,
        repetition_detection=RepetitionDetectionParams(
            min_pattern_size=64,
            max_pattern_size=128,
            min_count=10,
        ),
    )

    valid_extensions = {'.jpg', '.jpeg', '.png', '.bmp', '.gif', '.webp'}
    image_paths = [
        os.path.join(root, p) for p in os.listdir(root)
        if os.path.splitext(p)[1].lower() in valid_extensions
    ]
    tasks = [(prompt, encode_image_to_base64(p), p) for p in image_paths]
    print(f"Total images: {len(tasks)}")

    start_time = time.perf_counter()
    outputs, records = batch_predict_vllm(tasks, batch_size=batch_size)
    end_time = time.perf_counter()

    with open(PRED_OUT, "w", encoding="utf-8") as fp:
        json.dump(records, fp, indent=4, ensure_ascii=False)
    print(f"Predictions saved to: {PRED_OUT}")

    total_time = end_time - start_time
    total_input_tokens = sum(len(out.prompt_token_ids) for out in outputs)
    total_output_tokens = sum(len(out.outputs[0].token_ids) for out in outputs)

    print(f"Total Time: {total_time:.2f} s")
    print(f"Throughput (Requests/s): {len(tasks) / total_time:.2f}")
    print(f"Input Tokens/s: {total_input_tokens / total_time:.2f}")
    print(f"Output Tokens/s: {total_output_tokens / total_time:.2f}")
    print(f"Total Tokens/s: {(total_input_tokens + total_output_tokens) / total_time:.2f}")
    print(f"Avg Input Tokens per Request: {total_input_tokens / len(tasks):.2f}")
    print(f"Avg Output Tokens per Request: {total_output_tokens / len(tasks):.2f}")

    metrics = {
        "Total Time (s)": f"{total_time:.2f}",
        "Throughput (Requests/s)": f"{len(tasks) / total_time:.2f}",
        "Input Tokens/s": f"{total_input_tokens / total_time:.2f}",
        "Output Tokens/s": f"{total_output_tokens / total_time:.2f}",
        "Total Tokens/s": f"{(total_input_tokens + total_output_tokens) / total_time:.2f}",
        "Avg Input Tokens per Request": f"{total_input_tokens / len(tasks):.2f}",
        "Avg Output Tokens per Request": f"{total_output_tokens / len(tasks):.2f}",
        "Total Requests": len(tasks),
        "Total Input Tokens": total_input_tokens,
        "Total Output Tokens": total_output_tokens,
    }
    record_metrics(model_path, metrics)