[Ray RLlib로 강화학습 쉽게 사용하기] 7편: 사용자 정의 환경, 관측/행동 전처리, 콜백 활용하기

이전까지는 주로 Gym에 내장된 표준 환경(CartPole, MountainCar, Atari 등)을 활용했습니다. 그러나 실제 문제 해결 과정에서는 고유한 시뮬레이터나 데이터 소스에서 얻은 관측을 RL 환경으로 구성하고, 에이전트가 특정 형식의 행동을 내도록 설계해야 할 수 있습니다. 또한 RL 실험 중간에 특정 이벤트에 반응하거나, 관측값을 가공하는 등의 커스터마이징이 필요할 수도 있습니다.

이번 글에서는 다음 내용을 다룹니다.

  1. 사용자 정의 Gym 환경을 RLlib에 등록하고 적용하기
  2. Observation/Action Wrapper를 통한 관측, 행동 전처리
  3. 콜백(Callbacks)을 활용한 로그 확장, 성능 조건부 로직 삽입

사용자 정의 환경 연동

RLlib은 기본적으로 Gym 인터페이스에 맞는 환경이면 어떤 것이든 학습 대상로 사용할 수 있습니다. 사용자 정의 환경을 사용하려면 다음 단계를 따르면 됩니다.

  1. 사용자 환경 구현: gym.Env를 상속받아 __init__(), reset(), step() 메서드를 구현. 관측(observation), 행동(action), 보상(reward), done 반환 형식을 Gym 규칙에 맞춰야 합니다.
    import gym
    from gym import spaces
    import numpy as np
    
    class MyCustomEnv(gym.Env):
        def __init__(self, config=None):
            super(MyCustomEnv, self).__init__()
            self.action_space = spaces.Discrete(2)    # 예: 행동 2개
            self.observation_space = spaces.Box(low=0, high=1, shape=(4,))
            self.state = np.zeros(4)
        
        def reset(self):
            self.state = np.zeros(4)
            return self.state
        
        def step(self, action):
            # action에 따라 상태 변화, 보상 계산
            reward = 1.0 if action == 0 else 0.0
            done = False
            # 상태 업데이트 로직
            self.state = np.random.rand(4)
            if np.mean(self.state) > 0.9:
                done = True
            return self.state, reward, done, {}
    
  2. 예:
  3. 환경 등록:
    Gym 등록 방식을 이용하거나, RLlib에서 config.environment() 호출 시 env 인자에 이 환경 클래스를 직접 전달할 수도 있습니다.
    from ray.rllib.algorithms.ppo import PPOConfig
    
    config = (
        PPOConfig()
        .environment(env=MyCustomEnv)  # 클래스 자체 전달
        .framework("torch")
    )
    trainer = config.build()
    
    이렇게 하면 RLlib이 MyCustomEnv를 인스턴스화하여 사용합니다. env_config를 통해 환경 생성 시 필요한 추가 파라미터를 넘길 수도 있습니다:
  4. config = PPOConfig().environment(env=MyCustomEnv, env_config={"param1":123})
  5. 예:

이 방식으로 실제 산업 시뮬레이터, 로보틱스 시뮬레이션, 재무 데이터 처리 환경 등을 RLlib에 쉽게 통합할 수 있습니다.

관측/행동 전처리: Wrapper 활용

경우에 따라 관측값을 정규화하거나, 특정 행동을 행동공간에 매핑하는 전처리가 필요합니다. Gym에는 ObservationWrapper, ActionWrapper와 같은 래퍼(Wrapper) 클래스를 제공하며, RLlib에서도 이를 투명하게 사용할 수 있습니다.

예를 들어, 관측값을 정규화하기 위한 Wrapper:

import gym

class ObsNormalizeWrapper(gym.ObservationWrapper):
    def __init__(self, env):
        super().__init__(env)
    
    def observation(self, obs):
        return obs / 1.0  # 예: 단순 스케일링

env = ObsNormalizeWrapper(MyCustomEnv())

RLlib에서는 래퍼 적용 방법 중 하나로 env_make 콜백을 활용하거나, environment() 설정에서 직접 래핑한 환경 객체를 반환하는 함수를 지정할 수 있습니다.

def env_creator(env_config):
    base_env = MyCustomEnv(env_config)
    wrapped_env = ObsNormalizeWrapper(base_env)
    return wrapped_env

config = PPOConfig().environment(env=env_creator)

이렇게 하면 RLlib이 env_creator를 통해 래핑된 환경을 사용하게 됩니다.

Action Wrapper도 유사한 방식으로 행동을 변환할 수 있으며, 필요한 경우 연속 행동을 특정 범위로 클리핑, 이산 행동을 다른 형태로 매핑하는 작업을 수행할 수 있습니다.

콜백(Callbacks)으로 커스터마이징

callbacks는 RLlib에서 매우 유용한 기능으로, 학습 과정 중 특정 이벤트(에피소드 시작, 에피소드 종료, 스텝 완료, iteration 완료 등) 발생 시 사용자 정의 함수를 실행할 수 있게 합니다. 이를 통해 다음과 같은 작업이 가능합니다.

  • 에피소드마다 특별한 로그 기록
  • 특정 성능 기준 달성 시 파라미터 변경 또는 체크포인트 저장
  • 추가 모니터링 지표 계산 후 result에 포함

콜백 사용 예:

def my_callbacks(params):
    def on_episode_end(info):
        episode = info["episode"]
        ep_reward = episode.total_reward
        print(f"Episode finished with reward: {ep_reward}")
    return {
        "on_episode_end": on_episode_end
    }

config = PPOConfig().environment(env="CartPole-v1").callbacks(my_callbacks)
trainer = config.build()

여기서 on_episode_end 이벤트 발생 시 에피소드 리워드를 콘솔에 출력. 더 확장하면, 특정 리워드 달성 시 trainer.save() 호출하거나, 외부 DB에 결과 전송도 가능.

실제 프로젝트 적용 예시

  • 실제 산업용 RL 프로젝트에서:
    • 커스텀 환경: 로보틱스 시뮬레이터를 Env로 감싸기, 관측 전처리(센서 노이즈 정리), 행동 변환(토크→모터 명령)
    • 콜백: 특정 milestone(평균 리워드 200 이상 달성) 시 Slack 알림 전송, 정책 파라미터 JSON export
    • Wrapper: 관측값 정규화, 클리핑, 차원 축소 등으로 학습 안정성 개선

이런 방식으로 RLlib을 환경 중심의 실제 문제에 맞추어 커스터마이징할 수 있습니다.

마무리

핵심 포인트 정리:

  • 사용자 정의 환경: Gym 인터페이스로 구현 후 env=<class> 또는 env_creator 함수로 RLlib에 등록
  • Wrapper: 관측, 행동 전처리 용이. ObsNormalizeWrapper, ActionWrapper 등을 활용해 관측/행동 변환 가능
  • 콜백(callbacks): 학습 이벤트 기반 커스터마이징, 로그 확장, 조건부 동작 삽입
  • 실제 프로젝트 적용 시 다양한 환경, 전처리, 콜백 조합으로 고유 상황에 맞는 RL 파이프라인 구현 가능

이번 글에서는 RLlib을 단순히 기본 환경에서 사용하는 것을 넘어, 사용자 정의 환경 연동, 관측/행동 전처리 Wrapper, 콜백을 통한 커스터마이징 기법을 배웠습니다. 이를 통해 RLlib을 다양한 현실적인 상황에 적용할 수 있으며, 원하는 로직을 쉽게 삽입하고 변형할 수 있습니다.

다음 글에서는 지금까지 다룬 내용을 종합하고, 실전 프로젝트에서 RLlib을 활용할 때 고려해야 할 포인트, 추가 학습 자료, 앞으로의 방향성 등을 제안하며 시리즈를 마무리할 예정입니다.

반응형