Tensorflow Debug指南
通用的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]
评论已关闭