Précédemment Pouvez-vous apprendre des jeux supplémentaires avec un apprentissage amélioré? a été essayé et j'ai pu apprendre sans aucun problème.
Cette fois, je suppose un problème plus réaliste.
Il ya un problème. Eh bien, il y a une histoire que vous devriez envoyer à tout le monde s'il s'agit de courrier électronique, mais si vous en envoyez trop, cela entraînera un retrait, et les coupons sont coûteux, donc je ne veux pas éclater.
La question cette fois est de savoir ce qui se passerait si ce problème était résolu dans un cadre Q-Learning. Avec Q-Learning, c'est un bon endroit pour pouvoir gérer plusieurs actions. Cependant, pensez-y comme une situation simple et complètement virtuelle.
Pour l'écrire facilement
C'est comme ça.
Dans le cas de ce jeu, je craignais qu'il ne soit difficile de dire qu'il y a un intervalle entre la réalisation de la meilleure action et l'obtention de la récompense. Il semble que l'apprentissage sera rapide si vous obtenez une récompense immédiatement après l'action optimale, mais le plus important est que ce n'est pas le cas. Je pense qu'il est difficile de définir le terme «pénalité», mais maintenant je ne fais que le donner à des actions qui semblent être erronées. (Est-ce trop facile pour le problème ...?).
Cependant, comme vous pouvez le voir dans Explorer le labyrinthe avec un apprentissage amélioré, vous pouvez apprendre rétroactivement, donc je me demande si vous pouvez le faire. Je voulais juste le vérifier.
Vous n'obtiendrez des récompenses que lorsque U = 2 se produit, augmentez donc chance_count
lorsque U = 2 se produit. La récompense maximale que vous pouvez obtenir sur une période donnée est «chance_count».
Par conséquent, laissez hit_rate
être la récompense / chance_count
obtenue.
La figure ci-dessous montre comment cela a changé après 10 000 apprentissages / évaluations.
J'ai essayé environ 50 millions de fois, mais après environ 30 millions de fois, j'ai senti que l'apprentissage avait atteint son apogée et qu'il s'agissait d'environ hit_rate = 0,9.
Q L'apprentissage est amusant car cela ressemble à une simple IA en un sens. J'espère qu'il peut être utilisé pour quelque chose.
Je le posterai pour référence.
#!/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) #Undefined renvoie un petit nombre aléatoire
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