code: def _critic_learn(self, obs, action, reward, next_obs, terminal):
      with torch.no_grad():
          noise = (torch.randn_like(action) * self.policy_noise).clamp(
              -self.noise_clip, self.noise_clip
          )
  
          next_action = (
              self.target_model.policy(next_obs) + noise
          ).clamp(-1, 1)
  
          target_Q1, target_Q2 = self.target_model.value(
              next_obs, next_action
          )
          target_Q = torch.min(target_Q1, target_Q2)
          target_Q = reward + (1 - terminal) * self.gamma * target_Q
  
      current_Q1, current_Q2 = self.model.value(obs, action)
  
      critic_loss = F.mse_loss(current_Q1, target_Q) + F.mse_loss(
          current_Q2, target_Q
      )
  
      self.critic_optimizer.zero_grad()
      critic_loss.backward()
      self.critic_optimizer.step()
  
file_path: PARL/parl/algorithms/torch/td3.py
imports: import copy
  import numpy
  import torch
  import torch.nn.functional
  from copy import deepcopy
  import parl
  from parl.utils.utils import check_model_method
label_desc: Use image node_id 4 for calling the TD3 obj's underlying member method code with example usage: obj._critic_learn(obs, action, reward, next_obs, terminal) without return types