強化学習: ノート10 大反省会

読んでいる本(出典): 強化学習 : Richard S.Sutton, Andrew G.Barto, 三上 貞芳, 皆川 雅章 : 本 : Amazon.co.jp
この記事はただのデバッグ記録です。

経緯

前回の記事の、「レンタカー2営業所問題」のスクリプトがバグっていた(現在は修正済)。

調査

まず駐車台数5台まで、移動可能な台数2台までに縮小して確認してみる。→ この時点でなんかもうおかしい。
右側のグラフ(方策)の一番左上のマスは、「第1営業所に5台あって第2営業所に0台あるとき、移動しないのが最適」を示唆しているけど、第2営業所の方がレンタカー要求数の期待値が高いんだから動かした方がいいはず。
もちろん1台動かすのに2ドルかかるんだけど、1台要求がくれば10ドルもらえるんだから。

f:id:cookie-box:20160411134655p:plain:w450

とりあえず「第1営業所に5台あって第2営業所に0台あるとき」を吐き出して確認すると、とりあえず元スクリプトの以下はバグっていた(上:誤→下:正)。レンタカーが借りられていったらその分駐車スペースが空いて返却を受け入れられるんだろうというあれだったけど、符号が逆だった。

    # ありうる返却台数 (駐車台数オーバー考慮)
    n.car.return.max <- max(0, 20 - n.car.morning - n.car.demand[[i.d]])
    # ありうる返却台数 (駐車台数オーバー考慮)
    n.car.return.max <- min(20, max(0, 20 - n.car.morning + n.car.demand[[i.d]]))

それで上記箇所を直しても根本的には直らなかったんだけど、補助関数内での報酬の取り扱いがまずかったようで、それを直したら直った。
元のスクリプトでは、朝時点の台数と夜時点の台数がわかった下での報酬の期待値を出していたつもりだったんだけど、なんかいまいち出せていなかったので、報酬はいつも確率を乗じた報酬として扱うことにした。

    for (i.r in 1:length(n.car.return)) {
      n.car <- n.car.morning - n.car.demand[[i.d]] + n.car.return[[i.r]]
      p.n.car[[n.car + 1]] <- p.n.car[[n.car + 1]] + p.n.car.demand[[i.d]] * p.n.car.return[[i.r]]
      reward[[n.car + 1]] <- reward[[n.car + 1]] + 10.0 * n.car.demand[[i.d]] * p.n.car.return[[i.r]] # 駄目
    }
    for (i.r in 1:length(n.car.return)) {
      n.car <- n.car.morning - n.car.demand[[i.d]] + n.car.return[[i.r]]
      p.n.car[[n.car + 1]] <- p.n.car[[n.car + 1]] + p.n.car.demand[[i.d]] * p.n.car.return[[i.r]]
      reward[[n.car + 1]] <- reward[[n.car + 1]] + 10.0 * n.car.demand[[i.d]] * p.n.car.demand[[i.d]] * p.n.car.return[[i.r]] # こうする
    }

これで補助関数が返却する reward には既に確率が乗じられていることになったので、合わせて Bellman 更新式周辺も修正する。

        p.dynam <- next.s.office1$p.n.car %o% next.s.office2$p.n.car
        r1.dynam <- matrix(rep(next.s.office1$reward, 21), nrow=21)
        r2.dynam <- matrix(rep(next.s.office2$reward, 21), nrow=21, byrow=TRUE)
        r.dynam <- r1.dynam + r2.dynam - 2.0 * abs(pi[[n1 + 1, n2 + 1]])
        v[[n1 + 1, n2 + 1]] <- sum(p.dynam * (r.dynam + gamma * v.org)) # Bellman 方程式による更新
        p.dynam <- next.s.office1$p.n.car %o% next.s.office2$p.n.car
        r1.dynam <- next.s.office1$reward %o% next.s.office2$p.n.car
        r2.dynam <- next.s.office1$p.n.car %o% next.s.office2$reward
        r.dynam <- r1.dynam + r2.dynam - 2.0 * abs(pi[[n1 + 1, n2 + 1]]) * p.dynam
        v[[n1 + 1, n2 + 1]] <- sum(r.dynam + p.dynam * gamma * v.org) # Bellman 方程式による更新

所感
これ教科書に正解がある例だからバグだとわかるけど、実際の問題でバグらせていたらどう気付くんだろう。
まあこの問題設定で方策がまだらになっているのは結構変なんだけど。だからといってどう変なのかすぐわからなかったわけだし。