머신러닝 딥러닝
[강화학습-7] 함수 근사 (Function Approximation)
Qcoding
2025. 5. 28. 17:22
반응형
7. 함수 근사 (Function Approximation)
무한/거대한 상태 공간에서는 테이블($V(s)$ 또는 $Q(s,a)$)에 값을 저장할 수 없습니다.
대신 가치 함수를 어떤 파라미터 벡터로 근사해야 합니다.
7-1. 왜 함수 근사가 필요한가?
- 차원의 저주 – 상태 수가 지수적으로 폭발.
- 일부 상태는 평생 한 번도 방문하지 않을 수 있음 → 테이블 학습 불가.
- 근사는 일반화와 압축을 동시에 제공.
7-2. 선형 vs 비선형 근사
종류 | 모델 | 장점 | 단점 |
---|---|---|---|
선형 | $$\hat Q(s,a;\mathbf{w})=\mathbf{w}_a^\top \phi(s)$$ | 빠른 학습, 이론적 수렴 보장, 구현 단순 | 표현력 제한 (복잡 패턴 어려움) |
비선형 (NN, RBF, 결정트리 등) |
$$\hat Q=f_{\theta}(s,a)$$ | 표현력 높음, 자동 특성 추출 | 불안정·하이퍼파라미터 민감, 수렴 보장 약함 |
7-3. 특성(Feature) 설계
선형 근사의 성능은 특성 벡터 $\phi(s)$ 품질에 크게 의존합니다.
방법 | 아이디어 | 장 · 단점 |
---|---|---|
원-핫 (Tabular) | $\phi_i(s)=\mathbb{1}\{s=i\}$ | 정확하지만 규모 ↑ |
타일 코딩 (Tile) | 다수 겹친 격자 → 지역 코드 | 빠른 계산, 저차원에 강함 |
다항 / Fourier basis | $\phi(s)=[1,x,x^2,\dots]$ 또는 $\sin(\pi k x)$ | 연속치에 매끄럽게 작동 |
RBF (가우시안) | $\phi_j(s)=\exp\!(-\|s-c_j\|^2/2\sigma^2)$ | 국소 일반화, 고차원 가능 |
뉴럴넷 | 층이 곧 특성 변환 | 특성 공학 필요 ↓ / 학습 ↑ |
Tip : Tile Coding + Linear 는 TD 학습에서 여전히 강력하며, 마이크로컨트롤러 등 저전력 장치에서 자주 쓰입니다.
7-4. 간단한 선형 Q-러닝 실습 (MountainCar-v0)
아래 코드는 MountainCar-v0
(연속 위치·속도 2D) 환경을 타일 코딩 + Q-Learning 으로 해결합니다.
"""
pip install gymnasium numpy
"""
import gymnasium as gym
import numpy as np
from collections import defaultdict
env = gym.make("MountainCar-v0")
n_actions = env.action_space.n
# --- Tile Coding ---------------------------------------------------------
n_tilings = 8
bins = (8, 8) # 각 축 격자 수
pos_range = [-1.2, 0.6]
vel_range = [-0.07, 0.07]
tile_offsets = np.linspace(0, 1, n_tilings, endpoint=False)
def create_tiles(x, x_range, bins, offsets):
""" x: 실수, x_range: [low, high] """
scaled = (x - x_range[0]) / (x_range[1] - x_range[0])
tiles = []
for off in offsets:
shifted = scaled * bins + off # 0~bins 오프셋
idx = int(np.floor(shifted)) % bins
tiles.append(idx)
return tiles # 길이 n_tilings
def featurize(obs):
pos, vel = obs
pos_tiles = create_tiles(pos, pos_range, bins[0], tile_offsets)
vel_tiles = create_tiles(vel, vel_range, bins[1], tile_offsets)
# one-hot 인덱스 : (tiling, dim, idx)
features = []
for t,(p,v) in enumerate(zip(pos_tiles, vel_tiles)):
i = t*bins[0]*bins[1] + p*bins[1] + v
features.append(i)
return features # 총 n_tilings·bins[0]·bins[1]
n_feats = n_tilings * bins[0] * bins[1]
# 각 행동마다 가중치 벡터
W = np.zeros((n_actions, n_feats))
def q_hat(state):
feats = featurize(state)
return W[:, feats].sum(axis=1), feats
# --- Q-Learning ----------------------------------------------------------
alpha = 0.1 / n_tilings
gamma = 1.0
epsilon= 1.0
eps_min, eps_decay = 0.01, 0.9995
episodes = 20_000
def epsilon_greedy(q_values, eps):
if np.random.rand() < eps:
return env.action_space.sample()
return np.argmax(q_values)
for ep in range(episodes):
state, _ = env.reset()
done = False
while not done:
q_values, feats = q_hat(state)
action = epsilon_greedy(q_values, epsilon)
next_state, reward, terminated, truncated, _ = env.step(action)
done = terminated or truncated
q_next, _ = q_hat(next_state)
target = reward + gamma * np.max(q_next) * (not done)
# 선형 근사 가중치 업데이트
td_error = target - q_values[action]
W[action, feats] += alpha * td_error # 각 특성에 동일한 업데이트
state = next_state
epsilon = max(eps_min, epsilon * eps_decay)
if (ep+1) % 2000 == 0:
print(f"Episode {ep+1:5d} | ε = {epsilon:.3f}")
- 설명 : 타일 수 = 8×8, 8겹 ⇒ 특성 512개.
한 스텝당 가중치 512개 업데이트만으로 작동하므로 매우 가볍습니다. - 성공 기준 : MountainCar-v0 는 100 에피소드 평균 Reward ≥ −110 이면 솔브.
7-5. 요약 & 다음 편 예고
- 함수 근사는 거대/연속 상태 공간 문제를 해결하기 위한 필수 도구.
- 선형 모델은 빠르고 안정적, 비선형 모델은 높은 표현력.
- 특성 설계는 선형 근사의 성능을 좌우한다 (타일 코딩, RBF, Fourier…).
다음 글 : 뉴럴 네트워크를 가치 함수에 직접 사용한 DQN(Deep Q-Network) 구조와
경험 재플레이, 타깃 네트워크 등 안정화 기법을 자세히 탐구합니다.
참고 자료
- Sutton & Barto, Reinforcement Learning: An Introduction, Ch. 9
- Albus (1975), CMAC: Cerebellar Model Articulation Controller
- Richard Sutton, CMAC & Tile Coding 노트
반응형