본문 바로가기

AI

[NLP] OpenAI GPT-3 에서 토큰을 선택하는 방식 (feat. 샘플링)

최근 대규모 언어 모델(LLM)을 사용하여 서비스를 내놓는 스타트업이 많아지고 있다. 우리 팀에서도 문장 생성을 위한 서비스를 준비하고 있고, 따라서 gpt-3와 hyperCLOVA로 퓨샷러닝, 프롬프트 튜닝을 진행하며 테스트를 수행하고 있다.

그 과정에서 내가 수행중인 태스크에 대해 최적의 결과를 내기 위해 프롬프트 튜닝 및 파라미터 조정을 진행하면서 공부한 것들에 대해 기록하고자 한다.

GPT가 문장을 생성하는 과정

gpt의 구조

GPT 모델은 기본적으로 여러 트랜스포머 레이어를 통해 연산을 진행한다. 트랜스포머에서 인코더를 제외하고 디코더만 사용하며, 결과로 산출되는 벡터를 이용하면 다음 위치에 적합한 각 단어들이 지니는 확률 값을 추출해 낼 수 있게 된다.

확률값 추출 과정

  1. 마지막 레이어의 Hidden state에 LayerNorm 연산을 수행
  2. vocab의 임베딩 테이블 값과 행렬 곱셈을 진행
  3. softmax 연산을 진행하여 각 단어의 확률값 추출

 

샘플링

문장 생성 시에는 이 확률값들을 이용하여 샘플링 과정을 거쳐 다음 단어를 선택한다. 기본적인 방식은 여러 단어들 중 가장 확률값이 높은 단어를 선택하는 것인데, 문장 생성 의도에 따라서 기존에 나온 단어들은 생성하지 않도록 페널티를 주거나(repetition_penalty) 랜덤한 특성을 부여해 확률값이 높은 몇 개의 단어들 중에서 임의로 선택하는 방법(top_k , top_p)을 선택할 수도 있다.

샘플링에 대해서는 허깅페이스ratsgo님의 글에서 잘 설명이 되어 있어서 이번 글에서는 따로 정리하지는 않으려고 한다. 이번 글에서는 HyperCLOVA의 근간이 된 gpt-3의 playground에서 실제 문장이 생성되는 결과를 통해 토큰이 어떻게 다뤄지는지 확인하고 프롬프트 튜닝 후의 모델의 하이퍼 파라미터를 조정한 결과를 공유하고자 한다.

 

 

선택된 토큰의 확률값 확인하기

샘플링에 대한 이론 파악 후, 실제로 생성된 토큰이 선택되기까지의 과정을 파악하고자 하였다.

GPT-3의 playground 에서 아래와 같이 ML Tutor와의 대화로 프롬프트 구성후 Show probabilities 를 Full spectrum으로 설정하고 결과를 확인하였다.

선택된 토큰과 후보 토큰에 대한 확률이 %로 보여지는데, 아래에 나온 -0.54 logprob 값이 어떻게 계산되었는지 의문이 들었다. 해당 글을 참고하여 브라우저의 개발자 도구로 Request-Response를 살펴보았다.

 

 

data: {"id": "cmpl-6Bgs5kmLBI9SGf6n3EjUWjbWXIz4o", "object": "text_completion", "created": 1668244425, "choices": [{"text": "ML", "index": 0, "logprobs": {"tokens": ["ML"], "token_logprobs": [-0.5379175], "top_logprobs": [{" ML": -6.589348, "Stat": -6.4672556, "\n": -0.9063353, "A": -4.8677373, "ML": -0.5379175}], "text_offset": [226]}, "finish_reason": null}], "model": "text-davinci-002"}

 

실제 결과 값에서는 %가 아닌 logprob값이 반환되고, 이를 웹에서 %로 처리한 듯한데 log (자연로그) 를 쓴 이유는 전체 합 1의 분포에서 각각의 확률이 매우 작기 때문에 0 ~ 1에 log를 취해 -∞ ~ 0 사이의 값으로 표현한 것으로 보인다고 한다.

ML 의 logprob은 -0.5379175 이고, Math.exp(-0.5379175) = 0.5839 = 58.40% 가 되는 것이다.

로그를 취했으니 곱하기가 더하기 연산으로 바뀌게 되고, 그 결과 여러 토큰을 드래그하여 함께 선택했을 때 나오는 logprob은 각 토큰의 logprob의 합이 되는 것이다.

ML Tutor 드래그 시 계산된 logprob

logprob(ML Tutor)

= logprob(ML) + logprob(Tut)+ logprob(or)

= (-0.5379175) + (-0.00011928824) + (-8.0580685e-06)

= -0.5380448463085

 

 

낮은 확률의 토큰이 선택된 이유

어떤 토큰을 보면 아래와 같이 가장 높은 확률값이 토큰으로 뽑히지 않은 것을 확인 할 수 있는데, 이는 아까 말한 것처럼 문장 생성에 다양성을 주기 위해 설정한 샘플링에 의한 것이라고 볼 수 있다.

하이퍼 파라미터를 Top_P = 1, Temperature = 0.7 로 주었고, 이는 확률값이 낮은 단어를 전혀 배제하지 않고 다음 단어 후보로 전체 어휘를 고려한 다음 원래 확률 분포를 좀 더 평평하게 해서 낮은 확률의 토큰이 살짝 더 잘 나오도록 조정한 것이다.