# 2022 인공지능 온라인 경진대회 - 문서 검색 효율화를 위한 기계독해 문제 ### 1st Ranked (Team: TUNiB) - [Soohwan Kim](https://github.com/sooftware) - [Giseong Lee](https://github.com/gistarrr) - [Donghyeop Son](https://github.com/sonacer) - [Bin Jang](https://github.com/binjang) - [Kijun Kwon](https://github.com/abepy) ## Project Structure ``` /USER/TUNIB_COMPETITION ├── args │   ├── __init__.py │   ├── data_args.py │   ├── logging_args.py │   ├── model_args.py │   └── training_args.py ├── classifier_train │   ├── dataset.py │   ├── train.py │   ├── ensemble.py │   └── trainer.py ├── data │   ├── __init__.py │   ├── make_csv.ipynb │   ├── make_noans.py │   ├── pg.ipynb │   ├── postprocess.py │   ├── processor.py │   └── ratio_data.ipynb ├── data_collator.py ├── ensemble_lstm_add_noans.py ├── ensemble_lstm.py ├── ensemble_mlm.py ├── ensemble_rl.py ├── inference.sh ├── model.py ├── postprocessing.ipynb ├── requirement.sh ├── run_qa_lstm_add_noans.py ├── run_qa_lstm.py ├── run_qa_rl.py ├── run_qa_with_mlm.py ├── running.sh ├── trainer.py └── utils.py ``` - `args/`: 학습에 필요한 데이터 및 전처리를 위한 코드가 있는 디렉토리 - `__init__.py` : 하위 모듈을 import - `data_args.py` : 데이터와 관련된 arguments - `logging_args.py` : wandb와 관련된 arguments - `model_args.py` : 모델과 관련된 arguments - `training_args.py` : 학습과 관련된 arguments - `classifier_train/`: 분류기를 위한 모델을 학습할 코드와 앙상블을 할 코드가 있는 디렉토리 - `dataset.py`: 학습에 맞게 데이터를 처리하는 코드 - `train.py`: 모델을 학습하기 위한 코드 - `ensemble.py`: 앙상블 인퍼런스 로직이 정의된 파일 - `trainer.py`: 모델을 학습시키기 위한 Trainer 클래스가 정의된 파일 - `data/`: 학습에 필요한 데이터 및 전처리를 위한 코드가 있는 디렉토리 - `__init__.py` : 하위 모듈을 import - `make_csv.ipynb` : 주어진 데이터를 csv로 변형(train, valid, test) - `make_noans.py` : 질문을 섞어 No answer Data를 생성하는 파일 - `pg.ipynb` : pororo PG를 활용해 No answer의 질문만 변형하는 파일 - `postprocess.py` : 모델 추론 후 후처리와 관련된 파일 - `processor.py` : 모델 학습을 위한 전처리 함수가 정의된 파일 - `ratio_data.ipynb` : answer와 noanswer의 비율을 맞춘 Data를 생성하는 파일 - `data_collator.py`: MLM loss를 추가한 Model을 위해 정의한 data collator 파일 - `ensemble_*`: 해당 모델들의 checkpoint ensemble을 수행하는 파일 - `inference.sh`: 추론을 위한 script가 정의된 파일 - `model.py`: 모델이 정의되어 있는 파일 - `postprocessing.ipynb`: Reader를 통해 나온 결과에 후처리를 적용하는 파일(조사 제거, 분류기 부착) - `requirement.sh`: 프로그램 실행을 위해 필요한 패키지를 설치해주는 shell script - `run_qa_*`: 해당 모델들의 학습을 수행하는 파일 - `running.sh`: 학습을 위한 script가 정의된 파일 - `trainer.py`: 학습에 필요한 Trainer가 정의된 파일 - `utils.py`: config 설정을 위한 함수가 정의되어 있는 파일 ## Installation 학습에 필요한 라이브러리를 설치합니다. 재현 서버에 이미 환경설정을 마친 상태입니다. ## Pre-trained Weight를 이용한 최종 제출 파일 재현 방법 - PLM Weight는 `/USER/PLM_WEIGHT` 내부에 있습니다. - 최종 제출 파일은 `/USER/submission` 에 `최고점.csv` 로 있습니다. - PLM Weight 파일을 이용하여 아래의 "3. Ensemble" 부분부터 MODEL_PATH만 바꿔가며 진행해 주시면 됩니다 (MODEL_PATHs는 초기에 PLM Weight 기준으로 되어 있습니다) - output 파일을 덮어씌우지 않으려면 inference.sh에서 output_dir를 변경해 주세요 ## 주최측 제공 데이터부터 시작하여 최종 제출 파일 재현 방법 ## 1. Data Preparation - 데이터 오그멘테이션 및 학습을 위한 파일들을 준비합니다. - train, validation 데이터셋 구성, 데이터 오그멘테이션 등이 포함되어 있습니다. - 해당 작업은 수 시간이 소요될 수 있습니다. - 해당 파이썬 파일을 실행한 결과는 `/USER/data/inputs/` 폴더에 저장됩니다. - `pg.py`를 사용할 때는 "nlp" 라는 이름의 가상환경을 사용하셔야 합니다. - Run: ``` make_csv.ipynb make_noans.py pg.py ratio_data.ipynb ``` ## 2. Training - 앙상블을 위해 각 모델들을 학습합니다. Out-Of-Memory 에러가 나는 경우 `per_device_train_batch_size`의 인수를 절반, `gradient_accumulation_steps`의 인수를 2배로 늘려주시면 됩니다. - `output_dir` 인자를 통해 모델 checkpoint가 저장될 path를 지정하면 됩니다. ### Reader Model #1 - full_lstm - running.sh에 있는 첫번째 스크립트 실행 - Roberta-large에 lstm 레이어를 추가하여 validation 없이 전체 학습한 모델 ``` $ cd /USER/TUNIB_COMPETITION $ python run_qa_lstm.py \ --model_name_or_path klue/roberta-large \ --output_dir /USER/MODEL/reader/full_lstm \ --overwrite_output_dir \ --preprocessing_num_workers 4 \ --do_train \ --learning_rate 3e-5 \ --num_train_epochs 2 \ --per_device_train_batch_size 4 \ --gradient_accumulation_steps 4 \ --per_device_eval_batch_size 32 \ --weight_decay 1e-4 \ --max_seq_length 512 \ --max_answer_length 40 \ --save_strategy epoch \ --lstm_model \ --full_training \ --fp16 ``` ### Reader Model #2 - lstm_ep2_clean_add_noans - running.sh에 있는 두번째 스크립트 실행 - Roberta-large에 lstm 레이어를 추가하고 정답 없음 문제들을 paraphrase generation을 통해 추가 증강하여 학습시킨 모델 ``` $ cd /root/competition $ python run_qa_lstm_add_noans.py \ --model_name_or_path klue/roberta-large \ --output_dir /USER/MODEL/reader/lstm_ep2_clean_add_noans \ --overwrite_output_dir \ --preprocessing_num_workers 4 \ --do_train \ --learning_rate 3e-5 \ --num_train_epochs 2 \ --per_device_train_batch_size 4 \ --gradient_accumulation_steps 4 \ --per_device_eval_batch_size 32 \ --weight_decay 1e-4 \ --max_seq_length 512 \ --max_answer_length 40 \ --save_strategy epoch \ --lstm_model \ --fp16 ``` ### Reader Model #3 - rl_pg_permute_noans - running.sh에 있는 세번째 스크립트 실행 - Roberta-large에 paraphrase generation로 증강한 데이터와 같은 title 내의 지문을 permute하여 증강한 데이터를 추가하여 학습한 모델 ``` $ cd /USER/TUNIB_COMPETITION $ python run_qa_rl.py \ --model_name_or_path klue/roberta-large \ --output_dir /USER/MODEL/reader/rl_pg_permute_noans \ --overwrite_output_dir \ --preprocessing_num_workers 4 \ --do_train \ --learning_rate 3e-5 \ --num_train_epochs 2 \ --per_device_train_batch_size 4 \ --gradient_accumulation_steps 4 \ --per_device_eval_batch_size 32 \ --weight_decay 1e-4 \ --max_seq_length 512 \ --max_answer_length 40 \ --save_strategy epoch \ --fp16 ``` ### Reader Model #4 - 4ep_ans_mlm_all_ensem - running.sh에 있는 네번째 스크립트 실행 - 지문에 masking을 추가하여 해당 mask token을 예측하는 MLM loss를 추가한 모델 ``` $ cd /USER/TUNIB_COMPETITION $ python run_qa_with_mlm.py \ --model_name_or_path klue/roberta-large \ --output_dir /USER/MODEL/reader/4ep_ans_mlm_all_ensem \ --overwrite_output_dir \ --preprocessing_num_workers 4 \ --do_train \ --learning_rate 1e-5 \ --num_train_epochs 3 \ --per_device_train_batch_size 4 \ --gradient_accumulation_steps 4 \ --per_device_eval_batch_size 32 \ --weight_decay 1e-4 \ --max_seq_length 512 \ --max_answer_length 30 \ --save_strategy epoch \ --fp16 ``` ### Classifier Model #1 - tunib-electra-ko-base - running.sh에 있는 다섯번째 스크립트 실행 - tunib-electra-ko-base에 정답 비정답 비율이 같은 데이터로 학습 ``` $ cd /USER/TUNIB_COMPETITION $ /classifier_train/train.py \ --save_dir /USER/MODEL/classifier/classific_tunib-electra-ko-base \ --pretrain_model_name_or_path tunib/electra-ko-base \ --batch_size 32 \ --lr 2e-05 \ --num_epochs 1 ``` ### Classifier Model #2 - klue-roberta-Large - running.sh에 있는 여섯번째 스크립트 실행 - klue-roberta-Large에 정답 비정답 비율이 같은 데이터로 학습 ``` $ cd /USER/TUNIB_COMPETITION $ python /classifier_train/train.py \ --save_dir /USER/MODEL/classifier/classific_klue-roberta-large \ --pretrain_model_name_or_path klue/roberta-large \ --batch_size 4 \ --lr 2e-05 \ --num_epochs 1 ``` ## 3. Ensemble - 학습된 모델들을 이용해서 앙상블 예측을 합니다. - `output_dir` 인자를 통해 json, csv 파일 등의 저장경로를 설정하시면 됩니다. ### Reader Ensemble #1 - full_nt_lstm - inferense.sh 파일의 첫번째 스크립트 실행 - 첫번째 Reader Model의 학습 체크포인트 2개 앙상블 - 각 파일별 경로를 설정해주시면 됩니다. ``` $ cd /USER/TUNIB_COMPETITION $ python ensemble_lstm.py \ --test_file test.json \ --output_dir /root/competition/submission_ensemble/full_nt_lstm \ --overwrite_output_dir \ --preprocessing_num_workers 4 \ --do_predict \ --per_device_eval_batch_size 32 \ --max_seq_length 512 \ --max_answer_length 30 ``` ### Reader Ensemble #2 - lstm_ep2_clean_add_noans - inferense.sh 파일의 두번째 스크립트 실행 - 두번째 Reader Model의 학습 체크포인트 2개 앙상블 ``` $ cd /USER/TUNIB_COMPETITION $ python ensemble_lstm_add_noans.py \ --test_file test.json \ --output_dir /root/competition/submission_ensemble/lstm_ep2_clean_add_noans \ --overwrite_output_dir \ --preprocessing_num_workers 4 \ --do_predict \ --per_device_eval_batch_size 32 \ --max_seq_length 512 \ --max_answer_length 30 ``` ### Reader Ensemble #3 - rl_pg_permute_noans - inferense.sh 파일의 세번째 스크립트 실행 - 세번째 Reader Model의 학습 체크포인트 2개 앙상블 ``` $ cd /USER/TUNIB_COMPETITION $ python ensemble_rl.py \ --test_file test.json \ --output_dir /root/competition/submission_ensemble/rl_pg_permute_noans \ --overwrite_output_dir \ --preprocessing_num_workers 4 \ --do_predict \ --per_device_eval_batch_size 32 \ --max_seq_length 512 \ --max_answer_length 30 ``` ### Reader Ensemble #4 - 4ep_ans_mlm_all_ensem - inferense.sh 파일의 네번째 스크립트 실행 - 네번째 Reader Model의 학습 체크포인트 4개 앙상블 ``` $ cd /USER/TUNIB_COMPETITION $ python ensemble_mlm.py \ --test_file test.json \ --output_dir /root/competition/submission_ensemble/4ep_ans_mlm_all_ensem \ --overwrite_output_dir \ --preprocessing_num_workers 4 \ --do_predict \ --per_device_eval_batch_size 32 \ --max_seq_length 512 \ --max_answer_length 30 ``` ### Classifier Ensemble #1 - 분류기 앙상블 - klue-roberta-large의 학습 체크포인트 2개와 tunib-electra-ko-base의 학습체크포인트 1개를 앙상블 - /USER/TUNIB_COMPETITION/classifier_train/ensemble.py의 model_path부분에 /USER/MODEL/classific_klue-roberta-large의 EPOCH 하나와 가장 높은 BEST_CKPT /USER/MODEL/classific_tunib-electra-ko-base의 EPOCH 하나의 경로를 입력 한뒤 실행합니다. - weight 측정시에는 /USER/TUNIB_COMPETITION/classifier_train/ensemble.py의 model_path부분에 /USER/PLM_WEIGHT/classifier/에 있는 BEST_CKPT세개의 경로를 입력 한뒤 실행 하고 no_check.to_csv 경로를 /USER/classifier/plm_weight_classification.csv로 변경 ``` $ cd /USER/TUNIB_COMPETITION/ $ python /classifier_train/ensemble.py \ ``` ## 4. Postprocessing - 추론 결과에 대해 후처리를 진행합니다. - Majority voting Ensemble 진행 - 불필요한 조사 제거 - 분류기 예측 결과 적용 ``` $ cd /USER/TUNIB_COMPETITION/ ``` - `postprocess.ipynb`를 코드블럭 순서에 맞춰 실행해주시면 됩니다. - Ensemble 시 지정된 `output_dir` 내부에 생성된 파일을 이용해 Majority voting을 진행합니다. - `/USER/submission/result.csv` 해당 경로에 최종 결과가 생성됩니다. ## Contact 위 내용에 오류가 있거나 문의사항이 있는 경우 kaki.ai@tunib.ai 혹은 tori.ai@tunib.ai 로 연락 부탁드립니다.