強化学習/Pythonで強化学習する のバックアップの現在との差分(No.1)


  • 追加された行はこの色です。
  • 削除された行はこの色です。
#freeze
*はじめに [#l524e399]

ここでは、Pythonで強化学習を行います。

例題として、Sutton & Barto の『エージェント・アプローチ人工知能』で用いられている [math]4 \times 3[/math] の迷路を使います。
#ref(./maze.png,nolink,25%)
Sのマスが初期状態、+1 と -1 のマスが終端状態です。

行動は東西南北の4種類です。

外側と塗られているマスには壁があり、その方向には進めません。
0.8の確率で選んだ方向に進むことができ、0.1の確率で選んだ方向に対して90度左のマス、0.1の確率でその反対側のマスに進みます。

数値が書かれているマスに到達するとその数値が報酬として得られます。
その他のマスに到達すると報酬 -0.02 が得られます。


強化学習アルゴリズムはQ学習、行動選択は[math]\epsilon[/math]-グリーディーです。

次の環境で確認しました。
-macOS Sierra 10.12.5
-Python 3.5.1


*準備 [#t9a5a07c]

NumPyを使いますので、インストールします。

まず、pip3をインストールし、最新版にします。
#geshi(sh){{
$ sudo easy_install pip
$ sudo pip3 install --upgrade pip
}}

次に、pip3でNumPyをインストールします。
#geshi(sh){{
$ sudo pip3 install numpy
}}



*クラス構造 [#we2a4a0c]

強化学習の枠組みでは、学習エージェントが環境から状態を観測し、それに基づいて行動を選択し、実行します。
すると、環境の状態が変化し、次の状態と報酬が観測できます。
これを繰り返します。
-環境を表す Environment
--迷路を表す Maze
-強化学習エージェントを表す ReinformentLearningAgent
--Q学習エージェントを表す QLearningAgent

そこで、強化学習エージェントを表す ReinforcementLearningAgent と環境を表す Environment クラスを用意します。

また、Q学習エージェントを表す QLearningAgent を用意し、ReinforcementLearningAgent クラスのの子クラスとします。

同様に、迷路を表す Maze クラスを用意し、Environment クラスの子クラスとします。


*Q学習エージェント qlagent.py [#m72d7cc6]

Q学習エージェントを表す QLearningAgent クラスには、Q学習のアルゴリズムだけを実装します。

Q学習のアルゴリズムは、次のようなものです。
+行動価値 [math]Q(s, a)[/math] を初期化
+エピソードごとに繰り返し:
++状態 [math]s[/math] を初期化
++[math]s[/math] が終端状態になるまで繰り返し:
+++[math]Q[/math]から導かれる行動選択確率に基づいて [math]s[/math] から行動 [math]a[/math] を選択
+++[math]a[/math] を実行し、次の状態 [math]s'[/math] と報酬 [math]r[/math] を観測する
+++[math]Q(s, a) \leftarrow Q(s, a) + \alpha \left[ r + \gamma * \max_{a'}Q(s', a') - Q(s, a)\right][/math]
+++[math]s \leftarrow s'[/math]

これを、Pythonで実装すると、次のようになります。

#ref(./qlagent.py)
#geshi(python){{
#!/usr/bin/env python3
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# qlagent.py
#
# Copyright 2017 Tohgoroh Matsui All Rights Reserved.
# Copyright 2017-2018 Tohgoroh Matsui All Rights Reserved.
#
import rlagent
import environment as env
from rlagent import ReinforcementLearningAgent
import numpy as np


class QLearningAgent(rlagent.ReinforcementLearningAgent):
  # 学習する
  def learn(self):
    gamma = self.discountRate   # 割引率
    alpha = self.stepSize       # ステップ・サイズ
class QLearningAgent(ReinforcementLearningAgent):
    """Q学習エージェント。"""

    episodes = 0
    self.aQ = np.zeros([self.env.states, self.env.actions])       # Q値をゼロに初期化する
    while episodes < self.episodes:
      steps = 0
      s = self.env.initState()                                                  # 状態 s を初期化する
      while not self.env.isTerminal(s):                                         # 状態 s が終端状態になるまで繰り返す:
        a = self.epsilonGreedy(s)                                                 # Q値と状態 s から行動 a を選択する
        s_, r = self.env.takeAction(s, a)                                         # 行動 a を実行し、次の状態 s_ と報酬 r を観測する
        # self.env.printLog(steps, s, a, r)                                       # ログを出力する
        a_ = self.greedy(s_)                                                      # 次の状態 s_ でQ値が最大の行動を調べる
        self.aQ[s, a] += alpha * (r + gamma * self.aQ[s_, a_] - self.aQ[s, a])    # Q値を更新する
        s = s_                                                                    # 状態を更新する
        steps += 1
      episodes += 1
    print(self.aQ)
    def learn(self):
        """Q学習を用いて学習する。"""
        env = self.environment  # 環境
        gamma = self.discount_rate  # 割引率
        alpha = self.step_size  # ステップ・サイズ
        episodes = 0    # エピソード数
        total_steps = 0 # 全ステップ数
        self.q = np.zeros([env.states, env.actions])    # Q値をゼロに初期化する
        while total_steps < self.max_steps:
            steps = 0   # このエピソードにおけるステップ数
            state = env.init_state()    # 状態を初期化する
            while total_steps < self.max_steps and not env.is_terminal(state):  # 終端状態になるまで繰り返す:
                action = self.epsilon_greedy(state) # 行動を選択する
                reward , state_ = env.take_action(state, action) # 行動を実行し、次の状態と報酬を観測する
                if self.verbose_level > 1:
                    env.print_log(steps, state, action, reward, state_) # ログを出力する
                action_ = self.greedy(state_)   # 次の状態でQ値が最大の行動を調べる
                s, a, = env.get_s(state), env.get_a(action)
                s_, a_ = env.get_s(state_), env.get_a(action_)
                self.q[s, a] += alpha * (reward + gamma * self.q[s_, a_] - self.q[s, a])    # Q値を更新する
                state = state_  # 状態を更新する
                steps += 1
                total_steps += 1
                if self.evaluation and total_steps % np.power(10, np.floor(np.log10(total_steps))) == 0:
                    eval = self.evaluate()  # 評価する
                    print('%d, %f' % (total_steps, eval))
            episodes += 1
        if self.verbose_level > 0:
            print(self.q)   # Q値を出力


  # コンストラクター
  def __init__(self, seed=0, discountRate=0.9, stepSize=0.1, epsilon=0.1, episodes=10000):
    super().__init__(seed, discountRate, stepSize, epsilon, episodes)
    def __init__(self, environment=None, seed=None, discount_rate=0.9, step_size=0.1, epsilon=0.1, max_steps=1000000, evaluation=True, verbose_level=0):
        super().__init__(environment, seed, discount_rate, step_size, epsilon, max_steps, evaluation, verbose_level)
}}

ステップ数を数えたり、学習した方策を評価する部分がありますので、アルゴリズムよりは長くなっていますが、基本的にはQ学習のままです。

ここで呼び出しているメソッドは、親クラスの ReinforcementLearningAgent に実装されています。

迷路の問題を解くだけならもう少しシンプルに書くことができますが、[[LEGO MINDSTOMS EV3でも動く>強化学習/LEGO MINDSTORMS EV3で強化学習する]]ように作ってあるので、少し大げさなプログラムになっています。


*強化学習エージェント rlagent.py [#qdcfcadd]

強化学習エージェントを表す ReinforcementLearningAgent クラスには、どの強化学習アルゴリムにも共通する行動選択と評価を実装します。


#ref(./rlagent.py)
#geshi(python){{
#!/usr/bin/env python3
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# rlagent.py
#
# Copyright 2017 Tohgoroh Matsui All Rights Reserved.
# Copyright 2017-2018 Tohgoroh Matsui All Rights Reserved.
#
from abc import ABCMeta, abstractmethod
import environment as env
import numpy as np


class ReinforcementLearningAgent(metaclass=ABCMeta):
  @abstractmethod
  def learn():
    pass
    """強化学習エージェント。"""

    @abstractmethod
    def learn(self):
        """強化学習を用いて学習する。"""
        pass

  # 一様ランダム選択
  def uniformly(self):
    a = np.random.randint(self.env.actions)     # 0からaction-1までの整数をランダムに生成する
    return a                                    # 生成した行動を返す
    def evaluate(self):
        """学習した行動価値が最も高い行動を選択したときの平均ステップ数を返す。"""
        env = self.environment  # 環境
        episodes = 0    # エピソード数
        total_steps = 0  # ステップ数
        while episodes < 100:   # 100エピソード繰り返す:
            steps = 0   # このエピソードにおけるステップ数
            state = env.init_state() # 状態を初期化する            state = self.getState(rawState) # 状態を状態番号に
            while not env.is_terminal(state) and steps < 100:   # 状態が終端状態になるか、または、100ステップになるまで繰り返す:
                action = self.greedy(state)  # グリーディーに行動を選択する
                reward, state_ = env.take_action(state, action) # 行動を実行し、報酬と次の状態を観測する
                if self.verbose_level > 2:
                    env.printLog(steps, state, action, reward, state_)  # ログを出力する
                state = state_
                steps += 1
                total_steps += 1
            episodes += 1
        return total_steps / 100

    def uniformly(self):
        """一様ランダムに行動を選択して返す。"""
        action = np.random.randint(self.environment.actions)    # 0からaction-1までの整数をランダムに生成する
        return action

  # グリーディー選択
  #   s:  状態
  def greedy(self, s):
    maxQ     = float('-inf')                    # 最大のQ値
    maxA     = -1                               # 最大のQ値を持つ行動
    for a in range(self.env.actions):           # すべての行動 a について繰り返し:
      if self.aQ[s, a] > maxQ:                    # Q値がこれまでの最大のQ値よりも大きいなら:
        maxQ     =  self.aQ[s, a]                 # 最大のQ値を更新する
        maxA     =  a                             # 最大のQ値を持つ行動を更新する
    # 最大のQ値を持つ行動が複数ある場合、その中から一様ランダムに選択する
    aMaxId = np.where(self.aQ[s] == maxQ)[0]    # Q値がmaxQである要素のインデックスの配列
    if len(aMaxId) > 1:                         # Q値がmaxQである要素が複数あるなら
      r = np.random.randint(len(aMaxId))          # 0から要素数-1までの整数をランダムに生成する
      maxA = aMaxId[r]                            # Q値がmaxQである要素のインデックスから行動を選択する
    return maxA                                 # 最大のQ値を持つ行動を返す
    def greedy(self, state):
        """グリーディーに行動を選択して返す。"""
        s = self.environment.get_s(state)   # 状態番号
        max = self.q[s].max()   # 最大のQ値
        aIds = np.where(self.q[s] == max)[0]    # Q値がmaxである要素のインデックスの配列
        r = np.random.randint(len(aIds))    # 0から要素数-1までの整数をランダムに生成する
        action = aIds[r]    # Q値がmaxQである要素のインデックスから行動を選択する
        return action

    def epsilon_greedy(self, state):
        """ε-グリーディー選択を用いて行動を選択して返す。"""
        r = np.random.rand()    # 乱数を生成する
        action = self.uniformly() if  r < self.epsilon else self.greedy(state)  # 確率εで一様ランダムに、確率1-εでグリーディーに行動を選択する
        return action

  # ε-グリーディー選択
  #   aQ: Q値
  #   s:  状態
  def epsilonGreedy(self, s):
    r = np.random.rand()          # 乱数を生成する
    if r < self.epsilon:          # 確率εで:
      a = self.uniformly()          # 一様ランダムに行動を選択する
    else:                         # 確率1-εで:
      a = self.greedy(s)            # グリーディーに行動を選択する
    return a                      # 選択した行動を返す
    def __init__(self, environment=None, seed=None, discount_rate=0.9, step_size = 0.1, epsilon=0.1, max_steps=1000000, evaluation=True, verbose_level=0):
        self.environment = environment  # 環境
        self.seed = seed    # 乱数のシード
        self.discount_rate = discount_rate  # 割引率 γ
        self.step_size = step_size  # ステップ・サイズ α
        self.epsilon = epsilon  # ε-グリーディー選択のε
        self.max_steps = max_steps  # 最大ステップ数
        self.evaluation = evaluation    # 評価
        self.verbose_level = verbose_level  # ログ出力
        self.env = None # 環境
        self.q = None   # Q値
        if self.seed is not None:
            np.random.seed(seed)
}}


  # 環境をセットする
  #   env: 環境
  def setEnvironment(self, env):
    self.env = env
*環境 environment.py [#y715bf52]

まず初めに、環境を表すクラスがどのような変数とメソッドを持っているかを決めておきます。

  # コンストラクター
  def __init__(self, seed=0, discountRate=0.9, stepSize = 0.1, epsilon=0.1, episodes=10000):
    np.random.seed(seed)
    self.discountRate = discountRate    # 割引率 γ
    self.stepSize     = stepSize        # ステップ・サイズ α
    self.epsilon      = epsilon         # ε-グリーディー選択のε
    self.episodes     = episodes        # 最大エピソード数
    self.aQ           = None            # Q値
}}
変数としては、次のものを持つことにします。
-状態数 states
-行動数 actions

メソッドしては、次のものを持つことにします。
-状態を初期化して返す initState
-終端状態かどうかを調べる isTerminal
-報酬を返す getReward
-行動を実行して次の状態と報酬を返す takeAction
-状態を文字列で返す strState
-行動を文字列で返す strAction
-ログを出力する printLog

*環境 environment.py [#y715bf52]
printLog 以外の実際の実装は、子クラスで行います。


#ref(./environment.py)
#geshi(python){{
#!/usr/bin/env python3
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# environment.py
#
# Copyright 2017 Tohgoroh Matsui All Rights Reserved.
# Copyright 2017-2018 Tohgoroh Matsui All Rights Reserved.
#
from abc import ABCMeta, abstractmethod


class Environment(metaclass=ABCMeta):
  @abstractmethod
  def initState(self):
    pass
    """強化学習の環境。"""

  @abstractmethod
  def isTerminal(self, s):
    pass
    states = None   # 状態数
    actions = None  # 行動数

  @abstractmethod
  def getState(self):
    pass
    @classmethod
    @abstractmethod
    def init_state(cls):
        """初期状態を返す。"""
        pass

  @abstractmethod
  def getReward(self, s):
    pass
    @classmethod
    @abstractmethod
    def is_terminal(cls):
        """終端状態ならTrue、そうでないならFalseを返す。"""
        pass

  @abstractmethod
  def takeAction(self, s, a):
    pass
    @classmethod
    @abstractmethod
    def get_reward(cls, state):
        """報酬を返す。"""
        pass

  @abstractmethod
  def strState(self, s):
    pass
    @classmethod
    @abstractmethod
    def take_action(cls, state, action):
        """行動を実行して状態を更新し、報酬と次の状態を返す。"""
        pass

  @abstractmethod
  def strAction(self, a):
    pass
    @classmethod
    @abstractmethod
    def str_state(cls, state):
        """状態を表す文字列を返す。"""
        pass

    @classmethod
    @abstractmethod
    def str_action(cls, action):
        """行動を表す文字列を返す。"""
        pass

  # ログを出力する
  def printLog(self, steps, s, a, r):
    print('%d: %s, %s, %f' % (steps, self.strState(s), self.strAction(a), r))
    @classmethod
    def print_log(cls, steps, state, action, reward, state_):
        """ログを出力する。"""
        print('# %d, %s, %s, %f, %s' % (steps, cls.str_state(state), cls.str_action(action), reward, cls.str_state(state_)))
}}


*迷路 maze.py [#se58b5a5]
#geshi(python){{
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# maze.py
#
# Copyright 2017 Tohgoroh Matsui All Rights Reserved.
#
import environment as env
import numpy as np

class Maze(env.Environment):
  # 壁
  walls = np.array([[0, 0, 0, 0],
                    [0, 1, 0, 0],
                    [0, 0, 0, 0]]).T

  # 終端状態
  terminals = np.array([[0, 0, 0, 1],
                        [0, 0, 0, 1],
                        [0, 0, 0, 0]]).T

  # 報酬
  rewards = np.array([[-0.02, -0.02, -0.02,  1.  ],
                      [-0.02,     0, -0.02, -1.  ],
                      [-0.02, -0.02, -0.02, -0.02]]).T


  # 状態を初期化する
  def initState(self):
    s = self.coordinate2state(0, 2)
    self.state = s
    return s


  # 終端状態ならTrue、そうでないならFalseを返す
  #   s: 状態
  def isTerminal(self, s):
    x, y = self.state2coodinate(s)
    if self.terminals[x, y] == 1:
      return True
    else:
      return False


  # 北に進む
  #   s: 状態
  def north(self, s):
    x_, y_ = self.state2coodinate(s)
    if y_ > 0 and self.walls[x_, y_ - 1] == 0:
      y_ -= 1
    s_ = self.coordinate2state(x_, y_)
    return s_
*迷路 maze.py [#se58b5a5]

#ref(./maze.py)
#geshi(python){{
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# maze.py
#
# Copyright 2017-2018 Tohgoroh Matsui All Rights Reserved.
#
from environment import Environment
import numpy as np

  # 東に進む
  #   s: 状態
  def east(self, s):
    x_, y_ = self.state2coodinate(s)
    if x_ < 3 and self.walls[x_ + 1, y_] == 0:
      x_ += 1
    s_ = self.coordinate2state(x_, y_)
    return s_

class Maze(Environment):
    """Sutton & Barto 4x3迷路問題。状態は (x座標, y座標) で表される。"""

  # 西に進む
  #   s: 状態
  def west(self, s):
    x_, y_ = self.state2coodinate(s)
    if x_ > 0 and self.walls[x_ - 1, y_] == 0:
      x_ -= 1
    s_ = self.coordinate2state(x_, y_)
    return s_
    walls = np.array([[0, 0, 0, 0],
                      [0, 1, 0, 0],
                      [0, 0, 0, 0]]).T  # 壁
    terminals = np.array([[ 0, 0, 0, 1],
                          [ 0, 0, 0, 1],
                          [ 0, 0, 0, 0]]).T # 終端状態
#    rewards = np.array([[-0.02, -0.02, -0.02,  1.],
#                        [-0.02,  0.,   -0.02, -1.],
#                        [-0.02, -0.02, -0.02, -0.02]]).T    # 報酬
    rewards = np.array([[0., 0., 0.,  1.],
                        [0., 0., 0., -1.],
                        [0., 0., 0.,  0.]]).T    # 報酬
    width = len(walls)  # 迷路の幅
    height = len(walls[0])   # 迷路の高さ
    states = width * height   # 状態数
    actions = 4   # 行動数
    deterministic = True # 状態遷移が決定的

    @classmethod
    def init_state(cls):
        """初期状態を返す。"""
        return (0, 2)

  # 南に進む
  #   s: 状態
  def south(self, s):
    x_, y_ = self.state2coodinate(s)
    if y_ < 2 and self.walls[x_, y_ + 1] == 0:
      y_ += 1
    s_ = self.coordinate2state(x_, y_)
    return s_
    @classmethod
    def is_terminal(cls, state):
        """渡された状態が終端状態ならTrue, そうでないならFalseを返す。"""
        x, y = state[0], state[1]
        return True if cls.terminals[x, y] == 1 else False

    @classmethod
    def is_wall(cls, state):
        """渡された状態が壁ならTrue, そうでないならFalseを返す。"""
        x, y = state[0], state[1]
        return True if x < 0 or x >= cls.width or y < 0 or y >= cls.height or cls.walls[x, y] == 1 else False

  # 座標から状態に変換する
  #   x: x座標
  #   y: y座標
  def coordinate2state(self, x, y):
    s = y * self.height + x
    return s
    @classmethod
    def get_s(cls, state):
        """状態を状態番号に変換して返す。"""
        x, y = state[0], state[1]
        s = y * cls.width + x
        return s

    @classmethod
    def get_a(cls, action):
        """行動を行動番号に変換して返す。"""
        return action

  # 状態から座標に変換する
  #   s: 状態
  def state2coodinate(self, s):
    x = s % self.height
    y = s // self.height
    return x, y
    @classmethod
    def get_reward(cls, state):
        """報酬を返す。"""
        x, y = state[0], state[1]
        reward = cls.rewards[x, y]
        return reward

    @classmethod
    def take_action(cls, state, action):
        """行動を実行して状態を更新し、報酬と次の状態を返す。"""
        if action == 0:
            forward = cls.north(state)
            left = cls.west(state)
            right = cls.east(state)
        elif action == 1:
            forward = cls.east(state)
            left = cls.north(state)
            right = cls.south(state)
        elif action == 2:
            forward = cls.west(state)
            left = cls.south(state)
            right = cls.north(state)
        else:
            forward = cls.south(state)
            left = cls.east(state)
            right = cls.west(state)
        if cls.deterministic:
            state_ = forward
        else:
            r = np.random.random()
            if r < 0.8:
                state_ = forward
            elif r < 0.9:
                state_ = left
            else:
                state_ = right
        reward = cls.get_reward(state_)  # 報酬
        return reward, state_

  # 状態を返す
  def getState():
    return self.state
    @classmethod
    def str_state(cls, state):
        """状態を表す文字列を返す。"""
        x, y = state[0], state[1]
        return '(%d, %d)' % (x, y)

    @classmethod
    def str_action(cls, action):
        """行動を表す文字列を返す。"""
        if action == 0:
            str = 'north'
        elif action == 1:
            str = 'east'
        elif action == 2:
            str = 'west'
        else:
            str = 'south'
        return str

  # 報酬を返す
  #   s: 状態
  def getReward(self, s):
    x, y = self.state2coodinate(s)
    r = self.rewards[x, y]
    return r
    @classmethod
    def north(cls, state):
        """北に壁がない場合は北隣の状態を、壁がある場合は現在の状態を返す。"""
        x, y = state[0], state[1]
        x_, y_ = x, y - 1
        return (x_, y_) if not cls.is_wall((x_, y_)) else state

    @classmethod
    def east(cls, state):
        """東に壁がない場合は東隣の状態を、壁がある場合は現在の状態を返す。"""
        x, y = state[0], state[1]
        x_, y_ = x + 1, y
        return (x_, y_) if not cls.is_wall((x_, y_)) else state

  # 行動する
  #   s: 状態
  #   a: 行動
  def takeAction(self, s, a):
    act = self.lActions[a]        # 行動
    s_ = act(s)                   # 行動を実行する
    r  = self.getReward(s_)       # 報酬を観測する
    return s_, r                  # 次の状態と報酬を返す
    @classmethod
    def west(cls, state):
        """西に壁がない場合は西隣の状態を、壁がある場合は現在の状態を返す。"""
        x, y = state[0], state[1]
        x_, y_ = x - 1, y
        return (x_, y_) if not cls.is_wall((x_, y_)) else state

    @classmethod
    def south(cls, state):
        """南に壁がない場合は南隣の状態を、壁がある場合は現在の状態を返す。"""
        x, y = state[0], state[1]
        x_, y_ = x, y + 1
        return (x_, y_) if not cls.is_wall((x_, y_)) else state

  # 状態を文字列で表して返す
  #   s: 状態
  def strState(self, s):
    x, y = self.state2coodinate(s)
    return '(%d, %d)' % (x, y)


  # 行動を文字列で表して返す
  #   a: 行動
  def strAction(self, a):
    return self.lActions[a].__name__


  # コンストラクター
  def __init__(self):
    super().__init__()
    self.width    = len(self.walls[0])                              # 迷路の幅
    self.height   = len(self.walls)                                 # 迷路の高さ
    self.states   = self.width * self.height                        # 状態の数
    self.lActions = [self.north, self.east, self.west, self.south]  # 行動のリスト
    self.actions  = len(self.lActions)                              # 行動の数
    self.initState()                                                # 状態を初期化する
    def __init__(self, deterministic=False):
        Maze.deterministic = deterministic
        super().__init__()
}}


*実行用ファイル mazeql.py [#ab065b92]

#ref(./mazeql.py)
#geshi(python){{
#!/usr/bin/env python3
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# mazeql.py
#
# Copyright 2017 Tohgoroh Matsui All Rights Reserved.
# Copyright 2017-2018 Tohgoroh Matsui All Rights Reserved.
#
import maze
import qlagent
from maze import Maze
from qlagent import QLearningAgent
import sys

# mainモジュール
if __name__ == '__main__':
  env   = maze.Maze()                   # 環境
  agent = qlagent.QLearningAgent()      # Q学習エージェント
  agent.setEnvironment(env)             # 環境をエージェントにセットする
  agent.learn()                         # 学習する
    argvs = sys.argv    # コマンドライン引数
    seed = None if len(argvs) == 1 else int(argvs[1])  # 乱数のシード
    maze = Maze(deterministic=True) # 環境
    agent = QLearningAgent(environment=maze, seed=seed, verbose_level=1, step_size=0.1, epsilon=0.4)   # Q学習エージェント
    agent.learn()   # 学習する
}}


*実行結果 [#y77c1664]

#geshi(sh){{
$ python3 mazeql.py
1, 49.290000
2, 42.750000
3, 59.680000
4, 64.650000
5, 67.800000
6, 37.910000
7, 46.420000
8, 55.940000
9, 51.880000
10, 44.650000
20, 66.240000
30, 70.940000
40, 71.500000
50, 97.150000
60, 62.780000
70, 100.000000
80, 100.000000
90, 100.000000
100, 14.470000
200, 50.660000
300, 46.580000
400, 9.960000
500, 9.270000
600, 8.780000
700, 9.610000
800, 7.630000
900, 9.740000
1000, 7.850000
2000, 6.960000
3000, 7.010000
4000, 7.170000
5000, 6.510000
6000, 6.600000
7000, 6.610000
8000, 7.310000
9000, 6.580000
10000, 6.680000
20000, 6.700000
30000, 7.700000
40000, 6.920000
50000, 7.190000
60000, 6.970000
70000, 6.790000
80000, 7.080000
90000, 7.070000
100000, 7.400000
200000, 7.460000
300000, 6.770000
400000, 7.730000
500000, 6.970000
600000, 6.790000
700000, 7.220000
800000, 7.590000
900000, 7.270000
1000000, 7.030000
[[ 0.57936398  0.66081859  0.54196507  0.47743206]
 [ 0.68507578  0.80528612  0.59248293  0.6700417 ]
 [ 0.83194323  0.94140941  0.67752173  0.59096585]
 [ 0.          0.          0.          0.        ]
 [ 0.56468961  0.44486706  0.47738216  0.39147569]
 [ 0.          0.          0.          0.        ]
 [ 0.40230731 -0.64613184  0.33453209  0.17906799]
 [ 0.          0.          0.          0.        ]
 [ 0.45612173  0.31248324  0.37599547  0.35867265]
 [ 0.30082596  0.30399564  0.3301133   0.3123197 ]
 [ 0.31227229  0.13243078  0.31015554  0.28215629]
 [-0.6082414  -0.0130165   0.18116616 -0.01257615]]
}}
乱数を使っているので、乱数のシードを変えて何回か実行し、平均を取らないといけません。

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS