-
[강화학습] chatgpt랑 공부하는 강화학습: Q-learning, FrozenLake - 2배우기 - computer로 하는거 2025. 4. 10. 22:27
지난번에는 학습, 실행 코드를 정리했었다. 이번 글에서는 하나씩 천천히 살펴보도록 하겠다. (전체 코드는 이전 글 참조)
1. main 함수:
우선 메인함수는 아래와 같다. main 함수는 학습을 수행하고, 실제로 특정 환경에서 학습된 agent를 동작시키는 역할을 한다.
def main(): train_env = gym.make("FrozenLake-v1", map_name="4x4", is_slippery=True) play_env = gym.make("FrozenLake-v1", map_name="4x4", is_slippery=True, render_mode="human") q_table = train_on_frozen_lake(train_env) # 학습만 수행 play_trained_agent(play_env, q_table) # 학습된 q_table로 결과 보기 if __name__ == '__main__': main()
train_env는 학습하는 환경, play_env는 실행하는 환경이다. render_mode는 각 환경에서 실행되는 결과를 눈으로 확인할수 있는 부분이다. render_mode 옵션으로는 ansi, human 등을 지정할 수 있는데 둘의 차이는 아래와 같다.
ansi human 🚶 에이전트 경로:
(Left)
SFFF
FHFH
FFFH
HFFG
(Left)
SFFF
FHFH
FFFH
HFFG
...
(Left)
SFFF
FHFH
FFFH
HFFG
(Down)
SFFF
FHFH
FFFH
HFFG
🎉 성공적으로 Goal 도달!
ansi에서 각 필드 위의 방향과 결과가 다른 것은 is_slippery 옵션을 True 했기 때문에 랜덤으로 움직일 확률이 있어서 그렇다.
이때, render_mode="human"으로 하기 위해서는 pygame 을 설치해야 한다.pip install pygame 명령어로 설치할수도 있는데, "gymnasium[toy-text]" 방식이 더 깔끔하고 추천된다고 한다.
2. 학습
학습 코드는 아래와 같다.
def train_on_frozen_lake(env): rewards = [] # 하이퍼파라미터 설정 alpha = 0.8 # 학습률 (learning rate) gamma = 0.99 # 할인율 epsilon = 1.0 # 탐험 확률 (epsilon-greedy) epsilon_min = 0.1 epsilon_decay = 0.9995 episodes = 10000 # 에피소드 수 # Q-테이블 초기화: 상태 수 x 행동 수 q_table = np.zeros([env.observation_space.n, env.action_space.n]) # 학습 루프 for _ in tqdm(range(episodes)): state, _ = env.reset() done = False total_reward = 0 while not done: # 행동 선택: 탐험 or 활용 (epsilon-greedy) if np.random.uniform(0, 1) < epsilon: action = env.action_space.sample() # 무작위 행동 else: action = np.argmax(q_table[state]) # 환경에 행동 적용 -> 다음 상태, 보상, 종료 여부 등 받기 next_state, reward, terminated, truncated, _ = env.step(action) done = terminated or truncated # Q 테이블 업데이트 q_table[state, action] = q_table[state, action] + alpha * ( reward + gamma * np.max(q_table[next_state]) - q_table[state, action] ) # 상태 업데이트 state = next_state # epsilon 감소 if epsilon > epsilon_min: epsilon *= epsilon_decay total_reward += reward rewards.append(total_reward) # 학습 완료 후 Q 테이블 출력 print("Q-table") print(q_table) # 누적 성공률 (100 에피소드마다 평균) window = 100 moving_avg = [np.mean(rewards[i - window:i + 1]) for i in range(window, len(rewards))] plt.plot(moving_avg) plt.title("🎯 Moving Average of Success Rate") plt.xlabel("Episode") plt.ylabel("Success Rate") plt.grid(True) plt.show() return q_table
2.1. 하이퍼 파라미터
학습에 사용하는 하이퍼파라미터는 아래와 같다.
- alpha: 학습률 (learning rate)
- gamma: 할인율
- epsilon: 탐험 확률 (epsilon-greedy)
- episodes: 에피소드 수
alpha는 일반적인 기계학습, 딥러닝에사용하는 학습률인것 같고, 에피소드 수는 epoch, 이나 몇 스텝을 돌릴지에 대한 값이다.
gamma, epsilon은 생소해서 chatGPT한테 물어봤다.
2.1.1 gamma:
라고 물어보니,
좋은 질문이야! gamma = 0.95 처럼 나오는 할인율(Discount Factor) 은 **"미래 보상을 얼마나 중요하게 생각할 것인가"**를 정하는 값이야.
라고 한다. 뒤에 더 길게 설명해줬는데 정리하면
gamma가 크면 미래 보상을 더 중요시하고
gamma가 작으면 당장 눈앞의 이득만 추구한다
고 보면 되겠다. (0 ~ 1 로 세팅)
2.1.2. epsilon:
2.2. 학습
하이퍼 파라미터 이후 코드는 아래와 같다.
2.2.1. q_table
# Q-테이블 초기화: 상태 수 x 행동 수 q_table = np.zeros([env.observation_space.n, env.action_space.n])
q_table은 최초에 전부 0으로 설정한다. 그리고 q_table이란
저러고나서 한참 또 설명하는데, 내가 한번 보면서 정리를 해보겠다.
Q-table: 어떤 상태(State)에서 행동(action)을 취했을 때 얻을수 있는 보상(reward, Q)이 들어있는 테이블이다. 즉,
이런 식이다.
2.2.2. 학습 루프
그다음 바로 학습 루프 안으로 들어가는데,
# 학습 루프 for _ in tqdm(range(episodes)): state, _ = env.reset() done = False total_reward = 0
총 episodes 만큼 반복하고, 현재 에피소드에서 상태(state)를 초기화한다.
2.2.2.1. action
이제 학습 코드의 나머지 부분을 살펴보겠다.
while not done: # 행동 선택: 탐험 or 활용 (epsilon-greedy) if np.random.uniform(0, 1) < epsilon: action = env.action_space.sample() # 무작위 행동 else: action = np.argmax(q_table[state])
epsilon에 따른 분기처리하는 부분은 위에서 살펴봤고, action은 1~4 사이의 값이고 각 값은 방향을 나타낸다. 처음 chatGPT가 FrozenLake 설명해줄때 말해줬는데, 까먹어서 또 물어봤다.
근데 글 쓰면서 확인해보니 앞에서는 chatGPT가 다르게 말했었다.. 이런
일단 다 정리하고 다시 확인해보겠다. chatGPT 랑 공부할때는 이런 디테일한 부분은 잘 확인해봐야겠다.
2.2.2.2. 상태 업데이트
다음 코드는 아래와 같다. (while문 내부)
# 환경에 행동 적용 -> 다음 상태, 보상, 종료 여부 등 받기 next_state, reward, terminated, truncated, _ = env.step(action) done = terminated or truncated # Q 테이블 업데이트 q_table[state, action] = q_table[state, action] + alpha * ( reward + gamma * np.max(q_table[next_state]) - q_table[state, action] ) # 상태 업데이트 state = next_state
일단 env.step(action)을 통해 action을 입력받고, action에 대해 다음 상태, 보상, 종료 여부 등을
라고 한다.
q_table 을 실제로 업데이트하는 아래 부분에 대해서 chatGPT는
라고 설명해줬다.
그리고 state = next_state를 통해 state를 next_state로 업데이트하고, 한 에피소드 당 이 과정을 done = True일 때까지 반복한다. (epsilon 관련 부분은 위 하이퍼파라미터 부분 참조)
즉, 매 에피소드마다 구멍에 빠지거나 골에 도달할때까지 q_table에 있는 값(액션에 대한 보상)에 따라 action을 선택하고 그 action으로 다시 q_table을 업데이트하는 것을 반복하는 것이다. 그리고 각 에피소드의 reward (성공 1, 실패 0)을 저장해둔다. (필수는 아님)
2.3. 학습결과 확인
# 누적 성공률 (100 에피소드마다 평균) window = 100 moving_avg = [np.mean(rewards[i - window:i + 1]) for i in range(window, len(rewards))] plt.plot(moving_avg) plt.title("🎯 Moving Average of Success Rate") plt.xlabel("Episode") plt.ylabel("Success Rate") plt.grid(True) plt.show()
100 에피소드 당 성공률의 이동평균 위 그래프를 보면 6,000 스텝까지는 성공률이 거의 0이다가 이후에 성공하기 시작하며 학습 완료시점에는 20~30퍼센트까지 올라가는 것을 확인할 수 있다.
다음 글에서는 학습이 끝난 q_table 을 이용해 agent가 실제로 어떻게 동작하는지 확인해보겠다.
[강화학습] chatgpt랑 공부하는 강화학습: Q-learning, FrozenLake - 3
'배우기 - computer로 하는거' 카테고리의 다른 글
[강화학습] chatgpt랑 공부하는 강화학습: Q-learning, FrozenLake - 3 (0) 2025.04.13 [강화학습] chatgpt랑 공부하는 강화학습: Q-learning, FrozenLake - 1 (0) 2025.04.10