카테고리 없음

패스트캠퍼스 환급챌린지 45일차 : 스크래치부터 시작하는 강화학습의 모든 것 강의 후기

dev-self 2025. 4. 18. 10:50

<TD(Temporal Difference)  예제 연습_3>

코드 설명

1. 환경 (environment.py)

이 코드는 강화학습에서 사용되는 4x4 그리드 환경을 구현:

  • 상태 공간: 4x4 그리드로 다음과 같은 값을 가짐
    • 에이전트 위치: 1
    • 직장 위치: 2 (오른쪽 상단 모서리, [0,3])
    • 집 위치: 3 (오른쪽 하단 모서리, [3,3])
    • 공원 구역: -1 (중앙 2x2 영역, [1:3, 1:3])
  • 행동 공간: {0, 1, 2, 3}
    • 0: 위로 이동
    • 1: 오른쪽으로 이동
    • 2: 아래로 이동
    • 3: 왼쪽으로 이동
  • 전이 역학:
    • 사용자가 선택한 행동이 70% 확률로 실행됨
    • 30% 확률로 다른 임의의 행동이 대신 실행됨
    • 에이전트가 그리드 경계에 도달하면 그 자리에 머무름
  • 보상 구조:
    • 기본 이동 보상: -0.5
    • 공원 구역에 있을 때: -1.0
    • 직장에 도착했을 때: +5
    • 직장에 머무를 때: 0
    • 집에 도착했을 때: +10
    • 집에 머무를 때: 0
  • 종료 조건:
    • 에이전트가 직장이나 집에 도착하면 에피소드 종료
  • 전이 확률 함수:
    • 환경의 확률적 특성을 명시적으로 계산하는 함수 포함

2. TD 예측 알고리즘 (td_prediction.py)

이 코드는 시간차(TD) 학습 알고리즘으로 주어진 정책에 따른 상태 가치와 행동 가치를 예측:

  • 하이퍼파라미터:
    • 감마(gamma): 0.9 (할인 인자)
    • 알파(alpha): 1e-3 (학습률)
  • TD 상태 가치 예측:
    • td_value_prediction 함수
    • 주어진 정책을 평가하여 각 상태의 가치를 계산
    • TD(0) 업데이트 규칙 사용: V(s) ← V(s) + α[r + γV(s') - V(s)]
  • TD 행동 가치 예측:
    • td_action_value_prediction 함수
    • 주어진 정책에 대해 각 상태-행동 쌍의 가치를 계산
    • Sarsa 업데이트 규칙 사용: Q(s,a) ← Q(s,a) + α[r + γQ(s',a') - Q(s,a)]
  • 메인 실행부:
    • 균일한 무작위 정책(모든 행동에 대해 확률 0.25)을 사용
    • 상태 가치와 행동 가치를 계산하고 출력
    • 계산된 행동 가치에서 정책을 사용해 상태 가치를 역산하여 일관성 확인

코드 실행 흐름

  1. 환경 초기화: 4x4 그리드 생성, 에이전트는 [0,0]에서 시작
  2. 정책 설정: 모든 상태에서 4가지 행동에 대해 균등한 확률(0.25) 부여
  3. TD 상태 가치 예측:
    • 10,000번의 반복으로 상태 가치 추정
    • 각 반복마다 에피소드 생성 (에이전트가 목표 지점에 도달할 때까지)
    • TD 업데이트로 상태 가치 조정
  4. TD 행동 가치 예측:
    • 유사하게 10,000번 반복으로 행동 가치 추정
    • Sarsa 알고리즘으로 상태-행동 가치 조정
  5. 결과 출력:
    • 계산된 상태 가치와 행동 가치 출력
    • 일관성 검증을 위한 비교값 계산

주요 알고리즘 및 초기화 코드 상세 분석

1. 환경 초기화 코드 (__init__)

def __init__(self):
    '''
    state_space: 4x4 grid info using numpy
    value ot the agent location: 1
    value of the workplace location: 2
    value of the home location: 3
    value of the park: -1

    action_space: {0, 1, 2, 3}
    0: up
    1: right
    2: down
    3: left
    '''
    self.agent_pos = {'y': 0, 'x': 0}
    self.workplace_pos = {'y': 0, 'x': 3}
    self.home_pos = {'y': 3, 'x': 3}
    self.park_area = {'y':[1, 2], 'x':[1, 2]}
    self.y_min, self.x_min, self.y_max, self.x_max = 0, 0, 3, 3

    
    # set up state
    self.state = self.set_state(self.agent_pos['y'], self.agent_pos['x'])

    self.state_space = list()
    for y in range(4):
        for x in range(4):
            state = self.set_state(y, x)
            self.state_space.append(state)

    self.action_space = [0, 1, 2, 3]

상세 설명:

  • 위치 초기화: 환경에서 주요 요소들의 위치를 딕셔너리로 설정.
    • 에이전트: 왼쪽 상단 모서리 (0,0)
    • 직장: 오른쪽 상단 모서리 (0,3)
    • 집: 오른쪽 하단 모서리 (3,3)
    • 공원: 중앙 2x2 영역 ([1,2], [1,2])
  • 그리드 경계: 4x4 그리드의 경계를 지정 (y_min=0, x_min=0, y_max=3, x_max=3)
  • 상태 공간 생성: 가능한 모든 상태(16개 위치)를 생성하고 리스트에 저장
    • 각 상태는 4x4 NumPy 배열로 표현
    • 배열 내 값은 에이전트, 직장, 집, 공원의 위치 정보를 담음

2. 상태 설정 함수 (set_state)

def set_state(self, y_agent, x_agent):
    state = np.zeros([4,4])
    state[self.workplace_pos['y'], self.workplace_pos['x']] = 2
    state[self.home_pos['y'], self.home_pos['x']] = 3
    state[self.park_area['y'], self.park_area['x']] = -1
    state[y_agent, x_agent] = 1
    return state

상세 설명:

  • 4x4 크기의 0으로 초기화된 배열 생성
  • 환경의 주요 요소들을 배열에 표시:
    • 직장 위치(값: 2)
    • 집 위치(값: 3)
    • 공원 영역(값: -1)
    • 에이전트 위치(값: 1)
  • 주의할 점: 에이전트가 직장이나 집에 있을 때는 값 1이 덮어씌워짐

3. 환경 진행 함수 (step)

def step(self, action):
    # Update environmental variables 
    is_random_action = np.random.choice([0, 1], p=[0.7, 0.3])

    if is_random_action:
        random_action_set = list(self.action_space)
        random_action_set.remove(action)
        action = np.random.choice(random_action_set)

    if action == 0:
        # 'y' should be decreased by 1 or stay the same when it is at the top row
        self.agent_pos['y'] = max(
            self.agent_pos['y'] - 1, 
            self.y_min
        )
    elif action == 1:
        # 'x' should be increased by 1 or stay the same when it is at the most right column
        self.agent_pos['x'] = min(
            self.agent_pos['x'] + 1, 
            self.x_max
        )
    elif action == 2:
        # 'y' should be increased by 1 or stay the same when it is at the bottom row
        self.agent_pos['y'] = min(
            self.agent_pos['y'] + 1, 
            self.y_max
        )
    elif action == 3:
        # 'x' should be decreased by 1 or stay the same when it is at the most left column
        self.agent_pos['x'] = max(
            self.agent_pos['x'] - 1, 
            self.x_min
        )
    else:
        assert False, "Invalid action value was fed to step."

    # Make a next state after transition
    prev_state = self.state
    self.state = self.set_state(self.agent_pos['y'], self.agent_pos['x'])

    done = False
    if (
            self.agent_pos == self.workplace_pos or
            self.agent_pos == self.home_pos
        ):
        done = True

    reward = self.reward(prev_state, action, self.state)

    return reward, self.state, done

상세 설명:

  • 확률적 행동 처리:
    • 70% 확률로 선택된 행동 실행
    • 30% 확률로 다른 임의의 행동으로 대체
  • 행동 실행:
    • 상/하/좌/우 이동을 처리하며 그리드 경계 체크
    • 경계에 도달하면 그 자리에 머무름 (max/min 함수 사용)
  • 상태 업데이트:
    • 이전 상태 저장 후 새 상태 설정
    • set_state 함수로 에이전트 새 위치 반영
  • 종료 조건 확인:
    • 에이전트가 직장이나 집에 도착했는지 확인
    • 도착했다면 done = True로 설정
  • 보상 계산:
    • reward 함수 호출하여 보상 계산
    • 이전 상태, 행동, 새 상태를 기반으로 함
  • 반환값:
    • 보상, 새 상태, 종료 여부를 튜플로 반환

4. 보상 함수 (reward)

def reward(self, s, a, s_next):
    reward = -0.5
    y, x = np.where(s == 1)
    y_next, x_next = np.where(s_next == 1)

    was_at_workplace = (
        y == self.workplace_pos['y'] and 
        x == self.workplace_pos['x']
    )
    is_at_workplace = (
        y_next == self.workplace_pos['y'] and 
        x_next == self.workplace_pos['x']
    )

    was_at_home = (
        y == self.home_pos['y'] and 
        x == self.home_pos['x']
    )
    is_at_home = (
        y_next == self.home_pos['y'] and 
        x_next == self.home_pos['x']
    )

    is_in_park = (
        y_next in self.park_area['y'] and 
        x_next in self.park_area['x']
    )
    
    if was_at_workplace and is_at_workplace:
        reward = 0 
    elif (
            not was_at_workplace and
            is_at_workplace
        ):  # Reached the workplace
        reward = 5
    
    if was_at_home and is_at_home:
        reward = 0 
    if (
            not was_at_home and
            is_at_home
        ): # Reached the home
        reward = 10
    
    if is_in_park:
        reward = -1.0
        
    return reward

상세 설명:

  • 기본 보상: 모든 이동에 대해 -0.5 기본 보상 설정
  • 위치 파악: 이전 상태와 새 상태에서 에이전트 위치 추출 (numpy의 where 사용)
  • 직장 관련 보상:
    • 직장에 이미 있었고 계속 있음: 0
    • 다른 곳에서 직장으로 도착: +5
  • 집 관련 보상:
    • 집에 이미 있었고 계속 있음: 0
    • 다른 곳에서 집으로 도착: +10
  • 공원 관련 보상:
    • 공원 구역 내에 있음: -1.0

5. TD 가치 예측 알고리즘 (td_value_prediction)

def td_value_prediction(env, policy):
    value_vector = np.zeros([len(env.state_space)])
    
    # Repeat policy evaluation
    for loop_count in range(10000):
        done = False
        step_count = 0
        s = env.reset()
        # Generate an episode
        while not done:
            i_s = get_state_index(env.state_space, s)
            pi_s = policy[i_s]
            a = np.random.choice(env.action_space, p=pi_s)
            r, s_next, done = env.step(a)
            
            i_s_next = get_state_index(env.state_space, s_next)
            td = r + gamma * value_vector[i_s_next] - value_vector[i_s]
            value_vector[i_s] = value_vector[i_s] + alpha * td

            if done:
                value_vector[i_s_next] = 0

            step_count += 1            
            s = s_next

        if (loop_count + 1) % 100 == 0:
            print(f"[{loop_count}] value_vector: \n{value_vector}")

    return value_vector

상세 설명:

  • 초기화: 모든 상태의 가치를 0으로 초기화
  • 정책 평가 반복: 10,000회 반복하여 가치 함수 학습
  • 에피소드 생성: 각 반복마다 에피소드 생성
    • 에이전트가 목표(직장/집)에 도달할 때까지 진행
  • 행동 선택: 현재 상태에서 정책에 따라 확률적으로 행동 선택
  • TD 업데이트: TD(0) 알고리즘으로 상태 가치 업데이트
    • TD 오차 = 보상 + (감마 * 다음 상태 가치) - 현재 상태 가치
    • 현재 상태 가치 += 학습률 * TD 오차
  • 목표 상태 처리: 에피소드 종료 시 목표 상태 가치를 0으로 설정
  • 로깅: 100회 반복마다 현재 가치 벡터 출력

6. TD 행동 가치 예측 알고리즘 (td_action_value_prediction)

def td_action_value_prediction(env, policy):
    action_value_matrix = np.zeros([len(env.state_space), len(env.action_space)])
    
    # Repeat policy evaluation
    for loop_count in range(10000):
        done = False
        step_count = 0
        s = env.reset()

        i_s = get_state_index(env.state_space, s)
        pi_s = policy[i_s]
        a = np.random.choice(env.action_space, p=pi_s)
        # Generate an episode
        while not done:
            
            r, s_next, done = env.step(a)
            i_s_next = get_state_index(env.state_space, s_next)
            pi_s_next = policy[i_s_next]
            a_next = np.random.choice(env.action_space, p=pi_s_next)
            
            td = r + gamma * action_value_matrix[i_s_next][a_next] - action_value_matrix[i_s][a]
            action_value_matrix[i_s][a] = action_value_matrix[i_s][a] + 5 * alpha * td

            if done:
                action_value_matrix[i_s_next] = 0

            step_count += 1            
            s = s_next
            i_s = i_s_next
            a = a_next

        if (loop_count + 1) % 100 == 0:
            print(f"[{loop_count}] action_value_matrix: \n{action_value_matrix}")

    return action_value_matrix

상세 설명:

  • 초기화: 모든 상태-행동 쌍의 가치를 0으로 초기화
  • 에피소드 사전 준비:
    • 초기 상태와 행동을 에피소드 시작 전에 선택
    • 이는 Sarsa 알고리즘의 특징 (on-policy TD 제어)
  • Sarsa 업데이트:
    • 현재 (s,a), 다음 (s',a')의 행동-상태 쌍을 사용
    • TD 오차 = 보상 + (감마 * 다음 상태-행동 가치) - 현재 상태-행동 가치
    • 현재 상태-행동 가치 += 5 * 학습률 * TD 오차
    • (주의: 학습률이 상태 가치 예측보다 5배 높음)
  • 목표 상태 처리: 에피소드 종료 시 목표 상태의 모든 행동 가치를 0으로 설정
  • 상태-행동 갱신: 다음 단계로 이동하여 현재 상태와 행동 업데이트

7. 메인 실행 코드

if __name__ == "__main__":
    np.set_printoptions(formatter={'float': '{: 0.3f}'.format})

    env = Env()
    policy1 = list()
    for i_s, s in enumerate(env.state_space):
        pi = np.array([0.25, 0.25, 0.25, 0.25])
        policy1.append(pi)
    policy1 = np.array(policy1)  # (|S|, |A|)

    value_vector1 = td_value_prediction(env, policy1)
    value_table1 = value_vector1.reshape(4, 4)

    action_value_matrix1 = td_action_value_prediction(env, policy1)  # (|S|, |A|)
    value_vector_temp1 = np.sum(policy1 * action_value_matrix1, axis=-1)

    print(f"value_table1: \n{value_table1}")
    print(f"action_value_matrix1: \n{action_value_matrix1}")
    print(f"value_vector1: \n{value_vector1}")
    print(f"value_vector_temp1: \n{value_vector_temp1}")

상세 설명:

  • 출력 형식 설정: NumPy 출력 형식을 소수점 3자리로 지정
  • 환경 초기화: 4x4 그리드 환경 생성
  • 정책 생성: 모든 상태에서 균등한 확률(0.25)의 무작위 정책 생성
  • 상태 가치 예측: TD 알고리즘으로 상태 가치 계산
  • 가치 테이블 변환: 벡터를 4x4 그리드 형태로 재구성하여 시각화
  • 행동 가치 예측: TD-Sarsa 알고리즘으로 행동 가치 계산
  • 일관성 검증:
    • 정책과 행동 가치를 곱하여 각 상태의 가치 재계산
    • 이는 직접 계산한 상태 가치와 비교를 위한 것

TD 학습 알고리즘 학습 과정 및 결과 분석

제공된 이미지는 TD(Temporal Difference) 학습 알고리즘의 실행 결과를 보여주고 있다. 이는 강화학습 과정에서 가치 함수가 어떻게 학습되는지 보여주는 중요한 정보이다.

1. 가치 벡터 (value_vector) 수렴 과정

이미지 1의 상단부는 TD 상태 가치 예측 알고리즘이 반복됨에 따라 각 상태의 가치가 어떻게 변화하는지 보여준다:

  • 반복 횟수: [9399], [9499], [9599], ... 등의 숫자는 알고리즘 반복 횟수를 나타낸다.
  • 가치 수렴: 반복이 진행됨에 따라 가치 벡터의 값들이 점차 안정화되고 있다. 예를 들어:
    • 첫 번째 위치의 가치는 약 -3.67에서 -3.69 사이로 수렴
    • 세 번째 위치의 가치는 약 -0.1에서 -0.2 사이로 수렴

이는 TD 학습의 핵심 특성을 보여준다 - 매 반복마다 예측된 가치가 실제 얻은 보상과 다음 상태의 가치를 기반으로 점차 조정된다.

2. 행동 가치 행렬 (action_value_matrix) 학습

이미지 1의 하단부와 이미지 2는 행동 가치 행렬의 학습 과정과 최종 결과를 보여준다:

  • 초기 행렬([99]): 초기에는 상대적으로 작은 값(-0.3~0.6 범위)을 가짐
  • 중간 행렬([199]): 학습이 진행됨에 따라 값의 범위가 넓어짐(-0.6~1.3)
  • 최종 행렬([9999]): 충분한 학습 후 행동 가치가 크게 분화됨(-3.9~7.1)

행동 가치 행렬의 특징적인 패턴:

  1. 집과 직장 위치([3,3]과 [0,3])의 행은 모두 0으로 설정됨 (종료 상태)
  2. 집 근처 위치([2,3])에서는 아래(2) 행동이 높은 가치(7.152)를 가짐
  3. 직장 근처 위치([0,2])에서는 오른쪽(1) 행동이 높은 가치(3.060)를 가짐
  4. 공원 구역에 있는 상태는 대체로 낮은 행동 가치를 가짐

3. 가치 테이블 (value_table1) 분석

바로 위 이미지의 중간부에 나타난 가치 테이블은 4x4 그리드에서 각 위치의 가치를 보여준다:

[[-3.673 -2.834 -0.098  0.000]
 [-3.896 -3.253 -1.444  1.231]
 [-3.734 -2.960 -0.723  2.739]
 [-3.246 -2.140  1.787  0.000]]

이 테이블에서 중요한 패턴:

  1. 목표 위치: 직장(0,3)과 집(3,3)은 0 값을 가짐 (종료 상태)
  2. 높은 가치 위치: 집 근처([3,2]는 1.787, [2,3]은 2.739)와 직장 근처([1,3]은 1.231)는 양수 값
  3. 낮은 가치 위치: 공원 구역(중앙 2x2)과 시작점 근처(왼쪽 상단)는 큰 음수 값
  4. 가치 경사: 목표 위치에서 멀어질수록 가치가 감소하는 경향

4. 일관성 검증 결과

이미지 2의 하단부는 두 가지 방법으로 계산된 가치 벡터를 비교한다:

  • value_vector1: TD 상태 가치 예측으로 직접 계산된 가치
  • value_vector_temp1: 행동 가치와 정책을 곱해 계산된 가치

두 벡터의 값이 매우 유사하지만 약간의 차이가 있다. 이는 두 알고리즘(TD 상태 가치 예측과 TD 행동 가치 예측)이 서로 다른 방식으로 학습되었지만, 결과적으로 일관된 가치 체계를 학습했음을 의미한다.

디버깅 결과의 의미

이 디버깅 출력은 다음과 같은 중요한 의미를 가진다:

  1. 학습 성공: TD 학습 알고리즘이 성공적으로 가치 함수를 학습했음을 보여준다.
  2. 정책 평가 검증: 균등한 무작위 정책(모든 행동에 0.25의 확률)에 대한 가치 함수 예측이 정확함을 검증한다.
  3. 보상 구조 반영: 가치 함수가 환경의 보상 구조(집 도착 +10, 직장 도착 +5, 공원 -1, 이동 -0.5)를 잘 반영하고 있다.
  4. 에이전트 동작 예측: 에이전트가 어떤 위치에서 어떤 행동을 취하는 것이 유리한지 행동 가치를 통해 알 수 있다.

특히, 행동 가치 행렬에서 각 상태별로 가장 높은 가치를 가진 행동을 선택하면 최적 정책을 구성할 수 있으며, 이는 에이전트가 가장 효율적으로 목표(직장 또는 집)에 도달하는 경로를 나타낸다.

 

 

|인증|

 

-------

패스트캠퍼스 링크

https://bit.ly/4hTSJNB