-
Notifications
You must be signed in to change notification settings - Fork 48
강화학습 관련 노하우
RL Korea 운영진과 소수의 멤버분들이 개인적으로 강화학습을 공부하고 여러 에이전트를 학습시키며 경험한 노하우를 적어보았습니다. 정답이라고 생각해서 적은 내용이 아니니 조언 정도로 생각해서 봐주시면 좋을 것 같습니다.
- Deep Learning에 대한 기본적인 이해를 하고 Deep RL을 공부하는 것이 이해하기 좋습니다.
- 강화학습 알고리즘의 분류 체계를 볼 때는 OpenAI Spinning Up에 있는 A Taxonomy of RL Algorithms을 참고하면 좋습니다.
- 강화학습의 세부분야의 흐름이나 중요한 논문들은 OpenAI Spinning Up에 있는 Key Papers in Deep RL을 참고하면 좋습니다.
- 강화학습 기초 공부를 끝냈다면 domain(도메인)이나 task을 하나 정해서 프로젝트 식으로 진행해보는 것이 좋습니다.
- 관련 블로그도 좋지만 원 저자의 자료를 보는 것이 좋습니다.
- 논문도 틀릴 수 있기 때문에 너무 틀린 부분에 시간을 쏟지 않는 것이 좋습니다.
- 단순히 논문만 읽고 알고리즘을 구현하기보다는 다음과 같은 것들을 생각해보고 구현하는 것이 좋습니다.
- 어떠한 문제 때문에 나오게 되었으며, 무엇을 말하고자 하는지, 왜 그것이 중요한지
- 장점
- 강점
- 의의
- 단점
- 부실한 점
- 보충되어야할 점
- 논문을 글로서 보는 것보다는 이 논문에서 하고자하는 방법론 측면에서의 단점
- 꼭 이 개념 or 방법을 이렇게 쓸 필요가 있었을까? 다른 방법은 없을까? etc.
- ICLR 등 논문에 대한 리뷰가 공개되어 있는 논문의 경우, 논문을 읽은 후 리뷰를 보면서 논문을 좀 더 비판적으로 보는 방법을 기를 수 있습니다.
- 각 알고리즘마다 맞는 환경이 있습니다. 따라서 어떠한 환경에서 에이전트를 학습할 때는 다양한 알고리즘을 테스트해보는 것이 좋습니다.
- 우선적으로 환경이 잘 돌아가는지 random agent를 돌려서 확인해보는 것이 좋습니다.
- state, action, reward, next state, done 출력해보기
- 각 action이 어떠한 action인지, 어떤 값인지를 확인하기
- 보통 딥러닝이라고 하면 데이터 전처리가 중요하다고 많이들 언급하시는 거처럼, 강화학습은 에이전트 학습 알고리즘 못지 않게 환경이 어떤지를 보는 것 또한 중요합니다. 단순히 reward plot만 보지 마시고, 논문에서 제시하는 RL 알고리즘이 그 환경에 유리하게 되지는 않았는지, 다른 task에서는 좀 불리할 수 있지 않은지, 환경의 random seed를 한 두개만 고정해서 cherry picking 하지는 않았는지 고려해보시는 것도 좋습니다.
- 주어진 환경이 simulator가 있는 환경인지, 환경이 stable한 환경인지 등 환경에 대한 정보들을 먼저 잘 확인해야 그 다음에 어떤 RL 알고리즘을 쓸 지를 정할 수 있습니다.
- Real world나 환경을 제작하여 사용할 시 구현 하기 전에 에이전트가 어떤 행동을 하기에 충분한 상태를 줬는지를 꼭 살펴봐야합니다.
- Gym, Atari 등과 같이 이미 만들어진 환경을 이용하여 강화학습 알고리즘의 성능을 테스트하는 경우 환경에 대한 수정이 어렵거나 원하는 환경이 없는 문제가 발생할 수 있습니다. 이런 경우 Unity ML-agents나 Pygame 등을 이용하여 직접 환경을 제작해야합니다.
- 환경을 직접 제작하는 경우 꼭 처음에는 직접 환경을 플레이하거나 에이전트가 탐험하는 동안 게임이 어떻게 진행되는지 살펴보면서 의도대로 환경이 작동하는지 확인해야 합니다. 가끔 특정 오브젝트가 너무 의도보다 느리게 움직이거나 갑자기 사라져버리는 등 환경에 버그가 존재하는 경우가 종종 있습니다. 이에 따라 환경의 정상적인 작동 여부를 꼭 확인하신 후 환경 제작을 완료하고 학습을 수행해주세요!
- 모든 상황에 대해 보상을 프린트해보면서 설정한대로 보상이 얻어지는지 확인해야합니다. 보상이 연속해서 많이 얻어진다거나 패널티가 너무 많이 발생해서 학습에 문제가 생기는 경우도 많이 있습니다.
- 직접 환경을 제작하고 알고리즘을 짜서 학습을 시키는 경우 학습이 잘 되지 않을 때 환경이 문제여서 학습이 잘 안되는지, 알고리즘이 문제여서 학습이 잘 안되는지 알기 어렵습니다. 이런 경우 미리 짜놓은 성능이 검증된 알고리즘을 이용하거나 다른 사람이 구현한 검증된 코드를 이용하여 직접 제작한 환경에서 학습을 시켜야합니다. 만약 검증된 알고리즘으로 학습했을 때 학습이 되지 않는다면 환경 제작에서 문제가 발생했을 가능성이 있습니다.
- 블로그나 다른 사람이 구현한 github 코드들은 틀릴 수 있으니 참고만 하시길 바랍니다.
- 이미 논문에서 다룬 환경을 통해 에이전트를 학습한다면 꼭 먼저 그 논문의 hyperparameter를 적용해 보세요. 예를 들어 DQN은 기본이 replay buffer의 크기가 100만입니다.
- 너무 쉬운 task에 학습을 할 경우에 해당 알고리즘을 제대로 구현한 것인지 알 수 없습니다. 예를 들어 학습하기 쉬운 카트폴에 해당 알고리즘을 구현했다고 그냥 넘어가지말고 다른 여러가지 환경에서도 해당 알고리즘을 구현해봐야 자신이 제대로 구현을 해본 것인지 알 수 있습니다.
- Tensor의 shape을 항상 주의 깊게 봐야합니다. 현재 tensor의 shape이 어떻게 되는지, 앞으로 계산할 때는 어떻게 변형시켜줘야 하는지 등을 잘 생각하고 구현해야 합니다.
- Tensor의 자료형이 현재 일반 list인지, numpy의 array인지, torch(or tf)의 tensor인지를 잘 확인해야 합니다.
- Return값을 구할 때는 경우에 따라 standardization을 해주는 것이 좋습니다.
- Discount factor의 경우 0.99라면 계속 곱해서 몇 번쯤 곱하면 0에 가까워지는지를 통해 episode 길이가 대략 얼마 정도가 될지 맞춰볼 수 있습니다.
- 에이전트가 잘하는 환경은 사람이 잘하는 환경과 다릅니다. 예를 들어 flappy bird의 경우 1초에 몇 번씩 random하게 행동하면 날아가 버립니다. 또한 mountain car의 경우에도 제자리에서 움직이지 않습니다. 걸어다니는 에이전트의 입장에서도 제자리에서 옴직이지 않는 경우가 많습니다. 따라서 에이전트가 어떻게 움직이는지를 시각적으로 rendering해서 확인해볼 필요가 있습니다.
- Reward가 너무 sparse한 경우에 intrinsic reward를 사용하거나 imitation learning을 하거나 hierarchical rl을 사용하는 것이 효과적입니다.
- 강화학습은 고질적인 문제인 exploration과 exploitation의 tradeoff를 해야합니다. 따라서 알고리즘에 따라 exploration을 장려할 수 있는 기법들을 사용해야합니다.
- Experience replay는 off-policy learning 기법을 통해 학습해야 합니다.
- Mse error를 사용할 때(예를 들어 DQN), target에 해당하는 부분은 gradient가 흘러가지 않도록 해야합니다. (PyTorch의 경우 detach() 하기)
- Mse error를 사용할 때는 반드시 input으로 들어오는 shape과 target으로 들어오는 shape을 같도록 해야 올바르게 loss function이 만들어집니다.
- Reward의 scale도 생각해줄 필요가 있습니다. 예를 들어 DQN에서는 reward를 -1에서 1로 clipping을 해줍니다.
- DQN에서는 보통 epsilon-greedy policy를 사용하게 되는데 epsilon을 0.1으로 고정시키고 학습시키는 것보다 처음엔 1로 두어서 random한 policy를 내뱉다가 일정 step 이후에는 epsilon을 decaying하는 것이 더 효과적인 exploration입니다. 여기서 중요한 것이 일정 step을 어떻게 잡느냐인데 환경마다 상태와 행동의 차원마다 달라집니다.
- target Q-Network는 일정 step마다 업데이트를 해야하는데 이것 또한 case by case마다 다릅니다.
- DQN은 Q-Value를 너무 과하게 좋은 값을 주어서 overestimation될 수 있기 때문에 Q-Value값이 과도하게 커지지 않도록 target값을 정의할 때 Double DQN에서 사용되는 loss를 사용하여 stable하게 학습이 되도록 하는 것이 좋습니다.
- Policy gradient에서 stochastic policy로 실험하는 경우에 policy의 entropy가 0으로 수렴하는 지를 통해 수렴 정도를 판단하면 좋습니다.
- Continuous control 문제에 강화학습을 적용할 경우에는 deterministic policy와 stochastic policy를 고려해볼 수 있습니다. deterministic policy의 경우 DDPG를 사용하고, stochastic policy의 경우는 gaussian distribution에서 mu, std를 output으로 하여 policy를 만드는 TRPO, PPO, SAC를 사용할 수 있습니다. 또는 행동을 쪼개서 discrete action 문제로도 만들 수 있습니다.
- Deterministic policy와 stochastic policy의 명확한 차이점을 아는 것이 구현하여 환경에 적용하는 데 좋습니다. deterministic policy는
$a = \pi(s)$ 이며, stochastic policy는$\pi(a|s) = P(a_t = a|s_t = s)$ 입니다. 즉, deterministic policy는 어떠한 고정된 정해진 policy에 해당하는 action이 나오며, stochastic policy는 어떠한 상태에서 어떠한 행동을 할 확률이 나오게 됩니다. - 그냥 Actor-Critic (A2C)는 왠만하면 학습이 잘 되지 않습니다. A3C나 Parallel로 여러 환경에 에이전트를 뿌려서 학습을 해야 하거나, 또는 ACER를 쓸 수도 있습니다.
- Episode의 끝마다 무조건 reward가 나온다면 제일 먼저 REINFORCE 알고리즘을 적용해보는 것이 좋습니다.
- 네트워크를 초기화할 때 stochastic policy의 경우 만약 행동이 3개라면 0.33, 0.33, 0.33과 같이 처음에는 행동마다 동일한 확률이 나오도록 하는 것이 학습에 좋습니다. 이렇게 하기 위해서는 neural network의 weight initialization에 대해서 알아야 합니다. (CS231n과 같은 강의를 참고)
- Actor-Critic (A2C) 할 때 regularization term으로 entropy bonus를 추가해주는 것이 초기에 suboptimal policy로 수렴하는 것을 제한함으로써 exploration을 향상하는데에 좋습니다.
- TensorFlow나 PyTorch를 사용할 경우 각각의 프레임워크에 있는 distributions 함수들을 이용하는 것이 편리합니다. PyTorch를 예를 들자면, discrete action일 때는 'import Categorical', continuous action일 때는 'import Normal'을 해서 관련 함수들을 사용하여 구현하면 좋습니다. torch.distributions 참고
- TRPO는 다른 알고리즘과는 다르게 이론적인 부분이 많습니다. 따라서 충분히 이론에 대해서 공부한 뒤에 구현을 하는 것이 좋습니다.
- TRPO에서 KL-Divergence의 hessian값을 구할 때는 two univariate Gaussians 사이에서의 KL-Divergence를 구해야하기 때문에 일반적인 KL-Divergence 수식이 아닌 Gaussians에서의 KL-Divergence 수식을 사용해야합니다.
- Backtracking line search 사용 시, break하고 빠져나올 if 문을 잘 정의해줘야 합니다. 논문에 나와있는 것은 KL-Divergence의 값이 Delta보다 작아야하고 Backtracking line search의 while문이 만족되어야 합니다.
- GAE(Generalized Advantage Estimator)는 gamma나 lambda의 값에 민감하니 GAE 논문을 잘 참고하기 바랍니다.
- TRPO와 PPO에서 return과 GAE를 구할 때는 보통 computation을 줄이기 위해 reversed를 하여 뒤에서부터 구합니다.
- TRPO에서 GAE를 쓰지 않을 경우 Critic을 업데이트 할 때 mini batch로 쪼개서 업데이트를 하지 않을 것이기 때문에 return에서 standardization 해주는 것이 좋으며, GAE를 쓸 때는 GAE에 standardization를 해주는 것이 좋습니다.
- PPO에서 GAE를 쓰지 않을 경우 Critic이 어짜피 mini batch로 쪼개서 업데이트가 되기 때문에 따로 return값을 standardization 해주지 않아도 되고, GAE를 쓸 때는 TRPO와 마찬가지로 standardization 해주는 것이 좋습니다.
- 원래의 PPO version 1은 value function을 clipping하지는 않습니다. 하지만 version 2에서는 value function까지 clipping을 해줌으로써 critic을 업데이트합니다. value function까지 clipping을 해주는 것이 학습 시에는 더 stable할 수 있습니다.
- PPO는 단순히 clipping을 하는 알고리즘이기 때문에 계산량이 더 간편하고 mini batch로 나눠서 학습시킬 수 있다는 장점이 있습니다.
- DDPG는 haperparameter에 따라 성능이 불안정해지기 때문에 haperparameter를 매우 잘 조정해주어야 합니다.
- Exploration으로 주는 noise는 unstable한 환경일 경우 exploration이 잘 안될 수 있습니다.
- Haperparameter 조정 시, OU noise에 있는 theta와 sigma도 조정을 해주어야 하는데, 이 점이 쉽지 않습니다. 그래서 대체방법으로 초기 몇 step까지만 random action을 취하도록 해서 exploration을 장려하고, 이후에는 noise 자체를 0으로 주고(theta=0, sigma=0) action을 뽑기도 합니다.
- OU noise말고도 epsilon-greedy 방법을 사용할 수도 있습니다. 하지만 로봇 팔이나 2d car처럼 물리적인 관성이 존재하는 에이전트는 OU noise가 더 쓸만한 것으로 알려져 있습니다.
- deterministic policy를 output으로 내뱉는 neural net의 경우, action에 대해 직접적으로 clipping을 해주어야 합니다. 예를 들어 'np.clip(action, env.action_space.low, env.action_space.high)' 와 같이 action_space에 맞게끔 clipping을 해주어야 train이 끝나고 test를 했을 때, policy가 한 곳으로 수렴하는 것을 볼 수 있습니다.
- step size 가 trust region method에 의해 조정이 되는 TRPO, PPO와 달리 DDPG는 학습 후반에 step size 문제로 성능이 급격히 떨어지는 경우가 많습니다. 때문에 구현체들을 보면 optimizer로 바로 업데이트를 하지 않고 gradient를 clipping 한 후 업데이트 하도록 구현된 경우가 많은데, 그 clipping value를 정하는데 많은 시행착오가 필요합니다.
- Soft target update에서 쓰이는 tau는 보통 0.005 정도 두고 진행합니다.
- SAC 구현체는 DDPG의 구현체와 비슷한 점이 많기 때문에 DDPG를 먼저 구현하고 SAC를 구현하는 것이 좋습니다.
- SAC 구현 시, entropy term을 조정하는 temperature parameter alpha를 추가적으로 구현하는 것이 학습 측면에서 stability가 좋습니다. (SAC version 1이 아닌 SAC version 2를 구현하는 것이 좋습니다.)
- alpha의 optimizer 또한 adam과 같은 optimizer를 사용하여 alpha를 근사해나갑니다. 여기서 중요한 것이 alpha를 직접적으로 근사하는 것이 아니라 log alpha를 만들어서 log alpha가지고 optimizer로 근사를 하고, exp(log alpha)를 하여 alpha로 사용하게 됩니다. 이렇게 되면 alpha를 [0,1) 사이로 제한하는 parameter로 만들 수 있습니다.
- SAC를 구현할 때, alpha를 추가적으로 찍어보면서 1부터 잘 수렴해가는지, target entropy와 가까워지도록 낮아지지만, automatic하게 조정이 잘 되는지를 살펴봐야합니다.
- SAC의 critic은 two Q-function을 사용하여 Q-value을 뽑는 것이 overestimation bias를 완화하는데에 좋습니다.
- 하지만 SAC는 reward가 sparse한 경우 학습이 어려울 수 있습니다. 이럴 경우, intrinsic reward를 사용하거나 imitation learning을 사용하는 것이 좋습니다.
- C51은 논문과 구현체 사이의 차이가 큰 것으로도 유명합니다. 논문에서는 Wasserstein distance 를 가지고 수렴을 증명하려 했지만, 결국 구현체는 cross entropy를 쓰는데, 이후에 QRDQN에서 이 이론적인 약점을 보완했으니, 이 부분에 대한 고민으로 지나치게 많은 시간을 보내지는 않는 것이 좋습니다.
- C51는 action value Q를 categorical distribution으로 표현하기 때문에 action value의 min-max가 제한되어 있습니다. 이는 에이전트의 action value 표현력을 제한하는 원인이 됩니다. 때문에 리워드와 discount factor 를 좀 낮추면서 존재 가능한 모든 action value 가 제한된 action value 범위 안에 들어가도록 해야하며, 에이전트의 액션뿐만 아니라 action value distribution 도 모니터링해야 합니다.
- C51의 구현체 중 상당수가 target distribution projection을 구현할 때 이중 for loop를 쓴다는 점에 있습니다. 이는 전체적인 알고리즘 학습 시간을 배로 늘려버리는 단점이 있기에 가장 간단한 환경인 cartpole 에서도 그 느린 속도를 체감할 수 있을 정도입니다. categorical distribution의 bin index를 for loop 가 아닌 numpy 등을 사용하여 array 형태로 이중 for loop 중 하나를 없애서 알고리즘을 보다 가볍게 만드셔야 합니다.
- Quantile regression의 loss 인 quantile huber loss는 구현 시 다른 loss 처럼 quantile support의 target 과 prediction 을 1대1로 error를 구하시면 안됩니다. cumulative density function을 regression하는 것이기 때문에 quantile의 순서에 잘 맞느냐에 대해서도 loss로 정의되는 개념이기에, N개의 target 과 prediction 의 quantile 에 대해 N by N 개의 pair로 error를 합하고 평균을 내야합니다.
- QRDQN을 구현하면서 느꼈던 단점 중 하나가 optimizer와 하이퍼파라메터에 상당히 민감했단 거였습니다. 텐서플로우에 디폴트 값으로 정의된 ADAM의 epsilon 같은 하이퍼 파라메터들을 그대로 쓰지 말고, 논문대로 변경이 필요합니다. 이는 quantile huber loss가 mse나 crose entropy 같은 다른 loss 들에 비해 복잡한 형태였기 때문에 학습이 민감했던 거 아닌가 사료됩니다.
- QRDQN는 C51과 달리 action value를 discretizaiton 할 필요도 없고 범위 제약도 없지만, 논문에서도 언급되어 있듯이 Q 값의 overestimation의 위험이 있습니다. 때문에 discount factor를 낮추거나, Double DQN을 써서 overestimation을 줄이기 위한 시도도 필요합니다.
- Implicit quantile network는 QRDQN과 달리 quantile probability tau를 무작위로 샘플링해서 필요한 갯수(8개)만 가지고 학습을 하기 때문에, 출력단도 다른 QRDQN에 비해 구조가 비대하진 않고 학습 시 시간도 덜 드는 편입니다.
- 구현 시에 특이한 점은 state(ex. atari 이미지)를 받는 convolution layer 인 psi와 샘플링된 tau를 받는 embedding function phi가 나뉘어져 있다는 것인데 이 둘을 결합하는 방법을 논문에선 2가지 제시합니다. 하나는 psi와 phi를 element-wise로 곱하는 것, 또 하나는 둘을 element-wise 곱한 것에 psi를 더해서 마치 res net과 같은 형태로 만들어 주는 것입니다. atari 대신 box2d 와 간단한 openai gym에서 적용해본 필자의 경험으론 후자가 조금 더 빨랐습니다.
- 앞서 언급한 psi와 phi 중 cartpole이나 mountain car 같은 저차원의 state를 받는 환경에선 psi 자체를 없애고, phi의 출력을 state 의 dimension 과 맞춰서 state에 직접 element-wise 로 곱해줘도 동일한 결과를 얻을 수 있었습니다. 허나 이는 환경에 따라 그 결과가 많이 다를 수 있으므로, 참고만 하시기 바랍니다.
- 보통 액션을 결정하는 부분을 구현 시 risk averse RL인 conditional VaR를 쓰는 경우가 많은데, 아무래도 논문에서도 conditional VaR가 성능이 잘 나오기도 했고, 환경의 변수가 크게 바뀔 때 conditional VaR 같은 risk averse RL가 좀 더 강건한 성능이 나왔던 경우가 많았기 때문이라 봅니다. 허나, 자율주행 판단 알고리즘처럼 때로는 과감하게 추월이 필요한 상황에서도 risk averse RL로 설정되어 있으면 차선 변경 없이 쫄보처럼 움직이는 경우도 있기 때문에 risk sensitive RL 로써 환경에 맞는 적절한 방법이 있는지 고민이 필요합니다.
Exploration 이라는 분야는 '랜덤하게 행동을 선택하는 것으로는 보상을 받기 어려운 환경에서 어떻게 강화학습을 사용할 수 있을까' 하는 고민에서 시작되었습니다. 고전 강화학습에서 배운 epsilon-greedy도 포함되고, Bandit 문제를 풀때 많이 보는 optimistic initial value나 Upper Confidence Bound (UCB)역시 exploration의 일종으로 볼 수 있습니다.
그러나 최근 트렌드인 Atari나 MuJoCo 등 더 크고 복잡한 환경에서는 통상적으로 좀 더 다른 기법을 사용합니다. 크게 많이 쓰이는 기법은 NoisyNet, DQN+CTS, DQN+PixelCNN, ICM, RND입니다.
-
NoisyNet 은 DQN에 noise를 주는 방식입니다. Rainbow 가 워낙에 baseline 으로 많이 인용되기 때문에 NoisyNet의 구현체가 많으므로 여러 개를 찾아 읽어보는 걸 권장합니다.
-
DQN+CTS 와 DQN+PixelCNN 은 비슷한 경험을 몇번 했는지 세어서 (pseudo-count) 적게 경험한 것을 마주하면 추가 보상을 주는 방법입니다. 두 논문 다 구현하기 굉장히 어렵기 때문에 다른 exploration 기법을 먼저 시도하는 걸 추천합니다. 만약 구현하신다면, 더 상세하게 설명된 CTS 부터 읽고 구현하는 걸 추천합니다.
-
ICM 과 RND 는 위 논문과 비슷하게 내적 보상 (Intrinsic reward)을 계산하는데, 단순하게 인공신경망을 이용하기 때문에 위의 두 논문보다 구현하기 쉽습니다.
-
ICM 과 RND를 조금만 심오하게 살펴보면 Model-based Reinforcement Learning이라고 볼 수 있습니다. 일반적인 로보틱스에 쓰이는 Model-based Reinforcement Learning은 오차를 줄이기 위해 학습한다고 볼 수 있지만, ICM과 RND는 그 오차를 계속적으로 증폭시키기 위한 Model-based Reinforcement Learning이라고 볼 수 있습니다.
그 외 전반적인 팁들은:
- 구현 후 성능 실험을 할 때 가장 확실한 건 Montezuma's Revenge 에서 돌려보는 것입니다. Exploration 기법을 동반한 에이전트와 (PPO+RND) 와 동반하지 않은 에이전트 (PPO) 의 성능을 비교해보세요.
- 위처럼 ablation study 를 할때 꼭 기존 논문에서 쓰인 에이전트를 똑같이 쓰세요. NoisyNet, CTS, PixelCNN은 DQN 이고, ICM, RND 는 PPO입니다.
- Montezuma's Revenge에서 논문의 결과에 비해 1000점 정도의 차이가 나는 것은 코드보다 시드의 문제일 가능성이 큽니다.
- 내적 보상 논문들 중 하나를 구현할 경우, normalization 부분을 상세하게 읽어보고 꼭 맞게 구현하세요! 이 부분이 잘못될 경우 아예 학습하지 않을 수도 있습니다. 또한 외적 보상 (Extrinsic reward)를 0으로 고정시키고 내적 보상만을 이용하여 breakout 같은 환경에서 학습을 해보세요! 내적 보상만을 이용해서 학습이 잘되는 경우 구현이 잘 되었다고 생각할 수 있습니다.
- RND 는 알고리즘은 간단하지만 논문에 많은 trick들을 소개하는데, 우선 dual value head 와 discount factor 만 다르게 한 버전을 구현하고 실험하는 걸 추천합니다.
- AlphaGo의 근본적인 아이디어는 Monte Carlo Tree Search (MCTS)를 어떻게 개선할 것인가에 대한 고민에서 나왔다고 생각합니다.
- MCTS를 확실히 이해하는게 중요합니다. (틱택토 같은) 간단한 환경을 만들어서 MCTS를 먼저 적용해보세요. Deep RL 적용은 그 이후에 진행해도 충분합니다.
-
Scaling RL에서는 RL에 대한 지식에 더해서 서버, 네트워크에 대한 지식이 필요합니다. pytorch의 경우에는 distributed framework을 지원하지 않아 일반적으로 zmq server를 사용하거나 python 내부의 multiprocessing library를 사용하여 구현을 합니다. tensorflow의 경우에는 distributed tensorflow를 사용할 수도 있지만 자료가 굉장히 부족하기 때문에 tensorflow 또한 multiprocessing library를 사용하는 경우가 많습니다. 하지만 distributed tensorflow를 사용한다면 컴퓨터의 성능을 최대한으로 끌어올릴 수 있을 것입니다.
-
IMPALA, APE-X의 경우에는 off-policy하게 돌아가기 때문에 학습을 하는 모델은 gpu에서 학습을 하고 그외 actor들은 cpu에서 데이터를 수집하기 때문에 서버의 컴퓨팅 파워 분배 또한 중요합니다.
- 논문에서 GAIL의 에이전트는 TRPO를 사용하였지만, 구현이 보다 간편한 PPO도 가능합니다.
- 다만, On-policy 로만 적용이 가능하기에 리플레이 버퍼는 쓰지 못하고, A3C나 distributed PPO처럼 분산환경으로 구현하여 적용하는 경우가 있습니다. 만일 multi-process 를 쓰지 못하는 경우는 2,3번의 에피소드 동안 roll-out trajectory를 모아두었다가 5 epoch 정도 에이전트를 업데이트 하는 방법도 있습니다.
- Roll-out trajectory를 모을 땐, GAIL 의 discriminator D가 내놓는 리워드를 포함하여
$(s_t, a_t, r_t)$ 로 샘플링하도록 구현한 경우도 있습니다. 허나$(s_t, a_t)$ 로만 샘플링을 하고 난 후 discriminator 먼저 업데이트하고$r_t=-\log D(s_t, a_t)$ 로 리워드를 새로 뽑은 다음에 에이전트를 업데이트해도 무방합니다. - PPO 에도 적용하는 GAE가 GAIL에도 유용하게 쓰일 수 있습니다.
- GAIL도 GAN과 마찬가지로 하이퍼 파라메터의 변화에 민감합니다. 때문에 roll-out trajectory를 가지고 discriminator와 agent를 각각 몇번 업데이트해야 하는지와 learning rate를 얼마나 해주는지도 관건인데, 보통 GAN의 generator에 해당되는 agent를 더 자주 업데이트하는 구현들이 많았습니다.
- Hyperparameter의 경우, 기본적으로 expert와 learner를 얼마나 update할 것인지가 제일 중요합니다. 보통 2:10, 1:5, 3:15, 1:2 등의 비율로 학습을 합니다. 이후로는 learning rate, sample size(PPO의 경우), batch size 등이 있습니다.
- expert와 learner의 accuracy를 반드시 출력해보셔서 learner가 얼마나 expert처럼 올라왔는지 체크해보시는 것이 좋습니다. 보통 expert는 0.8 ~ 0.9 정도로 출력이 되며, learner는 0.2 ~ 0.3에서 시작해서 0.8까지 올라갔을 때 flag를 걸어두어서 더이상 discriminator가 학습이 되지 않도록 막아주셔야 합니다.
- VAIL은 discriminator 앞에 VAE의 encoder를 붙이고, Variational Discriminator Bottleneck(VDB) constraint를 Lagrangian 형태로 loss 에 올린 다음, dual gradient method 를 통해서 문제를 푸는 방식이기 때문에 Lagrangian multiplier 또한 trainable variable로 정의해서 구현하셔야 합니다.
- 학습 도중에 VDB constraint 을 프린트해보면 constraint 를 항상 만족하진 못하는데 (mutual information의 upper bound를 왔다갔다 함.), 아무래도 Lagrangian 형태의 unconstrained optimization 문제로 정의해서 간접적으로 constraint를 만족시키려 했기 때문인 것 같습니다.
- Lagrangian multiplier 의 learning rate를 올리면 초반 학습이 상대적으로 더뎌지더라도 constraint를 만족시키려고 하고, 낮추면 GAIL에 가까워지면서 초반 학습이 빠른듯 하다가 후반에 robustness 가 떨어져서 가끔씩 퍼포먼스가 감소하는 것을 볼수 있습니다. 이를 감안하여 Lagrangian multiplier의 learning rate를 조절하시는 것이 좋습니다.