강의/NLP

[NLP] Alignment - Reinforcement Learning from Human Feedback (InstructGPT)

하기싫지만어떡해해야지 2026. 4. 11. 23:16

이 게시글은 서울대학교 데이터사이언스대학원 조요한 교수님의

거대언어모델과 대화형 인공지능 강의를

학습을 위해 재구성하였습니다


 

오늘 배울 내용은 reinforcement learning from human feedback

 

 

 

 

 

전체 수업 과정 중에서 이정도까지 왔는데 

이 부분은 언어모델의 학습의 일부분인데 가장 마지막 단계에 해당된다

 

사람의 value와 좀 더 align을 잘 시키기 위한 과정인데

크게 2가지 주제가 있다

첫 번째는 alignment로 실제 학습하는 부분이고

저 ppt에 나와있는 3개 부분의 내용이 굉장히 techinical한 내용이다

 

두번째 주제는 interpretability인데 해석가능성이다

 

 

 

 

 

위에서 말했지만 이 내용은 기술적인 내용이라 수식이 많아서

조금 어렵게 느껴질 수 있다

 

이 Reinforcement Learning from Human Feedback을 보통

RLHF라고 부르는데

이게 instructGPT를 다루기 위해서 제안한 방식이다

 

 

 

 

 

LLM은 instruction following을 꽤나 잘하는데

그럼에도 불구하고 사실이 아닌 것을 얘기하거나 toxic한 얘기를 할 때가 있다

이런 부분들이 인간이 중요하다고 생각하는 가치랑

잘 맞지 않는다고 판단한 것이다

그래서 human preference와 좀 더 정렬을 잘 시켜보자고 한 것이다

 

그래서 GPT3을 더  finetuning을 시키고자 했던 것인데

human feedback 데이터를 이용해서 finetuning을 시키자는 것이다

 

 

 

 

 

학습 과정은 크게 3개로 나뉜다

 

첫 번쨰는 지난 시간에 배웠던 instruction tuning이고

세번째가 우리가 흔히 말하는 RLHF 단계이다

 

이 단계는 강화학습을 시키는 단계인데

기본적인 강화학습 내용을 안다면 알겠지만

reward로 학습을 시키게된다

그래서 reward를 주는 모델을 또 따로 학습을 시킨다

그래서 그 학습에 필요한 단계가 데이터를 모으는 단계인데

이게 위 그림에서 step2이다

 

 

 

 

 

첫 번째 tuning은 instructGPT와 거의 비슷하다

 

사람이 모범 답안을 만들고 이걸 가지고 모델에게 supervised finetuning을 시킨다

그런데 이런 경우에 여러 가지 한계점들이 존재하는데

첫 번째는 overfitting이 발생한다는 점이다

SFT(supervised finetuned)에서 사용했던 demonstrate data에서

overfitting이 들어가서 generalize가 잘 안되는 것이다

 

그리고 SFT에 쓴 데이터는 사람이 모범답안을 만들었기 떄문에 퀄리티가 매우 높다

그러다보니까 나쁜 답변에 대해서 모델이 잘 인식하지를 못한다

즉, 나쁜 답안을 생성할 확률을 낮추는 방법을 모르는 것이다

그래서 이 2가지를 극복하고자 강화학습을 통해서 추가학습을 진행하고 하였다

 

 

 

 

 

강화학습 과정을 간단하게 살펴보자

 

모델에 새로운 프롬프트로 지시를 내려 일단 질문을 던진다

모델이 이걸 가지고 답변을 생성하면

그 답변에 우선 reward를 부여하는 것이다

이 reward를 가지고 모델을 학습시키는 강화학습을 수행한다

 

그렇다면 SFT와 큰 차이점은 무엇일까?

SFT는 사람이 만든 데이터로 학습을 한다

그럼 여기서 reward를 줄 무언가가 필요한데

사람이 이걸 하나하나 주려면 학습을 많이 시키지 못하기 때문에

이 리워드 모델 자체를 학습시킬 데이터가 필요해진다

이걸 위해서 human preference data라는 것을 모으게 된다

 

 

 

 

 

 

모델에게 프롬프트를 주고 몇 개 답변을 시킨다

이걸 사람이 보고 답변에 순위를 매기는데

그 매긴 순위를 활용해서 리워드모델을 학습시킨다

 

 

 

 

 

 

 

supervised finetuning은 GPT3로 학습시켰다

프롬프트가 들어가면 답변이 나오는 방식이고 이게 instruction tuning인데

이걸 위한 데이터를 수집하기 위해서 40명의 contractors로 데이터를 labeling을 한다

 

이걸 위해서 human written demonstrations dataset을 수집한다 

우선적으로 prompt를 구해야 하는데

어떤 prompt를 줬을 때 어떤 답변이 나올 것인지를 label을 해야하는 것이다

그래서 프롬프트를 2가지 source를 통해서 수집하는데

첫 번째는 사람들이 openAI API를 통해서 날린 프롬프트이고

두번째는 위의 labelers들이 직접 만든 프롬프트이다

 

 

 

 

 

 

labelers들에 의해서 만들어진 프롬프트는 위와 같다

첫 번째 plain은 labeler들이 상상해서 만든 프롬프트로

diversity를 고려하라는 instruction만 주어지고 나머지는 labelers들이 직접 프롬프트를 만들었다

 

두번째는 fewshot prompt인데 GPT가 진화해오면서 발견한게 pretraining model에게 shot을 주면

성능이 올라간다는 것이었다

그래서 아예 fewshot 자체를 학습시키려는 것이다

그래서 prompt에 instruction+shot까지 같이 넣어주고 학습을 시켰다

이렇게 학습을 시켜주면 fewshot learning을 더 잘하지않을까? 했던 것이다

이렇게 2개를 합친 프롬프트를 만들었다

 

openAI의 API를 사용할 때 user들이 waitlist에 들어가기 위해서

해당 API의 신청 사유를 썼었어야했는데

그 Usecase들을 다 모아서 labeler들이 이걸 바탕으로 프롬프트를 생성했다

우리가 instruction GPT를 사용하면 사람들이 무슨 용도로 쓰겠구나~

이걸 학습시키고자 한 것이다

이렇게 프롬프트를 만들고 모범 답안을 만들었다

 

 

 

 

 

API usecase를 바탕으로 프롬프트를 생성했는데

이걸 기반으로 categorizing을 시킨 것이다

여기서 제일 많은 비중을 차지한게 generation인데

이야기 쓰기와 같은 task들을 말한다

그 다음은 openQA이고 그 다음은 brainstroming이다

 

 

 

 

 

이렇게 해서 모범답안까지 만들어서 finetuning을 1단계로 시킨 것이다

 

 

 

 

 

 

이렇게 SFT model을 학습시킨걸 더 발전시키고 싶은 것이다

 

강화학습을 위해서 일단 SFT 모델의 copy를 한 개 만든다

그 copy된 모델의 파라미터를 우리가 phi라고 하자

우리는 이 phi를 update 시키고 싶은 것이다

업데이트시키고자 하는 이 모델은 보통 RL에서는 policy model이라고 부른다

RL에서 기본적으로 policy model이 하는 역할이

주어진 state에 대해서 어떤 역할을 하는지 내뱉는 것이기 때문이다

우리가 이 언어 모델도 RL context가 왔을 때

주어진 state(여기서는 text context)가 왔을 때

어떤 token(action)을 내뱉는지 결정하는 것이다

 

그래서 우리가 추가학습하려는 모델을 policy model이라고 부를 수 있는 것인데

특별한 모델은 아니고 그냥 언어모델이다

그리고 이 친구의 파라미터가 Phi이다

그리고 GPT3의 경우 이 phi는 175B 정도로 굉장히 크다

 

이 SFT 모델의 복사본을 만드는 이유는 얘가 강화학습을 시키기 바로 직전 모델이

계속해서 학습 과정 중에 쓰여야하기 때문이다

우리가 그런걸 보통 reference model이라고 부르고 여기선 이게 SFT model이다

 

어떤 프롬프트가 주어졌을 때 우리는 이 언어모델이 simple하게

딱 2개의 답변만을 할 수 있다고 가정해보자

첫 번째는 you're beautiful이고 이걸 말하면 1점을 받는다하고

you're terrible이라는 말을 하면 -1점을 받는다고 하자

우리의 목적은 policy model이 더 높은 리워드를 받는 답변을

생성할 확률을 높이도록 학습시키는 것이다

 

 

 

 

 

그래서 what do you think of me라는 프롬프트가 들어왔을 때

우리가 you're beautiful을 답변할 확률을

 

이렇게 표현할 수 있다

여기서 Phi는 엄청나게 큰 파라미터이다

그냥 설명을 위해서 위 ppt에서는 1차원으로 표현했다

이 phi가 커진다기보다는 phi가 여러가지 값들을 가짐에 따라 확률이 저런식으로 변한다는 것이다

 

그런데 모델이 밑에처럼 you're  terrible이라는 답변을 생성할 수도 있다

이 답변을 모델이 생성할 확률은 phi가 변함에 따라서 위 그래프처럼 떨어진다

왜냐하면 위 2개가 나올 확률을 합쳤을 때 항상 합이 1이어야하기 때문이다

 

그렇다면 이때의 expected reward를 계산해보자

이 리워드의 기댓값인데

 

이런식으로 표현할 수가 있다

 

각각의 이벤트에 대해서 그 이벤트가 일어날 확률 곱하기 결과값들을

모두 summation해주면 그게 기댓값이 된다

 

그래서 이 기댓값을 plot으로 만들면

이런식으로 만들 수가 있는 것이다

phi가 가장 오른쪽에 있을 때 beautiful을 만들어낼 확률이 1이 되고 terrible을 만들 확률이 0이 된다

그러면 Expected probability는 1이 될 것이다

사실 phi값은 무한한 space에서 가질 수가 있는데

각각의 phi값에 따라서 expected reward가 이렇게 될 수 있다는 것이다

 

여기서 t번째 step에서 갖고 있었던 모델의 phi값을 phi(t)라고 하자

여기서 모델을 한 번 더 업데이트를 시키고 싶은 것인데

가장 직관적인 방식은 expected reward가 커지는 방향으로

phi를 한 단계 업데이트를 시키는 것이다

그때 우리가 쓸 수 있는 가장 직관적이고 단순한 방식은 gradient를 계산하는 것이다

gradient가 높아지는 방향으로 phi를 한 번 더 업데이트를 한다

 

실제로 우리는 각 phi값에 따라서 expected reward 값을 볼 수가 없다

phi(t)에서의 expected reward값 정도만 볼 수 있지

내부적으로 함수가 어떻게 생겼는지는 볼 수 없다

그래서 gradient를 계속 구하가면서 조금씩 업데이트를 시켜주는 것이다

업데이트를 수식으로 나타내면

 

위와 같이 나타낼 수 있다

 

t+1 step에서 t의 값을 어떻게 세팅하냐

t단계에서의 phi 값에다가 expected reward의 gradient를 구하는 방향으로

알파만큼의 learning rate를 곱해준 방향으로 업데이트를 수행한다

 

그래서 이렇게 gradient를 이용해서 policy를

직접 수정하는 방식을 policy gradient method라고 한다

 

token의 단위를 이 language model에서는 action의 단위로 본다

 

 

 

 

 

expected reward를 구하는 과정이 굉장히 computation이 많이 든다

expected reward를 구해서 한 번 업데이트 시키고

이걸 또 계산해서 다시 평균 구한 다음에 업데이트 시키고..

이런걸 반복하는게 굉장히 힘들다

그래서 이걸 practically하게 어떻게 수행하냐

reinforce라는 알고리즘을 사용한다

 

이 phi를 업데이트할 때 sample by sample로 업데이트를 하는데

샘플 하나를 조금 뽑아서 업데이트하고

한 번 더 샘플을 뽑아서 업데이트하는 그런 방식이다

 

 

위 ppt의 수식은 앞에서 봤던 policy gradient method를 조금 더 자세히 써놓은 것인데

expectation이란 부분은 x와 y로 구성이 되어있는데

x는 사람들이 모아놓은 프롬프트 데이터의 샘플이고

y는 현재 학습하려고 하는 모델이 x가 주어졌을 때 y를 생성할 확률에서 가져온 것이다

이게 reinforcement learning의 핵심적인 부분이다

학습하려는 모델에서 샘플을 한 그 답을 가지고 학습을 진행한다

 

y는 현재 모델의 policy(확률)에서 도출이 된 y이고

그리고 gradient를 시킬건데 우리가 학습하려는 모델의 파라미터에 대한 gradient이다

 

그래서 다른 방식으로 이 공식을 써보면

이 expectation의 부분을 summation으로 쪼개면

모든 확률에 reward를 곱한 것의 summation이 expectation이 된다

그래서 이걸 gradient의 안으로 옮기는데 이건 일반적인 기댓값의 정의이다

 

reward 값은 x, y가 주어지면 결정이 되는 상수이다

즉, 이건 phi랑은 전혀 상관이 없다

그렇기 때문에 이 리워드는 gradient에서 뺄 수가 있다

 

그런 다음 식의 뒷 부분을 log로 다시 써줄건데

logP라는 것의 gradient를 계산하면 log 미분 공식에 따라서

gradient of P / P가 된다

그래서 P = P * logP로 결국 나타낼 수가 있기 때문에 식을 다시 써주면

 

이렇게 나타낼수가 있다

그럼 저 summation안에 다시 P(y|x)가 등장했기 때문에

이걸 다시 expectation으로 바꿔줄수가 있다

이때 R과 gradient logP만 합쳐서 다시 gradient 안으로 넣어준다

그럼 결국 처음에 계산하려고 했던 expectation의 gradient가 된다

 

 

 

 

 

 

그렇게해서 최종적으로 이렇게 다시 쓸 수가 있다

저 샘플에 대해서 한 번 업데이트하고 이 과정을 계속 반복한다

이게 stochastic gradient 방식이다

 

원래 gradient descent는 batch에 대해서 평균을 구해서 업데이트 시키는건데

그렇게 하지않고 sample by sample로 시켜도 잘 작동을 한다

그게 stochastic gradient 방식이고 이걸 여기서는 REINFORCE algorithm이라고 한다

 

그럼 이 식을 next word prediction에서 모델이 gradient descent로 업데이트하는 식과 비교를 해보자

이걸 가지고 모델을 학습할 때 그 logP에다가 gradient를 취해서

그 방향으로 phi를 조금씩 옮기는 방향으로 실제로 학습을 수행한다

그런데 위에있는 식과 아래의 식이 굉장히 많이 닮은 것을 확인할 수 있다

 

그래서 이 식을 이용해서 모델 파라미터를 업데이트할 때

완전히 다른 방식의 구현을 쓰는 것이 아니고

next word prediction 때 썼던 함수의 코드에다가

objective 부분만 바꾸면 되는 것이다

그래서 크게 달라지지 않는다

 

neuarl network에서 일반적으로 gradient descent를 학습하듯이 하면 된다

gradient 부분만 R * logP로 바뀌는 것이다

나머지 back prop의 과정은 다 동일하다

 

 

 

 

 

그래서 첫 번째 objective function을 도출했다

expected reward를 최대화하고자하는 것이 objective가 된다

그런데 이걸 실제로 수행할 때 한 가지 장애물을 맞닥뜨리게 된다

expectation을 최대한 정확하게 구하려면 sample이 굉장히 많아야한다는 것이다

그리고 prompt, response, reward까지 있어야 한다

그리고 이 개수가 굉장히 많아야한다

그래서 이걸 사람이 하나하나 scoring을 하는 것이 너무 어려운 것이다

그래서 automate reward model을 만들어보자고 했던 것이다

 

 

 

 

 

Reward model도 결국 SFT model이다

되게 여러 가지 버전으로 많이 만들었는데

6B 모델부터 시작했다

 

프롬프트와 답변을 받고 이 답변이 얼마나 좋은 답변인지 reward를 내뱉도록 학습했다

그런데 기본적으로 언어모델이라는건 scalar 값을 뱉도록 한 모델이 아니다

그래서 unembedding model을 마지막에 갈아끼운다

토큰을 내뱉는게 아니고 scalar값을 내뱉도록 바꿔준다

 

 

 

 

 

그래서 preference data를 수집한다

 

각각의 프롬프트를 SFT model에다가 넣어서 response를 4개에서 9개 사이로 후보를 생성한다

원칙적으로는 각각에 대해서 누군가가 score를 측정해야하는데 사람이 하나하나 하기가 힘드니까

ranking을 기반으로 레이블링을 하게 해서 preference data를 만든다

 

사람한테 답변 후보들을 보여주고 좋은것부터 나쁜것 순으로 랭킹을 매기게했다

그래서 위 같은 경우네는 response 1이 랭킹2, response 2가 랭킹9.. 이런식으로 쭈욱 ..

이걸가지고 preference data라는 것을 만드는데 x와 2개의 y로 구성되고

왼쪽의 y는 yw라고 해서 wining response(좋은 답변)이 되고

오른쪽은 losing response(나쁜 답변)이 된다

 

이 랭킹을 갖고 여러 가지 pair의 wining response와 losing response를 뽑아낼 수가 있다

 

 

 

 

 

그런데 이건 reward score가 아니다

우리가 필요한건 reward score이기 때문에

우리가 만든 이 preference data를 이용해서 reward score 함수를 만들고자 한 것이다

 

 

 

 

 

그래서 나온게 바로 이 모델이다

 

어떤 x가 주어지고 2개의 y response가 주어졌을 때

각 y값들에 대해서 우리가 볼 수 있는 reward값이 있을 것이다

그렇다면 두개의 y 중에서 어떤 x가 들어갔을 때

사람이 봤을 때도 y1이 y2보다 더 좋은 답변이라고 대답한 확률은

r1에서 r2를 뺀 값에 시그모이드를 취해준 값일 것이라고 가정하는 것이다

 

여기서 왜 확률값이 도입이 되었냐?

같은 y1, y2를 누구에게 물어보냐에 따라서 달라지기 때문에

약간의 random sampling 개념이 들어간 것이다

그렇게 했을 때 이 확률값은 0에서 1사이의 값을 가질텐데

y1의 quality에서 y2의 quality를 뺀 값에 비례하는 그런 확률이 될 것이다

 

왼쪽 아래의 그래프가 시그모이드 함수인데

 

이게 의미하는 바는

y1의 quality가 y2의 quality보다 실제로 누가봐도 절대적으로 좋았더라면

r1이 r2보다 클 확률은 1이 된다는 것이다

그 반대도 마찬가지가 되는 것이다

그리고 두 response의 quality가 비슷했다면

100명에게 물어봤 을 때 50명은 y1이 더 낫다고 대답할 것이라는 것이다(확률이 0.5)

 

 

 

 

 

그렇다면 하나의 샘플을 우리가 가정하고 생각을 해보자

 

yw가 y1보다 낫다라고 사람들이 대답할 확률을 이 모델에 적용하면

r2-r1에 시그모이드를 취한 값이 된다

하지만 우리는 실제로 이 r1값을 모른다

그래서 Reward model을 통해서 이 값을 estimation을 하고싶은 것이다

그래서 r* 대신에 reward model의 output으로 대체한다

 

우리가 그래서 관찰한 확률을 최대한 높여주도록 학습하는 것이다

reward model이 내뱉은 스코어가 human preference data를 수집하면서 관찰한

실제 선호와 align이 되도록 이 모델을 학습시켜주는 것이다

실제로 human annotator가 저 reference data에서 y2가 y1보다 낫다고 했기 때문에

저 확률이 최대가 되도록 reward model을 학습시켜 주는 것이다

 

 

 

 

 

 

이 리워드 모델에서의 학습을 objective function으로 다시 적어보자

 

확률 앞에 보통 log를 취해서 목적함수를 만든다

그래서 logP의 기댓값을 최대화시키는 방향으로 학습하고

이걸 다시 쓰면 reward model의 function으로 다시 쓸 수 있다

 

 

 

 

 

RLHF의 첫 번째 objective에서 이 reward를 어떻게 할거냐했던 것이었는데

여기서 Reward Model을 우리가 위에서 배웠던 방식으로 학습시킴으로써

되게 안정적으로 나오게 할 수가 있었다

 

그래서 실제로 학습하는 과정을 보면 어떤 policy 모델에게 프롬프트를 주면

걔가 답변을 생성할텐데

그 prompt와 response를 reward model에 넣으면 걔가 score를 예측할 것이고

그걸 바탕으로 Policy model을 업데이트한다

 

 

 

 

 

 

근데 이렇게까지만 하면 학습이 잘 안된다

policy model이 RM을 가지고 reward hacking을 한다

 

이게 뭔소리냐면 RM의 취약점을 파고들어서 실제로는 좋은 답변이 아님에도 불구하고

높은 리워드를 받을 수 있는 답변을 만들어낸다

이 리워드모델이 완벽하지 않기 때문에 위 예시에서 beautiful이라는 단어가

좋은 리워드를 받도록 학습이 되어있다고 하면 저 beautiful만 계속해서 내뱉는 것이다

 

그래서 위와같은 문제를 해결하기 위해서 penalize를 시키는 방식을 수행했다

이 policy model이 Unnatural한 text를 생성하는 이유는

policy model이 학습을 하면할수록 SFT 모델에서 점점 멀이지기 때문이다

RL을 하다보면 SFT 모델과 점점 멀어지면서 이상한 답변을 생성하게 되는 것이다

 

 

 

 

 

 

그래서 objective function에 KL Divergence라고 하는 새로운 것을 도입시킨다

 

policy model이 생성하는 확률 분포와

SFT model이 생성하는 텍스트의 확률분포의 차이를 최소화시키고 싶었던 것이다

이걸 위해서 두 확률분포가 서로 얼마나 떨어져있는가를 수치화할 수 있어야했는데

두 확률분포의 차를 계산하기 위해 가장 많이 쓰이는 metric 중 한개가

Kullback Leibler divergence(KL divergence)이다

 

 

 

 

 

 

 

KL divergence에 대해서 간단하게 살펴보자

 

LLM과는 상관없는 예제로 한 번 예시를 들어보겠다

시골에 살 때의 생활비와 서울에 살 때의 생활비라는 두 확률분포가 존재한다

2가지 에시에서 food는 비슷한데 leisure와 hosuing이 차이가 큰 것을 확인할 수 있다

 

우린 이 두 확률분포의 거리를 KL Divergence를 이용해서 계산하고 싶은 것이다

위가 Q이고 아래가 P인데

Q 대비 P의 거리는 

 

위와 같은 공식으로 계산할 수가 있다

 

그렇다면 가능한 모든 이벤트(food, leisure, housing)에 대해서

위의 공식을 따라 모두 계산을 해주자

x가 food인 경우는 Q(x)는 0.5, P(x)는 0.5이기 때문에

0.5 * log (0.5/0.5)라서 0.5*0이 된다

그럼 결국 0이라서 이 food의 경우에서는 두 확률분포의 차이가 없는 것이 된다

 

x가 leisure인 경우를 살펴보면

P(x)는 0, Q(x)는 0.4가 되는데

log를 취하면 -1.386만큼의 divergence가 발생했고

housing에서는 1.386만큼의 divergence가 발생했다

부호만 바뀌었지 magnititude는 똑같은 것이다

그런데 앞에 붙은 중요도값 때문에 서로 상쇄가 되지는 않는다

housing이 더 중요하고 Leisure는 상대적으로 중요하지 않은 것이 된다

그래서 이 값을 계산해보니 총 0.4158이라는 값이 나오게 된다

 

P와 Q가 정확하게 동일하면 KL Divergence는 0이 나오고 그렇지 않으면 0보다 큰 값이 나온다

 

 

 

 

 

이걸 언어모델에 적용을 해보자

 

이걸 가지고 KL Divergence를 수행할건데

SFT model 대비 현재 policy model의 KL Divergence를 구하면 아래와 같이 식으로 쓸 수 있다

x가 condition으로 들어가게 된다

 

위 식을 다시 한 번 정리하면

이렇게 정리될 수 가 있다

 

그래서 우리는 SFT와 RL모델의 KL Divergence를 이렇게 작성할 수가 있다

그리고 이 값은 phi에 depend하다

PM 모델이 y를 생성할 확률이 들어가있기 때문에

phi값에 따라서 결과가 달라지게 된다

 

 

 

 

 

 

그래서 이걸 Phi의 어떤 function으로 나타낼 수가 있다

뭐 그럼 값이 올라갔다 내려갔다 할 것이다

 

우리의 목적은 이 KL Divergence를 줄이는 것이 목적이다

그래서 -KL Divergence 값을 올리는 것이 objective function이 되는 것이다

 

t번째 step에서 갖고있는 파라미터를 phi(t)라고 하자

그때 어떤 KL divergence 값이 있을 것이다

이걸 줄이는 방식으로 학습을 하는데

이 자리에서 바로 gradient를 계산을 한다

그리고 그 gradient가 낮아지는 방향으로 계산을 한다

이렇게 해서 한 번 업데이트를 하고 기댓값의 graident의 반대 방향으로 learning rate를 붙여서 업데이트를 한다

 

그런데 우리는 아까 공부했던 REINFORCE algorithm대로

이걸 sample by sample로 진행을 해야한다

그럼 위 함수를 어떻게 변경할 수가 있을까

이걸 exercise로 한 번 해보라고 해서 해보도록 하자

 

우리가 한 개의 sample을 뽑았을 때의 loss는

위와 같다

여기서 사실 SFT는 고정된 상수값이기 때문에

이 sample에 대한 Gradient는

그냥 이렇게만 나타낼 수 있다

 

그래서 per sample에 대한 gradient update 식은

가장 단순하게 위와 같은 방식으로 정리할 수가 있다

 

 

 

 

 

 

아무튼 그래서 KL divergence를 포함한 objective function은

위와 같이 정리할 수 있다

 

앞의 expected reward는 최대화를 해야하고

KL Divergence는 최소화를 해야한다

그리고 이 KL Divergence값에 베타라는 weight를 조금 준 것이다

 

 

 

 

 

 

이렇게 했을 때의 또 다른 문제가 발생했는데

PM이 자꾸 pretraining 때의 지식을 잊어버린다는 문제였다

이 부분도 그래서 objective를 추가해서 해결하고자했다

 

가장 간단한 방식은 pretrain data에 대해서 추가학습을 더 수행하는 것인데

이걸 위해서 또 위와같은 objective가 들어가게 된다

 

 

 

 

 

이렇게 해서 총 3개의 objective가 들어가게 된다

 

 

 

 

 

 

PPO라는 것에 대해서 알아보자

 

앞에서 expected reward를 학습을 시키는 것인데 실제로 학습이 굉장히 불안했다

그래서 이 REINFORCE algorithm을 그대로 사용하지는 않고

이 PPO를 사용했다

이건 엄청 자세하게 설명은 하지 않는다고 하기 때문에

어느정도만 이해하고 넘어가보도록 하자

 

이게 원래 optimize하려고 했던 expected reward인데

training 초기 단계에 모델이 생성한 답변들이 대부분 퀄리티가 낮다

얘네들의 퀄리티가 negative reward 값을 가진다

 

negative reward를 받으면 확률이 떨어지도록 학습이 되는데

그럼 모델이 무서워서 뭔 찍소리도 못하는(..) 상황이 발생하게 된다

아무튼 그래서 학습도 굉장히 느려지고 되게 덩어리처럼 되는?

아무말도 못하고 아주 짧은 답변만 생성을 하는 등의 collapse가 발생한다

 

그래서 expected reward에서 진짜 생으로 reward를 주지 말고

reward를 살짝만 바꾸자고 하는 것이 첫 번째 변화이다

여기서의 reward를 A라는 것으로 바꿀건데 이건 Advantage function이다

이 리워드값에서 어떤 value function의 값을 빼는 식으로 바꾼다는 것이다

리워드는 우리가 다 알고있는데 V는 프롬프트만 봤을 때

이 모델이 지금 어느 정도의 리워드를 받을 수 있을까에 대한 기댓값이다

이 때 y는 주지 않는다

 

그래서 이 V(x)라는 seperate prediction model을 추가 모델로 두는데

이 프롬프트에 대해서 모델에 여러번 적용했을 때 어느정도의 리워드를 받겠네하는 것의 평균을 계산하는 모델이다

 

그럼 이렇게 seperate prediction model을 두면 뭐가 좋냐

리워드가 무조건 음수가 나왔다고 페널티를 받는 것이 아니고

얘가 음수가 나와도 기대했던 것보다는 잘했으면 양수방향으로 training을 하게 된다

Reward에서 이 기댓값인 V(x)를 빼줬기 때문이다

또, 절대 리워드가 좋은 답변을 생성했다고 무조건 확률을 높이는 방향으로 학습을 시키지 않고

기대했던 것보다 안좋았으면 그 답변을 생성할 확률을 낮추는 방향으로 업데이트를 시킨다

이렇게 하면 학습이 전반적으로 stable해진다

 

 

 

 

 

원래 원칙은 프롬프트를 주고 답변을 생성하고 리워드를 주고 학습하고 샘플링하고 넘어가고..

원래 이런 방식으로 학습을 하는 것이 원칙이었는데 

사실 이게 practically하게 너무 비효율적이다

inference model과 학습하는 모델을 계속해서 바꿔가면서 수행해야하기 때문이다

그래서 약간의 compromise를 수행한다

 

y를 batch단위로 쭈욱 뽑아놓고 이거에 대해서 학습을 수행한다

모든 x 샘플에 대해서 쭈욱 업데이트를 수행하고

다음 epoch에 대해서 x들에 대한 y들을 쭈욱 다 뽑아놓고 업데이트를 진행하는

그런 방식으로 조금 타협을 수행한다

 

그런데 여기서 타협을 하면 발생하는 문제는

실제로 objective에는 현재 학습하는 그 당시의 모델의 확률에서 y를 뽑는다고 가정하고 있는데

실제로는 학습이 step마다 진행되다보면

그 당시의 모델이 y를 생성할 확률과 그 당시의 모델이 미리 뽑아놨던 확률의 차이가 나게 된다

그래서 학습 과정에서 오차가 생기게 되는 것이다

 

그래서 A에 weight를 주게 되었다

학습할 때 썼던 sample의 중요도를 사용해서 weighting을 시키고자 한 것인데

이 샘플의 중요도를 위와 같이 계산해준다

여기서 분모에 있는 Psample은 sample 할 당시의 policy이다

이 값이 1보다 커지게되면 현재의 PM이 sample할 당시의 PM보다

이 답변에 대해서 더 자주 내려고 한다는 것

즉, 해당 sample은 더 자기 정책다운 sample이 된 상태이고

1보다 작아지게 된다면 해당 sample은 현재 policy와는 조금 멀어진 sample이 된다

 

이렇게 이 importance sampling 값을 A 앞에다가 곱해주는데

이 모델이 이 y를 생성할 확률이 샘플을 했을 당시보다 조금 더 커져있으면

이 샘플을 조금 더 중요한 샘플이 되는 것이고

반대는 조금 덜 중요해지는 것이다

그래서 이 importance sampling이 커지면 모델이 더 빡세게 학습을 시키는 역할을 하게된다

 

 

 

 

 

 

세번째 변화는 x, y에 대해서 advantage의 값이 양수였다고 하자

그렇다면 모델은 기본적으로 y를 생성할 확률을 높이는 방향으로 업데이트가 될 것이다

그런데 여기서 importance weight가 너무 컸다고 가정해보자

자칫 잘못하면 모델이 y를 생성할 확률을 극단적으로 높일 수가 있게 된다

그런데 대부분 이런 경우는 노이즈일 확률이 크다

 

반대로 이 advantage의 값이 음수라고 해보자

그때 이 importance weight의 값이 너무 낮으면

여기서 확률을 더 낮춰버리고 모델이 y를 생성할 확률이 극단적으로 낮아진다는 부작용이 발생한다

그리고 이런 경우도 대부분 노이즈다

 

그래서 이런 문제를 해결하고자 A의 값이 양수일 경우에는

importance weight의 값이 우리가 미리 정의해놓은 threshold보다 커지면

이 확률이 너무 커질 가능성이 있기 때문에 그때는 업데이트를 하지 않도록 한다

반대로 우리가 정의한 threshold보다 작으면 그떄도 업데이트를 하지 않도록 

clipping이라는 것을 수행하게 된다

 

 

 

 

 

그래서 원래는 이랬던 expected reward 값에

위에서 설명했떤 3가지 문제 때문에 이 부분을 아래와 같은 방식으로 바꿔주는 것이

지금까지 설명했던 Proximal Policy Optimization(PPO) 방식이다

 

R대신에 advantage(R-V)를 사용하고

앞에 importance weight를 붙여주는데

이게 너무 커지거나 작아지면 clipping을 수행한다

 

그래서 이 object를 갖고 학습을 시킨 것을 PPO 방식이라고 한다