A privacy-first node-classification competition template with automated secure scoring and a live public leaderboard.
- Live leaderboard: Open Live Leaderboard
- Repository: Bechirdardouri/gnn-challenge
- Task: node classification on graph-structured data
- Public data:
data/train.csv,data/val.csv,data/test.csv,data/edges.csv - Hidden data: private test labels (never committed in plaintext)
- Main metric: Macro-F1 for class-label submissions
- Privacy model: predictions are submitted encrypted (
.enc) and scored in trusted GitHub Actions - Output: leaderboard updates are committed automatically and published via GitHub Pages
This competition is intentionally designed as a low-label graph problem:
train.csv: 100 labeled nodesval.csv: 300 labeled nodestest.csv: 7200 unlabeled nodes for submissionedges.csv: 53,411 graph edges over 7,600 total nodes
What makes it interesting:
- You have very little supervised signal relative to test size
- Performance depends on combining feature learning and graph structure
- Evaluation is private and automated, so leaderboard gains must come from genuine generalization
Dataset Quirks And Hidden Traps
These are the main pitfalls teams should account for:
- Label scarcity is real:
- only 400 labeled nodes total (
train + val) vs 7,200 test nodes
- only 400 labeled nodes total (
- Class prior mismatch risk:
valis perfectly balanced across 5 classes, whiletrainis slightly skewed
- Graph degree is heavy-tailed:
- median total degree is 8, 95th percentile is 46, max degree is 2606
- hub nodes can dominate naive neighbor aggregation
- Graph signal is not purely homophilous:
- on known-known labeled edges, same-class rate is around 0.24 (close to 0.20 random baseline for 5 classes)
- aggressive same-label propagation can hurt
- Direct label reach into test is limited:
- only about 25% of test nodes have a direct edge to a labeled node
- relying on 1-hop supervision alone leaves most test nodes weakly informed
Recommended strategy for strong, stable submissions:
- Treat this as hybrid tabular + graph learning
- start from feature-strong models
- add graph-derived features (1-hop/2-hop aggregates, degree/log-degree)
- Use
valfor serious model selection- tune seeds, depth/regularization, and feature mixing on Macro-F1
- avoid single-seed conclusions; use seed ensembles for stability
- Control hub effects
- use degree-normalized aggregation
- include explicit degree features so model can adapt to hub vs non-hub nodes
- Handle class imbalance cautiously
- class-balanced losses/weights can help on small-train settings
- validate calibration behavior on
val, not only raw train fit
- Reduce variance before final test inference
- after selecting hyperparameters, retrain on
train + val - ensemble multiple seeds/models where feasible
- after selecting hyperparameters, retrain on
- Keep submissions strict and reproducible
- validate
node_idcoverage againstdata/test.csv - keep a deterministic pipeline from training to CSV to encryption
- validate
- Fair evaluation: hidden labels are not exposed to participants
- Transparent operations: scoring logic is versioned in repo code
- Reproducible workflow: validation, encryption, scoring, and rendering are scripted
- Fast feedback: leaderboard updates automatically after successful evaluation runs
- Read
docs/PARTICIPANT_GUIDE.md - Train and generate predictions
- Validate CSV format and coverage
- Encrypt submission with organizer public key
- Open PR containing only
submissions/*.enc
Quick path:
# 1) Generate starter SOTA predictions
python starter_code/sota_graph_ensemble.py --output submissions/sota_ensemble_submission.csv
# 2) Validate your file
python competition/validate_submission.py submissions/sota_ensemble_submission.csv data/test.csv
# 3) Encrypt (replace team/model names)
python encryption/encrypt.py \
submissions/sota_ensemble_submission.csv \
encryption/public_key.pem \
submissions/<team_name>__<model_name>.enc- Read
docs/ORGANIZER_GUIDE.md - Configure secrets for private labels and private key
- Verify Actions workflows are enabled with write permissions
- Run a smoke test submission to confirm end-to-end scoring
- Participant generates
node_id,targetCSV offline - Participant encrypts with
encryption/public_key.pem - Participant submits
.encin PR Score Encrypted PR Submissionworkflow decrypts and scores in trusted runner- Leaderboard artifacts update automatically
Workflow: .github/workflows/score_submission.yml
- Team uploads CSV through Google Form
- Google Sheet + Apps Script trigger dispatches workflow
- Workflow downloads submissions from Drive and scores them
- Leaderboard updates automatically
Workflow: .github/workflows/process_google_form_submissions.yml
- Submissions are scored against private labels
leaderboard/leaderboard.csvis updatedcompetition/render_leaderboard.pyregeneratesleaderboard/leaderboard.mdanddocs/leaderboard.json- GitHub Pages serves the live UI from
docs/
Primary publish workflows:
.github/workflows/sync_leaderboard_from_encrypted_submissions.yml.github/workflows/publish_leaderboard.yml
- Public repository stores encrypted submissions, not plaintext predictions
- Private key is injected at runtime from secret
PRIVATE_KEY_PEM - Private labels are materialized at runtime by
scripts/materialize_private_labels.py - Trusted base-branch workflow code performs scoring
- PR scorer reads submission files via GitHub API and avoids running untrusted PR code
Private label sources supported:
PRIVATE_TEST_LABELS_CSV(preferred)PRIVATE_TEST_LABELS_CSV_GZIP_B64(for large secrets)TEST_LABELS_KEY+data/test_labels.csv.enc(legacy mode)- External source via
PRIVATE_DATA_METHOD(google_drive,url,s3)
Deep dive: docs/SECURITY.md
competition/: validation, metrics, evaluation, renderingencryption/: key utilities and encryption/decryption scriptsstarter_code/: baseline and stronger starter modelsscripts/: CI helpers for private data and scoring pipelinessubmissions/: participant submissions and examplesleaderboard/: canonical leaderboard data filesdocs/: live UI assets and operational documentation
# Environment and dependency checks
python check_setup.py
# Show shortcut commands
make help
# Build starter submission
make train-sota
# Validate a submission
make validate-sota
# Render leaderboard markdown/json from leaderboard.csv
make render-leaderboard
# Local evaluation (requires local private labels)
python competition/evaluate.py submissions/sota_ensemble_submission.csv data/private/test_labels.csv --metric autoIf the leaderboard UI shows no rows:
- Open Actions and inspect latest run of
Sync Leaderboard From Encrypted Submissions - Confirm at least one private-label source secret is configured
- Re-run sync workflow manually (
workflow_dispatch) - Confirm run steps
Materialize private labelsandProcess repository submissionsare green - Hard refresh leaderboard page after Pages deploy completes
- Do not commit private keys or plaintext private labels
- Keep submission PRs limited to encrypted files
- Keep workflow and scoring changes documented in PR descriptions
- Preserve reproducibility: prefer explicit scripts over ad-hoc manual edits
- Participant instructions:
docs/PARTICIPANT_GUIDE.md - Organizer setup:
docs/ORGANIZER_GUIDE.md - Security model:
docs/SECURITY.md - Repo map:
docs/REPO_MAP.md - FAQ:
docs/FAQ.md - Contribution guide:
CONTRIBUTING.md