Task 6: Predicting TNM Staging from TCGA Pathology Reports SMM4H-HeaRD 2026 Workshop @ ACL 2026
This repository contains the URJC team's submission for the TNM multi-label classification challenge: predicting cancer staging components from free-text TCGA pathology reports.
Goal: Build a system that reads pathology reports and predicts the three TNM cancer staging components (Tumor, Node, Metastasis) using NLP models and techniques.
uv as dependency managergit clone <repo-url>
cd smm4h-heard-2026-tnm-extraction
uv sync
The TCGA dataset is included in data/raw/.
smm4h-heard-2026-tnm-extraction/
├── data/
│ ├── raw/ # Original TCGA reports and TNM labels
│ │ ├── text/
│ │ │ └── TCGA_Reports.csv
│ │ └── labels/
│ │ ├── TCGA_T14_patients.csv
│ │ ├── TCGA_N03_patients.csv
│ │ └── TCGA_M01_patients.csv
│ ├── interim/ # Processed training data
│ │ └── TCGA_T0_TNMX_filtered.csv
│ └── submission/ # Challenge submission data and predictions
│ ├── 01-validation/
│ └── 02-evaluation/
│
├── models/
│ └── custom/ # Fine-tuned models (output of training scripts)
│
├── scripts/
│ ├── processing/ # Data preparation
│ └── experiments/
│ ├── validation/ # Phase 1 scripts
│ │ ├── train/
│ │ ├── predict/
│ │ └── codabench_scorer.py
│ └── evaluation/ # Phase 2 scripts
│ ├── train/
│ └── predict/
│
├── src/tnm/ # Shared library
│ ├── config.py # Paths and stage constants
│ ├── llm/ # LLM prompts and chat templates
│ └── training/ # Trainer classes and utilities
│
├── pyproject.toml
├── uv.lock
└── .gitignore
Multi-label classification of cancer TNM staging from free-text pathology reports (TCGA).
The system predicts three independent labels:
| Component | Description | Classes |
|---|---|---|
| T (Tumor) | Size and extent of the primary tumor | T1, T2, T3, T4 |
| N (Node) | Spread to regional lymph nodes | N0, N1, N2, N3 |
| M (Metastasis) | Distant metastasis | M0, M1 |
Pathology Reports
data/raw/text/TCGA_Reports.csvTNM Labels (Ground Truth)
data/raw/labels/
TCGA_T14_patients.csv — T stage labels (T1–T4)TCGA_N03_patients.csv — N stage labels (N0–N3)TCGA_M01_patients.csv — M stage labels (M0–M1)Macro-averaged F1 per stage (T, N, M), then averaged across all three stages. Implemented locally in scripts/experiments/validation/codabench_scorer.py.
data/interim/TCGA_T0_TNMX_filtered.csvCustom training dataset built from TCGA reports and labels. Generated by scripts/processing/merge_reports_labels_filtered.py.
patient_id, text, t, n, mT0, TX, NX, or MX labelsTraining data: data/submission/01-validation/challenge/tcga_tnm_train.csv
Training scripts (scripts/experiments/validation/train/):
train_validation_bioclinicalmodernbert_{t,n,m}.py — Fine-tune BioClinical-ModernBERT-large per stagetrain_validation_qwen_27b_{t,n,m}.py — SFT fine-tune Qwen3.5-27B per stagePrediction scripts (scripts/experiments/validation/predict/):
| Script | Description |
|---|---|
predict_validation_majority.py | Majority-class baseline |
predict_validation_logreg.py | BoW + Logistic Regression |
predict_validation_regex.py | Regex extraction |
predict_validation_cbb.py | Clinical-BigBird baseline (jkefeli) |
predict_validation_bioclinicalmodernbert.py | Fine-tuned BioClinical-ModernBERT |
predict_validation_qwen_zs.py | Qwen3.5-27B zero-shot |
predict_validation_qwen_sft.py | Qwen3.5-27B SFT fine-tuned |
predict_validation_regex_qwen_zs.py | Regex + Qwen ZS fallback |
predict_validation_regex_qwen_sft.py | Regex + Qwen SFT fallback |
Training data: data/interim/TCGA_T0_TNMX_filtered.csv
Training scripts (scripts/experiments/evaluation/train/):
train_evaluation_qwen_27b_{t,n,m}.py — SFT fine-tune Qwen3.5-27B per stage on full filtered datasetPrediction scripts (scripts/experiments/evaluation/predict/):
| Script | Description |
|---|---|
predict_evaluation_regex.py | Regex extraction |
predict_evaluation_qwen_zs.py | Qwen3.5-27B zero-shot |
predict_evaluation_qwen_sft.py | Qwen3.5-27B SFT fine-tuned |
predict_evaluation_regex_qwen_zs.py | Regex + Qwen ZS fallback |
predict_evaluation_regex_qwen_sft.py | Regex + Qwen SFT fallback |
scripts/processing/)| Script | Description |
|---|---|
merge_reports_labels_filtered.py | Build TCGA_T0_TNMX_filtered.csv from raw data |
shift_t_labels.py | Shift T labels down by 1 in a prediction file (experimental correction) |
The challenge on Codabench has 2 phases. Data for each phase is in data/submission/:
data/submission/
├── 01-validation/
│ ├── challenge/ ← organiser-provided data (train + unlabelled val)
│ └── predict/ ← predictions to upload
├── 02-evaluation/
│ ├── challenge/ ← blind test set (provided by organisers)
│ └── predict/ ← predictions to upload
Task 6: Predicting TNM Staging from TCGA Pathology Reports SMM4H-HeaRD 2026 Workshop @ ACL 2026
This repository contains the URJC team's submission for the TNM multi-label classification challenge: predicting cancer staging components from free-text TCGA pathology reports.
Goal: Build a system that reads pathology reports and predicts the three TNM cancer staging components (Tumor, Node, Metastasis) using NLP models and techniques.
uv as dependency managergit clone <repo-url>
cd smm4h-heard-2026-tnm-extraction
uv sync
The TCGA dataset is included in data/raw/.
smm4h-heard-2026-tnm-extraction/
├── data/
│ ├── raw/ # Original TCGA reports and TNM labels
│ │ ├── text/
│ │ │ └── TCGA_Reports.csv
│ │ └── labels/
│ │ ├── TCGA_T14_patients.csv
│ │ ├── TCGA_N03_patients.csv
│ │ └── TCGA_M01_patients.csv
│ ├── interim/ # Processed training data
│ │ └── TCGA_T0_TNMX_filtered.csv
│ └── submission/ # Challenge submission data and predictions
│ ├── 01-validation/
│ └── 02-evaluation/
│
├── models/
│ └── custom/ # Fine-tuned models (output of training scripts)
│
├── scripts/
│ ├── processing/ # Data preparation
│ └── experiments/
│ ├── validation/ # Phase 1 scripts
│ │ ├── train/
│ │ ├── predict/
│ │ └── codabench_scorer.py
│ └── evaluation/ # Phase 2 scripts
│ ├── train/
│ └── predict/
│
├── src/tnm/ # Shared library
│ ├── config.py # Paths and stage constants
│ ├── llm/ # LLM prompts and chat templates
│ └── training/ # Trainer classes and utilities
│
├── pyproject.toml
├── uv.lock
└── .gitignore
Multi-label classification of cancer TNM staging from free-text pathology reports (TCGA).
The system predicts three independent labels:
| Component | Description | Classes |
|---|---|---|
| T (Tumor) | Size and extent of the primary tumor | T1, T2, T3, T4 |
| N (Node) | Spread to regional lymph nodes | N0, N1, N2, N3 |
| M (Metastasis) | Distant metastasis | M0, M1 |
Pathology Reports
data/raw/text/TCGA_Reports.csvTNM Labels (Ground Truth)
data/raw/labels/
TCGA_T14_patients.csv — T stage labels (T1–T4)TCGA_N03_patients.csv — N stage labels (N0–N3)TCGA_M01_patients.csv — M stage labels (M0–M1)Macro-averaged F1 per stage (T, N, M), then averaged across all three stages. Implemented locally in scripts/experiments/validation/codabench_scorer.py.
data/interim/TCGA_T0_TNMX_filtered.csvCustom training dataset built from TCGA reports and labels. Generated by scripts/processing/merge_reports_labels_filtered.py.
patient_id, text, t, n, mT0, TX, NX, or MX labelsTraining data: data/submission/01-validation/challenge/tcga_tnm_train.csv
Training scripts (scripts/experiments/validation/train/):
train_validation_bioclinicalmodernbert_{t,n,m}.py — Fine-tune BioClinical-ModernBERT-large per stagetrain_validation_qwen_27b_{t,n,m}.py — SFT fine-tune Qwen3.5-27B per stagePrediction scripts (scripts/experiments/validation/predict/):
| Script | Description |
|---|---|
predict_validation_majority.py | Majority-class baseline |
predict_validation_logreg.py | BoW + Logistic Regression |
predict_validation_regex.py | Regex extraction |
predict_validation_cbb.py | Clinical-BigBird baseline (jkefeli) |
predict_validation_bioclinicalmodernbert.py | Fine-tuned BioClinical-ModernBERT |
predict_validation_qwen_zs.py | Qwen3.5-27B zero-shot |
predict_validation_qwen_sft.py | Qwen3.5-27B SFT fine-tuned |
predict_validation_regex_qwen_zs.py | Regex + Qwen ZS fallback |
predict_validation_regex_qwen_sft.py | Regex + Qwen SFT fallback |
Training data: data/interim/TCGA_T0_TNMX_filtered.csv
Training scripts (scripts/experiments/evaluation/train/):
train_evaluation_qwen_27b_{t,n,m}.py — SFT fine-tune Qwen3.5-27B per stage on full filtered datasetPrediction scripts (scripts/experiments/evaluation/predict/):
| Script | Description |
|---|---|
predict_evaluation_regex.py | Regex extraction |
predict_evaluation_qwen_zs.py | Qwen3.5-27B zero-shot |
predict_evaluation_qwen_sft.py | Qwen3.5-27B SFT fine-tuned |
predict_evaluation_regex_qwen_zs.py | Regex + Qwen ZS fallback |
predict_evaluation_regex_qwen_sft.py | Regex + Qwen SFT fallback |
scripts/processing/)| Script | Description |
|---|---|
merge_reports_labels_filtered.py | Build TCGA_T0_TNMX_filtered.csv from raw data |
shift_t_labels.py | Shift T labels down by 1 in a prediction file (experimental correction) |
The challenge on Codabench has 2 phases. Data for each phase is in data/submission/:
data/submission/
├── 01-validation/
│ ├── challenge/ ← organiser-provided data (train + unlabelled val)
│ └── predict/ ← predictions to upload
├── 02-evaluation/
│ ├── challenge/ ← blind test set (provided by organisers)
│ └── predict/ ← predictions to upload