This repository contains the runnable pipeline used for the MAQuA experiments. The code is organized as a staged workflow where each stage writes outputs used by the next stage.
Data is private and not distributed in this repository.
Create environment:
conda env create -f environment.yml
conda activate maquaIf the env already exists, update it:
conda env update -n maqua -f environment.yml --pruneVerify CUDA-enabled PyTorch:
/chronos_data/conda_envs/maqua/bin/python -c "import torch; print('torch', torch.__version__); print('cuda_compiled', torch.version.cuda); print('cuda_available', torch.cuda.is_available())"If CUDA is still unavailable, force CUDA build:
conda install -n maqua -c pytorch -c nvidia pytorch pytorch-cuda=12.4Optional dependencies (only if needed):
pip install vllm
pip install --prefer-binary llama-cpp-pythonAt minimum, place these files under formatted_data/:
question_embeddings.csvinput_dataset_words.csvinput_dataset_essay.csvoutput_questionnaire_outcomes.csvquestions_symptom_outcomes_type.csv
Recommended:
diagnoses.csv(needed for diagnosis correlations)
Optional private input:
private_data/transcripts_with_code.csv(used by GPT/Qwen scoring scripts)
From repo root:
bash optional/sh/run_minimal_pipeline.shPreview commands only:
bash optional/sh/run_minimal_pipeline.sh --dry-runInclude optional plots:
bash optional/sh/run_minimal_pipeline.sh --with-plotsInclude user-level reports (point-biserial + Table-A-aligned Pearson/MSE):
bash optional/sh/run_minimal_pipeline.sh --with-user-level-reportParallel singletask shards (faster ALBA stage):
bash optional/sh/run_minimal_pipeline.sh --singletask-jobs 3Parallel singletask shards across multiple GPUs (round-robin by shard):
MAQUA_PYTHON=/chronos_data/conda_envs/maqua/bin/python \
bash optional/sh/run_minimal_pipeline.sh --singletask-jobs 3 --singletask-gpus 0,1,2Notes:
--singletask-jobs Ncontrols concurrent singletask shards.--singletask-gpus 0,1,2binds shards to those GPUs usingCUDA_VISIBLE_DEVICES.- If jobs exceed listed GPUs, shard-to-GPU assignment is round-robin.
--with-user-level-reportrunsuser_level_correlations.pyand writes user-level report CSVs toanalysis_outputs/.
Use a specific Python interpreter:
MAQUA_PYTHON=/chronos_data/conda_envs/maqua/bin/python \
bash optional/sh/run_minimal_pipeline.sh --dry-runRun on a specific GPU (example: third GPU, index 2):
CUDA_VISIBLE_DEVICES=2 \
MAQUA_PYTHON=/chronos_data/conda_envs/maqua/bin/python \
bash optional/sh/run_minimal_pipeline.shCheck GPU binding quickly:
CUDA_VISIBLE_DEVICES=2 /chronos_data/conda_envs/maqua/bin/python -c "import torch; print(torch.cuda.is_available(), torch.cuda.device_count(), torch.cuda.get_device_name(0))"python train_user_level.py
python run_qa_level_save_outputs.py --strategy all_questionsNotes:
train_user_level.pycovers user-level multitask and singletask (depending on args/defaults).run_qa_level_save_outputs.py --strategy all_questionsis QA-level multitask output generation.
Optional single-task QA:
python optional/python/run_qa_level_singletask.py --outcome PHQ --strategy all_questionsThe command above is QA-level singletask and is separate from run_qa_level_save_outputs.py.
python discretize_question_scores.pyLATEST_DISCRETIZED_DIR=$(ls -td polytomized_data/*_discretized | head -n 1)
python adaptive_testing.py --input-dir "$LATEST_DISCRETIZED_DIR" --run-bothpython compute_tables.py
python diagnosis_correlations.pypython user_level_correlations.py --model both --metrics bothThis generates:
analysis_outputs/user_level_multitask_pointbiserial.csvanalysis_outputs/user_level_singletask_pointbiserial.csvanalysis_outputs/user_level_pointbiserial_all.csvanalysis_outputs/user_level_multitask_regression.csvanalysis_outputs/user_level_singletask_regression.csvanalysis_outputs/user_level_regression_all.csv
Metric notes:
pointbiserial: diagnosis label (0/1) vs predicted score correlation.regression: user-levelPearsonandMSEbetween true questionnaire scores and predicted scores (same metric family as Table A/ALBA).
Adaptive plots:
python plot_adaptive_results.py \
--adaptive-dir "adaptive_outputs/$(basename "$LATEST_DISCRETIZED_DIR")" \
--input-dir "$LATEST_DISCRETIZED_DIR"Figure 2 correlation plots:
LATEST_QA_DIR=$(python - <<'PY'
import glob, json
from pathlib import Path
candidates = []
def is_complete(d: Path, n_folds: int) -> bool:
if not (d / 'qa_level_test_outputs.csv').exists():
return False
for i in range(n_folds):
if not (d / f'fold_{i}' / 'qa_level_test_predictions.csv').exists():
return False
return True
for pattern in ('model_outputs/qa_level_outputs_*_*', 'model_outputs/all_questions_qa_level_outputs_*'):
for path in glob.glob(pattern):
d = Path(path)
if not d.is_dir():
continue
summary = d / 'cross_validation_summary.json'
if not summary.exists():
summary = d / 'overall_summary.json'
if not summary.exists():
summary = d / 'config.json'
if not summary.exists():
continue
try:
with summary.open() as f:
info = json.load(f)
except Exception:
continue
if info.get('question_strategy') == 'all_questions':
try:
n_folds = int(info.get('n_folds', 9))
except Exception:
continue
if n_folds <= 0:
continue
if not is_complete(d, n_folds):
continue
candidates.append((d.stat().st_mtime, str(d)))
if not candidates:
raise SystemExit('No complete QA output directory found for strategy=all_questions')
candidates.sort(key=lambda x: x[0])
print(candidates[-1][1])
PY)
python plot_adaptive_correlations.py \
--adaptive-dir "adaptive_outputs/$(basename "$LATEST_DISCRETIZED_DIR")" \
--input-dir "$LATEST_DISCRETIZED_DIR" \
--qa-dir "$LATEST_QA_DIR" \
--rolling-window 5 --std-threshold 0.01model_outputs/(stage 1)polytomized_data/(stage 2)adaptive_outputs/(stage 3)analysis_outputs/(stage 4 and plots)
GPT baseline:
python gpt4_adaptive_baseline.py --model gpt-4o --out-csv gpt4_predictions.csvSelf-hosted OpenAI-compatible endpoint example:
python gpt4_adaptive_baseline.py --model gpt-oss-20b --base-url http://localhost:8000/v1 --api-key dummy --api-mode chatQwen scoring (optional):
python optional/python/run_qwen_scores.pyFor table/figure-to-script mapping, see:
docs/repro_checklist.mddocs/run_with_formatted_and_private.md
- Paths are centralized in
maqua_paths.py. - Set
MAQUA_ROOTif running from outside repo root. - Legacy and experimental scripts are in
legacy/.