Views
No views yet
⚠️ Not a medical device. This is a research and educational project. It is not FDA/CE cleared, has not been clinically validated, and must not be used to diagnose, treat, or make any decision about a real patient. Outputs are frequently wrong. See Limitations — they are substantial and you should read them before using anything here.
The X-ray and the symptoms go into one model, not two. The fusion model is a single network that consumes the radiograph and the symptom text together and emits one set of logits —fusion_full.onnxis one graph with three inputs (pixel_values,input_ids,attention_mask). There is no separate image classifier and text classifier whose outputs get merged afterwards; the two modalities are fused inside the model, before the classifier head. The BLIP captioner below is a separate, optional model that only writes a text description of the image — it takes no symptom input and plays no part in the diagnosis path.
| Component | Path | Size | What it does |
|---|---|---|---|
| Fusion model (ONNX, end-to-end) — the main model | checkpoints/onnx_full/fusion_full.onnx | 787 MB | X-ray and symptom text → diagnosis logits, in one graph. Runs with onnxruntime alone — no PyTorch. |
| Fusion classifier head (PyTorch) | checkpoints/fusion_model.pth | 5.4 MB | Trained classifier head only; needs CLIP + Bio_ClinicalBERT at runtime. |
| Fusion classifier head (ONNX) | checkpoints/onnx/fusion_classifier.onnx | 4.5 MB | Head-only ONNX; encoders still run in PyTorch. |
| BLIP X-ray captioner | blip-xray-finetuned/ | 896 MB | Salesforce/blip-image-captioning-base fine-tuned on IU-Xray reports → radiology-style caption. |
| Default/demo classifier | models/default/fusion_classifier.onnx | 1.3 MB | 15 NIH classes, random weights. Ships so the app runs before training. Not predictive. |
| Application code | *.py, launch.*, config.json | — | CLI, Gradio web UI, batch predictor, training and ONNX export scripts. |
image ──► CLIP ViT-B/32 vision tower ──► visual_projection ──► L2-normalize ──┐
├─► concat ──► MLP classifier ──► logits
symptom text ──► Bio_ClinicalBERT ──► mean-pool last_hidden_state ────────────┘fusion_full.onnx bakes the whole graph — encoders included — into one file, which is why it is 787 MB.| Name | Shape | dtype | |
|---|---|---|---|
| in | pixel_values | [batch, 3, 224, 224] | float32 |
| in | input_ids | [batch, seq_len] | int64 |
| in | attention_mask | [batch, seq_len] | int64 |
| out | logits | [batch, 3018] | float32 |
CLIPProcessor (openai/clip-vit-base-patch32) for the image and AutoTokenizer (emilyalsentzer/Bio_ClinicalBERT) for the text. Class names are in checkpoints/onnx_full/labels.json, index-aligned to the logits.BlipForConditionalGeneration.from_pretrained. It does not see the symptoms and does not feed the fusion model; it exists to write a human-readable description alongside the diagnosis.1import json
2import numpy as np
3import onnxruntime as ort
4from PIL import Image
5from transformers import CLIPProcessor, AutoTokenizer
6from huggingface_hub import hf_hub_download
7
8repo = "GAD-Research-Lab/MedicalAI-Light-Weight"
9onnx_path = hf_hub_download(repo, "checkpoints/onnx_full/fusion_full.onnx")
10labels = json.load(open(hf_hub_download(repo, "checkpoints/onnx_full/labels.json")))
11
12clip = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")
13tok = AutoTokenizer.from_pretrained("emilyalsentzer/Bio_ClinicalBERT")
14
15image = Image.open("xray.jpg").convert("RGB")
16pixel_values = clip(images=image, return_tensors="np")["pixel_values"]
17text = tok("cough and fever", return_tensors="np", padding="max_length",
18 truncation=True, max_length=64)
19
20sess = ort.InferenceSession(onnx_path, providers=["CPUExecutionProvider"])
21logits = sess.run(["logits"], {
22 "pixel_values": pixel_values.astype(np.float32),
23 "input_ids": text["input_ids"].astype(np.int64),
24 "attention_mask": text["attention_mask"].astype(np.int64),
25})[0]
26
27probs = np.exp(logits - logits.max()) / np.exp(logits - logits.max()).sum()
28top = probs[0].argmax()
29print(labels[top], float(probs[0][top]))1from transformers import BlipProcessor, BlipForConditionalGeneration
2from PIL import Image
3
4repo = "GAD-Research-Lab/MedicalAI-Light-Weight"
5processor = BlipProcessor.from_pretrained(repo, subfolder="blip-xray-finetuned")
6model = BlipForConditionalGeneration.from_pretrained(repo, subfolder="blip-xray-finetuned")
7
8inputs = processor(Image.open("xray.jpg").convert("RGB"), return_tensors="pt")
9print(processor.decode(model.generate(**inputs, max_new_tokens=64)[0],
10 skip_special_tokens=True))1git clone https://huggingface.co/GAD-Research-Lab/MedicalAI-Light-Weight
2cd MedicalAI-Light-Weight
3pip install -r requirements.txt gradio
4python web_ui.py # http://127.0.0.1:7860launch.ps1 (Windows) / launch.sh (Linux/macOS) to set up a venv and start the UI in one step. python run.py for the interactive CLI, python batch_predict.py <dir> -o out.csv for batch.python training.py --mode train --epochs 10 --batch_size 8.python xray_training.py --mode train --epochs 3 --batch_size 4 --max_samples 500.expand_dataset.py — ~9,847 total.labels.json has 3,018 classes, and most are not diagnoses — they are raw, deduplicated report strings scraped from IU-Xray, e.g. "findings: . impression: 1. all lines and tubes in stable , xxxx position...". Only a handful (atelectasis, cardiomegaly, consolidation, edema, effusion, emphysema, fibrosis, …) are clean condition names. With ~9.8k training rows across 3,018 classes there are roughly 3 examples per class, and the reported "confidence" is a softmax over that space — it is not calibrated and should not be read as a probability of disease. Treat the classifier as a demonstration of the architecture, not as a working diagnostic.models/default/ is random weights by construction, so the app can start before training. Its predictions are noise.python training.py --mode prepare-data.xxxx anonymization tokens. Check each dataset's own terms before redistributing derivatives.1@software{medicalai_light_weight,
2 title = {MedicalAI — Light Weight: CPU-friendly chest X-ray analysis},
3 author = {GAD Research Lab},
4 year = {2026},
5 url = {https://huggingface.co/GAD-Research-Lab/MedicalAI-Light-Weight}
6}