web-dev-qa-db-ja.com

俳優批評家の政策損失がゼロになる(改善なし)

いくつかのOpenAIジム環境をテストするために、俳優評論家モデルを作成しました。ただし、一部の環境で問題が発生しています。

CartPole:モデルは最終的に収束し、最大の報酬を達成します。ただし、何らかの理由で、値関数/利点ではなく、ポリシー勾配法のみを使用すると、収束が速くなります。

MountainCar、Acrobot:これら2つのモデルにはマイナスの見返りがあります。エージェントがタスクを解決するのに10秒かかる場合、報酬は-10になります。何らかの理由で、負の報酬のある環境を解決しようとすると、ポリシーは負の値から始まり、ゆっくりと0に収束します。値の損失は、ある時点(ポリシーが崩壊したとき)で横ばいになりますが、途方もなく高く始まり、減少し始めます。誰かが私が問題を診断するのを手伝ってくれる?関連する一時的な値を含むいくつかのロギングステートメントを追加しました。

from scipy.signal import lfilter
import numpy as np
import gym
import tensorflow as tf

layers = tf.keras.layers

tf.enable_eager_execution()


def discount(x, gamma):
    return lfilter([1], [1, -gamma], x[::-1], axis=0)[::-1]


def boltzmann(probs):
    return tf.multinomial(tf.log(probs), 1)


def greedy(probs):
    return tf.argmax(probs)


def gae(bval, vals, rews):
    vboot = np.hstack((vals, bval))
    return rews * vboot[1:] - vals


class PG(tf.keras.Model):

    def __init__(self, n_actions, selection_strategy=boltzmann, lr=0.001):
        super(PG, self).__init__()
        self.fc1 = layers.Dense(64, activation='relu', kernel_initializer=tf.initializers.orthogonal(1))
        self.fc2 = layers.Dense(64, activation='relu', kernel_initializer=tf.initializers.orthogonal(1))
        self.pol = layers.Dense(n_actions, kernel_initializer=tf.initializers.orthogonal(0.01))
        self.val = layers.Dense(1, kernel_initializer=tf.initializers.orthogonal(1))
        self.optimizer = tf.train.AdamOptimizer(learning_rate=lr)
        self.selection_strategy = selection_strategy


    def call(self, input):
        x = tf.constant(input, dtype=tf.float32)
        x = self.fc1(x)
        x = self.fc2(x)
        return self.pol(x), self.val(x)


    def select_action(self, logits):
        probs = tf.nn.softmax(logits)
        a = self.selection_strategy(probs)
        return tf.squeeze(a, axis=[0, 1]).numpy()


def sample(env, model):
    obs, act, rews, vals = [], [], [], []
    ob = env.reset()
    done = False

    while not done:
        # env.render()
        logits, value = model([ob])
        a = model.select_action(logits)
        value = tf.squeeze(value, axis=[0, 1])

        next_ob, r, done, _ = env.step(a)
        obs.append(ob)
        act.append(a)
        rews.append(r)
        vals.append(value.numpy())

        ob = next_ob

    return np.array(obs), np.array(act), np.array(rews), np.array(vals)


# Hyperparameters
GAMMA = 0.99
SAMPLES = 10000000
MAX_GRAD_NORM = 20
UPDATE_INTERVAL = 20


env = gym.make('MountainCar-v0')
model = PG(env.action_space.n)


for t in range(1, SAMPLES + 1):
    obs, act, rews, vals = sample(env, model)
    d_rew = discount(rews, GAMMA)
    d_rew = (d_rew - np.mean(d_rew)) / np.std(d_rew)

    advs = d_rew - vals


    with tf.GradientTape() as tape:

        logits, values = model(obs)
        values = tf.squeeze(values)
        one_hot = tf.one_hot(act, env.action_space.n, dtype=tf.float32)
        xentropy = tf.nn.softmax_cross_entropy_with_logits_v2(labels=one_hot, logits=logits)
        policy_loss = tf.reduce_mean(xentropy * advs)

        diff = d_rew - values

        value_loss = tf.reduce_mean(tf.square(diff))

        policy = tf.nn.softmax(logits)
        entropy = tf.reduce_mean(policy * tf.log(policy + 1e-20))

        total_loss = policy_loss + 0.5 * value_loss - 0.01 * entropy


    grads = tape.gradient(total_loss, model.trainable_weights)
    grads, gl_norm = tf.clip_by_global_norm(grads, MAX_GRAD_NORM)
    model.optimizer.apply_gradients(Zip(grads, model.trainable_weights))


    if t % UPDATE_INTERVAL == 0 and not t is 0:
        print("BR: {0}, Len: {1}, Pol: {2:.4f}, Val: {3:.4f}, Ent: {4:.4f}"
              .format(np.sum(rews), len(rews), policy_loss, value_loss, entropy))

ER =総報酬、Len =エピソードの長さ、Pol =ポリシーの損失、Val =価値の損失、Ent =エントロピー、勾配ノルム=勾配ノルム

ER: -200.0, Len: 200, Pol: 0.0656, Val: 1.0032, Ent: -0.3661, Grad Norm: 0.0901
ER: -200.0, Len: 200, Pol: -0.0384, Val: 1.0006, Ent: -0.3640, Grad Norm: 0.1186
ER: -200.0, Len: 200, Pol: -0.0585, Val: 1.0034, Ent: -0.3605, Grad Norm: 0.0963
ER: -200.0, Len: 200, Pol: -0.0650, Val: 1.0021, Ent: -0.3595, Grad Norm: 0.1149
ER: -200.0, Len: 200, Pol: 0.0007, Val: 1.0011, Ent: -0.3581, Grad Norm: 0.0893
ER: -200.0, Len: 200, Pol: 0.0024, Val: 1.0007, Ent: -0.3556, Grad Norm: 0.0951
ER: -200.0, Len: 200, Pol: 0.0114, Val: 1.0006, Ent: -0.3529, Grad Norm: 0.0954
ER: -200.0, Len: 200, Pol: 0.0310, Val: 1.0006, Ent: -0.3493, Grad Norm: 0.1060
ER: -200.0, Len: 200, Pol: -0.0187, Val: 0.9997, Ent: -0.3449, Grad Norm: 0.1111
ER: -200.0, Len: 200, Pol: -0.0367, Val: 0.9975, Ent: -0.3348, Grad Norm: 0.1302
ER: -200.0, Len: 200, Pol: -0.0349, Val: 0.9988, Ent: -0.3250, Grad Norm: 0.0884

私があなたの質問に完全に答えることができるかどうかはわかりませんが、私は私の2セントを提供し、うまくいけば誰かが来て残りを埋めます!

モデルは最終的に収束し、最大の報酬を達成します。ただし、何らかの理由で、値関数/利点ではなく、ポリシー勾配法のみを使用すると、収束が速くなります。

これは、CartPoleには、左または右に移動する非常に単純なアクションスペースがあるためです。この問題の解決策は非常に単純であり、システムに追加された非常に基本的なノイズは、システムがその状態空間を探索するのに十分である可能性があります。アクター批評家の方法では、より多くの重みとバイアスを調整する必要があります。また、調整するパラメータが多いため、トレーニング時間が長くなります。

何らかの理由で、負の報酬のある環境を解決しようとすると、ポリシーは負の値から始まり、ゆっくりと0に収束します。

xentropy = tf.nn.softmax_cross_entropy_with_logits_v2(labels=one_hot, logits=logits)
    policy_loss = tf.reduce_mean(xentropy * advs)

この部分に関しては、実際の損失の定式化は

Loss = - log(policy) * Advantage

I https://math.stackexchange.com/questions/2730874/cross-entropy-loss-in-reinforcement-learning などのネガティブがある場合。あなたの定式化では、この負の値を損失関数に含めたかどうかはわかりません。 Policy Gradientを作成したときに、個人的に独自の損失関数を作成しましたが、Tensorflow関数がこれを考慮している可能性があります。

値については、基本的に最適値を推測しているため、最初は大きな損失が予想されます。

いくつかの追加のヒントとコツは、状態、アクション、報酬、およびs2にリプレイメモリを使用することです。このように、あなたはあなたの軌道を無相関化し、それは「均等な」学習を可能にします。あなたの州が相関している場合、それはあなたの最近の出来事に過剰適合する傾向があります。

また、現在オンラインで学習していますが、これはより難しいRLタスクでは非常に不安定です。これを支援する1つの方法は、上記のリプレイメモリを使用することです。別の方法はミニバッチで学習することです。 。そして、これはDavid Silverが彼の論文で使用した方法だと思います。基本的には、多くの軌道を実行する必要があります。各軌道の後で、バックプロパゲーションを実行して、TensorFlowのtf.gradientsメソッドを介してポリシー勾配の損失を計算します。これらの勾配を保存します。 、そして次のいくつかの軌道に対してこれを再度実行します。「ミニバッチ」量の軌道の後、すべての実行にわたってすべての勾配を平均し、勾配降下を実行してパラメーターを更新します。勾配降下は、何と同じように実行されます。 tf.apply_gradientsメソッドを使用してコードで実行しました。これを行うのは、環境にノイズが多いためです。多くの軌道をシミュレートすることにより、ミニバッチの平均軌道は1つの軌道ではなく、より確率的な表現になるという考えです。私は音響的に64のミニバッチを使用します。

状態空間での探索を強化するために、OrnsteinUlhenbeck確率過程をお勧めします。基本的に、これは安定した相関ノイズシステムです。相関ノイズであるため、非相関ノイズ(つまり、ガウスノイズ)を使用した場合よりも、初期状態から遠く離れて歩くことができます。非相関ノイズを使用する場合、平均が0であるため、長期平均は0になるため、単位分散。したがって、基本的に、非相関ノイズを使用すると、開始した場所に正確に到達することになります。良い説明はここにあります: https://www.quora.com/Why-do-we-use-the-Ornstein-Uhlenbeck-Process-in-the-exploration-of-DDPG そしてPythonのコードはここにあります: https://github.com/openai/baselines/blob/master/baselines/ddpg/noise.py atコードの一番下。このノイズをアクションに追加するだけで、探索が向上します。

概要

ポリシーの損失関数の標識が正しくない可能性があります。学習を改善するために、難しい問題のオンライン学習は非常に困難です。これを解決するための2つの簡単な実装方法は次のとおりです。

  • リプレイメモリー
  • 現在コードにある確率的勾配降下法ではなく、ミニバッチ最急降下法

安定性を高めるために、ターゲットネットワークを使用することもできます。ターゲットネットワークの考え方は、初期段階では重みが非常に速く更新されるためです。代わりに、ターゲットネットワークがシステム内にあり、問題を「移動しないターゲット」の問題にします。ターゲットネットワークの重みが凍結されているため、問題は動かず、各エピソードの後に​​「実際の」ネットワークが更新されます。そして、x回の反復の後、ターゲットネットワークを実際のネットワークに更新します。ただし、これは実装に時間がかかります。最初に上記の2つをお勧めします。

1
Rui Nian