*본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성하였습니다.
|내용 정리|
<강화학습 환경 및 Q-학습 코드 분석>

환경(Environment) 분석
이 코드에서 환경은 다음과 같은 특징을 가진다:
- 4x4 격자: 총 16개의 상태가 있다.
- 특별한 위치들:
- 직장(workplace): (0, 3) 위치, 값 2로 표시
- 집(home): (3, 3) 위치, 값 3으로 표시
- 공원(park): (1,1), (1,2), (2,1), (2,2) 위치, 값 -1로 표시
- 에이전트: 값 1로 표시, 초기 위치는 (0, 0)
- 행동(Actions): 4가지 행동 가능
- 0: 위로 이동
- 1: 오른쪽으로 이동
- 2: 아래로 이동
- 3: 왼쪽으로 이동
- 확률적 환경: 70%의 확률로 선택한 행동을 수행하고, 30%의 확률로 무작위 다른 행동을 수행한다.
- 보상 시스템:
- 기본 보상: -0.5 (매 스텝마다)
- 직장에 도착: +5
- 집에 도착: +10
- 공원에 위치: -1.0
- 이미 목표 지점(직장이나 집)에 있는 경우: 0
- 종료 조건: 에이전트가 직장이나 집에 도착하면 에피소드가 종료된다.
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 알고리즘의 내부 실행 과정을 보여준다:
- 초기화: 모든 상태-행동 쌍의 Q값을 0으로 초기화한다.
- 에피소드 시작: 에이전트를 초기 상태(0,0)로 리셋한다.
- 행동 선택: ε-greedy 정책에 따라 행동을 선택한다.
- ε 확률로 무작위 행동 선택
- (1-ε) 확률로 현재 최대 Q값을 가진 행동 선택
- ε는 시간에 따라 감소: ε = 1/(1+k_eps*total_step_count)
- 행동 실행: 선택된 행동을 실행하지만, 환경이 확률적이기 때문에 30%의 확률로 다른 무작위 행동이 실행된다.
- 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
- 종료 확인: 에이전트가 직장이나 집에 도달했는지 확인한다.
- 종료된 경우: 해당 에피소드를 마치고 다음 에피소드로 넘어간다.
- 종료되지 않은 경우: 상태를 전이(s←s')하고 다시 행동을 선택한다.
- 정책 추출: 충분한 학습 후, 각 상태에서 최대 Q값을 가진 행동을 선택하는 최적 정책을 추출한다.

|인증|




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