Я пытаюсь воссоздать очень простой пример Policy Gradient из исходного ресурса блога Andrej Karpathy . В этой статье вы найдете пример с CartPole и Policy Gradient со списком веса и активацией Softmax. Вот мой воссозданный и очень простой пример градиента политики CartPole, который отлично работает .
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)
,
,
Вопрос
Я пытаюсь сделать, почти тот же пример, но с активацией Sigmoid (просто для простоты). Это все, что мне нужно сделать. Переключить активацию в модели с softmax
на sigmoid
. Который должен работать наверняка (на основе объяснения ниже). Но моя модель градиента политики ничего не изучает и держит случайным образом. Любое предложение?
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)
Построение всего обучения ведется случайным образом. Ничто не помогает с настройкой гиперпараметров. Ниже образец изображения.
Рекомендации :
1) Обучение глубокому усилению: понг из пикселей
2) Введение в градиенты политики с помощью Cartpole и Doom
3) Извлечение градиентов политики и внедрение REINFORCE
4) Уловка дня машинного обучения (5): Уловка деривации логарифма 12
ОБНОВИТЬ
Похоже, ответ ниже может сделать некоторую работу из графики. Но это не логарифмическая вероятность, и даже не градиент политики. И меняет всю цель Политики Градиента RL. Пожалуйста, проверьте ссылки выше. Вслед за изображением у нас следующее утверждение.
Мне нужно использовать градиент функции лога моей политики (это просто веса и sigmoid
активация).
softmax
наsignmoid
. Это только одна вещь, которую мне нужно сделать в примере выше.[0, 1]
которое можно интерпретировать как вероятность положительного действия (например, повернуть направо в CartPole). Тогда вероятность негативного действия (поворот налево) равна1 - sigmoid
. Сумма этих вероятностей равна 1. Да, это стандартная среда полюсных карт.Ответы:
Проблема в
grad
методе.В оригинальном коде Softmax использовался вместе с функцией потери CrossEntropy. Когда вы переключаете активацию на Sigmoid, правильная функция потери становится Binary CrossEntropy. Теперь целью
grad
метода является вычисление градиента функции потерь относительно. веса. Сохраняя детали, правильный градиент задается(probs - action) * state
в терминологии вашей программы. Последнее, что нужно добавить, это добавить знак минус - мы хотим максимизировать отрицательный результат функции потерь.Правильный
grad
метод, таким образом:Еще одно изменение, которое вы можете добавить, - увеличить скорость обучения.
LEARNING_RATE = 0.0001
иNUM_EPISODES = 5000
будет производить следующий участок:Сходимость будет намного быстрее, если веса инициализируются с использованием гауссовского распределения с нулевым средним и малой дисперсией:
ОБНОВИТЬ
Добавлен полный код для воспроизведения результатов:
источник
sigmoid
. Но ваш градиент в ответе не должен иметь ничего общего с моим градиентом. Правильно?(action - probs) * sigmoid_grad(probs)
, но я пропустилsigmoid_grad
из-за исчезающей проблемы с сигмовидным градиентом.action = 1
мы хотимprobs
быть ближе к1
увеличению веса (положительный градиент). Еслиaction=0
мы хотимprobs
быть ближе к0
, следовательно, уменьшение веса (отрицательный градиент).(action - probs)
это просто еще один способ изменить то же самое.