PyTorch로 스크래치에서 PPO 코딩 (3/4 부)

4 부작 시리즈의 로드맵.

시리즈의 Part 3에 오신 것을 환영합니다. 여기서는 PyTorch를 사용하여 처음부터 PPO (Proximal Policy Optimization) 코딩을 완료합니다. 파트 1파트 2를 읽지 않았다면 먼저 읽으십시오 .

다음은 코드입니다. https://github.com/ericyangyu/PPO-for-Beginners

우리는 우리가 중단 된 곳에서 따기 될 것이다 : 5 단계는 여기에서 찾을 수 있습니다 다시 의사의 개요입니다 여기 뿐만 아니라 :

OpenAI의 Spinning Up 문서에있는 PPO의 의사 코드.

계속하기 전에 6 단계와 7 단계에 대해 반복 당 여러 epoch를 수행 할 것 입니다. 나중에 하이퍼 파라미터로 epoch 수 n을 추가 할 것 _init_hyperparameters입니다. 5-7 단계에서 매개 변수 Θ 및 Φ에 k 개의 첨자 가 있기 때문에이 작업 을 수행합니다. 이는 k 번째 반복의 매개 변수와 훈련의 현재 순간 사이에 차이가 있음을 의미하며, 이는 각 반복에도 실행할 자체 epoch 집합이 있음을 의미합니다. 해당 단계에 도달하면이를 다시 확인하고 이에 대한 코드를 작성합니다.

이제 5 단계를 살펴 보겠습니다.

5 단계

여기에 정의 된 Advantage 함수를 사용합니다 . TL; DR 다음은 Vᵩₖ로 수정 된 방정식입니다.

장점 기능.

여기서 Q는 ^ π 인 상태 액션 쌍의 Q 값 (S, A) 및 Vᵩₖ 일부 관측 값 다음에 파라미터가 우리 φ 비평가 네트워크에 의해 결정된 K 번째 반복.

여기 공식에서 수정 한 것은 예측 된 값이 k 번째 반복에서 매개 변수 Φ를 따르도록 지정하는 것이 었습니다 . 이는 7 단계에서 나중에 i 에서 매개 변수 Φ를 따라 V (s)를 다시 계산해야하기 때문에 중요합니다. -th epoch. 그러나 Q- 값은 각 롤아웃 후에 결정되고 Vᵩₖ (s)는 네트워크에 대한 여러 업데이트를 수행하기 전에 결정되어야합니다. 의사 코드와 일치하지 않음), Vᵩₖ (s) 및 이점은 epoch 루프 전에 계산되어야합니다.

이에 접근하는 방법은 서브 루틴을 사용하여 Q- 값과 예측값 Vᵩₖ (s)를 개별적으로 계산하는 것입니다. 우리는 이미으로 계산 된 Q- 값을 가지고 compute_rtgs있으므로 우리가 걱정해야 할 것은 Vᵩₖ (s)입니다.

evaluateVᵩₖ (s)를 계산 하는 함수 를 만들어 봅시다 .

def evaluate(self, batch_obs):
  # Query critic network for a value V for each obs in batch_obs.
  V = self.critic(batch_obs).squeeze()
return V

다음으로 이점을 간단히 계산할 수 있습니다.

# Calculate V_{phi, k}
V = self.evaluate(batch_obs)
# ALG STEP 5
# Calculate advantage
A_k = batch_rtgs - V.detach()

이제이 코드에서 사용하는 유일한 트릭 중 하나는 이점 정규화입니다. 시행 착오를 통해 원시 이점을 사용하면 PPO 훈련이 매우 불안정하다는 것을 발견했습니다 (예, Part 1의 그래프보다 훨씬 더 불안정하고 분산이 더 큽니다). 정규화 이점은 의사 코드에 있지 않지만 실제로 수치 알고리즘은 다른 차원도 규모가 다를 때 제대로 작동하지 않기 때문에 매우 중요합니다. 기술적으로는 최적화이기 때문에 이점 정규화를 파트 4에 적용하려고했지만 PPO로 합리적인 수준의 성능을 유지하려면 코드에 거의 필요하다는 것을 알았습니다. 그래서 여기 있습니다 :

# Normalize advantages
A_k = (A_k - A_k.mean()) / (A_k.std() + 1e-10)

지금까지 코드는 다음과 같습니다.

이제 6 단계를 살펴 보겠습니다.

6 단계.

아, 네, 방에있는 코끼리. PPO의 생명과 피. 이 공식은 액터 네트워크의 매개 변수 Θ를 업데이트하는 방법을 알려줍니다. 다행히도 우리에게 필요한 대부분은 이미 계산되었거나 기존 서브 루틴으로 계산할 수 있습니다.

먼저 left surrogate 함수의 비율을 살펴 보겠습니다.

매개 변수가 Θₖ 인 행동 확률 대비 매개 변수가 Θ 인 행동 확률의 비율.

좋아, 그래서 우리는 가장 최근의 롤아웃 동안 우리가 취한 행동의 로그 확률 (probs)을 계산해야 할 것입니다. 다시 말하지만, 우리는 로그 probs 대신 원시 액션 probs을 찾는 이유에 대한, 여기에 이유를 설명하고 자원 여기에 또 다른됩니다.

최하위 로그 프로브 세트는 k 번째 반복 (이미에서 가지고 있음 batch_log_probs) 에서 매개 변수 Θ와 관련이있는 반면, 상단은 현재 epoch에 있습니다 (원래 의사 코드도 여러 epoch를 가정 함). 로그 문제를 계산하기 위해 완전히 새로운 서브 루틴을 정의하는 대신 evaluate.

먼저 evaluate작업의 로그 문제 도 반환 하도록 수정하겠습니다 .

def evaluate(self, batch_obs, batch_acts):
  ...
  # Calculate the log probabilities of batch actions using most 
  # recent actor network.
  # This segment of code is similar to that in get_action()
  mean = self.actor(batch_obs)
  dist = MultivariateNormal(mean, self.cov_mat)
  log_probs = dist.log_prob(batch_acts)
# Return predicted values V and log probs log_probs
  return V, log_probs

V, _ = self.evaluate(batch_obs, batch_acts)
A_k = batch_rtgs - V.detach()
...

for _ in range(self.n_updates_per_iteration):
  # epoch code
def _init_hyperparameters(self):
  ...
  self.n_updates_per_iteration = 5
매개 변수가 Θₖ 인 행동 확률 대비 매개 변수가 Θ 인 행동 확률의 비율.

이미 하단 로그 프로브 ( batch_log_probs)가 있습니다. π_Θ (aₜ | sₜ)를 찾아야 evaluate합니다. 다시 사용할 수 있습니다 . 이것은 우리가를 두 번째로 호출 evaluate하는 것이며 이번에는 이전이 아닌 epoch 루프에있을 것입니다. evaluate우리는 단지 추출물로 이전이라는 V장점을 계산하는,이 시대 루프 전에 권리입니다.

for _ in range(self.n_updates_per_iteration):
  # Calculate pi_theta(a_t | s_t)
  _, curr_log_probs = self.evaluate(batch_obs, batch_acts)

# Calculate ratios
ratios = torch.exp(curr_log_probs - batch_log_probs)

# Calculate surrogate losses
surr1 = ratios * A_k
surr2 = torch.clamp(ratios, 1 - self.clip, 1 + self.clip) * A_k
...
def _init_hyperparameters(self):
  ...
  self.clip = 0.2 # As recommended by the paper

마지막으로 전체 액터 손실을 계산합니다.

actor_loss = (-torch.min(surr1, surr2)).mean()

액터 네트워크에서 역 전파를합시다. 먼저 액터 매개 변수에 대한 Adam 최적화 프로그램을 정의해야합니다. 하자는 점에서 할 __init__.

from torch.optim import Adam
class PPO:
  def __init__(self, env):
    ...
    self.actor_optim = Adam(self.actor.parameters(), lr=self.lr)
def _init_hyperparameters(self):
    ...
    self.lr = 0.005

# Calculate gradients and perform backward propagation for actor 
# network
self.actor_optim.zero_grad()
actor_loss.backward()
self.actor_optim.step()
__init__
배우다
평가, _init_hyperparameters

두 번째 단계 인 7 단계로 이동하겠습니다.

7 단계.

이것은 처음에는 정말 무섭게 보일 수 있지만 실제로는 현재 시대의 예측 값 Vᵩ (sₜ)에서 예상 값의 평균 제곱 오차로 비평가 매개 변수를 이동 보상으로 업데이트하고 있습니다. 우리는 우리를 torch.nn위해 MSE를 계산할 주어진 클래스를 사용할 것 torch.nn.MSELoss입니다. 다음은 몇 가지 문서 입니다. 원한다면 토치를 사용하는 대신 자신 만의 MSE 함수를 작성할 수도 있습니다. 너무 어렵지 않아야합니다.

먼저, 비평가 네트워크에 대한 또 다른 Adam 최적화 프로그램을 정의 해 보겠습니다.

self.critic_optim = Adam(self.critic.parameters(), lr=self.lr)

# Calculate V_phi and pi_theta(a_t | s_t)    
V, curr_log_probs = self.evaluate(batch_obs, batch_acts)

critic_loss = nn.MSELoss()(V, batch_rtgs)
# Calculate gradients and perform backward propagation for critic network    
self.critic_optim.zero_grad()    
critic_loss.backward()    
self.critic_optim.step()

이것이 7 단계입니다! 지금까지 코드는 다음과 같습니다.

__init__
배우다
나머지 코드는 6 단계 이후 변경되지 않았습니다.

이제 피날레를 위해… 8 단계.

8 단계.

예, 아마도 지금까지 가장 어려운 단계 일 것입니다. 그래도 9 단계가 보일 때까지 기다리십시오.

좀 더 진지하게 살펴보면, t_so_far몇 번의 반복을 실행할지 추적하기 위해 2 부 시작 부분에서 설정 한 값을 증가시키는 것을 잊을 수 없습니다 . 에서 batch_lens반환 된 것을 활용하여 그렇게합시다 rollout.

import numpy as np
...
# ALG STEP 2
while t_so_far < total_timesteps:
  ... 
  batch_obs, batch_acts, batch_log_probs, batch_rtgs, batch_lens = self.rollout()
# Calculate how many timesteps we collected this batch   
  t_so_far += np.sum(batch_lens)

import gym
env = gym.make('Pendulum-v0')
model = PPO(env)
model.learn(10000)

이제 궁금 할 것입니다. Eric, ppo.pynetwork.py 만 작성 했지만 Part 1에서는 main.py , arguments.pyeval_policy.py도 있습니다. 또한 로깅, 행위자 및 비평가 네트워크 저장, 명령 줄 인수 구문 분석, 사용자 지정 하이퍼 파라미터 등과 같은 더 많은 기능이 있습니다. 또한 초보자 용 PPO 코드는 위의 스크린 샷과 약간 다릅니다.

너가 확실히 맞아. 그러나 간단하게 유지하기 위해 PyTorch로 베어 본 PPO 구현을 작성하는 방법을 배우는 것과 관련이 없으므로이 시리즈에서 이러한 부분을 코딩하는 방법에 대해서는 논의하지 않을 것입니다. 나머지 코드의 기초 역할을하는 베어 본 PPO 위에 모든 추가 항목을 뿌릴 것을 약속합니다.

대신 추가 기능이 베어 본 PPO 구현과 동기화되어 작동하는 방식을 직접 살펴 보는 것이 좋습니다. 내가보기 엔 사용하는 것이 좋습니다 pdb부터 내 코드를 통해 단계로, 또는 파이썬 디버거 if __name__ == '__main__':에서 main.py . 사용 방법을 모르는 경우 여기에서pdb 빠르게 시작 하십시오 . pdb이미 전문가 라면 여기에 문서가 있습니다.

저장소 README.md 에는 "사용법"에서 코드를 실행하는 방법에 대한 지침이 포함되어 있습니다. 내 모든 파일과 코드는 매우 자세하고 잘 문서화되어 있으므로 마음껏 탐색 할 수 있습니다. 가능한 한 간단하고 모듈화 할 수 있도록 구성했습니다.

이것으로 시리즈의 Part 3을 마칩니다. 이 시점에서 의사 코드에서 PPO를 완전히 구현하고 1 부에서 본 그래프에서 성능을 얻을 수 있어야합니다.이 부분이 소화해야 할 내용이 많다는 것을 알고 있으므로 질문이 있으시면 주저하지 마십시오. eyyu@ucsd.edu로 저에게 연락하거나 아래에 의견을 남겨주세요.

4 부에서는 베어 본 PPO에서 수행 할 수있는 몇 가지 최적화를 탐색하여 성능을 높이고 분산을 줄입니다. 그러나 파트 4가 나올 때까지 시간이 걸릴 수 있습니다. 그때까지이 시리즈가 지금까지 도움이 되었기를 바랍니다.

Suggested posts

AI는 물리학이 자연의 법칙을 연구하는 것처럼 지능의 법칙을 연구합니다.

AI는 물리학이 자연의 법칙을 연구하는 것처럼 지능의 법칙을 연구합니다.

AI에 대한보다 정확한 정의는 그 역할과 영향을 더 잘 이해할 수있게합니다. AI에 대한 많은 정의가 있습니다. 누가 추가로 필요합니까? 나는 우리가 생각한다 : 현재의 정의는 인공 지능을 잘못 구성함으로써 많은 혼란을 야기한다.

“인공 일반 지능”이란 무엇입니까?

“인공 일반 지능”이란 무엇입니까?

일부 : 인공 일반 지능 소개. “어딘가에 놀라운 것이 알려지기를 기다리고 있습니다.