Zrozumienie pochodnej polityki gradientowej


19

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)

wprowadź opis zdjęcia tutaj

.

.

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 softmaxna 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.

wprowadź opis zdjęcia tutaj

Referencje :

1) Nauka głębokiego wzmacniania: Pong z pikseli

2) Wprowadzenie do Gradientów polityki z Cartpole i Doom

3) Wyprowadzanie gradientów polityki i wdrażanie REINFORCE

4) Trik dnia w uczeniu maszynowym (5): Log Trick Derick 12


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ź.

wprowadź opis zdjęcia tutaj

Muszę wziąć funkcję Gradient dziennika w mojej Polityce (która jest po prostu wagą i sigmoidaktywacją).


4
Sugeruję, abyś zamieścił to pytanie na Data Science Stack Exchange, ponieważ jest to głównie pytanie teoretyczne (przepełnienie stosu dotyczy głównie kodowania pytań). Dotrzesz także do większej liczby osób posiadających wiedzę w tej dziedzinie.
Gilles-Philippe Paillé

@ Gilles-PhilippePaillé Dodałem kod, który reprezentuje problem. To, co muszę zrobić, to naprawić niektóre części za pomocą aktywacji. Sprawdź zaktualizowaną odpowiedź.
GensaGames,

1
Aby wyprowadzić gradienty zasad, oto artykuł referencyjny z działającym przykładem tego samego rodzaju uzgodnień. Mam nadzieję, że dowiesz się szczegółowo: medium.com/@thechrisyoon/… .
Muhammad Usman,

@MuhammadUsman. Dziękuję za informację. Redytuję to źródło. W tej chwili jest to jasne i powyższy przykład. Próbuję zmienić aktywację z softmaxna signmoid. To tylko jedna rzecz, którą muszę zrobić w powyższym przykładzie.
GensaGames,

2
@JasonChia sigmoid generuje liczbę rzeczywistą w zakresie, [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) jest 1 - sigmoid. Suma tych prawdopodobieństw wynosi 1. Tak, jest to standardowe środowisko karty biegunowej.
Pavel Tyshevskyi

Odpowiedzi:


8

Problem dotyczy gradmetody.

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

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 gradmetody jest obliczenie gradientu funkcji straty wrt. ciężary Oszczędzając szczegóły, właściwy (probs - action) * statetermin podano w terminologii twojego programu. Ostatnią rzeczą jest dodanie znaku minus - chcemy zmaksymalizować minus funkcji straty.

Właściwa gradmetoda:

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

Kolejną zmianą, którą możesz chcieć dodać, jest zwiększenie szybkości uczenia się. LEARNING_RATE = 0.0001i NUM_EPISODES = 5000wyprodukuje następujący wykres:

Prawidłowa średnia nagroda vs. liczba odcinków

Konwergencja będzie znacznie szybsza, jeśli wagi zostaną zainicjowane przy użyciu rozkładu Gaussa z zerową średnią i małą wariancją:

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

wprowadź opis zdjęcia tutaj

AKTUALIZACJA

Dodano pełny kod do odtworzenia wyników:

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)

Dziękuję Ci bardzo. Wypróbuję to rozwiązanie później.
GensaGames,

Nie jestem pewien, skąd bierzesz takie pochodne dla mojej funkcji. Jak możesz sprawdzić obrazek powyżej. Musiałbym wziąć gradient dziennika polisy . Gdzie Polityka w moim przypadku jest po prostu ważna sigmoid. Ale twój gradient w odpowiedzi nie powinien mieć nic wspólnego z moim gradientem. Dobrze?
GensaGames,

Zauważ, że nie dołączasz żadnych informacji o tym, jakie działanie zostało wykonane. Zgodnie z wykładem na temat Gradientów Polityki (slajd 13) aktualizacja powinna wyglądać (action - probs) * sigmoid_grad(probs), ale pominąłem ją z sigmoid_gradpowodu znikającego problemu z gradientem sigmoidalnym.
Pavel Tyshevskyi

Najważniejsze jest tutaj wskazanie kierunku, w którym chcemy zmieniać wagi. Jeśli action = 1chcemy probsbyć bliżej 1, zwiększając wagi (gradient dodatni). Jeśli action=0chcemy probsbyć bliżej 0, to zmniejszamy wagi (gradient ujemny).
Pavel Tyshevskyi

1
W każdym razie powyższe zmiany w ogóle nie działają, czy możesz udostępnić cały plik? W tym samym czasie chcę zrobić wyraźną próbkę i nie dbam o zniknięcie problemu w tym przypadku. I (action - probs)to tylko kolejny sposób zmiany tych samych poglądów.
GensaGames,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.