質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.80%

強化学習 pythonを用いた方策勾配の実装で困っています

受付中

回答 0

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 829

Luisu

score 10

お世話になります。
初めての質問です。
宜しくお願い致します。

やりたいこと: 方策勾配を用いて報酬を最大化したい。
わからないこと: NNを用いた場合の方策勾配の実装が合っているか、そもそも全体の実装コードが悪いのか。

NeuralNetworkを用いて方策勾配を求めてパラメータを更新して学習させたいのですが上手くいきません。
環境のCartPole問題を用いて常にポール直立させたいのですが学習が上手く行っておらず、すぐに倒れてしまします。
以下が実装したコードです。改善すべき箇所があれば御指摘を頂きたいです。
宜しくお願い致します。

import numpy as np
import gym
import matplotlib.pyplot as plt
%matplotlib inline

np.random.seed(0)

def e_greedy(prediction_action, epsilon_percentage, start_epsilon=0.5, end_epsilon=0.001):
    epsilon = start_epsilon * (1 - epsilon_percentage) + end_epsilon * epsilon_percentage
    if np.random.rand() < epsilon:
        return np.random.randint(len(prediction_action[0]))
    else:
        return prediction_action[0].argmax()

class Agent:
    def __init__(self, state_size=4, action_size=2):
        self.parms = {
            'W1': np.random.randn(state_size, 16) * np.sqrt(2) * np.sqrt(6 / (state_size + 16)),
            'B1': np.zeros(16),
            'W2': np.random.randn(16, 16) * np.sqrt(2) * np.sqrt(6 / (16 + 16)),
            'B2': np.zeros(16),
            'W3': np.random.randn(16, action_size) * np.sqrt(2) * np.sqrt(6 / (16 + action_size)),
            'B3': np.zeros(action_size),
        }
        self.grads = {}

    def prediction(self, x):
        self.x = x
        self.ih = np.dot(self.x, self.parms['W1']) + self.parms['B1']
        # Relu
        ih_relu = self.ih.copy()
        ih_relu[ih_relu < 0] = 0

        self.hh = np.dot(ih_relu, self.parms['W2']) + self.parms['B2']
        # Relu
        hh_relu = self.hh.copy()
        hh_relu[hh_relu < 0] = 0

        self.ho = np.dot(hh_relu, self.parms['W3']) + self.parms['B3']
        # softmax
        exp = np.exp(self.ho - np.max(self.ho))
        self.y = exp / np.sum(exp)
        return self.y

    def gradient(self, dx=1):
        # Softmax Backward
        dx = self.y - dx
        self.grads['B3'] = np.sum(dx, 0)
        self.grads['W3'] = np.dot(self.hh.T, dx)
        dx = np.dot(dx, self.parms['W3'].T)

        # Relu Backward
        dx[dx < 0] = 0
        self.grads['B2'] = np.sum(dx, 0)
        self.grads['W2'] = np.dot(self.ih.T, dx)
        dx = np.dot(dx, self.parms['W2'].T)

        # Relu Backward
        dx[dx < 0] = 0
        self.grads['B1'] = np.sum(dx, 0)
        self.grads['W1'] = np.dot(self.x.T, dx)
        dx = np.dot(dx, self.parms['W1'].T)

    def fit(self, state, action ,reward):
        y = self.prediction(state)

        # j = - 1 / M * log(y) * R
        loss = - np.mean(np.log(y[np.arange(y.shape[0]), action]) * reward)
        grad_loss = y
        # grad_j = 1 / y * R
        grad_loss[np.arange(y.shape[0]), action] = 1 / y[np.arange(y.shape[0]), action] * reward

        # 勾配を求める
        self.gradient(grad_loss)

        #更新
        self.Updata()

        return loss

    def Updata(self, lr=0.01):
        for key in self.parms.keys():
            self.parms[key] -= lr * self.grads[key]

def discount_rewards(rewards, gamma=0.98):
    Rewards = np.zeros_like(rewards)
    r = 0.
    for t in reversed(range(len(rewards))):
        r = rewards[t] + r * gamma
        Rewards[t] = r
    return Rewards

class Buffer_hist:
    def __init__(self):
        self.states = []
        self.actions = []
        self.rewards = []
        self.next_state = []
        self.discounted_returns = []

    def add_buffer(self, state, action, reward, next_state):
        self.states.append(state)
        self.actions.append(action)
        self.rewards.append(reward)
        self.next_state.append(next_state)

class Buffer:
    def __init__(self):
        self.states = []
        self.actions = []
        self.discounted_returns = []

    def add(self, hist):
        self.states += hist.states
        self.actions += hist.actions
        self.discounted_returns += list(hist.discounted_returns)

    def reset_buffer(self):
        self.states = []
        self.actions = []
        self.discounted_returns = []


class Train:
    def __init__(self, episode=5001, epsilon_stop=3000):
        self.episode = episode
        self.epsilon_stop = epsilon_stop
        self.env = gym.make('CartPole-v0')
        self.agent = Agent()

    def play(self):
        self.Rewards = []
        self.batch_loss = []
        global_buffer = Buffer()

        for t in range(self.episode):
            state = self.env.reset()
            episode_reward = 0.
            episode_hist = Buffer_hist()
            epsilon_percentage = float(min(t / float(self.epsilon_stop), 1.))
            done = False

            while not done:
                action = e_greedy(self.agent.prediction([state]), epsilon_percentage)
                next_state, reward, done, _ = self.env.step(action)
                episode_hist.add_buffer(state, action, reward, next_state)
                state = next_state
                episode_reward += reward

                if done:
                    episode_hist.discounted_returns = discount_rewards(episode_hist.rewards)
                    global_buffer.add(episode_hist)

                    # エピソード8回ごとに学習
                    if t % 8 == 0:
                        loss = self.agent.fit(
                            np.array(global_buffer.states),
                            np.array(global_buffer.actions),
                            np.array(global_buffer.discounted_returns)
                        )
                        global_buffer.reset_buffer()

                    self.Rewards.append(episode_reward)
                    self.batch_loss.append(loss)

                    if t % 250 == 0:
                        print('episode: {} total reward: {}'.format(t, episode_reward))

T = Train()
T.play()
plt.plot(T.Rewards)
plt.plot(T.batch_loss)

追伸

色々と方策勾配の実装について調べても見たのですが、ほとんどがTensorflowやkerasなどのライブラリを用いた実装ばかりで参考になりません。できればライブラリを使わずに実装したいです。
宜しくお願い致します。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正の依頼

  • tiitoi

    2019/04/05 16:03 編集

    > ほとんどがTensorflowやkerasなどのライブラリを用いた実装ばかりで参考になりません。

    ニューラルネットワークをライブラリを使わずに実装するのは、逆伝播法とか全部自前で実装する必要があるので、「深層強化学習」を実装するという目的、本質からそれて、かなり遠回りすることになるのでオススメできません。
    数値計算するのに、numpy を使わずに行列積とかを全部自前で実装したいと言っているようなものです。
    深層強化学習をしたいのであれば、Tensorflow や PyTorch などのライブラリを使いましょう。

    キャンセル

  • Luisu

    2019/04/05 16:23

    ご回答有難う御座います。
    本質からは遠回りですが、ライブラリに頼って依存してしまうと他の言語で実装したい場合に不都合なので出来れば、依存しない方向で行きたいです。

    キャンセル

まだ回答がついていません

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.80%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る