|
| 1 | +# HotpotQA — SME corpus loader |
| 2 | + |
| 3 | +This directory holds the loader and SME-shape conversion for the |
| 4 | +**HotpotQA** benchmark (Yang et al., EMNLP 2018; arXiv 1809.09600). |
| 5 | +The dataset itself is **not committed** to this repo; see the download |
| 6 | +section below. |
| 7 | + |
| 8 | +HotpotQA is the Phase-1 multi-hop calibration surface from the |
| 9 | +standard-corpora integration plan (upstream |
| 10 | +`M0nkeyFl0wer/multipass-structural-memory-eval#43`). It is the public, |
| 11 | +1000s-scale corpus with **sentence-level annotated supporting facts** |
| 12 | +that lets SME demonstrate — not just design — construct validity for |
| 13 | +**Cat 2c** (multi-hop retrieval recall by depth): *"Cat 2c ran against |
| 14 | +HotpotQA's known 2-hop evidence and recovered N of M gold paragraphs."* |
| 15 | +It mirrors the LoCoMo / LongMemEval loaders' interface exactly. |
| 16 | + |
| 17 | +## Pinned subset (the comparability contract) |
| 18 | + |
| 19 | +HotpotQA cross-comparisons are unreliable unless the split and |
| 20 | +retrieval setting are pinned. This loader pins: |
| 21 | + |
| 22 | +| Constant | Value | Meaning | |
| 23 | +|---|---|---| |
| 24 | +| `SUBSET` | `"dev_distractor"` | the `hotpot_dev_distractor_v1.json` split | |
| 25 | +| `SETTING` | `"distractor"` | 10-paragraph haystack (2 gold + 8 distractor) | |
| 26 | +| `SUBSET_QUESTION_COUNT` | `7405` | questions in the dev distractor split | |
| 27 | +| `HOTPOT_MIN_HOPS` | `2` | every question is 2-hop by construction | |
| 28 | + |
| 29 | +**Any reading published from this loader must state the split and |
| 30 | +setting.** The **fullwiki** setting (retrieve over all of Wikipedia) is |
| 31 | +a different, IR-heavy task and is out of scope for a loader. The train |
| 32 | +split (`hotpot_train_v1.1.json`, 90,447 questions) is also loadable — |
| 33 | +pass its path explicitly — but the *pinned* comparability subset is the |
| 34 | +dev distractor split. |
| 35 | + |
| 36 | +## Dataset download |
| 37 | + |
| 38 | +```bash |
| 39 | +mkdir -p sme/corpora/hotpotqa/data |
| 40 | +cd sme/corpora/hotpotqa/data |
| 41 | +# dev distractor split (~44 MB) — the pinned subset |
| 42 | +wget http://curtis.ml.cmu.edu/datasets/hotpot/hotpot_dev_distractor_v1.json |
| 43 | +# optional: train split (~535 MB) |
| 44 | +# wget http://curtis.ml.cmu.edu/datasets/hotpot/hotpot_train_v1.1.json |
| 45 | +``` |
| 46 | + |
| 47 | +The `data/` directory is gitignored — keep the upstream JSON local. |
| 48 | +HotpotQA is released under **CC BY-SA 4.0**; redistribution requires |
| 49 | +attribution and share-alike, so the corpus is downloaded per-machine |
| 50 | +rather than vendored here. |
| 51 | + |
| 52 | +## Hop depth (the Cat 2c join) |
| 53 | + |
| 54 | +SME Cat 2c groups questions by `min_hops`. HotpotQA does not annotate an |
| 55 | +explicit integer hop depth, but **every released question is 2-hop by |
| 56 | +construction** (two gold supporting paragraphs), so the loader assigns |
| 57 | +`min_hops = 2` to every record. The `type` field is the qualitative |
| 58 | +multi-hop *shape*: |
| 59 | + |
| 60 | +| `type` | shape | retrieval behavior | |
| 61 | +|---|---|---| |
| 62 | +| `bridge` | sequential 2-hop | resolve a bridge entity in paragraph A, then use it to answer from paragraph B (true chaining) | |
| 63 | +| `comparison` | parallel 2-hop | retrieve a fact from each of two paragraphs and compare them (both must be found, no chaining) | |
| 64 | + |
| 65 | +Both require ≥2 distinct gold paragraphs, hence `min_hops = 2`. A |
| 66 | +deeper-hop corpus (e.g. MuSiQue) would extend the depth axis; HotpotQA |
| 67 | +pins the 2-hop calibration point that jp-realm-v0.1 cannot reach at |
| 68 | +scale. |
| 69 | + |
| 70 | +## Format mapping (HotpotQA → SME) |
| 71 | + |
| 72 | +| HotpotQA field | SME mapping | |
| 73 | +|---|---| |
| 74 | +| `_id` | `question_id` (preserved as the SME question `id` and the per-question vault dir) | |
| 75 | +| `question` | `text` | |
| 76 | +| `answer` | `gold_answer` (QA judge target; `"yes"`/`"no"` for comparison questions) | |
| 77 | +| `type` (`comparison`/`bridge`) | preserved under `hotpotqa.type`; named via `HOTPOT_TYPE_NAMES`; all map to SME `cat_2c` | |
| 78 | +| `level` (`easy`/`medium`/`hard`) | preserved under `hotpotqa.level` | |
| 79 | +| `supporting_facts` (`[[title, sent_id], …]`) | preserved under `hotpotqa.supporting_facts`; gold titles → `expected_sources`; sentence texts via `expected_sources_sentence_level()` | |
| 80 | +| `context` (`[[title, [sentence, …]], …]`) | one markdown file per paragraph under `vault/<question_id>/<title>.md`; gold paragraphs flagged `is_gold: true` | |
| 81 | +| — (assigned) | `min_hops: 2`, `sme_category: cat_2c` | |
| 82 | + |
| 83 | +## Architectural note: per-question vaults (not per-sample) |
| 84 | + |
| 85 | +LoCoMo shares one conversation across all of a sample's questions, so |
| 86 | +its loader writes a vault per *sample*. HotpotQA instead gives each |
| 87 | +question its own ~10-paragraph haystack, so this loader writes a vault |
| 88 | +per *question* (`vault/<question_id>/`) — the same per-question scoping |
| 89 | +as LongMemEval. A cross-validation run loops per question: |
| 90 | + |
| 91 | +```python |
| 92 | +for q in load_questions(dev_distractor_path): |
| 93 | + adapter.reset() |
| 94 | + adapter.ingest_corpus_from_dir(vault_dir / q.question_id) |
| 95 | + result = adapter.query(q.text, n_results=5) |
| 96 | + sme_score = sme_substring_match(result, q.expected_sources_paragraph_level()) |
| 97 | + # multi-hop recall: did retrieval surface BOTH gold paragraphs? |
| 98 | + record(q.question_id, sme_score, min_hops=q.min_hops) |
| 99 | +``` |
| 100 | + |
| 101 | +`materialize_sme_corpus(..., gold_only=True)` drops the distractors for |
| 102 | +an oracle-retrieval upper bound; the default writes the full distractor |
| 103 | +haystack (the standard setting). |
| 104 | + |
| 105 | +## Status |
| 106 | + |
| 107 | +- `loader.py` — `HotpotQuestion` / `HotpotParagraph` dataclasses, |
| 108 | + `load_questions(path)` iterator, |
| 109 | + `materialize_sme_corpus(questions, output_dir)` for per-question vault |
| 110 | + rendering. Pinned-subset constants exported. |
| 111 | +- `tests/test_hotpotqa_loader.py` — schema-fidelity tests against an |
| 112 | + inline fixture (no download needed). |
| 113 | +- **Pending (downstream):** the Cat 2c cross-validation run against the |
| 114 | + daemon. The loader is the prerequisite; the run is a separate task. |
| 115 | + |
| 116 | +## Citation |
| 117 | + |
| 118 | +Yang, Z., Qi, P., Zhang, S., Bengio, Y., Cohen, W. W., Salakhutdinov, |
| 119 | +R., & Manning, C. D. (2018). *HotpotQA: A Dataset for Diverse, |
| 120 | +Explainable Multi-hop Question Answering.* EMNLP 2018. arXiv:1809.09600. |
| 121 | + |
| 122 | +Upstream repo: https://github.com/hotpotqa/hotpot |
| 123 | +Project page: https://hotpotqa.github.io/ |
| 124 | +License: CC BY-SA 4.0 |
0 commit comments