정책경사
자 우리가 지금까지는 아 그러면 다음으로 넘어가서 우리가 지금까지는 이제 가치 기반 그러니까 이제 큐를 추정을 해가지고 큐가 큰 행동을 하는 방식으로 하는 걸 해봤는데
그럼 이제 반대로 정책 기반도 있겠죠
파일을 추정을 하는 겁니다.
그래서 이제 딥러닝으로 아까는 큐함수를 큐네트워크를 만들어서 딥러닝으로 큐를 근사를 했다면 이번에는 정책 파일을 딥러닝으로 근사를 할 거에요.
그럼 어떻게 트레이닝을 시켜야 되냐
그래서 이제 이런 방법을 정책 경사라고 하는데요.
가치 기반 강화학습은 가치를 정확하게 추정을 해서 그 중에 가치가 제일 높은 행동을 하는 거죠
근데 결국에는 이렇게 해도 그게 정책이잖아요.
가치가 제일 높은 행동을 한다.
이게 정책이니까 굳이 가치를 정확하게 추정을 안 해도 내가 정책만 어떻게 잘 할 수 있으면 이게 내 정책인데 이게 왜 좋은지 얼마나 좋은지는 몰라요
그냥 나는 그냥 이렇게 할 거야.
여러분이 예를 들면 뭐 아침마다 조깅을 하신다 그러면 여러분이 그 조깅을 함으로써 여러분이 앞으로 얼마나 건강하게 살고 앞으로 얼마나 오래 살지
예측이 되십니까?
잘 모르죠
그냥 하는 거죠.
좋겠지 뭐 하면서 열심히 조깅을 안 하셔도 운동을 하시는데 내가 이 운동을 함으로써 내 수명에 3년의 기대의 향상분이 있지
하하 이러면서 운동하지는 않는단 말이에요
그냥 하는 거죠.
그 다음에 DQN 같은 경우는 행동공간이 연속적인 경우에는 사용이 어렵습니다.
왜 어려울까요?
왜냐하면 Q를 계산을 여러 개 해가지고 Q1 Q2 Q3 쓰면 이렇게 있다
Q2가 제일 높구나
그럼 이걸 하자 이렇게 되는 거잖아요
그러면 연속적인 경우는 어떻게 돼요?
이게 Q가 무한히 많잖아요
그렇죠?
그러면 함수가 이렇게 될 건데 여기서 제일 높은 점을 찾아야 된단 말이에요.
이런 거는 또 어려운 문제가 됩니다.
그래서 DQN 같은 가치기반 강화학습은 일단 첫 번째 문제 굳이 이렇게까지 할 필요가 있을까?
굳이 이렇게 가치를 정확하게 할 필요가 있을까?
몰라도 그냥 할 거.
여러분 운동을 하는데 이 운동의 효과가 정확히 몰라도 사실 운동을 해야 한다는 결론 자체는 별 차이가 없거든요.
그럼 그냥 운동 열심히 하면 되지
내가 이 운동을 해서 3년을 더 살지
30년을 더 살지
그게 뭐가 중요합니까?
더 오래 건강하게 잘 산다는 게 중요하지
그리고 연속적인 경우에는 여러 개 중에 골라야 되는데 연속이라는 것 자체가 무한히 많은 거니까 고르는 게 좀 어렵습니다.
그 다음에 세 번째로는 이 얘기는 여러 번 드렸는데 가위바위보 같은 경우는 가치가 큰 행동을 하는 게 중요한 게 아니라 내 의도를 숨기는 게 중요하죠.
그래서 굉장히 많은 경우에 특히 상대방이 있는 경우는 내 의도가 드러나면 불리한 경우가 굉장히 많습니다.
근데 누가 봐도 나는 이렇게 하는 게 가치가 높아요.
그러면 상대방이 그거를 공략을 할 수 있겠죠.
너 그렇게 할 게 뻔하지.
너 그렇게 하는 게 너한테 이기잖아.
너 그렇게 할 거잖아.
그러니까 나는 네가 그렇게 할 걸 예상을 하고 선수를 치겠어.
이러면 꼼짝없이 당해야 된단 말이에요.
그래서 의도를 안 들키는 게 중요한데 그러려면 무자기적으로 해야 되죠.
약간 북한 같은 나라가 그런 전략을 쓰는 거잖아요.
도대체 무슨 생각인지 모르겠어요.
본인들한테도 딱히 이득이 아닌 것 같은데 이상한 짓을 한단 말이에요.
예측부로 하니까 그게 북한의 외교 전략인 거죠.
약간 미치광의 영어로 용어가 있거든요.
국제정치하게.
제가 용어는 까먹었는데 미치광이 장애인 전략인가
이런 전략이 있어요.
영어로 crazy crippled machine strategy. 정확한 용어는 기억 안 나는데 그러니까 나는 미쳤다
이러면 상대방이 도대체 얘가 어떻게 나올지.
보통 일반적으로 국가 대 국가 외교 전략은 내가 이렇게 나오면 상대방이 이렇게 나올 거고 그러면 저렇게 나올 거니까 이렇게 하고 서로 합리적으로 가정을 하고 전략을 짜는데 갑자기 거기서 나는 미쳤다
이러면 남들이 대응이 안 되니까 결국 질질 끌려다니는 거죠.
그래서 굉장히 보면 북한이 그 전략을 오랫동안 많이 써서 그 전략에 대해서는 전 세계에서 가장 노하우가 많이 쌓인 나랍니다.
우리가 보면 알죠.
답답하네.
도대체 원하는 게 뭐야.
이걸 해줘도 싫다 저걸 해줘도 싫다.
다 싫다고 그러고 갑자기 뭐 뜬금없이 새로운 전략을 누르잖아요.
갑자기 풍선을 야려 보내지 않나.
도대체 속내가 뭔지 모르겠고 이걸로 무슨 이 익을 노리는지
모르겠고.
그걸 모르게 하는 게 북한의 핵심입니다.
왜냐하면 다 수가 일키면 사실 북한이 돈이 있어요.
뭐가 있어요.
아무것도 없잖아요.
물론 행복이 있지만.
그러니까 수가 일키면 안 되는 거죠.
그래서 정책 경사 가치 기반 학습은 이런 문제들이 있고 그래서 우리가 정책 기반 강화학습을 해가지고 이런 문제를 극복을 하려는 거예요.
정책 경사는 가치를 추정을 안 합니다.
그리고 그 대신에 성능이 극대화되도록 정책을 직접 개선하는데.
그래서 이름이 왜 정책 경사냐 하면 우리가 경사하강법을 쓰잖아요.
지도학습에서.
왜 경사하강법을 쓰냐면 손실이 하강을 해야 되니까.
그러면 정책 경사에서는 경사상승법을 써요.
뭐가 상승되어야 됩니까.
고상이나 또는 수익이 상승을 해야겠죠.
R을 다 더하면 G니까.
똑같은 얘기고.
그러면 정책을 가지고 경사상승법을 쓴다.
정책 경사.
이렇게 얘기합니다.
이렇게 하면 수익이 높은 행동의 확률은 높아지고 수익이 낮은 행동의 확률은 낮아지고.
하지만 기본적으로 확률이기 때문에 뭘 할지는 몰라요.
그런데 이익이 되는 행동을 할 가능성은 좀 더 큰 편이죠.
그래서 정책이라는 것은 어떤 특정 상태에서 뭘 할지를 정해 놓은 건데.
여기 확률적 정책과 결정론적 정책이 있습니다.
확률적 정책은 그냥 어떤 행동을 할 확률이 있는 거죠.
어떤 상태 S에 이런 행동을 할 확률이 있고 이런 행동을 할 확률이 있고.
그 다음에 S프라임에는 반대로 이런 식으로 확률이 있고.
그때그때마다 확률에 따라 달라지는데 이 확률이 어떤 세타 라고 쓸 수 있는 파라미터에 의해 달라지는 그런 형태를 파라미터화된 정책이라고 합니다.
우리가 이전에는 정책을 표로 짜놓고 표에 따라서 정책을 시행을 했는데 이제는 어떤 파라미터가 있어서 그 파라미터 값에 의해서 어떤 계산을 하면 저 확률이 나온다는 것.
그럼 그 계산을 뭘로 하느냐.
보통 인공신경망으로 구현을 하고요.
그 다음에 출력층에 소프트맥스 함수를 적용을 합니다.
소프트맥스 함수는 우리가 MAB 할 때 다뤘는데 MAB 할 때 우리가 어떻게 하냐면 MAB 문제가 슬롱머신이 여러 대 있는데 슬롱머신 중에 뭘 당겨볼 거냐.
이게 MAB 문제잖아요.
슬롱머신과다 Q를 추정을 해요.
Q1은 되게 높고 Q2는 중간 정도고 Q3는 낮다.
그러면 입실로는 그릴이나 이런 방법은 Q1을 주로 하다가 가끔 Q2, Q3를 하는 이런 식인데 소프트맥스 전략은 가치가 높은 거는 확률을 많이 주고 가치가 낮은 거는 확률을 조금 주고 그래서 확률적으로 하는 거죠.
그래서 만약에 셋 다 가치가 비슷하다
그러면 확률도 비슷하게 주게 됩니다.
가위바위보 같은 경우 내가 가위로 이길 확률이랑 주먹으로 이길 확률이랑 보로 이길 확률은 비슷하잖아요.
그러니까 소프트맥스 전략으로 보면 랜덤하게 하는 게 맞습니다.
그래서 인공신경망에다가 앞단을 이렇게 붙여놓고 마지막에 어떤 값이 출력이 되는데 이 뒤에다가 소프트맥스 함수를 붙여주면 각각의 확률이 이렇게 나오는 거죠.
그래서 우리가 어떤 전략을 써가지고 그 결과로 좋은 결과가 있었다.
그럼 이 확률을 높여요.
별로 좋은 결과가 없었다.
그럼 그 확률을 이렇게 낮춥니다.
그럼 그걸 계속 반복하면 보상 을 받을 때마다 확률이 증가하고 손해를 보면 처벌을 받으면 확률이 감소하고 이걸 계속 반복하면 결국에는 가치가 높은 거는 보상을 자주 받으니까 확률이 계속 올라가고 별로 가치가 낮은 거는 처벌을 주로 받으니까 확률이 계속 내려가서 균형점에 도달하면 그게 가장 이상적인 상태가 되는 거죠.
지금까지 했던 얘기를 정리를 하면 정책 기반의 강화학습을 하고 싶은데 그러면은 결국에는 파라미터화 된 정책이라는 것은 정책을 어떤 신경망 모델로 만든다
그래서 우리가 어떤 상태를 입력을 하면은 내가 무슨 행동을 할지가 출력으로 나오게 된다
이런 얘기고 이렇게 했을 때 장점이 행동을 결정하기가 쉽고요
왜냐하면 행동 자체가 출력으로 나오기 때문에 그 다음에 지금은 제가 아까 소프트맥스를 붙이는 방법을 얘기 들었는데 그게 아니고 우리가 어떤 연속적인 행동이 있는 경우가 있잖아요
연속적인 행동이 있는 경우에는 그냥 행동 자체를 출력을 하는데 이 출력값이 실수로 나오게 하면은 되겠죠
예를 들면 로봇8이 이렇게 있는데 여기 조인트가 두 개가 있어요
그럼 이 두 개가 각각 어떤 정도의 각도를 이루어야 되는지 그 각도 자체를 출력 값으로 주면은 여기서는 소프트맥스처럼 탐색은 안 되지만 어쨌든 실수에서 되는 거죠
DQN에서는 이게 안 되거든요
그 다음에 매끄러운 변화 이것도 중요한데 우리가 DQN에서는 A의 가치가 이만큼이고 B의 가치가 이만큼이다
그럼 A만 죽도록 합니다
B는 가끔 해요 입실론 그리디에서만 해요
그래서 A를 엄청 많이 하고 B는 이만큼 하다가 갑자기 어떤 추정을 하다가 B가 추정치가 조금 올랐어요
그러면 갑자기 B를 확 많이 하 고 A를 거의 안 합니다
그래서 갑자기 정책이 급격하게 변하는 이런 문제가 있어요
정책이 급격하게 변하는 문제가 뭐냐
우리 아까 강학습에서 IID 문제에서 Identically Distributed 된 게 중요하다
이렇게 했는데 그러면 계속 내가 어떤 과거 데이터를 가지고 학습을 하고 있었는데 데이터가 갑자기 확 바뀐단 말이에요
예를 들면 여러분이 갑자기 나는 갑자기 뮤지션이 될 거야 라고 하면서 갑자기 음악을 시작을 하셨어요
회사도 때려치우고 그럼 여러분이 회사에서 하신 경험은 뮤지션 하는데 별로 도움이 안 되죠
갑자기 인생이 확 바뀌니까 이전에 했던 경험이 쓸모가 없게 됩니다
근데 우리가 정책을 직접 학습을 하면 A가 가치가 높을 때는 A를 많이 하다가 아까 소프트맥스 얘기하면서 얘기 드렸지만 그러면 A를 할 확률이 더 크고 B를 할 확률이 작지만 어차피 두 개가 가치가 비슷하기 때문에 확률이 그렇게까지 차이가 많이 나진 않는단 말이에요
그리고 B의 확률 가치가 올라가면 어떻게 됩니까
이쪽이 확률이 서서히 늘고 이쪽이 확률은 서서히 빠지겠죠
그래서 그렇게 변하게 됩니다
그래서 이전의 경험도 어느 정도 도움이 되는 거죠
그 다음에 탐색의 경우에 우리가 결정론적 정책은 탐색이 안 되기 때문에 그런데 DQM 같은 거는 애초에 결정론적 정책 밖에 못해요
그래서 입실론 그리디 같은 걸 써야 되는데 입실론 그리디 같은 거 자체가 가치 추정을 방해를 한단 말이에요
왜냐하면 실제 행동하고 다르니까 근데 확률적인 정책은 그냥 애초에 그 자체가 특정한 것을 하는 게 아니라 가치가 높은 건 많이 하고 가치가 낮은 건 적게 하지만 그 가치만큼 서로 확률이 다른 것 뿐이라서 원래 탐색을 하게 되어있습니다
그래서 이런 측면에 장점들이 있다
그럼
이제 학습을 시켜야 되는데 우리가 정책 경사에서의 목표함수는 결국 상태가치를 높이는 게 됩니다
내가 어떤 시작을 했을 때 S0라는 거는 내가 시작을 했을 때 나 아직 아무것도 안 했지만 지금 시작 상태에 선 것만으로도 나는 최종 상태에 도달할 때까지 굉장히 많은 가치를 얻을 수 있을 것이다
이렇게 되면 그냥 이상된 거죠
예를 들면 여러분이 초등학생이랑 팔씨름을 한다
그럼 뭐 시작하기 전에 이미 이겨지잖아요
이미 S0에서 이미 가치가 굉장히 크단 말이에요
초등학생 못 이기겠어요
안 해봐도 이기지 물론 해봐도 질 수도 있습니다
가치라는 건 항상 기대값이기 때문에 실제로는 좀 다를 수 있는데 그러면은 우리가 이제 이 파라미터를 어떻게 해야 되냐면 경사상승법이니까 경사를 구해야 돼요
그래서 미분을 해야 됩니다
그 세타로 이걸 미분을 하면 쭉 전개를 하면 어떻게 되냐면 중간에 복잡시런 걸 다 떼고 나면 제일 중요한 게 요기인데 여기를 보시면 Q하고 그 다음에 이게 정책이죠 정책의 미분가 정책의 미분하고 여기 네블라는 삼각형 거꾸로 쓴 거는 미분했다는 뜻이에요
정책의 미분하고 Q를 곱한 게 요 식 안에 들어가 있습니다
그럼 그 얘기는 뭐냐 하면은 예를 미분하려면 뭔가 복잡한 계산을 거치는데 결국에는 정책만 잘 미분할 수 있으면 된다
Q는 미분을 안 해도 된다는 얘기입니다
그래서 이게 굉장히 중요해요
가치함수가 미분 가능하지 않아도 된다 자유로운 형태를 취할 수 있다 가치함수가 어떤 희한한 형태를 가지고 있어 도 예를 들면 뭐 이런 식의 함수다 상관없다
얘기 그래서 이게 굉장히 중요한 함인데 왜 중요한 함이냐면 가끔 지도학습을 해야 되는데 지도학습을 안 하고 강화학습을 하는 경우가 있어요
보통은 반대가 많거든요
강화학습을 해야 되는데 강화학습이 까다롭다 보니까 어떻게든 어워즈로 지도학습으로 바꿔서 하는 경우가 많은데 쉬운 지도학습을 놔두고 굳이 굳이 강화학습으로 바꿔서 하는 경우가 있습니다
어떤 경우냐
예를 들면 번역기를 학습을 시킬 때 번역을 하면 영어에서 한국어로 번역을 했어요
번역을 잘했냐를 따져야 되는데 이게 애매하죠 번역을 잘했는지
못했는지를 어떻게 점수를 줄까요
한가지 방법은 인간 번역가가 번역한 답이 있을 겁니다
인간 번역가가 번역한 답이랑 쉽게 말해서 몇 글자나 겹치냐 몇 글자나 겹치나 뭐 이런 식으로 평가할 수 있거든요
몇 글자가 너무 심하면 몇 단어나 겹치나
그래서 이걸 단어 겹침
측정치라고 해요
번역을 잘했으면 사람이 번역한 거랑 완전히 문장이 똑같진 않겠지만 그래도 단어가 많이 겹칠 거 아니에요
그래서 간접적으로 우리가 평가를 할 수 있단 말이에요
근데 문제는 단어 겹침
측정치는 어떤 특성을 가지냐면 단어가 1개 2개 3개 4개 5개 이렇게 겹치기 때문에 함수가 개단함수 형태라서 이거는 미분이 안됩니다
그죠
미분이 되려면 이렇게 부드럽게 변해야 되는데 미분이 안 돼요
그래서 지도학습을 할 수가 없습니다
왜냐면 미분이 돼야 경사강법을 써서 오차를 줄이는데 이거는 미분이 안 되니까 오차를 줄일 수가 없어요
강학습으로 하면 됩니다
이거를 보 상함수로 쓰면 어차피 보상함수는 미분이 안 되는다니까 상관이 없어요
정책만 미분이 되면 됩니다
그래서 정책 경사정리 이걸 미분하면 이런 거에 비례한다
이런 얘기인데 이거에 가장 이 정리가 주는 가장 중요한 인사이트는 정책 경사를 쓰는 경우에 보상함수가 뭐든지 상관없다 무슨 희한한 형태로도 상관없다
그냥 죽인만 해도 보상함수만 다오 가치함수만 다오 하여간 그러면 뭐든지 된다
그래서 가끔 지도학습 중에서 오차를 미분 가능하게 정의하기 어려운 경우에 강학습을 써서 이거를 해결을 하는 그런 경우들이 있습니다
근데 이제 약간 그거는 또 고민을 해 봐야 돼요
과연 이게 강학습으로 하는 게 좋은 것인가
그래서 우리가 이제 대표적인 이런 정책 경사 정리에 기반한 알고리즘 중에 리인폴스 알고리즘이라고 있습니다
이 알고리즘도 저는 이름을 개떡같이 지었다고 생각하는데 그냥 강화잖아요
번역하면 아니 알고리즘 이름을 이렇게 지으면 어떡합니까
그래서 이거는 주의하셔야 되는데 강학습 관련된 자료를 보시다가 대문자로 리인폴스라고 써 놓으면 이거는 강학습을 말하는 게 아니라 그냥 이 알고리즘을 말하는 거에요
알고리즘 이름은 이따위로 지으면 안 됩니다
예를 들면 배를 만드는 알고리즘인데 알고리즘 이름이 조선 알고리즘 이따위로 지으면 안 되는 거죠 구별이 안되잖아요
뭐하는 알고리즘이야
이거 조선 알고리즘 조선 알고리즘이 너 하나야
뭐 약간 아니요 그냥 알고리즘 여러 개인데 저는 이름을 조선으로 지켰습니다
이러면은 그러면 안 되는 거죠
그래서 옛날에 은행 중에 우리은행이 우리은행이 옛날이 라는 거였죠
옛날 이름 있었는데 우리은행으로 이름 바꿔서 욕을 엄청 먹었거든요
다른은행들은 아니 은행들 다 우리은행이지 니네만은 우리은행이냐
그래서 아직도 금융계에서는 우리은행을 월의은행이라고 부르거든요
내부적으로 그러니까 뭐 다른 은행 신한은행 이런데서 내부적으로 우리은행을 지칭할 때는 헷갈리지 않아요
우리은행이라고 하면 신한은행에서 우리은행이라고 하면 우리은행입니까
그 우리은행인가 헷갈리니까 신한은행 사람들이 우리은행 볼 때는 월의은행이라고 이렇게 한대요
헷갈리지 말라고
근데 약간 이제 이 린포스 알고리즘 도 이름만 보시면 되게 헷갈릴 수 있는데 그냥 알고리즘 이름을 이따위로 지어 놓은 겁니다
그래서 이제 헷갈리지 않게 하기 위해서 보통 대문자로 써요
이거는 리인 볼스 이렇게 그래서 강화학습 말 때는 리인 볼스 이렇게 소문자로 쓰고 멍트도 붙어야 되죠
그래서 이 알고리즘은 굉장히 간단한 알고리즘인데 그냥 하나의 에피소드를 현재 정책에 따라서 뉴럴렛을 돌려 가지고 쭉 처음부터 끝까지 해요
그러면 이제 내가 어떤 상태에서 어떤 앵긍 설치하고 어떤 보상을 받고 그 다음에 어떤 상태로 가서 그 다음에 어떤 행동을 하고 그 다음에 어떤 보상을 받고 쭉 있겠죠
이걸 이제 괴적이라고 합니다
이걸 쭉 기록을 해요 맨 마지막에 우리가 끝까지 가면은 어떤 그 이때까지 받은 보상들을 다 더하면 지가 나오겠죠
리턴 수익 지가 나올 건데 그러면은 우리가 이 상태는 이 지를 가지고 학습을 하면 되겠죠
이 상태에서 이 지를 최대한 하려면 어떤 액션을 해야 되는지를 학습하면 될 겁니다
어떻게 하냐면 내가 이 액션을 했는데 이 지를 크게 많이 좋게 받았어요
그럼 다음번엔 이 액션을 더 많이 하면 되겠죠
그 다음에 이 A'를 했더니 지가 작아요
그럼 이 A'는 다음에 확률을 줄이면 되겠죠
그래서 그런 식으로 각각의 행동에 뒤따르는 그 지를 수익을 계산해서 수익이 크면 행동을 늘리고 수익이 작으면 행동을 줄이는 이런 방식으로 파라미터를 업데이트를 해 주면 됩니다
그래서 예를 들면은 내가 바둑을 넣었어요
그럼 내가 이 바둑을 한판 두면 보통 1인당 100수 정도 둔단 말이에요
그럼
제일 쉽게 하는 방법은 바둑은 이제 굳이 할인을 잘 안 하거든요
그럼 내가 바둑에 이겼어요
이번에 이번 판 이겼다
그럼 내가 둔 100개의 모든 수를 확률을 다 높입니다
그 중에 안 좋은 수도 있잖아요
안 좋은 수도 있지만 어쨌든 높아요
그 다음에 졌다
그러면 모든 수의 확률을 다 깎아 버립니다
그럼 그 중에 좋은 수도 있잖아요
그럼 일단 깎아요
그럼 그거를 수천만 판을 두다 보면 어떻게 되냐면 그래도 잘 둔 수는 이기는 결과로 이어질 가능성이 크죠
그리고 나쁜 수는 지는 결과로 이어질 가능성이 크죠
그래서 한판 한판에서는 좋은 수도 만약에 패배한 판에 있으면 확률이 깎이 있고 나쁜 수도 이긴 판에 있으면 확률이 올라가는데 아무래도 나쁜 수는 이쪽에 들어갈 확률이 높고 좋은 수는 이쪽에 들어갈 확률이 높아서 이 짓을 수천만 판을 하다 보면은 결국 좋은 수는 확률이 많이 올라가서 그 수는 많이 두게 되고 나쁜 수는 확률이 깎여 가지고 결국 안두게 됩니다
그래서 수천만 판으로 모자라면 수십억 판 수백억 판 을 두면 되요
어차피 컴퓨터가 하면 되니까 죽도록 돌리면 되는거죠
그래서 알파고 같은 경우에 개발하는데 돈이 되게 많이 들었는데 그 중에 컴퓨터 값만 한 몇백억 들었다고 합니다
컴퓨터를 몇백억 원어치를 돌려서 그렇게 바둑을 잘 두게 만들어요
지금 돌리면 몇백억도 안될 것 같아요
한 몇억 정도면 되지 않을까 싶어요
어쨌든 그래서 이렇게 하는 것이 리인포스 알고리즘 뭐 별 얘기 없죠
간단한 아이디어입니다
그래서 여기 보시면 결국 아까 그 정책 경사 정리해 보면은 여기가 그 값이고 여기가 그 미분 값인데 여기 보면은 이게 값이 대신에 실제 수익을 곱해주고 여기에다가 정책의 미분 값, 로그가 분대, 뭐 여기가 중요한건 아니고 미분 값을 곱해주면 되고 그러면은 아까 제가 바둑을 예로 두면 바둑에 2면 플러스 1 지면 마이너스 3이다
그러면 여기 플러스 1이니까 미분 만큼 파라미터를 더해주면 되고 마이너스 3이면 미분 값만큼 파라미터를 깎아주면 됩니다
이걸 계속 반복을 하면은 좋은 수는 점점 많이 두게 되고 나쁜 수는 점점 안두게 돼서 결국에는 좋은 수만 두는 ai가 된다
이런 얘기죠
근데 이거는 이제 코드를 제가 이렇게 해놓긴 했는데 제가 코드를 해놨다는 건 뭐겠어요?
스테이블 베이스 라인에 구현이 안 되어 있다는 얘기죠
왜 구현이 안 되어 있을까 하면은 단점이 굉장히 많기 때문에 그렇습니다
그래서 순수한 리인포스 알고리즘은 아무도 쓰지 않습니다
왜 안 쓰느냐
기본적으로 리인포스는 mc제어의 일종이에요
mc제어는 뭐가 문제였죠?
항상 처음부터 끝까지 다 해봐야만 학습이 됩니다
그래서 학습속도 가 느리고 그다음에 분산, 편향분산 교환에 의해서 분산이 높아요
왜냐하면 끝까지 가야 되니까 내가 앞에서 뭐 수를 하나 돋는데 받으기라고 쳐봐요 상대방하고 나오고 합쳐서 200수를 돋는데 초반에 뭐 하나 돋는데 게임이 졌어요
근데 이것 때문에 이겼어요
설마 근데 얘도 확률이 깎인단 말이에요 억울하잖아요
그죠
그리고 중간에 뭐 하나 돋는데 이겼어요
근데 확률을 올려 그럼 얘 때문에 이겼겠어요
아니겠죠
근데 억울하단 말이에요
이게 뭐냐면 뒤로 갈수록 분산이 커지니까 결과가 들중할 중 하니까 조금만 뭐 하면 확률이 확 올라왔다가 조금만 확 떨어졌다가 이렇게 된단 말이에요
그 다음에 바둑 같은 경우는 예를 들면 이기면 플러스 1 지면 마이너스 1인데 카트폴 같은 경우는 항상 플러스에요
무조건 1초라도 더 버티면 플러스입니다
그게 문제가 있는데 문제가 뭐냐면 내가 예를 들면 기둥이 이렇게 기울어져있어요
그럼 이쪽으로 가야 되죠
만약에 이쪽으로 가도 기둥이 이만큼만 기울었다
근데 이제 게임 오버가 되려면 여기까지 기울어야 돼요
그러면 한 칸 더 갔으니까 플러스 1점이잖아요
그럼 어쨌든 수익이 플러스로 난다는 얘기입니다 수익이 플러스로 난다는 얘기는 뭐냐면 앞에 공식을 보시면 어쨌든 여기가 플러스니까 이 파라미터를 올리게 됩니다
이 파라미터는 항상 올라가요
항상 올라갑니다
뭐야
이건 이렇게 되는 거죠
아니 그러면 어떻게 학습이 됩니까
학습이 되긴 되요
학습이 되긴 되는데 어떻게 되냐면 이쪽으로 가면 많이 플러스가 되고 이쪽으로 가야 되죠
원래는 이쪽으 로 가도 플러스는 되는데 플러스가 조금 돼요
그럼 얘가 더 빨리 늘어나서 확률이 이쪽은 더 빨리 늘어나고 이쪽은 천천히 늘어나서 상대적으로 시간이 지나면 얘가 확률이 더 크고 얘는 확률이 작아지는데 왜냐하면 확률은 다 더해서 1이 되야 되니까 어쨌든 한쪽이 더 빨리 늘어나면 나머지가 못 따라가면 확률 차이가 나게 되거든요
그래서 보상이 큰 행동은 확률이 많이 보상이 작은 행동은 확률이 조금 업데이트되는 거라서 얘네가 자기 확률 대로 되려면 되게 데이터가 많이 필요합니다
얘는 깎이고 얘는 올라가야 빨리 수렴하는데 둘 다 같이 늘어나니까 비율대로 되려면 속도 차이로 인해서 수렴할 때까지 굉장히 시간이 많이 걸려요
그래서 이런 단점이 있다
그래서 이제 리인폴스는 여기 R이 빠졌네요
현재는 더 이상 쓰지 않습니다
그래서 이제 여러가지 해결책이 있는데 그 해결책에 대해서는 좀 있다가 소개를 드리도록 하구요
정책망
import torch
import torch.nn as nn
import torch.optim as optim
import tqdm
class PolicyNetwork(nn.Module):
def __init__(self, input_dim, output_dim):
super(PolicyNetwork, self).__init__()
self.fc1 = nn.Linear(input_dim, 64)
self.fc2 = nn.Linear(64, 64)
self.fc3 = nn.Linear(64, output_dim)
def forward(self, x):
x = torch.relu(self.fc1(x))
x = torch.relu(self.fc2(x))
return torch.softmax(self.fc3(x), dim=-1)
REINFORCE
class ReinforceAgent:
def __init__(self, env, gamma=0.99, learning_rate=0.001, update_timestep=2000):
self.env = env
self.gamma = gamma
self.update_timestep = update_timestep
self.policy_network = PolicyNetwork(env.observation_space.shape[0], env.action_space.n)
self.optimizer_policy = optim.Adam(self.policy_network.parameters(), lr=learning_rate)
self.policy_old = PolicyNetwork(env.observation_space.shape[0], env.action_space.n)
self.policy_old.load_state_dict(self.policy_network.state_dict())
self.eps_clip = 0.2
self.K_epochs = 4
def select_action(self, state):
state = torch.FloatTensor(state).unsqueeze(0)
probabilities = self.policy_network(state)
action = torch.multinomial(probabilities, 1).item()
return action, probabilities[:, action].item()
def compute_returns(self, rewards, dones):
returns = []
R = 0
for reward, done in zip(reversed(rewards), reversed(dones)):
if done:
R = 0
R = reward + self.gamma * R
returns.insert(0, R)
return returns
def update_policy(self, trajectories):
for states, actions, rewards, dones in trajectories:
returns = self.compute_returns(rewards, dones)
returns = torch.FloatTensor(returns)
states = torch.FloatTensor(states)
actions = torch.LongTensor(actions)
log_probs = torch.log(torch.stack([self.policy_network(state)[action]
for state, action in zip(states, actions)]))
loss = -log_probs * returns
loss = loss.mean()
self.optimizer_policy.zero_grad()
loss.backward()
self.optimizer_policy.step()
def train(self, num_episodes):
timestep = 0
trajectories = []
for episode in tqdm.trange(num_episodes):
state, _ = self.env.reset()
done = False
states, actions, rewards, dones = [], [], [], []
while not done:
action, _ = self.select_action(state)
next_state, reward, done, _, _ = self.env.step(action)
states.append(state)
actions.append(action)
rewards.append(reward)
dones.append(done)
state = next_state
timestep += 1
if timestep % self.update_timestep == 0:
trajectories.append((states, actions, rewards, dones))
self.update_policy(trajectories)
trajectories = []
def evaluate_policy(env, agent, num_episodes=10):
total_reward = 0
for _ in range(num_episodes):
state, _ = env.reset()
done = False
steps = 0
while not done and steps < 1000:
steps += 1
action, _ = agent.select_action(state)
next_state, reward, done, _, _ = env.step(action)
total_reward += reward
state = next_state
return total_reward / num_episodes
실험
def evaluate_policy(env, agent, num_episodes=10):
total_reward = 0
for _ in range(num_episodes):
state, _ = env.reset()
done = False
steps = 0
while not done and steps < 1000:
steps += 1
action, _ = agent.select_action(state)
next_state, reward, done, _, _ = env.step(action)
total_reward += reward
state = next_state
return total_reward / num_episodes
초기화된 상태로 평가
import gymnasium as gym
env = gym.make("CartPole-v1", render_mode="rgb_array")
reinforce_agent = ReinforceAgent(env)
evaluate_policy(env, reinforce_agent)
25.9
50개 에피소드 후 평가
reinforce_agent.train(num_episodes=50)
evaluate_policy(env, reinforce_agent)
100%|██████████████████████████████████████████████████████████████████████████████████| 50/50 [00:00<00:00, 96.03it/s]
27.0