- 2023/09/15: 本ベースラインを公開しました。
- 2023/12/01: 最終投稿方法(API利用)に対応しました。
- 2023/12/06: 最終投稿方法(API利用)に関するエラーを修正しました。
- Open-Domain QA
- 初めに
- ディレクトリ構造
- 学習済みモデルのダウンロード
- 環境構築
- コンテナの起動
- Dense Passage Retrieval
- データセット
- ダウンロード
- Retriever
- DPRモデルについて
- データセットの質問に関連する文書の抽出
- データセット
- Fusion-in-Decoder
- データセット
- 作成
- 形式
- Reader
- FiDモデルについて
- 解答生成と評価
- データセット
- Dockerを用いた最終提出の準備
- 謝辞・ライセンス
本実装では、早押し形式のオープンドメイン質問応答に取り組むために二つのモジュール(Retriever-Reader)を使用します。
- 与えられた質問に対して、文書集合から関連する文書を検索するモジュール(Retriever - Dense Passage Retrieval)
- 質問と検索した関連文書から、質問の答えを生成するモジュール(Reader - Fusion-in-Decoder)
より詳細な解説は、以下を参照して下さい。
Karpukhin, Vladimir and Oguz, Barlas and Min, Sewon and Lewis, Patrick and Wu, Ledell and Edunov, Sergey and Chen, Danqi and Yih, Wen-tau. Dense Passage Retrieval for Open-Domain Question Answering (EMNLP2020) [paper] [github]
Gautier, Izacard and Edouard, Grave. Leveraging Passage Retrieval with Generative Models for Open Domain Question Answering (EACL2021) [paper]
本実装は、通常のオープンドメイン質問応答形式による学習を行ったモデルを、出力の生成確率に基づいて早押し形式での解答に対応させたものです。
従って、早押し自体の学習を行ったモデルではありません。
モデルを動かすにあたって、まず本リポジトリのクローンとディレクトリの移動を行ってください。
# コマンド実行例
$ git clone git@github.com:cl-tohoku/aio4-fid-baseline.git
$ cd aio4-fid-baseline
- datasets.yml: データセット定義
# データセットの前処理
- prepro/:
- convert_dataset.py: データ形式変換
# Retriever
- retrievers/:
- DPR/: DPR モジュール
# 生成型 Reader
- generators/:
- fusion_in_decoder/: FiD モジュール
- download_models.sh: 学習済みモデルのダウンロードスクリプト
- dense_retriever.py: DPR モジュールの実行スクリプト
- test_generator.py: FiD モジュールの実行スクリプト
- compute_score.py: 評価スクリプト
- evaluate_docker_api.py: 最終提出時に用いる評価スクリプト
- prediction_api.py: 最終提出時に用いる予測スクリプト
本ベースラインでは、クイズに対する関連文書を検索するためのDPR(Dense Passage Retrieval)と、検索された関連文書から解答を生成するためのFiD(Fusion-in-Decoder)の学習済みモデルの配布を行っています。
学習済みモデルは下記のコマンドでダウンロードすることができます。
# 学習済みモデルのダウンロード
$ bash download_models.sh
$ du -h retrievers/DPR/models/baseline/*
2.5G biencoder.pt
13G embedding.pickle
$ du -h generators/fusion_in_decoder/models_and_results/baseline/*
4.0K config.json
1.7G optimizer.pth.tar
855M pytorch_model.bin
- まず、Dockerコンテナを起動します。
# コマンド実行例
$ docker image build --tag aio4_fid:latest .
$ docker container run \
--name fid_baseline \
--rm \
--interactive \
--tty \
--gpus all \
--mount type=bind,src=$(pwd),dst=/app \
aio4_fid:latest \
bash
- なお、運営の環境では Docker イメージのビルドに約1時間を要しました。
-
Retriever (Dense Passage Retrieval) の訓練データには、クイズ大会「abc/EQIDEN」 の過去問題に対して Wikipedia の記事段落の付与を自動で行ったものを使用しています。
-
以上のデータセットの詳細については、AI王 〜クイズAI日本一決定戦〜 の公式サイト、および下記論文をご覧下さい。
JAQKET: クイズを題材にした日本語QAデータセット
- https://www.nlp.ecei.tohoku.ac.jp/projects/jaqket/
- 鈴木正敏, 鈴木潤, 松田耕史, ⻄田京介, 井之上直也. JAQKET:クイズを題材にした日本語QAデータセットの構築. 言語処理学会第26回年次大会(NLP2020) [PDF]
第4回AI王コンペティションで配布されている開発・リーダーボード評価用クイズ問題、およびRetriever (Dense Passage Retrieval) の学習で使用するデータセット(訓練・開発用クイズ問題に Wikipedia の記事段落の付与を行ったもの)は、下記のコマンドで取得することができます。
$ datasets_dir="retrievers/DPR/datasets"
$ bash retrievers/DPR/scripts/download_data.sh $datasets_dir
# ダウンロードされたデータセット
<datasets_dir>
|- aio_04_dev_unlabeled_v1.0.jsonl # 第4回開発データ(問題のみ)
|- aio_04_dev_v1.0.jsonl # 第4回開発データ(問題と正解)
|- aio_04_test_lb_unlabeled_v1.0.jsonl # 第4回リーダーボード用データ
|- wiki/
| |- jawiki-20220404-c400-large.tsv.gz # Wikipedia 文書集合
|- retriever/
| |- aio_01_train.json.gz # DPRの訓練データに Wikipedia の記事段落の付与を行ったもの
| |- aio_01_dev.json.gz
| |- aio_01_test.json.gz
| |- aio_01_train.tsv # 「質問」と「正解」からなる TSV 形式の訓練データ
| |- aio_01_dev.tsv
| |- aio_01_test.tsv
データ | ファイル名 | 質問数 | 文書数 |
---|---|---|---|
訓練用 | aio_01_train | 17,735 | - |
開発用 | aio_04_dev_v1.0.jsonl | 500 | - |
リーダーボード用 | aio_04_test_lb_unlabeled_v1.0.jsonl | 500 | - |
文書集合 | jawiki-20220404-c400-large | - | 4,288,199 |
- データセットの構築方法の詳細については、retrievers/DPR/data/README.mdを参照して下さい。
- 学習済みモデルのダウンロード節で既に学習済みRetriever(DPR)・文書エンベッディングのダウンロードを行った場合は、既にモデルの準備が完了しているため、この節はスキップしてください。
- なお、Retriever(DPR) の学習を行う場合、また文書集合(Wikipedia)のエンコード方法の詳細については、retrievers/DPR/README.mdを参照して下さい。
# 学習済みRetriever(DPR)・文書エンベッディングのダウンロードを行った場合
$ du -h retrievers/DPR/models/baseline/*
2.5G biencoder.pt
13G embedding.pickle
データセットの質問に関連する文書を抽出します。質問エンコーダから取得した質問エンベッディングと文書エンベッディングに対して Faiss を用いて類似度を計算します。
$ vim retrievers/DPR/scripts/configs/config.pth
- データセットやモデルを任意の場所に保存した方は、上記設定ファイルに以下の項目を設定してください。
WIKI_FILE
:Wikipedia の文書集合ファイルTRAIN_FILE
:第4回訓練データ(Retriever(=DPR)の訓練を行う場合に設定が必要な項目です)DEV_FILE
:第4回開発データ(問題のみ)TEST_FILE
:第4回リーダーボード用データDIR_DPR
:モデルや文書エンベッディングが保存されているディレクトリへのパスDIR_RESULT
: 関連文書抽出結果の保存先
下記のコマンドを実行することで、DPRがデータセットの質問に関連する文書を抽出します。 なお、運営の実行環境(NVIDIA GeForce GTX 1080 Ti x3)では、第4回開発データに対する関連文書の抽出に1時間弱を要しました。
# 実行例
$ exp_name="baseline"
$ model="retrievers/DPR/models/baseline/biencoder.pt"
$ embed="retrievers/DPR/models/baseline/embedding.pickle"
$ targets="dev" # {train, dev, test} から関連文書抽出対象を「スペースなしの ',' 区切り」で指定してください
$ bash retrievers/DPR/scripts/retriever/retrieve_passage.sh \
-n $exp_name \
-m $model \
-e $embed \
-t $targets
# 実行結果
$ ls ${DIR_RESULT}/${exp_name}/retrieved
dev_aio_pt.json # 予測結果
dev_aio_pt.tsv # 予測スコア(Acc@k を含む)
logs/
predict_aio_pt.log # 実行時ログ
Fusion-in-Decoder(FiD) は、質問と各関連文書を連結したものをエンコーダーでベクトル化し、それを連結したものをデコーダーに入力することで解答を生成するモデルです。
前節のRetrieverによる関連文書抽出結果を任意の場所に保存した方は、/app/datasets.yml ファイルを編集して下さい。
$ vim datasets.yml
このファイルには、Retriever(Dense Passage Retrieval) によって検索された関連文書と質問を含むファイルへのパスを、下記に合わせて設定して下さい。
DprRetrieved:
path: JaqketAIO.load_jaqketaio2
class: JaqketAIO
data:
# train: retrievers/DPR/results/baseline/retrieved/train_aio_pt.json
dev: retrievers/DPR/results/baseline/retrieved/dev_aio_pt.json
# test: retrievers/DPR/results/baseline/retrieved/test_aio_pt.json
Retriever で訓練データやリーダーボード用データに対する関連文書抽出を行った場合は,上記ファイル内でtrain
や test
に対応する項目も設定して下さい。
設定が完了したら、次に Reader 用にデータセット形式を変換します。
$ python prepro/convert_dataset.py DprRetrieved fusion_in_decoder
変換後のデータセットは次のディレクトリに保存されます。
/app/datasets/fusion_in_decoder/DprRetrieved/dev.jsonl
以下のインスタンスからなる JSONL ファイルを使用します。
なお、評価データを用いる際は答えが含まれていないため、answers
およびtarget
は空となります。
{
"id": "(str) 質問ID",
"question": "(str) 質問",
"target": "(str) answers から一つ選択した答え。ない場合はランダムに選択される。",
"answers": "(List[str]) 答えのリスト",
"ctxs": [{
"id": "(int) 記事ID",
"title": "(str) Wikipedia 記事タイトル",
"text": "(str) Wikipedia 記事",
"score": "(float) retriever の検索スコア (ない場合は 1/idx で置換される。generator では使用されない。)",
"has_answer": "(bool) 'text'内に答えが含まれているかどうか"
}]
}
- 学習済みモデルのダウンロード節で既に学習済みReader(FiD)のダウンロードを行った場合は、既にモデルの準備が完了しているため、この節はスキップしてください。
- Reader (Fusion-in-Decoder) の学習については、generators/fusion_in_decoder/README.md を参照して下さい。
# 学習済みReader(FiD)のダウンロードを行った場合
$ du -h generators/fusion_in_decoder/models_and_results/baseline/*
4.0K config.json
1.7G optimizer.pth.tar
851M pytorch_model.bin
$ vim generators/fusion_in_decoder/configs/test_generator.yml
- データセットなどを任意の場所に保存した方は、上記設定ファイルに以下の項目を設定して下さい。
name
:生成される解答テキストファイルの保存先eval_data
:評価したい変換後のデータセットへのパス(=評価データ)checkpoint_dir
:name
ディレクトリが作成されるディレクトリのパス(デフォルト:使用する Reader モデルが保存されているディレクトリ)model_path
:使用する Reader モデルが保存されているディレクトリへのパス
- デフォルトでは出力した解答候補の生成確率が 85.0% 以上であるときに、その候補を解答とする(=早押しボタンを押すことに対応)仕様になっていますが、上記設定ファイルの以下の項目の値を変更することで、生成確率に対する閾値を変更することができます。
threshold_probability
:早押しボタンを押すための、解答候補の生成確率に対する閾値
学習済み生成モデルにより、解答を生成します。
下記スクリプトを実行することで、質問に対する解答をReaderが生成します。
モデルが早押しボタンを押さないと判断した場合、解答としてnull
が出力されます。
なお、運営の実行環境(NVIDIA GeForce GTX 1080 Ti x1)では、第4回開発データに対する解答の生成に約6時間半を要しました。
# 実行例
$ bash generators/fusion_in_decoder/scripts/test_generator.sh generators/fusion_in_decoder/configs/test_generator.yml
# 実行結果
$ ls ${checkpoint_dir}/${name}
final_output.jsonl # 生成された解答が出力されたファイル
- 関連文書の上位 60 件の文書を用いた時の、第4回開発データに対する解答出力の例
# 例
$ head -n 5 ${checkpoint_dir}/${name}/final_output.jsonl
{"qid": "AIO04-0001", "position": 1, "prediction": null, "generated": "2", "score": 75.48603415489197}
{"qid": "AIO04-0001", "position": 2, "prediction": null, "generated": "", "score": 85.75647473335266}
{"qid": "AIO04-0001", "position": 3, "prediction": null, "generated": "ローマ", "score": 55.69896697998047}
{"qid": "AIO04-0001", "position": 4, "prediction": null, "generated": "広島", "score": 80.89383840560913}
{"qid": "AIO04-0001", "position": 5, "prediction": "終戦", "generated": "終戦", "score": 95.80135345458984}
早押し設定に対応した評価スクリプトcompute_score.py
を実行し、開発データに対する生成結果の評価を行います。
$ python compute_score.py \
--prediction_file ${checkpoint_dir}/${name}/final_output.jsonl \
--gold_file retrievers/DPR/datasets/aio_04_dev_v1.0.jsonl \
--limit_num_wrong_answers 3
引数の説明は以下の通りです。
--limit_num_wrong_answers
:1つの問題に対して、この引数で渡した回数誤答した場合、その問題は得点なしとして計算されます。
評価スクリプトが正しく実行された場合、以下のような出力が得られます。
# 出力例
num_questions: 500
num_correct: 228
num_missed: 253
num_failed: 19
accuracy: 45.6%
accuracy_score: 228.000
position_score: 75.151
total_score: 303.151
出力の説明は以下のとおりです。
num_questions
:評価データの問題数num_correct
:正解数num_missed
:誤答は--limit_num_wrong_answers
回未満だが、正解を出力できなかった問題数num_failed
:誤答を--limit_num_wrong_answers
回以上した問題数accuracy
:正解率accuracy_score
:正解数に対する得点(正解数×1.0点)position_score
:早押しボタンを押した時点に応じた得点total_score
:総合得点(accuracy_score
とposition_score
の総和)
スコアの詳細については、第4回AI王 web サイトの早押し解答部門「スコアの算出方法」もご参照ください。
- Docker コンテナの内側にいる状態の場合は、一度コンテナを停止します。
# コンテナを停止する
$ exit
- コンテナの外にいる状態で、Dockerfile の内容を変更します。
# "aio4-fid-baseline"ディレクトリに移動する
$ cd {path_of_the_cloned_directory}/aio4-fid-baseline
$ vim Dockerfile
- Dockerfile の末尾でコメントアウトされている
CMD
を有効にします。
CMD ["uvicorn", "prediction_api:app", "--host", "0.0.0.0", "--port", "8000"]
- Dockerfile の書き換えが完了したら、以下の手順を参考にDockerコンテナを起動します。
# Docker イメージのビルド
$ docker image build --tag aio4_fid:api .
# コンテナの起動
$ docker container run \
--name fid_baseline \
--rm \
--gpus all \
--publish 8000:8000 \
--mount type=bind,src=$(pwd),dst=/app \
aio4_fid:api
- 次に、上記コンテナを起動した端末のウィンドウとは別のウィンドウを開きます。
- 別のウィンドウ上で、第4回AI王のリーダーボード用データに対して、下記のコマンドで解答ファイルが生成できることを確認します。
- なお、reader が早押しボタンを押すための、解答候補の生成確率に対する閾値は、
prediction_api.py
内のTHRESHOLD_PROBABILITY
で設定が可能です。
- なお、reader が早押しボタンを押すための、解答候補の生成確率に対する閾値は、
# clone した "aio4-fid-baseline" ディレクトリに移動する
$ cd {path_of_the_cloned_directory}/aio4-fid-baseline
# リーダーボード用データを移動させる
$ mkdir data
$ mv retrievers/DPR/datasets/aio_04_test_lb_unlabeled_v1.0.jsonl data/.
# 実行例
$ python3 -m evaluate_docker_api \
--test_unlabelded_file data/aio_04_test_lb_unlabeled_v1.0.jsonl \
--output_prediction_file work/aio_04_test_lb_prediction_v1.0.jsonl
--output_prediction_file
で指定したファイルが生成されていることを確認します。
$ ls work
aio_04_test_lb_prediction_v1.0.jsonl
- 学習データに含まれるクイズ問題の著作権は abc/EQIDEN 実行委員会 に帰属します。東北大学において研究目的での再配布許諾を得ています。
- 開発データは クリエイティブ・コモンズ 表示 - 継承 4.0 国際 ライセンスの下に提供されています。
- 開発/評価用クイズ問題は 株式会社キュービック および クイズ法人カプリティオ へ依頼して作成されたものを使用しております。