Views
No views yet

sproto package (which contains MultiProtoModule) and specific versions of its dependencies. Version mismatches — especially in torchmetrics and pytorch-lightning — will cause AttributeError or import failures.1pip install torch>=1.12.1 \
2 transformers==4.40.0 \
3 torchmetrics==0.10.3 \
4 pytorch-lightning==1.9 \
5 huggingface-hub \
6 matplotlib| Package | Required version | Reason |
|---|---|---|
torch | >= 1.12.1 | Minimum version for nn.PairwiseDistance and torch.einsum patterns used in the prototype layer |
transformers | == 4.40.0 | Required to bypass a metadata parsing bug |
torchmetrics | == 0.10.3 | MultilabelAveragePrecision was added in 0.10; older versions raise AttributeError on load |
pytorch-lightning | == 1.9 | MultiProtoModule is a pl.LightningModule; the exact API (e.g. validation_epoch_end) changed in 2.x |
huggingface-hub | any | Required for fetching additional assets like thresholds and labels |
matplotlib | any | Used for visualizations |
sproto | bundled | The sproto/ package is included in this HF repo and downloaded automatically with trust_remote_code=True — no separate install needed |
1import torch
2import sys
3import json
4from huggingface_hub import snapshot_download, hf_hub_download
5from transformers import AutoTokenizer, AutoModel
6
7def main():
8 # 1. Download the repo and inject it into sys.path to resolve the internal 'sproto' package
9 repo_id = "DATEXIS/sproto"
10 repo_path = snapshot_download(repo_id)
11 if repo_path not in sys.path:
12 sys.path.insert(0, repo_path)
13
14 # 2. Load Tokenizer and Model
15 tokenizer = AutoTokenizer.from_pretrained(repo_id)
16 # use_safetensors=False is required to bypass a metadata parsing bug in transformers 4.40.0
17 model = AutoModel.from_pretrained(repo_id, trust_remote_code=True, use_safetensors=False)
18 model.eval()
19
20 # 3. Prepare Input Text
21 text = """CHIEF COMPLAINT: depression, chest pain and vomiting
22
23 PRESENT ILLNESS: The patient is a 53-year-old woman with a history of hypertension, diabetes, and depression. She developed severe anxiety and depression. She was having chest pains along with significant vomiting and diarrhea.
24 """
25
26 inputs = tokenizer(
27 text,
28 return_tensors="pt",
29 padding="max_length",
30 truncation=True,
31 max_length=512
32 )
33
34 # Sproto requires raw token strings for its clinical section masking logic
35 tokens = [tokenizer.convert_ids_to_tokens(ids) for ids in inputs["input_ids"]]
36
37 # 4. Forward Pass
38 with torch.no_grad():
39 outputs = model(
40 input_ids=inputs["input_ids"],
41 attention_mask=inputs["attention_mask"],
42 tokens=tokens
43 )
44
45 # Apply sigmoid to convert BCE loss logits to probabilities
46 probs = torch.sigmoid(outputs.logits)[0]
47
48 # 5. Fetch Labels and Thresholds dynamically from Hugging Face Hub
49 try:
50 labels_path = hf_hub_download(repo_id=repo_id, filename="labels.txt")
51 icd_mapping_path = hf_hub_download(repo_id=repo_id, filename="icd_10_mappings.json")
52 thresholds_path = hf_hub_download(repo_id=repo_id, filename="thresholds_per_label.json")
53
54 with open(labels_path, "r") as f:
55 labels = f.read().strip().split("\n")
56 with open(icd_mapping_path, "r") as f:
57 icd_mapping = json.load(f)
58 with open(thresholds_path, "r") as f:
59 threshold_mapping = json.load(f)
60 except Exception as e:
61 print(f"Warning: Could not load label mapping files from HF Hub: {e}")
62 labels, threshold_mapping = None, None
63
64 # 6. Evaluate and Print Results
65 print("\n--- Inference Results ---")
66 if labels and threshold_mapping:
67 threshold_tensor = torch.zeros(len(labels))
68 for idx, label in enumerate(labels):
69 val = threshold_mapping.get(label, 0.20)
70 threshold_tensor[idx] = val if val > 0.0 else 0.20 # Enforce valid > 0.0 threshold
71
72 predicted_indices = torch.where(probs > threshold_tensor)[0]
73 else:
74 predicted_indices = torch.where(probs > 0.20)[0]
75
76 if len(predicted_indices) == 0:
77 print("No diagnoses predicted above the threshold.")
78 else:
79 results = []
80 for idx in predicted_indices:
81 idx_val = idx.item()
82 prob = probs[idx_val].item()
83
84 if labels and idx_val < len(labels):
85 icd_code = labels[idx_val]
86 description = icd_mapping.get(icd_code, "Unknown Description")
87 results.append((icd_code, description, prob))
88
89 # Sort alphabetically by ICD-10 code
90 results.sort(key=lambda x: x[0])
91 for icd_code, description, prob in results:
92 print(f"- {icd_code} ({description}): {prob:.4f}")
93
94if __name__ == "__main__":
95 main()Note:tokens(the list of token strings per sample) is required whenuse_attention=True(which is the default). The attention mechanism uses the actual token strings to mask clinical section headers ([CLS],[SEP],"chief complaint :", etc.) before computing token-to-prototype attention. Omittingtokenswill raise aValueError. Obtain them withtokenizer.convert_ids_to_tokens(input_ids[i])as shown above.

thresholds_per_label.json file.0.0 in the JSON file (which typically happens for extremely rare diseases with no validation positives), you should manually fall back to a reasonable default (e.g., 0.20) during inference. If you strictly apply probability > 0.0, the neural network's sigmoid function will falsely trigger for every patient.1git clone https://github.com/DATEXIS/sproto.git
2cd sprotopoetry installpoetry env activate1train \
2 --batch_size 3 \
3 --pretrained_model microsoft/biomednlp-pubmedbert-base-uncased-abstract-fulltext \
4 --pretrained_model_path path_to_pretrained_model.ckpt \
5 --model_type MULTI_PROTO \
6 --train_file training_data.csv \
7 --val_file validation_data.csv \
8 --test_file test_data.csv \
9 --save_dir ../experiments/ \
10 --gpus 1 \
11 --check_val_every_n_epoch 2 \
12 --num_warmup_steps 0 \
13 --num_training_steps 50 \
14 --max_length 512 \
15 --lr_features 0.000005 \
16 --lr_prototypes 0.001 \
17 --lr_others 0.001 \
18 --num_val_samples None \
19 --use_attention True \
20 --reduce_hidden_size 256 \
21 --all_labels_path all_labels.pcl \
22 --seed 42 \
23 --label_column labels \
24 --metric_opt auroc_macro \
25 --train_files [] \
26 --val_files [] \
27 --only_test True \
28 --model_name 5p \
29 --store_metadata False \
30 --num_prototypes_per_class 51@inproceedings{figueroa2024sproto,
2 title={Boosting Long-Tail Data Classification with Sparse Prototypical Networks},
3 author={Figueroa, Alexei and Papaioannou, Jens-Michalis and Fallon, Conor and Bekiaridou, Alexandra and Bressem, Keno and Zanos, Stavros and Gers, Felix and Nejdl, Wolfgang and Löser, Alexander},
4 booktitle={Proceedings of the European Conference on Machine Learning and Principles and Practice of Knowledge Discovery in Databases (ECML PKDD)},
5 year={2024}
6}