006. 딥러닝 공부 3일차 2
잡설
결국 내 처음부터의 목표는 졸업논문이다.
이 프로젝트에서 다루고자 했던 것은 게임의 세계관? 스토리등에 대해서 모두 학습시킨 모델을 가지고 NPC와 대화를 할 수 있게 만드는 것이 최종 목표인데, 게임의 세계관을 내가 직접 짜기엔 데이터셋이 부족하므로 League of legend의 세계관 데이터들을 가져다가 튜닝해서 만들어보는 것을 목표로 정했다.
근데 이거 Fine-Tunning으로 되는거겠지? Pre-trained모델 그대로 써도 되는거겠지? 엄청 불안함 ㅋㅋㅋㅋ....
이번 책을 읽기 전에도 바로 NLP를 조금이라도 시작할 수 있으면 시작해보려고 BERT, ALBERT, T5 뭐 이런 것들을 좀 찾아봤는데, Transformers라는 라이브러리가 나오고, 문장은 파악 잘하는데 생성이 안되고, 파악은 못하는데 생성이 좋고 뭐 이런 내용들 보고 이게 뭘까... 했었는데 이제야 조금씩 이해가 되기 시작했다.
적어도 16일까지는 사전지식 다 습득해놓고 싶은데... 점점 이해속도가 느려진다... 문과란...
BERT 구조에서
L : Layers ( 인코더의 개수 )
A : Attention ( 각 Multi-head Attention에서 사용하는 어텐션 개수 )
H : Hidden ( 피드포워드 네트워크에서 사용되는 Dense 유닛의 개수 )
즉 BERT-tiny는 2L_2A_128H이므로 2개의 인코더, 2개의 어텐션, 128개의 유닛으로 구성된다.
이번 글도 지난번 글에서 읽던 책 '구글 BERT의 정석'을 마저 읽는 과정이다.
1. BERT에 데이터 입력하기
[Wordpiece Tokenizer]
워드피스 토크나이저를 통해 단어를 subword로 분할한다.
각 단어를 subword로 분할하고, 어휘 사전에 포함되는지를 계속 체크하면서 OOV를 최소화 하는 과정이다.
모델의 vocab.txt에 보면 ##~~와 같이 ##이 붙어있는 단어들이 앞단어에 붙어서 표현되는 subword이다.
(한글로 따지면 사랑의 매 -> 사랑 + ##의 + 매 와 같이 분할되는 것이다.)
[Token Embedding]
입력하려는 데이터를 토큰화 하고, 첫 문장의 시작부분에 [CLS], 각 문장의 끝에는 [SEP]를 넣는다.
[Segment Embedding]
[Sep]와는 별개로 문장을 구분하기 위한 임베딩이다.
[Position Embedding]
각 토큰에 대한 인덱스를 임베딩으로 만든다.
이렇게 wordpiece로 토큰화한 문장에 3가지 임베딩을 더하여 BERT에 입력하게 된다.
2. 사전 학습 전략
- 마스크 언어 모델링 (Masked Language Modelling)
BERT는 자동 인코딩 언어 모델로, 예측을 위해 예측하려는 단어의 앞 뒤를 모두 읽어서 예측한다.
즉, 주어진 문장의 일부를 무작위로 마스킹 한 뒤, 마스킹 된 단어의 앞 뒤 문맥을 통해 마스킹 된 단어가 무엇인지 예측한다.
이와 같은 과정을 거쳐 Pre-train된 모델은 Fine-tunning에 입력될 값에는 [MASK]가 없어서 불일치가 생긴다.
여기서 발생하는 문제점을 줄이기 위해 무작위로 선정된 토큰들에 대해
80%는 [MASK]로 변환
10%는 임의의 다른 토큰으로 변환
10%는 변경하지 않음
의 규칙을 수행한다.
이후 인코더를 모두 지난 결과에서 MASK가 무슨 단어로 예측되는지에 대한 확률을 얻는다.
- 전체 단어 마스킹 (Whole Word Masking)
마스킹된 단어가 어떤 한 단어의 subword라면, 그 단어 전체를 마스킹하는 방식이다.
이후 마스킹 비율을 유지하기 위해 몇몇 단어의 마스킹을 해제한다.
- 다음 문장 예측 (Next Sentence Prediction)
각 문장에 대해 현재 문장이 이전 문장의 후속 문장일 경우, 이 문장 쌍에 isNext 혹은 notNext로 표시한다.
이를 통해 문장간의 관계를 이해할 수 있다.
이를 수행하는 데이터셋은 isNext와 notNext 데이터의 비율을 50/50으로 맞춰주는 것이 좋다.
NSP는 이진 분류 작업이고, 예측 결과는 CLS에 들어간다.
BERT는 NSP와 MLM을 동시에 사용하면서
beta_1 = 0.9, beta_2 = 0.999, adam optimizer으로 진행된다.
또한, 모든 레이어에 dropout=0.1이 적용되고,
웜업스텝을 이용해 학습률은 0부터 0.0001로 1만스텝동안 선형적으로 증가한다.
활성화 함수는 GELU(Gaussian Error Linear Unit)을 사용하는데, 먼소린지는 잘 모르겠다.
표준 가우시안 누적 분포? 이게 뭐람
- BPE ( Byte-Pair Encoding )
이전 글에서 올렸던 유튜브 영상에서도 소개 됬던 개념으로 기억하는데,
데이터셋 내 모든 단어들이 같이 등장하는 빈도수를 통해 단어를 분할하는 방법이다.
예를들어 play와 played가 같이 사용되고 enjoy와 enjoyed가 같이 사용되면,
같이 등장하는 빈도를 통해 play, enjoy, ##ed로 분할할 수 있을 것이다.
wordpiece는 BPE와는 조금 다르게 빈도가 아니라 가능도?를 사용해 분할/병합한다.
3. 특징 추출
책 챕터상 pre-train에 대해서도 살짝 알아봤지만, 결국 내가 해야되는건 fine-tunning이다.하지만 파인 튜닝 전에 특징 추출기에 대한 챕터가 있으니 이것부터 해보자.
먼저 문장을 토큰형식으로 처리하고 길이을 맞추기 위해 post방식으로 [PAD]토큰을 추가한다.그리고 [PAD]토큰이 실제 문장이 아님을 모델에게 알리기 위해 어텐션 마스크를 추가한다.(실제 문장은 1, 패딩은 0으로 설정한다)
이렇게 전처리가 완료되면tokenizers.covert_tokens_to_ids(tokens)로 모델에 맞춰 토큰화를 진행하고토큰 배열과 마스크에 대해 tensor로 만든 뒤 squeeze(0)을 해준다. (배치 차원 제거)model(토큰, attention_mask=어텐션마스크, return_dict=False)를 통해 은닉층 정보를 얻는다.
4. 파인튜닝
드디어 기다리던 파인튜닝...이지만 별 내용 없었다... 참조하는 라이브러리는 업데이트 되지않아 참조 오류를 일으키고...후.. 일단 더 읽고 생각해봐야겠다..