ノート

強化学習関連のこと

MENU

【強化学習】ε-greedyアルゴリズムでバンディット問題を解く【2】

進捗2

ε-greedy手法で バンディット問題を解いてみた。 (バンディット問題といってもシンプルなやつです)

前回

www.tcom242242.net

目的

ε-greedy行動選択を実装して試したい

ちなみにε-greedy行動選択については以下を参照

進捗

  • ε-greedy行動選択を行いながら、学習行動
  • シンプルな強化学習エージェントの実装
  • ε-greedyの実装

結果

かるーく実験してみました。 探索率を小さくしてるんで(0.001)にしてるんで、以下のようになりました。

f:id:ttt242242:20180531213520p:plain

もうちょい問題を難しくしていろいろ実験したいです

プログラム

ファイル構成

├── agents
│   ├── policy.py
│   └── simple_rl_agent.py
├── envs
│   └── multi_arm_bandit.py
└── example
     └── run-multi-arm-bandit-eps-greedy.py

実験用プログラム(run-multi-arm-bandit-eps-greedy.py)

import os,sys
sys.path.append(os.getcwd())
import random
import numpy as np
import matplotlib.pyplot as plt
from agents.simple_rl_agent import SimpleRLAgent
from agents.policy import EpsGreedyQPolicy
from envs.multi_arm_bandit import MultiArmBandit

if __name__ == '__main__':
    nb_arm=5    # armの数
    game = MultiArmBandit(nb_arm=nb_arm) # 5本のアームを設定
    policy = EpsGreedyQPolicy(epsilon=0.001)    # exploration rate を0.001に設定
    agent = SimpleRLAgent(alpha=0.1, policy=policy, action_list=np.arange(nb_arm))  # agentの設定
    nb_step = 10000   #ステップ数
    rewards = []
    for step in range(nb_step):
        action = agent.act()    # レバーの選択
        reward = game.step(action) # レバーを引く
        rewards.append(reward) 
        agent.get_reward(reward) # エージェントは報酬を受け取り学習

    plt.plot(np.arange(nb_step), rewards)
    plt.ylim(0, 1)
    plt.ylabel("reward")
    plt.xlabel("steps")
    plt.savefig("fig/result2.png")
    plt.show()

マルチアームバンディットプログラム(multi_arm_bandit.py)

import random
import numpy as np
import matplotlib.pyplot as plt

class Arm():
    def __init__(self, idx):
        self.value = random.random()    # ランダムでこのアームを引いた時の報酬を設定

    def pull(self):
        return self.value

class MultiArmBandit():
    def __init__(self, nb_arm):
        self.arms = self._init_arms(nb_arm)

    def _init_arms(self, nb_arm):
        arms = []
        for i in range(nb_arm):
            arms.append(Arm(i))

        return arms

    def step(self, arm_id):
        """
            pull lever 
        """
        return self.arms[arm_id].pull()

if __name__ == '__main__':
    game = MultiArmBandit(nb_arm=5) # 5本のアームを設定
    nb_step = 100   #ステップ数
    rewards = []
    for step in range(nb_step):
        reward = game.step(random.randint(0, 4))
        rewards.append(reward)

    plt.plot(np.arange(nb_step), rewards)
    plt.ylim(0, 1)
    plt.savefig("result1.png")

エージェントプログラム(simple_rl_agent.py)

from abc import ABCMeta, abstractmethod
import numpy as np
import ipdb

class Agent(metaclass=ABCMeta):
    """Abstract Agent Class"""

    def __init__(self, alpha=None, policy=None):
        """
        :param alpha:
        :param policy:
        """
        self.alpha = alpha
        self.policy = policy
        self.reward_history = []

    @abstractmethod
    def act(self):
        pass

    @abstractmethod
    def get_reward(self, reward):
        pass


class SimpleRLAgent(Agent):
    """
        シンプルな強化学習エージェント
    """
    def __init__(self, action_list=None, **kwargs):
        """
        :param action_list:
        :param q_values:
        :param kwargs:
        """
        super().__init__(**kwargs)
        self.action_list = action_list  # 選択肢
        self.last_action_id = None
        self.q_values = self._init_q_values()   # 期待報酬値の初期化

    def _init_q_values(self):
        q_values = {}
        q_values = np.repeat(0.0, len(self.action_list))
        return q_values

    def act(self, q_values=None):
        action_id = self.policy.select_action(self.q_values)    # 行動選択
        self.last_action_id = action_id
        action = self.action_list[action_id]
        return action

    def get_reward(self, reward):
        self.reward_history.append(reward)
        self.q_values[self.last_action_id] = self._update_q_value(reward)   # 期待報酬値の更新

    def _update_q_value(self, reward):
        return ((1.0 - self.alpha) * self.q_values[self.last_action_id]) + (self.alpha * reward) # 通常の指数移動平均で更新

行動選択用プログラム(policy.py)

import copy
import numpy as np
import ipdb
from abc import ABCMeta, abstractmethod

class Policy(metaclass=ABCMeta):

    @abstractmethod
    def select_action(self, **kwargs):
        pass

class EpsGreedyQPolicy(Policy):
    """
        ε-greedy選択 
    """
    def __init__(self, epsilon=.1, decay_rate=1):
        super(EpsGreedyQPolicy, self).__init__()
        self.epsilon = epsilon
        self.decay_rate = decay_rate

    def select_action(self, q_values):
        assert q_values.ndim == 1
        nb_actions = q_values.shape[0]

        if np.random.uniform() < self.epsilon:  # random行動
            action = np.random.random_integers(0, nb_actions-1)
        else:   # greedy 行動
            action = np.argmax(q_values)

        return action

    def decay_epsilon():    # 探索率を減少
        self.epsilon = self.epsilon*self.decay_rate