Skip to content

9.2 TD3 and SAC ​

9.1 explained Deterministic Policy Gradients (DPG) and DDPG, which transfer DQN's off-policy approach to continuous actions. DDPG, however, has three widely criticized weaknesses: Q-value overestimation, hyperparameter sensitivity, and unstable training. This section presents two complementary remedies: TD3 stabilizes DDPG with engineering techniques, while SAC reformulates the objective through maximum-entropy RL.

Stability Improvements for DDPG ​

Twin Delayed Deep Deterministic Policy Gradient (Fujimoto et al., 2018) addresses DDPG's three weaknesses with three modifications.

1. Twin Q-Networks ​

Following the idea behind Double DQN, TD3 trains two independent critics, , and uses the smaller value as the target:

This structure suppresses Q-value overestimation because two networks are much less likely to overestimate the same value simultaneously than one network is.

python
class TD3Critic:
    def __init__(self, state_dim, action_dim):
        self.Q1 = QNetwork(state_dim, action_dim)
        self.Q2 = QNetwork(state_dim, action_dim)  # Initialized independently

    def forward(self, s, a):
        return self.Q1(s, a), self.Q2(s, a)

    def target_min(self, s, a):
        return torch.min(self.Q1(s, a), self.Q2(s, a))

2. Delayed Policy Updates ​

The critic has a more difficult learning problem than the actor: the critic must fit the two-argument function , while the actor needs to learn only the single-argument function . TD3 updates the actor only once every steps, with , giving the critic more updates before it supplies a signal to the actor:

python
for step in range(total_steps):
    # Update the critic at every step
    update_critic()

    # Update the actor and target networks only every d=2 steps
    if step_count % policy_delay == 0:
        update_actor()
        soft_update_targets()

The intuition is that while the critic is still inaccurate, its gradients are noisy. Delayed updates keep the actor from following these inaccurate gradients.

3. Target Policy Smoothing ​

DDPG's target action is deterministic, but the function approximator's values may vary sharply around . TD3 adds a small amount of smoothing noise to the target action:

This performs a local average in the action space, making the Q-function smoother along the action dimension and reducing the critic's sensitivity to small perturbations. Common settings are .

The Combined Effect of the Three Modifications ​

TD3 makes DDPG substantially more stable on MuJoCo and outperformed contemporary early versions of SAC. TD3 remains a strong baseline for continuous control.

python
class TD3:
    def update(self, batch_size=256):
        states, actions, rewards, next_states, dones = \
            self.replay_buffer.sample(batch_size)

        # === Critic update (twin Q-networks) ===
        with torch.no_grad():
            next_actions = self.actor_target(next_states)
            # Target policy smoothing
            noise = (torch.randn_like(next_actions) * 0.2).clamp(-0.5, 0.5)
            next_actions = (next_actions + noise).clamp(-self.action_max, self.action_max)
            # Take the minimum of the twin Q-values
            target_q1, target_q2 = self.critic_target(next_states, next_actions)
            target_q = torch.min(target_q1, target_q2)
            target_q = rewards + self.gamma * (1 - dones) * target_q

        current_q1, current_q2 = self.critic(states, actions)
        critic_loss = F.mse_loss(current_q1, target_q) + F.mse_loss(current_q2, target_q)
        self.critic_optim.zero_grad(); critic_loss.backward()
        self.critic_optim.step()

        # === Actor update (delayed) ===
        if self.step_count % self.policy_delay == 0:
            actor_loss = -self.critic.Q1(states, self.actor(states)).mean()
            self.actor_optim.zero_grad(); actor_loss.backward()
            self.actor_optim.step()

            soft_update(self.actor_target, self.actor, self.tau)
            soft_update(self.critic_target, self.critic, self.tau)

Maximum-Entropy RL ​

Soft Actor-Critic (Haarnoja et al., 2018) takes a different approach: the policy maximizes return plus entropy, rather than expected return alone.

The Maximum-Entropy RL Objective ​

Here, is the policy entropy, and the temperature coefficient controls its weight.

Why add entropy?

  • Encouraging exploration: a high-entropy policy does not converge prematurely to a single action
  • Robustness: a multimodal policy that assigns probability to several good actions is more robust to environmental perturbations
  • Training stability: entropy regularization makes the Q-function smoother and reduces overestimation

The Soft Bellman Equation ​

The modified Bellman backup is

The key change is that is no longer . It is a soft maximum, expressed in log-sum-exp form and evaluated as an expectation for continuous actions:

Reparameterizing the Stochastic Policy ​

SAC's policy is Gaussian. It uses the reparameterization trick to compute actor gradients:

This makes the actor loss differentiable:

Automatic Temperature Tuning ​

The most difficult hyperparameter is . An engineering innovation in SAC is automatic temperature tuning:

Here, is the target entropy, usually set to . This allows to adjust automatically during training: when entropy is too high, decreases; when entropy is too low, increases.

python
# Optimize alpha for automatic temperature tuning
def update_alpha(self, states, actions):
    # Learn alpha so that policy entropy approaches target_entropy
    log_pi = -self.actor.log_prob(states, actions)  # Current policy's negative log-likelihood
    alpha_loss = -(self.log_alpha * (log_pi + self.target_entropy).detach()).mean()
    self.alpha_optim.zero_grad()
    alpha_loss.backward()
    self.alpha_optim.step()
    self.alpha = self.log_alpha.exp()

Advantages of SAC ​

SAC has remained a leading method on MuJoCo because it provides

  1. High off-policy sample efficiency, inherited from DDPG
  2. Automatic exploration through maximum entropy, without a manually tuned noise scale
  3. Stable training through twin Q-networks and soft targets
  4. Performance beyond the human level, reaching scores above 15,000 on HalfCheetah

Comparing the Three Algorithms ​

DimensionDDPGTD3SAC
Policy typeDeterministicDeterministicStochastic (Gaussian)
Number of Q-networks12 (twin)2 (twin)
Exploration methodAdded noiseAdded noiseEntropy reward (built in)
StabilityPoorModerateStrong
Hyperparameter sensitivityHighModerateLow
Recommended first choice❌⚠️✅

Practical recommendation: use SAC as the first choice for continuous control. If a deterministic policy is required, for example to eliminate randomness at deployment time, use TD3.

Training Curves on HalfCheetah ​

The following diagram compares training for one million steps in the MuJoCo HalfCheetah-v3 environment:

return
12000 │                    ╭─────── SAC (stable convergence)
10000 │                  ╭─╯
 8000 │                ╭─╯  ╭─────── TD3 (stable but slightly slower)
 6000 │              ╭─╯   ╱
 4000 │            ╭─╯    ╱
 2000 │          ╭─╯     ╱  ╭───── DDPG (occasional recovery after divergence)
     0 │─────────╯──────╱──╯
       └───────────────────────────────
        0    200K  400K  600K  800K  1M steps

Three observations follow:

  • SAC converges fastest and most steadily because maximum-entropy exploration accelerates early learning
  • TD3 is slightly slower than SAC but reaches similar final performance because its stability modifications make DDPG practical
  • DDPG diverges much of the time and trains successfully only under some random seeds

Section Summary ​

DDPG → TD3 → SAC forms a three-stage development in continuous control:

  1. DDPG extends DQN's ideas to continuous actions, but is unstable
  2. TD3 stabilizes DDPG with twin Q-networks, delayed updates, and target smoothing
  3. SAC reformulates the objective through maximum-entropy RL, incorporating exploration and automatic temperature tuning

In practice, SAC is the first choice, TD3 is the alternative when a deterministic policy is required, and DDPG is no longer recommended.

The next section, 9.3 Model-Based RL, turns to another direction: when sampling the real environment is expensive, learning an environment model can generate "synthetic" data and improve sample efficiency by a factor of 10–100.

Hands-on Modern Reinforcement Learning