새소식

딥러닝/자연어 처리

How to generate text: decoding methods

  • -

auto-regressive은 문장의 확률값을 구하듯이 이전의 단어들로 다음 단어의 probability distribution을 추정한다.

(입력값은 prompt이고 출력값은 prompt 다음에 오는 단어의 확률 분포)

현재 transformers에서 auto-regressive 언어 생성을 사용할 수 있는 모델은 GPT2XLNetCTRLTransfoXLBartT5등이 있다.

 

학습된 distribution 에서 어떤 단어를 선택하는지에 따라 greedy search, beam search, Top-K, Top-p 같은 방법이 존재한다.

 

Greedy Search

https://huggingface.co/blog/how-to-generate?fbclid=IwAR2BZ4BNG0PbOvS5QaPLE0L3lx7_GOy_ePVu4X1LyTktQo-nLEPr7eht1O0

 

The에서 시작해서 3번째 토큰으로 적절한 것을 선택하려면 위의 그림에서는 총 9가지의 경우의 확률 분포를 계산해보아야 한다. 위 그림은 9가지로 단순화하여 표현하였지만 실제로는 어휘 집합의 크기 만큼의 경우의 수가 존재할 것이고 수많은 경우의 수를 계산하는 것은 비효율적이다.

 

Greedy Search는 이러한 문제를 해결하기 위해 이전 단어로 예측한 다음 단어의 확률값 중 가장 높은 확률 값을 지닌 단어를 선택하여 탐색 범위를 줄이게 된다.

따라서 The → nice → woman 의 결과가 나오게 된다.

greedy 탐색의 문제점은 순간의 최선이 항상 전체의 최선일 수 는 없다.
예를 들면 (the, nice, woman)과 (the, dog, has)의 값을 비교 해보면 the dog has의 값이 0.4 * 0.9 = 0.36으로 the, nice, woman의 값보다 높지만 선택되지 않음을 볼 수 있다.

→ Beam Search는 Greedy Search의 문제를 완화할 수 있다.

 

 

import torch

with torch.no_grad():
	generated_ids = model.generate(
    	input_ids,
        do_sample=False, # Greedy Search를 수행하고자 할 때 설정: 확률값이 높은 단어를 다음 단어로 결정
        min_length=50,
        max_length=250,
    )

 



Beam Search

https://huggingface.co/blog/how-to-generate?fbclid=IwAR2BZ4BNG0PbOvS5QaPLE0L3lx7_GOy_ePVu4X1LyTktQo-nLEPr7eht1O0

위 그림은 num_beams = 2 인 그림이다.

num_beams가 2이므로 예측 결과에서 확률이 높은 2개를 탐색 대상으로 고려한다.

1. 모델은 The 다음으로 nice(0.5) , dog(0.4), car(0.1)을 예측하였다. 

     따라서 확률이 높은 nice, dog만을 탐색 대상으로 고려한다.

2. 그렇게되면 총 6가지의 경우의 수만 존재한다.

    6가지의 경우의 수에서 가장 확률이 높은 시퀀스 2개만 남겨두게 된다.

    (the, nice, woman) : 0.20, (the, dog, has): 0.36

3. Beam search를 여기까지만 진행한다면 the dog has가 최종적으로 생성되게 된다.

 

Beam Search는 Greedy Search보다는 계산량이 많지만 더 높은 확률을 내는 문장을 생성할 수 있다는 것이 장점이다.

import torch
with torch.no_grad():
	generated_ids = model.generate(
    	input_ids,
        do_sample=False, # Beam Search를 수행하고자 할 때 설정: 확률값이 높은 단어를 다음 단어로 결정
        min_length=50,
        max_length=250,
        num_beams=2, # Beam Search 크기
    )

 

Greedy Search와 Beam Search는 최고 확률을 내는 단어 시퀀스를 찾는 방법이므로 반복해서 실행해도 결과가 바뀌지 않는다.


+ 또한 출력값에 특정 표현이 반복되는 경우가 있는데 no_repeat_ngram_size 인자를 추가하면 3개 이상의 토큰이 반복될 경우 세번째 토큰의 등장 확률을 0으로 만든다.

import torch
with torch.no_grad():
	generated_ids = model.generate(
    	input_ids,
        do_sample=False,
        min_length=50,
        max_length=250,
        no_repeat_ngram_size = 3, # 토큰이 3개 이상 반복될 경우 3번째 토큰 확률을 0으로 변경
    )


+ repetition penalty라는 인자로도 반복을 제어할 수 있다.
   1.0 보다 클수록 penalty가 세게 적용되고 1.0인 경우는 penalty가 적용되지 않는다.
   (logit 값이 양수이면 그 값을 repetiton_penalty로 나누고, 음수이면 repetition_penalty를 곱한다.)

import torch
with torch.no_grad():
	generated_ids = model.generate(
    	input_ids,
        do_sample=False,
        min_length=50,
        max_length=250,
        repetiton_penalty=1.2 # 페널티 적용
    )

 

 

Sampling 방식

앞서 설명한 방식은 확률이 가장 높은 토큰을 결정하는 방식이다.

 

1. Sampling 방식은 the라는 프롬프트를 입력했을 때 nice(0.5), dog(0.4), car(0.1)의 확률 분포를 계산한다.

2. 그 다음 토큰을 확률적으로 선택한다. 

    nice가 선택될 확률은 0.5, dog은 0.4, car은 0.1이다.

    nice가 선택될 확률이 높지만 car도 선택될 확률이 아예 없는 것은 아니다.

3. 아래 그림은 0.1이라는 확률로 car이 선택된 경우이다. 

https://huggingface.co/blog/how-to-generate?fbclid=IwAR2BZ4BNG0PbOvS5QaPLE0L3lx7_GOy_ePVu4X1LyTktQo-nLEPr7eht1O0

 

이렇게 Samling 방식은 같은 프롬프트여도 수행 때마다 문장 생성 결과가 다를 수 있다.

 

 

 

top-k Sampling 

top-k Sampling은 모델이 계산한 다음 토큰 확률 분포에서 확률값이 가장 높은 k개 토큰들 중에 하나를 선택하는 방법이다.

아래 그림은 k=6일 때 Sampling 대상 토큰들을 나타낸 것이다.

https://life-is-also-pizza.tistory.com/manage/newpost/?type=post&returnURL=%2Fmanage%2Fposts%2F#

import torch
with torch.no_grad():
	generated_ids = model.generate(
    	input_ids,
        do_sample=True, # Sampling 방식 사용
        min_length=50,
        max_length=250,
        tok_k=6, # top-k sampling 수행
    )

 

 

 

top-p Sampling 

top-p Sampling은 확률값이 높은 순서대로 내림차순 정렬을 한 뒤 누적 확률값이 p 이상인 최소 개수의 토큰들 중 하나를 선택하는 방법이다.

top-k는 상위 k개를 후보로 놓지만 top-p는 누적 확률값이 p이상인 최소 개수의 토큰들을 후보로 놓는 방법이다.

 

아래 왼쪽 그림은 p=0.92로 설정하고 the라는 프롬프트를 입력했을 때 후보 토큰들은 nice 부터 house 까지(누적 확률 합= 0.94) 임을 알 수 있다. 

https://huggingface.co/blog/how-to-generate?fbclid=IwAR2BZ4BNG0PbOvS5QaPLE0L3lx7_GOy_ePVu4X1LyTktQo-nLEPr7eht1O0

 

이렇게 top-p와 top-k Sampling 방식은 확률값이 낮은 토큰은 후보 토큰 목록에서 빠지므로 문장의 품질을 높일 수 있다.

 

top_p는 0~1 사이의 실수를 입력해야 한다.

import torch
with torch.no_grad():
	generated_ids = model.generate(
    	input_ids,
        do_sample=True, # Sampling 방식 사용
        min_length=50,
        max_length=250,
        tok_p=0.92, # top-p sampling 수행
    )

 

 

 

Temperature Scaling 

temperature scaling은 모델의 다음 토큰 확률 분포를 대소 관계의 역전 없이 분포의 모양만을 바꾸는 방식이다.

아래 그림은 temperature scaling을 적용 전, 후의 예시이다.

temperature scaling 적용 전
temperature scaling 적용 후

 

temperature scaling은 모델의 출력 logit 값을 temperature로 나누는 방식이다.

확률 값의 대소관계는 변하지 않았지만 원래 컸던 확률은 더 커지고 원래 작았던 확률은 더 작아짐을 확인할 수 있다.

 

temperature 값이 0에 가까울 수록 원래 컸던 확률은 더 커지고 원래 작았던 확률은 더 작아지는 정도가 높아진다.

즉, temperature을 1보다 작게 하면 상대적으로 정확한 문장을, 1보다 크게하면 상대적으로 다양한 문장을 생성할 수 있다.

import torch
with torch.no_grad():
	generated_ids = model.generate(
    	input_ids,
        do_sample=True,
        min_length=50,
        max_length=250,
        tok_p=0.92,
        temperature=0.01 # temperature scaling 적용
    )

 

 

 

728x90

'딥러닝 > 자연어 처리' 카테고리의 다른 글

NLP_Preprocessing : 1)코퍼스 수집 & 2)정제  (0) 2022.06.26
RNN & LSTM  (0) 2022.06.25
[LM metric] BLEU(Bilingual Evaluation Understudy)  (0) 2022.06.08
[LM metric] Perplexity  (0) 2022.06.07
GPT & GPT2  (0) 2022.06.04
Contents