본문 바로가기

AI/Paper - Theory

[ChatGPT 리뷰] - GPT와 Reinforcement Learning Human Feedback

반응형

*ChatGPT에 대해서 설명하는 글입니다! 궁금하신 점은 댓글로 남겨주세요!

 

InstructGPT: https://openai.com/research/instruction-following#guide

 

Aligning language models to follow instructions

We’ve trained language models that are much better at following user intentions than GPT-3 while also making them more truthful and less toxic, using techniques developed through our alignment research. These InstructGPT models, which are trained with

openai.com

 

ChatGPT: https://openai.com/blog/chatgpt

 

Introducing ChatGPT

We’ve trained a model called ChatGPT which interacts in a conversational way. The dialogue format makes it possible for ChatGPT to answer followup questions, admit its mistakes, challenge incorrect premises, and reject inappropriate requests.

openai.com


Contents

1. Simple Introduction

2. Background Knowledge: GPT

3. Method

    - Supervised Fine Tuning

    - Reward Model

    - Proximal Policy Optimization

4. Result

5. Furthermore


Simple Introduction

InstructGPT Overview
ChatGPT Overview

ChatGPT가 엄청난 인기 가운데, ChatGPT를 활용한 여러 fine-tuning 모델들이 나오고 있다. ChatGPT는 어떻게 인간을 뛰어넘는 지식과 학습능력을 갖게 되었을까?

 

그 방법은 바로 RLHF(Reinforcement Learning Human Feedback)이다. 이는 기존의 InstructGPT에서 제안된 방법으로, ChatGPT는 거의 InstructGPT와 유사하다고 보면 된다. (단지 데이터셋 수집에 차이가 있다.)

해당 방법은 적은 데이터셋으로도 높은 성능을 이끌어낼 수 있도록 도와주는 fine-tuning 방법 중 하나라고 말할 수 있다. (아니면 새로운 강화학습을 이용한 모델 튜닝 방법)

 

RLHF가 도대체 무엇인지 같이 살펴보자..!


Background Knowledge: GPT

GPT-1 논문 리뷰: https://kyujinpy.tistory.com/74

 

[GPT-1 논문 리뷰] - Improving Language Understanding by Generative Pre-Training

*GPT-1를 위한 논문 리뷰 글입니다! 궁금하신 점은 댓글로 남겨주세요! (학기중이라 블로그를 자주 못 쓰는데.. 나중에 시간되면 ChatGPT도 정리해서 올릴께요. 일단 간단한 GPT부터..ㅎㅎ) GPT-1 paper: h

kyujinpy.tistory.com

ChatGPT에서는 GPT-3.5를 가지고 학습을 진행했다.

GPT-3.5와 GPT-1은 차이점이 존재하지만, GPT-1을 이해하고 있는 것만으로도 ChatGPT가 어떻게 text를 받고 학습하는지에 대해서 길을 헤매지는 않을 것이다!

 

*해당 글은 NLP에 대한 지식이 어느정도 있다고 가정합니다.


Method

ChatGPT는 Supervised fine tuning(SFT) > Reward Model(RM) training > Fine-tuning using PPO 단계로 이루어진다.

즉, 총 3가지 step을 걸쳐서 ChatGPT를 학습한 것인데, 여기서 Reward model과 PPO가 생소하게 느껴질 수 있다.

밑에서 자세히 각각의 스텝이 무엇이고, 데이터셋의 형태는 어떠한지 살펴보면서 이해를 해보자!


Supervised Fine Tuning(SFT)

Supervised fine tuning

Supervised fine tuning(SFT)는 우리가 흔히 알고 있는 fine-tuning이라고 할 수 있다.

즉, 기존의 pretrained-model을 불러와서, 적은 데이터셋을 바탕으로 학습을 진행하는 것이다.

사람이 직접 만든 데이터로 학습을 진행하기 때문에 supervised learning이다.


Reward Model(RM)

Reward Model

두번째는, Reward Model(RM)이다. 

RM의 역할은 '어떤 text prompt에 대한 응답(response)를 LLM(large language model)이 예측했을 때, 그 응답에 대한 reward score(보상 점수)를 예측하는 것'이다.

 

RM 학습에 이용되는 데이터셋 예시 - KoChatGPT

Reward Model을 구성하는 데이터셋은 위와 같이 표현할 수 있다.

해당 데이터셋을 보면 prompt는 input, completion_0,1,2는 각각 ChatGPT, GPT3('text-davinci-003'),GPT3('text-ada-001')에 대한 output이다.

 

그리고 각 completion에 대해서 순서대로 ranking point가 [2,1,0]으로 매겨진다.

즉, ChatGPT > GPT3('text-davinci-003') > GPT3('text-ada-001') 순으로 점수를 매긴 것이다.

Reward Model을 구성하는 데이터셋은 여러개의 LLM을 활용하여 각 LLM이 나온 text output에 인간이 직접 rank를 매긴 것이다. 따라서 이 과정을 Human Feedback이라고 한다!

+) 여기서 Reward Model은 기존의 LLM에 1개의 scalar를 출력할 수 있는 linear layer를 하나를 붙인 형태이다.

 

Reward Model

위의 이미지는 Reward Model의 학습 방법이다.

 

0. 데이터셋: 여러 개의 LLM를 이용하여 text prompt에 대한 여러 개의 generated text를 생성하고, 기준에 따라서 인간이 각 text에 대한 순위를 매긴다. 

1. 위의 데이터셋을 바탕으로 두 개의 text를 짝 지어서 Model에 넣는다. ( {text1, text2} pairs) 

2. text1과 text2에 대한 reward score를 RM으로부터 계산한 후, PairWise loss function을 이용하여 RM을 optimization 한다.

3. 위의 과정을 반복하여, 각 text에 대해서 적절한 reward가 생성될 수 있도록 훈련한다.

 

class PairWiseLoss(nn.Module):
    """
    Pairwise Loss for Reward Model
    """

    def forward(self, chosen_reward: torch.Tensor, reject_reward: torch.Tensor) -> torch.Tensor:
        probs = torch.sigmoid(chosen_reward - reject_reward)
        log_probs = torch.log(probs)
        loss = -log_probs.mean()
        return loss

여기서 PairWise loss function은 위와 같이 정의된다.

위의 코드에서 chosen_reward가 ranking이 높은 text의 reward score이고, reject_reward가 ranking이 낮은 text의 reward score이다.


Proximal Policy Optimization(PPO)

PPO를 이용한 학습 과정

마지막 단계는 PPO를 이용한 방법이다. 

해당 글에서는 PPO에 대한 엄밀한 수식적 정의와 안에 있는 개념을 정리하지 않을 것이다.

PPO가 무엇이고, 이게 어떻게 딥러닝 학습에 이용되었는지에 대한 궁금증을 해소하는데 초점을 두고 설명을 해보겠다..!

 

PPO를 이용한 학습 과정 overview
Ref: https://moon-walker.medium.com/chatgpt에-적용된-rlhf-인간-피드백-기반-강화학습-의-원리-eb456c1b0a4a

PPO는 SFT로 fine-tuning된 LLM과 RM을 이용하여 적절한 cost로 LLM을 fine-tuning한다.

 

1. 기존의 pretrained된 Model과 fine-tuning을 진행할 두개의 LLM을 준비하고, 각각에 text-prompt를 넣는다.

- 여기서 Weight가 frozen된 LLM이 존재하는 이유는, trainable LLM의 weight가 많이 변화하는 것을 방지하고, 이는 RM에 들어가는 text가 이상하게 변질(?)되는 것을 막아준다.

2. 각각의 LLM에서 나온 outputs 사이의 KL-Divergence(임의의 두 확률분포 사이의 유사도를 계산하는 수식)를 계산한다. 

3. Fine-tuning을 진행할 LLM에서 나온 output을 Reward Model에 넣어서 reward score을 얻는다. 

PPO 내부 로직

4. KL-divengence의 값과 reward score 사이의 값을 더해서 final reward score를 계산한다.

- Final reward score(FR) 수식: reward score + KL loss * (-λ)

 

5. Final reward score를 PPO에 넣어서 loss function을 계산한다. 

- Initial probs: 처음 예측된 output probability (probability; text에 대한 확률; n vector)

- New probs: trained LM이 예측한 probability

- ratio 정의: New probs / Initial probs

- (Policy) Loss function 수식: -min(ratio * FR, clip(ratio, 0.8, 12.) * FR)

 

6. PPO 결과로 나온 loss function으로 LLM을 fine-tuning하고 위의 과정을 반복한다.


class PPOTrainer(Trainer):
    """
        Trainer for PPO algorithm.

    Args:
        strategy (Strategy): the strategy to use for training
        actor (Actor): the actor model in ppo algorithm
        critic (Critic): the critic model in ppo algorithm
        reward_model (nn.Module): the reward model in rlhf algorithm to make reward of sentences
        initial_model (Actor): the initial model in rlhf algorithm to generate reference logits to limit the update of actor
        actor_optim (Optimizer): the optimizer to use for actor model
        critic_optim (Optimizer): the optimizer to use for critic model
        kl_coef (float, defaults to 0.1): the coefficient of kl divergence loss
        train_batch_size (int, defaults to 8): the batch size to use for training
        buffer_limit (int, defaults to 0): the max_size limitaiton of replay buffer
        buffer_cpu_offload (bool, defaults to True): whether to offload replay buffer to cpu
        eps_clip (float, defaults to 0.2): the clip coefficient of policy loss
        value_clip (float, defaults to 0.4): the clip coefficient of value loss
        experience_batch_size (int, defaults to 8): the batch size to use for experience generation
        max_epochs (int, defaults to 1): the number of epochs of training process
        tokenier (Callable, optional): the tokenizer to use for tokenizing the input
        sample_replay_buffer (bool, defaults to False): whether to sample from replay buffer
        dataloader_pin_memory (bool, defaults to True): whether to pin memory for data loader
        callbacks (List[Callback], defaults to []): the callbacks to call during training process
        generate_kwargs (dict, optional): the kwargs to use while model generating
    """

    def __init__(self,
                 strategy: Strategy,
                 actor: Actor,
                 critic: Critic,
                 reward_model: nn.Module,
                 initial_model: Actor,
                 actor_optim: Optimizer,
                 critic_optim: Optimizer,
                 kl_coef: float = 0.1,
                 train_batch_size: int = 8,
                 buffer_limit: int = 0,
                 buffer_cpu_offload: bool = True,
                 eps_clip: float = 0.2,
                 value_clip: float = 0.4,
                 experience_batch_size: int = 8,
                 max_epochs: int = 1,
                 tokenizer: Optional[Callable[[Any], dict]] = None,
                 sample_replay_buffer: bool = False,
                 dataloader_pin_memory: bool = True,
                 callbacks: List[Callback] = [],
                 **generate_kwargs) -> None:
        experience_maker = NaiveExperienceMaker(actor, critic, reward_model, initial_model, kl_coef)
        replay_buffer = NaiveReplayBuffer(train_batch_size, buffer_limit, buffer_cpu_offload)
        generate_kwargs = _set_default_generate_kwargs(strategy, generate_kwargs, actor)
        super().__init__(strategy, experience_maker, replay_buffer, experience_batch_size, max_epochs, tokenizer,
                         sample_replay_buffer, dataloader_pin_memory, callbacks, **generate_kwargs)
        self.actor = actor
        self.critic = critic

        self.actor_loss_fn = PolicyLoss(eps_clip)
        self.critic_loss_fn = ValueLoss(value_clip)

        self.actor_optim = actor_optim
        self.critic_optim = critic_optim

    def training_step(self, experience: Experience) -> Dict[str, float]:
        self.actor.train()
        self.critic.train()

        num_actions = experience.action_mask.size(1)
        action_log_probs = self.actor(experience.sequences, num_actions, attention_mask=experience.attention_mask)
        actor_loss = self.actor_loss_fn(action_log_probs,
                                        experience.action_log_probs,
                                        experience.advantages,
                                        action_mask=experience.action_mask)
        self.strategy.backward(actor_loss, self.actor, self.actor_optim)
        self.strategy.optimizer_step(self.actor_optim)
        self.actor_optim.zero_grad()

        values = self.critic(experience.sequences,
                             action_mask=experience.action_mask,
                             attention_mask=experience.attention_mask)
        critic_loss = self.critic_loss_fn(values,
                                          experience.values,
                                          experience.reward,
                                          action_mask=experience.action_mask)
        self.strategy.backward(critic_loss, self.critic, self.critic_optim)
        self.strategy.optimizer_step(self.critic_optim)
        self.critic_optim.zero_grad()

        return {'actor_loss': actor_loss.item(), 'critic_loss': critic_loss.item()}


def _set_default_generate_kwargs(strategy: Strategy, generate_kwargs: dict, actor: Actor) -> None:
    origin_model = strategy._unwrap_actor(actor)
    new_kwargs = {**generate_kwargs}
    # use huggingface models method directly
    if 'prepare_inputs_fn' not in generate_kwargs and hasattr(origin_model, 'prepare_inputs_for_generation'):
        new_kwargs['prepare_inputs_fn'] = origin_model.prepare_inputs_for_generation

    if 'update_model_kwargs_fn' not in generate_kwargs:
        new_kwargs['update_model_kwargs_fn'] = update_model_kwargs_fn

    return new_kwargs

- PPOTrainer에 대한 코드이다. 이 코드만 봐서는 잘 이해가 안될 수 있지만, 나중에 ChatGPT에서 PPO를 이용하게 된다면, PPOTrainer class를 정의를 해서 사용하게 될 것이다..!

- self.actor(LLM), self.critic(RM)

- self.actor_loss_fn이 PPO의 Training Policy(정책) loss function이다.

 

class PolicyLoss(nn.Module):
    """
    Policy Loss for PPO
    """

    def __init__(self, clip_eps: float = 0.2) -> None:
        super().__init__()
        self.clip_eps = clip_eps

    def forward(self,
                log_probs: torch.Tensor,
                old_log_probs: torch.Tensor,
                advantages: torch.Tensor,
                action_mask: Optional[torch.Tensor] = None) -> torch.Tensor:
        ratio = (log_probs - old_log_probs).exp()
        surr1 = ratio * advantages
        surr2 = ratio.clamp(1 - self.clip_eps, 1 + self.clip_eps) * advantages
        loss = -torch.min(surr1, surr2)
        if action_mask is not None:
            loss = masked_mean(loss, action_mask)
        loss = loss.mean()
        return loss

- PPO를 학습할 때 이용되는 (Policy) Loss의 코드 수식이다.


- 즉, RLHF는 Human feedback를 기반으로 한 강화학습 방법을 의미하고, chatGPT에서는 Human feedback을 RM으로 설정하고 PPO 강화학습 방법론을 이용하였다.

- PPO 과정에서는 데이터셋에 input text prompt만 있어도, RM에서 나오는 reward score를 기준으로, reward score가 높게 나올 수 있도록 LLM을 fine-tuning시킨다.


Result

# SFT 예시
'''
Prompt(명령어): 불고기용 고기 한우에요?
Completion(응답): '저는 인공지능 어시스턴트이기 때문에, 불고기용 고기에 대한 정보를 알 수 없습니다. 
하지만 일반적으로 불고기용으로 사용되는 고기는 쇠고기, 소고기, 돼지고기, 닭고기, 오리고기 등 
다양한 종류가 있을 수 있습니다. 따라서 정확한 정보를 원하신다면, 
인터넷 검색을 통해 확인하시는 것이 좋

Prompt(명령어): 리처드 닉슨이 43대 부통령직을 수행한 년도는?
Completion(응답): '리처드 닉슨은 40대 부통령직을 수행했습니다. "리처드 닉슨"이 어떤 인물인지 
구체적으로 알려주시면 더 정확한 답변을 드릴 수 있을 것 같습니다. "이미지"가 무엇인지에 따라 
답변이 달라질 수 있기 때문입니다. "리처드슨 닉슨"은 리처드

Prompt(명령어): 시카고 오헤어 국제공항은 어디에 있어
Completion(응답): '시카고 오 헤어 국제공항은 미국 캘리포니아주 샌프란시스코에 위치해 있습니다. 
\n\n시카고오 헤어 국제공항의 위치는 다음과 같습니다.\n- 텍사스 주 휴스턴 (Texaster)\n- 
일리노이 주 시카고 (Californa)\n- 워싱턴 D.C. (W

Prompt(명령어): 오늘 미세먼지 어때?
Completion(응답): '저는 인공지능 챗봇이므로 미세먼지 여부를 판단할 수 없습니다. 
하지만 일반적으로 미세먼지는 공기 중에 떠다니는 먼지로 인해 발생하는 것으로 알려져 있습니다. 
따라서 대기 오염이 심한 지역에서는 미세먼지 농도가 높아질 가능성이 높습니다. "미세먼지"가 어떤 
의미인지 알려주시면 더
'''
# Reward Model 예시
'''
Input: 인공지능은 인공지능입니다.
Reward score: 0.1

Input: 저는 인공지능 언어모델이기 때문에 불고기용 고기의 어떤 종류, 
조리 방법에 대한 정보를 알지 못합니다. 따라서 답변을 원하신다면, 
검색 엔진을 사용하여 적합한 사이즈와 영양소 등을 알려주시면 도움을 드릴 수 있습니다.
Reward score: 1.5
'''
# PPO 과정 이후, RLHF를 모두 수행한 LLM의 결과
'''
Prompt(명령어): 불고기용 고기 한우에요?
Completion(응답): '저는 인공지능 어시스턴트이기 때문에 이 질문에 대한 답변을 드릴 수 없습니다. 
그러나 일반적으로 불고기의 부위별 구분 없이 먹을 수 있으며, 다른 종류의 불고기도 있을 수 있습니다.
하지만 불고기용 쇠고기의 부위별은 개인마다 다를 수 있으므로, 미리 해당 부위를 체크해서 먹는 것이
좋습니다. 불고기 한우의 부위별 구분 없이 먹을 수 있는 한우와 불고기 한우의 크기는 개인의 취향에 
따라 다릅니다. 불고기 한우의 크기나 크기는 개인마다 다를 수 있으므로 전문가의 조언을 받는 것이 
좋습니다. 불고기 한우의 종류별 구분은 개인의 입맛에 따라 다릅니다. 
불고기 한우의 종류, 크기, 위치, 부위별 종류, 부위별 크기는 개인의 선호도와 선호하는 맛이 다르기 
때문입니다. 불고기 한우의 종류, 종류, 종류별 크기는 개인마다 다를 수 있으므로, 
전문가의 조언을 받는 것이 좋습니다. 불고기 한우의 종류별 종류, 종류별 크기와 종류 및 위치에 
따라 가격이 상이하므로, 정확한 가격을 확인하려면 관련 기관에 문의하시는 것이 좋습니다. 
불고기 한우의 종류 및 위치는 관련 단체나 언론 등에서 확인하실 수 있으니 참고하시기 바랍니다. 
불고기의 종류 및 위치도 자세히 확인하시면 됩니다.

Prompt(명령어): 리처드 닉슨이 43대 부통령직을 수행한 년도는?
Completion(응답): '리처드 닉슨은 50대 부통령직을 수행한 적이 없습니다. 
"리처드 닉슨의 43대 부통령직을 수행한 년도는 알려지지 않았습니다. "리처드 닉슨의 33대 부통령직을 
수행한 년도는 알려지지 않았습니다. 언급된 인물은 제임스 닉슨 대통령의 남편인 닉슨이 있습니다. 
언급된 인물들 중 윌리엄 로젠월드 또는 레이놀드 마코브였습니다. 언급된 인물로는 
톰 블렌더 (Tom Blender)의 아들 에드워드 (Edward McCawnow)의 아들이 있습니다. 언급된 인물들에 
대한 추가 정보가 제공되지 않아 명확한 답변을 제공할 수 없습니다. 언급된 인물에 대한 추가 정보가 
제공되지 않는다면 답변을 제공할 수 없습니다. 언급된 인물들에 대한 추가 정보가 있다면 
다시 한 번 답변을 제공할 수 있습니다. 언급된 인물이 언급된 인물들과의 만남과 관련된 정보는 
제공되지 않았습니다. 언급된 인물이 언급된 인물들과 함께한 추억은 새로운 기회를 제공할 것입니다. 
언급된 인물들과의 만남으로 인해 어떤 이슈가 생겼는지에 대해 더 많은 정보가 제공되어야 합니다. 
언급된 인물들에 대한 추가 정보가 있으면 더 많은 도움을 드릴 수 있습니다. 
언급된 인물에 대한 추가 정보가 제공된다면 더 큰 도움을 드릴

Prompt(명령어): 시카고 오헤어 국제공항은 어디에 있어
Completion(응답): '시카고 오헤어 국제공항은 미국 플로리다 주에 위치하고 있습니다. 
Americanaus Java, Lake Belan, Cheapes, Routled Martin 등이 그립니다. 
Americanaus Java는 국제공항 공식 웹사이트인 Juden-Metrophy Information에 있으며, 
해당 정보는 해당 공항의 공식 웹사이트인 Juden-Metrophy Information에서 확인하실 수 있습니다. 
Americanaus Java는 미국 남부 지역에서 가장 유명한 국제공항 중 하나입니다. Americanaus Java는 
미국 남부 지역에서 가장 인기있는 공항이며 다양한 항공사에서도 이용할 수 있습니다. 
Americanaus Java는 항공사에 대한 전문적인 지식과 경험을 가진 미국인들의 안전과 관련된 보안을 
위한 공항입니다. Americanaus Java는 국제항공기구(IA)와 협력하며 항공 안전을 위한 노력을 기울이고
있으며, 특히 국제항공화국에서 미국 대륙 최초로 취항한 항공사 중 하나로도 잘 알려져 있습니다. 
Americanaus Java는 현재 미국 전역에서 가장 유명한 공항이 되고 있습니다. Americanaus Java는 
세계에서 가장 유명한 국제공항 중 하나입니다.


Prompt(명령어): 오늘 미세먼지 어때?
Completion(응답): '저는 인공지능 챗봇이기 때문에 미세먼지 여부를 확인할 수는 없습니다. 
하지만, 최근 미세먼지는 인체에 매우 중요한 영향을 미칩니다. 외출 시 마스크 착용 등 미세먼지를 
줄이는 방법을 찾는 것이 좋습니다. 또한, 외출 시 마스크를 착용하면 체내 혈압과 면역력을 높여 주는 
효과가 있습니다.慎太子가 사용한 것으로 알려진 '新三重雨'는 미세먼지에 노출되면 혈압 조절이
불가능하므로, 면역력을 높여주는 치료법입니다.信太子가 사용한 치료법으로는 스테로이드와 같은 
약물을 처방하는 '항미노화 및 항염증제'가 있습니다. \n\n또한, 미세먼지를 줄여주는 방법은 
다음과 같습니다.\n\n1. 인공지능 챗봇이기 때문에 미세먼지를 줄일 수 있는 방법은 다음과 같습니다.
\n\n1. 마스크를 착용해보세요: 미세먼지는 여러 가지 방법이 있기 때문에 이러한 방법들은 
생활습관을 개선하거나 줄이는 방법으로 미세먼지를 줄일 수 있습니다.\n\n2. 
미세먼지 방지 프로그램\n마스크를 착용해서 미세먼지를 예방할 수 있습니다. 이를 통해 미세먼지를 
줄일 수 있습니다.
'''

 

*코드 참고: GitHub - airobotlab/KoChatGPT: ChatGPT의 RLHF를 학습을 위한 3가지 step별 한국어 데이터셋

 

GitHub - airobotlab/KoChatGPT: ChatGPT의 RLHF를 학습을 위한 3가지 step별 한국어 데이터셋

ChatGPT의 RLHF를 학습을 위한 3가지 step별 한국어 데이터셋. Contribute to airobotlab/KoChatGPT development by creating an account on GitHub.

github.com


Furthermore

 

KoChatGPT 코드 리뷰: https://kyujinpy.tistory.com/78

 

[KoChatGPT 코드 리뷰] - KoChatGPT: ChatGPT fine tuning with korean dataset

References: GitHub - airobotlab/KoChatGPT: ChatGPT의 RLHF를 학습을 위한 3가지 step별 한국어 데이터셋 GitHub - airobotlab/KoChatGPT: ChatGPT의 RLHF를 학습을 위한 3가지 step별 한국어 데이터셋 ChatGPT의 RLHF를 학습을 위

kyujinpy.tistory.com


- 2023.05.18 Kyujinpy 작성.

반응형