強化学習/Pythonで強化学習する
をテンプレートにして作成
開始行:
*はじめに [#l524e399]
ここでは、Pythonで強化学習を行います。
例題として、Sutton & Barto の『エージェント・アプローチ人...
#ref(./maze.png,nolink,25%)
Sのマスが初期状態、+1 と -1 のマスが終端状態です。
行動は東西南北の4種類です。
外側と塗られているマスには壁があり、その方向には進めませ...
0.8の確率で選んだ方向に進むことができ、0.1の確率で選んだ...
数値が書かれているマスに到達するとその数値が報酬として得...
その他のマスに到達すると報酬 -0.02 が得られます。
強化学習アルゴリズムはQ学習、行動選択は[math]\epsilon[/ma...
次の環境で確認しました。
-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
*Q学習エージェント qlagent.py [#m72d7cc6]
Q学習エージェントを表す QLearningAgent クラスには、Q学習...
Q学習のアルゴリズムは、次のようなものです。
+行動価値 [math]Q(s, a)[/math] を初期化
+エピソードごとに繰り返し:
++状態 [math]s[/math] を初期化
++[math]s[/math] が終端状態になるまで繰り返し:
+++[math]Q[/math]から導かれる行動選択確率に基づいて [math...
+++[math]a[/math] を実行し、次の状態 [math]s'[/math] と報...
+++[math]Q(s, a) \leftarrow Q(s, a) + \alpha \left[ r + \...
+++[math]s \leftarrow s'[/math]
これを、Pythonで実装すると、次のようになります。
#ref(./qlagent.py)
#geshi(python){{
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# qlagent.py
#
# Copyright 2017-2018 Tohgoroh Matsui All Rights Reserved.
#
from rlagent import ReinforcementLearningAgent
import numpy as np
class QLearningAgent(ReinforcementLearningAgent):
"""Q学習エージェント。"""
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]) #...
while total_steps < self.max_steps:
steps = 0 # このエピソードにおけるステップ数
state = env.init_state() # 状態を初期化する
while total_steps < self.max_steps and not en...
action = self.epsilon_greedy(state) # 行...
reward , state_ = env.take_action(state, ...
if self.verbose_level > 1:
env.print_log(steps, state, action, r...
action_ = self.greedy(state_) # 次の状...
s, a, = env.get_s(state), env.get_a(action)
s_, a_ = env.get_s(state_), env.get_a(act...
self.q[s, a] += alpha * (reward + gamma *...
state = state_ # 状態を更新する
steps += 1
total_steps += 1
if self.evaluation and total_steps % np.p...
eval = self.evaluate() # 評価する
print('%d, %f' % (total_steps, eval))
episodes += 1
if self.verbose_level > 0:
print(self.q) # Q値を出力
def __init__(self, environment=None, seed=None, disco...
super().__init__(environment, seed, discount_rate...
}}
ステップ数を数えたり、学習した方策を評価する部分がありま...
ここで呼び出しているメソッドは、親クラスの ReinforcementL...
迷路の問題を解くだけならもう少しシンプルに書くことができ...
*強化学習エージェント rlagent.py [#qdcfcadd]
強化学習エージェントを表す ReinforcementLearningAgent ク...
#ref(./rlagent.py)
#geshi(python){{
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# rlagent.py
#
# Copyright 2017-2018 Tohgoroh Matsui All Rights Reserved.
#
from abc import ABCMeta, abstractmethod
import numpy as np
class ReinforcementLearningAgent(metaclass=ABCMeta):
"""強化学習エージェント。"""
@abstractmethod
def learn(self):
"""強化学習を用いて学習する。"""
pass
def evaluate(self):
"""学習した行動価値が最も高い行動を選択したときの...
env = self.environment # 環境
episodes = 0 # エピソード数
total_steps = 0 # ステップ数
while episodes < 100: # 100エピソード繰り返す:
steps = 0 # このエピソードにおけるステップ数
state = env.init_state() # 状態を初期化する ...
while not env.is_terminal(state) and steps < ...
action = self.greedy(state) # グリーディ...
reward, state_ = env.take_action(state, a...
if self.verbose_level > 2:
env.printLog(steps, state, action, re...
state = state_
steps += 1
total_steps += 1
episodes += 1
return total_steps / 100
def uniformly(self):
"""一様ランダムに行動を選択して返す。"""
action = np.random.randint(self.environment.actio...
return action
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値がma...
r = np.random.randint(len(aIds)) # 0から要素数...
action = aIds[r] # Q値がmaxQである要素のインデ...
return action
def epsilon_greedy(self, state):
"""ε-グリーディー選択を用いて行動を選択して返す。...
r = np.random.rand() # 乱数を生成する
action = self.uniformly() if r < self.epsilon el...
return action
def __init__(self, environment=None, seed=None, disco...
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)
}}
*環境 environment.py [#y715bf52]
まず初めに、環境を表すクラスがどのような変数とメソッドを...
変数としては、次のものを持つことにします。
-状態数 states
-行動数 actions
メソッドしては、次のものを持つことにします。
-状態を初期化して返す initState
-終端状態かどうかを調べる isTerminal
-報酬を返す getReward
-行動を実行して次の状態と報酬を返す takeAction
-状態を文字列で返す strState
-行動を文字列で返す strAction
-ログを出力する printLog
printLog 以外の実際の実装は、子クラスで行います。
#ref(./environment.py)
#geshi(python){{
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# environment.py
#
# Copyright 2017-2018 Tohgoroh Matsui All Rights Reserved.
#
from abc import ABCMeta, abstractmethod
class Environment(metaclass=ABCMeta):
"""強化学習の環境。"""
states = None # 状態数
actions = None # 行動数
@classmethod
@abstractmethod
def init_state(cls):
"""初期状態を返す。"""
pass
@classmethod
@abstractmethod
def is_terminal(cls):
"""終端状態ならTrue、そうでないならFalseを返す。"""
pass
@classmethod
@abstractmethod
def get_reward(cls, state):
"""報酬を返す。"""
pass
@classmethod
@abstractmethod
def take_action(cls, state, action):
"""行動を実行して状態を更新し、報酬と次の状態を返...
pass
@classmethod
@abstractmethod
def str_state(cls, state):
"""状態を表す文字列を返す。"""
pass
@classmethod
@abstractmethod
def str_action(cls, action):
"""行動を表す文字列を返す。"""
pass
@classmethod
def print_log(cls, steps, state, action, reward, stat...
"""ログを出力する。"""
print('# %d, %s, %s, %f, %s' % (steps, cls.str_st...
}}
*迷路 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
class Maze(Environment):
"""Sutton & Barto 4x3迷路問題。状態は (x座標, y座標) ...
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)
@classmethod
def is_terminal(cls, state):
"""渡された状態が終端状態ならTrue, そうでないなら...
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 o...
@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
@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_
@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
@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...
@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...
@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...
@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...
def __init__(self, deterministic=False):
Maze.deterministic = deterministic
super().__init__()
}}
*実行用ファイル mazeql.py [#ab065b92]
#ref(./mazeql.py)
#geshi(python){{
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# mazeql.py
#
# Copyright 2017-2018 Tohgoroh Matsui All Rights Reserved.
#
from maze import Maze
from qlagent import QLearningAgent
import sys
if __name__ == '__main__':
argvs = sys.argv # コマンドライン引数
seed = None if len(argvs) == 1 else int(argvs[1]) # ...
maze = Maze(deterministic=True) # 環境
agent = QLearningAgent(environment=maze, seed=seed, v...
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]]
}}
乱数を使っているので、乱数のシードを変えて何回か実行し、...
終了行:
*はじめに [#l524e399]
ここでは、Pythonで強化学習を行います。
例題として、Sutton & Barto の『エージェント・アプローチ人...
#ref(./maze.png,nolink,25%)
Sのマスが初期状態、+1 と -1 のマスが終端状態です。
行動は東西南北の4種類です。
外側と塗られているマスには壁があり、その方向には進めませ...
0.8の確率で選んだ方向に進むことができ、0.1の確率で選んだ...
数値が書かれているマスに到達するとその数値が報酬として得...
その他のマスに到達すると報酬 -0.02 が得られます。
強化学習アルゴリズムはQ学習、行動選択は[math]\epsilon[/ma...
次の環境で確認しました。
-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
*Q学習エージェント qlagent.py [#m72d7cc6]
Q学習エージェントを表す QLearningAgent クラスには、Q学習...
Q学習のアルゴリズムは、次のようなものです。
+行動価値 [math]Q(s, a)[/math] を初期化
+エピソードごとに繰り返し:
++状態 [math]s[/math] を初期化
++[math]s[/math] が終端状態になるまで繰り返し:
+++[math]Q[/math]から導かれる行動選択確率に基づいて [math...
+++[math]a[/math] を実行し、次の状態 [math]s'[/math] と報...
+++[math]Q(s, a) \leftarrow Q(s, a) + \alpha \left[ r + \...
+++[math]s \leftarrow s'[/math]
これを、Pythonで実装すると、次のようになります。
#ref(./qlagent.py)
#geshi(python){{
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# qlagent.py
#
# Copyright 2017-2018 Tohgoroh Matsui All Rights Reserved.
#
from rlagent import ReinforcementLearningAgent
import numpy as np
class QLearningAgent(ReinforcementLearningAgent):
"""Q学習エージェント。"""
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]) #...
while total_steps < self.max_steps:
steps = 0 # このエピソードにおけるステップ数
state = env.init_state() # 状態を初期化する
while total_steps < self.max_steps and not en...
action = self.epsilon_greedy(state) # 行...
reward , state_ = env.take_action(state, ...
if self.verbose_level > 1:
env.print_log(steps, state, action, r...
action_ = self.greedy(state_) # 次の状...
s, a, = env.get_s(state), env.get_a(action)
s_, a_ = env.get_s(state_), env.get_a(act...
self.q[s, a] += alpha * (reward + gamma *...
state = state_ # 状態を更新する
steps += 1
total_steps += 1
if self.evaluation and total_steps % np.p...
eval = self.evaluate() # 評価する
print('%d, %f' % (total_steps, eval))
episodes += 1
if self.verbose_level > 0:
print(self.q) # Q値を出力
def __init__(self, environment=None, seed=None, disco...
super().__init__(environment, seed, discount_rate...
}}
ステップ数を数えたり、学習した方策を評価する部分がありま...
ここで呼び出しているメソッドは、親クラスの ReinforcementL...
迷路の問題を解くだけならもう少しシンプルに書くことができ...
*強化学習エージェント rlagent.py [#qdcfcadd]
強化学習エージェントを表す ReinforcementLearningAgent ク...
#ref(./rlagent.py)
#geshi(python){{
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# rlagent.py
#
# Copyright 2017-2018 Tohgoroh Matsui All Rights Reserved.
#
from abc import ABCMeta, abstractmethod
import numpy as np
class ReinforcementLearningAgent(metaclass=ABCMeta):
"""強化学習エージェント。"""
@abstractmethod
def learn(self):
"""強化学習を用いて学習する。"""
pass
def evaluate(self):
"""学習した行動価値が最も高い行動を選択したときの...
env = self.environment # 環境
episodes = 0 # エピソード数
total_steps = 0 # ステップ数
while episodes < 100: # 100エピソード繰り返す:
steps = 0 # このエピソードにおけるステップ数
state = env.init_state() # 状態を初期化する ...
while not env.is_terminal(state) and steps < ...
action = self.greedy(state) # グリーディ...
reward, state_ = env.take_action(state, a...
if self.verbose_level > 2:
env.printLog(steps, state, action, re...
state = state_
steps += 1
total_steps += 1
episodes += 1
return total_steps / 100
def uniformly(self):
"""一様ランダムに行動を選択して返す。"""
action = np.random.randint(self.environment.actio...
return action
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値がma...
r = np.random.randint(len(aIds)) # 0から要素数...
action = aIds[r] # Q値がmaxQである要素のインデ...
return action
def epsilon_greedy(self, state):
"""ε-グリーディー選択を用いて行動を選択して返す。...
r = np.random.rand() # 乱数を生成する
action = self.uniformly() if r < self.epsilon el...
return action
def __init__(self, environment=None, seed=None, disco...
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)
}}
*環境 environment.py [#y715bf52]
まず初めに、環境を表すクラスがどのような変数とメソッドを...
変数としては、次のものを持つことにします。
-状態数 states
-行動数 actions
メソッドしては、次のものを持つことにします。
-状態を初期化して返す initState
-終端状態かどうかを調べる isTerminal
-報酬を返す getReward
-行動を実行して次の状態と報酬を返す takeAction
-状態を文字列で返す strState
-行動を文字列で返す strAction
-ログを出力する printLog
printLog 以外の実際の実装は、子クラスで行います。
#ref(./environment.py)
#geshi(python){{
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# environment.py
#
# Copyright 2017-2018 Tohgoroh Matsui All Rights Reserved.
#
from abc import ABCMeta, abstractmethod
class Environment(metaclass=ABCMeta):
"""強化学習の環境。"""
states = None # 状態数
actions = None # 行動数
@classmethod
@abstractmethod
def init_state(cls):
"""初期状態を返す。"""
pass
@classmethod
@abstractmethod
def is_terminal(cls):
"""終端状態ならTrue、そうでないならFalseを返す。"""
pass
@classmethod
@abstractmethod
def get_reward(cls, state):
"""報酬を返す。"""
pass
@classmethod
@abstractmethod
def take_action(cls, state, action):
"""行動を実行して状態を更新し、報酬と次の状態を返...
pass
@classmethod
@abstractmethod
def str_state(cls, state):
"""状態を表す文字列を返す。"""
pass
@classmethod
@abstractmethod
def str_action(cls, action):
"""行動を表す文字列を返す。"""
pass
@classmethod
def print_log(cls, steps, state, action, reward, stat...
"""ログを出力する。"""
print('# %d, %s, %s, %f, %s' % (steps, cls.str_st...
}}
*迷路 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
class Maze(Environment):
"""Sutton & Barto 4x3迷路問題。状態は (x座標, y座標) ...
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)
@classmethod
def is_terminal(cls, state):
"""渡された状態が終端状態ならTrue, そうでないなら...
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 o...
@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
@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_
@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
@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...
@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...
@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...
@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...
def __init__(self, deterministic=False):
Maze.deterministic = deterministic
super().__init__()
}}
*実行用ファイル mazeql.py [#ab065b92]
#ref(./mazeql.py)
#geshi(python){{
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# mazeql.py
#
# Copyright 2017-2018 Tohgoroh Matsui All Rights Reserved.
#
from maze import Maze
from qlagent import QLearningAgent
import sys
if __name__ == '__main__':
argvs = sys.argv # コマンドライン引数
seed = None if len(argvs) == 1 else int(argvs[1]) # ...
maze = Maze(deterministic=True) # 環境
agent = QLearningAgent(environment=maze, seed=seed, v...
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]]
}}
乱数を使っているので、乱数のシードを変えて何回か実行し、...
ページ名: