독서/기초부터 시작하는 강화학습 신경망 알고리즘

3.1 가치함수: 상태 가치 계산

studylida 2025. 3. 29. 00:43

 


📘 2장 이론: 상태가치와 벨만 방정식

❓ 에이전트는 어떻게 보상을 최대화하는 행동을 학습할까?

에이전트는 각 상태 또는 상태에서 가능한 행동들의 가치를 수치화한 후, 그 중 가장 가치가 높은 선택지를 고르는 방식으로 학습한다.
즉, 상태가치(state-value) 또는 행동가치(action-value)를 기준으로 행동을 결정한다.


📊 상태가치와 행동가치 (그림 2.19)

  • 그림 2.19a는 각 상태의 상태가치(V)를 나타낸다.
    • 도착지점에 가까울수록 상태가치가 높다.
    • 에이전트는 어디서든 가치가 높은 이웃 상태를 따라 이동하게 된다.
  • 그림 2.19b는 각 상태에서 선택할 수 있는 행동들의 가치(Q)를 보여준다.
    • 에이전트는 각 상태에서 행동가치가 가장 높은 행동을 선택해 도착지점에 도달한다.

이처럼 강화학습은 수익 G를 기준으로 상태나 행동의 가치를 수치화하여 학습을 수행한다.


🔍 상태가치함수 ( V_π(s) )

어떤 정책 π를 따를 때, 상태 s에서 얻을 수 있는 기대 수익 G상태가치 V_π(s)라 한다.

V_π(s) = E_π[G_t | S_t = s]     # 식 2.5

여기서 수익 G_t는 다음과 같이 정의된다:

G_t = r_{t+1} + γr_{t+2} + γ²r_{t+3} + …    # 할인된 보상의 합

따라서 식 2.5에 G_t를 대입하면 다음과 같이 된다:

V_π(s) = E_π[r_{t+1} + γr_{t+2} + γ²r_{t+3} + ... | S_t = s]   # 식 2.6

→ 그림 2.20은 이 식의 구조를 시각적으로 표현한 것이다.


🔁 식 2.6의 정리: 벨만 기대 방정식 (식 2.7)

식 2.6에서 보상 항에서 r_{t+1} 이후의 식을 다음과 같이 묶어보면,

γr_{t+2} + γ²r_{t+3} + γ³r_{t+4} + … 
= γ(r_{t+2} + γr_{t+3} + γ²r_{t+4} + …) 
= γG_{t+1} = γV_π(s_{t+1})

따라서 상태가치는 다음과 같이 표현된다:

V_π(s) = E_π[r_{t+1} + γV_π(s_{t+1}) | S_t = s]   # 식 2.7

이 식은 현재 상태의 가치가 즉시 보상다음 상태의 가치로 계산됨을 보여준다.
→ 이를 벨만 방정식(Bellman equation)이라고 한다.

🎯 강화학습은 결국 이 벨만 방정식을 반복적으로 풀어 최적의 상태가치를 찾는 과정이다.


🧭 다양한 행동이 가능한 환경: 식 2.8

지금까지는 다음 상태가 하나라고 가정했지만, 실제로는 하나의 상태에서 여러 행동이 가능하다. 예를 들어, 미로에서 상태 s7에서 상하좌우로 이동할 수 있는 경우 다음과 같은 4개의 상태로 전이된다:

s7 → s4 (위), s8 (오른쪽), cliff (아래), s6 (왼쪽)

이를 반영한 상태가치 계산식은 다음과 같다:

V_π(s7) = π(a1|s7) * P(s4|s7,a1) * [r(s7,a1,s4) + γV_π(s4)]
        + π(a2|s7) * P(s8|s7,a2) * [r(s7,a2,s8) + γV_π(s8)]
        + π(a3|s7) * P(cliff|s7,a3) * [r(s7,a3,cliff) + γV_π(cliff)]
        + π(a4|s7) * P(s6|s7,a4) * [r(s7,a4,s6) + γV_π(s6)]     # 식 2.8
  • π(a|s): 정책 π가 상태 s에서 행동 a를 선택할 확률
  • P(s'|s,a): 상태 s에서 행동 a를 했을 때 상태 s'로 전이될 확률
  • r(s,a,s'): 그에 대한 보상

📌 이 식은 식 2.7의 기댓값을 명시적으로 풀어 쓴 형태이다.


📐 일반화된 상태가치 계산식 (식 2.9)

식 2.8을 일반화하면 다음과 같다:

V_π(s) = ∑_a π(a|s) ∑_{s'} P(s'|s,a) [r(s,a,s') + γV_π(s')]   # 식 2.9

모든 가능한 행동과 그 행동의 결과로 도달할 상태를 고려한 기대 상태가치 계산 공식이다.


🔁 식 2.10: 상태가치 계산의 통합 표현

앞서 소개한 식들을 통합하면 다음과 같이 정리할 수 있다:

V_π(s) = E_π[G_t | S_t = s]
       = E_π[r_{t+1} + γG_{t+1} | S_t = s]
       = E_π[r_{t+1} + γV_π(s_{t+1}) | S_t = s]
       = ∑_a π(a|s) ∑_{s'} P(s'|s,a) [r(s,a,s') + γV_π(s')]    # 식 2.10

식 2.10은 확률적 환경에서도 일반적으로 사용할 수 있는 상태가치 계산식이다.


⚙️ 결정론적 환경에서의 단순화

이 책에서는 결정론적 환경을 전제로 한다.
즉, 어떤 행동 a를 선택하면 항상 하나의 상태 s′로 이동하며, P(s′|s,a) = 1이다.

따라서 식 2.10은 다음과 같이 간략화된다:

V_π(s) = ∑_a π(a|s) [r(s,a,s') + γV_π(s')]    # 상태 전이 확률 생략

📌 백업 다이어그램 (그림 2.24)

그림 2.24는 결정론적 환경과 확률적 환경에서 상태가치가 어떻게 계산되는지를 시각적으로 보여주는 상태가치 백업 다이어그램이다.

  • 상태 → 행동 → 다음 상태 → 보상 및 가치
  • 이를 통해 벨만 방정식이 실제로 어떻게 계산되는지를 직관적으로 이해할 수 있다.

🧮 2장 코드 구현: 상태가치 함수 구현과 시각화

🔧 상태가치 계산 개요

강화학습에서 상태가치 V_π(s)는 정책 π를 따를 때, 상태 s에서 얻을 수 있는 기대 수익이다. 하지만 실제 구현에서는 다음 상태를 어디까지 참고할 것인가를 정해야 한다.

  • 만약 가능한 모든 다음 상태를 무한히 탐색한다면 계산이 끝나지 않는다.
  • 따라서 프로그램에서는 max_step이라는 변수로 얼마나 먼 미래까지의 상태를 참고할지를 제한한다.
    • max_step = 0: 현재 상태와 다음 상태까지만 고려
    • max_step = 3: 현재 상태부터 최대 3단계 뒤 상태까지 고려

📌 now_step은 현재 얼마나 진행되었는지를 추적하며, now_step == max_step이거나 도착지점(goal)에 도달하면 재귀를 종료한다.


🔁 상태가치 함수 구현: state_value_function()

# 상태 가치 계산
def state_value_function(env, agent, G, max_step, now_step):

	# 1. 감가율 설정
	gamma = 0.9

	# 2. 현재 위치가 도착 지점인지 확인
	if env.reward_list1[agent.pos[0]][agent.pos[1]] == "goal":
		return env.goal  # 도착지점이면 보상 1 반환, 재귀 종료

	# 3. 마지막 상태는 보상만 계산
	if max_step == now_step:
		pos1 = agent.get_pos()

		# 3.1 가능한 모든 행동의 보상을 계산
		for i in range(len(agent.action)):
			agent.set_pos(pos1)
			observation, reward, done = env.move(agent, i)
			G += agent.select_action_pr[i] * reward

		return G
  • max_step == now_step이면 현재 상태에서만 행동을 수행하고 보상만 계산
  • 보상은 가능한 행동에 대한 기대값으로 계산

🔄 다음 상태 고려: 재귀 호출

	else:
		# 4. 현재 상태의 보상을 계산한 후 다음 step으로 이동

		# 4.1 현재 위치 저장
		pos1 = agent.get_pos()

		# 4.2 가능한 모든 행동을 시도
		for i in range(len(agent.action)):
			observation, reward, done = env.move(agent, i)

			# 4.2.1 현재 상태에서 보상을 계산
			G += agent.select_action_pr[i] * reward

			# 4.2.2 미로 밖일 경우 이전 좌표로 복귀
			if done:
				if observation[0] < 0 or observation[0] >= env.reward.shape[0] or \
				   observation[1] < 0 or observation[1] >= env.reward.shape[1]:
					agent.set_pos(pos1)

			# 4.2.3 다음 step에 대한 상태가치 계산
			next_v = state_value_function(env, agent, 0, max_step, now_step+1)
			G += agent.select_action_pr[i] * gamma * next_v

			# 4.2.4 현재 위치 복구
			agent.set_pos(pos1)

		return G
  • 각 행동을 시도한 후 다음 상태의 가치를 재귀적으로 계산
  • 이동 결과가 미로 밖이면 원래 위치로 되돌림
  • 다음 상태의 가치는 감가율 γ을 곱해 누적

🧪 전체 상태의 상태가치 계산

# 1. 환경 초기화
env = Environment()

# 2. 에이전트 초기화
agent = Agent()

# 3. 최대 max_step_number 세팅
max_step_number = 13

# 4. 계산 시간 저장을 위한 list
time_len = []

# 5. 재귀함수 state_value_function을 이용해 각 상태 가치 계산
for max_step in range(max_step_number):

	# 5.1 상태 가치 테이블 초기화
	v_table = np.zeros((env.reward.shape[0], env.reward.shape[1]))
	start_time = time.time()

	# 5.2 각 상태에 대해 상태가치 계산
	for i in range(env.reward.shape[0]):
		for j in range(env.reward.shape[1]):
			agent.set_pos([i, j])
			v_table[i, j] = state_value_function(env, agent, 0, max_step, 0)

	# 5.3 계산 시간 저장
	time_len.append(time.time() - start_time)
	print("max_step = {} total_time = {}(s)".format(max_step, np.round(time.time() - start_time, 2)))

	show_v_table(np.round(v_table, 2), env)

# 6. step별 계산 시간 그래프 그리기
plt.plot(time_len, 'o-k')
plt.xlabel('max_step')
plt.ylabel('time (s)')
plt.title('max_step별 계산 시간')
plt.show()

📈 결과 해석

그림 2.26 상태가치 계산의 범위

  • (a) max_step = 0: 현재 상태와 바로 다음 상태까지만 참고
  • (b) max_step = 1: 다음 상태의 다음 상태까지 포함
    → 이처럼 max_step을 늘려가며 더 멀리 있는 미래 보상을 고려한다.

그림 2.27 상태가치의 수렴

  • max_step이 작을 때는 상태가치가 불안정함
  • max_step = 7~8부터는 도착지점에 가까운 상태일수록 상태가치가 높아짐
  • 작은 미로에서는 max_step ≈ 8 정도면 수렴된 상태가치를 얻을 수 있다

그림 2.28 계산 시간의 증가

  • max_step이 얼마일 때 각 상태의 상태가치가 수렴될지 알 수 없음.
  • max_step이 증가할수록 계산 시간은 지수적으로 증가
  • max_step > 10 이후에는 시간이 급격히 늘어나며, 수렴까지 걸리는 시간 예측이 어려움

⚠️ 단순 재귀 기반 계산으로는 효율적인 상태가치 추정이 어렵기 때문에, 이후에는 정책 반복, 가치 반복과 같은 개선된 알고리즘을 사용한다.