質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

91.06%

  • Python

    5124questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • 機械学習

    443questions

    機械学習は、データからパターンを自動的に発見し、そこから知能的な判断を下すためのコンピューターアルゴリズムを指します。人工知能における課題のひとつです。

  • Chainer

    87questions

    Chainerは、国産の深層学習フレームワークです。あらゆるニューラルネットワークをPythonで柔軟に書くことができ、学習させることが可能。GPUをサポートしており、複数のGPUを用いた学習も直感的に記述できます。

chainerのNStepLSTMを使う際、backwardを呼んだときにエラーが出る

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 319

karibou

score 0

前提・実現したいこと

chainerのNStepLSTMを用いて分類器を作成したいのですが、backwardを呼んだときにエラーが発生してしまい上手くいきません。
最終ステップの出力のみを使用するモデルで、hとcの初期値はゼロ(None)です。

問題の原因が全く分からず、行き詰まってしまっています。
どなたか、ご教授いただけると助かります。よろしくお願いいたします。

該当のソースコード

以下は検証用に書いたコードですので入力データはランダムですが、本番コードと全く同じエラーが発生します。

class LSTM(Chain):
    def __init__(self):
        super(LSTM, self).__init__()
        with self.init_scope():
            self.lstm = L.NStepLSTM(2, 10, 20, dropout=0.2)
            self.linear = L.Linear(20, 5)

    def __call__(self, x):
        hy, cy, ys = self.lstm(None, None, x)
        h = ys[-1] # 最終ステップの出力のみ使用
        y = self.linear(h)
        return y

# 検証用にランダムデータを生成
x = (
    np.random.rand(1, 10).astype(np.float32),
    np.random.rand(1, 10).astype(np.float32),
    np.random.rand(1, 10).astype(np.float32),
)
t = chainer.Variable(np.random.randint(0, 5, 1)) # 0~4
model = LSTM()
y = model(x)

loss = F.softmax_cross_entropy(y, t)
loss.backward() # ここでエラーが発生します

発生している問題・エラーメッセージ

以下は実際に発生したエラーメッセージです。

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-434-55a3c0a0f5fa> in <module>()
     11 
     12 loss = F.softmax_cross_entropy(y, t)
---> 13 loss.backward()

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/chainer/variable.py in backward(self, retain_grad, enable_double_backprop)
    878         """
    879         with chainer.using_config('enable_backprop', enable_double_backprop):
--> 880             self._backward_main(retain_grad)
    881 
    882     def _backward_main(self, retain_grad):

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/chainer/variable.py in _backward_main(self, retain_grad)
    979 
    980             gxs = func.backward_accumulate(
--> 981                 target_input_indexes, out_grad, in_grad)
    982 
    983             assert len(gxs) == len(in_grad)

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/chainer/function_node.py in backward_accumulate(self, target_input_indexes, grad_outputs, grad_inputs)
    512         # The default implementation uses backward(). You can override this
    513         # method without using backward().
--> 514         gxs = self.backward(target_input_indexes, grad_outputs)
    515 
    516         len_gxs = len(gxs)

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/chainer/functions/array/transpose_sequence.py in backward(self, indexes, grad_outputs)
     83 
     84     def backward(self, indexes, grad_outputs):
---> 85         return TransposeSequence(len(self.inputs)).apply(grad_outputs)
     86 
     87 

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/chainer/function_node.py in apply(self, inputs)
    228 
    229         if configuration.config.type_check:
--> 230             self._check_data_type_forward(in_data)
    231 
    232         hooks = chainer.get_function_hooks()

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/chainer/function_node.py in _check_data_type_forward(self, in_data)
    288         try:
    289             with type_check.light_mode:
--> 290                 self.check_type_forward(in_type)
    291             return
    292         except type_check.InvalidType:

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/chainer/functions/array/transpose_sequence.py in check_type_forward(self, xs_type)
     73         for p, n in zip(xs_type, xs_type[1:]):
     74             type_check.expect(
---> 75                 p.shape[0] >= n.shape[0],
     76                 p.shape[1:] == n.shape[1:],
     77             )

AttributeError: 'NoneType' object has no attribute 'shape'

試したこと

以下は試行錯誤していて気づいたことです。
不思議なのですが、以下のように各ステップの出力を加算するモデルに変更するとエラーが出なくなります。

class LSTM(Chain):
    ...
    def __call__(self, x):
        hy, cy, ys = self.lstm(None, None, x)
        h = sum(ys) # 各ステップの出力を加算する
        y = self.linear(h)
        return y

...

loss.backward() # エラーが発生しない

補足情報(言語/FW/ツール等のバージョンなど)

Python 3.6.2
Chainer 3.2.0

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

check解決した方法

0

NStepLSTMの使い方を間違えていました。
ys[-1]は、最終ステップの出力ではなく、ミニバッチ内の1つのデータに対する全ステップ出力を指しているようです。

なので、正しく最終ステップの出力を得るには以下の様にリスト内の各要素の末尾を取って連結すれば良いみたいです。

def __call__(self, x):
    hy, cy, ys = self.lstm(None, None, x)
    h = F.vstack(map(lambda y: y[-1], ys))
    y = self.linear(h)
    return y

このコードで問題なく動きました。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

NStepLSTMの実装の問題かもしれません。(仕様?)

BPする時にys[-1]だと、ys[-1]にしか伝搬できなくて、ys[0]=ys[1]=Noneになっているようです。
sumすると分配されて、Noneが解消されます。

https://www.slideshare.net/Retrieva_jp/chainer-trainer-nsteplstm#46
のようにlossは自分で書かないといけないのかもしれません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 91.06%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Python

    5124questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • 機械学習

    443questions

    機械学習は、データからパターンを自動的に発見し、そこから知能的な判断を下すためのコンピューターアルゴリズムを指します。人工知能における課題のひとつです。

  • Chainer

    87questions

    Chainerは、国産の深層学習フレームワークです。あらゆるニューラルネットワークをPythonで柔軟に書くことができ、学習させることが可能。GPUをサポートしており、複数のGPUを用いた学習も直感的に記述できます。