Model, loss, thresholds, metrics
Numbers are from DAM 1 (research/stable/ordinal_regression_mtl_mar_2024/, config.yaml).
DAM 2/3 reuse the same head, loss and metrics (Experiments).
Architecture (DAM 1)
flowchart TB
A["raw audio<br/>[ΣW, ≤480000]"] -->|"pad to 480,000"| B["log-mel on GPU<br/>[ΣW, 80, 3000]"]
B --> C["Whisper small.en encoder<br/>LoRA r=32 α=64, conv1/conv2 full<br/>[ΣW, 1500, 768]"]
C -->|"mean over time"| D["[ΣW, 768]"]
D --> E["Shared: Linear 768→256 + Mish<br/>Linear 256→64 (no act.)"]
E --> F1["depression head<br/>64→128 Mish Dropout 0.4 →1 (no bias)"]
E --> F2["anxiety head<br/>64→128 Mish Dropout 0.4 →1 (no bias)"]
F1 --> G["score per window<br/>[ΣW, 1] per task"]
F2 --> G
G -->|"mean per recording (length)"| H["[B] per task"]
| Part |
Setting |
Where |
| Log-mel |
80 bins, n_fft 400, hop 160, per-window z-norm, log10 clip max−8, (x+4)/4, then per-bin shift to IDEAL_LOGMEL_ENERGIES |
WhisperTorchFeatureExtractor |
| Encoder |
openai/whisper-small.en, decoder dropped, 1500 positions, dropouts 0 |
WhisperBackbone |
| LoRA |
r 32, α 64, dropout 0.4, all-linear, bias all; conv1, conv2 trained fully |
KintsugiBackboneBase.apply_lora |
| Shared layers |
[256, 64]; last layer is the shared factor B in Wt = Ht·B |
MultitaskHead.SharedLayers |
| Task head |
proj 128, dropout 0.4, final Linear without bias (CORAL holds the biases) |
MultitaskHead.TaskHead |
| Optimizer |
AdamW: backbone lr 1.6e-4, head + CORAL biases lr 8e-4, wd 1e-3; MultiStepLR γ 0.5 at epochs 20, 26 |
DepAnxClassifier.configure_optimizers |
| Precision |
fp16 on GPU, DDP find_unused_parameters=True |
launcher |
3 · Model (DAM 1)
Raw audio windows become log-mel images on the GPU, the Whisper encoder (with LoRA) turns each window into a 768-d vector, and a shared layer feeds one small head per task that outputs a single score.
Main path: steps 25–31 of a train run (walkthrough). Gold boxes open the step; grey boxes are side paths and open the code.
flowchart LR
subgraph research_stable_ordinal_regression_mtl_mar_2024_model_py___box["mtl_mar_2024/model.py"]
direction TB
research_stable_ordinal_regression_mtl_mar_2024_model_py__DepAnxClassifier["<b>DepAnxClassifier()</b><br/>DAM 1: log-mel -› Whisper small.en<br/>encoder (LoRA) -› mean pool -›<br/>multitask CORAL head."]
class research_stable_ordinal_regression_mtl_mar_2024_model_py__DepAnxClassifier opt
click research_stable_ordinal_regression_mtl_mar_2024_model_py__DepAnxClassifier "https://github.com/Pipotheavenger/kintsugi-rad-docs/blob/main/research/stable/ordinal_regression_mtl_mar_2024/model.py#L25" _blank
research_stable_ordinal_regression_mtl_mar_2024_model_py__DepAnxClassifier_forward["<b>27 · DepAnxClassifier.forward()</b><br/>Backbone then MultitaskHead -›<br/>({task: [ΣW, 1] scores}, lengths)."]
class research_stable_ordinal_regression_mtl_mar_2024_model_py__DepAnxClassifier_forward main
click research_stable_ordinal_regression_mtl_mar_2024_model_py__DepAnxClassifier_forward "../walkthrough/#step-27"
research_stable_ordinal_regression_mtl_mar_2024_model_py__DepAnxClassifier_forward_backbone["<b>28 · DepAnxClassifier.forward_backbone()</b><br/>Pad raw audio to 480,000 samples,<br/>log-mel on GPU, Whisper encoder -›<br/>[ΣW, 768]."]
class research_stable_ordinal_regression_mtl_mar_2024_model_py__DepAnxClassifier_forward_backbone main
click research_stable_ordinal_regression_mtl_mar_2024_model_py__DepAnxClassifier_forward_backbone "../walkthrough/#step-28"
research_stable_ordinal_regression_mtl_mar_2024_model_py__DepAnxClassifier_configure_optimizers["<b>DepAnxClassifier.configure_optimizers()</b><br/>AdamW with two groups (backbone,<br/>head + CORAL biases) and<br/>MultiStepLR."]
class research_stable_ordinal_regression_mtl_mar_2024_model_py__DepAnxClassifier_configure_optimizers opt
click research_stable_ordinal_regression_mtl_mar_2024_model_py__DepAnxClassifier_configure_optimizers "https://github.com/Pipotheavenger/kintsugi-rad-docs/blob/main/research/stable/ordinal_regression_mtl_mar_2024/model.py#L109" _blank
end
subgraph kirad_feature_extraction_whisper_py___box["feature_extraction_whisper.py"]
direction TB
kirad_feature_extraction_whisper_py__WhisperTorchFeatureExtractor_forward["<b>29 · WhisperTorchFeatureExtractor.forward()</b><br/>Normalize each window, compute<br/>log-mel, shift bins to<br/>IDEAL_LOGMEL_ENERGIES."]
class kirad_feature_extraction_whisper_py__WhisperTorchFeatureExtractor_forward main
click kirad_feature_extraction_whisper_py__WhisperTorchFeatureExtractor_forward "../walkthrough/#step-29"
kirad_feature_extraction_whisper_py__WhisperTorchFeatureExtractor__torch_extract_fbank_features["<b>WhisperTorchFeatureExtractor._torch_extract_fbank_features()</b><br/>Log10 mel spectrogram, clipped to<br/>8 below the max, scaled (x + 4) /<br/>4 as Whisper."]
class kirad_feature_extraction_whisper_py__WhisperTorchFeatureExtractor__torch_extract_fbank_features opt
click kirad_feature_extraction_whisper_py__WhisperTorchFeatureExtractor__torch_extract_fbank_features "https://github.com/Pipotheavenger/kintsugi-rad-docs/blob/main/kirad/feature_extraction_whisper.py#L97" _blank
end
subgraph kirad_base_models_py___box["base_models.py"]
direction TB
kirad_base_models_py__WhisperBackbone_forward["<b>30 · WhisperBackbone.forward()</b><br/>Whisper encoder on log-mel<br/>windows, mean over time -› [ΣW, D]<br/>(768 for small.en)."]
class kirad_base_models_py__WhisperBackbone_forward main
click kirad_base_models_py__WhisperBackbone_forward "../walkthrough/#step-30"
kirad_base_models_py__KintsugiBackboneBase_apply_lora["<b>KintsugiBackboneBase.apply_lora()</b><br/>Wrap self.backbone with PEFT LoRA<br/>from lora_params; no-op (full<br/>fine-tune) if empty."]
class kirad_base_models_py__KintsugiBackboneBase_apply_lora opt
click kirad_base_models_py__KintsugiBackboneBase_apply_lora "https://github.com/Pipotheavenger/kintsugi-rad-docs/blob/main/kirad/base_models.py#L818" _blank
kirad_base_models_py__MultitaskHead_forward["<b>31 · MultitaskHead.forward()</b><br/>Shared layers, then one TaskHead<br/>per task -› {task: [ΣW, 1] score}."]
class kirad_base_models_py__MultitaskHead_forward main
click kirad_base_models_py__MultitaskHead_forward "../walkthrough/#step-31"
kirad_base_models_py__MultitaskHead_SharedLayers["<b>MultitaskHead.SharedLayers()</b><br/>Shared MLP: Linear+Mish per<br/>proj_dim, last Linear without<br/>activation (e.g. D-›256-›64)."]
class kirad_base_models_py__MultitaskHead_SharedLayers opt
click kirad_base_models_py__MultitaskHead_SharedLayers "https://github.com/Pipotheavenger/kintsugi-rad-docs/blob/main/kirad/base_models.py#L1002" _blank
kirad_base_models_py__MultitaskHead_TaskHead["<b>MultitaskHead.TaskHead()</b><br/>Per-task head: Linear(in,<br/>proj_dim) -› Mish -› Dropout -›<br/>Linear(proj_dim, 1, no bias)."]
class kirad_base_models_py__MultitaskHead_TaskHead opt
click kirad_base_models_py__MultitaskHead_TaskHead "https://github.com/Pipotheavenger/kintsugi-rad-docs/blob/main/kirad/base_models.py#L1034" _blank
kirad_base_models_py__MultiTaskOrdinalRegressionPLModule_training_step["<b>25 · MultiTaskOrdinalRegressionPLModule.training_step()</b><br/>Lightning train step: returns the<br/>step dict with total_loss."]
class kirad_base_models_py__MultiTaskOrdinalRegressionPLModule_training_step main
click kirad_base_models_py__MultiTaskOrdinalRegressionPLModule_training_step "../walkthrough/#step-25"
kirad_base_models_py__MultiTaskOrdinalRegressionPLModule_step["<b>26 · MultiTaskOrdinalRegressionPLModule.step()</b><br/>Run model once, sum each task's<br/>loss (task.step) into total_loss."]
class kirad_base_models_py__MultiTaskOrdinalRegressionPLModule_step main
click kirad_base_models_py__MultiTaskOrdinalRegressionPLModule_step "../walkthrough/#step-26"
end
from_prev(["◀ from step 24: broadcast_collate()"])
class from_prev edge
from_prev ==> kirad_base_models_py__MultiTaskOrdinalRegressionPLModule_training_step
click from_prev "#stage-data"
kirad_base_models_py__MultiTaskOrdinalRegressionPLModule_training_step ==> kirad_base_models_py__MultiTaskOrdinalRegressionPLModule_step
kirad_base_models_py__MultiTaskOrdinalRegressionPLModule_step ==> research_stable_ordinal_regression_mtl_mar_2024_model_py__DepAnxClassifier_forward
research_stable_ordinal_regression_mtl_mar_2024_model_py__DepAnxClassifier_forward ==> research_stable_ordinal_regression_mtl_mar_2024_model_py__DepAnxClassifier_forward_backbone
research_stable_ordinal_regression_mtl_mar_2024_model_py__DepAnxClassifier_forward_backbone ==> kirad_feature_extraction_whisper_py__WhisperTorchFeatureExtractor_forward
kirad_feature_extraction_whisper_py__WhisperTorchFeatureExtractor_forward ==> kirad_base_models_py__WhisperBackbone_forward
kirad_base_models_py__WhisperBackbone_forward ==> kirad_base_models_py__MultitaskHead_forward
to_next(["▶ next, step 32: OrdinalRegressionPLModule.step()"])
class to_next edge
kirad_base_models_py__MultitaskHead_forward ==> to_next
click to_next "#stage-loss"
kirad_feature_extraction_whisper_py__WhisperTorchFeatureExtractor_forward -.-> kirad_feature_extraction_whisper_py__WhisperTorchFeatureExtractor__torch_extract_fbank_features
research_stable_ordinal_regression_mtl_mar_2024_model_py__DepAnxClassifier_forward_backbone -.->|"log-mel"| kirad_base_models_py__WhisperBackbone_forward
research_stable_ordinal_regression_mtl_mar_2024_model_py__DepAnxClassifier_forward -.->|"768-d"| kirad_base_models_py__MultitaskHead_forward
kirad_base_models_py__MultitaskHead_forward -.-> kirad_base_models_py__MultitaskHead_SharedLayers
kirad_base_models_py__MultitaskHead_SharedLayers -.->|"64-d"| kirad_base_models_py__MultitaskHead_TaskHead
classDef main fill:#FFF4DC,stroke:#A67C1B,stroke-width:2px,color:#1A1A1A
classDef opt fill:#F3F4F6,stroke:#B8BEC7,color:#555,stroke-dasharray:4 3
classDef edge fill:#FFFFFF,stroke:#1F7A5C,color:#1F7A5C,stroke-width:1.5px
| Step |
Function |
File |
What it does |
| — |
DepAnxClassifier |
research/stable/ordinal_regression_mtl_mar_2024/model.py:25 |
DAM 1: log-mel -> Whisper small.en encoder (LoRA) -> mean pool -> multitask CORAL head. |
| 27 |
DepAnxClassifier.forward |
research/stable/ordinal_regression_mtl_mar_2024/model.py:84 |
Backbone then MultitaskHead -> ({task: [ΣW, 1] scores}, lengths). |
| 28 |
DepAnxClassifier.forward_backbone |
research/stable/ordinal_regression_mtl_mar_2024/model.py:89 |
Pad raw audio to 480,000 samples, log-mel on GPU, Whisper encoder -> [ΣW, 768]. |
| — |
DepAnxClassifier.configure_optimizers |
research/stable/ordinal_regression_mtl_mar_2024/model.py:109 |
AdamW with two groups (backbone, head + CORAL biases) and MultiStepLR. |
| 29 |
WhisperTorchFeatureExtractor.forward |
kirad/feature_extraction_whisper.py:138 |
Normalize each window, compute log-mel, shift bins to IDEAL_LOGMEL_ENERGIES. |
| — |
WhisperTorchFeatureExtractor._torch_extract_fbank_features |
kirad/feature_extraction_whisper.py:97 |
Log10 mel spectrogram, clipped to 8 below the max, scaled (x + 4) / 4 as Whisper. |
| 30 |
WhisperBackbone.forward |
kirad/base_models.py:877 |
Whisper encoder on log-mel windows, mean over time -> [ΣW, D] (768 for small.en). |
| — |
KintsugiBackboneBase.apply_lora |
kirad/base_models.py:818 |
Wrap self.backbone with PEFT LoRA from lora_params; no-op (full fine-tune) if empty. |
| 31 |
MultitaskHead.forward |
kirad/base_models.py:1075 |
Shared layers, then one TaskHead per task -> {task: [ΣW, 1] score}. |
| — |
MultitaskHead.SharedLayers |
kirad/base_models.py:1002 |
Shared MLP: Linear+Mish per proj_dim, last Linear without activation (e.g. D->256->64). |
| — |
MultitaskHead.TaskHead |
kirad/base_models.py:1034 |
Per-task head: Linear(in, proj_dim) -> Mish -> Dropout -> Linear(proj_dim, 1, no bias). |
| 25 |
MultiTaskOrdinalRegressionPLModule.training_step |
kirad/base_models.py:722 |
Lightning train step: returns the step dict with total_loss. |
| 26 |
MultiTaskOrdinalRegressionPLModule.step |
kirad/base_models.py:734 |
Run model once, sum each task's loss (task.step) into total_loss. |
CORAL loss
One score s per window and task; K = 27 (PHQ-9, num_classes 28) or 21 (GAD-7, 22) learned
biases bk. Logits s + bk; target is the thermometer code [y > k]
(torch.gt(y, arange(K))); BCE summed over cutoffs, each weighted 0/1 by
ordinal_loss_target_type (exact28 / exact22 = all ones).
| Term |
Weight (config key, default) |
DAM 1 current |
| CORAL |
coral_loss_weight, 1.0 |
1.0 |
| Variance of window scores within a recording |
score_variance_loss_weight, 0.0 |
40.0 |
| MSE to teacher score (KD) |
kd_loss_weight, 0.0; needs score_targets_csv |
0 |
Train: per-window loss, averaged within each recording, then over recordings. Val/test: loss of the per-recording mean score
(mean_before_loss). Total loss = sum over tasks.
4 · Loss
Each task turns its score into 27 (or 21) ordered yes/no questions with CORAL. Train: CORAL loss per window, averaged per recording; val/test: loss of the per-recording mean score. A variance penalty makes windows of the same recording agree.
Main path: steps 32–35 of a train run (walkthrough). Gold boxes open the step; grey boxes are side paths and open the code.
flowchart LR
subgraph kirad_base_models_py___box["base_models.py"]
direction TB
kirad_base_models_py__MultiTaskOrdinalRegressionPLModule_step["<b>MultiTaskOrdinalRegressionPLModule.step()</b><br/>Run model once, sum each task's<br/>loss (task.step) into total_loss."]
class kirad_base_models_py__MultiTaskOrdinalRegressionPLModule_step opt
click kirad_base_models_py__MultiTaskOrdinalRegressionPLModule_step "https://github.com/Pipotheavenger/kintsugi-rad-docs/blob/main/kirad/base_models.py#L734" _blank
kirad_base_models_py__OrdinalRegressionPLModule_step["<b>32 · OrdinalRegressionPLModule.step()</b><br/>Accumulate per-recording mean/var<br/>scores for val/test, then return<br/>the loss."]
class kirad_base_models_py__OrdinalRegressionPLModule_step main
click kirad_base_models_py__OrdinalRegressionPLModule_step "../walkthrough/#step-32"
kirad_base_models_py__OrdinalRegressionPLModule_compute_and_log_loss["<b>33 · OrdinalRegressionPLModule.compute_and_log_loss()</b><br/>Loss = coral_w·CORAL +<br/>var_w·Var(window scores) +<br/>kd_w·MSE(teacher), logged."]
class kirad_base_models_py__OrdinalRegressionPLModule_compute_and_log_loss main
click kirad_base_models_py__OrdinalRegressionPLModule_compute_and_log_loss "../walkthrough/#step-33"
end
subgraph kirad_losses_py___box["losses.py"]
direction TB
kirad_losses_py__CORALLoss_forward["<b>35 · CORALLoss.forward()</b><br/>Weighted sum of BCE over cutoffs:<br/>sigmoid(s + b_k) vs [y › k] for<br/>each cutoff k."]
class kirad_losses_py__CORALLoss_forward main
click kirad_losses_py__CORALLoss_forward "../walkthrough/#step-35"
end
subgraph kirad_utils_py___box["utils.py"]
direction TB
kirad_utils_py__average_and_variance_tensor_in_segments["<b>34 · average_and_variance_tensor_in_segments()</b><br/>Per-recording mean and (biased)<br/>variance of window scores: [ΣW,<br/>...] -› two [B, ...]."]
class kirad_utils_py__average_and_variance_tensor_in_segments main
click kirad_utils_py__average_and_variance_tensor_in_segments "../walkthrough/#step-34"
kirad_utils_py__average_tensor_in_segments["<b>average_tensor_in_segments()</b><br/>Mean over each recording's<br/>windows: [ΣW, ...] -› [B, ...]<br/>using `length`."]
class kirad_utils_py__average_tensor_in_segments opt
click kirad_utils_py__average_tensor_in_segments "https://github.com/Pipotheavenger/kintsugi-rad-docs/blob/main/kirad/utils.py#L90" _blank
end
from_prev(["◀ from step 31: MultitaskHead.forward()"])
class from_prev edge
from_prev ==> kirad_base_models_py__OrdinalRegressionPLModule_step
click from_prev "#stage-model"
kirad_base_models_py__OrdinalRegressionPLModule_step ==> kirad_base_models_py__OrdinalRegressionPLModule_compute_and_log_loss
kirad_base_models_py__OrdinalRegressionPLModule_compute_and_log_loss ==> kirad_utils_py__average_and_variance_tensor_in_segments
kirad_utils_py__average_and_variance_tensor_in_segments ==> kirad_losses_py__CORALLoss_forward
to_next(["▶ next, step 36: MultiTaskOrdinalRegressionPLModule.on_validation_test_epoch_end()"])
class to_next edge
kirad_losses_py__CORALLoss_forward ==> to_next
click to_next "#stage-metrics"
kirad_base_models_py__MultiTaskOrdinalRegressionPLModule_step -.->|"per task"| kirad_base_models_py__OrdinalRegressionPLModule_step
kirad_utils_py__average_and_variance_tensor_in_segments -.-> kirad_utils_py__average_tensor_in_segments
kirad_base_models_py__OrdinalRegressionPLModule_compute_and_log_loss -.-> kirad_losses_py__CORALLoss_forward
classDef main fill:#FFF4DC,stroke:#A67C1B,stroke-width:2px,color:#1A1A1A
classDef opt fill:#F3F4F6,stroke:#B8BEC7,color:#555,stroke-dasharray:4 3
classDef edge fill:#FFFFFF,stroke:#1F7A5C,color:#1F7A5C,stroke-width:1.5px
Thresholds
Tuned after every validation on the per-recording scores, stored as buffers in the checkpoint,
reused unchanged on test.
| Method |
Optimizes |
Algorithm |
accuracy, absolute_error, macro_recall |
per-sample cost |
DP, O(n) |
macro_precision, macro_f1 |
per-class cost |
DP over cost matrix, O(t²) |
coral |
none |
−bk at the metric cutoffs (learned in training) |
Candidates: midpoints between unique validation scores, plus ±∞. Classes come from
METRIC_TARGET_CUTOFFS: depression (9, 14) → 3 classes, anxiety (4, 9, 14) → 4 classes; a label
counts the cutoffs it exceeds (strict >). Report cards default to macro_f1.
Metrics
For each binary cut (e.g. PHQ > 9, PHQ > 14), IndetSnSpArray evaluates every (lower, upper)
threshold pair; scores in between are indeterminate. At budgets of 0 % and 40 %
indeterminate, it reports AUROC and the best min(Sn, Sp) (sn_eq_sp). Cuts are averaged per
task, tasks are combined by harmonic mean.
| Metric |
Use |
metrics/val/sn_eq_sp@0%i |
selects the checkpoint and drives early stopping (patience 10 validations) |
metrics/val/auroc@0%i, @40%i |
reported |
metrics/test/sn_at_val_eq_thresh@…, sp_…, indet_frac_… |
test at thresholds chosen on val |
A validation runs every training_examples_per_eval recordings (16,000 in DAM 1), else once per epoch.
5 · Thresholds and metrics
After every validation, scores of all recordings are gathered, five threshold sets are tuned by dynamic programming, a sixth is read from the CORAL biases, and Sn/Sp with an indeterminate band are computed. Test reuses the validation thresholds.
Main path: steps 36–41 of a train run (walkthrough). Gold boxes open the step; grey boxes are side paths and open the code.
flowchart LR
subgraph kirad_base_models_py___box["base_models.py"]
direction TB
kirad_base_models_py__MultiTaskOrdinalRegressionPLModule_on_validation_test_epoch_end["<b>36 · MultiTaskOrdinalRegressionPLModule.on_validation_test_epoch_end()</b><br/>Run each task's epoch end, then<br/>log harmonic mean of shared<br/>metrics across tasks."]
class kirad_base_models_py__MultiTaskOrdinalRegressionPLModule_on_validation_test_epoch_end main
click kirad_base_models_py__MultiTaskOrdinalRegressionPLModule_on_validation_test_epoch_end "../walkthrough/#step-36"
kirad_base_models_py__OrdinalRegressionPLModule_on_validation_test_epoch_end["<b>37 · OrdinalRegressionPLModule.on_validation_test_epoch_end()</b><br/>Gather scores, log W&B table, tune<br/>thresholds on val, compute Sn/Sp<br/>metrics."]
class kirad_base_models_py__OrdinalRegressionPLModule_on_validation_test_epoch_end main
click kirad_base_models_py__OrdinalRegressionPLModule_on_validation_test_epoch_end "../walkthrough/#step-37"
kirad_base_models_py__OrdinalRegressionPLModule_quantize_labels["<b>38 · OrdinalRegressionPLModule.quantize_labels()</b><br/>Map input labels (e.g. PHQ-9 sum)<br/>to output labels (e.g. 0/1/2 for<br/>L/M/H)."]
class kirad_base_models_py__OrdinalRegressionPLModule_quantize_labels main
click kirad_base_models_py__OrdinalRegressionPLModule_quantize_labels "../walkthrough/#step-38"
kirad_base_models_py__OrdinalRegressionPLModule_log_ordinal_metrics["<b>41 · OrdinalRegressionPLModule.log_ordinal_metrics()</b><br/>Log AUROC and min(Sn, Sp) per<br/>binary cut and indet budget, plus<br/>their mean."]
class kirad_base_models_py__OrdinalRegressionPLModule_log_ordinal_metrics main
click kirad_base_models_py__OrdinalRegressionPLModule_log_ordinal_metrics "../walkthrough/#step-41"
kirad_base_models_py__OrdinalRegressionPLModule_log_thresholding_metrics["<b>OrdinalRegressionPLModule.log_thresholding_metrics()</b><br/>Log each tuned method's cost when<br/>scored with every method's<br/>thresholds."]
class kirad_base_models_py__OrdinalRegressionPLModule_log_thresholding_metrics opt
click kirad_base_models_py__OrdinalRegressionPLModule_log_thresholding_metrics "https://github.com/Pipotheavenger/kintsugi-rad-docs/blob/main/kirad/base_models.py#L315" _blank
end
subgraph kirad_ordinal_thresholding_py___box["ordinal_thresholding.py"]
direction TB
kirad_ordinal_thresholding_py__OptimalOrdinalThresholdingViaDynamicProgramming_tune_thresholds["<b>40 · OptimalOrdinalThresholdingViaDynamicProgramming.tune_thresholds()</b><br/>Set thresholds by DP over<br/>midpoints of unique scores<br/>(+/-inf); return the best metric."]
class kirad_ordinal_thresholding_py__OptimalOrdinalThresholdingViaDynamicProgramming_tune_thresholds main
click kirad_ordinal_thresholding_py__OptimalOrdinalThresholdingViaDynamicProgramming_tune_thresholds "../walkthrough/#step-40"
kirad_ordinal_thresholding_py__OptimalCostPerSampleOrdinalThresholding_dp_step["<b>OptimalCostPerSampleOrdinalThresholding.dp_step()</b><br/>O(n) DP step: histogram per-sample<br/>costs over candidates, cumsum,<br/>running max."]
class kirad_ordinal_thresholding_py__OptimalCostPerSampleOrdinalThresholding_dp_step opt
click kirad_ordinal_thresholding_py__OptimalCostPerSampleOrdinalThresholding_dp_step "https://github.com/Pipotheavenger/kintsugi-rad-docs/blob/main/kirad/ordinal_thresholding.py#L291" _blank
kirad_ordinal_thresholding_py__OptimalCostPerClassOrdinalThresholding_dp_step["<b>OptimalCostPerClassOrdinalThresholding.dp_step()</b><br/>O(T^2) DP step: add prev_cost to<br/>each lower-threshold row and max<br/>over it."]
class kirad_ordinal_thresholding_py__OptimalCostPerClassOrdinalThresholding_dp_step opt
click kirad_ordinal_thresholding_py__OptimalCostPerClassOrdinalThresholding_dp_step "https://github.com/Pipotheavenger/kintsugi-rad-docs/blob/main/kirad/ordinal_thresholding.py#L450" _blank
kirad_ordinal_thresholding_py__CORALThresholding_tune_thresholds["<b>CORALThresholding.tune_thresholds()</b><br/>Copy -biases[threshold_indices]<br/>from the CORAL loss; scores and<br/>labels are ignored."]
class kirad_ordinal_thresholding_py__CORALThresholding_tune_thresholds opt
click kirad_ordinal_thresholding_py__CORALThresholding_tune_thresholds "https://github.com/Pipotheavenger/kintsugi-rad-docs/blob/main/kirad/ordinal_thresholding.py#L85" _blank
end
subgraph kirad_metrics_py___box["metrics.py"]
direction TB
kirad_metrics_py__MultiCatMetric["<b>MultiCatMetric()</b><br/>Accumulate parallel tensors over<br/>batches and ranks (uuids, scores,<br/>variances, labels)."]
class kirad_metrics_py__MultiCatMetric opt
click kirad_metrics_py__MultiCatMetric "https://github.com/Pipotheavenger/kintsugi-rad-docs/blob/main/kirad/metrics.py#L41" _blank
kirad_metrics_py__IndetSnSpArray_build["<b>39 · IndetSnSpArray.build()</b><br/>Sn/Sp/indet_frac for all threshold<br/>pairs (or the given ones) via<br/>histogram cumsums."]
class kirad_metrics_py__IndetSnSpArray_build main
click kirad_metrics_py__IndetSnSpArray_build "../walkthrough/#step-39"
kirad_metrics_py__IndetSnSpArray_roc_curve["<b>IndetSnSpArray.roc_curve()</b><br/>Pareto ROC curve of (Sn, Sp) using<br/>only pairs with indet_frac ‹=<br/>indet_budget."]
class kirad_metrics_py__IndetSnSpArray_roc_curve opt
click kirad_metrics_py__IndetSnSpArray_roc_curve "https://github.com/Pipotheavenger/kintsugi-rad-docs/blob/main/kirad/metrics.py#L291" _blank
kirad_metrics_py__IndetSnSpArray_sn_eq_sp_graph["<b>IndetSnSpArray.sn_eq_sp_graph()</b><br/>Best min(Sn, Sp) per indeterminate<br/>fraction; these thresholds are<br/>saved in the ckpt."]
class kirad_metrics_py__IndetSnSpArray_sn_eq_sp_graph opt
click kirad_metrics_py__IndetSnSpArray_sn_eq_sp_graph "https://github.com/Pipotheavenger/kintsugi-rad-docs/blob/main/kirad/metrics.py#L305" _blank
end
from_prev(["◀ from step 35: CORALLoss.forward()"])
class from_prev edge
from_prev ==> kirad_base_models_py__MultiTaskOrdinalRegressionPLModule_on_validation_test_epoch_end
click from_prev "#stage-loss"
kirad_base_models_py__MultiTaskOrdinalRegressionPLModule_on_validation_test_epoch_end ==> kirad_base_models_py__OrdinalRegressionPLModule_on_validation_test_epoch_end
kirad_base_models_py__OrdinalRegressionPLModule_on_validation_test_epoch_end ==> kirad_base_models_py__OrdinalRegressionPLModule_quantize_labels
kirad_base_models_py__OrdinalRegressionPLModule_quantize_labels ==> kirad_metrics_py__IndetSnSpArray_build
kirad_metrics_py__IndetSnSpArray_build ==> kirad_ordinal_thresholding_py__OptimalOrdinalThresholdingViaDynamicProgramming_tune_thresholds
kirad_ordinal_thresholding_py__OptimalOrdinalThresholdingViaDynamicProgramming_tune_thresholds ==> kirad_base_models_py__OrdinalRegressionPLModule_log_ordinal_metrics
to_next(["▶ next, step 42: DistributedModelCheckpoint.on_validation_end()"])
class to_next edge
kirad_base_models_py__OrdinalRegressionPLModule_log_ordinal_metrics ==> to_next
click to_next "#stage-outputs"
kirad_metrics_py__MultiCatMetric -.->|"gathered scores"| kirad_base_models_py__OrdinalRegressionPLModule_on_validation_test_epoch_end
kirad_base_models_py__OrdinalRegressionPLModule_on_validation_test_epoch_end -.->|"val only"| kirad_ordinal_thresholding_py__OptimalOrdinalThresholdingViaDynamicProgramming_tune_thresholds
kirad_ordinal_thresholding_py__OptimalOrdinalThresholdingViaDynamicProgramming_tune_thresholds -.-> kirad_ordinal_thresholding_py__OptimalCostPerSampleOrdinalThresholding_dp_step
kirad_ordinal_thresholding_py__OptimalOrdinalThresholdingViaDynamicProgramming_tune_thresholds -.-> kirad_ordinal_thresholding_py__OptimalCostPerClassOrdinalThresholding_dp_step
kirad_base_models_py__OrdinalRegressionPLModule_on_validation_test_epoch_end -.-> kirad_ordinal_thresholding_py__CORALThresholding_tune_thresholds
kirad_base_models_py__OrdinalRegressionPLModule_on_validation_test_epoch_end -.-> kirad_metrics_py__IndetSnSpArray_build
kirad_base_models_py__OrdinalRegressionPLModule_on_validation_test_epoch_end -.->|"Sn=Sp ops (val)"| kirad_metrics_py__IndetSnSpArray_sn_eq_sp_graph
kirad_base_models_py__OrdinalRegressionPLModule_on_validation_test_epoch_end -.-> kirad_base_models_py__OrdinalRegressionPLModule_log_ordinal_metrics
kirad_base_models_py__OrdinalRegressionPLModule_log_ordinal_metrics -.-> kirad_metrics_py__IndetSnSpArray_roc_curve
kirad_base_models_py__OrdinalRegressionPLModule_on_validation_test_epoch_end -.-> kirad_base_models_py__OrdinalRegressionPLModule_log_thresholding_metrics
classDef main fill:#FFF4DC,stroke:#A67C1B,stroke-width:2px,color:#1A1A1A
classDef opt fill:#F3F4F6,stroke:#B8BEC7,color:#555,stroke-dasharray:4 3
classDef edge fill:#FFFFFF,stroke:#1F7A5C,color:#1F7A5C,stroke-width:1.5px
| Step |
Function |
File |
What it does |
| 36 |
MultiTaskOrdinalRegressionPLModule.on_validation_test_epoch_end |
kirad/base_models.py:680 |
Run each task's epoch end, then log harmonic mean of shared metrics across tasks. |
| 37 |
OrdinalRegressionPLModule.on_validation_test_epoch_end |
kirad/base_models.py:423 |
Gather scores, log W&B table, tune thresholds on val, compute Sn/Sp metrics. |
| 38 |
OrdinalRegressionPLModule.quantize_labels |
kirad/base_models.py:222 |
Map input labels (e.g. PHQ-9 sum) to output labels (e.g. 0/1/2 for L/M/H). |
| 41 |
OrdinalRegressionPLModule.log_ordinal_metrics |
kirad/base_models.py:228 |
Log AUROC and min(Sn, Sp) per binary cut and indet budget, plus their mean. |
| — |
OrdinalRegressionPLModule.log_thresholding_metrics |
kirad/base_models.py:315 |
Log each tuned method's cost when scored with every method's thresholds. |
| 40 |
OptimalOrdinalThresholdingViaDynamicProgramming.tune_thresholds |
kirad/ordinal_thresholding.py:179 |
Set thresholds by DP over midpoints of unique scores (+/-inf); return the best metric. |
| — |
OptimalCostPerSampleOrdinalThresholding.dp_step |
kirad/ordinal_thresholding.py:291 |
O(n) DP step: histogram per-sample costs over candidates, cumsum, running max. |
| — |
OptimalCostPerClassOrdinalThresholding.dp_step |
kirad/ordinal_thresholding.py:450 |
O(T^2) DP step: add prev_cost to each lower-threshold row and max over it. |
| — |
CORALThresholding.tune_thresholds |
kirad/ordinal_thresholding.py:85 |
Copy -biases[threshold_indices] from the CORAL loss; scores and labels are ignored. |
| — |
MultiCatMetric |
kirad/metrics.py:41 |
Accumulate parallel tensors over batches and ranks (uuids, scores, variances, labels). |
| 39 |
IndetSnSpArray.build |
kirad/metrics.py:176 |
Sn/Sp/indet_frac for all threshold pairs (or the given ones) via histogram cumsums. |
| — |
IndetSnSpArray.roc_curve |
kirad/metrics.py:291 |
Pareto ROC curve of (Sn, Sp) using only pairs with indet_frac <= indet_budget. |
| — |
IndetSnSpArray.sn_eq_sp_graph |
kirad/metrics.py:305 |
Best min(Sn, Sp) per indeterminate fraction; these thresholds are saved in the ckpt. |