Views
No views yet
transformers ecosystem, making it seamlessly compatible with standard deployment pipelines.| Model | CT-RATE Macro AUROC | RAD-ChestCT AUROC (frozen / retrained probe) | Role |
|---|---|---|---|
| DALE-CT-0-L ⭐ | 0.8156 | 0.6281 / 0.7572 | Recommended general-purpose backbone — best 2D external-transfer point estimates; supervision-free at ~287k-scan scale |
| DALE-CT-2S | 0.8247 | 0.6252 / 0.7389 | Best in-domain (CT-RATE) |
| DALE-CT-1S-v2 | 0.8098 | 0.6284 / 0.7334 | Anatomical (TotalSegmentator) dense supervision only |
| DALE-CT-0 | 0.8057 | 0.5946 / 0.7477 | Pure self-supervised, CT-RATE |
| Finetuned DINOv2 | 0.7953 | 0.6252 / 0.7550 | Continual-pretraining baseline — strongest dense (patch-level) features |
Dinov2WithRegistersModel, ViT-Large).518x518 resolution. Standard Hugging Face DINOv2 models support variable input sizes, provided the height and width are multiples of the patch size (14).[-997.0, 888.0]. These values correspond to the 0.5% and 99.5% pixel intensities of the foreground voxels calculated on a subset of the CT-RATE dataset. The clipped values were mapped to a [0, 1] range, followed by Z-score normalization utilizing a dataset mean of -142.39 and standard deviation of 360.97.bf16 mixed precision.2.0e-04 (decaying to 1.0e-05), and a 3,300-step warmup.timm-based LeJEPA models, this model is natively supported by the Hugging Face transformers library. The repository contains the necessary config.json and model.safetensors files.1import torch
2import torch.nn.functional as F
3import numpy as np
4from transformers import AutoModel
5
6class CTInferenceTransform:
7 """
8 Applies the exact HU windowing and Z-score normalization used during training.
9 """
10 def __init__(self):
11 self.clip_min = -997.0
12 self.clip_max = 888.0
13 self.mean_hu = -142.39
14 self.std_hu = 360.97
15 self.patch_size = 14
16
17 # Calculate 0-1 scaled mean and std
18 range_val = self.clip_max - self.clip_min
19 self.norm_mean = (self.mean_hu - self.clip_min) / range_val
20 self.norm_std = self.std_hu / range_val
21
22 def __call__(self, volume):
23 # Expects a 2D numpy array or torch tensor (H, W) in Hounsfield Units
24 if isinstance(volume, np.ndarray):
25 volume = torch.from_numpy(volume).float()
26 if volume.ndim == 2:
27 volume = volume.unsqueeze(0) # Add channel dim: (1, H, W)
28
29 # 1. Clamp HU values and map strictly to [0, 1]
30 volume = torch.clamp(volume, self.clip_min, self.clip_max)
31 range_val = self.clip_max - self.clip_min
32 volume = (volume - self.clip_min) / range_val
33
34 # 2. Z-score standardization
35 volume = (volume - self.norm_mean) / self.norm_std
36
37 # 3. Padding/Interpolation for strict patch size alignment
38 # HF DINOv2 expects dimensions to be multiples of the patch size (14)
39 C, H, W = volume.shape
40 target_h = int((H // self.patch_size) * self.patch_size)
41 target_w = int((W // self.patch_size) * self.patch_size)
42
43 if target_h != H or target_w != W:
44 volume = volume.unsqueeze(0) # (1, C, H, W)
45 # Use nearest interpolation to prevent averaging of exact HU values
46 volume = F.interpolate(volume, size=(target_h, target_w), mode='nearest')
47 volume = volume.squeeze(0)
48
49 # Returns (1, 1, H, W). For batched inference, stack these along dim=0.
50 return volume.unsqueeze(0)
51
52def load_finetuned_dinov2_ct(repo_id="Kentucky-Open-Science/Finetuned-DINOv2-Chest-CT"):
53 """
54 Downloads and initializes the ViT-Large backbone using Hugging Face transformers.
55 """
56 # The config.json in the HF repo handles architecture setup (1 in_chan, 518 native size)
57 model = AutoModel.from_pretrained(repo_id, trust_remote_code=True)
58 model.eval()
59
60 return model
61
62if __name__ == "__main__":
63 # Initialize the transform and the model
64 transform = CTInferenceTransform()
65 model = load_finetuned_dinov2_ct()
66
67 # Simulate a raw CT slice (Replace this with an actual NIfTI/DICOM load in Hounsfield Units)
68 raw_ct_slice = np.random.uniform(-1000, 1000, size=(512, 512))
69
70 # Process the image to ensure correct normalization
71 input_tensor = transform(raw_ct_slice)
72
73 # Extract embeddings
74 with torch.no_grad():
75 outputs = model(pixel_values=input_tensor)
76
77 # DINOv2 returns last_hidden_state, pooler_output, etc.
78 # last_hidden_state includes the [CLS] token, register tokens, and spatial patch tokens
79 hidden_states = outputs.last_hidden_state
80
81 # [CLS] token is the first token
82 cls_token = hidden_states[:, 0, :]
83
84 # Register tokens (4 tokens based on config)
85 register_tokens = hidden_states[:, 1:5, :]
86
87 # Dense patch tokens (for fine-grained tasks like Segmentation)
88 patch_tokens = hidden_states[:, 5:, :]
89
90 print(f"Input tensor shape: {input_tensor.shape}")
91 print(f"Full hidden states shape: {hidden_states.shape}")
92 print(f"CLS token shape: {cls_token.shape}")
93 print(f"Register tokens shape: {register_tokens.shape}")
94 print(f"Dense patch tokens shape: {patch_tokens.shape}")