-
Notifications
You must be signed in to change notification settings - Fork 243
Expand file tree
/
Copy pathinfer_single_image.py
More file actions
147 lines (123 loc) · 4.01 KB
/
Copy pathinfer_single_image.py
File metadata and controls
147 lines (123 loc) · 4.01 KB
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
145
146
147
"""
inference/infer_single_image.py
-------------------------------
Single 2D medical image inference with HealthGPT-Pro.
Accepts any common medical image format (PNG, JPG, DICOM-exported PNG, etc.)
and a free-form clinical question.
Usage:
python inference/infer_single_image.py \
--model lintw/HealthGPT-Pro-4B \
--image examples/chest_xray.png \
--question "Describe the main radiological findings in this image."
python inference/infer_single_image.py \
--model lintw/HealthGPT-Pro-8B \
--image examples/fundus.png \
--question "Are there any signs of diabetic retinopathy? If so, describe the severity."
"""
from __future__ import annotations
import argparse
import sys
from pathlib import Path
import torch
from PIL import Image
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from inference.utils import decode_output, load_model
def run_single_image_inference(
model,
processor,
image_path: str,
question: str,
max_new_tokens: int = 512,
temperature: float = 0.7,
) -> str:
"""Run inference on a single 2D medical image.
Args:
model: Loaded Qwen3VLForConditionalGeneration model.
processor: Corresponding AutoProcessor.
image_path: Path to the input image file (PNG / JPG / etc.).
question: Clinical question about the image.
max_new_tokens: Maximum tokens to generate.
temperature: Sampling temperature (0.0 = greedy).
Returns:
Generated response string.
"""
# Validate image
img_path = Path(image_path)
if not img_path.exists():
raise FileNotFoundError(f"Image not found: {image_path}")
# Load image to verify it is valid (also converts non-RGB modes)
image = Image.open(img_path).convert("RGB")
messages = [
{
"role": "user",
"content": [
{"type": "image", "image": image},
{"type": "text", "text": question},
],
}
]
inputs = processor.apply_chat_template(
messages,
tokenize=True,
add_generation_prompt=True,
return_dict=True,
return_tensors="pt",
).to(model.device)
generate_kwargs: dict = {"max_new_tokens": max_new_tokens}
if temperature > 0.0:
generate_kwargs.update({"do_sample": True, "temperature": temperature})
else:
generate_kwargs["do_sample"] = False
with torch.inference_mode():
generated_ids = model.generate(**inputs, **generate_kwargs)
return decode_output(generated_ids, inputs.input_ids, processor)
def main() -> None:
parser = argparse.ArgumentParser(
description="HealthGPT-Pro — Single 2D Medical Image Inference"
)
parser.add_argument(
"--model",
type=str,
default="lintw/HealthGPT-Pro-4B",
help="HuggingFace model ID or local path.",
)
parser.add_argument(
"--image",
type=str,
required=True,
help="Path to the input medical image (PNG, JPG, etc.).",
)
parser.add_argument(
"--question",
type=str,
default="Describe the main findings in this medical image.",
help="Clinical question about the image.",
)
parser.add_argument(
"--max_new_tokens",
type=int,
default=512,
help="Maximum number of tokens to generate (default: 512).",
)
parser.add_argument(
"--temperature",
type=float,
default=0.7,
help="Sampling temperature. 0.0 = greedy (default).",
)
args = parser.parse_args()
model, processor = load_model(model_id=args.model)
print(f"\n{'='*60}")
print(f"[Image ] {args.image}")
print(f"[Question] {args.question}")
print(f"{'='*60}")
answer = run_single_image_inference(
model, processor,
image_path=args.image,
question=args.question,
max_new_tokens=args.max_new_tokens,
temperature=args.temperature,
)
print(f"[Answer]\n{answer}")
if __name__ == "__main__":
main()