Paoの技術力を磨くブログ

機械学習やブロックチェーン等の技術を身に付けていくブログです。

【深層強化学習】Chainerrlのa3cのモデル定義で入力チャネル数でNoneは使わないこと

急にテーマが代わり、強化学習の話。
しかも、かなりニッチな話。

深層強化学習のライブラリとして「Chainrrl」を使っている。
「Chainrrl」はPreferred Networksが提供しているChainerを使った深層強化学習ライブラリ。
新しい手法とかも実装されているので便利。

「a3c」という強化学習手法を実装しているとき下記のようなエラーが発生した。

エラー内容

  File "/Library/Python/2.7/site-packages/chainerrl/agents/a3c.py", line 122, in __init__
    async.assert_params_not_shared(self.shared_model, self.model)
  File "/Library/Python/2.7/site-packages/chainerrl/misc/async.py", line 63, in assert_params_not_shared
    assert a_param.data.ctypes.data != b_param.data.ctypes.data
AttributeError: 'NoneType' object has no attribute 'ctypes'

エラーの内容の通りだが、指定したモデルを同期しようしたときにパラメータ型でエラーが発生している。

原因と対策

モデルの中で下記の通り、モデルの定義部分で入力チャネル数(Convolution2Dの第1引数)をNoneにするとダメらしい。

    def __init__(self, ndim_obs,n_channels=4):
        super(CommonFunction, self).__init__(
            conv1=L.Convolution2D(None,16,ksize=(4,1),pad=1,stride=1),
            conv2=L.Convolution2D(None,32,ksize=4,pad=1,stride=1),
            conv3=L.Convolution2D(None,64,ksize=4,pad=1,stride=1),
            c_fc1=L.Linear(256, 200),
            c_fc2=L.Linear(200, 200),
            c_fc3=L.Linear(200, 34))

入力チャネル数を指定するとうまく動く

    def __init__(self, ndim_obs,n_channels=4):
        super(CommonFunction, self).__init__(
            conv1=L.Convolution2D(3,16,ksize=(4,1),pad=1,stride=1),
            conv2=L.Convolution2D(16,32,ksize=4,pad=1,stride=1),
            conv3=L.Convolution2D(32,64,ksize=4,pad=1,stride=1),
            c_fc1=L.Linear(256, 200),
            c_fc2=L.Linear(200, 200),
            c_fc3=L.Linear(200, 34))

おそらく、a3cのaの一つである「Asynchronous(非同期)」の実装に、ctypesを利用しているが、
L.Convolution2D(None,....)とすると、ctypesを持たないインスタンスになってしまうので、エラーになってしまう。
(chainerrlのasync.pyの56~63行目あたり)
(あまりちゃんとchainerrlのソース読んでないので憶測です。)
ちなみにDeepQNetwork(DQN)ではL.Convolution2D(None,....)で問題なかった。
(Asynchronousではないからかな?)

ちなみに上の例では、L.Convolition2DでNoneを指定しているが、L.Linear(None,...)でも同じ話。

まぁ深く考えず入力チャネル数を指定すればいいだけ。