| --- |
| license: mit |
| base_model: google/siglip-so400m-patch14-384 |
| tags: |
| - medical-imaging |
| - ophthalmology |
| - oct |
| - age-related-macular-degeneration |
| - vision-transformer |
| - siglip |
| - pytorch |
| pipeline_tag: image-classification |
| --- |
| |
| # vit-oct-wamd |
|
|
| A [SigLIP](https://huggingface.co/google/siglip-so400m-patch14-384) vision transformer |
| fine-tuned to classify optical coherence tomography (OCT) B-scan images as **normal** |
| or **wet AMD** (neovascular age-related macular degeneration). |
|
|
| Released as supporting material for an accompanying paper. |
|
|
| ## Model description |
|
|
| - **Base encoder:** `google/siglip-so400m-patch14-384`, fine-tuned end-to-end. |
| - **Head:** a single linear layer (`1152 β 2`) on top of the encoder's CLS token, with dropout before the head. |
| - **Auxiliary branch:** the released checkpoint also includes a frozen T5-base text encoder + projection (`siglip_loss` in the state dict), |
| used only for an auxiliary contrastive image-text alignment loss during training. |
| It is **not used at inference time** β `forward()` only calls `image_encoder` and `cls_head`. |
|
|
| ## Dataset |
|
|
| Dataset: [kavin-aravindhan/oct-wamd](https://huggingface.co/datasets/kavin-aravindhan/oct-wamd). |
| Public access is pending IRB approval β for interim access, contact Kavin |
| Aravindhan (kr3131@columbia.edu). |
|
|
| ## Files in this repo |
|
|
| | File | Purpose | |
| |---|---| |
| | `best_model.pt` | Full training checkpoint (classifier weights + auxiliary branch + optimizer/scheduler state). | |
| | `modeling.py`, `alignment.py`, `embedder.py` | Model definition matching the checkpoint exactly. | |
| | `infer.py` | Quick-start CLI: run the classifier on one or more images. | |
| | `demo_app.py` | Local interactive Gradio demo (image upload β prediction). | |
| | `train.py` | Trainer script reproducing the paper's training procedure. | |
| | `training_config.json` | Exact hyperparameters used for this checkpoint. | |
| | `requirements.txt`, `requirements-train.txt`, `requirements-demo.txt` | Pinned dependency versions for `infer.py`, `train.py`, and `demo_app.py` respectively. | |
|
|
| ## Quick start |
|
|
| ```bash |
| pip install huggingface_hub |
| huggingface-cli download kavin-aravindhan/vit-oct-wamd infer.py requirements.txt --local-dir . |
| pip install -r requirements.txt |
| python infer.py path/to/scan.png |
| ``` |
|
|
| `requirements.txt` pins `torch`/`transformers`/`huggingface_hub` to the exact |
| versions used to produce `best_model.pt` β an unpinned `pip install |
| transformers` can resolve to a version whose `SiglipVisionModel` uses |
| different internal parameter names, which will fail to load this |
| checkpoint's state dict. |
|
|
| ``` |
| path/to/scan.png: wet_amd (confidence=0.513) |
| ``` |
|
|
| First run downloads the checkpoint (~5.1GB) and caches it; subsequent runs take a few seconds per image on GPU, ~15-20s on CPU. |
|
|
| Or from Python: |
|
|
| ```python |
| from huggingface_hub import hf_hub_download |
| import sys, os, torch |
| |
| repo_id = "kavin-aravindhan/vit-oct-wamd" |
| local_dir = os.path.dirname(hf_hub_download(repo_id=repo_id, filename="modeling.py")) |
| for f in ["alignment.py", "embedder.py", "best_model.pt"]: |
| hf_hub_download(repo_id=repo_id, filename=f, local_dir=local_dir) |
| |
| sys.path.insert(0, local_dir) |
| from modeling import load_model, IMAGE_SIZE |
| |
| model = load_model(os.path.join(local_dir, "best_model.pt"), device="cuda") # or "cpu" |
| ``` |
|
|
| See `infer.py` for the exact image preprocessing (resize to 384Γ384, normalize to `[-1, 1]`). |
|
|
| ## Interactive demo |
|
|
| Run the demo locally: |
|
|
| ```bash |
| pip install huggingface_hub |
| huggingface-cli download kavin-aravindhan/vit-oct-wamd demo_app.py requirements-demo.txt --local-dir . |
| pip install -r requirements-demo.txt |
| python demo_app.py |
| ``` |
|
|
| This opens a local web UI where you can upload an OCT B-scan and see the |
| prediction. `requirements-demo.txt` pins a specific gradio + transformers + |
| huggingface_hub + pydantic/starlette/fastapi combination verified to work |
| together end-to-end β gradio's latest releases require `huggingface_hub>=1.0`, |
| which conflicts with the `transformers==4.53.0` needed to load the |
| checkpoint, and an unpinned newer pydantic/starlette paired with older |
| gradio breaks page rendering outright. |
|
|
| ## Reproducing training |
|
|
| `train.py` is a cleaned-up, parameterized version of the exact script used |
| to train this checkpoint β same architecture, loss, hyperparameters (500-trial |
| Optuna search, see `training_config.json`), and augmentation recipe. |
|
|
| ```bash |
| pip install -r requirements-train.txt |
| python train.py --tfrecord-path /path/to/.tfrecord --output-dir ./runs/my_run |
| ``` |
|
|
| **Data access:** see [Dataset](#dataset) above β the training set (112 |
| labeled images with clinical-finding captions) is hosted as a private HF |
| dataset pending IRB approval. |
|
|
| **Note on training-set size:** training draws 1000 samples per epoch, with replacement and augmentation, from only 112 unique images β not 1000 unique examples. |
|
|
| | Hyperparameter | Value | |
| |---|---| |
| | Image encoder | `google/siglip-so400m-patch14-384` | |
| | Text encoder (auxiliary branch) | `google-t5/t5-base` | |
| | Batch size | 8 | |
| | Learning rate | 1e-4 | |
| | Weight decay | 1.6e-6 | |
| | Alpha (loss mixing, cls vs. alignment) | 0.884 | |
| | Dropout | 0.057 | |
| | Epochs | 50 (early stopping patience 20) | |
|
|
| ## License |
|
|
| MIT. |
|
|
| ## Citation |
|
|
| TODO β paper citation to be added before camera-ready. |
|
|