29

我是 tensoflow 的新手,我想用我自己的数据(40x40 的图像)调整 MNIST 教程https://www.tensorflow.org/tutorials/layers 。这是我的模型功能:

def cnn_model_fn(features, labels, mode):
        # Input Layer
        input_layer = tf.reshape(features, [-1, 40, 40, 1])

        # Convolutional Layer #1
        conv1 = tf.layers.conv2d(
                inputs=input_layer,
                filters=32,
                kernel_size=[5, 5],
                #  To specify that the output tensor should have the same width and height values as the input tensor
                # value can be "same" ou "valid"
                padding="same",
                activation=tf.nn.relu)

        # Pooling Layer #1
        pool1 = tf.layers.max_pooling2d(inputs=conv1, pool_size=[2, 2], strides=2)

        # Convolutional Layer #2 and Pooling Layer #2
        conv2 = tf.layers.conv2d(
                inputs=pool1,
                filters=64,
                kernel_size=[5, 5],
                padding="same",
                activation=tf.nn.relu)
        pool2 = tf.layers.max_pooling2d(inputs=conv2, pool_size=[2, 2], strides=2)

        # Dense Layer
        pool2_flat = tf.reshape(pool2, [-1, 10 * 10 * 64])
        dense = tf.layers.dense(inputs=pool2_flat, units=1024, activation=tf.nn.relu)
        dropout = tf.layers.dropout(
                inputs=dense, rate=0.4, training=mode == tf.estimator.ModeKeys.TRAIN)

        # Logits Layer
        logits = tf.layers.dense(inputs=dropout, units=2)

        predictions = {
            # Generate predictions (for PREDICT and EVAL mode)
            "classes":       tf.argmax(input=logits, axis=1),
            # Add `softmax_tensor` to the graph. It is used for PREDICT and by the
            # `logging_hook`.
            "probabilities": tf.nn.softmax(logits, name="softmax_tensor")
        }

        if mode == tf.estimator.ModeKeys.PREDICT:
            return tf.estimator.EstimatorSpec(mode=mode, predictions=predictions)

        # Calculate Loss (for both TRAIN and EVAL modes)
        loss = tf.losses.sparse_softmax_cross_entropy(labels=labels, logits=logits)

        # Configure the Training Op (for TRAIN mode)
        if mode == tf.estimator.ModeKeys.TRAIN:
            optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001)
            train_op = optimizer.minimize(
                    loss=loss,
                    global_step=tf.train.get_global_step())
            return tf.estimator.EstimatorSpec(mode=mode, loss=loss, train_op=train_op)

        # Add evaluation metrics (for EVAL mode)
        eval_metric_ops = {
            "accuracy": tf.metrics.accuracy(
                    labels=labels, predictions=predictions["classes"])}
        return tf.estimator.EstimatorSpec(
                mode=mode, loss=loss, eval_metric_ops=eval_metric_ops)

我在标签和 logits 之间有一个形状大小错误:

InvalidArgumentError(参见上文的追溯):logits 和标签必须具有相同的第一维,得到 logits 形状 [3,2] 和标签形状 [1]

filenames_array 是一个 16 个字符串的数组

["file1.png", "file2.png", "file3.png", ...]

labels_array 是一个 16 个整数的数组

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

主要功能是:

# Create the Estimator
mnist_classifier = tf.estimator.Estimator(model_fn=cnn_model_fn, model_dir="/tmp/test_convnet_model")

# Train the model
cust_train_input_fn = lambda: train_input_fn_custom(
        filenames_array=filenames, labels_array=labels, batch_size=1)

mnist_classifier.train(
        input_fn=cust_train_input_fn,
        steps=20000,
        hooks=[logging_hook])

我试图重塑 logits 但没有成功:

logits = tf.reshape(logits, [1, 2])

我需要你的帮助,谢谢


编辑

经过更多时间搜索,在我的模型函数的第一行

input_layer = tf.reshape(features, [-1, 40, 40, 1])

表示将动态计算 batch_size 维度的“-1”在此处具有值“3”。与我的错误中相同的“3”:logits 和 labels 必须具有相同的第一维,得到 logits 形状 [3,2] 和标签形状 [1]

如果我将值强制为“1”,我会遇到这个新错误:

reshape 的输入是一个有 4800 个值的张量,但请求的形状有 1600 个

也许我的功能有问题?


编辑2:

完整的代码在这里:https ://gist.github.com/geoffreyp/cc8e97aab1bff4d39e10001118c6322e


编辑3

我更新了要点

logits = tf.layers.dense(inputs=dropout, units=1)

https://gist.github.com/geoffreyp/cc8e97aab1bff4d39e10001118c6322e

但是我不完全理解您对批量大小的回答,这里的批量大小如何可以为 3 而我选择批量大小为 1 ?

如果我选择一个 batch_size = 3 我有这个错误: logits 和 labels 必须具有相同的第一维,得到 logits 形状 [9,1] 和标签形状 [3]

我试图重塑标签:

labels = tf.reshape(labels, [3, 1])

我更新了功能和标签结构:

    filenames_train = [['blackcorner-data/1.png', 'blackcorner-data/2.png', 'blackcorner-data/3.png',
                   'blackcorner-data/4.png', 'blackcorner-data/n1.png'],
                   ['blackcorner-data/n2.png',
                   'blackcorner-data/n3.png', 'blackcorner-data/n4.png',
                   'blackcorner-data/11.png', 'blackcorner-data/21.png'],
                   ['blackcorner-data/31.png',
                   'blackcorner-data/41.png', 'blackcorner-data/n11.png', 'blackcorner-data/n21.png',
                   'blackcorner-data/n31.png']
                   ]

labels = [[0, 0, 0, 0, 1], [1, 1, 1, 0, 0], [0, 0, 1, 1, 1]]

但没有成功...

4

6 回答 6

60

问题在于您的目标形状,并且与正确选择适当的损失函数有关。你有两种可能性:

1.可能性:如果你有一维整数编码的目标,你可以sparse_categorical_crossentropy用作损失函数

n_class = 3
n_features = 100
n_sample = 1000

X = np.random.randint(0,10, (n_sample,n_features))
y = np.random.randint(0,n_class, n_sample)

inp = Input((n_features,))
x = Dense(128, activation='relu')(inp)
out = Dense(n_class, activation='softmax')(x)

model = Model(inp, out)
model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['accuracy'])
history = model.fit(X, y, epochs=3)

2.可能性:如果您对目标进行单热编码以获得二维形状(n_samples,n_class),则可以使用categorical_crossentropy

n_class = 3
n_features = 100
n_sample = 1000

X = np.random.randint(0,10, (n_sample,n_features))
y = pd.get_dummies(np.random.randint(0,n_class, n_sample)).values

inp = Input((n_features,))
x = Dense(128, activation='relu')(inp)
out = Dense(n_class, activation='softmax')(x)

model = Model(inp, out)
model.compile(loss='categorical_crossentropy',optimizer='adam',metrics=['accuracy'])
history = model.fit(X, y, epochs=3)
于 2020-06-09T16:04:57.207 回答
35

我解决了它从sparse_categorical_crossentropyto的变化,categorical_crossentropy现在运行良好。

于 2020-05-07T09:17:20.457 回答
11

我在第一次使用 tensorflow 时就遇到了这个问题,我发现我的问题是忘记将属性class_mode='sparse'/添加class_mode='binary'到上传训练数据和验证数据的函数中:

所以试着照顾 class_mode 选项

image_gen_val = ImageDataGenerator(rescale=1./255)
val_data_gen = image_gen_val.flow_from_directory(batch_size=batch_size,
                                                 directory=val_dir,
                                                 target_size=(IMG_SHAPE, IMG_SHAPE),
                                                 class_mode='sparse')
于 2020-05-30T13:18:04.380 回答
2

我遇到了类似的问题,发现我错过了 CNN 和 Dense 层之间的 flatten 层。添加展平层为我解决了这个问题。

于 2021-08-01T23:59:43.613 回答
1

我遇到了类似的问题,结果发现一个池化层没有正确重塑。在我的情况下,我错误地使用了tf.reshape(pool, shape=[-1, 64 * 7 * 7])而不是tf.reshape(pool, shape=[-1, 64 * 14 * 14]),这导致了关于 logits 和标签的类似错误消息。改变因素,例如tf.reshape(pool, shape=[-1, 64 * 12 * 12])导致完全不同的、较少误导的错误消息。

或许这里也是如此。我建议通过代码检查节点的形状,以防万一。

于 2018-03-20T19:17:35.137 回答
1

您的 logits 形状看起来正确,批量大小为 3,输出层大小为 2,这就是您定义为输出层的内容。您的标签也应该是 [3, 2] 形状。3 个批次,每个批次有 2 个 [1,0] 或 [0,1]。

另请注意,当您有布尔分类输出时,输出/logits 层上不应有 2 个神经元。您可以只输出一个取 0 或 1 的值,您可能会看到 [1,0] 的 2 个输出如何,而 [0,1] 是多余的,可以表示为简单的 [0|1] 值。当你这样做时,你往往会得到更好的结果。

因此,您的 logits 最终应该是 [3,1] 并且您的标签应该是一个由 3 个值组成的数组,一个用于您批次中的每个样本。

于 2018-03-09T21:18:42.707 回答