Response-Quality-Assessment / docs /context /04_environment_setup.md
Ryoya Awano
deploy: fix MedLFQA Marginal mode sample matching
19fc84f
# 環境構築・実行手順
実行環境は **Singularity コンテナ経由****ホスト直接実行** の2通りをサポートする。
---
## 1. 前提条件
| ツール | バージョン要件 | 用途 |
|--------|-------------|------|
| Git | 任意 | リポジトリのクローン |
| Singularity (SingularityCE) | 3.x 以上 | コンテナ実行・SIF ビルド(コンテナ経由の場合) |
| `fakeroot` | — | SIF ビルド時に必要(`singularity build --fakeroot`) |
| Python 3.11 + `requirements-dev.txt` | — | ホスト直接実行の場合のみ |
> **推奨**: HPC 環境など Python 環境の管理が難しい場合は Singularity コンテナ経由を使う。ローカル開発では直接実行でも動作する。
---
## 2. ホスト側ディレクトリ構成
ホストの任意のディレクトリ(`DATA_ROOT` の親)に以下の構造を作成する。
重いファイル(FAISS インデックス、生データ、HuggingFace キャッシュ)はすべてここに集約し、Singularity の `--bind` でコンテナ内にマウントする。
```
/mnt/data/<username>/
├── sif/
│ └── response_quality.sif ← SIF_DIR
├── hf_cache/ ← HF_HOME
└── ResponseQualityAssessment/ ← DATA_ROOT
├── data/
│ ├── raw/
│ │ └── WikiDB/ ← Wikipedia SQLite DB
│ ├── processed/
│ ├── out/ ← main.py 出力(サブクレーム JSON)
│ └── result/
└── index_store/
├── FactScore/ ← FAISS インデックス
├── HotpotQA/
├── PopQA/
└── MedLFQA/
```
> `demo/data/`(thresholds.csv, samples.json)はリポジトリ内に含まれるため `DATA_ROOT` 側への配置・バインドは不要。
---
## 3. `.env` の設定
`.env.example` をコピーして `.env` を作成し、環境に合わせて値を設定する。
```bash
cp .env.example .env
```
`.env` の内容(`.gitignore` 対象):
```bash
# Machine-specific absolute paths
DATA_ROOT=/mnt/data/<username>/ResponseQualityAssessment
SIF_DIR=/mnt/data/<username>/sif
HF_HOME=/mnt/data/<username>/hf_cache
# API keys
OPENAI_API_KEY=sk-...
```
`conf/path_config.yaml` と `conf/dataset_config.yaml` の各パスは `${DATA_ROOT}` を起点として定義されており、実行時にこの環境変数を展開して解釈する。
> - **ホスト直接実行時**: `.env` の `DATA_ROOT`(例: `/mnt/data/<username>/ResponseQualityAssessment`)をそのまま使用する。
> - **コンテナ経由実行時**: `run_*.sh` スクリプトがホストの `data/` と `index_store/` を `REPO_ROOT` 以下にバインドマウントするため、コンテナ内での `DATA_ROOT` は `REPO_ROOT` に上書きされる。スクリプト内の `--env DATA_ROOT="${REPO_ROOT}"` がこれを担っている。
---
## 4. Singularity コンテナのビルド(初回のみ)
```bash
bash scripts/build_sif.sh
```
- `singularity/response_quality.def`(`docker://python:3.11-slim` ベース)から SIF をビルドする
- 出力先: `${SIF_DIR}/response_quality.sif`
- ビルドには数分かかる。`fakeroot` が必要
- `torch` はコンテナ内では CPU 専用 wheel(`--index-url https://download.pytorch.org/whl/cpu`)でインストールされる。ローカル開発で `requirements-dev.txt` から直接インストールする場合は同オプションを手動で指定すること
**requirements ファイルの構成:**
| ファイル | 用途 |
|----------|------|
| `requirements.txt` | HF Spaces 向け最小セット(`torch` 等の重い依存を除く)。Spaces はこのファイルを自動で読む |
| `requirements-dev.txt` | ローカル・Singularity 向け全依存(`-r requirements.txt` で共通部分を継承) |
ホスト直接実行時のインストール:
```bash
pip install -r requirements-dev.txt
```
---
## 5. データ準備(初回のみ)
| 方法 | 用途 | API 消費 |
|--------|------|---------|
| **A. 著者提供データを使う** | 生データ・FAISS インデックスを再利用して API 呼び出しを削減 | Embeddings 不要(FAISS スキップ)、Chat は必要 |
| **B. 自前でフルパイプライン実行** | 新モデルや新データセットで結果を再現 | あり(Chat + Embeddings) |
---
### A. 著者提供データを使う(FAISS 構築スキップ)
著者提供の Google Drive フォルダには以下が含まれる(**注**: 事前計算済みサブクレーム JSON は含まれていない):
- `data.zip` — 生クエリデータ(`HotpotQA/raw_hotpot_qa.json`、`PopQA/raw_pop_qa.json`、`FactScore/factscore_names.txt`、`MedLFQA/*.jsonl`)
- `index_store.zip` — 事前構築済み FAISS インデックス(各データセット × 各 query_size 分の `.faiss` と `indice2fm_*.json`)
FAISS インデックスが揃っていれば Embeddings API(インデックス構築)はスキップされる。ただし、RAG 回答生成・サブクレーム抽出・スコアリング・アノテーションには Chat API が必要。
**1. Wikipedia DB をダウンロードして配置する**
全データセット共通で必要(QueryProcessor が常に参照する)。
> [enwiki-20230401.db(Google Drive)](https://drive.google.com/file/d/1mekls6OGOKLmt7gYtHs0WGf5oTamTNat/view?usp=drive_link)
```
DATA_ROOT/data/raw/WikiDB/enwiki-20230401.db
```
**2. `medlf_qa` を使う場合は生データを手動取得する**
`fact_score` / `hotpot_qa` / `pop_qa` は DataLoader が HuggingFace から自動取得するため不要。
```bash
source .env
# 以下どちらか一方
git clone https://github.com/dmis-lab/OLAPH.git /tmp/olaph
cp -r /tmp/olaph/MedLFQA ${DATA_ROOT}/data/raw/MedLFQA
# または
git clone https://github.com/jjcherian/conformal-safety.git /tmp/cs
cp -r /tmp/cs/data/MedLFQAv2 ${DATA_ROOT}/data/raw/MedLFQA
```
**3. 著者提供データをダウンロードして展開する**
> https://drive.google.com/drive/folders/1aLbHxS6V1ipMH8FpVCxKmr8oMYfqmRgb
```bash
source .env
# gdown でフォルダをダウンロード("conformal prediction with RAG/" という名前で保存される)
gdown --folder https://drive.google.com/drive/folders/1aLbHxS6V1ipMH8FpVCxKmr8oMYfqmRgb \
-O "${DATA_ROOT}/data/out/"
# 生データを data/raw/ に展開
unzip "${DATA_ROOT}/data/out/conformal prediction with RAG/data.zip" \
-d "${DATA_ROOT}/data/raw/"
# FAISS インデックスを DATA_ROOT 直下に展開(index_store/ が作られる)
unzip "${DATA_ROOT}/data/out/conformal prediction with RAG/index_store.zip" \
-d "${DATA_ROOT}/"
```
展開後の構造:
```
DATA_ROOT/
├── data/
│ └── raw/
│ ├── HotpotQA/raw_hotpot_qa.json
│ ├── PopQA/raw_pop_qa.json
│ ├── FactScore/factscore_names.txt
│ └── MedLFQA/*.jsonl
└── index_store/
├── FactScore/index_500.faiss, indice2fm_500.json, ...
├── HotpotQA/index_500.faiss, indice2fm_500.json
└── MedLFQA/index_10.faiss, index_500.faiss, indice2fm_*.json, ...
```
**4. 実行する**
FAISS インデックスが存在する場合、インデックス構築(Embeddings API)はスキップされる。RAG 推論・スコアリング・アノテーションには Chat API が必要。
```bash
# コンテナ経由
bash scripts/run_main.sh --dataset medlf_qa
# ホスト直接実行
source .env && python main.py --dataset medlf_qa
```
---
### B. 自前でフルパイプライン実行(API あり)
**1. Wikipedia DB をダウンロードして配置する**
上記 A の手順 1 と同じ。
**2. `medlf_qa` を使う場合は生データを手動取得する**
上記 A の手順 2 と同じ。`fact_score` / `hotpot_qa` / `pop_qa` は不要。
**3. 実行する**
データセットごとに1つずつ実行する(並列不可)。
```bash
# コンテナ経由
bash scripts/run_main.sh --dataset medlf_qa
# 利用可能: fact_score, hotpot_qa, pop_qa, medlf_qa
# ホスト直接実行
source .env && python main.py --dataset medlf_qa
```
---
実行後に生成されるファイル(`DATA_ROOT` 以下):
| パス | 内容 |
|------|------|
| `data/out/{DatasetName}/` | サブクレームスコア付き JSON |
| `index_store/{DatasetName}/` | FAISS インデックス (`index_*.faiss`, `indice2fm_*.json`) |
---
### CLI オプション一覧
| オプション | デフォルト | 説明 |
|---|---|---|
| `--dataset` | config 参照 | データセット名(`fact_score` / `hotpot_qa` / `pop_qa` / `medlf_qa`) |
| `--query_size` | 500 | 処理するクエリ件数 |
| `--run_id` | タイムスタンプ | ログ・結果ディレクトリの識別子 |
| `--lite` | false | `frequency``doc_claim_cosine_similarity` スコアと conformal グラフ生成をスキップ |
| `--log_level` | `INFO` | ログレベル(`DEBUG` / `INFO` / `WARNING` / `ERROR`) |
### API コールのログ確認
`--log_level DEBUG` を付けると、OpenAI API の個別コール(purpose・model・トークン数)が `[API:Chat]` / `[API:Embeddings]` プレフィックスで記録される。
```bash
# API ログを有効にして実行(コンテナ経由)
bash scripts/run_main.sh --dataset medlf_qa --query_size 10 --lite --log_level DEBUG
# ログから API コールのみ抽出
grep "\[API:" logs/<run_id>/run_<run_id>.log
# purpose 別の集計
grep "\[API:" logs/<run_id>/run_<run_id>.log \
| sed 's/.*\[API:\([^]]*\)\] purpose=\([^ ]*\).*/\1 \2/' \
| sort | uniq -c | sort -rn
```
出力例:
```
103 Embeddings cosine_similarity(claim)
103 Embeddings cosine_similarity(query)
103 Embeddings relevance_score
103 Chat claim_verification
10 Chat subclaim_extraction
10 Chat rag_response
```
---
## 6. 事前計算(データ更新・モデル変更時)
`demo/data/thresholds.csv``demo/data/samples.json` を(再)生成する。
モデル変更やデータセット追加後に実行する。
**コンテナ経由:**
```bash
bash scripts/run_precompute.sh
```
**ホスト直接実行:**
```bash
source .env
python -m demo.precompute
```
出力はリポジトリ内の `demo/data/` に書き込まれる。
生成後は `git add demo/data/ && git commit` でコミットする。
---
## 7. デモの起動
**コンテナ経由:**
```bash
bash scripts/run_demo.sh # デフォルト: ポート 8502
bash scripts/run_demo.sh --port 8503 # ポートを指定する場合
```
**ホスト直接実行:**
```bash
source .env
streamlit run demo/app.py --server.port 8502
```
- デフォルトポート: **8502**(8501 はサーバー上の別アプリが使用中のため)
- ポートが使用中の場合は `--port` オプションで別ポートを指定する
**Singularity バインド構成(スクリプト内部):**
```bash
singularity run \
--bind "${DATA_ROOT}/data:${REPO_ROOT}/data" \
--bind "${DATA_ROOT}/index_store:${REPO_ROOT}/index_store" \
--bind "${HF_HOME}:${HF_HOME}" \
--env HF_HOME="${HF_HOME}" \
--env OPENAI_API_KEY="${OPENAI_API_KEY}" \
--env DATA_ROOT="${REPO_ROOT}" \
--env PYTHONPATH="${REPO_ROOT}" \
--pwd "${REPO_ROOT}" \
"${SIF_DIR}/response_quality.sif" \
streamlit run demo/app.py --server.port 8502
```
`REPO_ROOT` はスクリプト自身の場所から自動解決される。コンテナ内では `DATA_ROOT``REPO_ROOT` に上書きすることで、バインドマウント先のパスと整合させている。)
`demo/data/` はリポジトリ内に存在するため、バインド不要。
---
## 8. トラブルシューティング
### `.env` が読み込まれない
各スクリプトはリポジトリルートの `.env` を自動的に探して読み込む(`REPO_ROOT` をスクリプトの場所から導出するため、どのディレクトリから実行しても動作する)。`.env` ファイル自体が存在するか確認する。
```bash
ls /path/to/ResponseQualityAssessment/.env
```
### `DATA_ROOT` 以下のディレクトリが存在しない
`data/out/` や `index_store/` は `main.py` 実行時に自動作成されるが、
`DATA_ROOT` 自体と `DATA_ROOT/data/`, `DATA_ROOT/index_store/` は事前に作成が必要。
```bash
source .env
mkdir -p ${DATA_ROOT}/data/raw/WikiDB \
${DATA_ROOT}/data/processed \
${DATA_ROOT}/data/out \
${DATA_ROOT}/data/result \
${DATA_ROOT}/index_store \
${HF_HOME} \
${SIF_DIR}
```
### FAISS インデックスが見つからない(デモ起動時にエラー)
`scripts/run_main.sh` が未実行、または対象データセットが処理されていない。
§5「データ準備」を実行する。
### `demo/data/thresholds.csv` が見つからない
`scripts/run_precompute.sh` が未実行。§6「事前計算」を実行する。
または、リポジトリの `demo/data/` にコミット済みファイルがあるか確認する(`git pull` で最新化)。
### `subclaims_schema.json` が見つからない(コンテナ経由実行時)
コンテナ実行時は `DATA_ROOT/data/` が `REPO_ROOT/data/` にバインドマウントされるため、リポジトリ内の `data/out/subclaims_schema.json` が隠れてしまう。初回実行前に手動でコピーする。
```bash
source .env
cp data/out/subclaims_schema.json ${DATA_ROOT}/data/out/subclaims_schema.json
```
### OpenAI API エラー
`.env``OPENAI_API_KEY` が正しく設定されているか確認する。
`#` で始まる行はコメントとして無視されるため、`OPENAI_API_KEY=sk-...` のように `#` なしで記述する。
推論実行ボタンを押した場合のみ API が呼ばれる。サンプルクエリはボタンを押さずにプルダウン選択するだけのため API 不要。