【问题标题】:Image two-classification with CNN, but it always predicts everything into one class使用 CNN 进行图像二分类,但它总是将所有内容预测为一类
【发布时间】:2018-01-15 15:26:00
【问题描述】:

简介

我有一个基于 tensorflow 的普通 CNN 网络,我的目标是训练它,然后用它来将图像分类为 2 类。

关于训练数据集

X:图片(健康,不健康),128*128

标签:[1, 0](不健康)或 [0, 1](健康)

我使用 TFrecords 来制作数据集。

关于 CNN 模型

def weight_variable(shape):

    initial = tf.truncated_normal(shape, stddev = 0.1, dtype = tf.float32)
    return tf.Variable(initial)


def bias_variable(shape):

    initial = tf.constant(0.1, shape = shape, dtype = tf.float32)
    return tf.Variable(initial)


def conv2d(x, W):

    #(input, filter, strides, padding)
    #[batch, height, width, in_channels]
    return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')


def max_pool_2x2(x):

    #(value, ksize, strides, padding)
    return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')

def cnn_model():

    epochs = 1
    batch_size = 200
    learning_rate = 0.001
    hidden = 1024
    cap_c = 498
    cap_h = 478
    num = cap_c + cap_h # the sum number of the training x
    image_size = 128
    label_size = 2
    ex = 2
 
    #train_loss = np.empty((num//(batch_size * ex)) * epochs)
    #train_acc = np.empty((num//(batch_size * ex)) * epochs)

    x = tf.placeholder(tf.float32, shape = [None, image_size * image_size])
    y = tf.placeholder(tf.float32, shape = [None, label_size])

    X_train_ = tf.reshape(x, [-1, image_size, image_size, 1])

    #First layer
    W_conv1 = weight_variable([5, 5, 1, 32])
    b_conv1 = bias_variable([32])
  
    h_conv1 = tf.nn.relu(conv2d(X_train_, W_conv1) + b_conv1)
    h_pool1 = max_pool_2x2(h_conv1)

    #Second layer
    W_conv2 = weight_variable([5, 5, 32, 64])
    b_conv2 = bias_variable([64])

    h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
    h_pool2 = max_pool_2x2(h_conv2)

    #Third layer
    #W_conv3 = weight_variable([5, 5, 64, 128])
    #b_conv3 = bias_variable([128])

    #h_conv3 = tf.nn.relu(conv2d(h_pool2, W_conv3) + b_conv3)
    #h_pool3 = max_pool_2x2(h_conv3)

    #Full connect layer
    W_fc1 = weight_variable([64 * 64 * 32, hidden])
    b_fc1 = bias_variable([hidden])

    h_pool2_flat = tf.reshape(h_pool2, [-1, 64 * 64 * 32])
    h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)

    #Output_Softmax

    W_fc2 = weight_variable([hidden, label_size])
    b_fc2 = bias_variable([label_size])

    y_conv = tf.nn.softmax(tf.matmul(h_fc1, W_fc2) + b_fc2)

    loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels = y, logits = y_conv))
    optimize = tf.train.AdamOptimizer(learning_rate).minimize(loss)
    correct_prediction = tf.equal(tf.argmax(y_conv, 1), tf.argmax(y, 1)) 
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

然后是数据读取或会话部分。

关于形状

作为占位符的形状,如果batch size为200

X 形状:[200, 128 * 128]

标签形状:[200, 2]

输出形状:[200, 2]

关于输出结果

我认为预测值应该被训练为[1, 0]或者[0, 1],但是大约5步之后,预测值都是[1, 0]或者[0, 1]。例如,如果批量大小为 5,则结果将是

[[1, 0],
[1, 0],
[1, 0],
[1, 0],
[1, 0]] 

或完全相反。 但是,有时结果会有所不同,像这样

[[1, 0],
[0, 1],
[1, 0],
[0, 1],
[1, 0]] 

但这只会持续大约 5 个步骤,然后结果将是一样的。

关于损失和准确率

由于预测结果不正确,所以损失不收敛。换句话说,损失和准确率完全取决于训练数据集的X,这是没有意义的。

我的想法

我认为数据集TFrecords没有问题,因为我已经打印了图像矩阵和标签,它们都很好。所以我认为问题出在模型上。

我没有得到可以从 Google 搜索和 SO 中的其他问题中解决我的问题和问题的答案,如果你能帮我解决这个问题,真的非常感谢。如果您需要更多结果或参考代码,请告诉我。

【问题讨论】:

    标签: python image tensorflow neural-network classification


    【解决方案1】:

    我认为您的数据可能不平衡,即两个类的训练样本数量并不大致。在您的示例中,您的健康目标可能比不健康的目标多得多。在这种情况下,通过将所有样本归为同一类可以显着降低损失函数,但在此之后,错误分类的样本不太可能在一段时间后再次被正确分类。

    您可以尝试重新采样您的数据,以便为两个类获得大致相等的数字。

    另一种方法是使用加权交叉熵(例如,您可以计算每个样本的交叉熵,并将其乘以权重(准确地说,是每个样本的权重张量);只有在这之后才应该你申请tf.reduce_mean。例如,你可以对包含较少样本的类应用更大的权重,从而迫使优化器更多地关注这些样本。

    这应该是这样的:

    weights = tf.placeholder(tf.float32, shape=[None])
    loss = tf.reduce_mean(tf.multiply(tf.nn.softmax_cross_entropy_with_logits(labels = y, logits = y_conv), weights))
    

    当然,您需要在某些时候用值填充weights

    【讨论】:

    • 感谢您的回答。由于healthy是478,unhealthy是498,所以在'tf.train.shuffle_batch'做random的时候可能会出现不平衡的情况,我会在这个过程中尝试平衡样本。关于第二个,我会按照你写的那样尝试后告诉你我的结果,谢谢
    • 其他几点:在使用tf.nn.softmax_cross_entropy_with_logits() 之前,您不应执行tf.nn.softmax() 操作,因为此交叉熵需要未缩放的logits (tensorflow.org/api_docs/python/tf/nn/…)。您还只训练了一个 epoch,因此如果增加训练 epoch 的数量,您可能会获得更好的结果。将批量大小减少到大约 50 或 100 可能也有帮助。
    • 是的,正如你所说,我删除了tf.nn.softmax_cross_entropy_with_logits() 并使用加权交叉熵:tf.nn.weighted_cross_entropy_with_logits。但结果表明,这种方法还是不能很好地工作……经过一些步骤,它们仍然是全部[0, 1]或全部[1, 0]。是否我的网络有问题?还是损失函数也不合适?
    • 最后,我对网络的学习率(更小)和隐藏层数(更小)做了一些调整。然后它可以很好地工作。此外,使用加权交叉熵
    猜你喜欢
    • 2020-08-17
    • 2018-02-15
    • 2020-05-22
    • 1970-01-01
    • 2020-10-28
    • 2017-07-18
    • 2022-01-01
    • 2016-04-19
    • 2018-06-04
    相关资源
    最近更新 更多