Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PPO #28

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open

PPO #28

wants to merge 11 commits into from

Conversation

nelsonayamashita
Copy link
Contributor

Coloquei o notebook com a implementação de PPO da aula, mas acredito que ela não esteja funcionando 100% (vide gráfico no fim do nb).

@Berbardo Berbardo requested a review from a team November 1, 2020 21:12
@Berbardo

This comment has been minimized.

@fernandokm

This comment has been minimized.

.vscode/settings.json Outdated Show resolved Hide resolved
@fernandokm

This comment has been minimized.

Comment on lines 302 to 306
" with torch.no_grad():\n",
" _, v = self.actorcritic.forward(states)\n",
" _, v2 = self.actorcritic.forward(next_states)\n",
" \n",
" advantages, returns = self.compute_gae(rewards, dones, v, v2)\n",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Existe um jeito mais elegante e mais eficiente de pegar v e v2 sem ter que dar esse forward? Achei que ficou meio desnecessário mas foi o que eu pensei na hora.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Como os estados estão em ordem cronológica, o v2[i] é sempre o v[i+1]. Se você quiser otimizar ao máximo dá pra colocar o último v2 no v e passar tudo de uma vez no forward, aí mudar o gae pra usar só o v[i] e o v[i+1]. Mas não sei se tem muita coisa pra melhorar ;P, esse que eu comentei já pode ficar um pouco estranho também.

Copy link
Member

@fernandokm fernandokm Nov 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Não precisaria necessariamente mudar o gae. Da pra fazer isso:

with torch.nograd():
    _, vs = self.actorcritic.forward(numpy.append(states, next_states[[-1]], axis=0))
v1 = vs[:-1]
v2 = vs[1:]

I.e. a mesma coisa que o @Berbardo disse, mas separando em v1 e v2 antes de mandar pro gae. Se tiver um comentário apropriado lá no meio, acho que não tem muito problema. Mas é certamente menos didático.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nelsonayamashita @fernandokm mexemos nisso aqui?

@nelsonayamashita nelsonayamashita marked this pull request as ready for review January 18, 2021 21:09
@nelsonayamashita

This comment has been minimized.

@nelsonayamashita

This comment has been minimized.

@nelsonayamashita

This comment has been minimized.

@nelsonayamashita nelsonayamashita requested a review from Berbardo July 1, 2021 21:21
@Berbardo Berbardo requested a review from a team July 8, 2021 21:09
Comment on lines +56 to +62
Nota-se que:
- Quando a vantagem é positiva, se **r** aumentar, então **L** aumenta. No entanto, esse benefício é limitado pelo clip: se **r > 1+ε**, não há mais benefício para **r** aumentar.
- Quando a vantagem é negativa, se **r** diminuir, então **L** aumenta. No entanto, esse benefício é limitado pelo clip: se **r < 1-&epsilon;**, não há mais benefício para **r** diminuir.

A seguinte imagem pode te ajudar a visualizar o clip. Note que todos os valores fora do clip estipulado estão constantes:

![imagem ilustrando o clip](imgs/clip.png)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Está sem o algoritmo de PPO em LaTeX (não sei se precisa)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acho legal por consistência, mas não vejo muito problema em não ter

"Como já foi mencionado, a restrição ($KL < \\delta$) imposta em TRPO torna o algoritmo relativamente complicado. PPO é uma tentativa de simplificar esse algoritmo. Ao invés de utilizar trust regions, PPO mexe diretamente com a função objetivo:\n",
"\n",
"$$\n",
" L(\\theta_{\\mathrm{old}},\\theta) = E_{s,a\\sim\\pi_{\\theta_{\\mathrm{old}}}} \\Bigl[\\min\\left(r A^{\\pi_{\\theta_{\\mathrm{old}}}}(s,a),\\, \\operatorname{clip}(r,1-\\varepsilon,1+\\varepsilon) A^{\\pi_{\\theta_{\\mathrm{old}}}}(s,a)\\right)\\Bigr],\n",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

não entendi esse (r, 1-eps, 1+eps)

"\n",
"A seguinte imagem pode te ajudar a visualizar o clip. Note que todos os valores fora do clip estipulado estão constantes:\n",
"\n",
"![imagem ilustrando o clip](imgs/clip.png)\n"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acho que compensa explicar melhor o resultado prático disso

Comment on lines +118 to +138
" def __init__(self, observation_shape, action_shape):\n",
" super(ActorCritic, self).__init__()\n",
" self.policy1 = nn.Linear(observation_shape, 64)\n",
" self.policy2 = nn.Linear(64, 64)\n",
" self.policy3 = nn.Linear(64, action_shape)\n",
" \n",
" self.value1 = nn.Linear(observation_shape, 64)\n",
" self.value2 = nn.Linear(64, 64)\n",
" self.value3 = nn.Linear(64, 1)\n",
"\n",
" def forward(self, state):\n",
" dists = torch.relu(self.policy1(state))\n",
" dists = torch.relu(self.policy2(dists))\n",
" dists = F.softmax(self.policy3(dists), dim=-1)\n",
" probs = Categorical(dists)\n",
" \n",
" v = torch.relu(self.value1(state))\n",
" v = torch.relu(self.value2(v))\n",
" v = self.value3(v)\n",
"\n",
" return probs, v"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adicionar comentários, mesmo que pequenos, para ficar mais explicativo. O do Buffer possui tantos e as outras classes não possuem nenhum, tadinha delas :(((

Comment on lines 241 to 328
"class PPO:\n",
" def __init__(self, observation_space, action_space, lr=7e-4, gamma=0.99, lam=0.95, vf_coef=0.5, entropy_coef=0.005,clip_param =0.2, epochs =10, memory_len=16):\n",
" self.device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
"\n",
" self.gamma = gamma\n",
" self.lam = lam\n",
" self.vf_coef = vf_coef\n",
" self.entropy_coef = entropy_coef\n",
" self.clip_param = clip_param\n",
" self.epochs = epochs\n",
"\n",
" self.memory_len = memory_len\n",
" self.memory = MemoryBuffer(memory_len, observation_space.shape[0])\n",
"\n",
" self.actorcritic = ActorCritic(observation_space.shape[0], action_space.n).to(self.device)\n",
" self.actorcritic_optimizer = optim.Adam(self.actorcritic.parameters(), lr=lr)\n",
"\n",
" def act(self, state):\n",
" state = torch.FloatTensor(state).to(self.device).unsqueeze(0)\n",
" probs, v = self.actorcritic.forward(state)\n",
" action = probs.sample()\n",
" log_prob = probs.log_prob(action)\n",
" return action.cpu().detach().item(), log_prob.detach().cpu().numpy()\n",
"\n",
" def remember(self, state, action, reward, next_state, done, logp):\n",
" self.memory.update(state, action, reward, next_state, done, logp)\n",
"\n",
" def compute_gae(self, rewards, dones, v, v2):\n",
" T = len(rewards)\n",
"\n",
" returns = torch.zeros_like(rewards)\n",
" gaes = torch.zeros_like(rewards)\n",
" \n",
" future_gae = torch.tensor(0.0, dtype=rewards.dtype)\n",
" next_return = torch.tensor(v2[-1], dtype=rewards.dtype)\n",
"\n",
" not_dones = 1 - dones\n",
" deltas = rewards + not_dones * self.gamma * v2 - v\n",
"\n",
" for t in reversed(range(T)):\n",
" returns[t] = next_return = rewards[t] + self.gamma * not_dones[t] * next_return\n",
" gaes[t] = future_gae = deltas[t] + self.gamma * self.lam * not_dones[t] * future_gae\n",
"\n",
" gaes = (gaes - gaes.mean()) / (gaes.std() + 1e-8) # Normalização\n",
"\n",
" return gaes, returns\n",
"\n",
" def train(self):\n",
" if self.memory.length < self.memory_len:\n",
" return\n",
"\n",
" (states, actions, rewards, next_states, dones, old_logp) = self.memory.get_batch()\n",
"\n",
" states = torch.FloatTensor(states).to(self.device)\n",
" actions = torch.FloatTensor(actions).to(self.device)\n",
" rewards = torch.FloatTensor(rewards).unsqueeze(-1).to(self.device)\n",
" next_states = torch.FloatTensor(next_states).to(self.device)\n",
" dones = torch.FloatTensor(dones).unsqueeze(-1).to(self.device)\n",
" old_logp = torch.FloatTensor(old_logp).to(self.device)\n",
" \n",
" with torch.no_grad():\n",
" _, v = self.actorcritic.forward(states)\n",
" _, v2 = self.actorcritic.forward(next_states)\n",
" \n",
" advantages, returns = self.compute_gae(rewards, dones, v, v2)\n",
" \n",
" for epoch in range(self.epochs):\n",
" \n",
" probs, v = self.actorcritic.forward(states)\n",
"\n",
" new_logp = probs.log_prob(actions)\n",
"\n",
" #Equações principais do algoritmo\n",
" ratio = (new_logp.unsqueeze(-1) - old_logp.unsqueeze(-1)).exp() \n",
" surr1 = ratio * advantages.detach()\n",
" surr2 = torch.clamp(ratio, 1.0 - self.clip_param, 1.0 + self.clip_param) * advantages.detach()\n",
"\n",
" entropy = probs.entropy().mean()\n",
"\n",
" policy_loss = - torch.min(surr1,surr2).mean()\n",
" value_loss = self.vf_coef * F.mse_loss(v, returns.detach())\n",
" entropy_loss = -self.entropy_coef * entropy\n",
"\n",
" self.actorcritic_optimizer.zero_grad()\n",
" (policy_loss + entropy_loss + value_loss).backward()\n",
" self.actorcritic_optimizer.step()\n",
"\n",
" return policy_loss + entropy_loss + value_loss"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Colocar comentários também, principalmente nas linhas mais importantes (relacionadas com a teoria).

"cell_type": "markdown",
"metadata": {},
"source": [
"O agente demonstra consegue solocuinar o ambiente. Porém acaba desaprendendo, para solucionar isso é possível fazer uma otimização nos hiper-parâmetros. É possível também implementar algum tipo de parada antecipada."
Copy link
Member

@FelipeAugustoMachado FelipeAugustoMachado Aug 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"O agente demonstra consegue solocuinar o ambiente. Porém acaba desaprendendo, para solucionar isso é possível fazer uma otimização nos hiper-parâmetros. É possível também implementar algum tipo de parada antecipada."
"O agente aparentemente consegue solucionar o ambiente, no entanto, acaba desaprendendo. Para solucionar isso, é possível fazer uma otimização nos hiper-parâmetros ou implementar algum tipo de parada antecipada."

Co-authored-by: Fernando Matsumoto <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants