ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [강화학습] chatgpt랑 공부하는 강화학습: Q-learning, FrozenLake - 3
    배우기 - computer로 하는거 2025. 4. 13. 17:11

    지난번까지는 학습 코드에 대해 살펴봤다. 이번 글에서는 학습이 끝난 agent가 어떻게 행동하는지 살펴보겠다.

    우선 main함수를 다시 살펴보면

    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와 전부 똑같은데 render_mode만 "human"으로 되어 있다. render_mode에 따른 차이는 지난 글을 참고하면 된다.

    main에서 play_trained_agent를 호출하는데, agent를 실행하고 실행 과정을 확인하는 코드는 아래와 같다.

    def play_trained_agent(env, q_table):
        state, _ = env.reset()
        done = False
    
        print("\n🚶 에이전트 경로:")
        env.render()
        time.sleep(0.05)
    
        while not done:
            action = np.argmax(q_table[state])
            state, reward, terminated, truncated, _ = env.step(action)
            done = terminated or truncated
    
            # print(env.render())
            env.render()
            time.sleep(0.05)
    
        env.close()
    
        if reward == 1:
            print("🎉 성공적으로 Goal 도달!")
        else:
            print("💥 실패! 구멍에 빠졌거나 종료됨")

    실행결과를 확인할 환경(env)과 학습이 끝난 q_table을 입력으로 받아 q_table을 이용해 env안에서 action을 순서대로 실행한다.

    while 문 안쪽은 학습 코드와 동일하다. 실제로 실행하면 결과는 아래와 같이 나타난다.

    성공한 케이스


    실패한 케이스


    위와 같은 실행 결과를 동영상으로도 저장할 수 있다.

    받은 코드:

    from gymnasium.wrappers import RecordVideo
    
    def main():
        train_env = gym.make("FrozenLake-v1", map_name="4x4", is_slippery=True)
    
        # 영상 저장용 환경: render_mode는 'rgb_array'
        play_env = gym.make(
            "FrozenLake-v1",
            map_name="4x4",
            is_slippery=True,
            render_mode="rgb_array"
        )
    
        # 영상 녹화 래퍼 적용
        play_env = RecordVideo(
            play_env,
            video_folder="./videos",             # 저장 경로
            name_prefix="frozenlake_final",      # 파일 이름 prefix
            episode_trigger=lambda x: True       # 모든 실행 저장
        )
    
        q_table = train_on_frozen_lake(train_env)
        play_trained_agent(play_env, q_table)
        play_env.close()  # 이게 호출되어야 영상 저장됨

    위 코드로 메인함수를 수정하면 되는데, RecordVideo를 사용하려면 "pip install moviepy" 로 moviepy라는걸 설치해야 한다. 최초 에러메세지에는 

    gymnasium.error.DependencyNotInstalled: MoviePy is not installed, run
    pip install "gymnasium[other]"

    라고 나오는데, chatGPT가 pip install "gymnasium[other]" 를 하면 쓸데없는 패키지도 깔리니까 그냥 pip install moviepy 로 설치하라고 한다.

    어쨋든, 필요한 패키지를 설치하고 아래 코드를 실행하면 학습 후 실행 결과가 동영상으로 저장이 된다. 1편에서 올렸던 코드와 달라진 점은 main함수 부분인데, 1편에서는 학습 결과를 바로 실행하여 확인할수 있고, 이 버전은 동영상으로 저장하는 버전이다.

    최종 코드 (동영상으로 저장):

    import gymnasium as gym
    import numpy as np
    import time
    import matplotlib.pyplot as plt
    from tqdm import tqdm
    from gymnasium.wrappers import RecordVideo
    
    
    def play_trained_agent(env, q_table):
        state, _ = env.reset()
        done = False
    
        print("\n🚶 에이전트 경로:")
        env.render()
        time.sleep(0.05)
    
        while not done:
            action = np.argmax(q_table[state])
            state, reward, terminated, truncated, _ = env.step(action)
            done = terminated or truncated
    
            # print(env.render())
            env.render()
            time.sleep(0.05)
    
        env.close()
    
        if reward == 1:
            print("🎉 성공적으로 Goal 도달!")
        else:
            print("💥 실패! 구멍에 빠졌거나 종료됨")
    
    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
    
    
    def main():
        train_env = gym.make("FrozenLake-v1", map_name="4x4", is_slippery=True)
        # 영상 저장용 환경: render_mode는 'rgb_array'
        play_env = gym.make(
            "FrozenLake-v1",
            map_name="4x4",
            is_slippery=True,
            render_mode="rgb_array"
        )
    
        # 영상 녹화 래퍼 적용
        play_env = RecordVideo(
            play_env,
            video_folder="./result_video",  # 저장 경로
            name_prefix="frozenlake_final",  # 파일 이름 prefix
            episode_trigger=lambda x: True  # 모든 실행 저장
        )
    
        q_table = train_on_frozen_lake(train_env)  # 학습만 수행
        play_trained_agent(play_env, q_table)      # 학습된 q_table로 결과 보기
        play_env.close()  # 이게 호출되어야 영상 저장됨
    
    if __name__ == '__main__':
        main()
Designed by Tistory.