web-dev-qa-db-ja.com

RLのProximal Policy Optimization Algorithmを理解する方法は何ですか?

私は強化学習の基本を知っていますが、読むことができるために理解する必要がある用語は何ですか arxiv PPO paper

[〜#〜] ppo [〜#〜] を学習して使用するためのロードマップは何ですか?

31

PPOをよりよく理解するには、次のような論文の主な貢献を見ると役立ちます。(1) Clipped Surrogate Objectiveおよび(2)「複数のエポックの確率的勾配上昇各ポリシーの更新を実行します」。


最初に、これらの点を元の点に基づいて PPO論文

複数のエポックの確率的勾配上昇を使用して各ポリシー更新を実行するポリシー最適化手法のファミリーである[PPO]を導入しました。これらのメソッドは、trust-region [ [〜#〜] trpo [〜#〜] ]メソッドの安定性と信頼性を備えていますが、実装がはるかに簡単で、より一般的な設定に適用可能なバニラポリシーグラデーションの実装(たとえば、ポリシーとバリュー関数に共同アーキテクチャを使用する場合)、全体的なパフォーマンスが向上します。


1.クリップされた代理対物レンズ

Clipped Surrogate Objectiveは、各ステップでポリシーに加えた変更を制限することでトレーニングの安定性を向上させるように設計されたポリシーグラデーション目標のドロップイン置換です。

バニラポリシーの勾配(例:REINFORCE)---よく知っている必要がある、または これを理解する前に==に精通している -ニューラルネットワークを最適化するために使用される目的は次のようになります

PG objective

これは、 Sutton book および otherresources で見られる標準的な式であり、アドバンテージ(ハット)はしばしば置き換えられます割引リターン。ネットワークパラメータに関してこの損失に対して勾配上昇ステップを実行することにより、より高い報酬につながるアクションをインセンティブにします。

バニラポリシー勾配法では、アクションの対数確率(logπ(a | s))を使用してアクションの影響を追跡しますが、別の関数を使用してこれを行うことを想像できます。 このペーパー で導入された別のそのような関数は、current policy(π(a | s))の下でのアクションの確率を、あなたの下でのアクションの確率で割ったものを使用します前のポリシー(π_old(a | s))。これに精通している場合、これは重要度サンプリングに少し似ています。

r eq

アクションがoldポリシーよりもcurrentポリシーに対してmore可能性が高い場合、このr(θ)は1より大きくなります。現在のポリシーでは、古いアクションよりもアクションの可能性が低い場合、0〜1になります。

ここで、このr(θ)を使用して目的関数を作成するには、logπ(a | s)項と単純に交換できます。これは、TRPOメソッドで行われることです。

TRPO objective

しかし、あなたのアクションが現在のポリシーに対してmuchより可能性が高い(100倍以上)場合、ここで何が起こるでしょうか? r(θ)は非常に大きくなる傾向があり、ポリシーを壊す可能性のある大きな勾配ステップを実行することになります。この問題やその他の問題に対処するために、TRPOメソッドはいくつかの余分な機能を追加して(KL発散制約など)、ポリシーが変更できる量を制限し、単調に改善されることを保証します。

これらの追加機能をすべて追加する代わりに、これらのプロパティを目的関数に組み込むことができたらどうでしょうか?結局のところ、これがPPOの機能です。同じパフォーマンス上の利点が得られ、この単純な(しかし、ちょっと変わった見た目の)Clipped Surrogate Objectiveを最適化することにより、合併症を回避します。

annotated clipped surrogate

最小化内の最初の項(青)は、TRPO目標で見た(r(θ)A)項と同じです。 2番目の用語(赤)は、(r(θ))が(1-e、1 + e)の間でクリップされたバージョンです。 (論文では、eの適切な値は約0.2であるため、rは〜(0.8、1.2)の間で変化する可能性があると述べています)。そして、最後に、これら両方の用語の最小化が行われます(緑色)。

時間をかけて方程式を注意深く見て、すべての記号が何を意味するのか、数学的に何が起こっているのかを確認してください。コードを見ることも役立ちます。 OpenAI ベースラインanyrl-py の両方の実装に関連するセクションがあります。

すばらしいです。

次に、Lクリップ関数が作成する効果を見てみましょう。 Advantageが正と負の場合のクリップの目的の値をプロットした論文の図を次に示します。

Clip intro

図の左半分(A> 0)で、これはアクションが結果に推定正の効果をもたらした場所です。 (A <0)の図の右半分で、これはアクションが結果に推定負の影響を与えた場所です。

左半分で、r値が高くなりすぎるとクリップされることに注意してください。これは、現在のポリシーのもとでアクションが古いポリシーの場合よりもはるかに可能性が高くなった場合に起こります。これが発生した場合、貪欲になりすぎて遠くに行きたくありません(これは単にローカルな近似値であり、ポリシーのサンプルなので、あまりにも遠くに行けば正確ではありません)成長から。 (これは、グラデーションをブロックする逆方向のパスで効果があります---グラデーションを0にするフラットライン)。

アクションが結果にマイナス効果を及ぼすと推定されるダイアグラムの右側では、クリップが0近くでアクティブになり、現在のポリシーでのアクションはほとんどありません。同様に、このクリッピング領域は、すでに大きなステップを実行して可能性を低くした後、アクションを非常に低くして更新することを防ぎます。

したがって、これらのクリッピング領域の両方により、欲張りになりすぎて一度に更新し過ぎて、このサンプルが適切な推定値を提供する領域を離れることを防ぐことがわかります。

しかし、なぜダイアグラムの右端でr(θ)を無限に成長させるのですか?これは最初は奇妙に思えますが、この場合にr(θ)が本当に大きくなる原因は何ですか?この領域でのr(θ)の増加は、アクションをかなり可能性の高いにした勾配ステップによって引き起こされ、ポリシー悪いになります。その場合は、その勾配ステップを元に戻すことができます。そして、Lクリップ関数がこれを許可しているのは偶然です。ここでの関数は負であるため、勾配は他の方向に歩き、それをどれだけねじ込んだかに比例する量だけアクションの可能性を低くするように指示します。 (図の左端に同様の領域があり、アクションが良好であり、誤って確率を低くしたことに注意してください。)

これらの「元に戻す」領域は、目的関数に奇妙な最小化用語を含める必要がある理由を説明します。それらは、クリップされたバージョンよりも低い値を持ち、最小化によって返される、クリップされていないr(θ)Aに対応します。これは、それらが間違った方向へのステップであったためです(例えば、アクションは良かったのに、偶然それを可能性が低くしました)。目的関数に最小値を含めなかった場合、これらの領域は平坦(勾配= 0)になり、間違いを修正できなくなります。

これを要約した図を次に示します。

L Clip Diagram

そして、それがその要点です。 Clipped Surrogate Objectiveは、Vanillaポリシーグラディエントで使用できるドロップイン置換にすぎません。クリッピングは、安定性を改善するために各ステップで行うことができる効果的な変更を制限し、最小化により、間違った場合にミスを修正できます。私が議論しなかったことの1つは、論文で議論されているように、PPOが「下限」であることの意味です。詳細については、著者が行った講義の この部分 をお勧めします。

2.ポリシー更新の複数のエポック

バニラのポリシーグラデーションメソッド、およびClipped Surrogate Objective関数のためとは異なり、PPOを使用すると、破壊的に大きなポリシー更新を引き起こすことなく、サンプルに対して複数のエポックの勾配上昇を実行できます。これにより、データをさらに絞り込み、サンプルの非効率性を減らすことができます。

PPOは、それぞれデータを収集する[〜#〜] n [〜#〜]パラレルアクターを使用してポリシーを実行し、このデータのミニバッチをサンプリングして[〜#〜] k [〜#〜] Clipped Surrogate Objective関数を使用したエポック。以下の完全なアルゴリズムを参照してください(おおよそのパラメーター値は次のとおりです:[〜#〜] k [〜#〜] = 3-15、[〜#〜] m [〜#〜] = 64-4096、[〜#〜] t [〜#〜](水平)= 128-2048):

PPO Algo

パラレルアクターパートは A3Cペーパー によって普及し、データを収集するためのかなり標準的な方法になりました。

新機能は、軌道サンプルで[〜#〜] k [〜#〜]勾配上昇のエポックを実行できることです。彼らが論文で述べているように、各サンプルからより多くを学ぶことができるように、データの複数のパスに対してVanillaポリシー勾配最適化を実行することは素晴らしいことです。ただし、これは一般にバニラのメソッドでは実際に失敗します。なぜなら、ローカルサンプルで非常に大きなステップを実行し、これによりポリシーが破壊されるためです。一方、PPOには、過度の更新を防ぐためのメカニズムが組み込まれています。

反復ごとに、環境をπ_oldでサンプリングした後(3行目)、最適化の実行を開始すると(6行目)、ポリシーπはπ_oldと正確に等しくなります。そのため、最初は更新はクリップされず、これらの例から何かを学ぶことが保証されます。ただし、複数のエポックを使用してπを更新すると、目的はクリッピング制限に達し始め、それらのサンプルの勾配は0になり、次の反復に進んで新しいサンプルを収集するまで、トレーニングは徐々に停止します。

....

そして、これですべてです。理解を深めることに興味がある場合は、 元の論文 をさらに掘り下げて、自分で実装しようとするか、 ベースラインの実装 に飛び込んで、コード。

[編集:2019/01/27]:より良い背景とPPOが他のRLアルゴリズムとどのように関連するかについては、OpenAIの Spinning Upリソースと実装をチェックすることを強くお勧めします

81
matwilso

PPOは単純なアルゴリズムで、ポリシー最適化アルゴリズムクラスに分類されます(DQNなどの値ベースのメソッドとは対照的です)。もしあなたが「知っている」RL基本(少なくとも Suttonの本 の最初の章を思慮深く読んでいるなら))ポリシーの勾配アルゴリズムに精通してください このペーパー または サットンの本 新版の第13章を読むことができます。また、 このペーパー を読むこともできます。 PPOの最初の著者の以前の作品であるTRPOについて(このペーパーには表記上の誤りが多数ありますが、注意してください)。

9
Mehdi

TRPOを含むPPOは、各ポリシー更新間でパフォーマンスに悪影響を与えることなく、ポリシーを保守的に更新しようとします。

これを行うには、各更新後にポリシーがどの程度変更されたかを測定する方法が必要です。この測定は、更新されたポリシーと古いポリシーの間のKLの相違を見ることによって行われます。

これは制約付きの最適化問題になります。新しいポリシーと古いポリシーの間のKLの相違が事前に定義された(または適応性のある)しきい値を超えないという制約に従って、最大パフォーマンスの方向にポリシーを変更します。

TRPOでは、更新時にKL制約を計算し、この問題の学習率を見つけます(Fisher Matrixおよび共役勾配を使用)。これは実装がやや面倒です。

PPOを使用すると、KLの発散を制約からペナルティ項に変えることで問題を単純化します。たとえば、L1、L2の重みペナルティ(重みの大きな値の増加を防ぐため)に似ています。 PPOは、ポリシー比率(更新されたポリシーと古いポリシーの比率)を1.0前後の小さな範囲内にハードクリッピングすることにより、KLの相違をすべて計算する必要性を排除することにより、追加の修正を行います。

9
Sunrisetofu

Cartpole-v1などの個別のアクションスペースの実装は、連続アクションスペースの実装よりも簡単だと思います。しかし、連続アクションスペースの場合、これはPytorchで見つけた最も簡単な実装です。OpenAIBaselinesなどの有名な実装では不可能だったmuおよびstdがどのように得られるかが明確にわかります。スピンアップまたは安定したベースライン。

RLアドベンチャーPPO

上記のリンクの次の行:

class ActorCritic(nn.Module):
    def __init__(self, num_inputs, num_outputs, hidden_size, std=0.0):
        super(ActorCritic, self).__init__()

        self.critic = nn.Sequential(
            nn.Linear(num_inputs, hidden_size),
            nn.ReLU(),
            nn.Linear(hidden_size, 1)
        )

        self.actor = nn.Sequential(
            nn.Linear(num_inputs, hidden_size),
            nn.ReLU(),
            nn.Linear(hidden_size, num_outputs),
        )
        self.log_std = nn.Parameter(torch.ones(1, num_outputs) * std)

        self.apply(init_weights)

    def forward(self, x):
        value = self.critic(x)
        mu    = self.actor(x)
        std   = self.log_std.exp().expand_as(mu)
        dist  = Normal(mu, std)
        return dist, value

そしてクリッピング:

def ppo_update(ppo_epochs, mini_batch_size, states, actions, log_probs, returns, advantages, clip_param=0.2):
    for _ in range(ppo_epochs):
        for state, action, old_log_probs, return_, advantage in ppo_iter(mini_batch_size, states, actions, log_probs, returns, advantages):
            dist, value = model(state)
            entropy = dist.entropy().mean()
            new_log_probs = dist.log_prob(action)

            ratio = (new_log_probs - old_log_probs).exp()
            surr1 = ratio * advantage
            surr2 = torch.clamp(ratio, 1.0 - clip_param, 1.0 + clip_param) * advantage

Youtubeのこのビデオのコメントの上にリンクを見つけました。

arxiv insights PPO

1
mLstudent33