code: def _apply_gradient_descent(
      self,
      memory: ReplayMemory,
      batch_size: int,
      learning_rate: float,
      discount_factor: float,
      entropy_c: float,
  ):
      huber_loss = tf.keras.losses.Huber()
      wsce_loss = tf.keras.losses.SparseCategoricalCrossentropy(
          from_logits=True
      )
      optimizer = tf.keras.optimizers.Adam(lr=learning_rate)
  
      transitions = memory.tail(batch_size)
      batch = A2CTransition(*zip(*transitions))
  
      states = tf.convert_to_tensor(batch.state)
      actions = tf.convert_to_tensor(batch.action)
      rewards = tf.convert_to_tensor(batch.reward, dtype=tf.float32)
      dones = tf.convert_to_tensor(batch.done)
      values = tf.convert_to_tensor(batch.value)
  
      returns = []
      exp_weighted_return = 0
  
      for reward, done in zip(rewards[::-1], dones[::-1]):
          exp_weighted_return = (
              reward
              + discount_factor * exp_weighted_return * (1 - int(done))
          )
          returns += [exp_weighted_return]
  
      returns = returns[::-1]
  
      with tf.GradientTape() as tape:
          state_values = self.critic_network(states)
          critic_loss_value = huber_loss(returns, state_values)
  
      gradients = tape.gradient(
          critic_loss_value, self.critic_network.trainable_variables
      )
      optimizer.apply_gradients(
          zip(gradients, self.critic_network.trainable_variables)
      )
  
      with tf.GradientTape() as tape:
          returns = tf.reshape(returns, [batch_size, 1])
          advantages = returns - values
  
          actions = tf.cast(actions, tf.int32)
          logits = self.actor_network(states)
          policy_loss_value = wsce_loss(
              actions, logits, sample_weight=advantages
          )
  
          probs = tf.nn.softmax(logits)
          entropy_loss_value = tf.keras.losses.categorical_crossentropy(
              probs, probs
          )
          policy_total_loss_value = (
              policy_loss_value - entropy_c * entropy_loss_value
          )
  
      gradients = tape.gradient(
          policy_total_loss_value,
          self.actor_network.trainable_variables,
      )
      optimizer.apply_gradients(
          zip(gradients, self.actor_network.trainable_variables)
      )
  
file_path: tensortrade/tensortrade/agents/a2c_agent.py
imports: from deprecated import deprecated
  import random
  import numpy
  import tensorflow
  from collections import namedtuple
  from tensortrade.agents import Agent, ReplayMemory
  from datetime import datetime
label_desc: Use image node_id 8 for calling the A2CAgent obj's underlying member method code with example usage: obj._apply_gradient_descent(memory, batch_size, learning_rate, discount_factor, entropy_c) without return types