59 lines
2.2 KiB
Python
Raw Normal View History

2020-03-17 20:22:37 +08:00
import torch
2020-03-18 21:45:41 +08:00
from torch import nn
2020-03-17 20:22:37 +08:00
import torch.nn.functional as F
from tianshou.data import Batch
from tianshou.policy import PGPolicy
class A2CPolicy(PGPolicy):
"""docstring for A2CPolicy"""
2020-03-19 17:23:46 +08:00
def __init__(self, actor, critic, optim,
dist_fn=torch.distributions.Categorical,
2020-03-20 19:52:29 +08:00
discount_factor=0.99, vf_coef=.5, ent_coef=.01,
2020-03-18 21:45:41 +08:00
max_grad_norm=None):
2020-03-19 17:23:46 +08:00
super().__init__(None, optim, dist_fn, discount_factor)
self.actor = actor
self.critic = critic
2020-03-20 19:52:29 +08:00
self._w_vf = vf_coef
self._w_ent = ent_coef
2020-03-18 21:45:41 +08:00
self._grad_norm = max_grad_norm
2020-03-17 20:22:37 +08:00
def __call__(self, batch, state=None):
2020-03-19 17:23:46 +08:00
logits, h = self.actor(batch.obs, state=state, info=batch.info)
2020-03-17 20:22:37 +08:00
dist = self.dist_fn(logits)
2020-03-18 21:45:41 +08:00
act = dist.sample()
2020-03-19 17:23:46 +08:00
return Batch(logits=logits, act=act, state=h, dist=dist)
2020-03-17 20:22:37 +08:00
2020-03-20 19:52:29 +08:00
def learn(self, batch, batch_size=None, repeat=1):
losses, actor_losses, vf_losses, ent_losses = [], [], [], []
for _ in range(repeat):
for b in batch.split(batch_size):
self.optim.zero_grad()
result = self(b)
dist = result.dist
v = self.critic(b.obs)
a = torch.tensor(b.act, device=dist.logits.device)
r = torch.tensor(b.returns, device=dist.logits.device)
2020-03-26 11:42:34 +08:00
a_loss = -(dist.log_prob(a) * (r - v).detach()).mean()
2020-03-20 19:52:29 +08:00
vf_loss = F.mse_loss(r[:, None], v)
ent_loss = dist.entropy().mean()
2020-03-26 11:42:34 +08:00
loss = a_loss + self._w_vf * vf_loss - self._w_ent * ent_loss
2020-03-20 19:52:29 +08:00
loss.backward()
if self._grad_norm:
nn.utils.clip_grad_norm_(
self.model.parameters(), max_norm=self._grad_norm)
self.optim.step()
2020-03-26 11:42:34 +08:00
actor_losses.append(a_loss.detach().cpu().numpy())
2020-03-20 19:52:29 +08:00
vf_losses.append(vf_loss.detach().cpu().numpy())
ent_losses.append(ent_loss.detach().cpu().numpy())
losses.append(loss.detach().cpu().numpy())
return {
'loss': losses,
'loss/actor': actor_losses,
'loss/vf': vf_losses,
'loss/ent': ent_losses,
}