Zuvor Können Sie Zusatzspiele mit erweitertem Lernen lernen? wurde ausprobiert und ich konnte ohne Probleme lernen.
Dieses Mal gehe ich von einem realistischeren Problem aus.
Es gibt ein Problem. Nun, es gibt eine Geschichte, die Sie an alle senden sollten, wenn es um E-Mails geht, aber wenn Sie zu viel senden, führt dies zu einer Auszahlung, und Gutscheine sind teuer, sodass ich nicht zu viel herausplatzen möchte.
Die Frage ist diesmal, was passieren würde, wenn dieses Problem in einem Q-Learning-Framework gelöst würde. Mit Q-Learning ist es ein guter Ort, um mehrere Aktionen ausführen zu können. Stellen Sie sich dies jedoch als eine einfache, vollständig virtuelle Situation vor.
Um es einfach zu schreiben
Es ist wie es ist.
Bei diesem Spiel war ich besorgt, dass es schwierig sein könnte zu sagen, dass es eine Pause zwischen der besten Aktion und der Belohnung gibt. Es scheint, dass das Lernen schnell sein wird, wenn Sie unmittelbar nach der optimalen Aktion eine Belohnung erhalten, aber der größte Punkt ist, dass dies nicht der Fall ist. Ich denke, es ist schwierig, "Strafe" zu definieren, aber jetzt gebe ich es nur für Aktionen, die falsch zu sein scheinen. (Ist das zu einfach für das Problem ...?).
Wie Sie jedoch in Erkundung des Labyrinths mit erweitertem Lernen sehen können, können Sie rückwirkend lernen, sodass ich mich frage, ob Sie dies tun können. Ich wollte es nur überprüfen.
Sie erhalten nur Belohnungen, wenn U = 2 auftritt. Erhöhen Sie also die Wahrscheinlichkeitszahl, wenn U = 2 auftritt. Die maximale Belohnung, die Sie über einen bestimmten Zeitraum erhalten können, ist "Chance_Count". Daher sei "hit_rate" die erhaltene "Belohnung / Chance_Count". Die folgende Abbildung zeigt, wie es sich nach 10.000 Lern- / Evaluierungsarbeiten geändert hat.
Ich habe es ungefähr 50 Millionen Mal versucht, aber nach ungefähr 30 Millionen Mal hatte ich das Gefühl, dass das Lernen seinen Höhepunkt erreicht hatte, und es ging um hit_rate = 0,9.
Q Lernen macht Spaß, weil es in gewissem Sinne wie eine einfache KI aussieht. Ich hoffe es kann für etwas verwendet werden.
Ich werde es als Referenz posten.
#!/usr/bin/env python
# coding: utf-8
import numpy as np
from random import random, choice
class Game(object):
state = None
actions = None
game_over = False
def __init__(self, player):
self.player = player
self.turn = 0
self.last_reward = 0
self.total_reward = 0
self.init_state()
def player_action(self):
action = self.player.action(self.state, self.last_reward)
if action not in self.actions:
raise Exception("Invalid Action: '%s'" % action)
self.state, self.last_reward = self.get_next_state_and_reward(self.state, action)
def play(self):
yield(self)
while not self.game_over:
self.player_action()
self.turn += 1
self.total_reward += self.last_reward
yield(self)
def init_state(self):
raise NotImplemented()
def get_next_state_and_reward(self, state, action):
raise NotImplemented()
class UserAndPushEventGame(Game):
"""
State :S : list of (U, A)
UserActivity :U : int of 0~3
Action :A : int of 0 or 1
Next-State(S, A):S':
S[-1][1] = A
S.append((Next-U, None))
S = S[-5:]
Next-U : :
if S[-4] == (2, 1) then 3
else 10% -> 2, 10% -> 1, 80% -> 0
Reward(S, A) :R :
if S[-1] == (3, *) then R += 1
wrong_action_count := Number of ({0,1,3}, 1) in S
R -= wrong_action_count * 0.3
"""
STATE_HISTORY_SIZE = 5
def init_state(self):
self.actions = [0, 1]
self.state = [(0, None)]
self.chance_count = 0
def get_next_state_and_reward(self, state, action):
next_state = (state + [(self.next_user_action(state), None)])[-self.STATE_HISTORY_SIZE:]
next_state[-2] = (next_state[-2][0], action)
reward = 0
if len(state) > 0 and state[-1][0] == 3:
reward += 1
action_count = reduce(lambda t, x: t+(x[1] or 0), state, 0)
correct_action_count = len([0 for x in state if x == (2, 1)])
wrong_action_count = action_count - correct_action_count
reward -= wrong_action_count * 0.3
return next_state, reward
def next_user_action(self, state):
if len(state) > 4 and state[-4] == (2, 1):
return 3
else:
rnd = np.random.random()
if rnd < 0.8:
return 0
elif rnd < 0.9:
return 1
else:
self.chance_count += 1
return 2
class HumanPlayer(object):
training = False
def action(self, state, last_reward):
print "LastReward=%s, CurrentState: %s" % (last_reward, state)
while True:
action_input = raw_input("Enter 0~1: ")
if int(action_input) in [0, 1]:
return int(action_input)
class QLearnPlayer(object):
ALPHA = 0.1
GAMMA = 0.99
E_GREEDY = 0.05
def __init__(self):
self.actions = [0, 1]
self.q_table = {}
self.last_state = self.last_action = None
self.training = True
def get_q_value(self, state, action):
return self.q_table.get(state, {}).get(action, (np.random.random() - 0.5)/1000) #Undefiniert gibt eine kleine Zufallszahl zurück
def get_all_q_values(self, state):
return [self.get_q_value(state, act) for act in self.actions]
def set_q_value(self, state, action, val):
if state in self.q_table:
self.q_table[state][action] = val
else:
self.q_table[state] = {action: val}
def action(self, state, last_reward):
state = tuple(state)
next_action = self.select_action(state)
if self.last_state is not None:
self.update_q_table(self.last_state, self.last_action, state, last_reward)
self.last_state = state
self.last_action = next_action
return next_action
def select_action(self, state):
if self.training and random() < self.E_GREEDY:
return choice(self.actions)
else:
return np.argmax(self.get_all_q_values(state))
def update_q_table(self, last_state, last_action, cur_state, last_reward):
if self.training:
d = last_reward + np.max(self.get_all_q_values(cur_state)) * self.GAMMA - self.get_q_value(last_state, last_action)
self.set_q_value(last_state, last_action, self.get_q_value(last_state, last_action) + self.ALPHA * d)
if __name__ == '__main__':
SWITCH_MODE_TURN_NUM = 10000
fp = file("result.txt", "w")
dt = file("detail.txt", "w")
player = QLearnPlayer()
# player = HumanPlayer()
game = UserAndPushEventGame(player)
last_chance_count = last_score = 0
for g in game.play():
# dt.write("%s: isT?=%s LastReward=%s TotalReward=%s S=%s\n" %
# (g.turn, player.training, g.last_reward, g.total_reward, g.state))
if g.turn % SWITCH_MODE_TURN_NUM == 0:
if not player.training:
this_term_score = game.total_reward - last_score
this_term_chance = game.chance_count - last_chance_count
if this_term_chance > 0:
hit_rate = 100.0*this_term_score/this_term_chance
else:
hit_rate = 0
# print "Turn=%d: This 100 turn score=%2.2f chance=%02d: HitRate=%.1f%% %s" % \
# (g.turn, this_term_score, this_term_chance, hit_rate, '*' * int(hit_rate/2))
fp.write("%d\t%.2f\t%d\t%f\n" % (g.turn, this_term_score, this_term_chance, hit_rate))
last_score = game.total_reward
last_chance_count = game.chance_count
player.training = not player.training
if g.turn % 10000 == 0:
fp.flush()
Recommended Posts