深度学习难的原因


77

也许这个问题太笼统,但是谁能解释导致卷积神经网络发散的原因是什么?

细节:

我正在使用Tensorflow的iris_training模型处理一些自己的数据,并不断获取

错误:张量流:模型因损失= NaN而发散。

追溯...

tensorflow.contrib.learn.python.learn.monitors.NanLossDuringTrainingError:训练期间NaN丢失。

回溯源于以下行:

 tf.contrib.learn.DNNClassifier(feature_columns=feature_columns,
                                        hidden_units=[300, 300, 300],
                                        #optimizer=tf.train.ProximalAdagradOptimizer(learning_rate=0.001, l1_regularization_strength=0.00001),                                                          
                                        n_classes=11,
                                        model_dir="/tmp/iris_model")

我尝试过调整优化器,将学习率设置为零,并且不使用优化器。任何对网络层,数据大小等的见解都将受到赞赏。


5
这是随机梯度下降的自然属性,如果学习率太大,SGD可以发散到无穷大
Yaroslav Bulatov

@YaroslavBulatov我已经尝试过该AdagradOptiizer,其学习率约为1E-15。也许我的数据不适合SGD,您能建议其他算法吗?Tensorflow和深度学习仍然是新手。
免费网址

就我而言,规范化有所帮助
Dmitry

对我来说,解决方案是使用tf.losses.sparse_softmax_cross_entropy(y, logits)我自己的Safe Softmax实现,而不是使用tf.nn.Softmax
Eduardo Reis,

Answers:


121

我见过很多东西使模型产生分歧。

  1. 学习率太高。您通常可以判断出损失是否开始增加然后发散到无穷大。

  2. 我不熟悉DNNClassifier,但我猜想它使用了分类交叉熵代价函数。这涉及获取预测的对数,该对数随着预测接近零而发散。这就是为什么人们通常在预测中添加较小的ε值以防止这种差异。我猜测DNNClassifier可能会这样做或使用tensorflow opp。可能不是问题。

  3. 可能存在其他数值稳定性问题,例如零除,在这种情况下添加epsilon可能会有所帮助。如果在处理有限精度数时未适当简化,则导数的平方根可以发散的另一种不那么明显的方法。我再次怀疑这是DNNClassifier的问题。

  4. 您可能对输入数据有疑问。尝试调用assert not np.any(np.isnan(x))输入数据以确保您没有引入nan。还要确保所有目标值均有效。最后,确保数据正确归一化。您可能希望像素在[-1,1]而不是[0,255]范围内。

  5. 标签必须在损失函数的域中,因此,如果使用基于对数的损失函数,则所有标签都必须是非负的(如evan pu和以下评论所指出)。


1
感谢您的细分。我的问题是我的标签围绕零对称(即[-5,...,5])。转移解决了这个问题。
免费网址

4
标签应为二进制。1或0。否则,分类交叉熵代价函数将没有意义。
chasep255 '16

tf.keras.utils.normalize(data)对标准化数据很有用。
transistor1

“二进制”的意思是它们应该是单热编码的,例如对于第一类(0,1,0,...)的矢量(1,0,0,....,0)。第二类的示例为0),最后一类的示例为(0,....,0,1)。输出节点的数量应与您拥有的类的数量相同。
安德烈·霍尔兹纳

1
你是我的英雄!当我尝试线性回归示例(toptal.com/machine-learning / ...使用另一个数据集)时,对摄氏对华氏温度说,我得到W,b,都失去了'nan'。但是按照您的回答,我将learning_rate = 0.01更改为learning_rate = 0.001,然后一切正常!
holibut

12

如果您正在训练交叉熵,则需要在输出概率中添加一个小数,例如1e-8。

因为log(0)是负无穷大,所以当您的模型经过足够的训练后,输出分布将非常偏斜,例如说我正在执行4类输出,一开始我的机率就好像

0.25 0.25 0.25 0.25

但到最后,可能性可能看起来像

1.0 0 0 0

然后,您将对该分布进行交叉熵分解,一切都会爆炸。解决方法是人为地在所有术语中添加少量数字,以防止出现这种情况。


我使用了categorical_crossentropy来自keras的损失函数,它已经实现了吗?
StayFoolish

@StayFoolish我不确定,解决的办法是看他们的源代码,但是我敢打赌他们已经在他们的代码中照顾了这一点。我尝试看看,很可能您还好。
埃文·普

4

如果使用整数作为目标,请确保它们不对称于0。

即,不要使用-1、0、1类。而应使用0、1、2类。


1
您是否愿意就原因或引用完成的原因发表一些评论?
gsimard '18

@gsimard老实说,我不记得我前一段时间使用它了。
Rok Povsic

@gsimard,这是因为接受答案中的原因5。基于逻辑的回归函数通常使用对数,这些对数仅在非负数上定义
Free Url

1
@Zroach没有,在我的情况负数被支持,但它不工作的原因是明确对称的0
韩城Povsic

4

就我而言,设置远距离整数LABEL时得到NAN。即:

  • 标记[0..100]的培训还可以,
  • 标签[0..100]加上一个附加标签8000,然后我得到了NAN。

因此,不要使用距离很远的标签。

编辑您可以在以下简单代码中看到效果:

from keras.models import Sequential
from keras.layers import Dense, Activation
import numpy as np

X=np.random.random(size=(20,5))
y=np.random.randint(0,high=5, size=(20,1))

model = Sequential([
            Dense(10, input_dim=X.shape[1]),
            Activation('relu'),
            Dense(5),
            Activation('softmax')
            ])
model.compile(optimizer = "Adam", loss = "sparse_categorical_crossentropy", metrics = ["accuracy"] )

print('fit model with labels in range 0..5')
history = model.fit(X, y, epochs= 5 )

X = np.vstack( (X, np.random.random(size=(1,5))))
y = np.vstack( ( y, [[8000]]))
print('fit model with labels in range 0..5 plus 8000')
history = model.fit(X, y, epochs= 5 )

结果显示添加标签8000后的NAN:

fit model with labels in range 0..5
Epoch 1/5
20/20 [==============================] - 0s 25ms/step - loss: 1.8345 - acc: 0.1500
Epoch 2/5
20/20 [==============================] - 0s 150us/step - loss: 1.8312 - acc: 0.1500
Epoch 3/5
20/20 [==============================] - 0s 151us/step - loss: 1.8273 - acc: 0.1500
Epoch 4/5
20/20 [==============================] - 0s 198us/step - loss: 1.8233 - acc: 0.1500
Epoch 5/5
20/20 [==============================] - 0s 151us/step - loss: 1.8192 - acc: 0.1500
fit model with labels in range 0..5 plus 8000
Epoch 1/5
21/21 [==============================] - 0s 142us/step - loss: nan - acc: 0.1429
Epoch 2/5
21/21 [==============================] - 0s 238us/step - loss: nan - acc: 0.2381
Epoch 3/5
21/21 [==============================] - 0s 191us/step - loss: nan - acc: 0.2381
Epoch 4/5
21/21 [==============================] - 0s 191us/step - loss: nan - acc: 0.2381
Epoch 5/5
21/21 [==============================] - 0s 188us/step - loss: nan - acc: 0.2381

有趣。我认为这取决于您的损失函数。您能说明一下您如何衡量损失吗?
免费网址

1
我照原样使用了'sparse_categorical_crossentropy'–
Guido


0

正则化可以提供帮助。对于分类器,无论是二进制分类器还是多分类器,都有很好的活动正则化条件。对于回归器,内核正则化可能更合适。


0

我想插入一些我经历过的(浅)原因,如下所示:

  1. 我们可能已经更新了字典(用于NLP任务),但是模型和准备的数据使用了不同的字典。
  2. 我们可能已经重新处理了我们的数据(二进制tf_record),但是我们加载了旧模型。重新处理的数据可能与上一个冲突。
  3. 我们可能应该从头开始训练模型,但我们忘记删除检查点,并且模型会自动加载最新参数。

希望能有所帮助。


0

的原因naninf-inf往往来自一个事实,即division by 0.0在TensorFlow不零异常导致分裂。这可能导致naninf-inf“价值”。在您的训练数据中,您可能会有0.0,因此在损失函数中,您可能会做一次division by 0.0

a = tf.constant([2., 0., -2.])
b = tf.constant([0., 0., 0.])
c = tf.constant([1., 1., 1.])
print((a / b) + c)

输出为以下张量:

tf.Tensor([ inf  nan -inf], shape=(3,), dtype=float32)

加一个小eplison(例如1e-5)通常可以解决问题。此外,从TensorFlow 2开始tf.math.division_no_nan定义了展开。


0

尽管大多数观点已经讨论过了。但是我想再次强调一下缺少NaN的另一个原因。

tf.estimator.DNNClassifier(
    hidden_units, feature_columns, model_dir=None, n_classes=2, weight_column=None,
    label_vocabulary=None, optimizer='Adagrad', activation_fn=tf.nn.relu,
    dropout=None, config=None, warm_start_from=None,
    loss_reduction=losses_utils.ReductionV2.SUM_OVER_BATCH_SIZE, batch_norm=False
)

默认情况下,激活功能为“ Relu”。中间层可能会生成负值,“ Relu”会将其转换为0。逐渐停止训练。

我观察到“ LeakyRelu”能够解决此类问题。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.