Search
Duplicate

lightning-transformers로 살펴본 Hydra 어플리케이션 구성

Created
7/4/2021, 9:02:00 AM
Tags
implementation
Hydra
Config
lightning-transformers
일시
2021/06/11
글쓴이
hyungjun.kim
✅main
포스팅 종류
코드구현
이번 편에서는 간단한 예제로 살펴본 Hydra를 이용한 어플리케이션 구성 내용에 이어 lightning-transformers을 사례를 보면서 정리해보겠습니다.
conf/ ┣ backbone/ # Configs defining the backbone of the model/pre-trained model if any ┣ dataset/ # Configs defining datasets ┣ optimizer/ # Configs for optimizers ┣ scheduler/ # Configs for schedulers ┣ task/ # Configs defining the task, and any task specific parameters ┣ tokenizer/ # Configs defining tokenizers, if any. ┣ trainer/ # Configs defining PyTorch Lightning Trainers, with different configurations ┣ training/ # Configs defining training specific parameters, such as batch size. ┗ config.yaml # The main entrypoint containing all our chosen config components
YAML
먼저 가장 기본이 되는 config.yaml을 정의합니다. 아래의 예시를 보면 lightning-transformers에서는 conf/config.yaml에서 defaults로 task, optimizer, scheduler, training, trainer로 하위 계층 구조를 정의하고 있습니다.
defaults: # loads default configs - task: default - optimizer: adamw - scheduler: linear_schedule_with_warmup - training: default - trainer: default experiment_name: ${now:%Y-%m-%d}_${now:%H-%M-%S} log: False ignore_warnings: True # todo: check warnings before release
YAML
주) now는 Hydra에서 미리 등록되어 사용할 수 있습니다. https://github.com/facebookresearch/hydra/blob/master/hydra/core/utils.py#L185
다음으로 conf/task/default.yaml를 살펴보면, package와 _group_ 개념이 사용되고 있습니다.
conf/task/default.yaml
# @package task defaults: - /dataset@_group_: default # By default we turn off recursive instantiation, allowing the user to instantiate themselves at the appropriate times. _recursive_: false _target_: lightning_transformers.core.model.TaskTransformer optimizer: ${optimizer} scheduler: ${scheduler}
YAML
dataset의 config group을 default로 설정하였기 때문에, conf/dataset/default.yaml을 로드합니다. 또한 optimizer와 scheduler는 각각 conf/config.yaml에서 앞서 정의된 optimizer와 scheduler를 변수로 받습니다. _recursive_ 는 해당 파일에 종속된 다른 config들을 instantiate 할 것인지를 나타냅니다.
대표적인 예로 LanguageModeling를 살펴봅니다.
python train.py task=nlp/language_modeling
train.py를 살펴보면 가장 기본이 되는 conf/config.yaml config_path와 config_name을 정의하고 있습니다.
"""The shell entry point `$ pl-transformers-train` is also available""" import hydra from omegaconf import DictConfig from lightning_transformers.cli.train import main @hydra.main(config_path="./conf", config_name="config") def hydra_entry(cfg: DictConfig) -> None: main(cfg) if __name__ == "__main__": hydra_entry()
Python
conf/config.yaml
defaults: # loads default configs - task: default - optimizer: adamw - scheduler: linear_schedule_with_warmup - training: default - trainer: default experiment_name: ${now:%Y-%m-%d}_${now:%H-%M-%S} log: False ignore_warnings: True # todo: check warnings before release
YAML
이전 편에서 배운 overrding을 살펴봅니다. 예를 들어 Q. batch 사이즈를 바꾸고 싶은데 어떻게 해야할까요? batch 사이즈는 training/default.yaml에 정의되어 있습니다. 따라서 CLI 명령어에 training.batch_size=8 등을 추가하면 변경이 됩니다.
conf/training/default.yaml
run_test_after_fit: True lr: 5e-5 output_dir: '.' # read in dataset batch_size: 16 num_workers: 16
YAML
python train.py task=nlp/language_modeling training.batch_size=8
본격적으로 task에 대해 알아봅니다. 먼저 conf/config.yaml에 의해 conf/task/default.yaml 내용을 입력 받아야 합니다. 그런데, CLI 명령에 의해 conf/task/nlp/language_modeling.yaml로 대체됩니다.
conf/task/nlp/language_modeling.yaml
# @package task defaults: - nlp/default - override /dataset@_group_: nlp/language_modeling/default _target_: lightning_transformers.task.nlp.language_modeling.LanguageModelingTransformer downstream_model_type: transformers.AutoModelForCausalLM
YAML
그런데, 처음 defaults에 의해 conf/task/nlp/default.yaml 필요한 값들을 불러옵니다.
conf/task/nlp/default.yaml
# @package task defaults: - /dataset@_group_: default # By default we turn off recursive instantiation, allowing the user to instantiate themselves at the appropriate times. _recursive_: false _target_: lightning_transformers.core.model.TaskTransformer optimizer: ${optimizer} scheduler: ${scheduler}
YAML
dataset은 conf/dataset/default.yaml 파일을 가져옵니다.
conf/dataset/default.yaml
# @package dataset _target_: lightning_transformers.core.data.TransformerDataModule cfg: # torch data-loader specific arguments batch_size: ${training.batch_size} num_workers: ${training.num_workers}
YAML
그런데, language_modeling은 TransformerDataModule 대신 LanguageModelingTransformer을 사용합니다. 그리고 모형 아키텍쳐 역시 transformers.AutoModelForCausalLM 사용해야합니다. 따라서 CLI 명령어를 통해 python train.py task=nlp/language_modeling 실행이 필요합니다.
conf/nlp/language_modeling.yaml
# @package task defaults: - nlp/default - override /dataset@_group_: nlp/language_modeling/default _target_: lightning_transformers.task.nlp.language_modeling.LanguageModelingTransformer downstream_model_type: transformers.AutoModelForCausalLM
YAML
또한, 데이터셋 역시 그룹을 default(task/nlp/default.yaml에서 정의된)에서 dataset/nlp/language_modeling/default.yaml로 overrding 합니다. 그리고 _target_과 downstream_model_type로 각각 정의되어 있습니다.
override에 관한 자세한 것은 https://hydra.cc/docs/next/advanced/override_grammar/basic/ 참고하시기 바랍니다.
따라서, task=nlp/language_modeling.yaml를 정리해보면 (1) conf/task/nlp/default.yaml에 의해
# @package task defaults: - /task/default - /backbone@_group_: nlp/default # use AutoModel backbone by default - override /dataset@_group_: nlp/default backbone: ${backbone}
YAML
backbone값을 받고, (2) conf/nlp/language_modeling.yaml 에 의해 _target_과 downstream_model_type을 받습니다. 그리고, (3) 최초 conf/task/default.yaml에서 _recuresive_와 optimizer 그리고 scheduler를 가져옵니다. 이때 _target_은 lightning_transformers.task.nlp.language_modeling.LanguageModelingTransformer로 override 되었습니다.
conf/task/default.yaml
# @package task defaults: - /dataset@_group_: default # By default we turn off recursive instantiation, allowing the user to instantiate themselves at the appropriate times. _recursive_: false _target_: lightning_transformers.core.model.TaskTransformer optimizer: ${optimizer} scheduler: ${scheduler}
YAML
이를 task 전체에 대해 정리해보면 다음과 같습니다.
task: _recursive_: false _target_: lightning_transformers.task.nlp.language_modeling.LanguageModelingTransformer optimizer: ${optimizer} scheduler: ${scheduler} backbone: ${backbone} downstream_model_type: transformers.AutoModelForCausalLM
YAML
task는 앞서 살펴본대로 defaults에 의해 backbone과 dataset에도 영향을 줍니다. 먼저 backbone을 살펴보면 tokenizer를 설정하고 pretrained_model_name_or_path를 결정하고 있습니다.
conf/backbone/nlp/default.yaml
# @package backbone defaults: - /tokenizer@_group_: autotokenizer # use AutoTokenizer by default pretrained_model_name_or_path: bert-base-cased
YAML
dataset은 nlp/language_modeling/default.yaml에서
# @package task defaults: - nlp/default - override /dataset@_group_: nlp/language_modeling/default _target_: lightning_transformers.task.nlp.language_modeling.LanguageModelingTransformer downstream_model_type: transformers.AutoModelForCausalLM
YAML
nlp/default로 부터 cfg 다음을 입력 받고,
# @package dataset defaults: - /dataset/default _target_: lightning_transformers.core.nlp.HFDataModule cfg: dataset_name: null dataset_config_name: null train_file: null validation_file: null test_file: null train_val_split: null max_samples: null cache_dir: null padding: 'max_length' truncation: 'only_first' preprocessing_num_workers: 1 load_from_cache_file: True max_length: 128 limit_train_samples: null limit_val_samples: null limit_test_samples: null
YAML
dataset/default로 부터
# @package dataset _target_: lightning_transformers.core.data.TransformerDataModule cfg: # torch data-loader specific arguments batch_size: ${training.batch_size} num_workers: ${training.num_workers}
YAML
위의 cfg를 입력 받습니다.
따라서, 최종적으로 2개의 cfg가 합쳐지며,
dataset: _target_: lightning_transformers.task.nlp.language_modeling.LanguageModelingDataModule cfg: batch_size: ${training.batch_size} num_workers: ${training.num_workers} dataset_name: null dataset_config_name: null train_file: null validation_file: null test_file: null train_val_split: null max_samples: null cache_dir: null padding: max_length truncation: only_first preprocessing_num_workers: 1 load_from_cache_file: true max_length: 128 limit_train_samples: null limit_val_samples: null limit_test_samples: null block_size: null
YAML
_target_은 conf/task/nlp/language_modeling.yaml의 _target_인 lightning_transformers.task.nlp.language_modeling.LanguageModelingDataModule로 변경 됩니다.
또 다른 예제, Causal Language Modeling에서 config와 datasets, 그리고 model 등을 Hydra와 연결하여 잘 설명하고 있습니다.
그렇다면 새로운 흥미로운 예제에 응용을 해볼까요?
최근 한국에서 공개된 KLUE(Korean Language Understanding Evlauation) 데이터가 있습니다. 현재 KLUE 데이터셋과 벤치마크 모형이 오픈소스로 제공되고 있으므로 이를 Hydra와 Ligtning-transformer를 이용하여 학습하는 법에 대해 살펴봅니다.
다양한 TASK 중에서 비교적 손쉬운 KLUE-KNLI 분류 문제(classification)를 다뤄봅니다.
데이터셋은 https://huggingface.co/datasets/viewer/?dataset=klue 에서도 확인할 수 있으며, KLUE 벤치마크 모형은 https://huggingface.co/klue 에서 확인할 수 있습니다.
KLUE 데이터셋은 minho.ryu님과 jungwhank님께서 기여하였습니다. https://github.com/huggingface/datasets/blob/master/datasets/klue/klue.py
ligtning-transformers를 돌아와서 아래의 레포지토리를 install 혹은 clone 합니다.
git clone https://github.com/PyTorchLightning/lightning-transformers
먼저 데이터셋 부터 정의합니다.
nli에 맞게 task를 nlp/text_classification로 설정하고, dataset_name과 dataset_config_name을 정의합니다. 그리고 모형 backbone으로는 klue/bert-base로 설정하고, gpu 갯수와 max_epochs 등 가장 기본적인 파라미터만 셋팅합니다.
python train.py task=nlp/text_classification dataset.cfg.dataset_name=klue dataset.cfg.dataset_config_name=nli backbone.pretrained_model_name_or_path=klue/bert-base trainer.gpus=1 trainer.max_epochs=10
YAML
KLUE-NLI 리더보드에서 KLUE-BERT-base의 ACC는 81.63%로 보고되고 있습니다. 위의 스크립트 실행 결과 약 81.4%의 정확도를 보입니다. 위의 스크립트에서 배치 사이즈와 learning rate, 시퀀스 최대 길이 등을 간단히 변경한 것만으로도 아래의 스크립트로도 벤치마크 성능보다 뛰어난 82%의 정확도를 얻을 수 있습니다.
python train.py task=nlp/text_classification dataset.cfg.dataset_name=klue dataset.cfg.dataset_config_name=nli backbone.pretrained_model_name_or_path=klue/bert-base trainer.gpus=1 trainer.max_epochs=10 training.batch_size=64 training.lr=5e-05 dataset.cfg.max_length=64
YAML
현재 lightning-transformers에서는 text_classification 시 data에서 idx와 label을 제외하고 첫번째 field와 두번째 field를 label을 예측하는 데 사용하고 있습니다.(https://github.com/PyTorchLightning/lightning-transformers/blob/master/lightning_transformers/task/nlp/text_classification/data.py#L59 참조) 따라서 위 코드로 실행 시 데이터셋을 재정의하거나 해당 라인을 아래와 같이 수정한 후 실행하면 됩니다.
zip(example_batch[input_feature_fields[1]], example_batch[input_feature_fields[2]])
다음 편으로는 ligtning-transformer으로 특정 task를 해결하기 위해 tokenizerdatasetmodel 등을 직접 정의하는 방법에 대하여 알아보겠습니다.
본 블로그는 hydra-core==1.1.0rc1lightning-transformers==0.1 버전을 기준으로 작성되었습니다.

References