Понимание получения градиентной политики

19

Я пытаюсь воссоздать очень простой пример 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активация).

GensaGames
источник
4
Я предлагаю вам опубликовать этот вопрос на Data Science Stack Exchange, поскольку это в основном теоретический вопрос (переполнение стека в основном для вопросов кодирования). Вы также достигнете большего количества людей, знающих в этой области.
Жиль-Филипп Пайе
@ Gilles-PhilippePaillé Я добавил код, который представляет проблему. Что мне нужно сделать, так это просто исправить некоторые детали с помощью активации. Пожалуйста, проверьте обновленный ответ.
GensaGames
1
Для получения градиентов политики, вот справочная статья с рабочим примером того же типа соглашений, надеюсь, вы узнаете подробно: medium.com/@thechrisyoon/… .
Мухаммед Усман
@MuhammadUsman. Спасибо за информацию. Я красный этот источник. Прямо сейчас это ясно и пример выше, я пытаюсь изменить активацию с softmaxна signmoid. Это только одна вещь, которую мне нужно сделать в примере выше.
GensaGames
2
Сигмоид @JasonChia выводит действительное число в диапазоне, [0, 1]которое можно интерпретировать как вероятность положительного действия (например, повернуть направо в CartPole). Тогда вероятность негативного действия (поворот налево) равна 1 - sigmoid. Сумма этих вероятностей равна 1. Да, это стандартная среда полюсных карт.
Павел Тышевский

Ответы:

8

Проблема в gradметоде.

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

В оригинальном коде Softmax использовался вместе с функцией потери CrossEntropy. Когда вы переключаете активацию на Sigmoid, правильная функция потери становится Binary CrossEntropy. Теперь целью gradметода является вычисление градиента функции потерь относительно. веса. Сохраняя детали, правильный градиент задается (probs - action) * stateв терминологии вашей программы. Последнее, что нужно добавить, это добавить знак минус - мы хотим максимизировать отрицательный результат функции потерь.

Правильный gradметод, таким образом:

def grad(self, probs, action, state):
    grad = state.T.dot(probs - action)
    return -grad

Еще одно изменение, которое вы можете добавить, - увеличить скорость обучения. LEARNING_RATE = 0.0001и NUM_EPISODES = 5000будет производить следующий участок:

Правильная средняя награда против количества эпизодов

Сходимость будет намного быстрее, если веса инициализируются с использованием гауссовского распределения с нулевым средним и малой дисперсией:

def __init__(self):
    self.poly = PolynomialFeatures(1)
    self.w = np.random.randn(5, 1) * 0.01

введите описание изображения здесь

ОБНОВИТЬ

Добавлен полный код для воспроизведения результатов:

import gym
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures

NUM_EPISODES = 5000
LEARNING_RATE = 0.0001
GAMMA = 0.99


# noinspection PyMethodMayBeStatic
class Agent:
    def __init__(self):
        self.poly = PolynomialFeatures(1)
        self.w = np.random.randn(5, 1) * 0.01

    # 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):
        grad = state.T.dot(probs - action)
        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)
Павел Тышевский
источник
Большое спасибо. Я попробую это решение позже.
GensaGames
Я не уверен, где вы берете такой вывод для моей функции. Как вы можете проверить изображение выше. Мне нужно было бы взять градиент журнала политики . Где политика в моем случае просто весит sigmoid. Но ваш градиент в ответе не должен иметь ничего общего с моим градиентом. Правильно?
GensaGames
Обратите внимание, что вы не включаете информацию о том, какое действие было выполнено. Согласно этой лекции о градиентах политики (слайд 13) , обновление должно выглядеть примерно так (action - probs) * sigmoid_grad(probs), но я пропустил sigmoid_gradиз-за исчезающей проблемы с сигмовидным градиентом.
Павел Тышевский
Суть здесь в том, чтобы указать направление, в котором мы хотим изменить вес. Если action = 1мы хотим probsбыть ближе к 1увеличению веса (положительный градиент). Если action=0мы хотим probsбыть ближе к 0, следовательно, уменьшение веса (отрицательный градиент).
Павел Тышевский
1
В любом случае вышеприведенные изменения не работают вообще, вы можете поделиться целым файлом? В то же время я хочу сделать четкую выборку, и в данном случае мне плевать на исчезающую проблему. И (action - probs)это просто еще один способ изменить то же самое.
GensaGames