Auto-regressive 모델이 output 을 생성하도록 하는 디코딩 방식에는 여러가지가 있다.
이런 방법을 잘 사용하면 같은 모델로도 더 좋은 문장을 생성할 수 있다.
Auto-regressive 모델은 위와 같은 conditional 확률분포를 가지고 token 을 생성한다.
T 현재 문장 길이를 의미하고 W_0 는 initial context word sequence 이다.
Auto regressive model 의 디코딩 방법
1. Greedy search
가장 기본적으로 토큰을 선택하는 방법으로, 모델이 생성한 logit에서 가장 확률이 높은 토큰을 output으로 뽑는 방법이다.
2. Beam search
위 그림은 beam_size = 2로 설정하였을 때의 그림이다.
위 그림대로 설명하자면 ‘The’ 로 시작한 문장은 step 1에서 다음 토큰으로 가장 확률이 큰 2개 토큰인 ‘nice’ 과 ‘dog’ 를 둘 다 선택한다.
그 후 step 2 에서는 각 확률이 가장 큰 2개를 선택한다. 이전에 선택한 ‘dog’ 다음에 나오는 ‘has’ 의 확률은 0.4x0.9 =0.36 이 가장 큰 확률이다. 또한 ‘nice’ 다음 ‘woman’ 이 나오는 가지의 확률은 0.5x0.4=0.2 이다. 이런식으로 step 2 에서 또 2개의 선택지를 고를 수 있다.
이러한 과정을 반복하며 더 확률이 높은 문장을 생성하는 과정이다.
하지만 위의 그림만으로는 beam search 가 어떻게 작동하는지 정확히 알기 힘들다.
아래 그림을 보자.
beam size=2 일때 <sos> start token 이 들어가면 position 1 에서 첫 토큰에 대해 A 토큰과 C 토큰 2개의 가장 likelihood 가 높은 토큰을 고른다.
Position 2 에서는 첫번째 토큰 A 와 C, 2 가지 case 에 대해 총 2개의 토큰을 또 뽑는다. 즉 A 와 C 각각에 대해 2가지씩 뽑는 것이 아니다.
위 그림에서는 AB 와 AE 가 제일 likelihood 가 크기때문에 C branch 는 버려진다.
Position 3 에서도 AB 와 AE 에 대해 가장 확률이 높은 2개의 token 을 뽑는다. 그 후 position 4에서 <eos> end 토큰이 나오면 생성을 멈추고 가장 확률이 높은 AED 가 선택된다.
Beam search도 단점이 있다.
- Beam search는 길이가 정해진 machine translation 이나 summarization 과 같은 task 에서는 잘 작동할 수 있지만 open-ended 생성, 즉 생성할 글의 길이가 달라질 수 있는 생성에는 유리하지 않다는 연구결과가 있다. (Murray et al. (2018) 및 Yang et al. (2018) 참조)
- n-gram 등의 repetition penalty 들과 tradeoff 가 있다. Beam search 는 repetitive generation 하는것이 힘들다.
- 높은 퀄리티의 사람 언어와 높은 probability의 nezt words set 의 분포가 매우 다르다. (Ari Holtzman et al. (2019))
그래서 randomness 를 이용한 샘플링 방법이 나왔다.
3. Sampling
next token w_t 는 conditional probability distribution 에 따라 랜덤하게 샘플링되는 방법이다.
위와 같이 ‘The’ 로 시작하는 토큰에서부터 다음 단어를 예측할 때,
P(w|’The’) 로 부터 P(’car’)=0.1 의 확률로 ‘car’ 를 샘플링할 수 있고,
P(w|’The’,’car’) 로 부터 P(’drives’)=0.5 의 확률로 ‘drives 를 샘플링한다.
하지만 샘플링으로 얻은 문장이 부자연스러울 수도 있는 단점이 있다.
이를 해결하기 위해 huggingface transformers generate() 함수에서는 temperature argument 를 사용한다.
이후 generate() 함수의 사용법에서 다시 알아보자.
4. Top-K Sampling
k 개의 가장 확률이 높은 next word 를 필터링하여 probability mass 함수를 k개에 대해 redistribute(재분포) 한다.
GPT2 모델에서 이러한 sampling 방법을 사용하여 story generation 에 유리하게하였다.
아래는 k=6 일때 그 예시를 나타내는 그림이다.
위 왼쪽 그림은 기존 모든 vocab 에 대한 확률을 나타낸 그림이고, 오른 쪽은 k=6일 때를 분포를 다시 계산한 그림이다.
왼쪽은 확률이 가장 높은 6개의 token 이 전체의 약 68% 차지한다. 이는 vocab size 가 클수록 확률이 작아질 수 있고 부자연스러운 (확률이 상대적으로 낮은) 토큰들도 뽑힐 확률이 높아진다.
하지만 오른쪽은 likelihood 가 높은 단어들이 약 99% 할당된다. 그럼으로서 상대적으로 부자연스러운 token 들인 a, not, the, told 등이 삭제된다.
Top-k 방법의 문제점은 k 의 수가 동적이지 않고 사람이 직접 설정해줘야한다는 것이다. 이는 vocab 의 분포에 따라 적절한 k 의 수가 달라질 수 있다.
이에 따라 Top-p 방법이 제안되었다.
5. Top-P Sampling
Top-p sampling 은 nucleus sampling 이라고도 한다. k개를 사용자가 직접 설정하지 않고 가장 큰 확률부터 sorting 된 token 에서 확률의 누적합이 p 를 넘는 가장 작은 set 을 가져와 probability mass 를 재분포한다.
이는 확률 분포에 따라 set 의 크기가 동적으로 설정될 수 있다.
위의 그림에서 top_p = 92% 로 설정하면 92% 를 초과하는 최소 단어수를 계산하고 이를 $V_{top-p}$ 라고 정의한다. 오른쪽 예시에서는 총 9개 토큰이 포함되었고 왼 쪽 예시에서는 총 3개가 선택된다.
** Top-k 와 Top-p sampling 은 함께 사용할 수 있다.
transformers 라이브러리 에서의 generation config 사용방법
outputs = model.generate(
input_ids,
max_length=1024
)
보통 위와 같이 generate() 함수를 사용하지만 generation 설정이 복잡한 경우 아래와 같이 정리하여 사용할 수 있다.
from transformers import AutoModelForCausalLM, GenerationConfig
generation_config = GenerationConfig(max_new_tokens=1024,
min_new_tokens=0,
do_sample=True,
top_k=5,
top_p=0.9,
repetition_penalty = 3.0,
early_stopping = True,
bos_token_id=2,
eos_token_id=1,
pad_token_id=0)
output = model.generate(model_inputs['input_ids'], generation_config=generation_config)
<이 외 genetation config 의 argument>
max_new_tokens
: 새로 생성할 토큰 최대 개수. prompt 에 들어가는 토큰 개수는 무시된다.(이는 아마 input 으로 들어가는 토큰 개수가 무시되는 듯 하다.)
1. Greedy search
do_sample
= False 로 설정하면(사실 설정을 따로 하지 않아도 된다. default=False 이기 때문에) Greedy 하게 토큰을 채택한다.
2. Beam search
do_sample
= False 로 설정하고 (beam search 는 sampling 을 하지 않기 때문)
num_beams
로 beam size 를 설정할 수 있다.
Beam search 에서 사용하는 option들
1. no_repeat_ngram_size
로 설정할 수 있다.
beam search 를 사용하면 기본 greedy search 보다 낫지만 여전히 같은 token 의 repetition 이 발생할 수 있다.
이를 방지하기 위해 n-gram penalties 를 사용할 수 있다.
n 개의 연속적인 토큰 묶음이 2번 이상 나오는 것을 방지하기 위해 이미 나온 n 개 묶음의 next token 의 확률을 0 으로 만든다.
💡 n-gram 이란? n 은 토큰이 연속적으로 나오는 개수를 의미한다.
no_repeat_ngram_size
=2 로 설정하면 2- gram 이라고 할 수 있다.
N-gram penalty는 조심히 써야 한다. 2-gram 이라고 할 때 New York 은 2-gram 이기 때문에 같은 text 내에서 1번 생성 시 다시는 반복해서 나오지 않을 수 있다.
2. early_stopping = True
beam-based 방법에서 모든 beam hypotheses(후보군) 이 EOS 토큰을 가지면 generation 을 멈추도록 한다.
3. num_return_sequence
Beam search 의 좋은 점은 여러 개를 생성 후에 상위 빔을 비교하여 (사용자가) 가장 적절한 beam 을 선택할 수 있다는 것이다.
이때 num_return_sequence
옵션에 생성할 문장의 개수를 설정할 수 있다.
num_return_sequences
<= num_beams
이어야 한다.
Sampling
do_sample
=True 로 설정하면 랜덤 샘플링으로 토큰을 채택한다.
top_k
=0 을 설정함으로서 top_k sampling 을 deactivate 시켜야 한다.
temperature
: default = 1.0 으로, softmax 로 계산된 확률을 smoothing하거나 sharpening 하는 기능이다. (즉, softmax temperature 값이다)
예를 들면, 위와 같이 나타낼 수 있다. temperature
값을 줄이면 확률이 더 sharp 해진다. 높은 확률은 더 높아지고 낮은 확률은 더 낮아지게 한다.
기존의 random sampling 보다 덜 랜덤해지면서 더 자연스러운 표현을 생성하도록 하는 것이다.
Top-K 와 Top-p
do_sample
=True 로 설정하고 top_p
값을 주거나 top_k
를 원하는 값으로 설정하면 사용할 수 있다.
top_p
값은 0 < top_p
< 1 사이 값을 가져야한다. 그리고 이때 top_k
값은 0으로 세팅한다.
Warning
📢 UserWarning: do_sample is set to False. However, top_p is set to 0.9 -- this flag is only used in sample-based generation modes. You should set do_sample=True or unset top_p.
📢 warnings.warn(~ UserWarning: do_sample is set to False. However, top_k is set to 5 -- this flag is only used in sample-based generation modes. You should set do_sample=True or unset top_k.)
위와 같은 warning은 generation_config에서
do_sample
을 False 로 설정했는데 top_k
나 top_p
를 설정해주면 나타난다.
아마 자동으로 무시해주기는 하는 듯 하다.
또한 Top-k 나 Top-p sampling 에서 num_return_sequences
수를 설정하여 beam search 와 비슷하게 여러 생성된 문장을 확인할 수 있다.
Reference
How to generate text: using different decoding methods for language generation with Transformers
Huggingeface model generator method do_sample parameter