【问题标题】:tensorflow giving nans when calculating gradient with sparse tensorstensorflow 在计算稀疏张量的梯度时给出 nans
【发布时间】:2017-07-06 19:11:41
【问题描述】:

以下 sn-p 来自相当大的一段代码,但希望我能提供所有必要的信息:

y2 = tf.matmul(y1,ymask)

dist = tf.norm(ystar-y2,axis=0)

y1 和 y2 是 128x30,ymask 是 30x30。 ystar 是 128x30。距离是 1x30。当 ymask 是单位矩阵时,一切正常。但是,当我将它设置为全零时,除了沿对角线的单个 1(以便将 y2 中除一之外的所有列设置为零)外,我使用 tf.梯度(距离,[y2])。 dist 的具体值为 [0,0,7.9,0,...],所有 ystar-y2 值都在第三列的范围 (-1,1) 附近,其他地方为零。

鉴于没有日志或除法,我很困惑为什么这里会出现数字问题,这是下溢吗?我在数学中遗漏了什么吗?

对于上下文,我这样做是为了尝试使用整个网络训练 y 的各个维度,一次一个。

要复制的更长版本:

import tensorflow as tf
import numpy as np
import pandas as pd

batchSize = 128
eta = 0.8
tasks = 30
imageSize = 32**2
groups = 3
tasksPerGroup = 10
trainDatapoints = 10000

w = np.zeros([imageSize, groups * tasksPerGroup])
toyIndex = 0
for toyLoop in range(groups):
    m = np.ones([imageSize]) * np.random.randn(imageSize)
    for taskLoop in range(tasksPerGroup):
        w[:, toyIndex] = m * 0.1 * np.random.randn(1)
        toyIndex += 1

xRand = np.random.normal(0, 0.5, (trainDatapoints, imageSize))
taskLabels = np.matmul(xRand, w) + np.random.normal(0,0.5,(trainDatapoints, groups * tasksPerGroup))
DF = np.concatenate((xRand, taskLabels), axis=1)
trainDF = pd.DataFrame(DF[:trainDatapoints, ])

# define graph variables
x = tf.placeholder(tf.float32, [None, imageSize])
W = tf.Variable(tf.zeros([imageSize, tasks]))
b = tf.Variable(tf.zeros([tasks]))
ystar = tf.placeholder(tf.float32, [None, tasks])
ymask = tf.placeholder(tf.float32, [tasks, tasks])
dataLength = tf.cast(tf.shape(ystar)[0],dtype=tf.float32)

y1 = tf.matmul(x, W) + b
y2 = tf.matmul(y1,ymask)
dist = tf.norm(ystar-y2,axis=0)
mse = tf.reciprocal(dataLength) * tf.reduce_mean(tf.square(dist))
grads = tf.gradients(dist, [y2])

trainStep = tf.train.GradientDescentOptimizer(eta).minimize(mse)

# build graph
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)

randTask = np.random.randint(0, 9)
ymaskIn = np.zeros([tasks, tasks])
ymaskIn[randTask, randTask] = 1
batch = trainDF.sample(batchSize)
batch_xs = batch.iloc[:, :imageSize]
batch_ys = np.zeros([batchSize, tasks])
batch_ys[:, randTask] = batch.iloc[:, imageSize + randTask]

gradOut = sess.run(grads, feed_dict={x: batch_xs, ystar: batch_ys, ymask: ymaskIn})

sess.run(trainStep, feed_dict={x: batch_xs, ystar: batch_ys, ymask:ymaskIn})

【问题讨论】:

  • 请包含一个独立的 sn-p 以重现该问题(即使用 y1y2ystar 的常量)。
  • 感谢您的快速回复,因此重现的不仅仅是常量,已在问题中添加了一些代码

标签: tensorflow


【解决方案1】:

这是一个非常简单的复制:

import tensorflow as tf

with tf.Graph().as_default():
  y = tf.zeros(shape=[1], dtype=tf.float32)
  dist = tf.norm(y,axis=0)
  (grad,) = tf.gradients(dist, [y])
  with tf.Session():
    print(grad.eval())

打印:

[ nan]

问题在于tf.norm 计算sum(x**2)**0.5。梯度为x / sum(x**2) ** 0.5(参见例如https://math.stackexchange.com/a/84333),因此当sum(x**2) 为零时,我们将除以零。

就特殊情况而言,没有太多工作要做:x 接近全零时的梯度取决于它从哪个方向接近。例如,如果x 是一个单元素向量,则x 接近 0 的极限可能是 1 或 -1,具体取决于它从零的哪一侧接近。

因此,就解决方案而言,您只需添加一个小的epsilon

import tensorflow as tf

def safe_norm(x, epsilon=1e-12, axis=None):
  return tf.sqrt(tf.reduce_sum(x ** 2, axis=axis) + epsilon)

with tf.Graph().as_default():
  y = tf.constant([0.])
  dist = safe_norm(y,axis=0)
  (grad,) = tf.gradients(dist, [y])
  with tf.Session():
    print(grad.eval())

打印:

[ 0.]

请注意,这实际上不是欧几里得规范。只要输入远大于epsilon,这是一个很好的近似值。

【讨论】:

  • 啊,很酷的欢呼,是的,我忘记了在下一步中平方它不会取消用于反向传播的根。使用 mse = tf.losses.mean_squared_error(ystar,y2),也修复了它,我可以保留我的 dist calc 作为输出指标,但在链外,干杯
猜你喜欢
  • 2017-04-30
  • 2018-01-03
  • 2017-04-29
  • 1970-01-01
  • 2016-10-19
  • 2017-05-02
  • 2017-02-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多