Torthai
@Torthai

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

DQNで迷路を解くプログラムでtarget_networkの出力がNaNになる

解決したいこと

DQNで迷路を解くプログラムを
作っています。しかし、学習している途中に急激にtarget-networkの出力が変化することがあり困っています。
ちなみにGoogle colaboratoryでやっています。

発生している問題

IMG_0787.jpeg

(写真の2つ数値を持つのtuple型のデータは迷路上の位置です。)
こんな感じで最終的には出力がNaNになり、学習が止まってしまうのです。Q-networkに問題があるものとみていますが解決方法がわかりませんでした。

迷路の説明

[[3, 2, 0, 1],
[0, 0, 0, 2],
[0, 0, 2, 0],
[2, 0, 2, 0],
[0, S, 0, 0]]
0は通常の道、1はゴール、2は壁、3はトラップで、Sはスタートで、わかりやすくするためにSと書いています(本当は通常の道です)
ゴールかトラップに着いたらスタートに戻ります。
報酬はゴールに着いたら1,トラップに着いたら-1,壁に着いたら-1で、通常の道に着いたら0です。

自分で試してみたこと

NaNを0.0に置き換えるコードを追加したら、出力が全て0.0になってしまいました。
隠れ層の層の数を減らしても問題が発生しなくなることはありませんでした。

Deeplearningののプログラム

IMG_0788.jpeg
(Jupyterliteでにて撮影)

参考文献

https://qiita.com/birdwatcher/items/75541ca2b14ba22e64a7
https://www.tcom242242.net/entry/ai-2/強化学習/【強化学習、入門】q学習_迷路を例に/

0

5Answer

僕はミニバッチ学習について、いまいちよく理解できていない

こちらの記事が理解に繋がると思います.

DQNの場合だと、例えば10個ランダムにサンプルデータを抽出して、そのデータのエラーを、サンプルデータの中で行動0をした数、行動1をした数というように集計したもので平均し、学習させるというものでよろしいでしょうか?

平均を取るのは一般にエラーの量です.エラー関数(損失関数のが一般ですね)の計算手順を見れば分かる通りの集計を行います.

2Like

Comments

  1. @Torthai

    Questioner

    つまり、N個のデータを集めたとしたら、N個そのエラーの合計をNで割れば良い、ということですか?

  2. 例えばCross Entropy LossはNで除しませんが,Mean Squared Errorは名前の通り平均をとりますね.

    モデル出力の関数特性次第でどういう損失関数を採用するか決めるので,Nで除すかどうかは一概には言えないです.値が発散しそうならNで除すぐらいの認識で良いかと思います(回答で「一般に〜」と濁したのはこの理由からです).

  3. @Torthai

    Questioner

    わかりました!

  4. copy.deepcopyを持ちいていないから?

    URLのアルゴリズムを机上ではわからないですが、扇子のように多岐に渡る経路をグループ化しているように感じます。力及ばずですみません。

  5. @Torthai

    Questioner

    大丈夫です。多分、copy.deepcopyは要らないと思います。急激に値が変化しているのでディープネットワークの問題だと思います。

深層学習でないのですが、

従来の手法ではダイクストラ法等のアルゴリズムを持ちいて最短パスを求めました。ご参考まで

さて、

DQNのロジックと迷路探査+点数計算のロジックをクラスで分離するとスッキリした構成になるのでは?

報酬はゴールに着いたら1,トラップに着いたら-1,壁に着いたら-1で、通常の道に着いたら0です。

どの経路のゴール報酬が1では最短パスが求められないのでは?

報酬は加算方式で高得点と経路を学習し最短パスを求める。

ゴールに着いたら合計点を報酬として学習
トラップに着いたら-99,(トラップ通過を許容)
壁に着いたら-99で、(壁通過を許容)
一度、通った通常の道に着いたら-9で、
新たな、通常の道に着いたら+1ではどうでしょう。

1Like

Comments

  1. @Torthai

    Questioner

    御回答ありがとうございます。DQNのロジックと迷路探索(移動)+報酬計算のロジックはすでにクラスで分けてあります。
    報酬を加算方式にすると最短経路のときの報酬が1番大きくなるわけですね。やってみたいと思います!
    また出力がNaNになって学習が止まってしまったらお伺いします。
    話は変わりますが、僕はミニバッチ学習について、いまいちよく理解できていないんです。
    DQNの場合だと、例えば10個ランダムにサンプルデータを抽出して、そのデータのエラーを、サンプルデータの中で行動0をした数、行動1をした数というように集計したもので平均し、学習させるというものでよろしいでしょうか?

  2. @Torthai

    Questioner

    御回答を編集されたようですね。御丁寧にありがとうございます。報酬についてですが大きな値にQ-networkが振り回されそうで心配です。

  3. 僕はミニバッチ学習について、いまいちよく理解できていない

    残念ながら私もです。余り深層学習に興味がないので、

    深層学習をホウキの先のようにニューラルネットワークを形成する際、ホウキ元を複数のグループに分けて(根本を紐で結んでいるように)、平均してグループの優位性を評価するだけで、二次学習の指針、方向性を見極めていると解釈してます。

    すみません。今はホウキは死語でしょうか? (魔女の宅配便のデッキブラシでしょうか?)

  4. @Torthai

    Questioner

    そうなんですね。御回答をもとにプログラムを変えていきたいと思います。後日、結果を報告させていただきます。

  5. @Torthai

    Questioner

    Screenshot_20231219-150049~2.png
    通ったことのない通常の道に着いたときの報酬は1.0,一度通ったことのある通常の道に着いたときの報酬は-1にしました。またゴールに着いたときの報酬は2.0,トラップに着いたときの報酬は-2.0、壁に着いたときの報酬は-1.0にしました。(壁の通り抜けはなしにしました)上手く行きそうな雰囲気なのですが、ディープネットワークがダメなのか、上のように出力がNaNになってしまうことが多いです。大きな値にかなり弱いようです。どうすればディープネットワークを大きな値に強くして出力がNaNになることを防げるのでしょうか?

  6. @Torthai

    Questioner

    ホウキについてですが、すみません。私の知識が浅すぎて死語なのかもわかりません。後日勉強します。

  7. @Torthai

    Questioner

    地震、大丈夫でしたか?

Screenshot_20231219-150049~2.png
通ったことのない通常の道に着いたときの報酬は1.0,一度通ったことのある通常の道に着いたときの報酬は-1にしました。またゴールに着いたときの報酬は2.0,トラップに着いたときの報酬は-2.0、壁に着いたときの報酬は-1.0にしました。(壁の通り抜けはなしにしました)上手く行きそうな雰囲気なのですが、ディープネットワークがダメなのか、上のように出力がNaNになってしまうことが多いです。大きな値にかなり弱いようです。どうすればディープネットワークを大きな値に強くして出力がNaNになることを防げるのでしょうか?

0Like

Comments

  1. 例えば時系列解析系のニューラルネットでは,1階微分の値を入出力として取ることで値域が一定の範囲に収まると仮定した学習をすることで対策します.

    今回は負の値が無限大になる可能性があるので,どこかしらで切らないとおかしくなると考えます.

    負の下限を決め,正の上限も通ったことないという制約のもと最大値が決まっているはずなので,この2つを使ってmin-max正規化をかけて報酬値を扱うのもありだと思います.

  2. @Torthai

    Questioner

    ふむふむ。しかし、報酬を1〜-1の範囲に収めても、だいたい10000回学習する間に出力がNaNになってしまいます。ミニバッチ学習でも、です。
    報酬を0〜1の範囲に収めても同じになってしまうのではないでしょうか。
    1つ質問があります。
    ニューラルネットワークを「どこかしらで切」るとはどういったことでしょうか?

  3. 切るのは学習の動作のほうです.

    例えば,倒立振子問題を強化学習する際には,支点がある範囲を越えたら失敗と見做してそれ以降の評価は行わないということをします.理論上の話で言えば,倒立振子が倒れる速度をちょうど打ち消すように,倒れる方向に移動させれば傾いたまま振り子を移動させることができますが,これでは問題を解決したとは言えなくなるからです.実際無限に倒れないので一見目的を達成しているようには見えますが...

    今回も,一度踏んだ場所を再訪問しまくるのは問題があるとして,それ以降コマを進めないようにするという打ち切りが必要です.

  4. @Torthai

    Questioner

    ご指摘ありがとうございます!

  5. @Torthai

    Questioner

    報酬はゴールに着いたら0.5、トラップに着いたら-0.5、通ったことのない通常の道に着いたら0.5、通ったことのある通常道に着いたら-0.5、壁(マップ外も含む)に着いたら-0.8にしました。報酬が-0.8以下になると、NaNが出やすくなります。1回だけ、この報酬値で学習したらNaNが出ました。
    ダウンロード (2).png
    [[0,1],
    [0],
    [0],
    [0],
    [0]]
    のような簡単な迷路は解くことができるようです。
    ただ、
    [[3, 2, 0, 1],
    [0, 0, 0, 2],
    [0, 0, 2, 0],
    [2, 0, 2, 0],
    [0, S, 0, 0]]
    この迷路だと、スタートから上にずっと進むようになってしまいます。
    どうすれば良いでしょうか?
    また、学習の打ち切りは具体的にはどうすれば良いでしょうか?私が考えているのは2つあります。
    1つ目は、
    一定回数以上同じ状態を繰り返したら強制的に違う状態にするようにプログラムする方法です。
    しかし、また同じところで止まって違う状態になるというループが始まり、その状態の学習が良い方向に進まなくなってしまうと思います。
    2つ目は、
    ディープネットワーク重みをリセットして全て重みを変える方法です。いかがでしょうか?

  6. これちゃんと$\epsilon-greedy$方策でやってる上でそうなる.という感じですか?

  7. @Torthai

    Questioner

    はい。εを0.3にしてます。

  8. @Torthai

    Questioner

    修正で、今、学習に困っている迷路は
    [[3, 2, 0, 1],
    [0, 0, 0, 2],
    [2, 0, 2, 0],
    [2, 0, 2, 0],
    [2, S, 2, 0]]
    です。段階的にやって、最後に最初の
    [[3, 2, 0, 1],
    [0, 0, 0, 2],
    [0, 0, 2, 0],
    [2, 0, 2, 0],
    [0, S, 0, 0]]
    の迷路を学習させようと思います。

  9. @Torthai

    Questioner

    ちなみに学習の数は30000回です。
    episode数ではなくてすみません。

  10. @Torthai

    Questioner

    学習数は60000回、583episodeの出力です。
    迷路の左上を(1,1)としています。
    (2, 5)
    [-2.72771174e-06 -5.83508447e-07 1.18600018e-04 1.11179306e-04]
    スタートで止まってしまうことが多いです。

  11. 手を動かせるのが週末以降になりそうなので,検証には少し時間をください.
    現状の確認ですが,質問本文に示している参考リンクの2つ目のプログラムをベースに,DQNにするべく1つ目リンクのDQNを真似ている.という認識で良いでしょうか.

  12. @Torthai

    Questioner

    すみません。コードに大きな誤りがあったため訂正しました。
    報酬はゴールに着いたら0.2、トラップに着いたら-0.2、通ったことのない通常の道に着いたら0.1、通ったことのある通常道に着いたら-0.1、壁(マップ外も含む)に着いたら-0.1にしました。
    報酬が小さいこのコードで
    [[0,1],
    [0],
    [0],
    [0],
    [0]]
    上記の迷路をやったら、学習回数60000回以内に下記のように出力がNaNになってしまいました。
    また報酬をゴールに着いたら0.1、トラップに着いたら-0.1に変えてもNaNになってしまいました。
    (1, 1)
    [nan nan nan nan]
    (1, 1)
    [nan nan nan nan]
    (1, 1)
    [nan nan nan nan]
    (1, 1)
    [nan nan nan nan]
    (1, 1)
    [nan nan nan nan]
    (1, 1)
    [nan nan nan nan]
    (1, 5)
    [nan nan nan nan]
    (1, 4)
    [nan nan nan nan]
    (1, 3)
    [nan nan nan nan]
    (1, 3)
    [nan nan nan nan]
    NaNの原因がわかりません。どうすれば良いでしょうか?
    実は今まで、報酬をクリップするコードで報酬が全てゼロになってしまっていました。
    何卒よろしくお願いいたします。

  13. @Torthai

    Questioner

    プログラムが雑で誠に申し訳ございません。

  14. @Torthai

    Questioner

    あんな雑な私の記事へ、いいねをしてくださり、本当にありがとうございます!

  15. いくつか通常とは異なる(つまりうまくいかなくなる要因となりそう)な実装が見つかりました.
    まず,stateに関してです.
    座標のみを受け取ってしまい,マップ依存の学習をしてしまいます.普通は,マップ全体とその状態(どこに何があるかなど)の情報を入力として受け取らなければなりません.

    同時に,mapの広さに応じて,入力としてとるstateの値が大きくなると思います.何せ整数座標値ですからね.普通は,mapの広さに応じた入力の数を増加させ,各座標の設定値(現在地,トラップ,ゴール,既訪問等)はOne-Hot Encodingするべきです.

    要素数で言えば,現状は$(x, y)$座標を意味する2要素の一次元配列ですが,普通はmapの広さ$(W, H)$と取りうる設定値の種類数の分だけ必要です.次のマップ例えると,

    G W 0 T
    0 0 0 W
    0 0 W 0
    W 0 W 0
    0 S 0 0
    

    という形式(Start, Goal, Wall, Trap, 0, Visited)の6種類の設定値かつ広さ$(W, H) = (4, 5)$であれば,入力の形式は$(4, 5, 6)$の三次元配列の入力を取るか,それを平滑化して要素数120の一次元配列を入力として取る必要があります.

    そうでないにしても,座標値だけを入力として受け取るだけでは,訪問済かどうかの記憶をする箇所がどこにもないので,初回のみ訪問に意味があり,それ以外はその座標に意味を見出せなくなり学習がうまくいきません.

    今回は,与えられた情報が少なすぎてストレートにゴールに行く以外は報酬が得られず,さらにはゴールに辿り着く方法ですら(座標でしか判断しないため)ダメな方法だと上書きしてしまうという過程から,値がnanに届いてしまうものだと考えます.

  16. @Torthai

    Questioner

    この迷路では、

    [[[0,0,0,0],
      [0,0,0,0],
      [0,0,0,0],
      [0,0,0,0],
      [0,0,0,0],
      [0,1,0,0]],
     [[1,0,0,0],
      [0,0,0,0],
      [0 0,0,0],
      [0,0,0,0],
      [0,0,0,0],
      [0,0,0,0]],
     [[0,1,0,0],
      [0,0,0,1],
      [0,0,1,0],
      [1,0,1,0],
      [1,0,1,0],
      [0,0,0,0]],
     [[0,0,0,1],
      [0,0,0,0],
      [0,0,0,0],
      [0,0,0,0],
      [0,0,0,0],
      [0,0,0,0]],
     [[0,0,1,0],
      [1,1,1,0],
      [1,1,0,1],
      [0,1,0,1],
      [0,1,0,1],
      [1,0,1,1]]]
    

    というようなデータになるのでしょうか?
    また、ワンホットエンコーディングはどのように使うのでしょうか?そして、学習とはどのように結びつくのでしょうか?

  17. その認識であたってます.よく考えたら訪問済を設定していなかったので,正しくは次のようになります.(先の回答を編集したついでにmapの広さを少し小さくしました)

    [[[0,0,0,0], # Start
      [0,0,0,0],
      [0,0,0,0],
      [0,0,0,0],
      [0,1,0,0]],
     [[1,0,0,0], # Goal
      [0,0,0,0],
      [0 0,0,0],
      [0,0,0,0],
      [0,0,0,0]],
     [[0,1,0,0], # Wall
      [0,0,0,1],
      [0,0,1,0],
      [1,0,1,0],
      [0,0,0,0]],
     [[0,0,0,1], # Trap
      [0,0,0,0],
      [0,0,0,0],
      [0,0,0,0],
      [0,0,0,0]],
     [[0,0,1,0], # not visited
      [1,1,1,0],
      [1,1,0,1],
      [0,1,0,1],
      [1,0,1,1]],
     [[0,0,0,0], # visited
      [0,0,0,0],
      [0,0,0,0],
      [0,0,0,0],
      [0,1,0,0]]]
    

    これはChannel First形式のOne Hot Encodingと言うことができて,画像処理分野でよく使われるスタイルです.
    NWHC形式とも呼ぶことがあります.(batch Number, Channel, Width, Height)の4階のテンソルをニューラルネットに与えてバッチ学習をするからですね.

  18. @Torthai

    Questioner

    ご丁寧にありがとうございます!
    現在地のデータはどのように使うのでしょうか?

  19. @Torthai

    Questioner

    現在地のデータも3次元配列に組み込む形でしょうか?
    たとえば、スタートにいるなら、
    [[0,0,0,0],
    [0,0,0,0],
    [0,0,0,0],
    [0,0,0,0],
    [0,1,0,0]]
    という形で3次元配列に組み込むのでしょうか?

  20. 確かに.その次元も増やさなくてはなりませんね.$(4, 5, 7)$になりそうでしょうか.

  21. @Torthai

    Questioner

    140個の入力層を取るか、7個の入力層を取って配列の掛け算をするかの2つの方法がありますが、どちらが良いのでしょうか?個人的には140個の入力層を取ったほうが楽そうです。
    配列掛け算はとてもややこしそうです…

  22. 前者を推奨します.後者までいくと機械学習のライブラリ使わないと無理があります.

  23. @Torthai

    Questioner

    わかりました!ありがとうございます!
    やってみて、後日報告させていただきたいと思います!

  24. @Torthai

    Questioner

    入力データを作るときに、そのデータをmapをもとに作る必要があると思います。
    しかし、考えてみたところ、
    1.入力データにするための空の1次元リストを作る。
    2.mapと形状が同じで全要素が0のリストを作って、それをfor文を使って指定の場所を1に置き換える。
    3.2で作ったものを1で作ったリストに追加する。
    という少々面倒なコードになりそうです。
    for文はあまり使いたくないのですが、
    どうすればもっと簡潔なコードになるのでしょうか?

  25. 次の実装が簡単簡潔な実装になりそうです.2重forは避けられないですね.

  26. @Torthai

    Questioner

    ありがとうございます!

  27. @Torthai

    Questioner

    自分でも考えて見ました。実は迷路は全要素が全て数値なのです。

    import numpy as np
    class test:
        def __init__(self):
            self.spawn=(2,5)
            self.world=[[3, 2, 0, 1],
                        [0, 0, 0, 2],
                        [0, 0, 2, 0],
                        [2, 0, 2, 0],
                        [0, 0, 0, 0]]
            self.copy_world=np.array(self.world)
            self.copy_world[self.spawn[1]-1][self.spawn[0]-1]=4
            self.data=[]
            for i in range(5):
                self.the_map=self.copy_world
                self.data.append(np.where(self.the_map==i,1,0))
            self.data.append(self.data[-1])
            self.data.append(np.where(self.data[-1]==0,1,0))
    
    
    a=test()
    

    どうでしょうか?

  28. @Torthai

    Questioner

    入力値を作れました。

    import numpy as np
    class test:
        def __init__(self):
            self.spawn=(2,5)
            self.world=[[3, 2, 0, 1],
                        [0, 0, 0, 2],
                        [0, 0, 2, 0],
                        [2, 0, 2, 0],
                        [0, 0, 0, 0]]
            self.copy_world=np.array(self.world)
            self.copy_world[self.spawn[1]-1][self.spawn[0]-1]=4
            self.data=[]
            for i in range(5):
                self.the_map=self.copy_world
                self.data.append(np.where(self.the_map==i,1,0))
            self.data.append(self.data[-1])
            self.data.append(np.where(self.data[-1]==0,1,0))
            self.data=list(np.ravel(self.data))
            print(self.data)
    
    a=test()
    
  29. いいですね.ちなみに1座標につき最大で

    • スタート地点
    • 現在地
    • 訪問済

    の3つのパラメータが重複する可能性があると思うのですが,これはどう対処する予定でしょうか.

  30. @Torthai

    Questioner

    ご指摘ありがとうございます。
    知識不足で誠に申し訳ないのですが、重複するとどのような問題が発生するのでしょうか?
    補足ですが、現在地、訪問済、未訪問の3つのリストを行動するごとに更新していく方針です。なお、このコードは初期値の設定のためのものです。

  31. なるほど,1つのリストで実現する場合は重複して問題になりますが,確かにそのように分けることで回避できます.これを聞きたかったところです.

  32. @Torthai

    Questioner

    [[[0,0,0,0], # Start
      [0,0,0,0],
      [0,0,0,0],
      [0,0,0,0],
      [0,1,0,0]],
     [[1,0,0,0], # Goal
      [0,0,0,0],
      [0 0,0,0],
      [0,0,0,0],
      [0,0,0,0]],
     [[0,1,0,0], # Wall
      [0,0,0,1],
      [0,0,1,0],
      [1,0,1,0],
      [0,0,0,0]],
     [[0,0,0,1], # Trap
      [0,0,0,0],
      [0,0,0,0],
      [0,0,0,0],
      [0,0,0,0]],
     [[0,0,1,0], # not visited
      [1,1,1,0],
      [1,1,0,1],
      [0,1,0,1],
      [1,0,1,1]],
     [[0,0,0,0], # visited
      [0,0,0,0],
      [0,0,0,0],
      [0,0,0,0],
      [0,1,0,0]],
     [[0,0,0,0], #現在地
      [0,0,0,0],
      [0,0,0,0],
      [0,0,0,0],
      [0,1,0,0]]]
    

    つまり、2次元リストの順番は入れ替えても良い(プログラム全体で統一する)として、上のような3次元リストを作り、それを1次元リストにして、ディープネットワークに入力する、という認識でよろしいでしょうか?

  33. はい,その認識で当たってます.

  34. @Torthai

    Questioner

    ありがとうございます。

  35. @Torthai

    Questioner

    上記の3次元リストをstate,syoki_stateとして、
    1.stateを受け取る。
    2.stateをもとにε-greedyで行動選択をする。
    3.選択した行動を受け取る。
    4.3をもとにstateのリストの中の現在地、既に訪問した場所、未訪問の場所のリストを更新し、next_stateと報酬を求める。ゴールかトラップについたら、stateを初期値に戻す。
    5.4をもとに学習する。
    6.1〜5を繰り返す。
    という流れでよろしいでしょうか?

  36. @Torthai

    Questioner

    meiro classとmain.pyだけ変更しました。

    meiro.py
    class meiro:
        def __init__(self,world,spawn):
            self.world=world
            self.actions={
                "UP": 0,
                "DOWN": 1,
                "LEFT": 2,
                "RIGHT": 3
            }
            self.filed_type={
                "N": 0,  # 通常
                "G": 1,  # ゴール
                "W": 2,  # 壁
                "T": 3,  # トラップ
            }
            self.spawn=(spawn[0]-1,spawn[1]-1)
            self.position=self.spawn
    
            #Deepnetworkの入力値を作る
            self.copy_world=np.array(self.world)
            self.copy_world[self.spawn[1]-1][self.spawn[0]-1]=4
            self.state=[]
            self.count_fieled_type=len(self.filed_type)
            for i in range(self.count_fieled_type+1):
                self.state.append(np.where(self.copy_world==i,1.0,0.0))
            self.state.append(self.state[-1])
            self.state.append(np.where(self.state[-1]==0,1.0,0.0))
    
            self.syoki_state=self.state
            #visited,not visitedのリスト内番号
            self.acsess_visited=self.count_fieled_type+1
            self.acsess_not_visited=self.count_fieled_type+2
    
            #初期化
            self.count_goal=[]
            self.episode_reward=[]
            self.rewards=[]
            self.episode_step=0
            self.steps=[]
            self.episode=0
    
        def show_state(self):
            return list(np.ravel(self.state))
    
        def action(self,act):
            print(self.position)
            self.xp=self.position[0]
            self.yp=self.position[1]
            if act==self.actions["UP"]:
               self.yp-=1
            if act==self.actions["DOWN"]:
               self.yp+=1
            if act==self.actions["LEFT"]:
               self.xp-=1
            if act==self.actions["RIGHT"]:
               self.xp+=1
            self.episode_step+=1
            if self.is_it_ok()==True:
                self.next_position=(self.xp,self.yp)
                if self.world[self.yp][self.xp]==self.filed_type["N"]:
                  if self.state[self.acsess_visited][self.yp][self.xp]==1.0:
                      self.reward=-0.1
                  else:
                      self.reward=0.1
                      self.state[self.acsess_visited][self.yp][self.xp]=1.0
                      self.state[self.acsess_not_visited][self.yp][self.xp]=0.0
    
                  #現在地の更新
                  self.the_position=self.state[self.count_fieled_type]
                  np.place(self.state[self.count_fieled_type],self.the_position==1.0,0.0)
                  self.state[self.count_fieled_type][self.yp][self.xp]=1.0
    
                  self.set_result_data(False,False,False)
    
                if self.world[self.yp][self.xp]==self.filed_type["G"]:
                    self.reward=0.1
                    self.state=self.syoki_state
                    self.set_result_data(True,True,True)
                if self.world[self.yp][self.xp]==self.filed_type["T"]:
                    self.reward=-0.1
                    self.state=self.syoki_state
                    self.set_result_data(True,False,False)
    
            else:
                self.reward=-0.1
                self.set_result_data(False,False,True)
    
            return (list(np.ravel(self.state)),self.reward,self.is_no_next)
    
        def is_it_ok(self):
            if self.yp>=len(self.world) or self.yp<0:
                return False
            elif self.xp>=len(self.world[self.yp]) or self.xp<0:
                return False
            elif self.world[self.yp][self.xp]==self.filed_type["W"]:
                return False
            return True
    
        def set_result_data(self,is_no_next,is_goal,is_it_wall):
          self.episode_reward.append(self.reward)
          if is_no_next==True:
            self.is_no_next=True
            self.rewards.append(sum(self.episode_reward))
            self.episode_reward=[]
            self.steps.append(self.episode_step)
            self.episode_step=0
            self.episode+=1
            self.position=self.spawn
            if is_goal==True:
              self.count_goal.append(True)
            else:
              self.count_goal.append(False)
          else:
            self.is_no_next=False
            if is_it_wall==True:
              self.next_position=self.position
            else:
              self.position=self.next_position
    
    
        def result(self):
            return (self.rewards,self.count_goal,self.steps,self.episode)
        def reset(self):
          self.rewards=[]
          self.count_goal=[]
          self.steps=[]
          self.episode_step=0
          self.position=self.spawn
          self.rewards=[]
          self.episode_reward=[]
          self.episode=0
          self.save_position=[self.spawn]
    
    main.py
    world=[[3, 2, 0, 1],
           [0, 0, 0, 2],
           [2, 0, 2, 0],
           [2, 0, 2, 0],
           [2, 0, 2, 0]]
    world2=[[1],
            [0],
            [0],
            [0],
            [0]]
    map=world
    a=Qlearning(0.3,0.3,0.3,np.array(map).size*7,4)
    b=meiro(map,(2,5))
    for i in range(30000):
        state=b.show_state()
        action=a.act(state)
        data=b.action(action)
        a.note(data[0],data[1],data[2])
        a.learn(True,10,True,0.5)
    episode=b.result()[3]
    b.reset()
    a.change_gamma(0.0)
    for i in range(50):
      state=b.show_state()
      action=a.act(state)
      b.action(action)
    result=b.result()[2]
    plt.plot(range(1,len(result)+1),result)
    plt.xlabel("episode")
    plt.ylabel("step")
    plt.show()
    print(result)
    result2=b.result()[1]
    print(episode)
    #for i in range(1,4):
      #c.append(np.where(result[i-50]<100,1,0))
    #d=len(c)
    #c=sum(c)
    #print(c/d*100)
    

    Screenshot_20231229-165208~2.png

    しかし、ミニバッチ学習でも、でなくとも
    出力がやはりNaNになってしまいます。どうすれば良いでしょうか?

  37. @Torthai

    Questioner

    地震、大丈夫でしたか?

皆様のアドバイスによって、プログラムを完成させることができました。ありがとうございました!

0Like

Your answer might help someone💌