中間層のニューロンを大きく取るとlossがnanになる?

7,902 views
Skip to first unread message

naturecode...@gmail.com

unread,
Sep 7, 2015, 8:04:24 AM9/7/15
to Chainer User Group
こんにちは
よろしくお願いします。

Chainerを使い始めたDeepLearning初学者です。1つわからない問題がありご質問させて頂きます。
入力が1875次元の2値分類のネットワークを以下の様に組み
model = chainer.FunctionSet(l1=F.Linear(1875, 2000),
                                l2=F.Linear(2000, 1000),
                                l3=F.Linear(1000, 256),
                                l4=F.Linear(256, 2))
学習させた所、lossがnanもしくは-infになり正しく学習されて無いように見えました。(ロス関数はサンプルにあったsoftmax_cross_entropyを使っています。)(関係無いかもしれないですが、入力データの数値が大きすぎてoverflowを起こしていた問題は気づいて修正しました。現在は1875次元全ての入力は有効数字5桁以内の数値です。)

他に試した以下の様な簡単なネットワークでも
def __init__(self):
        super(ThreeHiddenNN, self).__init__(
            l1=chainer.functions.Linear(5, 10),
            l2=chainer.functions.Linear(10, 10),
            l3=chainer.functions.Linear(10, 2)
        )
上の構造では正しく動いている様に見えましたが、
中間層を1000や2000など試しに大きく取ってみると、やはりlossがnanになります。
 lossがnanになる際に必ずWarningで

/usr/local/lib/python2.7/site-packages/chainer/functions/loss/softmax_cross_entropy.py:44: RuntimeWarning: divide by zero encountered in log

  y = numpy.log(p).sum(keepdims=True) * (-1.0 / count)


が出ます。これは何故でしょうか?

もしこの質問がニューラルネットの初歩的な質問である場合はご容赦ください。

初めの入力1875次元のネットワークのlossの計算についてアドバイス頂けましたら幸いです。

よろしくお願いします。


関連するソース
# モデルの設定 or 保存されたモデルの読み込み
if args.model != 0:
    if args.gpu >= 0:
        cuda.init(args.gpu)
    model = pickle.load(open(args.model, 'rb'))
else:
    model = chainer.FunctionSet(l1=F.Linear(1875, 2000),
                                l2=F.Linear(2000, 1000),
                                l3=F.Linear(1000, 256),
                                l4=F.Linear(256, 2))

def forward(x_data, y_data, train=True):
    x, t = chainer.Variable(x_data, volatile=not train), chainer.Variable(
        y_data, volatile=not train)
    h = F.dropout(F.relu(model.l1(x)),  train=train)
    h = F.dropout(F.relu(model.l2(h)), train=train)
    h = F.dropout(F.relu(model.l3(h)), train=train)
    y = model.l4(h)
    print("predict: {}".format(y.data.argmax()))
    print("answer: {}".format(t.data[0]))
    return F.softmax_cross_entropy(y, t), F.accuracy(y, t)

optimizer = optimizers.Adam()
optimizer.setup(model)

Message has been deleted

naturecode...@gmail.com

unread,
Sep 7, 2015, 8:15:18 AM9/7/15
to Chainer User Group, naturecode...@gmail.com
*POSデータ分析のために使用しています

Kenta Oono

unread,
Sep 7, 2015, 9:13:18 PM9/7/15
to Chainer User Group
こんにちは

nanやinfが発生している原因の一つとしてsoftmax_cross_entropyのxとして絶対値が大きな値が入っている可能性があります

nanが出る例
In [80]: x = chainer.Variable(numpy.array([[1, 1e40]], dtype=numpy.float32))
In [81]: t = chainer.Variable(numpy.array([1], dtype=numpy.int32))
In [82]: chainer.functions.softmax_cross_entropy(x, t).data
Out[82]: array(nan, dtype=float32)

infが出る例
In [85]: x = chainer.Variable(numpy.array([[-1e40, 1]], dtype=numpy.float32))
In [86]: t = chainer.Variable(numpy.array([0], dtype=numpy.int32))
In [87]: chainer.functions.softmax_cross_entropy(x, t).data
Out[87]: array(inf, dtype=float32)

(softmax_cross_entropyの出力は常に0以上なので、-infが出る原因がこれかどうかはわかりません)

憶測にしかなりませんが、中間層が多くなると出力層の活性の値が大きくなり、このような状況になっているのかもしれません。
まずは、それぞれの層の活性や重みの値を確認すると良いと思われます。

もし上記のような問題としたら、入力の正規化(例えば、入力の各次元について、訓練データでの平均を0、分散を1にするなど)や、
中間層の活性の正規化(中間層の出力ベクトルのノルムを1などの定数にする。上限を決めて、ノルムが上限以上の値になっていたら上限の値に切るなど)
などが対策案として考えられます。


2015年9月7日月曜日 21時04分24秒 UTC+9 naturecode...@gmail.com:

naturecode...@gmail.com

unread,
Sep 16, 2015, 8:51:44 AM9/16/15
to Chainer User Group
ご回答ありがとうございます

まずlossの-infは+infの間違いでした。すみませんでした。
訓練データの入力がゆうに1000万を超える値があったため、中間層の出力で値が大きくなりnan, infの原因になっていました。ノルムを1にする中間層の処理
h.data = h.data / numpy.linalg.norm(h.data)
を加えてlossが出力される様になりました

ありがとうございました。


2015年9月8日火曜日 10時13分18秒 UTC+9 Kenta Oono:
Reply all
Reply to author
Forward
0 new messages