DDPG by gymnasium 17日目

今回は、単純にノードを64から32に落としてみたらどうかと思います。

学習のステップ

  1. 100Steps x 1000Epsodes
  2. 200Steps x 1000Epsodes
  3. 300Steps x 1000Epsodes

非常にうまくいきました。文句なしです。

走りも安定しています。

 

これで、このDDPGシリーズはお終いにいたします。

続編はMalti Agent Deep Detarministic Policy Gradient:MADDPG の予定です。ありがとうございました。

 

 

DDPG by gymnasium 16日目

前回

学習が進まず、チーターの様子を見ると開始直後に静止してお終いです。ぐーたらになってしまいました。

考えうる原因

  • ノード数が多すぎる?256
  • 学習率が大きすぎる?0.01
  • パラメータの初期値 Heがうまくいってない?/1√256は小さすぎる?
  • レイヤー正規化が上手くいってない?

→レイヤー正規化をキャンセルしてみます。

actor:
def forward(self, obs):
        #print(‘AgetDDPG.ActorNN.forward is working’)
        #print(‘====ここまではOK1====’)
        x = self.fc1(obs)
        #x = self.bn1(x)
        x = F.relu(x)
        x = self.fc2(x)
        #x = self.bn2(x)
        x = F.relu(x)
        x = self.fc3(x)
        action = F.tanh(x)
        return action

 

critic:

def forward(self, obs, action):
        input_data = T.cat([obs, action], dim=1)
        x = self.fc1(input_data)
        #x = self.bn1(x)
        x = F.relu(x)
        x = self.fc2(x)
        #x = self.bn2(x)
        x = F.relu(x)
        x = self.fc3(x)
        return x #一つの状態価値を出力する。
結果:ダメです!学習が進みません。
  
次はHeの初期値をキャンセルしてみます。
→結果:ダメです、収益が徐々に下がり気味で、Actor_lossもなぜか安定して増えていっています。
次はノードを256から64に落としてみます。また同時にバッチサイズも256から64に落としてみます。
→結果:Stepは200にして始めています。
300回やったあと、続けて1000回やってみました。頑張ってる?
ここでStepを300にしてみます。安定して前進している姿を経験再生バッファに溜め込むのが目的です。
悪化しました・・・。
ということは、残すところ学習率?0.01から0.001に細かくしました。
100Stepを1000Episode、200Stepを1000Episode実行しました。
上手くいきました。

ActorNN:He適用しない, alpha=0.0001, Adam, bn1,キャンセル bn2キャンセル

batch64,obs17→17 fc1 64→64 ReLU 64→64 fc2 64→64ReLU64→64fc3 6 →Tanh6→ action6

CriticNN:He適用, beta=0.001, Adam,bn1,キャンセル bn2キャンセル

batch64,obs17+act6→input23  fc1 64→64 ReLU 64→64 fc2 64→64fc3 1→活性化関数なし→Q_value 1

結果的に、

  • ノード数が多すぎる?256→64
  • 学習率が大きすぎる?0.01→0.001
  • パラメータのHe初期値 →キャンセル
  • レイヤー正規化→キャンセル

でうまくいきましたが、学習率が大きすぎたのが原因ではないかと考えます。

またノード数が多すぎて過学習を起こしていた可能性もあります。

またレイヤー正規化が上手くいかないのも腑に落ちません。

He初期化は原因として考えにくいので、まずはここだけ戻してみます。

問題ありませんでした。次にレイヤー正規化を適用してみます。

600Epsodeを過ぎたあたりで悪化していますが、何とか持ち直しています。どうやら、スタートダッシュで前傾姿勢になりすぎて逆に速度が遅くなっているようです。ひっくり返っているのでしょう。1000回超えたあたりでStepを伸ばしたので前のめりが修正されつつあると考えます。よってStep300にして1000回続けてみます。

ブレ幅が大きいですが、よさそうです。

いや、やっぱダメです(笑)ずっと逆立ちして頭と前足で前進しています。

600回~900回あたりで、変な癖を覚えてしまったようです。

ほんとAIってやつは突拍子もないことを考え付きます。

原因は何でしょうか、過学習と言っていいものかはさだかではありませんが、正則化のようにニューラルネットワークの最適化に対して何らかの拘束を与えるとよいかもしれません。正則化というとよく活性化関数からの出力のうち10%程度を0にして学習をさせる、ドロップアウトがでてきますが、単純にノードを64から32に落としてみたらどうかと思います。次回やってみます。

 

DDPG by gymnasium 15日目

さて最終章に近づいてまいりました。(ような気がする)

ニューラルネットワークの学習をより安定化させるために標準化Standarzation,正規化Normalizationをやっていきましょう。

まずは入力値について考えます

各特徴量ごとの学習の感度を同じくらいにそろえるために、入力値の値を相対的に加工します。

標準化

Z-scor normalization

手持ちデータを平均ゼロ、分散1の正規分布にする手法

正規化

Min-Max normalization

最小値~最大値を0~1にスケーリングする手法

 

使い分け

標準化:最大最小が決まっていない場合、外れ値が存在する場合

正規化:最大値および最小値が決まっている場合

戦闘力は標準化が良い

住宅価格も標準化が良い

弱点

弱点として、入力値はいいのですが、ネットワークを伝播していくうちに各ノードの入力値(活性化関数がかかる前)の分布は崩れていきます。

すると、勾配消失が起こりやすくなります。

重みパラメータの初期値を工夫する

そこで重みの初期値を工夫して一様分布や正規分布に従うランスを使うのですがディープラーニングではうまく動かないことがあります。

解決策として 乱数xネットワークの大きさに合わせた係数 を初期値とすると 分布が崩れにくくなるそうです。(ちょっとわかりません。)

活性化関数がシグモイド関数の場合はXavierの初期値、ReLU関数の場合はHeの初期値というものが良いそうです。

重みの要素数がnである場合、Heの初期値は1/√nとなります。

 

バッチ正規化

もっと直接的で良い方法があります。

各ノードに入力されたら、そこで正規化してしまえば良いのです。各層で毎回正規化を繰り返します。

因みになぜバッチ正規化というのかはわかりません。各レイヤーのノード群をバッチと呼んでいるのでしょうか。

とにかく各層のノードを正規化するのです。

学習の成功率を上げるとともに過学習もしにくくなるらしいです。

やりかた

標準化して線形変換するだけです。

標準化:

あるレイヤーのノード群の平均値μと分散sを求める

各ノードの値xから平均値μを引いて標準偏差σで割った値が標準化された値z

線形変換:

zにパラメータw,バイアスbを使って y=wz+bへ線形変換する。

正確に言うとこれはバッチ正規化の発展系であるレイヤーノーマライゼーションを使っています。

ActorNNクラスの改造:

重みパラメータ、バイアスパラメータの初期値

今まではランダムに初期値を決めていたところをHeの初期値に変更しました。つまり、ネットワークの各層のノード数ActorNN.各fc.weight.data.size()[0]に応じて、初期値の上下限f1,f2を決定するようにしました。nn.init.uniform_()。

各層の入力値を正規化

今までは各層への入力値は特に加工せずに活性化関数へ入れていましたが、入力値は正規化nn.LayerNorm()を適用してから活性化関数に入れるように変更しました。入力値→正規化bn→活性化関数ReLU。

CriticNNクラスの改造:

こちらも考え方は同じです。

学習結果

1000エピソード以上学習しましたが、どういうことでしょう調子いいのは300エピソードくらいのところで、そこから一気に悪化しています。

横軸:エピソード、縦軸:収益

ハーフチーターは一体何をやっているのでしょうか?

開始直後に素早く美しく前転し、ひっくり返りながらバタバタしていました。どうやら300回転超えたあたりから学習するべきデータが間違ったものしかない状況になり、回復しなかったと推測します。負のスパイラルに落ち込んでいったのでしょう。

反省

今回の条件を確認します。

agentインスタンス:

alpha=0.01,
beta=0.01,
gamma=0.99,
tau=0.01,
n_obs_space=17 ,
n_action_space=6,
n_state_action_value=1,
layer1_size=256,
layer2_size=256,
layer3_size=256,
batch_size=256,

AgentDDPGクラス__init__():

alpha=0.000025,
beta=0.00025,
amma=0.99,
tau=0.001,
n_obs_space=17 ,
n_action_space=6,
n_state_action_value=1,
layer1_size=64,
layer2_size=64,
layer3_size=64,
batch_size=64,
self.actorインスタンス:
alpha=0.000025,※ここ間違った。alpha=self.alphaにするべき
n_obs_space=17,※ここ間違った。同上
n_action_space=6,※ここ間違った。同上
 layer1_size=64,※ここ間違った。同上
layer2_size=64,※ここ間違った。同上
layer3_size=64,※ここ間違った。同上
batch_size=64※ここ間違った。同上

なので actorとしては

ActorNN:He適用, alpha=0.000025, Adam

batch64,obs17→17 fc1 64→64 bn1 64→64 ReLU 64→64 fc2 64→64 bn2 64→64ReLU64→64fc3 6 →Tanh6→ action6

※layer3_sizeは不使用

という状況でした。一部間違っていました。直します。

修整後↓

self.actor = ActorNN(device=self.device, alpha=self.alpha, n_obs_space=self.n_obs_space, n_action_space=self.n_action_space,
                            layer1_size=self.layer1_size, layer2_size=self.layer2_size, layer3_size=self.layer3_size, batch_size=self.batch_size)

ちなみにActorNNの初期化メソドは

ActorNNクラス__init__():
alpha=0.001
n_obs_space=17,
n_action_space=6
layer1_size=256,
layer2_size=256,
layer3_size=256,
batch_size=64

です。

target_actorインスタンスも下記のように間違っているので

self.target_actor = ActorNN(device=self.device, alpha=0.000025, n_obs_space=17, n_action_space=6,
                                    layer1_size=64, layer2_size=64, layer3_size=64, batch_size=64)

直します。↓修整後

self.target_actor = ActorNN(device=self.device, alpha=self.alpha, n_obs_space=self.n_obs_space, n_action_space=self.n_action_space,
                                    layer1_size=self.layer1_size, layer2_size=self.layer2_size, layer3_size=self.layer3_size, batch_size=self.batch_size)

 

次に、target_criticインスタンスを見ていきます。

beta=0.000025,※ここも間違い。self.betaにするべき
n_obs_space=17,※同上
n_action_space=6,※同上
 layer1_size=64,※同上
layer2_size=64,※同上
layer3_size=64,※同上
batch_size=64)※同上
これも間違っているので修正。修整後はこちら↓
self.target_critic = CriticNN(device=self.device, beta=self.beta, n_obs_space=self.n_obs_space, n_action_space=self.n_action_space,
                                    layer1_size=self.layer1_size, layer2_size=self.layer2_size, layer3_size=self.layer3_size, batch_size=self.batch_size)

同じくtarget_criticインスタンスもself.なんちゃらにしていないので修正が必要です。修整後↓

self.critic = CriticNN(device=self.device, beta=self.beta, n_obs_space=self.n_obs_space, n_action_space=self.n_action_space,
                                    layer1_size=self.layer1_size, layer2_size=self.layer2_size, layer3_size=self.layer3_size, batch_size=self.batch_size)

なので target_criticとしては

CriticNN:He適用, beta=0.000025, Adam

batch64,obs17+act6→input23  fc1 64→64 bn1 64→64 ReLU 64→64 fc2 64→64 bn2 64→64fc3 1→活性化関数なし→Q_value 1

※layer3_sizeは不使用

ちなみに
CriticNNクラスの__init__()
beta=0.001,
n_obs_space=17,
n_action_space=6,
 layer1_size=256,
layer2_size=256,
layer3_size=256,
batch_size=64):
です。

現在までのまとめ

学習率とノード数を間違って入れていましたが、これが悪いとは現時点では言えません。

可能性としてはバッファメモリが10000で1エピソード2000ステップなので5回連続でダメな収益結果の場合、「ひっくり返ってお終い」、のようなダメな経験しか持ってない状態になります。

これが、二度とまともな状態に学習が継続できない要因ではないでしょうか。

(メモ:ステップを400とすると1エピソードがなぜか5倍の2000ステップまで実行されます。仕様ですかね。)

修正したコード

ひとまず、間違っていた部分を直したので張っておきます。

agent = AgentDDPG(device=device, alpha=0.01, beta=0.01, gamma=0.99, tau=0.01,
                  n_obs_space=17 , n_action_space=6, n_state_action_value=1,
                  layer1_size=256, layer2_size=256, layer3_size=256, batch_size=256, mode=EVAL_TRAIN_MODE) # cuda追加
がネットワーク生成までこのパラメータが適用されるように修正しました。
これの結果:学習が進みません。チーターの様子を見ると開始直後に静止してお終いです。ぐーたらになってしまいました。

ノード数が多すぎる?256

学習率が小さすぎる?0.01

パラメータの初期値 Heがうまくいってない?/1√256は小さすぎる?

レイヤー正規化が上手くいってない?

次回へ続きます。

DDPG by gymnasium 14日目

本日のお題は

保存したパラメータを読み出すのはactorとtarget_actorまたcriticとtarget_criticで共通で良いのだろうか。

です。結果として共通で良いです。

つまりactorとtarget_actorはactor_params.ptを呼び出して、criticとtarget_criticはcritic_params.ptを呼び出せば成り立ちます。

ただ、実行開始直後が同じパラメータになってしまうので、リプレイバッファに経験が貯まりTDターゲットの再計算が始まるまではcriticとの差が小さいので、しばらくは学習の進み方が遅くなるのではないかと予想しております。

実際は問題になるほどではありませんでしたが、ここはセオリー通り共通ではなくてそれぞれのパラメータを読み込むように修正しました。

ActorNNクラスの__initi__()の中に

そしてCriticNNクラスの_init__()の中に

と書いていたのを削除して、代わりに

actor, ciritc, target_critic, target_actorそれぞれのインスタンス生成直後に入れています。

 

 

DDPG by gymnasium 13日目

GPUによる計算に成功しました。

GPUとCPUの速度比較

episods=11 step=500
    GPUで80秒
    CPUで48秒
    episods=5 step=500
    GPUで40秒
    CPUで25秒

結論 CPUのほうが速い!!うそーん!

ショックすぎて、今日はもうやめます。CPU買ったほうがいいじゃん!

スクリプト

 

DDPG by gymnasium 12日目

GPUをニューラルネットワークのテンソル演算に利用します。

GPUへの飛ばし方

#変数deviceを’cuda’にする

device = torch.device(“cuda” if torch.cuda.is_available() else “cpu”)

#ネットワークのインスタンスを.to(‘cuda’)する

net_gpu.to(device)

# ネットワークへの入力xを.to(‘cuda’)する

x = x.to(device)

# ネットワークへの正解ラベルyをy.to(‘cuda’)する

y = y.to(device)

これでGPU上のnetへxとyを入れることができるので演算可能になります。

 

速度比較

 

class SimpleNet(nn.Module):クラスとしてネットワークを作成します。
n_inputs:2
バッチ数:4
n_output:1
n_hidden:1024
hidden layer 4層をもつ全5層のネットワークです。
ネットワークのインスタンスを2つ作って
net_cpu = SimpleNet()
net_gpu = SimpleNet()
エポック数:1000でそれぞれ回してみましょう。
結果は
CPU training time: 9.972002267837524 seconds
GPU training time: 2.5578291416168213 seconds
ということで。GPUのほうが高速です。
しかし、n_hiddenを64にすると、
CPU training time: 0.5419738292694092 seconds
GPU training time: 2.506857395172119 seconds
となり、node数が少ない場合はcpuのほうが高速になります。
GPUならいつでも高速というわけではないことに注意しましょう。

スクリプト

 

次回はDDPGコードをGPU対応していきます。

DDPG by gymnasium 11日目

  1. 計算の高速化(GPUの利用)
  2. 適切なエピソード数
  3. 適切なメモリバッファ数
  4. ネットワークの入力値?パラメータ?の正規化。
  5. 保存したパラメータを読み出すのはactorとtarget_actorまたcriticとtarget_criticで共通で良いのだろうか。

計算の高速化:GPUを使ってみる。

今日は下準備をやっていきます。

GPUの準備ができているPCなら

 

で’cuda’が出力されます。
‘cpu’が出力されたならGPUの準備から始める必要があります。

GPUの準備

PCIスロットに入っているGPUを調べる

$ nvidia-smi –query-gpu=name –format=csv
出力:NVIDIA GeForce RTX 3070 Ti

cudaバージョンを調べる

$ nvidia-smi

出力:

NVIDIA-SMI 528.49 Driver Version: 528.49 CUDA Version: 12.0

CUDA Toolkit のバージョンを調べる

$ nvcc -V

出力:

nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2023 NVIDIA Corporation
Built on Fri_Jan__6_19:04:39_Pacific_Standard_Time_2023
Cuda compilation tools, release 12.0, V12.0.140
Build cuda_12.0.r12.0/compiler.32267302_0

NVIDIAのGPUドライバを最新にする

https://www.nvidia.co.jp/Download/index.aspx?lang=jp
でNVIDIA GeForce RTX 3070 Tiのドライバをインストールします。Driver Version: 531.14 にアップデートしました。
再度 $ nvidia-smiで確認すると
CUDA Version: 12.1 にアップデートしていました。

CUDA ToolkitをGPUドライバに合わせてインストールする

https://developer.nvidia.com/cuda-toolkit-archive

GPUドライバをアップデートした結果CUDAバージョンは12.1になったので、それに合わせてCUDA Toolkit 12.1.0 (February 2023), Versioned Online Documentationを選択。

次にwindows10, exeファイルを選択して、ダウンロードしてインストール。

PytorchのGPU使用バージョンをインストールする

https://pytorch.org/get-started/locally/

Pytorchがインストールされているようであれば、アンインストールしておくのが良いです。

$ pip uninstall torch

下記のように自分に合ったOS, CUDAバージョンを指定すると、インストール用のコマンドが生成されるので、実行します。

確認する

今一度下記でdeviceが’cuda’と出力されれば完了です。

Pythonからもいろいろ情報を取得できます。

 

GPUでPytorchのテンソルを計算してみよう。

結果

GPU同士でないと計算できないので注意です。

演算後にCPU上の数値またはNumpy.arrayと演算するためにはGPU上からCPU上へ戻す必要があります。

 

また、GPU上にあるとmatplotlibでグラフが書けないので、GPU→CPUまたは、Numpy.arrayにしてからmatplotlibで描画します。

gpu上にある数値でグラフ描画を試みたときの警告

plt.plot(gpu_tensor)
#TypeError: can’t convert cuda:0 device type tensor to numpy. Use Tensor.cpu() to copy the tensor to host memory first.

次回

次回はニューラルネットワークに
device = torch.device(‘cuda’ if torch.cuda.is_available() else ‘cpu’)

tensor.to(device)

numpy_array = gpu_tensor.cpu().detach().numpy()
を入れ込んでみます。

 

 

DDPG by gymnasium 10日目

未解決の課題・疑問点

  1. model.train()とmodel.eval()の使い方が分からない。
  2. 計算の高速化(GPUの利用)
  3. 適切なエピソード数
  4. 適切なメモリバッファ数
  5. ネットワークの入力値?パラメータ?の正規化。
  6. 保存したパラメータを読み出すのはactorとtarget_actorまたcriticとtarget_criticで共通で良いのだろうか。

model.train()とmodel.eval()の使い方

ニューラルネットワークの訓練モードと評価モードを切り替えるメソドのようです。

例えばNNモデルがactorの場合

インスタンス生成:actor = ActorNN(引数) してから

actor.train()で訓練モードに設定すると、バッチ正規化やドロップアウトなどの要素が有効になります。あくまで自分でバッチ正規化、ドロップアウトを設定していた場合です。

逆に、actor.eval()にするとバッチ正規化、ドロップアウトを設定していたとしても無効化されます。

ここで重要なのはactor.eval()であっても勾配は計算するし、パラメータ更新も行われるということです。評価モードということなので、推論だけするのかと勘違いしてしまいますが違います。

証拠としてスクリプトを置いておきますので実行してみてください。ちゃんと勾配計算して損失関数の値も減少していきます。

サンプルスクリプト

パラメータ更新による損失関数の減少グラフ

推論するときはOUActionNoise()を止めよう

バッチ正規化やドロップアウトで訓練した場合、actor.eval()で無効化が必要なのはわかりました。しかし行動ノイズは依然として有効なので、こちらも止めましょう。

ou_noise = OUActionNoise(mu=np.zeros(1), sigma=0)

のように sigmaを0に設定することで更新を停止するギミックが必要になります。

メインスクリプト

 

 

AgentDDPGクラス

これでOUActionNoise()は無効化できました。

ハーフチーターがプルプルしなくなりました。
しかし、各ニューラルネットワークのパラメータ更新は止まっているわけではありません。

パラメータ更新を止める

書きかけです。おそらく、EVAL_TRAIN_MODE = ‘eval_mode’ でないときだけパラメータ更新メソドである、optim.step()を行うようにすればよいと思います。
if EVAL_TRAIN_MODE != ‘eval_mode’:
    self.optimizer.step()

現在のスクリプト全体

 

DDPG by gymnasium 9日目

前回まででうまいこと学習が進むようになりましたので、今回はパラメータの保存と読出をやってみましょう。

例えば、エピソードを100回繰り返しある程度ハーフチーターが前に進む方策を得たらパラメータをいったん保存します。

プログラムを止めて次回動かすときは保存したパラメータを読み込んで、学習済みの状態から動かすことができます。

これで突然プログラムが途中で止まってしまっても被害を最小限にできますね。

パラメータ保存

メインスクリプトでエピソードの終わり、次のエピソードが始まる直前に下記コードを入れます。

パラメータ読込

ActorNN(n.Module)クラスの__init__()内に入れて、actor, target_actorのインスタンス生成と同時にパラメータを引き継いでもらうようにします。

CriticNN(nn.Module)クラスも同様に。

これで、動きます。

学習のノウハウ

学習のコツを編み出しました。

学習初期はエージェントの動きが小さくなかなか前進しません。

最初はステップ数を10~100程度に小さくして、スタートダッシュだけを覚えさせました。

そこでいったん止めて、ステップ数を200、400と増やしていくと安定して走り続けるハーフチーターが得られます。

計算の高速化(3Dモデルの表示をオフにする)

env = gym.make(“HalfCheetah-v4”, render_mode= ‘human’)
の中のrender_modeを’depth_array’に変更すればOKです。

学習の進行状況のリアルタイム可視化

エピソード数とそのリワードだけを表示しています。
print(‘episode, total_reward : ‘, episode , total_reward)
パラメータの保存を10エピソード毎にやっています。
if episode % 10 == 0:
print(‘==== params were saved. ====’)
↓↓↓出力

解決できた課題

  1. パラメータのセーブとロード
  2. 途中で止まった時に続行可能にしたい
  3. 計算の高速化(print文の無効化)
  4. 計算の高速化(3Dモデルの表示をオフにする)
  5. 学習の進行状況のリアルタイム可視化
  6. 適切なステップ数
  7. 適切なニューラルネットワーク構造

未解決の課題・疑問点

  1. 計算の高速化(GPUの利用)
  2. 適切なエピソード数
  3. 適切なメモリバッファ数
  4. model.train()とmodel.eval()の使い方が分からない。
  5. ネットワークの入力値?パラメータ?の正規化。
  6. 保存したパラメータを読み出すのはactorとtarget_actorまたcriticとtarget_criticで共通で良いのだろうか。

これまでのスクリプト

 

DDPG by gymnasium 8日目

chatGPTより提案されたニューラルネットワーク構造を導入してみます。

actorNNは隠れ層ノードを64から256に増やしました。

criticNNも隠れ層ノードを64から256に増やしました。

actorNNの活性化関数はrelu, relu,tanhで出力のまま変わらず。

criticNnの活性化関数はrelu,reluで最終層は活性化関数なしで出力。こちらも変更なしです。

基本構造は悪くなかったようです。

変わらず actor_lossesが上昇傾向にあります。

次は、ステップ数を10から50に増やしてみます。

前のめりを覚えたようで、たまにひっくり返ります。

しかし、actor_losses, critic_lossesは上昇傾向で変わらす。しかし、なんか前に行こうと頑張っているようには見えます。符号が逆になってないだろうか?

ここで行動にノイズを入れて環境の探索性を上げることで学習が良い方向に進むかやってみます。

DDPGにおけるOUActionNoiseクラスは、行動に対してオルナシュウ-ウーレンベック(Ornstein-Uhlenbeck)過程に基づくノイズを生成するために使用されるクラスです。このノイズは、環境の探索性を増加させるためにアクションに追加されます。

このクラスのインスタンス化時に、平均値(mu)、標準偏差(sigma)、タイムステップの幅(dt)、回帰係数(theta)、初期値(x0)を指定します。__call__メソッドは、ノイズを生成して返します。

DDPGの学習時には、Actorネットワークから生成されたアクションにOUActionNoiseクラスを適用してノイズを追加し、環境への探索性を高めます。これにより、探索と収束のトレードオフを実現し、より良いポリシーの探索を促進することができます。

44.OUActionNOoiseクラスを作成する

AgentDDPGクラスに追加

choose_actionメソド内でactionにノイズを入れる。

actorにしろcriticにしろ、常にtargetが動いているのでlossが小さくなるわけではないのかなと思い始めました。

前にぴょんぴょん跳ねるような動作が生まれてきました。ノイズのおかげでしょうか。

EPISODES = 1000 # episodes
STEPS = 100    # steps
ではどうでしょうか。
30000ステップを超えたあたりから、ハーフチーターは開始1秒で前進側にすっ飛んでいく挙動が得られました。
しかし、安定してすっ飛んでいくわけではなく、ちょっともたついてから前傾姿勢で進む場合と混ざり合っています。それでも、開始直後に後退する動作はなくなりましたので確実に成長しています。
ニューラルネットワークのパラメータ更新はうまくいっているようです。
リプレイバッファのサイズはまだ1000だけにしていますがもっと多いほうがいいのでしょうか。多すぎると古い情報がなかなか更新されないので学習が遅くなってしまう気がします。
バッチサイズ64に対してベストなバッファサイズはどのように考えればよいでしょうか。課題です。
次回は、ニューラルネットワークモデルのパラメータ保存と読み出しについて考えていきましょう。