DDPG와 SAC로 이해하는 연속 제어 강화학습

DDPG와 SAC의 Actor-Critic 구조, 오프폴리시 학습, 탐색 전략과 안정화 방식, Stable-Baselines3 적용 방법을 비교한다.

2026-08-14 · 최초 발행 2024-04-29

연속 제어에서 갈리는 탐색 방식

DDPG(Deep Deterministic Policy Gradient)와 SAC(Soft Actor-Critic)는 정책 기반과 가치 기반 접근을 함께 쓰는 대표적인 연속 제어 알고리즘이다. 둘 다 오프폴리시 Actor-Critic 구조를 채택하지만, 행동을 만들고 탐색을 유지하는 방식은 다르다.

DDPG는 연속 행동 공간을 대상으로 하는 결정론적 정책 그라디언트 알고리즘이다. Actor는 결정론적 정책 μ(s|θ)를 출력하고, Critic은 Q(s, a|ϕ)를 근사한다. 탐색은 행동에 가우시안 또는 OU(Ornstein–Uhlenbeck) 노이즈를 더해 수행하며, 타깃 네트워크와 리플레이 버퍼로 학습 안정성을 확보한다.

SAC는 확률적 정책 π(a|s)에 최대 엔트로피 프레임워크를 결합한다. 보상과 α·엔트로피 항을 함께 최대화하므로 탐색과 수렴 안정성을 동시에 다룬다. 이중 Q-네트워크(Double Q), 온도(temperature) α 자동 조정(autotune)을 사용해 과추정과 하이퍼파라미터 민감도를 완화한다.

두 방법 모두 리플레이 버퍼, 타깃 네트워크, Polyak 평균(τ) 기반 소프트 업데이트를 공유한다. 배치 학습과 상태·보상 정규화도 학습 안정화에 쓰인다.

정책과 가치함수가 행동을 만드는 방식

DDPG의 Actor는 a=μ(s)처럼 결정론적으로 행동을 출력하고, Critic은 단일 네트워크로 Q(s, a)를 근사한다. 외부에서 주입하는 OU 또는 Gaussian 노이즈가 탐색의 역할을 맡기 때문에, 노이즈 스케줄링과 액션 클리핑을 함께 관리해야 한다.

SAC의 Actor는 가우시안 정책을 만들고 Tanh 변환을 거쳐 연속 행동을 샘플링한다. Critic은 Q1과 Q2를 별도 네트워크로 계산한 뒤 최소값을 사용한다. 엔트로피 정규화는 탐색을 정책 내부에 포함시키며, α 자동 튜닝은 탐색과 활용의 균형을 데이터 기반으로 조정한다.

리플레이 버퍼에서 미니배치를 꺼내고 타깃 네트워크로 부트스트랩 타깃을 계산하는 흐름은 공통이다. 분산 rollout과 병렬 환경은 샘플 효율을 높이고, 축적한 경험을 재사용해 데이터 비용을 줄인다.

DDPG는 하이퍼파라미터에 민감하고 환경 잡음에 취약할 수 있다. 다만 정규화와 노이즈 설정이 맞으면 높은 성능을 기대할 수 있다. SAC는 상대적으로 로버스트하고 튜닝 부담이 낮지만, 이중 Q와 확률적 정책 때문에 계산량이 늘고 약간의 추가 지연이 생긴다.

리플레이 버퍼에서 정책 업데이트까지

공통 학습 루프는 상태 s_t, 보상 r_t, 종료 done, 환경 전이 (s_t, a_t, r_t, s_{t+1})를 받아 리플레이 버퍼에 적재하는 것으로 시작한다. 이후 미니배치 샘플링, 타깃 계산, Critic과 Actor 갱신, 타깃 네트워크 소프트 업데이트를 차례로 수행한다. 결과물은 갱신된 Actor·Critic과 안정화된 타깃 네트워크다.

DDPG의 갱신식

  1. 수집: a_t = μ(s_t|θ) + ε, ε∼N(0, σ^2) 또는 OU 노이즈.
  2. 타깃: y = r + γ(1-done) Q'(s', μ'(s')).
  3. Critic 손실: L = MSE(Q(s, a), y).
  4. Actor 업데이트: ∇_θ J ≈ 1/N Σ ∇a Q(s, a)|{a=μ(s)} ∇_θ μ(s).
  5. 타깃 소프트 업데이트: θ'←τθ+(1−τ)θ', ϕ' 동일.

액션 범위 클리핑, 리워드·관측 정규화가 필요하다. 그라디언트 폭주가 발생하면 clipping(예: 1.0)을 적용하고, NaN이 탐지되면 학습을 중단한 뒤 버퍼와 정규화 파이프라인을 점검한다.

SAC의 갱신식

  1. 수집: a_t ∼ π(·|s_t) via reparameterization (a = tanh(μ + σ⊙ε)).
  2. 타깃: V_tgt = min(Q1', Q2')(s', a') − α log π(a'|s'); y = r + γ(1-done) V_tgt.
  3. Critic 손실: L_Q = MSE(Q1, y) + MSE(Q2, y).
  4. Actor 손실: L_π = E[α log π(a|s) − min(Q1, Q2)(s, a)].
  5. α 자동 튜닝(옵션): L_α = E[−α (log π(a|s) + H_target)].

Tanh-Gaussian 변환에서는 로그 확률의 정밀도에 주의해야 한다. α 하한·상한 클램프와 엔트로피 타깃 H_target의 스케일 검증도 필요하다.

수집과 업데이트가 연결되는 경로

Environmentaction a_tAgentActor (DDPG: μ(s), SAC:π(a|s))Action Noise / StochasticSamplinga_t(Replay Buffer)Sample Mini-batchTarget CalcDDPG: Q'(s', μ'(s'))SAC: min(Q1',Q2')-α log πCritic UpdateActor UpdateDDPG: DPGSAC: ReparameterizationTarget Soft Update (τ)State s_tReward r_t, s_{t+1}, done

운영 관점에서 보는 DDPG와 SAC

항목 DDPG SAC
성능(수렴 보장/성공률) 환경·튜닝에 민감하고 고성능 가능하나 변동성이 큼 전반적으로 높은 안정성·성공률
확장성(분산/병렬 수집) 단순 구조로 확장하기 쉬움 우수하나 이중 Q·확률적 정책으로 계산량 증가
일관성(재현성/변동성) 재현성이 낮고 시드 의존이 높음 재현성이 상대적으로 우수
안정성(훈련 진동/발산) 발산 위험이 있으며 노이즈·정규화가 중요 α 튜닝으로 진동을 완화하며 안정적
운영 편의(튜닝/배포) 노이즈·LR·τ 등 여러 파라미터에 민감 기본 설정으로도 양호하고 튜닝 부담이 낮음

로보틱스의 매니퓰레이터 토크·속도 제어와 경로 추종 최적화에서는 MuJoCo·Isaac Gym 같은 시뮬레이터에서 SAC를 선호하고, 실세계 전이에는 도메인 랜덤화를 적용한다.

자율주행 저수준 제어에서는 조향각과 가감속을 연속적으로 다룬다. 안전 제약은 액션 세이프가드(클리핑·혼합 정책)와 오프라인 검증 게이트로 보강한다.

HVAC와 빌딩 에너지 최적화는 연속 밸브·팬 속도를 제어하면서 비용과 쾌적성의 균형을 맞추는 문제다. 샘플 비용이 높아 오프폴리시·모델 예측을 혼합하며, SAC 적용 비중이 증가하고 있다.

추천과 광고 입찰의 연속 입찰가 결정에서는 스무딩된 가격 결정과 오프라인 로그 재사용이 필요하다. 안정성 요구 때문에 SAC를 채택하고 시뮬레이션 모델과 병행 학습한다.

오프폴리시 재사용은 환경에 따라 온라인 수집 대비 샘플을 3070% 절감할 수 있다. SAC는 연속 제어 벤치마크에서 동일 설정 기준 성공률이 +1030pp 상승하는 경향이 있으며, 최신 정보 확인이 필요하다. 분산 수집과 배치 업데이트는 GPU·CPU 활용 효율을 높이고 학습 시간을 20~40% 단축한 사례가 있다. 엔트로피 정규화는 외란·노이즈 환경에서의 성능 저하와 성능 분산을 완화한다.

Stable-Baselines3로 실행하는 예시

전제조건은 Python 3.10+, stable-baselines3>=2.3.0, gymnasium>=0.29, torch>=2.2다. CPU와 GPU를 모두 지원하며, 아래 예시는 MuJoCo가 필요 없는 환경을 사용한다.

pip install "stable-baselines3[extra]>=2.3.0" gymnasium[classic-control]>=0.29 torch>=2.2

Pendulum-v1에서 DDPG와 SAC를 학습하는 코드다.

import gymnasium as gym
from stable_baselines3 import DDPG, SAC
from stable_baselines3.common.monitor import Monitor
from stable_baselines3.common.vec_env import DummyVecEnv
from stable_baselines3.common.evaluation import evaluate_policy
import torch

SEED = 42

def make_env():
    env = gym.make("Pendulum-v1")  # continuous action [-2, 2]
    env = Monitor(env)
    return env

env = DummyVecEnv([make_env])

# 공통 하이퍼파라미터
policy_kwargs = dict(net_arch=[256, 256], activation_fn=torch.nn.ReLU)

ddpg = DDPG(
    "MlpPolicy", env,
    learning_rate=1e-3, buffer_size=100000, batch_size=256,
    tau=0.005, gamma=0.99, train_freq=1, gradient_steps=1,
    action_noise=None,                 # 필요 시 NormalActionNoise 적용
    policy_kwargs=policy_kwargs, verbose=1, seed=SEED
)
ddpg.learn(total_timesteps=100_000)
ddpg.save("ddpg_pendulum")

sac = SAC(
    "MlpPolicy", env,
    learning_rate=3e-4, buffer_size=100000, batch_size=256,
    tau=0.005, gamma=0.99, train_freq=1, gradient_steps=1,
    ent_coef="auto",                   # α 자동 튜닝
    policy_kwargs=policy_kwargs, verbose=1, seed=SEED
)
sac.learn(total_timesteps=100_000)
sac.save("sac_pendulum")

# 평가
for algo, model in [("DDPG", ddpg), ("SAC", sac)]:
    mean_r, std_r = evaluate_policy(model, env, n_eval_episodes=10, render=False)
    print(f"{algo} meanR: {mean_r:.2f} ± {std_r:.2f}")

DDPG 탐색에는 from stable_baselines3.common.noise import NormalActionNoise를 사용하고 sigma 스케줄링을 적용할 수 있다. 관측·보상 스케일 차이가 크면 RunningMeanStd 기반 정규화(VecNormalize)를 적용한다. 재현성을 위해 시드를 고정하고 evaluate_policy로 deterministic 평가를 수행한다.

라이브러리 API와 버전은 달라질 수 있으므로 최신 정보 확인이 필요하며, SB3 공식 문서 참조가 권장된다.

학습 파이프라인과 배포를 함께 관리하기

오프폴리시 수집자는 정책 SHA를 버전 태깅하고 리플레이 버퍼 스냅샷을 관리해야 한다. 환경 버전이 섞여 발생하는 버퍼 오염을 막기 위한 조치다.

NaN이나 발산을 감지하면 early stop, gradient clipping, reward clipping, target update 주기 조정을 적용한다. 수집과 학습을 분리하는 환경에서는 Prod: Ray/RLlib 또는 커스텀 gRPC와 다중 워커로 샘플을 수집하고, learner는 우선순위 버퍼(PER)를 고려할 수 있다.

배포 단계에서는 안전 제약과 액션 필터를 세이프가드로 두고, 오프라인 시뮬레이션 평가 뒤 A/B 테스트와 점진적 롤아웃을 수행한다. 실패하면 즉시 롤백할 수 있어야 한다.

빠른 실용성과 안정성이 우선이면 SAC가 적합하다. 환경이 매끄럽고 노이즈가 낮으며 최고 성능을 목표로 한다면 DDPG도 고려할 수 있지만, 그만큼 튜닝 비용은 증가한다.

강화학습DDPGSACActor-Critic연속 제어