Views
No views yet
embed_dim = 576), andpip install torch transformers timm einops numpy safetensors1import torch
2from transformers import AutoModel
3
4model = AutoModel.from_pretrained("raidium/Jolia", trust_remote_code=True).eval()
5
6# image: a preprocessed CT volume, shape (B, 11, 192, 192, 192) — see Preprocessing
7with torch.no_grad():
8 cls = model(image).pooler_output # (B, 576) global embedding(11, 192, 192, 192): 1.5 mm isotropic, 192³ crop, 11 CT windowing channels).
Grab the bundled preprocessor from the repo:1from huggingface_hub import snapshot_download
2import sys
3repo = snapshot_download("raidium/Jolia")
4sys.path.append(repo)
5from preprocessing_jolia import JoliaPreprocessor
6
7pre = JoliaPreprocessor()
8# volume: (H, W, D) in Hounsfield units; resolution in mm (row, col, slice)
9image = pre(volume, resolution=(0.7, 0.7, 1.0)).unsqueeze(0) # (1, 11, 192, 192, 192)1# All 102 organs as {name: (B, 576)}
2organs = model.encode_organs(image)
3
4# A subset, L2-normalized (cosine-ready)
5sub = model.encode_organs(image, organs=["liver", "spleen", "pancreas"], normalize=True)
6
7print(model.organ_slot_names) # the 102 available organ namesflat = model.extract_flat_feature(image) # (B, 576 * (1 + num_organs))Qwen/Qwen3-Embedding-8B)
to classify a CT against arbitrary text prompts with no fine-tuning.JoliaTextEncoder, that handles tokenization
and the (attention-mask-aware) last-token pooling the model was trained with.1import sys, torch
2from huggingface_hub import snapshot_download
3from transformers import AutoModel
4
5# 1) Vision: Jolia from the Hub (self-contained, ~89 MB).
6jolia = AutoModel.from_pretrained("raidium/Jolia", trust_remote_code=True).eval()
7
8# 2) Text: Qwen3-Embedding-8B + Jolia's bundled JoliaTextEncoder helper.
9repo = snapshot_download("raidium/Jolia"); sys.path.append(repo)
10from text_encoder_jolia import JoliaTextEncoder
11text_encoder = JoliaTextEncoder.from_pretrained(
12 "Qwen/Qwen3-Embedding-8B",
13 dtype=torch.bfloat16, # ~18 GB at fp32; bf16 halves it
14 device_map="auto", # or .to("cuda")
15).eval()
16
17# 3) Zero-shot classification on a preprocessed CT volume.
18prompts = ["a CT showing a liver lesion", "a CT showing pneumonia", "a normal abdominal CT"]
19with torch.no_grad():
20 text_features = text_encoder(prompts) # (N, 4096) last-token-pooled
21 logits = jolia.zero_shot(image, text_features) # (B, N) — calibrated CLIP logits
22 probs = torch.sigmoid(logits) # per-pair "is this a match?" probability
23
24# Same output as `MultimodalCLSZeroShotCLIP.get_logits_per_image` in rarm.
25# Pass `calibrated=False` if you want raw cosine in [-1, 1] (ranking-only):
26cosine = jolia.zero_shot(image, text_features, calibrated=False)1text_features = text_encoder(["a lesion", "looks normal"]) # (N, 4096)
2
3# Score N prompts against a single organ — calibrated CLIP logits (B, N)
4liver_logits = jolia.zero_shot_organ(image, text_features, organ="liver")
5liver_probs = torch.sigmoid(liver_logits)
6
7# Score N prompts against many organs at once -> {organ_name: (B, N)}
8scores = jolia.zero_shot_organs(
9 image, text_features, organs=["liver", "spleen", "kidneys", "pancreas"]
10)
11
12# Raw cosine if you only need ranking and don't want the bias offset:
13cosine = jolia.zero_shot_organ(image, text_features, organ="liver", calibrated=False)(200,)-shaped organ_logit_scale / organ_text_bias), automatically applied
when calibrated=True. jolia.organ_slot_names lists the 102 organs that can
be routed. The per-organ head uses a different text projection than the
global one (encode_text vs encode_organ_text), trained on per-organ
findings text.example_zero_shot.py.| Backbone | MultiModalAtlas — multi-scale 3D ViT, dim=192, heads 6, stages [2, 2, 8] |
| Patch embed | 6×6×6, 11 input channels (CT windowing), merge_ratio = 4³ |
| Global embedding | 576-d |
| Organ queries | 102 slots × 192-d × 3 scales → 576-d |
| Parameters | ~22 M (89 MB safetensors) |
| Input | (B, 11, 192, 192, 192) float32 |
| Training data | INSPECT, CT-RATE, Stanford-Abdominal-CT (chest + abdomen CT) |
| Objectives | Volume–report CLIP + per-organ ParallelOrganCLIP |
| Paired text encoder | Qwen/Qwen3-Embedding-8B (last-token pooling, context length 512) |
| Global text projection | Linear 4096 → 576 (+ scalar temperature + bias) — global CLIP head |
| Per-organ text projection | Linear 4096 → 576 (+ per-organ temperature + bias, both (200,)) — ParallelOrganCLIP head |
102–199 are unused
padding. Methods like encode_organs expose only the named slots.model(image) returns a JoliaOutput with:pooler_output — (B, 576) global embedding,organ_queries — (B, num_organs, 576), populated when called with
output_organ_queries=True.⚠️ Research preview. Not a medical device; not for clinical use.
1@misc{raidium_jolia,
2 title = {Jolia: a 3D CT Atlas foundation model with per-organ queries},
3 author = {Raidium},
4 year = {2026},
5 howpublished = {\url{https://huggingface.co/raidium/Jolia}}
6}