Implémentation de la tâche de bandit de compétences $ n $ en python. En tant que manuel ["Strengthening learning"](http://www.amazon.co.jp/ Strengthening learning-Richard-S-Sutton / dp / 4627826613 / ref = sr_1_1? Ie = UTF8 & qid = 1463965873 & sr = 8-1 & keywords = Renforcement de l'apprentissage % E3% 80% 80 Mikami) a été utilisé.
Structure de cet article
L'apprentissage d'intensification apprend quelles actions choisir pour maximiser les récompenses. Dans l'apprentissage supervisé, vous avez la bonne action à choisir, mais dans l'apprentissage intensif, vous sélectionnez une action basée sur une «certaine ligne directrice» et évaluez et mettez à jour l'action en utilisant les récompenses obtenues. Vous pouvez maximiser votre récompense en agissant selon les «certaines directives» apprises.
J'expliquerai les composants de l'apprentissage par renforcement et leurs brèves explications.
L'agent détecte l'environnement et sélectionne des actions en fonction de l'état détecté et de la fonction de valeur. L'environnement renvoie la récompense de l'action, et cette récompense est utilisée pour mettre à jour la valeur de l'action.
Une machine à sous avec des leviers $ n $ est appelée un bandit bras $ n $. Sélectionnez un livre à 1 $ parmi les leviers de livre $ n $ et tirez sur le levier pour gagner un prix. Tout d'abord, nous générons une récompense $ Q ^ {\ ast} (a) $ pour une action $ a $ à partir d'une distribution gaussienne avec une moyenne de 0 $ et une variance de 1 $. Ensuite, à partir de la distribution gaussienne avec la moyenne $ Q ^ {\ ast} (a) $ variance $ 1 $, nous générons les récompenses de la machine bandit. Créer plusieurs machines bandit et tirer toutes les machines bandit $ 1 $ chacune s'appelle $ 1 $ play. Maximisez les récompenses en apprenant à travers plusieurs jeux,
En faisant la moyenne des récompenses obtenues lorsqu'une action est sélectionnée, la valeur de cette action peut être estimée. C'est ce qu'on appelle la méthode de calcul de la moyenne des échantillons. Soit la valeur vraie de l'action $ a $ $ Q ^ {\ ast} (a) $ et le montant estimé dans le $ t $ ème jeu soit $ Q_t (a) $. Si l'action $ a $ est sélectionnée $ k_a $ fois dans le $ t $ ème jeu et que les récompenses pour chaque sélection sont $ r_ {1}, r_ {2}, ..., r_ {k_a} $ La valeur de l'action $ a $ jusqu'au temps $ t $ est définie comme suit.
Q_{t}(a) = \frac{r_{1} + r_{2} + \cdots + r_{k_a}}{k_a}
Dans $ k_a \ rightarrow \ infty $, il converge vers $ Q_t (a) \ rightarrow Q ^ {\ ast} (a) $ selon la loi de la majorité.
La méthode Greedy et la méthode $ \ varepsilon $ Greedy sont expliquées comme des règles de sélection d'action. La méthode Greedy sélectionne l'action avec la valeur d'action estimée la plus élevée. En d'autres termes, dans le $ t $ th play, $ 1 $ de comportement gourmand tel que $ Q_t (a ^ {\ ast}) = \ max_ {a} Q_t (a) $ $ a ^ {\ ast} $ Choisir. Dans la méthode gourmande $ \ varepsilon $, une action aléatoire est sélectionnée avec une probabilité de $ \ varepsilon $, et une action gourmande est sélectionnée avec une probabilité de $ 1- \ varepsilon $. Avec la méthode Greedy, nous choisissons toujours l'action avec la meilleure valeur et n'essayons jamais aucune autre action. Cela signifie que vous ne pouvez trouver aucun des comportements non testés qui soient encore meilleurs que ce que vous faites le mieux actuellement. D'un autre côté, dans la méthode $ \ varepsilon $ gloutonne, l'action est fondamentalement sélectionnée de manière gourmande, mais parfois l'action est exécutée au hasard avec une probabilité de $ \ varepsilon $. Cela peut vous permettre de trouver un comportement encore meilleur que ce que vous faites le mieux actuellement.
Je l'ai implémenté comme suit. J'ai préparé une machine à bandit à 10 $ avec 2000 $ et j'ai appris en jouant à 2000 $. Ici, le jeu $ 1 $ consiste à tirer $ 1 $ pour toutes les machines dans la gamme $ 2000 $. (Les résultats sont légèrement différents car certaines des règles du manuel ont été modifiées.)
bandit.py
import numpy
from matplotlib import pyplot
import random
import sys
class Bandit:
# constuctor
def __init__(self, n_machine, n_action):
for i in range(n_action):
_qstar = numpy.random.normal(0.0, 1.0)
_machine = numpy.random.normal(_qstar, 1.0, n_machine).reshape((-1, 1))
if i == 0:
self.machine = _machine
else:
self.machine = numpy.hstack((self.machine, _machine))
# public method
def play(self, n_play, epsilon):
self.q = numpy.zeros(self.machine.shape)
self.q_count = numpy.zeros(self.machine.shape)
average_reward = numpy.zeros(n_play)
n_machine = self.machine.shape[0]
for _p in range(n_play):
total = 0.0
for mac_index in range(n_machine):
act_index = self.__select_action(mac_index, epsilon)
reward = self.machine[mac_index, act_index]
total += reward
self.__update_qtable(reward, mac_index, act_index)
average_reward[_p] = total / n_machine
self.__display(_p, average_reward[_p])
return average_reward
# private method
def __select_action(self, mac_index, epsilon):
if numpy.random.rand() > epsilon:
act_index = self.__select_greedy_action(mac_index)
else:
act_index = self.__select_random_action()
return act_index
def __select_greedy_action(self, mac_index):
_max = self.q[mac_index, :].max()
indexes = numpy.argwhere(self.q[mac_index, :] == _max)
random.shuffle(indexes)
return indexes[0]
def __select_random_action(self):
return numpy.random.randint(10)
def __update_qtable(self, reward, mac_index, act_index):
_q = self.q[mac_index, act_index]
self.q_count[mac_index, act_index] += 1
self.q[mac_index, act_index] = _q + (reward - _q) / self.q_count[mac_index, act_index]
def __display(self, play, average_reward):
if (play + 1) % 100 == 0:
print u'play: %d, average reward: %f' % (play + 1, average_reward)
main.py
from bandit import *
if __name__ == '__main__':
# param
param = sys.argv
# init
n_machine = 2000
n_action = 10
n_play = 2000
epsilon = [0.0, 0.01, 0.1, 1.0]
# draw init
mergin = 5
color = ['b', 'g', 'r', 'k']
pyplot.figure(figsize = (8, 6))
pyplot.xlim(-mergin, n_play + mergin)
# bandit machine
bandit = Bandit(n_machine, n_action)
# play
for i in range(len(epsilon)):
print u'play count: %d, epsilon: %.2f' % (n_play, epsilon[i])
average_reward = bandit.play(n_play, epsilon[i])
_label = 'e = %.2f' % epsilon[i]
pyplot.plot(numpy.arange(n_play), average_reward, color = color[i], label = _label)
print '!!!finish!!!\n'
# save and show
if '-d' in param or '-s' in param:
pyplot.legend(loc = 'center right')
if '-s' in param:
pyplot.savefig('bandit2.png')
if '-d' in param:
pyplot.show()
Les résultats suivants ont été obtenus. À $ \ varepsilon = 0.0 $, vous choisissez toujours une action gourmande, donc lorsque vous trouvez une action valant 0 $ ou plus, vous continuerez toujours à choisir cette action. Par conséquent, la valeur moyenne des récompenses obtenues est toujours constante. A $ \ varepsilon = 1.0 $, il agit toujours au hasard, donc même si le nombre de jeux augmente, la valeur moyenne des récompenses qui peuvent être obtenues ne dépasse pas une certaine fourchette. Avec $ \ varepsilon = 0,1 $, il y a une chance $ 10 % $ d'agir au hasard et une chance $ 90 % $ de choisir une action gourmande. Nous trouvons le meilleur comportement le plus rapide, mais même après avoir appris, nous avons 10 $ % $ de chance d'agir au hasard, donc la récompense moyenne n'est que d'environ 1,8 $. Avec $ \ varepsilon = 0.01 $, il y a une chance $ 1 % $ d'agir au hasard et une chance $ 99 % $ de choisir une action gourmande. La vitesse de convergence est plus lente que $ \ varepsilon = 0,1 $, mais les performances sont les meilleures à partir d'environ 1000 $ de jeu.
Nous avons implémenté la tâche de bandit de compétences $ n $ en python et confirmé la différence dans le processus d'apprentissage due au changement de $ \ varepsilon $.
Recommended Posts