code: def _actor_learn(self, obs, action):
      act, log_pi = self.sample(obs)
      q1_pi, q2_pi = self.model.value(obs, act)
      min_q_pi = torch.min(q1_pi, q2_pi)
  
      if self.with_automatic_entropy_tuning:
          if self.target_entropy is None:
              self.target_entropy = -np.prod(act.shape[-1]).item()
          alpha_loss = -(
              self.log_alpha * (log_pi + self.target_entropy).detach()
          ).mean()
          self.alpha_optimizer.zero_grad()
          alpha_loss.backward(retain_graph=True)
          self.alpha_optimizer.step()
  
          self.alpha = self.log_alpha.exp()
      else:
          alpha_loss = 0
  
      actor_loss = (self.alpha * log_pi - min_q_pi).mean()
  
      if self._current_steps < self.policy_eval_start:
          """
          For the initial few epochs, try doing behaivoral cloning, if needed
          conventionally, there's not much difference in performance with having 20k
          gradient steps here, or not having it
          """
          policy_log_prob = self._sample_log_prob(obs, action)
          actor_loss = (self.alpha * log_pi - policy_log_prob).mean()
  
      self.actor_optimizer.zero_grad()
      actor_loss.backward(retain_graph=True)
      self.actor_optimizer.step()
      return actor_loss
  
file_path: PARL/parl/algorithms/torch/cql.py
imports: import parl
  import torch
  from torch.distributions import Normal
  import torch.nn.functional
  from parl.utils.utils import check_model_method
  from copy import deepcopy
  import numpy
label_desc: Use image node_id 6 for calling the CQL obj's underlying member method code with example usage: obj._actor_learn(obs, action) and returns: actor_loss