Próbuję odtworzyć bardzo prosty przykład zasady Gradient, z jego bloga źródłowego blogu Andreja Karpathy'ego . W tym artykule znajdziesz przykład z CartPole i Policy Gradient z listą masy i aktywacją Softmax. Oto mój odtworzony i bardzo prosty przykład gradientu zasad CartPole, który działa idealnie .
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)
.
.
Pytanie
Próbuję zrobić, prawie ten sam przykład, ale z aktywacją Sigmoid (tylko dla uproszczenia). To wszystko, co muszę zrobić. Przełącz aktywację w modelu z softmax
na sigmoid
. Które powinny na pewno zadziałać (na podstawie poniższych wyjaśnień). Ale mój model Gradientu zasad niczego się nie uczy i zachowuje losowość. Jakieś sugestie?
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)
Spisywanie całej nauki jest losowe. Nic nie pomaga w dostrajaniu hiper parametrów. Poniżej przykładowego obrazu.
Referencje :
1) Nauka głębokiego wzmacniania: Pong z pikseli
2) Wprowadzenie do Gradientów polityki z Cartpole i Doom
AKTUALIZACJA
Wygląda na to, że odpowiedź poniżej może trochę popracować z grafiką. Ale to nie jest log prawdopodobieństwa, ani nawet gradientu polityki. I zmienia cały cel RL Gradient Policy. Sprawdź referencje powyżej. Po obrazie następna wypowiedź.
Muszę wziąć funkcję Gradient dziennika w mojej Polityce (która jest po prostu wagą i sigmoid
aktywacją).
softmax
nasignmoid
. To tylko jedna rzecz, którą muszę zrobić w powyższym przykładzie.[0, 1]
który można interpretować jako prawdopodobieństwo pozytywnego działania (na przykład skręć w prawo w CartPole). Wtedy prawdopodobieństwo negatywnego działania (skręć w lewo) jest1 - sigmoid
. Suma tych prawdopodobieństw wynosi 1. Tak, jest to standardowe środowisko karty biegunowej.Odpowiedzi:
Problem dotyczy
grad
metody.W oryginalnym kodzie użyto Softmax wraz z funkcją utraty CrossEntropy. Po zmianie aktywacji na Sigmoid właściwą funkcją utraty staje się Binary CrossEntropy. Teraz celem tej
grad
metody jest obliczenie gradientu funkcji straty wrt. ciężary Oszczędzając szczegóły, właściwy(probs - action) * state
termin podano w terminologii twojego programu. Ostatnią rzeczą jest dodanie znaku minus - chcemy zmaksymalizować minus funkcji straty.Właściwa
grad
metoda:Kolejną zmianą, którą możesz chcieć dodać, jest zwiększenie szybkości uczenia się.
LEARNING_RATE = 0.0001
iNUM_EPISODES = 5000
wyprodukuje następujący wykres:Konwergencja będzie znacznie szybsza, jeśli wagi zostaną zainicjowane przy użyciu rozkładu Gaussa z zerową średnią i małą wariancją:
AKTUALIZACJA
Dodano pełny kod do odtworzenia wyników:
źródło
sigmoid
. Ale twój gradient w odpowiedzi nie powinien mieć nic wspólnego z moim gradientem. Dobrze?(action - probs) * sigmoid_grad(probs)
, ale pominąłem ją zsigmoid_grad
powodu znikającego problemu z gradientem sigmoidalnym.action = 1
chcemyprobs
być bliżej1
, zwiększając wagi (gradient dodatni). Jeśliaction=0
chcemyprobs
być bliżej0
, to zmniejszamy wagi (gradient ujemny).(action - probs)
to tylko kolejny sposób zmiany tych samych poglądów.