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に対してベストなバッファサイズはどのように考えればよいでしょうか。課題です。
次回は、ニューラルネットワークモデルのパラメータ保存と読み出しについて考えていきましょう。

DDPG by gymnasium 7日目

さて、日をあけてしまいましたが、続きをやっていきましょう。

前回

actorが行動して集めたデータから、経験再生を使って「次の状態」からtarget_actorが「次の行動」を出力し、「次の行動」と「次の状態」からtarget_criticが「次の状態価値」出力し、TDターゲットを算出しました。

一方で、criticは経験再生を使って「現在の状態」と「そのとき取った行動」から「現在の状態価値」別名ベースラインを算出しました。

今回

ここからは、本当の意味で学習・訓練、つまりパラメータ更新をやっていきます。

オプティマイザーを定義する

オプティマイザーをActorNNクラスとCriticNNクラスの__init__()に定義しておきます。
【ActorNN】#26
self.optimizer = optim.Adam(self.parameters(), lr=alpha)
【CriticNN】#27
self.optimizer = optim.Adam(self.parameters(), lr=beta)
引数のself.parameters()は、モデル自身が持っている重みやバイアスのパラメータです。それを学習率lrでAdamによって最適化(損失関数の最小化)するインスタンスself.optimizerを定義します。

criticの学習

lean()メソド内でのTDターゲット算出後からやっていきます。
クリティックの損失関数はtensor(0.0485, grad_fn=<MseLossBackward0>)の形で出力されます。

actorの学習

続けてactorを学習します。
Actorの目的は、Criticネットワークの出力(行動価値)を最大化するような行動を選択することです。
なので、actorNN→criticNNのDDPG構造全体の出力結果をactor_lossとして、actorNNとcriticNNの両方をbackwardすることによってactorにも勾配情報が届きパラメータの更新をすることができます。

全ニューラルネットワークのパラメータを更新する

learn()メソドの締めくくりとして、36の直後にself.update_network_parameters()を入れ、メソドとして定義します。
学習結果の確認
クリティックとアクタークリティックのパラメータ更新まで行ってアクターとターゲットアクターのパラメーター更新をしない状態で試してみました。
動作確認のつもりでやりましたが、学習は進んでいるようです。
10step x 100epsode で学習したところ、ハーフチーターはエピソード開始直後に前へ倒れこむような挙動を獲得し、リワードを稼ぐようになりました。10stepでは走り続ける動作を獲得するのは無理なようです。
続いて、アクターとターゲットアクターのパラメーター更新も追加して同じことを行いました。
こちらは、足を折りたたんで低い姿勢なることでリワードを稼ぎに行っているようです。しかし80エピソードから成績が悪化していっています。うまく学習が進んでいないようです。
まあ、ニューラルネットワーク構造もまだ適当に作っているので、改善の余地があります。
また下記のようにactor_lossesとcritic_lossesの変化も可視化してみると下記のように悪化していく方向にあります。

課題

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

現在までのスクリプト

 

以上。次回はニューラルネットワーク構造を見直しましょう。

DDPG by gymnasium 6日目

前回までの動き:

  1. agentがobsを受けてchoose_actionでactor(NN)をforwardしactionを出力する。
  2. actionを受けてenv.stepし結果としてnext_state,reward,doneを得る。
  3. agent.rememberで結果obs,action,rewerd,next_state,int(done)を保存する。
  4. rememberで64データ集まったらagent.learnで学習が始まる。
学習:
  1. sample_bufferで64データをランダムに取り出す。
  2. dtype=T.float32に変換する。
  3. target_actorへnext_states 64データを入力してtarget_actions 64データを得る。
ここまで作成しました。

今回

このtarget_actionsをnext_statesと共にtarget_criticへ入力するところからやっていきます。
この部分こそ連続値対応できるDDPGの核心部分なので十分に理解する必要があります。
引き続き 学習learn()メソド内での処理です。

やっていこう

AgentDDPG.learn()メソド内の

target_actions = self.target_actor.forward(next_states)

の直下に
target_critic_values
 = self.target_critic.forward(next_states, target_actions)
を入れます。
算出したてのtarget_actionsとnext_statesの2つを入力として、target_critic_valuesを出力します。

ちょっと説明をいれると、DDPGはTD法なのでTDターゲットとしてr + γ*V(w)[s_t+1]を考えます。target_critic_valuesはこれのことです。

この価値関数Vの部分をtarget_criticNNで表現します。

# 21.ターゲットクリティックネットワークインスタンスtarget_criticを作成します。AgentDDPG.__init__()内に定義します。
target_actorの引数 学習率alphaをcritic用にbetaへ変更しています
# 22.CriticNNクラスを作成します。
これでtarget_critic_values が返ってくる

#23.ベースラインとして機能するクリティックネットワーク(価値関数V(w)[s_t]ネットワーク)に 現在の状態observationsと行動actionsを入力してcritic_valueを算出する。
AgentDDPG.learn()メソドに戻ってさっきほどの
target_critic_values
 = self.target_critic.forward(next_states, target_actions)
の直下に
 critic_values
   = self.critic.forward(observations, actions)
を入れる。criticインスタンスはまだ作成していないので、AgentDDPG.__init__()に追加する
# 24. AgentDDPG.__init__()にクリティックインスタンス生成を追加する
これで4つのNNを導入することができた。

# 25.target_criticからTDターゲット(= r + γ*V(w)[s_t+1])を算出する。

AgentDDPG.learn()メソドに戻って、

まとめとこれまでのスクリプト

actorが行動して集めたデータから、経験再生を使って「次の状態」からtarget_actorが「次の行動」を出力し、「次の行動」と「次の状態」からtarget_criticが「次の状態価値」出力し、TDターゲットを算出しました。注意すべきはここで言う「次の行動」とはあくまでtarget_actorが生み出した「架空の行動」です。

一方で、criticは経験再生を使って「現在の状態」と「そのとき取った行動」から「現在の状態価値」を算出ししました。注意すべきは、こちらの「そのとき取った行動」とは実際にactorが行動して経験再生バッファに保存されたデータです。

また、この「現在の状態価値」をベースラインと呼びます。次回以降。「TDターゲット-ベースライン」の演算が出てくるので注目です。

ではまた次回

DDPG by gymnasium 5日目

次回は、actorNNへの引数修正、それに伴うagentDDPG引数修正、そしてリプレイバッファへの保存内容を修正しました。

今回は64データ集まった後に学習learn()メソドが走るとエラーが出るので修正していきます。

chatGPTより

このエラーメッセージは、F.linear関数を使用して乗算されている2つのテンソルのデータ型が一致しないことを示しています。この場合、inputテンソルとweightテンソルのデータ型が異なるようです。

この問題を解決するには、次の手順を試すことができます。

  1. inputテンソルとweightテンソルのデータ型を確認します。それらのdtype属性を出力して、同じかどうかを確認できます。
  2. データ型が異なる場合は、to()メソッドを使用してinputテンソルをweightテンソルと同じデータ型に変換します。たとえば、weightテンソルがfloat32テンソルの場合、input.to(torch.float32)を呼び出してinputテンソルをfloat32テンソルに変換できます。
  3. 代わりに、inputテンソルと同じデータ型にweightテンソルを変換することもできます。たとえば、inputテンソルがfloat64テンソルの場合、weight.to(torch.float64)を呼び出してweightテンソルをfloat64テンソルに変換できます。
  4. テンソル上で行われる他の操作も同じデータ型を維持するようにしてください。

テンソルのデータ型が一貫していることを確認することで、遭遇したRuntimeErrorを解決できるはずです。

とのこと。なるほど、入力データをpytorchの型に合わせる必要があるようです。

現状確認

データを保存するときにstore_transitionメソドで

        self.state_memory[index] = obs.detach().numpy().flatten()
        self.action_memory[index] = action.flatten()
        self.reward_memory[index] = reward.flatten()
        self.next_state_memory[index] = next_state.flatten()
        self.terminal_memory[index] = 1 – int(done)
としているので、type()で型を見てみます。
        print(‘type of state_memory :’, type(self.state_memory[0][0]))
        print(‘type of action_memory :’, type(self.action_memory[0][0]))
        print(‘type of reward_memory :’, type(self.reward_memory[0]))
        print(‘type of next_state_memory :’, type(self.next_state_memory[0][0]))
        print(‘type of memory.state_memory :’, type(self.terminal_memory[0]))
結果、値は 全てnumpy.float64になっています。
type of state_memory : <class ‘numpy.float64’>
type of action_memory : <class ‘numpy.float64’>
type of reward_memory : <class ‘numpy.float64’>
type of next_state_memory : <class ‘numpy.float64’>
type of memory.state_memory : <class ‘numpy.float64’>
取り出す際もsample_buffer(self, batch_size)メソドで
observations = self.state_memory[choosed_index]
として戻り値を得ているので変わりません。
戻り値はpytorchのテンソルに変換しています。troch.float64になっている。
        observations = T.tensor(observations, dtype=float)
        actions = T.tensor(actions, dtype=float)
        rewards = T.tensor(rewards, dtype=float)
        next_states = T.tensor(next_states, dtype=float)
        terminals = T.tensor(terminals, dtype=float)
それを
target_actions = self.target_actor.forward(next_states)
に入れたときに起こっているのか?
class ActorNN(nn.Module):
__init__: self.fc1 = nn.Linear(n_obs_space, layer1_size)
forward :      x = self.fc1(obs) ここでエラーが発生している
 obsはバッチサイズ64x観察空間17、を入力ノード17x次層ノード64で待ち受けている。数としては問題ない。
型が合わないということなので、重みパラメータの型を調べてみる
agent.actor.fc1.weight.dtype → torch.float32
agent.target_actor.fc1.weight.dtype → torch.float32
なるほど、torch.float32で入力しなければならないようなので、変更します。
修正前:observations = T.tensor(observations, dtype=float)
修正後:observations = T.tensor(observations, dtype=T.float32)
これで回るようになりました。

ここまでのスクリプト

target_actorへnext_states  バッチサイズ64データを入力し、target_actions 64データを得ることができました。
以降、actorが1ステップ行動するごとに、target_actorへnext_states 64データを入力してtarget_actions 64データを繰り返し出力する状態になりました。
次回は、このtarget_actionsをnext_statesと共にtarget_criticへ入力するところからやっていきます。
 

DDPG by gymnasium 4日目

前回はリプレイバッファを作りました。

今回はいよいよ、ニューラルネットワークの核心、学習部分を作っていきます。

12.メインスクリプトのagent.remember()直下にagent.learn()を作ります。

13.AgentDDPGクラス内にlearn()メソドを新規作成します。

14.バッチサイズ分のトランジションが集まるまでは何も実行しない。
        if self.memory.memory_count< self.batch_size:
            return
15.メモリバッファからデータを抜き出す sample_buffer()
        obs, action, reward, new_state, done = self.memory.sample_buffer(self.batch_size)
16.ReplayBufferのメソドとしてsample_bufferメソドを追加する。
    def sample_buffer(self, batch_size):
        # indexが最大メモリに到達していない場合を想定する。
        max_index = min(self.max_memory_size, self.memory_count)
        choosed_index = np.random.choice(max.index, batch_size)
        observations = self.state_memory[choosed_index]
        actions = self.action_memory[choosed_index]
        rewards = self.reward_memory[choosed_index]
        next_states = self.next_state_memory[choosed_index]
        terminals = self.terminal[choosed_index]
        return observations, actions, rewards, next_states, terminals
17.抜き出したデータをpytorchで微分可能なようにtorch.tensor化する。torch.tensor( obs, dtype=float)
        obs = T.tensor(obs, dtype=float)
        action = T.tensor(action, dtype=float)
        reward = T.tensor(reward, dtype=float)
        new_state = T.tensor(new_state, dtype=float)
        done = T.tensor(done, dtype=float)
18.ターゲットアクターネットワークインスタンスtarget_actorに
         次の状態next_satesを入れて、ターゲットアクションtarget_actionsとして取り出す。
        target_actions = self.target_actor.forward(next_states)
19.AgentDDPGクラスにターゲットアクターネットワークインスタンスtarget_actorを作成する。actorとtarget_actorのネットワークは同じActorNN構造で良い
        self.target_actor = ActorNN(input_dim=self.input_dim, output_dim=self.output_dim)
20.ターゲットクリティックネットワークインスタンスtareget_criticに
        # 次の状態next_statesと上記より算出したターゲットアクションの2つを入力して
        # 価値関数の推定値ターゲットバリューを出力する。
        # TDターゲット:r + γ*V(w)[s_t+1] の部分のこと。
        # ターゲットクリティックバリューはターゲットアクターネットワークを使う
        target_critic_values = self.target_critic.forward(next_states, target_actions)
21.AgentDDPGクラスにターゲットクリティックネットワークインスタンスtareget_criticを作成する
        self.target_critic = CriticNN(input_dim=self.input_dim, output_dim=self.output_dim)

問題発生

2.エージェントクラスのインスタンスを生成するところで
agent = AgentDDPG(input_dim=17, output_dim=6)
としていますが、これだけの引数ではDDPGを表現できないことに気が付きました。
ActorNNは入力obsと出力actionだけなので17と6だけの情報で良かったのですが、CriticNNは入力がactionと obsの2つ、また出力が状態価値state_valueの1つあるので、ニューラルネットワークに必要な入出力の数が異なります。
よって、入力の形、学習率、ニューラルネットワークの各層とノード数など、アクターとクリティックで異なるであろう部分はエージェントクラスから含めるように修正していきます。
以下のようにエージェントクラスの引数をたくさん増やしました。
agent = AgentDDPGalpha=0.000025, beta=0.00025, gamma=0.99, tau=0.001, n_obs_space=17 , n_action_space=6, layer1_size=64, layer2_size=64, batch_size=64)
またアクターニューラルネットワーククラスへ受け渡す引数を修正しました。
self.actor = ActorNN(alpha=0.000025, n_obs_space=17, n_action_space=6, layer1_size=64, layer2_size=64, batch_size=64)

さらなる問題

“””エラーメッセージ

このエラーメッセージは、行列の乗算に問題があることを示しています。具体的には、1×64の行列と17×64の行列を乗算しようとしていますが、この操作は許容されません。なぜなら、最初の行列の列数(64)が2番目の行列の行数(17)と異なるためです。

この問題を解決するには、乗算しようとしている行列の次元を確認し、行列乗算に対して互換性のある次元になるように調整する必要があります。あるいは、行列の次元に合わせて、適切な演算や変換を使用することも検討してみてください。

“””
バッファメモリーへ保存した観測情報obsを
observations = self.state_memory[choosed_index]
によって64個のバッチサイズで抜き出して、ニューラルネットワークへ入力した時点でエラーが発生しました。
流れを今一度おさらいします。
ひとつの観測情報obsをActorNNへ入力することによって、1つ行動actionが生成されます。
このobsの形は1×17なので、バッチ64個分をバッファから抜き出すと 64×17のはずです。しかし、エラーでは1×64となっているので根本的に間違っています。
患部リプレイバッファーの初期化部分でした。
self.state_memory = np.zeros((self.max_memory_size, self.n_obs_space))
これで、観測データ1000000 x 観測空間17 を確保するつもりが、
self.state_memory = np.zeros(self.max_memory_size)
となっており、観測空間17のメモリーしか確保されていませんでした。
さらに悪いことに保存データが
self.state_memory[index] = obs.detach().numpy().flatten()[0]
となっており、観測空間17個のうち先頭の1個しか保存されないという間違いがありました。
self.state_memory[index] = obs.detach().numpy().flatten()に修正しました。
ほかにも
self.new_state_memory[index]がありますので同様に修正が必要です。
ここまでの修正スクリプト
リプレイバッファが64データ蓄積されるまでは動きます。
学習learn()メソドが始まるとエラーが出る状態です。
次回はここを解消していきます。
 

pytorchで謎の部分は下記のサイトを参考にさせていただきました。

https://qiita.com/tatsuya11bbs/items/86141fe3ca35bdae7338