Ejemplo n.º 1
0
def update_self_PPO_list(
    r_q: Deque[float],
    o_q: Deque[np.ndarray],
    a_q: Deque[int],
    v_q: Deque[float],
    p_q: Deque[np.ndarray],
    d_q: Deque[float],
    gae_param: np.ndarray,
    train_data: TrainData,
) -> None:
    """

    Args:
        r_q (Deque): 時系列順に取得したリワードが格納されているキュー
        o_q (Deque): 時系列順にゲームの状態が格納されているキュー
        a_q (Deque): 時系列順に選択した行動が格納されているキュー
        v_q (Deque): 時系列順に算出されたバリューが格納されているキュー
        p_q (Deque): 時系列順に算出された確率ベクトルが格納されているキュー
        d_q (Deque): 時系列順にδが格納されているキュー
        gae_param (np.ndarray): GAE算出に使用するパラメータ
        train_data (TrainData): トレーニングデータが格納されているオブジェクト
    """
    r_q.popleft()

    o = o_q.popleft()
    a = action2int(a_q.popleft())
    v = v_q.popleft()
    p = p_q.popleft()
    gae = calc_gae(d_q, gae_param)
    d_q.popleft()

    update_PPO_list(train_data, [o], [a], [gae], [v], [p], [False])
Ejemplo n.º 2
0
 def step(
     self,
     obs: List[Observation],
     masked_flg: bool = False,
     before_done_list: List[bool] = None,
 ) -> Tuple[List[Action], np.ndarray, np.ndarray]:
     prob_list, value_list = self._model(np.array(obs))
     prob_list = prob_list.numpy()
     value_list = value_list.numpy()
     if masked_flg and self._last_action is not None:
         mask_action_index = [
             self._mask_action(action2int(action)) for action in self._last_action
         ]
         mask_action_one_hot = np.identity(len(ACTIONLIST))[mask_action_index]
         # 前回の行動を0、それ以外を1にする
         mask_action_one_hot = (
             mask_action_one_hot.T * (1 - np.array(before_done_list))
         ).T * -1 + 1
         # masking
         masked_prob_list = (prob_list + EPS) * mask_action_one_hot
         sum_prob_list = np.sum(masked_prob_list, axis=1)
         next_action_list = [
             np.random.choice(ACTIONLIST, p=prob / sum_prob)
             for prob, sum_prob in zip(masked_prob_list, sum_prob_list)
         ]
     else:
         next_action_list = [
             np.random.choice(ACTIONLIST, p=prob) for prob in prob_list
         ]
     self._last_action = next_action_list
     return next_action_list, value_list, prob_list
Ejemplo n.º 3
0
def create_padding_data(
    ppo_parameter: PPOParameter,
    train_data: TrainData,
    obs_q: Deque[np.ndarray],
    action_q: Deque[Action],
    reward_q: Deque[float],
    delta_q: Deque[float],
    value_q: Deque[float],
    prob_q: Deque[np.ndarray],
) -> None:
    """終了したゲームのデータに対して、n回分パディングしてトレーニングデータを作成する

    Args:
        ppo_parameter (PPOParameter): パラメータが格納されているオブジェクト
        train_data (TrainData): トレーニングデータが格納されているオブジェクト
        obs_q (Deque): 時系列順にゲームの各状態が格納されているキュー
        action_q (Deque): 時系列順にとった行動が格納されているキュー
        reward_q (Deque): 時系列順に取得したリワードが格納されているキュー
        delta_q (Deque): 時系列順に算出されたδが格納されているキュー
        value_q (Deque): 時系列順に算出されたバリューが格納されているキュー
        prob_q (Deque): 時系列順に算出された確率ベクトルが格納されているキュー

    Raises:
        ValueError: 渡した各キューの長さが異なっている場合、エラーとする
    """

    if (len(obs_q) != len(action_q) or len(obs_q) != len(value_q)
            or len(obs_q) != len(prob_q) or len(obs_q) != len(delta_q) + 1):
        raise ValueError("引数のQueueの長さがマッチしません。")

    add_delta(delta_q, reward_q[-1], value_q[-1], 0.0, ppo_parameter.gamma)
    if len(delta_q) != ppo_parameter.num_step:
        target_delta_q = copy.deepcopy(delta_q)
        while len(target_delta_q) != ppo_parameter.num_step:
            target_delta_q.append(0.0)
    else:
        target_delta_q = delta_q

    for _ in range(len(obs_q)):
        obs = obs_q.popleft()
        action = action2int(action_q.popleft())
        gae = calc_gae(target_delta_q, ppo_parameter.gae_param)
        target_delta_q.popleft()
        target_delta_q.append(0)
        value = value_q.popleft()
        prob = prob_q.popleft()
        update_PPO_list(train_data, [obs], [action], [gae], [value], [prob],
                        [False])

    # ダミーデータの投入
    obs_q.append(obs)
    action_q.append(ACTIONLIST[0])
    value_q.append(value)
    prob_q.append(prob_q)

    # ゴミ捨て
    delta_q.popleft()
Ejemplo n.º 4
0
    def step(
        self, actions: List[Action]
    ) -> Tuple[List[Observation], List[Reward], List[bool]]:
        # 今回死ぬGooseを判定するために、1個前のStateですでに死んでいるかどうかを保持
        pre_done = np.array([
            self._dena_env.env.state[p]["status"] != "ACTIVE"
            for p in range(NUM_GEESE)
        ])
        actions = {p: action2int(actions[p]) for p in range(NUM_GEESE)}
        # Envを次の状態へ遷移させる
        self._dena_env.step(actions)

        # Gooseごとの終了判定
        done: np.ndarray = np.array(
            [
                self._dena_env.env.state[p]["status"] != "ACTIVE"
                for p in range(NUM_GEESE)
            ],
            dtype=np.float,
        )

        # Envの報酬
        env_reward = [
            self._dena_env.env.state[p]["reward"] for p in range(len(actions))
        ]

        # 報酬関数の適用
        raw_reward = self._compute_reward(env_reward)

        if self._press_flg:
            raw_reward = list(
                map(lambda x: (x / self._max_reward_value - 0.5) * 2,
                    raw_reward))

        if self._scale_flg:
            raw_reward = self._update_reward(raw_reward, done, pre_done)

        # 前回生きていて(1 - pre_done)今回死んだ(done)GooseにのみRewardをリターン
        reward: list = ((1 - pre_done) * done * raw_reward).tolist()

        # 全Geeseが終了したらリセット
        if sum(map(int, done)) == NUM_GEESE:
            self._dena_env.reset()

        # Gooseごとの観測
        observation = [self._dena_env.observation(p) for p in range(NUM_GEESE)]
        done = done.astype(np.bool).tolist()
        return observation, reward, done
    def train(self) -> None:
        today = datetime.datetime.now().strftime("%Y-%m-%d_%H%M%S")
        logger = TensorBoardLogger(f"{LOG_BASE_DIR}/{today}")

        train_data = TrainData()
        ppo_trainer = PPOTrainer(self._ppo_parameter.ppo_trainer_parameter,
                                 logger)
        vec_env = VecEnv(self._ppo_parameter.num_parallels,
                         self._ppo_parameter.env_parameter)
        agent = self._agent

        obs_list = vec_env.reset()

        obs_q_list = create_que_list(self._ppo_parameter.num_parallels,
                                     NUM_GEESE)
        reward_q_list = create_que_list(self._ppo_parameter.num_parallels,
                                        NUM_GEESE)
        action_q_list = create_que_list(self._ppo_parameter.num_parallels,
                                        NUM_GEESE)
        value_q_list = create_que_list(self._ppo_parameter.num_parallels,
                                       NUM_GEESE)
        prob_q_list = create_que_list(self._ppo_parameter.num_parallels,
                                      NUM_GEESE)
        delta_q_list = create_que_list(self._ppo_parameter.num_parallels,
                                       NUM_GEESE)

        step = 1
        before_done_list = [[False] * NUM_GEESE
                            ] * self._ppo_parameter.num_parallels
        before_game_done_list = [True] * self._ppo_parameter.num_parallels
        value_o_list = []
        reward_o_list = []
        while True:
            action_list, value_n_list, prob_list = reshape_step_list(
                *agent.step(list(chain.from_iterable(obs_list))))

            next_obs_list, reward_list, done_list = vec_env.step(action_list)

            game_done_list = [sum(done) == NUM_GEESE for done in done_list]

            for i, (reward_q,
                    value_q) in enumerate(zip(reward_q_list, value_q_list)):

                if not before_game_done_list[i]:
                    add_delta_list(
                        delta_q_list[i],
                        reward_o_list[i],
                        value_o_list[i],
                        value_n_list[i],
                        self._ppo_parameter.gamma,
                    )

                # n回経つとGAEの計算が可能
                # →それ以降は毎回データを格納していく
                if len(reward_q_list[i][0]) == self._ppo_parameter.num_step:
                    [r_q.popleft() for r_q in reward_q]

                    o = [o_q.popleft() for o_q in obs_q_list[i]]
                    a = [action2int(a_q.popleft()) for a_q in action_q_list[i]]
                    v = [v_q.popleft() for v_q in value_q]
                    p = [p_q.popleft() for p_q in prob_q_list[i]]

                    gae = calc_gae_list(delta_q_list[i],
                                        self._ppo_parameter.gae_param)
                    [d_q.popleft() for d_q in delta_q_list[i]]

                    update_PPO_list(train_data, o, a, gae, v, p,
                                    before_done_list[i])

            # n回分の行動をキューで管理
            add_to_que_list(obs_q_list, obs_list)
            add_to_que_list(action_q_list, action_list)
            add_to_que_list(value_q_list, value_n_list)
            add_to_que_list(reward_q_list, reward_list)
            add_to_que_list(prob_q_list, prob_list)

            for i, (reward_q,
                    value_q) in enumerate(zip(reward_q_list, value_q_list)):

                # 今回終了したアクションに対してパディングを行ってデータを格納する
                [
                    create_padding_data(
                        self._ppo_parameter,
                        train_data,
                        obs_q_list[i][j],
                        action_q_list[i][j],
                        reward_q[j],
                        delta_q_list[i][j],
                        value_q_list[i][j],
                        prob_q_list[i][j],
                    ) for j, (done, before_done) in enumerate(
                        zip(done_list[i], before_done_list[i]))
                    if done != before_done
                ]

                if game_done_list[i]:
                    # queのリセット
                    obs_q_list[i] = reset_que(NUM_GEESE)
                    action_q_list[i] = reset_que(NUM_GEESE)
                    reward_q_list[i] = reset_que(NUM_GEESE)
                    value_q_list[i] = reset_que(NUM_GEESE)
                    prob_q_list[i] = reset_que(NUM_GEESE)
                    delta_q_list[i] = reset_que(NUM_GEESE)
                    before_done_list[i] = [False] * NUM_GEESE
                else:
                    before_done_list[i] = done_list[i]

            if len(train_data.obs_list) > self._ppo_parameter.num_sample_size:
                ppo_sample = PPOSample(
                    np.array(train_data.obs_list),
                    np.array(train_data.action_list),
                    np.array(train_data.gae_list),
                    np.array(train_data.v_list),
                    np.array(train_data.pi_list),
                )
                ppo_trainer.train(agent.model, ppo_sample)

                # trainに投げたデータ全削除
                reset_train_data(train_data)
            before_game_done_list = game_done_list
            value_o_list = value_n_list
            reward_o_list = reward_list
            obs_list = next_obs_list
            step += 1
            # Save
            if (step % self._ppo_parameter.save_freq == 0
                    and self._ppo_parameter.save_dir is not None):
                save_dir = Path(self._ppo_parameter.save_dir).joinpath(
                    str(step))
                self._agent.save(str(save_dir))