[강화학습] TD Learning (시간차 학습) 개념, 랜덤 벽 GridWorld 실습

2026. 3. 1. 18:42·개념 정리 step2/강화 학습

강화학습을 공부하다 보면 반드시 마주치는 중요한 개념이 있습니다. 바로 TD Learning(Temporal Difference Learning, 시간차 학습)입니다. Q-learning이나 SARSA 같은 유명한 알고리즘들이 모두 이 TD Learning을 뿌리로 두고 있죠.

오늘은 TD Learning이 대체 무엇인지, 왜 필요한지, 그리고 파이썬 코드로 어떻게 구현하는지 알아보겠습니다.


1. TD Learning 이란?

TD Learning(시간차 학습)은 환경의 상태 전이 확률을 완벽히 알지 못하는 상황에서 사용하는 가치 평가 방법입니다.

가장 큰 특징은 에피소드가 끝날 때까지 기다리지 않는다는 것입니다. 현재 상태에서 한 스텝 나아간 뒤, 바로 다음 상태의 가치와 얻은 보상을 이용해 현재 상태의 가치를 '점진적으로' 업데이트합니다.

수식으로 표현하면 다음과 같습니다.

$$V(S_{t}) \leftarrow V(S_{t}) + \alpha [R_{t+1} + \gamma V(S_{t+1}) - V(S_{t})]$$
  • $V(S_{t})$: 현재 상태의 가치
  • $\alpha$: 학습률 (Learning Rate)
  • $R_{t+1}$: 행동 후 받은 즉각적인 보상
  • $\gamma$: 할인율 (Discount Factor)
  • $V(S_{t+1})$: 다음 상태의 예상 가치
  • $[R_{t+1} + \gamma V(S_{t+1}) - V(S_{t})]$: 이 부분을 TD Error(시간차 오차)라고 부릅니다.

2. TD Learning이 필요한 이유와 핵심 아이디어

강화학습의 목표는 "어떤 상태(State)가 좋은 상태인지" 정확히 파악하는 것입니다. 미로 찾기를 예로 들면, 어떤 칸이 출구에 더 가까운 명당인지 알아내야 하죠.

하지만 우리는 미래를 정확히 모릅니다. 지금 밟은 이 칸이 정말 좋은 칸인지, 앞으로 상황이 어떻게 흘러갈지, 결국 목적지에 도착해 성공할지 실패할지 당장 알 길이 없습니다.

그래서 TD Learning은 이렇게 접근합니다.

"지금 당장 최종 정답(Return)은 모르니까, 일단 한 발짝 움직여보고 '다음 상태'를 참고해서 '현재 상태'의 가치를 조금씩 수정하자!"

핵심 아이디어 예시

현재 상태를 A, 한 번 움직여서 도달한 다음 상태를 B라고 해봅시다.

  1. 나는 현재 상태 A의 가치를 3이라고 예측하고 있었습니다.
  2. 실제로 한 번 움직여보니, 즉각적인 보상 $R = 1$을 받았고 다음 상태 B에 도착했습니다.
  3. 상태 B의 가치는 5로 평가되고 있습니다.

이때 TD Learning의 사고방식은 이렇습니다.

"아, A는 내가 생각했던 것(3)보다 훨씬 좋은 상태였네! 움직이자마자 보상(1)도 받고, 도착한 다음 상태도 꽤 좋으니까(5)." 결과적으로 TD Error를 계산하여 A의 가치를 상향 조정하게 됩니다.


3. Monte Carlo vs TD Learning

에피소드 기반 학습의 양대 산맥인 Monte Carlo(MC)와 비교하면 TD Learning의 장점이 더욱 명확해집니다.

특징 Monte Carlo (MC) TD Learning (TD)
업데이트 시점 에피소드가 끝난 후 최종 결과를 보고 학습 매 스텝마다 한 발짝 움직이고 즉시 학습
필요 조건 반드시 끝(Terminal state)이 있는 에피소드여야 함 끝나지 않는 연속적인(Continuous) 환경도 가능
분산(Variance) 최종 결과를 사용하므로 분산이 높음 (결과가 매번 다를 수 있음) 1스텝만 보므로 분산이 낮음
편향(Bias) 실제 얻은 Return을 쓰므로 편향이 없음 (Unbiased) 예측값으로 예측값을 업데이트(Bootstrapping)하므로 편향이 있음
학습 속도 에피소드가 길면 학습이 매우 느림 스텝 단위로 학습하므로 속도가 빠르고 효율적

 

요약: MC는 "끝까지 가보고 나서 한 번에 평가하자"는 주의고, TD는 "가면서 틈틈이 평가를 수정하자"는 주의입니다.


4. 파이썬 코드로 보는 TD Learning 구현

앞서 설명한 개념을 3가지 환경에서 코드로 확인해 보겠습니다.

4-1 기본 상태 전이 예제 (상태 A, B, C)

에이전트가 랜덤하게 왼쪽/오른쪽으로 이동하며 Home이나 Bar에 도착하면 끝나는 간단한 환경입니다.

import random

# 상태 가치 초기화
V = {"Home": 1.0, "A": 0.0, "B": 0.0, "C": 0.0, "Bar": -1.0}
alpha = 0.1
gamma = 1.0
episodes = 500000
states = ['A', 'B', 'C']

for ep in range(episodes):
    state = random.choice(states)
    while state not in ['Home', 'Bar']:
        move = random.choice(['left', 'right'])
        
        # 상태 전이 로직
        if state == 'A': next_state = 'Home' if move == 'left' else 'B'
        elif state == 'B': next_state = 'A' if move == 'left' else 'C'
        elif state == 'C': next_state = 'B' if move == 'left' else 'Bar'
        
        reward = 0
        # TD 업데이트 핵심 수식: V(s) = V(s) + alpha * (reward + gamma * V(s') - V(s))
        V[state] = V[state] + alpha * (reward + gamma * V[next_state] - V[state])
        state = next_state

for state, value in V.items():
    print(f'{state}: {value:.4f}')

4-2 술 취한 사람 문제 (Drunkard's Walk)

5x5 그리드의 정중앙(2,2)에서 시작하여, 안전한 집(0,0)에 가면 보상 +1, 위험한 곳(0,4)에 가면 보상 -1을 받는 환경입니다.

import random

class DrunkardGridWorld():
    # 환경 설정 (생략: 위에서 제공해주신 GridWorld 클래스 구조와 동일)
    # ... (x=2, y=2 시작, 0,0 도달시 +1, 0,4 도달시 -1, 스텝 보상 0) ...
    pass 

# TD Learning 진행부
def main():
    env = DrunkardGridWorld()
    # 5x5 상태가치 테이블 0으로 초기화
    data = [[0]*5 for _ in range(5)]
    gamma = 1.0
    alpha = 0.01
    # 목표 지점 가치 고정
    data[0][0] = 1.0
    data[0][4] = -1.0

    for k in range(50000):
        env.reset() # (2,2)로 리셋
        done = False
        while not done:
            x, y = env.get_state()
            action = random.randint(0, 3) # 랜덤 정책
            (x_prime, y_prime), reward, done = env.step(action)
            
            # 다음 상태가 도착 지점인지 아닌지에 따라 타겟 계산
            if done:
                td_target = reward
            else:
                td_target = reward + gamma * data[x_prime][y_prime]
                
            # TD 업데이트
            data[x][y] = data[x][y] + alpha * (td_target - data[x][y])
            
        # 목표 지점 가치 유지 보정
        data[0][0] = 1.0
        data[0][4] = -1.0

    for row in data:
        print([round(v, 4) for v in row])

 

결과를 보면 (0,0)에 가까운 상태일수록 가치가 1에 가깝고, (0,4)에 가까울수록 -1에 가까워지는 그라데이션을 확인할 수 있습니다.


5. [실습] 랜덤 벽(Random Wall) GridWorld 환경 구현

이번에는 난이도를 높여, 매 에피소드마다 벽의 위치가 무작위로 변하는 4x4 GridWorld를 만들고 TD Learning으로 상태 가치를 평가해 보겠습니다.

환경 조건

  • 크기: 4x4, 시작(0,0), 목표(3,3)
  • 행동: 상, 하, 좌, 우 (랜덤 정책)
  • 랜덤 벽: 매 에피소드 시작 시 무작위 위치에 2~3개의 벽 생성.
    • 단, 시작(0,0), 목표(3,3)에는 생성 불가. 중복 생성 불가.
  • 이동 규칙: 빈 칸 이동 가능. 격자를 벗어나거나 벽으로 이동 시도 시 '제자리 유지'.
  • 보상: 모든 이동 시도에 대해 -1. 목표 도달 시 에피소드 종료.
import random

class RandomWallGridWorld():
    def __init__(self):
        self.x = 0
        self.y = 0
        self.walls = []

    def reset(self):
        self.x = 0
        self.y = 0
        self.walls = []
        
        # 벽을 생성할 수 있는 후보 좌표들 (시작과 끝 제외)
        possible_walls = [(i, j) for i in range(4) for j in range(4) 
                          if (i, j) not in [(0, 0), (3, 3)]]
        
        # 벽 개수를 2개 또는 3개로 무작위 선택 후 좌표 샘플링
        num_walls = random.choice([2, 3])
        self.walls = random.sample(possible_walls, num_walls)
        
        return (self.x, self.y)

    def step(self, action):
        # 0:왼쪽, 1:위쪽, 2:오른쪽, 3:아래쪽
        next_x, next_y = self.x, self.y
        
        if action == 0:   next_y -= 1
        elif action == 1: next_x -= 1
        elif action == 2: next_y += 1
        elif action == 3: next_x += 1

        # 격자를 벗어나거나, 이동하려는 곳이 벽(walls)인 경우 제자리 유지
        if next_x < 0 or next_x > 3 or next_y < 0 or next_y > 3 or (next_x, next_y) in self.walls:
            pass # 위치 업데이트 하지 않음 (제자리)
        else:
            self.x, self.y = next_x, next_y

        reward = -1 # 모든 스텝에 대해 보상은 -1
        done = self.is_done()
        return (self.x, self.y), reward, done

    def is_done(self):
        return self.x == 3 and self.y == 3

    def get_state(self):
        return (self.x, self.y)

def main():
    env = RandomWallGridWorld()
    data = [[0.0]*4 for _ in range(4)]
    gamma = 1.0
    alpha = 0.01

    for k in range(50000):
        env.reset()
        done = False
        while not done:
            x, y = env.get_state()
            action = random.randint(0, 3) # 완전 랜덤 정책
            
            (x_prime, y_prime), reward, done = env.step(action)
            
            # TD Learning 가치 업데이트
            if done:
                data[x][y] = data[x][y] + alpha * (reward - data[x][y])
            else:
                data[x][y] = data[x][y] + alpha * (reward + gamma * data[x_prime][y_prime] - data[x][y])

    print("=== 랜덤 벽 GridWorld 상태 가치 (V(s)) ===")
    for row in data:
        print([round(v, 2) for v in row])

if __name__ == '__main__':
    main()

6. 결과 분석: 일반 그리드 vs 랜덤 벽 그리드의 상태 가치 차이

TD Learning을 통해 도출된 data(상태 가치 $V(s)$)를 비교해보면, 일반 환경과 랜덤 벽 환경 사이에 뚜렷한 차이가 나타납니다.

우선 현재 에이전트는 아무런 지능 없이 네 방향으로 무작위로 움직이는 랜덤 정책을 따르고 있다는 점을 기억해야 합니다. 여기서 상태 가치란 "이 칸에서 시작해서 목적지까지 갈 때 평균적으로 얼마나 많은 -1 보상을 받을 것인가(몇 걸음이나 걸릴 것인가)"를 의미합니다.

 

1. 전체적인 가치 하락 (더 큰 음수값)

  • 일반 그리드: 방해물이 없으므로 랜덤하게 움직여도 비교적 수월하게 목적지(3,3)로 흘러갑니다.
  • 랜덤 벽 그리드: 매번 위치가 바뀌는 2~3개의 벽 때문에 길이 막힙니다. 벽을 향해 걷다가 제자리에 멈춰 서서 쓸데없이 턴을 낭비(보상 -1 누적)하는 경우가 빈번하게 발생합니다. 목적지에 도달하기까지의 평균 스텝 수가 훨씬 길어지므로, 모든 상태의 가치 $V(s)$가 일반 그리드에 비해 훨씬 낮게(절대값이 큰 음수로) 수렴하게 됩니다.

2. 목표점(3,3) 주변 가치의 불확실성 증가

  • 일반 그리드: (2,3)이나 (3,2) 같은 목표 바로 옆 칸은 항상 가치가 가장 높습니다(가장 덜 마이너스입니다).
  • 랜덤 벽 그리드: 랜덤 벽이 하필 목표점 주변을 둘러싸는 형태로 맵이 생성되는 에피소드가 존재합니다. 이 경우 목표점 바로 옆 칸이라도 갇혀서 빠져나가지 못하고 헤맬 수 있습니다. 따라서 상태 가치는 이러한 '막막한 맵'에서 깎인 점수까지 평균내어 반영하므로, 일반 환경보다 목표점 주변과 시작점 간의 가치 격차(Gradient)가 상대적으로 완만해지거나 찌그러지는 양상을 보입니다.

결론적으로 랜덤 벽 환경에서의 TD Learning은, "어느 경로든 벽이 생길 수 있는 리스크(불확실성)"까지 모두 고려된 평균적인 상태 가치를 훌륭하게 찾아낸다고 볼 수 있습니다.

'개념 정리 step2 > 강화 학습' 카테고리의 다른 글

[강화학습] Q-learning의 개념부터 Gym을 활용한 DQN 구현까지  (0) 2026.03.04
[강화학습] Deep Reinforcement Learning 개념  (0) 2026.03.03
[강화학습] Monte Carlo Learning 정리  (0) 2026.02.28
[강화학습] 벨만 기대 방정식 (Bellman Expectation Equation)  (0) 2026.02.27
[강화학습] 마르코프 결정 과정 MDP 정리 (MP, MRP, MDP)  (0) 2026.02.26
'개념 정리 step2/강화 학습' 카테고리의 다른 글
  • [강화학습] Q-learning의 개념부터 Gym을 활용한 DQN 구현까지
  • [강화학습] Deep Reinforcement Learning 개념
  • [강화학습] Monte Carlo Learning 정리
  • [강화학습] 벨만 기대 방정식 (Bellman Expectation Equation)
고니3000원
고니3000원
공부 내용 정리, 자기발전 블로그 입니다. 기존 네이버 블로그에서 티스토리로 이전했습니다. https://blog.naver.com/pak1010pak
  • 고니3000원
    곤이의 공부 블로그
    고니3000원
  • 전체
    오늘
    어제
    • 분류 전체보기 (178) N
      • 1. AI 논문 + 모델 분석 (20)
        • AI 논문 분석 (13)
        • AI 모델 분석 (7)
      • 2. 자료구조와 알고리즘 (16)
        • 2-1 자료구조와 알고리즘 (13)
        • 2-2 강화학습 알고리즘 (3)
      • 3. 자습 & 메모(실전, 실습, 프로젝트) (25)
        • 3-1 문제 해석 (4)
        • 3-2 메모(실전, 프로젝트) (14)
        • 3-3 배포 실전 공부 (7)
      • 4. [팀] 프로젝트 및 공모전 (14)
        • 4-1 팀 프로젝트(메모, 공부) (1)
        • 4-2 Meat-A-Eye (6)
        • 4-3 RL-Tycoon-Agent (3)
        • 4-4 구조물 안정성 물리 추론 AI 경진대회(D.. (4)
      • 5. [개인] 프로젝트 및 공모전 (0)
        • 4-1 귀멸의칼날디펜스(자바스크립트 활용) (5)
        • 4-2 바탕화면 AI 펫 프로그램 (4)
        • 4-3 개인 프로젝트(기타) (3)
      • 개념 정리 step1 (32)
        • Python 기초 (7)
        • DBMS (1)
        • HTML | CSS (3)
        • Git | GitHub (1)
        • JavaScript (5)
        • Node.js (5)
        • React (1)
        • 데이터 분석 (6)
        • Python Engineering (3)
      • 개념 정리 step2 (57) N
        • Machine | Deep Learning (15)
        • 멀티모달(Multi-modal) (23)
        • 강화 학습 (10)
        • AI Agent (9) N
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • 네이버 곤이의 블로그(Naver->Tistory)
    • Github
  • 공지사항

  • 인기 글

  • 태그

    paddleocr
    강화학습
    Vision
    자바스크립트
    transformer
    공모전
    Grad-CAM
    알고리즘
    bottleneck
    html
    pandas
    데이터분석
    자료구조
    OCR
    강화 학습
    학습
    EfficientNet
    javascript
    파이썬
    프로젝트
    github
    Attention Is All You Need
    OCR학습
    파인튜닝
    구현
    Ai
    논문 리뷰
    Python
    ViT
    귀칼
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
고니3000원
[강화학습] TD Learning (시간차 학습) 개념, 랜덤 벽 GridWorld 실습
상단으로

티스토리툴바