J'essaie de recréer un exemple très simple de Gradient politique, à partir de son blog d'origine Andrej Karpathy . Dans cet article, vous trouverez un exemple avec CartPole et Policy Gradient avec une liste de poids et d'activation Softmax. Voici mon exemple recréé et très simple de gradient de politique CartPole, qui fonctionne parfaitement .
import gym
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures
import copy
NUM_EPISODES = 4000
LEARNING_RATE = 0.000025
GAMMA = 0.99
# noinspection PyMethodMayBeStatic
class Agent:
def __init__(self):
self.poly = PolynomialFeatures(1)
self.w = np.random.rand(5, 2)
def policy(self, state):
z = state.dot(self.w)
exp = np.exp(z)
return exp/np.sum(exp)
def __softmax_grad(self, softmax):
s = softmax.reshape(-1,1)
return np.diagflat(s) - np.dot(s, s.T)
def grad(self, probs, action, state):
dsoftmax = self.__softmax_grad(probs)[action,:]
dlog = dsoftmax / probs[0,action]
grad = state.T.dot(dlog[None,:])
return grad
def update_with(self, grads, rewards):
for i in range(len(grads)):
# Loop through everything that happend in the episode
# and update towards the log policy gradient times **FUTURE** reward
total_grad_effect = 0
for t, r in enumerate(rewards[i:]):
total_grad_effect += r * (GAMMA ** r)
self.w += LEARNING_RATE * grads[i] * total_grad_effect
print("Grads update: " + str(np.sum(grads[i])))
def main(argv):
env = gym.make('CartPole-v0')
np.random.seed(1)
agent = Agent()
complete_scores = []
for e in range(NUM_EPISODES):
state = env.reset()[None, :]
state = agent.poly.fit_transform(state)
rewards = []
grads = []
score = 0
while True:
probs = agent.policy(state)
action_space = env.action_space.n
action = np.random.choice(action_space, p=probs[0])
next_state, reward, done,_ = env.step(action)
next_state = next_state[None,:]
next_state = agent.poly.fit_transform(next_state.reshape(1, 4))
grad = agent.grad(probs, action, state)
grads.append(grad)
rewards.append(reward)
score += reward
state = next_state
if done:
break
agent.update_with(grads, rewards)
complete_scores.append(score)
env.close()
plt.plot(np.arange(NUM_EPISODES),
complete_scores)
plt.savefig('image1.png')
if __name__ == '__main__':
main(None)
.
.
Question
J'essaie de faire, presque le même exemple mais avec l'activation Sigmoid (juste pour plus de simplicité). C'est tout ce que je dois faire. Basculez l'activation dans le modèle de softmax
vers sigmoid
. Ce qui devrait fonctionner à coup sûr (basé sur l'explication ci-dessous). Mais mon modèle Policy Gradient n'apprend rien et reste aléatoire. Toute suggestion?
import gym
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures
NUM_EPISODES = 4000
LEARNING_RATE = 0.000025
GAMMA = 0.99
# noinspection PyMethodMayBeStatic
class Agent:
def __init__(self):
self.poly = PolynomialFeatures(1)
self.w = np.random.rand(5, 1) - 0.5
# Our policy that maps state to action parameterized by w
# noinspection PyShadowingNames
def policy(self, state):
z = np.sum(state.dot(self.w))
return self.sigmoid(z)
def sigmoid(self, x):
s = 1 / (1 + np.exp(-x))
return s
def sigmoid_grad(self, sig_x):
return sig_x * (1 - sig_x)
def grad(self, probs, action, state):
dsoftmax = self.sigmoid_grad(probs)
dlog = dsoftmax / probs
grad = state.T.dot(dlog)
grad = grad.reshape(5, 1)
return grad
def update_with(self, grads, rewards):
if len(grads) < 50:
return
for i in range(len(grads)):
# Loop through everything that happened in the episode
# and update towards the log policy gradient times **FUTURE** reward
total_grad_effect = 0
for t, r in enumerate(rewards[i:]):
total_grad_effect += r * (GAMMA ** r)
self.w += LEARNING_RATE * grads[i] * total_grad_effect
def main(argv):
env = gym.make('CartPole-v0')
np.random.seed(1)
agent = Agent()
complete_scores = []
for e in range(NUM_EPISODES):
state = env.reset()[None, :]
state = agent.poly.fit_transform(state)
rewards = []
grads = []
score = 0
while True:
probs = agent.policy(state)
action_space = env.action_space.n
action = np.random.choice(action_space, p=[1 - probs, probs])
next_state, reward, done, _ = env.step(action)
next_state = next_state[None, :]
next_state = agent.poly.fit_transform(next_state.reshape(1, 4))
grad = agent.grad(probs, action, state)
grads.append(grad)
rewards.append(reward)
score += reward
state = next_state
if done:
break
agent.update_with(grads, rewards)
complete_scores.append(score)
env.close()
plt.plot(np.arange(NUM_EPISODES),
complete_scores)
plt.savefig('image1.png')
if __name__ == '__main__':
main(None)
Tracer tout l'apprentissage reste aléatoire. Rien ne sert à régler les hyper paramètres. Sous l'image d'exemple.
Références :
1) Apprentissage par renforcement profond: Pong des pixels
2) Une introduction aux gradients politiques avec Cartpole et Doom
3) Dérivation des gradients de politique et mise en œuvre de RENFORCEMENT
4) Astuce d'apprentissage automatique du jour (5): Astuce dérivée de journal 12
MISE À JOUR
On dirait que la réponse ci-dessous pourrait faire du travail à partir du graphique. Mais ce n'est pas une probabilité logarithmique, ni même un gradient de la politique. Et change tout l'objet de la politique de dégradé RL. Veuillez vérifier les références ci-dessus. Après l'image, nous avons la déclaration suivante.
J'ai besoin de prendre un dégradé de la fonction de journal de ma politique (qui est simplement des poids et une sigmoid
activation).
softmax
àsignmoid
. C'est seulement une chose que je dois faire dans l'exemple ci-dessus.[0, 1]
qui peut être interprétée comme une probabilité d'action positive (tourner à droite dans CartPole, par exemple). La probabilité d'une action négative (tourner à gauche) est alors1 - sigmoid
. La somme de ces probabilités est 1. Oui, il s'agit d'un environnement de carte polaire standard.Réponses:
Le problème vient de la
grad
méthode.Dans le code d'origine, Softmax était utilisé avec la fonction de perte CrossEntropy. Lorsque vous basculez l'activation sur Sigmoid, la fonction de perte appropriée devient CrossEntropy binaire. Maintenant, le but de la
grad
méthode est de calculer le gradient de la fonction de perte wrt. poids. En épargnant les détails, un gradient approprié est donné par(probs - action) * state
dans la terminologie de votre programme. La dernière chose est d'ajouter le signe moins - nous voulons maximiser le négatif de la fonction de perte.Une
grad
méthode appropriée donc:Un autre changement que vous voudrez peut-être ajouter est d'augmenter le taux d'apprentissage.
LEARNING_RATE = 0.0001
etNUM_EPISODES = 5000
produira l'intrigue suivante:La convergence sera beaucoup plus rapide si les poids sont initialisés en utilisant la distribution gaussienne avec une moyenne nulle et une petite variance:
MISE À JOUR
Ajout d'un code complet pour reproduire les résultats:
la source
sigmoid
. Mais votre gradient en réponse ne devrait rien à voir avec mon gradient. Droite?(action - probs) * sigmoid_grad(probs)
, mais j'ai omis ensigmoid_grad
raison du problème de fuite avec le gradient sigmoïde.action = 1
, on veutprobs
se rapprocher1
, augmenter les poids (gradient positif). Siaction=0
nous voulonsprobs
être plus proches0
, donc diminuer les poids (gradient négatif).(action - probs)
c'est juste une autre façon de changer les mêmes poids.