studylida 2025. 3. 31. 02:07

📘 2장 이론 (2): 행동가치 함수 ( Q_π(s, a) )

🔍 행동가치란?

지금까지는 상태의 가치인 ( V_π(s) )를 계산하는 방법을 살펴봤다. 그러나 실제 강화학습에서는 상태에서 어떤 행동을 선택할 것인지가 핵심이다.
즉, 상태 ( s )에서 행동 ( a )를 했을 때 기대되는 수익을 나타내는 행동가치 함수 ( Q_π(s,a) )를 정의한다.


🧾 행동가치 함수의 정의

정책 π를 따를 때, 상태 ( s )에서 행동 ( a )를 선택했을 때의 기대 수익 ( G_t )는 다음과 같이 정의된다:

Q_π(s, a) = E_π[G_t | S_t = s, A_t = a]
         = E_π[r_{t+1} + γr_{t+2} + γ²r_{t+3} + ... | S_t = s, A_t = a]
         = E_π[r_{t+1} + γV_π(s') | S_t = s, A_t = a]

즉, 행동가치는 즉시 보상다음 상태의 가치를 통해 계산된다.

확률적 환경에서는 다음과 같이 정리된다:

Q_π(s,a) = ∑_{s' ∈ S} P(s'|s,a) [r(s,a,s') + γV_π(s')]   # 식 2.12

결정론적 환경에서는 다음과 같이 단순화된다:

Q_π(s,a) = r(s,a,s') + γV_π(s')   # 식 2.13

📌 행동가치 함수는 다음 상태의 상태가치 V_π(s′)에 기반해 계산된다.


📈 행동가치 백업 다이어그램 (그림 2.29)

  • 확률적 환경: 하나의 행동 ( a )가 여러 상태 ( s' )로 전이될 수 있으며, 각각의 전이 확률과 보상을 고려해 ( Q_π(s, a) )를 계산함
  • 결정론적 환경: 하나의 행동이 한 상태로만 전이되므로 계산이 간단해짐

→ 두 환경의 차이는 상태전이확률 ( P(s'|s,a) )에 있음


🔁 확률적 환경에서 상태가치와 행동가치의 관계

  • 상태가치 함수:
V_π(s) = ∑_a π(a|s) ∑_{s'} P(s'|s,a)[r(s,a,s') + γV_π(s')]
  • 행동가치 함수:
Q_π(s,a) = ∑_{s'} P(s'|s,a)[r(s,a,s') + γV_π(s')]

→ 행동가치는 다음 상태의 상태가치 V_π(s′)로 계산되며,
→ 상태가치는 각 행동의 행동가치 Q_π(s,a)를 가중 평균해 계산된다.


🔄 상태가치를 행동가치로 표현

상태가치 식의 내부를 보면 행동가치 정의와 동일하므로, 다음과 같이 정리할 수 있다:

V_π(s) = ∑_a π(a|s) Q_π(s,a)    # 식 2.14

→ 상태가치는 각 행동의 행동가치를 평균한 값

다음 상태 s′에 대해 쓰면:

V_π(s') = ∑_a π(a|s') Q_π(s',a)    # 식 2.15

🔁 행동가치의 재귀 표현

식 2.15를 행동가치 함수에 대입하면 다음과 같이 된다:

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

→ 즉, 행동가치는 다음 상태에서 선택될 수 있는 행동들의 행동가치를 이용해 계산할 수 있다.


📊 상태가치와 행동가치의 전체 관계 (그림 2.30)

  • 그림 2.30은 ( V_π(s) )와 ( Q_π(s,a) )의 관계를 수식과 백업 다이어그램으로 정리한 그림이다.
  • 이 그림을 통해 정책 π, 보상 r, 전이확률 P, 감가율 γ가 어떻게 연관되어 있는지 시각적으로 확인할 수 있다.

📌 상태가치와 행동가치는 서로 독립적인 함수가 아니라, 서로를 기반으로 정의되며 유기적으로 연결되어 있다.


🧮 2장 코드 구현 (2): 행동가치 함수 ( Q_π(s,a) )

🔍 개요

앞서 상태가치 함수 ( V_π(s) )를 구현한 것과 유사하게, 이제는 각 상태에서 가능한 행동들의 행동가치 ( Q_π(s,a) )를 계산한다.

행동가치는 다음 수식에 따라 계산된다:

Q_π(s,a) = ∑_{s' ∈ S} P(s'|s,a) [r(s,a,s') + γV_π(s')]
V_π(s') = r_{t+2} + γr_{t+3} + γ²r_{t+4} + γ³r_{t+5} …    

# 식 2.17

→ 다음 상태 s′의 상태가치 ( V_π(s') )는 보상의 합으로 계산됨


🧠 행동가치 함수 구현: action_value_function()

# 행동가치함수
def action_value_function(env, agent, act, G, max_step, now_step):

    # 1. 감가율 설정
    gamma = 0.9

    # 2. 현재 위치가 목적지인지 확인
    if env.reward_list1[agent.pos[0]][agent.pos[1]] == "goal":
        return env.goal

    # 3. 마지막 상태는 보상만 계산
    if (max_step == now_step):
        observation, reward, done = env.move(agent, act)
        G += agent.select_action_pr[act] * reward
        return G

    # 4. 현재 상태의 보상을 계산한 후 다음 행동과 함께 다음 step으로 이동
    else:
        # 4.1 현재 위치 저장
        pos1 = agent.get_pos()
        observation, reward, done = env.move(agent, act)
        G += agent.select_action_pr[act] * reward

        # 4.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.3 현재 위치를 다시 저장
        pos1 = agent.get_pos()

        # 4.4 가능한 모든 행동을 수행하며 다음 상태의 행동가치를 계산
        for i in range(len(agent.action)):
            agent.set_pos(pos1)
            next_v = action_value_function(env, agent, i, 0, max_step, now_step+1)
            G += agent.select_action_pr[i] * gamma * next_v

        return G
  • 기본 구조는 상태가치 함수와 유사
  • 다만 현재 상태에서 하나의 행동 act를 고정한 후 재귀적으로 그 행동의 가치를 추적
  • 다음 상태에서는 다시 가능한 모든 행동을 조사하며 기대값 계산

🔁 모든 상태·행동에 대한 행동가치 계산

# 재귀적으로 행동의 가치를 계산

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

# 2. 에이전트 초기화
agent = Agent()
np.random.seed(0)

# 3. 현재부터 max_step까지 계산
max_step_number = 8

# 4. 모든 상태에 대해
for max_step in range(max_step_number):

    # 4.1 행동가치를 저장할 Q-table 초기화
    print("max_step = {}".format(max_step))
    q_table = np.zeros((env.reward.shape[0], env.reward.shape[1], len(agent.action)))

    for i in range(env.reward.shape[0]):
        for j in range(env.reward.shape[1]):

            # 4.2 각 상태에서 가능한 모든 행동에 대해
            for action in range(len(agent.action)):

                # 4.2.1 에이전트 위치 초기화
                agent.set_pos([i, j])

                # 4.2.2 행동가치 계산
                q_table[i, j, action] = action_value_function(env, agent, action, 0, max_step, 0)

    # Q-table 시각화
    q = np.round(q_table, 2)
    print("Q - table")
    show_q_table(q, env)
    print("High actions Arrow")
    show_q_table_arrow(q, env)
    print()
  • 모든 상태에 대해 가능한 행동 4가지(상, 우, 하, 좌)의 가치를 계산
  • 행동가치는 최대 max_step=7까지 연결된 다음 상태를 참고하여 계산

📈 결과 해석

그림 2.31 행동가치 함수 시각화

  • Q-table: 각 상태에서 가능한 행동별 ( Q_π(s,a) ) 값
  • 행동 화살표: 각 상태에서 가장 높은 행동가치를 가지는 방향 표시

max_step별 해석 요약

  • max_step = 0: 보상만 고려. 미로 밖으로 나가는 행동만 낮은 값. 도착지점 바로 위(s5), 왼쪽(s7)에서 도착 방향으로 이동하는 행동만 상대적으로 큰 값 (0.25). 나머지 행동은 어떤 것이 더 좋은 행동인지 알 수 없음.
  • max_step = 1: 도착 확률이 높은 행동일수록 높은 가치 → 전체적으로 행동가치가 구별됨. 어떤 상태에서 출발하더라도 행동가치가 높은 행동을 따라가면 도착지점에 도착하게 됨.
  • max_step = 7: 행동가치가 어느 정도 수렴하지만, 완전 수렴은 아님