Tensorflow estimator 值错误:logits 和 labels 必须具有相同的形状((?,1)与(?,)不同)。

53

我正在使用二元交叉熵将电影评论分类为积极或消极。因此,当我尝试用tensorflow estimator包装keras模型时,出现错误:

Tensorflow estimator ValueError: logits and labels must have the same shape ((?, 1) vs (?,))

我的最后一层使用Sigmoid激活函数,我想我可能错过了一些微小的东西。有人可以帮忙吗?

from tensorflow import keras
import tensorflow as tf
print("Tensorflow {} loaded".format(tf.__version__))
import numpy as np

keras.__version__
from keras.datasets import imdb

(train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)
def vectorize_sequences(sequences, dimension=10000):
    # Create an all-zero matrix of shape (len(sequences), dimension)
    results = np.zeros((len(sequences), dimension))
    for i, sequence in enumerate(sequences):
        results[i, sequence] = 1.  # set specific indices of results[i] to 1s
    return results.astype('float32')

# Our vectorized training data
x_train = vectorize_sequences(train_data)

# Our vectorized test data
x_test = vectorize_sequences(test_data)

# Our vectorized labels
y_train = np.asarray(train_labels).astype('float32')
y_test = np.asarray(test_labels).astype('float32')

x_val = x_train[:10000]
partial_x_train = x_train[10000:]
y_val = y_train[:10000]
partial_y_train = y_train[10000:]

model = keras.models.Sequential()
model.add(keras.layers.Dense(16, activation='relu', input_shape=(10000,), name='reviews'))
model.add(keras.layers.Dense(16, activation='relu'))
model.add(keras.layers.Dense(1, activation='sigmoid'))
model.compile(optimizer='rmsprop',
              loss='binary_crossentropy',
              metrics=['accuracy'])
estimator_model = keras.estimator.model_to_estimator(keras_model=model)

def input_function(features,labels=None,shuffle=False,epochs=None,batch_size=None):
    input_fn = tf.estimator.inputs.numpy_input_fn(
        x={"reviews_input": features},
        y=labels,
        shuffle=shuffle,
        num_epochs=epochs,
        batch_size=batch_size
    )
    return input_fn

estimator_model.train(input_fn=input_function(partial_x_train, partial_y_train, True,20,512))
score = estimator_model.evaluate(input_function(x_val, labels=y_val))
print(score)
7个回答

42
你应该将标签重塑为2D张量(第一维是批处理维度,第二维是标量标签):

你应该将标签重塑为2D张量(第一维是批处理维度,第二维是标量标签):

# Our vectorized labels
y_train = np.asarray(train_labels).astype('float32').reshape((-1,1))
y_test = np.asarray(test_labels).astype('float32').reshape((-1,1))

28

如果您正在进行二元分类,请确保您最后的密集层(Dense layer)的形状只有(None, 1),而不是(None, 2)。

tf.keras.layers.Dense(1, activation="sigmoid") # binary activation output

1
为什么?二进制不是应该是2吗? - Kaschi14
二进制是0或1。你只需要一个节点来表示0或1。 - DonCarleone

15

通过model.summary()检查你的网络。

最终需要将网络变得更加简洁,以使其具有与类别相同的输出。例如,数字OCR需要Dense(10)的最终输出层(用于数字0到9)。

例如,区分狗和猫。最后一层必须有两个输出(0-狗,1-猫)。


15
只有在使用 softmax + 交叉熵时,你的最后一句话才是正确的。如果使用 sigmoid + 二元交叉熵,最终密集层应该只有一个节点。 - kelkka
@kelkka 你说得对...我尝试了你的建议(我不是这个问题的原始作者),在一个项目中它绝对有效...点赞! - Dave
@kelkka @Dave -- 我尝试了使用 tf.keras.losses.CategoricalCrossentropy()tf.keras.layers.Dense(2, activation='softmax') 作为最后一层,但是它显示了一个错误 ValueError: Shapes (None, 1) and (None, 2) are incompatible。但当我尝试使用2个节点时,它可以正常运行而没有错误。这里的问题是什么? - curiouscheese
好的,我找到了解决方案。如果在最后一层使用Softmax且有2个节点,则需要使用SparseCategoricalCrossentropy() - curiouscheese
@curiousguy,我已经有一段时间没有使用TensorFlow了,但我怀疑你收到的ValueError错误来自于标签的编码方式。如果您使用单热编码标签(例如[0,1]代表猫,[1,0]代表狗),那么您应该使用CategoricalCrossentropy。如果您不这样做,并且像上面一样使用标签,其中0表示猫,1表示狗,则SparseCategoricalCrossentropy是正确的选择。 - kelkka

12
我们可以通过在Dense层后添加一个Flatten层,将输出与标签的维度匹配来解决这个问题:
model.add(Flatten())

或者通过添加:
model.add(GlobalAveragePooling2D())

查看此 GitHub 问题以获取完整详情


6
如果您正在进行二元交叉熵,则您的数据集可能有2个类别,并且错误是因为您的标签向量(在测试和训练中)具有形式[0,1,0,1,1,1,0,0,1,...]。要对二进制标签进行one-hot编码,可以使用以下函数:Labels = tf.one_hot(Labels, depth=2)

0
在最后一层,您应该使用两个输出而不是一个输出:
model.add(keras.layers.Dense(2, activation='sigmoid'))

为什么海报应该使用两个输出?你的答案需要支持信息。你可以通过添加更多细节,例如引用或文档,来改进你的答案,以便其他人可以确认你的答案是否正确。你可以在帮助中心找到有关如何编写好答案的更多信息。 - moken

-1
你必须添加:
model.add(layers.Flatten())

或者:

model.add(layers.GlobalAveragePooling2D())

1
这已经在这个答案中提到了。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接