--- license: apache-2.0 tags: - medical-qa - multilingual - low-resource-african - lora - peft - rag - zindi - msrh library_name: peft pipeline_tag: text-generation base_model: - Qwen/Qwen3.5-27B - Qwen/Qwen3.6-27B - Qwen/Qwen3-32B --- # Magic — Zindi MSRH Multilingual Health Q&A (Top-1 Solution) A LoRA-adapter ensemble that scored **private LB = 0.730865** on the Zindi [Multilingual Sexual & Reproductive Health Q&A](https://zindi.africa/competitions/multilingual-health-question-answering-in-low-resource-african-languages-challenge) challenge. Ships 19 LoRA adapters over 3 Qwen base models plus a per-row consensus ensemble builder that regenerates the submitted `go.csv`. ## Model architecture - **Base models** (3 backbones): `Qwen3.5-27B`, `Qwen3.6-27B`, `Qwen3-32B`. - **Adapter type**: LoRA (`peft`), rank `r=128`, `alpha=256`, dropout `0.05`, `target_modules=all` (7 modules: q/k/v/o/gate/up/down proj). - **Training**: LlamaFactory + DeepSpeed ZeRO-3, `bf16`, `AdamW`, `lr=2e-4`, cosine schedule with `warmup_ratio=0.05`, 3 epochs, effective batch `=64` (`per_device=2 × grad_accum=4 × 8 GPUs`). - **Retrieval**: `McGill-NLP/AfriE5-Large-instruct` top-3 passages (Train+Val as candidate pool, per-subset filtering, self-mask on training queries). - **Few-shot demos**: K ∈ {3, 4, 5, 7} same-subset AfriE5-nearest (Q, A) pairs prepended to each prompt. - **Prompt variants**: v1 baseline + v8 anchored-extraction (shortened copy-verbatim instruction). - **Ensemble**: per-row consensus pick across the 19 adapter predictions. - **Private LB**: `0.730865` on the private test set (see `go.csv`). ## Intended use Answering **maternal, sexual, and reproductive health** questions posed in **English** and in four low-resource African languages: **Akan (`Aka_Gha`)**, **Amharic (`Amh_Eth`)**, **Luganda (`Lug_Uga`)** and **Swahili (`Swa_Ken`)** — together the 8 language×country subsets defined by the competition. Primary intended users are: - Research on retrieval-augmented multilingual medical Q&A. - Reviewers reproducing the leaderboard result. Out-of-scope: clinical decision-making, diagnosis, or any use case where factual correctness for a specific patient matters. The model has NOT been audited for medical safety. ## Dependencies Pinned versions and install instructions are in `requirements/infer.txt` (inference) and `requirements/train.txt` (training). Hardware: reproduce on any 80GB GPU (H100 / A100). The launcher auto-detects visible GPUs and runs up to `min(8, visible)` predicts concurrently, so **1 GPU works** (sequential, ~20-30h wall-clock) and **8 GPUs is the sweet spot** (~2h wall-clock). No config changes needed. ## Inference / reproduction (one command) ```bash bash scripts/run_all.sh ``` This driver runs the full end-to-end recipe: 1. Loads each of the 19 LoRA adapters onto its base model via vLLM. 2. Generates predictions on the shipped test JSONLs (`LF/data/`). 3. Converts each `generated_predictions.jsonl` to a Zindi-format CSV. 4. Runs `scripts/build_ensemble.py` over the 19 CSVs to regenerate `submission.csv`. 5. MD5-verifies the regenerated CSV against the shipped `go.csv`. Step-by-step (if you want to run individually): ```bash # 1. Generate 19 per-adapter predictions (writes to predict_out/) bash scripts/launch_all_predicts.sh # 2. (JSONL → CSV conversion runs inline inside run_all.sh; no separate script) # 3. Ensemble → final CSV (writes submission.csv + md5 check) python scripts/build_ensemble.py ``` Full detail (env setup, LlamaFactory installation, retraining from scratch) is in `README.md`. ## Known caveats & setup notes Before running `scripts/run_all.sh`, be aware of the following (from an end-to-end audit of a fresh clone from this repo): 1. **Base models are NOT included** (license reasons). Reviewers must download the three Qwen backbones separately from Hugging Face and place them under `hub/`: | Base model | HF link | Local path | |---|---|---| | Qwen3.5-27B | https://huggingface.co/Qwen/Qwen3.5-27B | `hub/Qwen3.5-27B/` | | Qwen3.6-27B | https://huggingface.co/Qwen/Qwen3.6-27B | `hub/Qwen3.6-27B/` | | Qwen3-32B | https://huggingface.co/Qwen/Qwen3-32B | `hub/Qwen3-32B/` | Example download: ```bash hf download Qwen/Qwen3.5-27B --local-dir hub/Qwen3.5-27B hf download Qwen/Qwen3.6-27B --local-dir hub/Qwen3.6-27B hf download Qwen/Qwen3-32B --local-dir hub/Qwen3-32B ``` If a repo ID 404s on your side, use a compatible mirror (e.g. an `unsloth/` upload of the same weights). 2. **`base_model_name_or_path` in every `adapter_config.json` points at `/mnt/msrh/Magic_submission/hub/`** — this is a submission-time fake path. Two options: - Extract this repo into `/mnt/msrh/Magic_submission/` (may need `sudo mkdir /mnt/msrh` first) and populate `hub/` there — no code changes. - Or edit `base_model_name_or_path` in each adapter config to point at your local snapshot / HF repo ID. 3. **`scripts/launch_all_predicts.sh` auto-locates its workspace root** from the script path (default: parent dir of `scripts/`). If you want to point at a different location, override the env var: ```bash ROOT=/my/extract/path bash scripts/launch_all_predicts.sh ``` 4. **First-run vLLM warm-up is slow** — the FlashInfer GDN prefill kernel is JIT-compiled on the first launch (~1 min extra per GPU). vLLM also suggests `--gdn-prefill-backend triton` as an alternative if you want to skip JIT; not required for correctness. 5. **Regenerated `submission.csv` matches `go.csv` byte-for-byte only on identical hardware / kernel / vLLM state.** vLLM inference is not deterministic across hardware, driver versions, or torch.compile / FlashInfer cache states. On a fresh environment, expect ~60-70% of rows to match `go.csv` byte-for-byte; the remaining rows will be paraphrases of the same underlying answer. **Functional LB equivalence (ROUGE metrics) is what actually matters for evaluation.** ## Citation If you use this work, please cite the Zindi competition: ``` Zindi Africa. "Multilingual Health Question Answering in Low-Resource African Languages Challenge", 2026. https://zindi.africa/competitions/ multilingual-health-question-answering-in-low-resource-african-languages-challenge ``` ## License Apache-2.0 for the adapter weights and code in this repository. The base Qwen models carry their own licenses (see the corresponding HF repos).