참고 : Do it! BERT와 GPT로 배우는 자연어처리
3. 숫자 세계로 떠난 자연어
Language Model ( 언어 모델 )
- 단어 시퀀스에 “확률을 부여”하는 모델
- ex) $n$ 개의 단어로 구성 시 : $P(w_1,w_2,…,w_n)$
- 조건부 확률로 분해해서 쓰면 :
- $P(w_1,w_2,…,w_n) = \prod_{i=1}^{n} P(w_i \mid w_1,…,w_{i-1})$.
- 조건부 확률로 분해해서 쓰면 :
- 넓은 의미의 언어 모델 : $P(w \mid \text{context})$
[1] 순방향 언어모델 (Forward LM)
- “이전 단어들”(=컨텍스트)이 주어졌을 때, “다음 단어 맞히기”
- ex) GPT, ELMo
[2] 역방향 언어모델 (Backward LM)
-
ex) ELMo
( ELMo = Forward LM + Backward LM )
[3] 마스크 언어모델 (Masked LM)
- 빈칸 뚫고 맞추기
- 순방향/역방향 모델과는 달리, “문장 전체의 맥락” 파악 가능
- ex) BERT
[4] 스킵그램 모델 (Skip-gram Model)
- 특정 단어 “앞/뒤의 특정 범위” 내를 참고
- ex) word2vec (2013)
트랜스포머
- seq2seq 기반의 모델
- 소스&타겟의 길이 달라도 OK
- teacher forcing
- 학습 중의 decoder 입력 : “실제 정답”
- 추론 중의 decoder 입력 : “이전의 예측값”
트랜스포머 블록
- 구성요소
- 1) Multi-head Attention
- 2) Feed Forward NN ( FFNN )
- 3) Residual Connection
- 4) Layer Normalization
- 인코더 & 디코더의 블록은 본질적으로 크게 다르지 X
- 인코더 : 마스크 X
- 디코더 : 마스크 O & 인코더/디코더 멀티헤드어텐션
트랜스포머의 output
- “정답에 해당하는 단어의 확률값”
- target 언어의 “어휘 수” 만큼의 차원을 가진다
어텐션 vs 셀프 어텐션
- 차이점 1
- 어텐션 : source 시퀀스 전체 & target 단어 1개
- 셀프 어텐션 : 입력 sequence 전체 끼리
- 차이점 2
- 어텐션 : RNN 구조 상
- 셀프 어텐션 : RNN 구조 X
- 차이점 3
- 어텐션 : target 단어 1개 생성할때, 어텐션 1회 수행
- 셀프 어텐션 : 인코더 & 디코더 블록 개수만큼 수행
셀프 어텐션
- 각 단어는 Q,K,V로 변환됨
- ex) 6개의 단어(토큰)로 구성된 문장
- 6개의 Q 벡터
- 6개의 K 벡터
- 6개의 V 벡터
- 셀프 어텐션을 “블록(레이어) 수”만큼 반복한다
Notation
-
단어 임베딩 차원 : $d$
-
단어 개수 : $n$
-
입력 시퀀스 : $\mathbf{X}$ …..$(n, d)$ 차원
- Q,K,V를 만들어주는 weight 행렬
- $\mathbf{W}_Q$ …..$(d, d_Q=d_K)$ 차원
- $\mathbf{W}_K $…..$(d, d_Q=d_K)$ 차원
- $\mathbf{W}_V$ …..$(d, d_v)$ 차원
- 어텐션 : $\text{Attention}(\mathbf{Q},\mathbf{K},\mathbf{V})= \text{softmax}(\frac{\mathbf{Q}\mathbf{K}^T}{\sqrt{d_k}}) \mathbf{V}$
멀티 헤드 어텐션
- 셀프 어텐션을 “동시에” 여러버 수행
- 각 헤드의 출력값 : $\mathbf{Z}_0,…\mathbf{Z}_H$
- $\mathbf{Z}_i$ 의 차원 : $(n, d_v)$
- $[\mathbf{Z}_0,\mathbf{Z}_1,…,\mathbf{Z}_H]$ 의 차원 : $(n, d_vH)$
- $\mathbf{W}_O$ 의 차원 : $(d_vH, \text{dim})$
- $\text{dim}$ : 목표 차원 수
Encoder의 어텐션
- source 언어들 끼리의 self-attention
- ex) 한글-영어 번역 => 한글 & 한글의 self-attention
Decoder의 어텐션
- 2개의 어텐션
- 1) 마스크 멀티헤드 self-attention
- 2) Encoder-Decoder 멀티헤드 attention
- 1) 마스크 멀티헤드 어텐션
- 영어 & 영어의 self-attention
- 치팅 방지를 위해, 뒷 부분 “마스킹”
- 2) Encoder-Decoder 멀티헤드 어텐션
- 한글 & 영어의 attention
Layer Normalization ( 레이어 정규화 )
- 데이터 “별”로 정규화
- ex) data17의 feature 1=1,feature2=2, feature3=3
- 평균 : (1+2+3) / 3 = 2
- 표준편차 : 0.8164
import torch
x = torch.tensor([[1.0, 2.0, 3.0],
[1.0, 1.0, 1.0]])
LN = torch.nn.LayerNorm(x.shape[-1]) # 차원 수 =3
output = LN(x)
print(LN.weight)
print(LN.bias)
Drop out ( 드롭 아웃 )
import torch
DO = torch.nn.Dropout(p = 0.2)
x = torch.randn(1, 10)
output = DO(x)
- 20% 확률로 죽은 애들 : 0
- 80% 확률로 살아남은 애들 : 1/(1-0.2) 배
옵티마이저
from torch.optim import Adam
opt = Adam(model.parameters(), lr = model.learning_rate)
BERT vs GPT
- GPT : LM / 순차적 / 문장 생성에 탁월 / Transformer의 DECODER 만 사용
- BERT : MLM / 양방향 / 문장 의미 추출에 탁월 / Transformer의 ENCODER 만 사용
단어 / 문장의 벡터화
- pre-train 완료 이후, “단어/문장” 수준의 임베딩 추출하기
- 활용도 :
- 문장 벡터 : Document Classification (문서 분류)
- 단어 벡터 : Named Entity Recognition (개체명 인식)
코드
from transformers import BertTokenizer, BertConfig, BertModel
BERT_dir = 'beomi/kcbert-base'
# (1) config
config = BertConfig.from_pretrained(BERT_dir)
# (2) model
model = BertModel.from_pretrained(BERT_dir,
config = config)
# (3) tokenizer
tokenizer = BertTokenizer.from_pretrained(BERT_dir,
do_lower_case = False)
# (4) Input 생성
sentences = ["xxxx", "yyyy"]
inputs_dict = tokenizer(
sentences,
max_length = 10,
padding = "max_length",
truncation = True
)
inputs_tensor = {k : torch.tensor(v) for k,v in inputs_dict.items()}
# (5) output
outputs = model(**inputs_tensor)
# (6) "단어 수준 벡터"
outputs.last_hidden_state # (2,10,768)
# (7) "문장 수준 벡터"
outputs.pooler_output # (2,768)
-
outputs.last_hidden_state
의 차원 : (2,10,768)- 2 : 문장 개수
- 10 : 최대 길이 10
- 768 : 각 토큰의 임베딩 차원
-
outputs.pooler_output
의 차원 : (2,768)- [CLS] 토큰이 FFNN 한번 걸쳐 나옴
- 2 : 문장 개수
- 768 : 문장의 임베딩 차원