카테고리 없음

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

dev-self 2025. 4. 24. 18:06

*본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성하였습니다.

 

|내용 정리|

<강화학습 환경 및 Q-학습 코드 분석>

환경(Environment) 분석

이 코드에서 환경은 다음과 같은 특징을 가진다:

  1. 4x4 격자: 총 16개의 상태가 있다.
  2. 특별한 위치들:
    • 직장(workplace): (0, 3) 위치, 값 2로 표시
    • 집(home): (3, 3) 위치, 값 3으로 표시
    • 공원(park): (1,1), (1,2), (2,1), (2,2) 위치, 값 -1로 표시
    • 에이전트: 값 1로 표시, 초기 위치는 (0, 0)
  3. 행동(Actions): 4가지 행동 가능
    • 0: 위로 이동
    • 1: 오른쪽으로 이동
    • 2: 아래로 이동
    • 3: 왼쪽으로 이동
  4. 확률적 환경: 70%의 확률로 선택한 행동을 수행하고, 30%의 확률로 무작위 다른 행동을 수행한다.
  5. 보상 시스템:
    • 기본 보상: -0.5 (매 스텝마다)
    • 직장에 도착: +5
    • 집에 도착: +10
    • 공원에 위치: -1.0
    • 이미 목표 지점(직장이나 집)에 있는 경우: 0
  6. 종료 조건: 에이전트가 직장이나 집에 도착하면 에피소드가 종료된다.

Q-learning 핵심 알고리즘 분석: 핵심 수식과 실제 코드 매핑

  • Q-learning의 핵심 업데이트 규칙은 다음과 같다:

  • 코드에서 이 수식이 구현된 부분을 살펴보자:
# 수식의 각 부분이 코드에서 어떻게 구현되었는지 매핑
td = r + gamma * action_value_matrix[i_s_next].max() - action_value_matrix[i_s][a]
action_value_matrix[i_s][a] = action_value_matrix[i_s][a] + alpha * td
  • 위의 실제 매핑을 표로 정리하면:

코드 내 핵심 Q-learning 구현 부분

다음은 코드에서 Q-learning의 핵심 부분과 수식을 직접 매핑한 것이다:

# 핵심 Q-learning 알고리즘 부분
def sarsa(env):
    # Q(s,a) 초기화: 모든 상태-행동 쌍에 대해 0으로 설정
    action_value_matrix = np.zeros([len(env.state_space), len(env.action_space)])
    
    # ε-greedy 정책에 따라 행동 선택
    def sample_action(eps, action_value):
        a_max = action_value.argmax()  # 최대 Q값을 가진 행동 선택 (greedy)
        pi = np.zeros([len(env.action_space)])
        pi[:] = eps / len(env.action_space)  # 모든 행동에 ε/|A| 확률 부여
        pi[a_max] = pi[a_max] + 1 - eps      # 최적 행동에 추가 확률 부여
        a = np.random.choice(env.action_space, p=pi)  # 확률에 따라 행동 선택
        return a

    # ε 값 계산 함수: 시간에 따라 감소
    def get_eps(total_step_count):
        return 1 / (1 + k_eps * total_step_count)  # k_eps = 1e-4
    
    # 학습 루프
    total_step_count = 0
    for loop_count in range(10000):  # 10000 에피소드 실행
        done = False
        step_count = 0

        # 환경 초기화 (s <- s0)
        s = env.reset()
        i_s = get_state_index(env.state_space, s)

        # 에피소드 실행
        while not done:
            # 현재 상태의 Q값들
            action_value = action_value_matrix[i_s]  # Q(s,·)
            
            # ε 계산 및 행동 선택
            eps = get_eps(total_step_count)
            a = sample_action(eps, action_value)  # a ~ π(·|s)
            
            # 행동 실행 및 결과 관찰
            r, s_next, done = env.step(a)  # r, s' <- Env(s,a)
            
            # TD 학습 (Q-learning)
            i_s_next = get_state_index(env.state_space, s_next)
            alpha = 1 / (1 + k_alpha * loop_count)  # 학습률 계산, k_alpha = 2e-2
            
            # --- 핵심 Q-learning 업데이트 공식 ---
            # TD 오차: δ = r + γ·max_a'Q(s',a') - Q(s,a)
            td = r + gamma * action_value_matrix[i_s_next].max() - action_value_matrix[i_s][a]
            
            # Q값 업데이트: Q(s,a) <- Q(s,a) + α·δ
            action_value_matrix[i_s][a] = action_value_matrix[i_s][a] + alpha * td
            # ---------------------------------
            
            # 종료 상태의 Q값은 0으로 설정
            if done:
                action_value_matrix[i_s_next] = 0
            
            # 카운터 업데이트 및 상태 전이
            step_count += 1
            total_step_count += 1
            
            s = s_next
            i_s = i_s_next

        # 진행 상황 출력
        if (loop_count + 1) % 100 == 0:
            print(
                f"[{loop_count}] action_value_matrix: \n{action_value_matrix} "
                + f"eps: {get_eps(total_step_count):.4f} "
                + f"alpha: {alpha:.4f}"
            )

    # 학습된 Q 함수에서 최적 정책 추출
    policy = np.zeros([len(env.state_space), len(env.action_space)])
    state_indexes = np.arange(len(env.state_space))
    argmax_actions = action_value_matrix.argmax(axis=-1)  # 각 상태에서 최대 Q값을 가진 행동
    policy[state_indexes, argmax_actions] = 1.0  # 최적 행동에 확률 1 부여

    return action_value_matrix, policy

실제 예시 계산

예를 들어, 특정 상황에서의 Q-learning 업데이트를 살펴보자:

상황 가정:

  • 현재 상태 s: (0,0) [그리드의 왼쪽 상단] (인덱스 i_s = 0)
  • 선택한 행동 a: 1 (오른쪽으로 이동)
  • 보상 r: -0.5 (기본 이동 보상)
  • 다음 상태 s': (0,1) [오른쪽으로 한 칸 이동] (인덱스 i_s_next = 1)
  • loop_count: 100 (100번째 에피소드)
  • total_step_count: 500 (총 500 스텝 진행)
  • 현재 Q값 action_value_matrix[0][1]: -1.2 (예시 값)
  • 다음 상태의 Q값들 action_value_matrix[1]: [-0.8, -0.5, -1.0, -1.1]

계산 과정:

  • 학습률 계산:
alpha = 1 / (1 + k_alpha * loop_count) = 1 / (1 + 0.02 * 100) = 1/3 ≈ 0.333
  • ε 계산:
eps = 1 / (1 + k_eps * total_step_count) = 1 / (1 + 0.0001 * 500) = 1/1.05 ≈ 0.952
  • TD 오차 계산:
max_q_next = action_value_matrix[i_s_next].max() = max([-0.8, -0.5, -1.0, -1.1]) = -0.5
td = r + gamma * max_q_next - action_value_matrix[i_s][a]
td = -0.5 + 0.95 * (-0.5) - (-1.2) = -0.5 - 0.475 + 1.2 = 0.225
  • Q값 업데이트:
action_value_matrix[i_s][a] = action_value_matrix[i_s][a] + alpha * td
action_value_matrix[0][1] = -1.2 + 0.333 * 0.225 = -1.2 + 0.075 = -1.125

 

 - 이렇게 Q값이 -1.2에서 -1.125로 업데이트되었다. TD 오차가 양수이므로 Q값이 증가했으며, 이는 실제 보상과 다음 상태의 예상 가치를 고려할 때 현재 행동의 가치가 이전보다 높다는 것을 의미한다.


Q-learning 알고리즘 실행 과정

아래 그림은 Q-learning 알고리즘의 내부 실행 과정을 보여준다:

  1. 초기화: 모든 상태-행동 쌍의 Q값을 0으로 초기화한다.
  2. 에피소드 시작: 에이전트를 초기 상태(0,0)로 리셋한다.
  3. 행동 선택: ε-greedy 정책에 따라 행동을 선택한다.
    • ε 확률로 무작위 행동 선택
    • (1-ε) 확률로 현재 최대 Q값을 가진 행동 선택
    • ε는 시간에 따라 감소: ε = 1/(1+k_eps*total_step_count)
  4. 행동 실행: 선택된 행동을 실행하지만, 환경이 확률적이기 때문에 30%의 확률로 다른 무작위 행동이 실행된다.
  5. Q값 업데이트: TD(시간차) 학습을 통해 Q값을 업데이트한다.
    • 학습률 α 계산: α = 1/(1+k_alpha*loop_count)
    • TD 오차 계산: TD = r + γ·max_a'Q(s',a') - Q(s,a)
    • Q값 업데이트: Q(s,a) ← Q(s,a) + α·TD
  6. 종료 확인: 에이전트가 직장이나 집에 도달했는지 확인한다.
    • 종료된 경우: 해당 에피소드를 마치고 다음 에피소드로 넘어간다.
    • 종료되지 않은 경우: 상태를 전이(s←s')하고 다시 행동을 선택한다.
  7. 정책 추출: 충분한 학습 후, 각 상태에서 최대 Q값을 가진 행동을 선택하는 최적 정책을 추출한다.

 

|인증|

 

 

-------

패스트캠퍼스 링크

https://bit.ly/4hTSJNB