docstr: update the value network and policy network parameters.
          
docstr_tok: ["update","the","value","network","and","policy","network","parameters","."]
code: def learn(
      self,
      share_obs_batch,
      obs_batch,
      actions_batch,
      value_preds_batch,
      return_batch,
      old_action_log_probs_batch,
      adv_targ,
      active_masks_batch=None,
  ):
      """update the value network and policy network parameters."""
      policy = self.model.policy(obs_batch)
      if not self.multi_discrete:
          action_dis = Categorical(logits=policy)
          action_log_probs = (
              action_dis.log_prob(actions_batch.squeeze(-1))
              .view(actions_batch.size(0), -1)
              .sum(-1)
              .unsqueeze(-1)
          )
          if active_masks_batch is not None:
              dist_entropy = (
                  action_dis.entropy() * active_masks_batch.squeeze(-1)
              ).sum() / active_masks_batch.sum()
          else:
              dist_entropy = action_dis.entropy().mean()
      else:
          actions_batch = torch.transpose(actions_batch, 0, 1)
          action_log_probs = []
          dist_entropy = []
  
          for i in range(len(self.model.act_dim)):
              action_dis = Categorical(logits=policy[i])
              action_log_probs.append(
                  action_dis.log_prob(actions_batch[i].squeeze(-1))
                  .view(actions_batch[i].size(0), -1)
                  .sum(-1)
                  .unsqueeze(-1)
              )
              if active_masks_batch is not None:
                  dist_entropy.append(
                      (
                          action_dis.entropy()
                          * active_masks_batch.squeeze(-1)
                      ).sum()
                      / active_masks_batch.sum()
                  )
              else:
                  dist_entropy.append(action_dis.entropy().mean())
          action_log_probs = torch.cat(action_log_probs, -1)
          dist_entropy = sum(dist_entropy) / len(dist_entropy)
  
      values = self.model.value(share_obs_batch)
  
      # actor update
      imp_weights = torch.exp(
          action_log_probs - old_action_log_probs_batch
      )
  
      surr1 = imp_weights * adv_targ
      surr2 = (
          torch.clamp(
              imp_weights, 1.0 - self.clip_param, 1.0 + self.clip_param
          )
          * adv_targ
      )
  
      if active_masks_batch is not None:
          policy_action_loss = (
              -torch.sum(torch.min(surr1, surr2), dim=-1, keepdim=True)
              * active_masks_batch
          ).sum() / active_masks_batch.sum()
      else:
          policy_action_loss = -torch.sum(
              torch.min(surr1, surr2), dim=-1, keepdim=True
          ).mean()
  
      policy_loss = policy_action_loss
      self.actor_optimizer.zero_grad()
      (policy_loss - dist_entropy * self.entropy_coef).backward()
      nn.utils.clip_grad_norm_(
          self.model.actor.parameters(), self.max_grad_norm
      )
      self.actor_optimizer.step()
  
      # critic update
      value_loss = self.cal_value_loss(
          values, value_preds_batch, return_batch, active_masks_batch
      )
      self.critic_optimizer.zero_grad()
      (value_loss * self.value_loss_coef).backward()
      nn.utils.clip_grad_norm_(
          self.model.critic.parameters(), self.max_grad_norm
      )
      self.critic_optimizer.step()
  
      return value_loss, policy_loss, dist_entropy
  
imports: import torch
  import torch.nn
  from torch.distributions import Categorical
  import numpy
  import parl
label_desc: Use image node_id 3 for calling the MAPPO obj's underlying member method code with example usage: obj.learn(share_obs_batch, obs_batch, actions_batch, value_preds_batch, return_batch, old_action_log_probs_batch, adv_targ, active_masks_batch) and returns: value_loss,  policy_loss,  dist_entropy