*본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성하였습니다.
|내용 정리|
<TD(Temporal Difference) 예제 연습_2>
TD 학습을 통한 가치 함수와 행동-가치 함수 분석
환경 설명

위의 그리드는 다음과 같은 특징을 가진 강화학습 환경이다:
- 상태 공간: 3x4 그리드
- 시작 위치: A (0,0)
- 목표 위치: G (0,3)
- 표류 영역(drift area): 첫 번째 행의 가운데 두 칸(///)
- 행동 공간: 상(0), 우(1), 하(2), 좌(3)
- 전이 모델:
- 에이전트의 행동에 따라 상하좌우 이동 (무작위성 없음)
- 표류 영역에 들어가면 시작점(0,0)으로 이동
- 목표에 도달하면 에피소드 종료
- 보상: 목표 도달 시 +10, 그 외에는 0
- 감가율(γ): 0.9
- 학습률(α): 2e-3 (Q-함수 학습 시 5배 증가)
정책 설명
코드에서는 두 가지 정책을 사용하여 TD 학습을 진행한다:
- 균일 정책(policy1):
- 모든 상태에서 각 행동의 확률: 상(0.25), 우(0.25), 하(0.25), 좌(0.25)
- 수학적 표기: π(a|s) = 0.25 (모든 행동 a에 대해)
- 불균일 정책(policy2):
- 모든 상태에서 각 행동의 확률: 상(0.25), 우(0.4), 하(0.25), 좌(0.1)
- 수학적 표기: π(up|s) = 0.25, π(right|s) = 0.4, π(down|s) = 0.25, π(left|s) = 0.1
TD 학습 코드 실행 프로세스 및 함수 관계 설명

전체 프로그램 실행 흐름
- 시작점 (main)
- 환경 초기화 (Env 클래스 인스턴스 생성)
- 두 가지 정책 초기화:
- 정책1: 모든 상태에서 각 행동의 확률이 동일 (0.25, 0.25, 0.25, 0.25)
- 정책2: 방향 별 확률이 다른 정책 (0.25, 0.4, 0.25, 0.1)
- 정책 평가 과정 실행
- 결과 출력 및 비교
- 환경 설정 (environment.py)
- 그리드 월드 환경 구현
- 유효한 상태 공간 정의
- 행동 공간 및 전이 모델 정의
- TD 학습 알고리즘 구현 (td_prediction.py)
- 상태 가치 함수(V(s)) 학습 함수
- 행동-가치 함수(Q(s,a)) 학습 함수
- 유틸리티 함수 (get_state_index)
주요 함수 역할 및 관계
환경 관련 함수들
- Env.__init__(): 환경 초기화
- 3x4 그리드 생성
- 시작 위치, 목표 위치, 표류 영역 설정
- 유효한 상태 공간과 행동 공간 정의
- Env.reset(): 환경 초기화 (에피소드 시작)
- 에이전트 위치를 시작점으로 되돌림
- 초기 상태 반환
- Env.step(action): 행동 실행
- 주어진 행동에 따라 에이전트 위치 갱신
- 표류 영역 체크 및 처리
- 보상, 다음 상태, 종료 여부 반환
- Env.reward(s, a, s_next): 보상 계산
- 목표 도달 시 +10, 그 외 0 반환
TD 학습 관련 함수들
- get_state_index(state_space, state): 상태 인덱스 찾기
- 주어진 상태가 상태 공간에서 몇 번째 인덱스인지 반환
- 상태 배열과 상태 인덱스 간 매핑 역할
- td_value_prediction(env, policy): 상태 가치 함수(V(s)) 학습
- 가치 벡터 초기화
- 5000개 에피소드 생성 및 학습
- 매 스텝마다 TD 오차 계산 및 가치 함수 업데이트
- 학습된 가치 벡터 반환
- td_action_value_prediction(env, policy): 행동-가치 함수(Q(s,a)) 학습
- 행동-가치 행렬 초기화
- 5000개 에피소드 생성 및 학습
- 매 스텝마다 TD 오차 계산 및 Q 함수 업데이트
- 학습된 행동-가치 행렬 반환
데이터 흐름
- 정책 정의 → TD 학습 함수
- 정책(policy): 각 상태에서 행동 확률 분포
- TD 학습 함수는 정책을 입력으로 받아 가치 함수 추정
- 환경(Env) → TD 학습 함수
- 환경은 상태 공간, 행동 공간, 전이 규칙 제공
- 환경의 step() 함수는 행동에 따른 다음 상태와 보상 제공
- TD 학습 함수 → 메인 프로그램
- 학습된 가치 함수(V(s) 또는 Q(s,a))를 반환
- 메인 프로그램에서 결과 비교 및 출력
결과 처리
- 가치 벡터 → 가치 테이블
- 1차원 가치 벡터를 2차원 그리드 형태로 변환
- 시각화 및 해석에 용이한 형태로 변환
- 행동-가치 행렬 → 정책 평가
- 각 상태에서 정책에 따른 기대 가치 계산
- 두 정책 간 성능 비교
주요 알고리즘 흐름
- TD 가치 함수 학습:
초기화: V(s) = 0
For 5000 에피소드:
s = 초기 상태
While 에피소드 진행 중:
a = π(s)에서 행동 선택
r, s' = 행동 a 실행 결과
V(s) ← V(s) + α[r + γV(s') - V(s)]
s = s'
- TD 행동-가치 함수 학습:
초기화: Q(s,a) = 0
For 5000 에피소드:
s = 초기 상태
a = π(s)에서 행동 선택
While 에피소드 진행 중:
r, s' = 행동 a 실행 결과
a' = π(s')에서 행동 선택
Q(s,a) ← Q(s,a) + 5α[r + γQ(s',a') - Q(s,a)]
s = s', a = a'
이 코드는 TD 학습의 기본 원리를 잘 보여주며, 서로 다른 정책에 대한 가치 함수와 행동-가치 함수를 학습하고 비교하는 과정을 구현하고 있다.
실행 프로세스


1. 초기화 단계
env = Env() # 환경 생성
# 정책1: 균일 정책 생성 (모든 행동 확률 0.25)
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|)
# 정책2: 불균일 정책 생성 (행동 확률 0.25, 0.4, 0.25, 0.1)
policy2 = list()
for i_s, s in enumerate(env.state_space):
pi = np.array([0.25, 0.4, 0.25, 0.1])
policy2.append(pi)
policy2 = np.array(policy2)
2. TD 학습 실행 프로세스 (V(s) 함수)
- 함수 호출: value_vector1 = td_value_prediction(env, policy1)
- 초기화: 가치 벡터를 0으로 초기화
에피소드 생성:
for loop_count in range(5000):
done = False
s = env.reset() # 환경 리셋
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)
# TD 업데이트
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
# 다음 상태로 이동
s = s_next
3. TD 학습 실행 프로세스 (Q(s,a) 함수)
- 함수 호출: action_value_matrix1 = td_action_value_prediction(env, policy1)
- 초기화: 행동-가치 행렬을 0으로 초기화
- 에피소드 생성:
for loop_count in range(5000):
done = False
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)
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 업데이트
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
# 다음 상태-행동으로 이동
s = s_next
i_s = i_s_next
a = a_next
4. 결과 처리
# 1차원 가치 벡터를 2차원 가치 테이블로 변환
value_table1 = np.zeros([3, 4])
value_table1[0,0] = value_vector1[0]
value_table1[0,3] = value_vector1[1]
value_table1[1:] = value_vector1[2:6]
value_table1[2:] = value_vector1[6:10]
# 행동-가치 행렬에서 정책에 따른 기대 가치 계산
value_vector_temp1 = np.sum(policy1 * action_value_matrix1, axis=-1)
상태 가치 함수(V(s)) 학습 코드 상세 분석
def td_value_prediction(env, policy):
value_vector = np.zeros([len(env.state_space)])
- 먼저 모든 상태의 가치를 0으로 초기화. value_vector는 1차원 배열로, 각 상태의 가치 함수 V(s)를 저장.
# Repeat policy evaluation
for loop_count in range(5000):
- 총 5000번의 에피소드를 실행. 각 에피소드마다 가치 함수를 업데이트.
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
- 여기가 TD 학습의 핵심이다:
- r + gamma * value_vector[i_s_next]는 현재 보상과 다음 상태의 할인된 가치를 합한 값으로, 가치 함수의 목표값.
- value_vector[i_s]는 현재 추정한 상태의 가치.
- td는 목표값과 현재 추정값의 차이, 즉 TD 오차.
- 가치 함수를 TD 오차의 방향으로 학습률 alpha만큼 업데이트.
if done:
value_vector[i_s_next] = 0
- 에피소드가 종료되면 종료 상태의 가치를 0으로 설정(목표 상태의 가치는 추가 보상이 없으므로).
step_count += 1
s = s_next
- 단계 수를 증가시키고 다음 상태로 이동.
if (loop_count + 1) % 100 == 0:
print(f"[{loop_count}] value_vector: \n{value_vector}")
- 100 에피소드마다 현재 가치 함수를 출력.
행동-가치 함수(Q(s,a)) 학습 코드 상세 분석
def td_action_value_prediction(env, policy):
action_value_matrix = np.zeros([len(env.state_space), len(env.action_space)])
- 모든 상태-행동 쌍의 가치를 0으로 초기화. action_value_matrix는 2차원 배열로, 각 상태-행동 쌍의 가치 함수 Q(s,a)를 저장.
# Repeat policy evaluation
for loop_count in range(5000):
done = False
step_count = 0
s = env.reset()
- V(s) 학습과 마찬가지로, 5000번의 에피소드를 실행하고 환경을 초기화.
i_s = get_state_index(env.state_space, s)
pi_s = policy[i_s]
a = np.random.choice(env.action_space, p=pi_s)
- Q 함수 학습에서는 에피소드 시작 전에 첫 행동을 선택. 이는 Q 함수가 상태-행동 쌍의 가치이기 때문에, 첫 업데이트를 위해 초기 행동이 필요하기 때문.
# 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
- Q 함수 업데이트의 핵심부분이다:
- r + gamma * action_value_matrix[i_s_next][a_next]는 현재 보상과 다음 상태-행동의 할인된 가치를 합한 값으로, Q 함수의 목표값.
- action_value_matrix[i_s][a]는 현재 추정한 상태-행동의 가치.
- td는 목표값과 현재 추정값의 차이, 즉 TD 오차.
- Q 함수를 TD 오차의 방향으로 학습률 5 * alpha만큼 업데이트. 특이한 점은 V 함수보다 5배 큰 학습률을 사용한다는 것.
if done:
action_value_matrix[i_s_next] = 0
- 에피소드가 종료되면 종료 상태의 모든 행동 가치를 0으로 설정.
step_count += 1
s = s_next
i_s = i_s_next
a = a_next
- 다음 상태와 행동으로 이동.
V(s)와 Q(s,a)의 주요 차이점
- 표현 차원:
- V(s)는 상태에 대한 가치만 저장 (상태 수 만큼의 값)
- Q(s,a)는 상태-행동 쌍에 대한 가치를 저장 (상태 수 × 행동 수 만큼의 값)
- 업데이트 방식:
- V(s) 업데이트: V(s) ← V(s) + α[r + γV(s') - V(s)]
- Q(s,a) 업데이트: Q(s,a) ← Q(s,a) + α[r + γQ(s',a') - Q(s,a)]
- 학습률 차이:
- 이 코드에서는 Q 함수에 더 큰 학습률(5α)을 사용하여 학습 속도를 높임
- 정책과의 관계:
- V(s)는 정책을 따랐을 때의 기대 가치를 나타냄
- Q(s,a)는 특정 행동을 선택한 후 정책을 따랐을 때의 기대 가치를 나타냄
- V(s)는 Q(s,a)를 정책에 따라 가중 평균한 값: V(s) = Σ π(a|s)Q(s,a)
|인증|




-------
패스트캠퍼스 링크