使用TENSORFLOW进行多标签分类---成本和权重中的NaN

时间:2018-05-04 12:11:36

标签: python tensorflow machine-learning deep-learning convolutional-neural-network

情境
我正在构建一个用于多标签分类的神经网络:识别图像中的标签(一个人穿的衣服,颜色等等)。我想使用纯粹的tensorflow(而不是像kears这样的API),以便在我的指标上有更大的灵活性 PS:用于此张量流模型的数据是使用Keras构建的模型进行测试的,并且没有产生我将在此处公开的问题。

数据
我的输入数据是(X,Y):X是形状(1814,204,204,3),Y是形状(1814,39)。因此,基本上X是图像集,Y是与每个图像相关联的标签,用于监督学习过程 总共有39个标签,因此对于每个尺寸的图像(1,204,204,3),我们将形状矢量(1,39)关联起来:39个值可以是0或1. 1,如果在该图像中识别出相应的标签,哦别的。 可以同时识别许多标签,这意味着我们没有使用一个热门编码,也不是多级分类情况!
PS:我已将我的数据标准化,以便适合[0,1]

我做了什么
1。我做的第一件事就是建立我的分类器的抽象版本(这是一个CNN): 这是CNN的结构:

# Convolutional Layer 1
# Dropout layer 1
# Convolutional Layer 2
# Pooling Layer 2
# Dense layer 3  
# Dropout layer 3   
# Dense layer 4

对于给定的大小数据集(?,204,204,3):这是通过不同层的数据流:

conv1 OUTPUT shape:  (?, 204, 204, 32)  
drop1 OUTPUT shape:  (?, 204, 204, 32)  
conv2 OUTPUT shape:  (?, 204, 204, 32)  
pool2 OUTPUT shape:  (?, 102, 102, 32)  
dense3 OUTPUT shape:  (?, 512)  
drop3 OUTPUT shape:  (?, 512)  
dense4 OUTPUT shape:  (?, 39)  

以下是构建CNN结构的代码

   def create_model(X,Y):
        # Convolutional Layer #1
        conv1 = tf.layers.conv2d(
          inputs=X,
          filters=32,
          kernel_size=[3, 3],
          padding="same",
          activation=tf.nn.relu)
        print('conv1 OUTPUT shape: ',conv1.shape)

        # Dropout layer #1
        dropout1 = tf.layers.dropout(
          inputs=conv1, rate=0.2, training='TRAIN' == tf.estimator.ModeKeys.TRAIN)
        print('drop1 OUTPUT shape: ',dropout1.shape)

        # Convolutional Layer #2
        conv2 = tf.layers.conv2d(
          inputs=dropout1,
          filters=32,
          kernel_size=[3, 3],
          padding="same",
          activation=tf.nn.relu)
        print('conv2 OUTPUT shape: ',conv2.shape)

        # Pooling Layer #2
        pool2 = tf.layers.max_pooling2d(inputs=conv2, pool_size=[2, 2],strides=2)
        print('pool2 OUTPUT shape: ',pool2.shape)
        pool2_flat = tf.reshape(pool2, [-1, pool2.shape[1]*pool2.shape[2]*pool2.shape[3]])

        # Dense layer #3
        dense3 = tf.layers.dense(inputs=pool2_flat, units=512, activation=tf.nn.relu)
        print('dense3 OUTPUT shape: ',dense3.shape)

        # Dropout layer #3
        dropout3 = tf.layers.dropout(
          inputs=dense3, rate=0.5, training='TRAIN' == tf.estimator.ModeKeys.TRAIN)
        print('drop3 OUTPUT shape: ',dropout3.shape)

        # Dense layer #4
        Z = tf.layers.dense(inputs=dropout3, units=39, activation=tf.nn.sigmoid)
        print('dense4 OUTPUT shape: ',Z.shape)

        return Z  

2。现在,我正在定义费用函数和我的优化程序

  • 对于成本函数,我使用 cross_entropy_with_logits 并独立计算批量样本中所有输出组件的平均值。例如,如果我有一批10号,那么模型的输出是形状的(10,39),所以 的成本我们将得到一个形状矢量(1,39) (对于每个标签,我们计算批次中不同例子的平均值)
  • 对于优化器,我使用的是adam优化器。

以下是计算成本和优化程序的代码。

def optimizer_and_cost(output,labels):
    # Calculating cost
    cost= tf.reduce_mean(labels * - tf.log(output) + (1 - labels) * - tf.log(1 - output),axis=0)
    print('cost: shape of cost: ',cost.shape)
    cost= tf.reshape(cost, [1, 39])
    print('cost reshaped: shape of cost reshaped: ',cost.shape)

    #Optimizer
    optimizer = tf.train.AdamOptimizer(learning_rate=0.001).minimize(cost)
    return optimizer,cost  

PS:'轴= 0'在tf.reduce_mean中允许我独立计算每个标签,即批处理示例的平均值!

3. 定义占位符,初始化模型和培训。
一旦定义了具有不同参数的抽象模型,我就创建了占位符并构建了计算图,然后我初始化了权重并开始了训练。 问题:我开始在优化过程中为不同层中的权重和成本函数中的NaN设置NaN值。因此,第一个Reflexe试图调试并了解会发生什么 我试着测试一个简单的案例如下:
初始化权重--->计算成本并打印出来(打印重量)--->做一个优化--->钙化成本并打印(打印重量)
结果:
第一次打印很好我有真正的价值(非常明显)。但是在第一次优化之后:我得到了成本的NaNs值。 为什么我的优化器会在一次优化步骤后使成本达到NaN!
这是测试的代码! (X_train和Y_train的形状(1269,204,204,3)和(1269,39):我每个只需要4个元素来测试)

#clearing the graph
ops.reset_default_graph()

#defining placeholders
X = tf.placeholder(tf.float32, [None, X_train.shape[1],X_train.shape[2],X_train.shape[3]])
Y = tf.placeholder(tf.float32, [None, Y_train.shape[1]])
optimizer, cost=optimizer_and_cost(create_model(X,Y),Y)

# Initialize all the variables globally
init = tf.global_variables_initializer()

# Start the session to compute the tensorflow graph
sess=tf.Session()
sess.run(init)

#printing cost and first layers weights
print('first layer weights ',sess.run(tf.trainable_variables()[0]) )
print('cost: ',sess.run(cost,feed_dict={X:X_train[0:4,:], Y:Y_train[0:4,:]}))

#doing one optimization step
_ ,OK=sess.run([optimizer, cost], feed_dict={X:X_train[0:4,:], Y:Y_train[0:4,:]})


#printing cost and first layers weights
print('first layer weights ',sess.run(tf.trainable_variables()[0]) )
print('cost :',sess.run(cost,feed_dict={X:X_train[0:4,:], Y:Y_train[0:4,:]}))

#closing session
sess.close()

欢迎任何帮助。

2 个答案:

答案 0 :(得分:0)

建议您使用tf.nn.softmax_cross_entropy_with_logits_v2而不是自己实施,因为它涵盖了很多通常导致nan损失的极端情况。

您使用tf.nn.softmax_cross_entropy_with_logits_v2的方式是将密集层4的激活设为linear而不是softmax。这样,Dense Layer 4的输出将为logits,然后可以直接输入tf.nn.softmax_cross_entropy_with_logits_v2

最后请务必仔细阅读以下内容:

编辑:我的不好,我没有仔细阅读这个问题所以我错过了你说这不是multi-class classification问题的事实。如果它不是multi-class classification问题,那么它可能超出了我目前的专业知识。所以我会给你留下你和我都可以仔细阅读的另一个链接。

答案 1 :(得分:0)

此链接解决了我的问题:Tensorflow NaN bug?

基本上,当计算y * ​​log(y)时,它必须具有0 log(0),因此解决方案在提供的链接中。无论如何,谢谢你的帮助。

替换

  cost= tf.reduce_mean(labels * - tf.log(output) + (1 - labels) * - tf.log(1 - output),axis=0)

有了这个

cost= tf.reduce_mean(labels * - tf.log(tf.clip_by_value(output,1e-10,1.0)) + (1 - labels) * - tf.log(tf.clip_by_value(1 - output,1e-10,1.0)),axis=0)