[AIAI 2022] ParlAI 실습

Minhan Cho·2023년 5월 11일
0

이론강의

Dialogue Systems 개괄

  • task oriented dialogue system: 문제 해결을 위함, 최대한 적은 대화로 이용자가 원하는 것을 이해하고 해결하는 것이 핵심
  • open-domain dialogue system: 자유로운 대화, 최대한 긴 대화를 하는 것이 핵심

How to build ODDS

  • reponse generation(seq2seq, transformer families): token 하나씩 생성, unseen task에도 대응 가능
  • response selection(bi-encoder 등)

Possible Issues of Response Generation

  • bland response: maximum likelihood를 기반으로 학습하기 때문에 자주 등장하는 평이하고 재미없는 답변이 나올 확률을 높임
  • corpus에 많은 사람들의 dialogue가 있으므로 일관성 있는 캐릭터(persona)를 갖기 어려움
  • 오랜 기간 나에 대한 기억을 잊지 않는 게 가능할까? (long term conversation): Meta의 Blender Bot

Response Selection

  • 연산량이 적고 빠름: IR과 맥이 닿아있음
  • embedding 사전에 만듦 -> filtering을 거쳐서 후보를 만듦 -> 문맥에 대한 정보와 후보의 유사도 측정
    • dialogBERT나 BERT 등 이용해 bi-encoder, cross-encoder, poly-encoder 등 구조 사용
    • bi-encoder에서 candidates는 미리 embedding 뽑을 수 있어서 속도가 빠르므로 실제 서비스에서 사용되는 빈도가 높음
    • cross-encoder: context와 candidates를 한 번에(concat) 인코딩하여 점수를 구함, 성능이 높지만 후보가 많아질수록 속도가 느려짐 (서비스 거의 불가)
    • poly-encoder: 앞의 둘을 합쳐놓음,

seq2seq

  • 하나의 domain text를 다른 domain text로 바꾸는 것
  • encoder-decoder 구조: response generation으로 보면 됨

BlenderBot

  • 모르는 정보는 검색해서 생성: static하지 않음
  • GPT3보다 좋은 성능
  • transformer seq2seq 구조

ParlAI

  • 다양한 태스크에 대해 대화 모델을 학습하고 평가하는 플랫폼
  • 장점:
    • Meta에서 나온 모든 모델이 있음: Meta가 대화모델을 많이 연구함
    • 데이터가 굉장히 많음
    • pretrained model 불러오는 과정이 간단함
    • AMTurk와 연동 쉬움
    • facebook messenger와 연동 가능
    • multimodal 지원

Dialogue Systems Evaluation

  • generation: BLUE, ROUGE, perplexity
  • selection: precision@k, recall@k etc.

번외: Poly Encoder

Humeau, S., Shuster, K., Lachaux, M. A., & Weston, J. (2019). Poly-encoders: Transformer architectures and pre-training strategies for fast and accurate multi-sentence scoring. arXiv preprint arXiv:1905.01969.

code: https://github.com/chijames/Poly-Encoder (ParlAI에서도 poly-encoder를 쓸 수는 있는데, 보기 좋은 코드는 위를 확인하는 게 좋을 듯)

  • 이전에 query-candidate의 유사도를 계산하는 방법 2가지: bi-encoder, cross-encoder
    • bi-encoder: candidates를 먼저 encoding해서 caching할 수 있으나, 성능이 떨어짐
    • cross-encoder: query와 candidate을 모두 합쳐서 self attention을 줄 수 있으나, 성능이 매우매우 느림

  • bi-encoder: context(query)와 candidate을 각각의 transformer에 encoding하여 reducing -> dot product해서 score 계산
  • cross-encoder: context와 candidate concat해서 transformer에 통과시키고 reducing해서 scalar 계산

  • poly-encoder: Bi-encoder와 cross-encoder의 짬뽕
    • candidates는 미리 encoding해서 caching할 수 있음
    • 다만, context를 하나의 vector representation 대신 multiple vector representation(yctxt1,...,yctxtmy_{ctxt}^1, ..., y_{ctxt}^m)으로 만들고, 각각의 yy는 context의 hidden represenation을 모두 참조 (global features)
    • mm개의 yy를 구하기 위해 mm개의 attention을 사용(보통 mm < sequence length): 논문에서 이는 mm context codes (c1,...,cmc_1, ..., c_m)을 이용해서 구할 수 있음

      (w1ci,...,wNci)=softmax(cih1,...,cihN)(w_1^{c_i},...,w_N^{c_i}) = softmax(c_i \cdot h_1, ..., c_i \cdot h_N)
      yctxti=jwjcihjy_{ctxt}^i = \sum_jw_j^{c_i}h_j

    • mm개의 global context feature에 대해 query로 ycandiy_{cand_i}를 줘서 attention을 계산할 수 있음, hih_i는 top layer output

      (w1,...,wm)=softmax(ycandiyctxt1,...,ycandiyctxtm)(w_1,...,w_m) = softmax(y_{cand_i} \cdot y_{ctxt}^1,..., y_{cand_i} \cdot y_{ctxt}^m)
      yctxt=iwiyctxtiy_{ctxt} = \sum_iw_iy^i_{ctxt}

    • 최종 score는 yctxtycandiy_{ctxt} \cdot y_{cand_i}로 계산됨
  • 위와 같은 encoder는 dialog와 IR에서 사용되므로, 실험 task는 크게 2개 type: Dialog(Neurips ConvAI2 competition, DSTC7 challenge track 1, Ubuntu V2 corpus) & IR(Wikipedia Article Search task)
  • result
    • bi-encoder보다는 높은 성능, cross-encoder보다는 빠른 성능
    • pretraining에 쓰인 corpus가 무엇이냐에 따라 downstream task 성능이 바뀜

Code

ParlAI

  • DisplayData 커맨드를 이용해 txt, json 파일 등을 좀 더 보기 쉽게 제공받을 수 있음

  • __Silence__ token: 대화가 시작함을 의미하는 token

  • ODDS에서는 화자가 2명이므로 각각을 모델이 학습하여 한 대화를 이용해 2배의 학습데이터로 쓸 수 있음

  • DisplayData

# notebook
from parlai.scripts.display_data import DisplayData
DisplayData.main(task = "blended_skill_talk", num_examples = 5, datatype = "test")

# terminal
!parlai display_data --task personachat --num-examples 5
  • 그런데 데이터 저장은 어떻게 하는거지..?

  • TrainModel from scratch

-rm -rf from_scratch_model
~mkdir -p from_scratch_model

from parlai.scripts.train_model import TrainModel
TrainModel.main(
    # 모델을 저장할 경로를 반드시 적어야합니다
    model_file='from_scratch_model/model',
    # dailydialog 데이터셋에 대해 학습합니다
    task='dailydialog',
    # 학습 시간은 1분으로 제한하고, batchsize는 16으로 지정하겠습니다
    # max_train_time=60,
    num_epochs=2, # num_epoch parameter 있더라
    batchsize=16,
    
    # 모델 타입은 seq2seq로 지정해줍니다
    model='seq2seq',
    # 이후의 선택은 hyperparameter입니다
    # 오늘 실습에서는 attention을 사용합니다
    # embedding_type='fasttext',를 지정해주면 pretrained embedding도 사용할 수 있지만
    # 다운로드에 시간이 걸리므로 오늘 실습에서는 생략하도록 하겠습니다
    attention='dot',
    # encoder/decoder/softmax 레이어에서 word embedding을 공유하도록 합니다
    lookuptable='all',
    # 메모리와 시간을 아끼기 위해서 text와 label을 64토큰에서 자릅니다
    truncate=64,
)
  • generative model은 규모가 커서 3-4 epoch 정도, response selection model은 8 epoch 정도 돌린다고 함

  • 그런데 seq2seq이긴 한데 encoder와 decoder는 무엇을 쓰는지?

  • TrainModel finetuning

!rm -rf from_pretrained
!mkdir -p from_pretrained
from parlai.scripts.train_model import TrainModel

TrainModel.main(
    # 이전에 학습시킬때와 거의 동일합니다
    task='empathetic_dialogues', 
    model='transformer/generator',
    model_file='from_pretrained/model',
    
    # pretrained model로 initialize합니다
    init_model='zoo:tutorial_transformer_generator/model',
    
    # pretrained model을 사용하기위한 argument입니다
    # 이는 모델의 종류에 따라 다르게 설정해주어야 합니다
    n_heads=16, n_layers=8, n_positions=512, text_truncate=512,
    label_truncate=128, ffn_size=2048, embedding_size=512,
    activation='gelu', variant='xlm',
    dict_lower=True, dict_tokenizer='bpe',
    dict_file='zoo:tutorial_transformer_generator/model.dict',
    learn_positional_embeddings=True,
    
    # fine-tuning에 사용되는 training argument입니다 
    # Adam optimizer와 작은 learning rate를 사용하도록 하겠습니다
    lr=1e-5, optimizer='adam',
    warmup_updates=100,
    # perplexity를 사용하여 validation하도록 합니다
    validation_metric='ppl',
    # 이번에도 이전과 동일하게 1분 학습시키도록 하겠습니다
    # validation은 0.25에폭마다 진행합니다
    max_train_time=60, validation_every_n_epochs=0.25,
    
    # 이 argument는 gpu에 맞게 설정해주시면 됩니다
    batchsize=12, fp16=True, fp16_impl='mem_efficient',
    
    # validation을 빠르게 하기 위해서 설정하는 argument입니다
    skip_generation=True,
    
    # gpu에서 한번에 최대한의 예시를 볼 수 있도록 설정합니다
    dynamic_batching='full',
)
  • init_model: ParlAI의 model zoo에서 나온 링크 참고
  • 모델의 학습 결과 확인
from parlai.scripts.display_model import DisplayModel
DisplayModel.main(
    task='dailydialog',
    model_file='/content/from_scratch_model/model',
    num_examples=2,
)
  • generative model: 학습 데이터에서 많이 나온 sequence (Oh no 등) 가 많이 나옴

  • model interaction: Interactive

from parlai.scripts.interactive import Interactive

Interactive.main(
    model_file='zoo:tutorial_transformer_generator/model'
)
profile
multidisciplinary

0개의 댓글