본문 바로가기

딥러닝/강화학습(RL)

[Analyse RLLib] 6 Multi Agent Two Step Game and MADDPG

Two Step Game

Actions

각각의 agent는 0 또는 1을 선택할 수 있고, 결과는 state에 따라서 다릅니다. 밑의 표 참고.

State

state global_reward done
0 0 False
(0,*)->state(1)
(1,*)->state(2)
1 7 True
2 (0,1)->0
(1,0)->8
otherwise->1
True
  • (a,b)에서 a :agent_1's action, b :agent_2's action

Observations

각 Agent마다 Observation을 가지게 된다. np.concatenate([self.state, [agent_index]])로 구현되며, state 2 상태의 2번 째 Agent라면, [0,0,1,2] 형태로 나온다.
state 0 상태의 1번 째 Agent라면, [1,0,0,1].

구현에서는 dict 타입으로 observaiton을 반환하며, state를 따로 줄 수도 있다.

def _obs(self):
        if self.with_state:
            return {
                self.agent_1:{
                    "obs": self.agent_1_obs(),
                    ENV_STATE:self.state
                },
                self.agent_2:{
                    "obs":self.agent_2_obs(),
                    ENV_STATE:self.state
                }
            }
        else:
            return {
                self.agent_1 : self.agent_1_obs(),
                self.agent_2 : self.agent_2_obs()
            }

# === obsevation of each agent ===
def agent_1_obs(self):
        if self.one_hot_state_encoding:
            return np.concatenate([self.state, [1]])
        else:
            return np.flatnonzero(self.state)[0]
def agent_2_obs(self):
    if self.one_hot_state_encoding:
        return np.concatenate([self.state, [2]])
    else:
        return np.flatnonzero(self.state)[0] + 3

Rewards

Reward는 State에서 구한 Global Reward 값의 절반이다.

rewards = {
            self.agent_1: global_rew / 2.0,
            self.agent_2: global_rew / 2.0
        }

MADDPG with TwoStepGame MultiAgent Environment

rllib/contrib/maddpg에는 이미 MADDPG모델이 구현이 되어 있습니다.

Two Step Game 환경에서 모델을 학습시키겠습니다.

configuration

multi agent 환경이므로 multiagent 키를 추가해줍니다. 또한, agent_id에 대해서 policy를 mapping해주는 policy_mapping_fn도 필요합니다.

config = {
        "learning_starts": 100,
        "env_config": {
            "actions_are_logits": True,
        },
        "multiagent": {
            "policies": {
                "pol1": (None, Discrete(6), TwoStepGame.action_space, {"agent_id": 0}),
                "pol2": (None, Discrete(6), TwoStepGame.action_space, {"agent_id": 1}),
            },
            "policy_mapping_fn": lambda x: "pol1" if x == 0 else "pol2",
        },
        "framework": "torch" if args.torch else "tf",
        # Use GPUs iff `RLLIB_NUM_GPUS` env var set to > 0.
        "num_gpus": int(os.environ.get("RLLIB_NUM_GPUS", "0")),
    }

tune

config에 env를 추가해줍니다. 위의 코드에서 env:~~로 추가할 수도 습니다. 여기서는 dictionary에 새로운 원소를 추가하는 부분이라서 그대로 사용했습니다.

ray.init(num_cpus=args.num_cpus or None)
    stop = {
        "episode_reward_mean": args.stop_reward,
        "timesteps_total": args.stop_timesteps,
    }
    config = dict(config, **{"env": TwoStepGame})

    # === train === 
    results = tune.run("contrib/MADDPG", stop=stop, config=config, verbose=1)

만일 제대로 동작하지 않는다면pip install tensorflow-probability==0.7.0 으로 tfp를 설치해야 합니다.

References

[1] tfp error https://github.com/ray-project/ray/issues/6895
[2] https://github.com/ray-project/ray

Appendix

What I found

  1. MADDPG의 Output은 Action에 대한 logit이다.
  2. Dict.get("name", False)는 "name"에 대한 값을 가져오며 키가 없다면 두 번째 파라미터를 반환한다.
  3. Constant 값 ENV_STATE"state" 값이다.
  4. state가 같이 있다면, observaiton_spacedict 타입이고, 아니면 gym.space.MultiDiscrete 타입이다
  5. np.flatnonzero(self.state)[0] + 3 # give the index of nonzero parts
np.flatnonzero([0,0,100,200])
# [2, 3]

MADDPG full code

"""The two-step game from QMIX: https://arxiv.org/pdf/1803.11485.pdf

Configurations you can try:
    - normal policy gradients (PG)
    - contrib/MADDPG
    - QMIX

See also: centralized_critic.py for centralized critic PPO on this game.
"""
import argparse
from gym.spaces import Tuple, MultiDiscrete, Dict, Discrete
import os

import ray
from ray import tune
from ray.tune import register_env, grid_search
from ray.rllib.env.multi_agent_env import ENV_STATE
from ray.rllib.examples.env.two_step_game import TwoStepGame
from ray.rllib.utils.test_utils import check_learning_achieved

parser = argparse.ArgumentParser()
parser.add_argument("--num-cpus", type=int, default=0)
parser.add_argument("--as-test", action="store_true")
parser.add_argument("--torch", action="store_true")
parser.add_argument("--stop-reward", type=float, default=7.0)
parser.add_argument("--stop-timesteps", type=int, default=50000)

if __name__ == "__main__":
    args = parser.parse_args()
    config = {
        "learning_starts": 100,
        "env_config": {
            "actions_are_logits": True,
        },
        "multiagent": {
            "policies": {
                "pol1": (None, Discrete(6), TwoStepGame.action_space, {"agent_id": 0}),
                "pol2": (None, Discrete(6), TwoStepGame.action_space, {"agent_id": 1}),
            },
            "policy_mapping_fn": lambda x: "pol1" if x == 0 else "pol2",
        },
        "framework": "torch" if args.torch else "tf",
        # Use GPUs iff `RLLIB_NUM_GPUS` env var set to > 0.
        "num_gpus": int(os.environ.get("RLLIB_NUM_GPUS", "0")),
    }


    # === setup ===
    ray.init(num_cpus=args.num_cpus or None)
    stop = {
        "episode_reward_mean": args.stop_reward,
        "timesteps_total": args.stop_timesteps,
    }
    config = dict(config, **{"env": TwoStepGame})

    # === train === 
    results = tune.run("contrib/MADDPG", stop=stop, config=config, verbose=1)
    if args.as_test:
        check_learning_achieved(results, args.stop_reward)

    ray.shutdown()