通用的Debug方案:

使用Tensorflow/Keras中在不同的网络层之间传递的tensor对象的eval()方法进行调试,在一个Tensorflow Session中,使用tf.global_variables_initializer()以初始化之前定义的tensor对象。之后就可以对之前定义的全局变量进行更改,以对网络的输入进行自定义,并使用eval()方法观察层之间的输出值了。

input_test = X[0],Y[0]  #从输入数据中截取的测试片段
output_test = model(
        [tf.convert_to_tensor(input_test[0][0],float), 
         tf.convert_to_tensor(input_test[0][1],float)]
    ) #输入网络,得到最终输出
loss = my_loss(tf.convert_to_tensor(input_test[1],float), output_test)
test_x1=tf.convert_to_tensor([[1,2],[2,3]],float) #对my_layer层的测试输入,第一个参数
test_x2=tf.convert_to_tensor([[2,1],[4,3]],float) #对my_layer层的测试输入,第二个参数
test_simulation = my_layer([test_x1,test_x2])     #计算测试结果
print(test_simulation.shape)                             #不用启动session也可以输入中间层的形状
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    print(test_simulation.eval())
    print(input_test[1],output_test.eval())
    print(loss.eval())

TypeError

TypeError: Input 'b' of 'MatMul' Op has type float32 that does not match
 type float64 of argument 'a'.

这种错误是可能是由于输入给模型(或函数)的tensor数据类型不是正常的float类型,可以将错误的tensor输入给函数tf.convert_to_tensor()以得到正常的tensor,其中函数convert_to_tensor的dtype参数应设置为np.float32或float(不怕麻烦的话可以把所有的tensor都设置一遍,肯定能解决这个问题)。如下例所示:

input = tf.convert_to_tensor(input,np.float32)

ValueError

ValueError: An operation has `None` for gradient. Please make sure that all of your
 ops have a gradient defined (i.e. are differentiable). Common ops without gradient:
 K.argmax, K.round, K.eval.

出现这种情况时一般是自己定义的Loss函数出了问题

ValueError: Error when checking target: expected dense to have 3 dimensions, 
but got array with shape (1, 1)

这种错误一般是由于输入张量数据和类别标签的张量维数形状/shape)与网络结构的输入层或输出不匹配导致的。比如在使用model.fit_generator()对训练数据进行拟合时,如果输入给这个函数的generator参数定义为如下形式:

X=[1,2,3]
Y=[1,2,3]
def generator(X,Y):
    while True:
        for i in range(len(Y)):
            yield [[[[X[i]]]],[[[[Y[i]]]]
model.fit_generator(generator(X,Y), steps_per_epoch=1, epochs=10, verbose=1)

那么generator输出的训练数据X在传递给fit_generator后会被自动转化成形状为(1,1,1)的张量,则模型的输入层就必须是(None, 1, 1),其中模型输入层的形状约定为(batch的大小, input_shape[0], input_shape[1]),即第一层中的input_shape参数应被设为(1, 1)。generator输出的类别标签Y也是形状为(1,1,1)的张量,因此Batch的大小应为1,输出层的形状应被设计为(None, 1, 1)注意:输入输出层形状的第一个参数是Batch的大小,与真实数据维数和形状无关,输入层的input_shape参数只是设定了输入数据形状,构成了输入层形状的后几个参数。

为了避免上述麻烦,建议在数据输入到网络之前进行reshape以适合网络的输入输出形状。对上例:

X=[1,2,3]
Y=[1,2,3]
def generator(X,Y):
    while True:
        for i in range(len(Y)):
            yield np.array(X[i]).reshape(input_layer_shape),
                  np.array([Y[i]).reshape(output_layer_shape)
model.fit_generator(generator(X,Y), steps_per_epoch=1, epochs=10, verbose=1)

AttributeError

AttributeError: 'Model' object has no attribute 'total_loss'

出现这种情况一般是模型定义和编译的代码运行时出了问题,模型没有正确生成,而你忘记处理了,导致生成了一半的模型出现缺什么东西的问题。

MemoryError

你的内存满了,试着减小模型的大小,或者换个大点的内存吧。

ResourceExhaustedError: OOM when allocating tensor with shape[1,64,1080,1920] and type float on /job:localhost/replica:0/task:0/device:GPU:0 by allocator GPU_0_bfc
     [[{{node concat_3}} = ConcatV2[N=2, T=DT_FLOAT, Tidx=DT_INT32, _device="/job:localhost/replica:0/task:0/device:GPU:0"](conv2d_transpose_3, g_conv1_2/Maximum, concat-2-LayoutOptimizer)]]
Hint: If you want to see a list of allocated tensors when OOM happens, add report_tensor_allocations_upon_oom to RunOptions for current allocation info.

     [[{{node DepthToSpace/_3}} = _Recv[client_terminated=false, recv_device="/job:localhost/replica:0/task:0/device:CPU:0", send_device="/job:localhost/replica:0/task:0/device:GPU:0", 
send_device_incarnation=1, tensor_name="edge_277_DepthToSpace", tensor_type=DT_FLOAT, _device="/job:localhost/replica:0/task:0/device:CPU:0"]()]]
Hint: If you want to see a list of allocated tensors when OOM happens, add report_tensor_allocations_upon_oom to RunOptions for current allocation info.

换个显存更大的机器就解决了


如果有两个或以上python进程都在使用gpu,有时会报出复制错误等运行时错误,这时关掉其余的进程或kernel即可。


Loss函数由于形式复杂,常常会出现NaN的现象,对于这种bug,可以使用以下语句逐个tensor进行分析:

tf.reduce_any(tf.math.is_nan(value)).eval(session=tf.Session())

常常引起NaN的函数有:tf.math.divide,tf.math.log,tf.math.sqrt,对于除以0的NaN可以使用如下函数保证分母不为0:

def safe_divisor(x):
    return tf.where(tf.logical_and(tf.less(x,1e-6),tf.greater_equal(x,0)), 1e-6 * tf.ones_like(x), x)

对于log和sqrt,可以使用以下函数保证大于0:

def safe_positive(x):
    return tf.math.abs(x)+0.001
def normalize(image):
    i_max = tf.math.reduce_max(image)
    i_min = tf.math.reduce_min(image)
    if i_max == i_min:
        return image
    return tf.math.divide(image - i_min, i_max - i_min)

此外,学习率过大也会引起loss变为NaN,但是通常随机初始化权重后,还没有反向传播时loss并不是NaN


ValueError: Cannot convert a partially known TensorShape to a Tensor: xxx

此类语句会引起这种错误:x,y,z = tensor.shape,因为tensor.shape还是tensor类型,不能转成元组


TypeError: Cannot create initializer for non-floating point type.

Placeholder的数据类型和网络输入类型不匹配会导致此错误


在所有Placeholder,变量,optimizer之后添加sess.run(tf.global_variables_initializer())即可解决


ValueError: Cannot convert an unknown Dimension to a Tensor: ?

tensor.shape[0]改成tf.shape(tensor)[0]

标签: none

评论已关闭