プロジェクト共有 | MindSpore を通じてゲームをプレイするための強化学習を実装する方法

著者: ハムウォン 

まとめ

「深層強化学習で Atari をプレイする」は、強化学習と深層学習を組み合わせた最初の古典的な深層強化学習の論文であり、DeepMind チームによって設計および開発され、そのアルゴリズムは Atari 2600 ゲーム環境でテストされました。一部のゲームは人間のプレイヤーよりも優れていました。

論文URL: https://paperswithcode.com/paper/playing-atari-with-deep-reinforcement

01

Pycharm で仮想環境プロジェクトを作成する

プロジェクトのコードとトレーニング結果は Baidu Netdisk にアップロードされており、最初にダウンロードできます。ただし、仮想環境が大きすぎるため、アップロードされません。具体的な操作については、「はじめに」を参照してください。下に。
リンク: https://pan.baidu.com/s/1zoh0glqH4xcNSbOUuR2r7g?pwd=00wd
抽出コード: 00wd

まず、Pycharm を使用して新しいプロジェクトを作成し、次に示すように設定に仮想環境を追加します。

仮想環境プロジェクトを作成する目的は、現在のプロジェクトの実行環境を独自の Python 環境から分離することです。その後、以前の Python 環境に影響を与えないように、必要なパッケージを仮想環境にインストールします。私が使用している Pycharm のバージョンは 2019 バージョンです。自分の状況に応じて、新しいバージョンの Pycharm の設定も同様であるはずです。 Anaconda のパスは人によって異なるため、インストール場所に応じて基本的なインタープリターを選択する必要があります。

仮想環境の構成については、CSDN の記事「Pycharm による仮想環境の作成と管理」を参照してください。

写真

仮想環境を作成した後も、設定でターミナル プログラムをセットアップする必要があります。

写真

この時点で、Pycharm の下のターミナル タブを開くと、ターミナルの前にプロンプ​​ト (venv) が表示され、現在のターミナルが仮想環境にあることを示します。

写真

現時点では、必要なパッケージはすべて、このターミナルの pip を介してインストールできます。

Baidu Cloud からダウンロードした3 つのフォルダーコード、Imgs、およびモデルを現在のプロジェクト フォルダーに忘れずにコピーしてください。プロジェクトに必要な Python パッケージは、コードフォルダーの下の要件.txファイルにすでに含まれています。Pycharm のターミナル タブを開き、cd コマンドを使用してコードフォルダーに入ります。

cd code

次に、 pip は必要なパッケージをインストールします。

pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

通常、上記の環境を構成すると、コード フォルダー内のコードが正常に実行できるようになります。正常に動作しない場合は、Atari のゲーム環境に問題がある可能性があります。詳しくは、CSDN の記事「[gym] 新バージョン (0.21 以降) のインストールと Atari 環境の超簡単な構成 (Windows)」を参照してください。

02

ペーパーモデルの説明

簡単に言うと、この論文では、84X84 に切り取られたゲーム画像の連続 4 フレームを 4X84X84 入力にスタックし、畳み込み + ReLU、畳み込み + ReLU、Flatten、フル コネクション + ReLU、およびフル コネクション Get を使用する DQNネットワークを設計しますアクションの次元に対応する出力。ここでは主に BreakOut ゲーム (ピンボールとブロック) をトレーニングおよびテストします。このゲームに対応するアクションは 4 種類あるため、ここでの出力次元は 4 です。

出力される 4 次元配列は、4 つのアクションにそれぞれ対応する Q(s,a) 値を表します。最大の Q 値に対応する数値が、ネットワークによって出力されるアクション コードとして選択されます。

0: 動きがないことを意味します

1:ゲームの開始を示します(すでにゲームが開始されている場合、1はまだ動きません)

2: 右シフトを示します

3: 左シフトを示します

畳み込みサイズの計算:

出力サイズ = (入力サイズ - コンボリューション カーネル サイズ + 2 x パディング) / ストライド + 1

写真

上記の DQN ネットワークをエージェントとして使用すると、ネットワークは現在の観測に基づいて写真アクションを生成し写真、下部のスライダーを制御し、環境の変化によって新しい観測が生成されます写真。スライダーがボールを正常に動かします。バウンスして上のブロックにヒットすると、ヒットしたブロックごとに報酬 = 1 が得られます。そうでない場合は、報酬 = 0 は得られません。

次に解決する必要があるのは、エージェントがゲームのプレイ方法を学習できるように、強化学習アルゴリズムがエージェントと環境の間の相互作用を通じてエージェントの DQN ネットワークのパラメーターを継続的に更新する方法です。

強化学習アルゴリズムは、エージェントと環境の間のインタラクション経験を保存し、論文の書き方によれば、一連の経験タプル、つまり(現在の観察、行動、次の観察、報酬、終了マーク)を取得できます。は次のように表現できます。

写真

経験写真タプル内の現在の観察をネットワークに入力します。ネットワークの出力は、現在の観察の下で実行された 4 つのアクションの値に対応する 4 次元配列です。経験タプル内の現在の観測によって行われた実際のアクションに従って、写真この配列から現​​在の観測によって写真行われたアクション写真に対応する値を取得できます写真。この値は明らかにネットワークの現在のパラメータ θ に関連しています。

実際、強化学習の基礎となるベルマン方程式によれば、アクションを実行した写真後に得られる報酬写真と、対応する次の観測の期待値を通じて現在の値を推定することもできます。この推定値は次のとおりです。

写真

ゲーム終了の状況では、アクションを実行した後に得られる報酬のみがあり、次の観測はないため、現在の値の推定値が報酬になります。

ゲームが終了していない状況の場合、現在の価値の推定値には、取得した報酬に、次の観測で実行された 4 つのアクションのうちの最大の推定値を加え、割引係数 γ を掛けた値が含まれます。この割引係数は、現在の価値と、それらの間の接続は近いですか? 0 の場合、現在の値は現在の報酬にのみ依存します。γ が大きいほど、接続は近くなります。

これで、次のようになります。

DQN ネットワークを使用して取得された現在の観測によって写真とられたアクション写真に対応する推定値写真

現在の値は、報酬と次の観測の最大推定値に割引係数を乗算して推定されます写真。 Bellman 方程式によれば、2 つの推定値は等しいはずですが、ネットワークの値の推定値が不正確であるため、2 つの推定値の間に差が生じます。

写真

ネットワーク トレーニング用の深層強化学習アルゴリズムの目標は、DQN ネットワーク戦略がベルマン方程式を満たすように 2 つの推定値の差を減らし、DQN ネットワークがこのゲームの最適な戦略を学習できるようにすることです。エージェント DQN ネットワークが環境と対話するプロセスでは、保存された経験タプルを使用して上記の損失を計算し、勾配降下法で DQN ネットワークのパラメーターを更新することで、上記の目的を達成できます。

以下では、Python 環境で MindSpore フレームワークを使用した具体的なコード実装と、それに対応する説明を示します。

03

Shengsi MindSpore コードの実装

コードフォルダー内のplaying_atari.pyファイルを開きます。コードの具体的な意味は次のとおりです。

3.1 ゲーム環境の作成

対応するライブラリをインポートした後、まずゲーム環境 env を作成します。

env = gym.make("BreakoutNoFrameskip-v4")  # 游戏环境
env = gym.wrappers.RecordEpisodeStatistics(env)
env = gym.wrappers.ResizeObservation(env, (84, 84))  # 设置图片放缩
env = gym.wrappers.GrayScaleObservation(env)  # 设置图片为灰度图
env = gym.wrappers.FrameStack(env, 4)  # 4帧图片堆叠在一起作为一个观测
env = MaxAndSkipEnv(env, skip=4)  # 跳帧,一个动作维持4帧

環境はここにカプセル化されておりenv、その出力画像はそれぞれ前処理されています。4X84X84 のスタックされたグレースケール画像です。

3.2 DQN ネットワークの定義

Sengsi MindSpore を使用して DQN ネットワークを定義し、nn.SequentialCell() を直接使用して、設計されたネットワークに従って定義します。

class DQN(nn.Cell):
    def __init__(self, nb_actions):
        super().__init__()
        self.network = nn.SequentialCell(
            nn.Conv2d(in_channels=4, out_channels=16, kernel_size=8, stride=4, pad_mode='valid'),
            nn.ReLU(),
            nn.Conv2d(in_channels=16, out_channels=32, kernel_size=4, stride=2, pad_mode='valid'),
            nn.ReLU(),
            nn.Flatten(),
            nn.Dense(in_channels=2592, out_channels=256),
            nn.ReLU(),
            nn.Dense(in_channels=256, out_channels=nb_actions),
        )

    def construct(self, x):
        return self.network(x / 255.)

construct() は、Pytorch フレームワークの forward() と同様に、ネットワークの出力を表します。

3.3 エクスペリエンスストレージプールの設計

class ReplayBuffer():
    def __init__(self, replay_memory_size):

    def add(self, obs, next_obs, action, reward, done):

    def sample(self, sample_num):
        ...
        return Tensor(temp_obs, ms.float32), Tensor(temp_next_obs, ms.float32), Tensor(temp_action, ms.int32), Tensor(temp_reward, ms.float32), Tensor(temp_done, ms.float32)

具体的なコードはここでは掲載しません。簡単に言えば、後続のニューラル ネットワークのトレーニングを容易にするための経験タプルの保存とバッチ サンプリングを実現します。

3.4 損失関数、オプティマイザ、トレーニング関数の定義

まず、定義された DQN クラスのネットワークをインスタンス化しq_network、次にオプティマイザを次のように定義しnn.Adam、損失関数を次のように定義します。nn.HuberLOss()

q_network = DQN(nb_actions=env.action_space.n)  # 网络实例化
optimizer = nn.Adam(params=q_network.trainable_params(), learning_rate=1.25e-4)  # 优化器
loss_fn = nn.HuberLoss()  # 损失函数

以下は、関数自動微分と呼ばれる、ネットワーク トレーニングを定義する際の MindSpore 独自の手順です。関数自動微分に関するチュートリアルは、公式 Web サイトで参照できます。具体的には、最初に損失計算関数を定義しforward_fn、次に損失計算関数に基づいて勾配計算関数を生成しgrad_fn、次に勾配計算関数を使用してネットワーク トレーニングの 1 ステップの関数を定義しますtrain_step。このように、train_stepこの関数を使用すると、必要なデータを入力するだけで、ネットワークパラメータを一度更新し、ワンステップのトレーニングを完了できます。

# 损失值计算函数
def forward_fn(observations, actions, y):
    current_q_value = q_network(observations).gather_elements(dim=1, index=actions).squeeze()  # 把经验对中这个动作对应的q_value给提取出来
    loss = loss_fn(current_q_value, y)
    return loss

関数ではforward_fn、値の推定値の計算が完了します写真。コードではcurrent_q_value、DQN ネットワークはこの関数で Q 値を計算する必要があります。この計算プロセスでは、後続の損失の勾配が DQN ネットワーク パラメーターに逆伝播されます。 . ニューラル ネットワークの更新。

y関数の入力は、写真関数の外部で計算された後に入力されることに注意してください写真。これは、約の計算にも DQN ネットワークが必要であり、損失の勾配を約の計算プロセスに逆伝播すべきではないためです写真。そうしないと、ネットワーク パラメーターが更新されない。したがって、写真についての計算は関数の外で計算してから に入力する必要がありますforward_fn

# 损失梯度函数
grad_fn = ms.ops.value_and_grad(forward_fn, None, optimizer.parameters)  
# 参考:https://www.mindspore.cn/tutorials/zh-CN/r2.1/beginner/autograd.html

# 训练一步的函数
def train_step(observations, actions, y):
    loss, grads = grad_fn(observations, actions, y)
    optimizer(grads)
    return loss

ms.ops.value_and_grad定義された損失計算関数 を使用してforward_fn、勾配計算関数 grad_fn を返すことができます。

train_step次に、トレーニング関数でgrad_fn勾配を計算し、オプティマイザーを使用してoptimizer勾配逆伝播を実行し、ネットワーク パラメーターを更新して、ワンステップ トレーニングを完了します。

3.4 ネットワークトレーニング

次に、ネットワークをトレーニングできます。主なキー コードについていくつか説明します。

def Deep_Q_Learning(env, replay_memory_size=100_000, nb_epochs=40000_000, update_frequency=4, batch_size=32,
                    discount_factor=0.99, replay_start_size=5000, initial_exploration=1, final_exploration=0.01,
                    exploration_steps=100_000):

まず、トレーニングに必要な関連パラメーターを定義します。これには、エクスペリエンス プールの容量サイズ 100_000、合計トレーニング エポック = 40000_000、ネットワーク パラメーターは 4 エポックごとに更新され、割引係数は 0.99、エクスペリエンス プールが 5000 でいっぱいになるとトレーニングが開始されます。 、初期探索確率は 1 です。総探索エポックは 100_000 です。

ここでの探索とは、DQN がより良い戦略を学習するために、トレーニング前に探索のためにアクションがランダムに生成され、探索確率が徐々に低下することを意味します。この戦略は、ε-greed と呼ばれます。戦略。

トレーニングの前に、ネットワークをトレーニング モードに設定します。

q_network.set_train()  # 设置网络为训练模式

次に、DQN がゲームと対話できるようにします。アクションを生成するための対応するコードは次のとおりです (ランダム探索または DQN によって生成されるアクション)。

if random.random() < epsilon:  # With probability ε select a random action a
    action = np.array(env.action_space.sample())
else:  # Otherwise select a = max_a Q∗(φ(st), a; θ)
    temp_input = Tensor(obs, ms.float32).unsqueeze(0)
    q_values = q_network(temp_input)
    action = q_values.argmax(axis=1).item().asnumpy()

各エクスペリエンス タプルをエクスペリエンス プールに保存します。

rb.add(obs, real_next_obs, action, reward, done)

エクスペリエンス プールからエクスペリエンス タプルのバッチを選択し、写真値を計算し、train_step関数を使用してネットワーク パラメーターを更新します。

data_obs, data_next_obs, data_action, data_reward, data_done = rb.sample(batch_size)
# 这一部分不用求梯度,所以写在forward_fn和train_step函数之外
max_q_value = q_network(data_next_obs).max(1)
y = data_reward.flatten() + discount_factor * max_q_value * (1 - data_done.flatten())
loss = train_step(data_obs, data_action, y)

写真計算プロセスに勾配逆伝播を行う必要がないため、ここで計算されることに注意してください写真。そのため、最初にここで計算され、次に事前に定義されたtrain_step関数に入力されてトレーニング セッションが完了します。

次に、長いトレーニング プロセスが続きます。これには、私自身のラップトップを使用して約 10 日間かかりました。ラップトップでトレーニング速度をテストしたところ、Pytorch とほぼ同じでした。 Ascend MindSpore は Huawei Ascend 910 (ファーウェイが開発した AI チップ) を使ってトレーニングを高速化できるのですが、貧乏学生としては考えものなので、vivo50 で試してみたいと思います(`・ω・´)。

トレーニング曲線は次のとおりです。Pytorch を使用して Github 上でボスがトレーニングした結果は約 200 です。ノートブックのメモリ 16g の制限により、現在の経験プール容量でトレーニングできる最高の結果は約 150 です。

写真

04

実験結果

トレーニング後、DQN はこのゲームをプレイできるようになったことがわかります。次のように、運が良ければ 300 ポイントを獲得できます。

写真

 

1990 年代生まれのプログラマーがビデオ移植ソフトウェアを開発し、1 年足らずで 700 万以上の利益を上げました。結末は非常に罰的でした。 Google は、Flutter、Dart、Python チームの中国人プログラマーの「35 歳の呪い」に関係する人員削減を認めた 。Microsoft 無力な中年者にとっては幸運なおもちゃでもある。強力で GPT-4.5 の疑いがある; Tongyi Qianwen オープンソース 8 モデルWindows 1.0 が 3 か月以内に正式に GA Windows 10 の市場シェアは 70% に達し、Windows 11 GitHub がAI ネイティブ開発ツール GitHub Copilot Workspace JAVAをリリースOLTP+OLAP を処理できる唯一の強力なクエリです。これが最高の ORM です。
{{名前}}
{{名前}}

おすすめ

転載: my.oschina.net/u/4736317/blog/11072521