This model is a Vision Transformer adapted for neuropathology tasks, developed using data from the University of Kentucky. It leverages principles from self-supervised learning models like DINOv2.
This model serves as an initial test while a proper training and evaluation dataset is generated
This model is intended for research purposes in the field of neuropathology.
facebook/dinov2-with-registers-giant loaded from Hugging Face Hub.The following PCA visualizations illustrate how embeddings extracted at 10× and 40× magnifications relate to each other across different models. Gray lines connect spatially aligned parent–child tile pairs, enabling a direct comparison of cross-magnification consistency. The DINOv2-Giant baseline shown here is fine-tuned on the same neuropathology dataset using the standard DINO self-supervised training strategy without magnification-aware alignment. While baseline models exhibit clear magnification-dependent separation, MAD-NP produces overlapping clusters where tissue identity is preserved across resolutions, indicating a unified and magnification-stable embedding space.
<table>
<tr>
<td align="center"><b>(a) MAD-NP</b></td>
<td align="center"><b>(b) Virchow2</b></td>
<td align="center"><b>(c) DINOv2 Giant Finetuned</b></td>
</tr>
<tr>
<td>
<img src="MAD-NP_pca_cross_mag.png" width="500">
</td>
<td>
<img src="Virchow2_pca_cross_mag.png" width="500">
</td>
<td>
<img src="DINOv2-Giant_pca_cross_mag.png" width="500">
</td>
</tr>
</table>
| Model | Linear F1 ↑ | k-NN F1 ↑ | AMI ↑ | DBI ↓ | |
|---|---|---|---|---|---|
| MAD-NP | 0.9307 | 0.9286 | 0.7668 | 1.2821 | |
| UNI2 | 0.9252 | 0.9209 | 0.4478 | 2.3078 | |
| Prov-GigaPath | 0.9273 | 0.9215 | 0.4732 | 2.0342 | |
| UNI | 0.9245 | 0.9284 | 0.2975 | 1.9559 | N/A |
| DINOv2-Giant (FT) | 0.9146 | 0.9092 | 0.5275 | 1.4133 | |
| Virchow2 | 0.9135 | 0.9072 | 0.3597 | 1.2867 |
While the evaluation dataset was distinct from the training set, they were from the same institution, using the same staining, and obtained from the same scanner. It is not unexpected that a model fine-tuned on such a closely associated dataset would perform better. An evaluation dataset with broader representation is needed for a proper evaluation of generalized performance.
<img src="model_compare_radar.png" alt="chart" width="800"/>
The radar chart provides a visual comparison of multiple models across several performance metrics. Each axis extending from the center represents a different metric. The farther a model’s line is from the center along a particular axis, the better its score for that specific metric (assuming higher is better for the metric).
How to Interpret:
Tests
Three example methods using Hugging Face transformers (adjust based on your actual model and task):
import torch
from PIL import Image
from transformers import AutoModel, AutoImageProcessor
from torchvision import transforms
def get_embeddings_with_processor(image_path, model_path):
"""
Extract embeddings using a HuggingFace image processor.
This approach handles normalization and resizing automatically.
Args:
image_path: Path to the image file
model_path: Path to the model directory
processor_path: Path to the processor config directory
Returns:
Image embeddings from the model
"""
# Load model
model = AutoModel.from_pretrained(model_path)
model.eval()
# Load processor from config
image_processor = AutoImageProcessor.from_pretrained(model_path)
# Process the image
with torch.no_grad():
image = Image.open(image_path).convert('RGB')
inputs = image_processor(images=image, return_tensors="pt")
outputs = model(**inputs)
embeddings = outputs.last_hidden_state[:, 0, :]
return embeddings
def get_embeddings_direct(image_path, model_path, mean=[0.874, 0.805, 0.775], std=[0.087, 0.095, 0.102]):
"""
Extract embeddings directly without an image processor.
This approach works with various image resolutions since transformers handle
different input sizes by design.
Args:
image_path: Path to the image file
model_path: Path to the model directory
mean: Normalization mean values
std: Normalization standard deviation values
Returns:
Image embeddings from the model
"""
# Load model
model = AutoModel.from_pretrained(model_path)
model.eval()
# Define transformation - just converting to tensor and normalizing
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(mean=mean, std=std)
])
# Process the image
with torch.no_grad():
# Open image and convert to RGB
image = Image.open(image_path).convert('RGB')
# Convert image to tensor
image_tensor = transform(image).unsqueeze(0) # Add batch dimension
# Feed to model
outputs = model(pixel_values=image_tensor)
# Get embeddings
embeddings = outputs.last_hidden_state[:, 0, :]
return embeddings
def get_embeddings_resized(image_path, model_path, size=(224, 224), mean=[0.874, 0.805, 0.775], std=[0.087, 0.095, 0.102]):
"""
Extract embeddings with explicit resizing to 224x224.
This approach ensures consistent input size regardless of original image dimensions.
Args:
image_path: Path to the image file
model_path: Path to the model directory
size: Target size for resizing (default: 224x224)
mean: Normalization mean values
std: Normalization standard deviation values
Returns:
Image embeddings from the model
"""
# Load model
model = AutoModel.from_pretrained(model_path)
model.eval()
# Define transformation with explicit resize
transform = transforms.Compose([
transforms.Resize(size, interpolation=transforms.InterpolationMode.BICUBIC),
transforms.ToTensor(),
transforms.Normalize(mean=mean, std=std)
])
# Process the image
with torch.no_grad():
image = Image.open(image_path).convert('RGB')
image_tensor = transform(image).unsqueeze(0) # Add batch dimension
outputs = model(pixel_values=image_tensor)
embeddings = outputs.last_hidden_state[:, 0, :]
return embeddings
# Example usage
if __name__ == "__main__":
image_path = "test.jpg"
model_path = "IBI-CAAI/MAD-NP"
# Method 1: Using image processor (recommended for consistency)
embeddings1 = get_embeddings_with_processor(image_path, model_path)
print('Embedding shape (with processor):', embeddings1.shape)
# Method 2: Direct approach without resizing (works with various resolutions)
embeddings2 = get_embeddings_direct(image_path, model_path)
print('Embedding shape (direct):', embeddings2.shape)
# Method 3: With explicit resize to 224x224
embeddings3 = get_embeddings_resized(image_path, model_path)
print('Embedding shape (resized):', embeddings3.shape)
Acknowledgements:
This initial work was supported by the broader Brain Digital Slide Archive (BDSA) Team.
This research was supported by the National Institute of Neurological Disorders and Stroke (NINDS) of the National Institutes of Health (NIH) under award numbers:
For any additional questions or comments, contact CAAI (ai@uky.edu),
Mahmut Gokmen (m.gokmen@uky.edu)
Cody Bumgardner (cody@uky.edu).
https://doi.org/10.48550/arXiv.2512.14796
Imported from hf:Kentucky-Open-Science/MAD-NP. Source last updated 2025-12-28. Synced 2026-07-27.
Available on Hugging Face.
Hosted on Hugging Face.