Tensorflow / Keras:“日志和标签必须具有相同的第一维”如何​​压缩日志或扩展标签?

时间:2019-05-25 03:21:33

标签: python tensorflow machine-learning keras

我正在尝试创建一个简单的CNN分类器模型。对于我的训练图像(BATCH_SIZEx227x227x1)和标签(BATCH_SIZEx7)数据集,我使用的是numpy ndarray,它们通过ImageDataGenerator批量馈入模型。我正在使用的损失函数是tf.nn.sparse_categorical_crossentropy。当模型尝试训练时会出现问题。该模型(在我的简化实验中,批量大小为1)输出的形状为[1,7],标签的形状为[7]。

我几乎可以肯定我的原因,但是我不确定如何解决它。我的假设是sparse_categorical_crossentropy挤压标签的尺寸(例如,当BATCH_SIZE为2时,输入的,真实的标签形状从[2,7]挤压为[14]),这使我无法修复标签形状,而我修复logit形状的所有尝试都是徒劳的。

我最初尝试使用np.expand_dims固定标签形状。但是无论我如何扩展尺寸,损失函数始终会使标签变平。

在此之后,我尝试在模型的末尾添加一个tf.keras.layers.Flatten(),以摆脱多余的第一维,但是它没有任何效果。我仍然有相同的确切错误。 然后,尝试使用tf.keras.layers.Reshape((-1,))压缩所有尺寸。但是,这导致了另一个错误:

  

在sparse_categorical_crossentropy logits = array_ops.reshape(output,[-1,int(output_shape [-1])])TypeError: int 返回了非int(类型NoneType)

问题:如何将logit的形状压缩为与sparse_categorical_crossentropy返回的标签相同的形状?

 ### BUILD SHAPE OF THE MODEL ###

 model = tf.keras.Sequential([
   tf.keras.layers.Conv2D(32, (3,3), padding='same', activation=tf.nn.relu, 
                          input_shape=(227,227,1)),
   tf.keras.layers.MaxPooling2D((2,2), strides=2),
   tf.keras.layers.Conv2D(64, (3,3), padding='same', activation=tf.nn.relu),
   tf.keras.layers.MaxPooling2D((2,2), strides=2),
   tf.keras.layers.Flatten(),
   tf.keras.layers.Dense(128, activation=tf.nn.relu),
   tf.keras.layers.Dense(7, activation=tf.nn.softmax), # final layer with node for each classification
   #tf.keras.layers.Reshape((-1,))
])

# specify loss and SGD functions
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy')

### TRAIN THE MODEL ###
#specify training metadata
BATCH_SIZE = 1
print("about to train")
# train the model on the training data
num_epochs = 1 
model.fit_generator(generator.flow(train_images, train_labels, batch_size=BATCH_SIZE), epochs=num_epochs)

---完整的错误跟踪---

Traceback (most recent call last):
  File "classifier_model.py", line 115, in <module>
    model.fit_generator(generator.flow(train_images, train_labels, batch_size=BATCH_SIZE), epochs=num_epochs)
  File "/Users/grammiegramco/Desktop/projects/HiRISE/lib/python3.6/site-packages/tensorflow/python/keras/engine/training.py", line 1426, in fit_generator
    initial_epoch=initial_epoch)
  File "/Users/grammiegramco/Desktop/projects/HiRISE/lib/python3.6/site-packages/tensorflow/python/keras/engine/training_generator.py", line 191, in model_iteration
    batch_outs = batch_function(*batch_data)
  File "/Users/grammiegramco/Desktop/projects/HiRISE/lib/python3.6/site-packages/tensorflow/python/keras/engine/training.py", line 1191, in train_on_batch
    outputs = self._fit_function(ins)  # pylint: disable=not-callable
  File "/Users/grammiegramco/Desktop/projects/HiRISE/lib/python3.6/site-packages/tensorflow/python/keras/backend.py", line 3076, in __call__
    run_metadata=self.run_metadata)
  File "/Users/grammiegramco/Desktop/projects/HiRISE/lib/python3.6/site-packages/tensorflow/python/client/session.py", line 1439, in __call__
    run_metadata_ptr)
  File "/Users/grammiegramco/Desktop/projects/HiRISE/lib/python3.6/site-packages/tensorflow/python/framework/errors_impl.py", line 528, in __exit__
    c_api.TF_GetCode(self.status.status))
tensorflow.python.framework.errors_impl.InvalidArgumentError: logits and labels must have the same first dimension, got logits shape [1,7] and labels shape [7]
     [[{{node loss/dense_1_loss/SparseSoftmaxCrossEntropyWithLogits/SparseSoftmaxCrossEntropyWithLogits}}]]

2 个答案:

答案 0 :(得分:2)

请考虑在所有密集层之前添加一个扁平层。我和你有同样的问题,不得不从 categorical_crossentropy 更改为 sparse_categorical_crossentropy。 由于 sprarse_categorical_crossentropy 涉及单热编码,因此您的阵列需要是 CNN 层输出的 4D 阵列中较小(2D)阵列。

这为我解决了问题!

答案 1 :(得分:1)

不,原因全错了。您正在提供一键编码的标签,但是sparse_categorical_crossentropy期望使用整数标签,因为一键编码本身也是如此(因此,稀疏)。

一个简单的解决方案是将损失更改为categorical_crossentropy,而不是稀疏版本。另请注意,形状为(7,)的y_true不正确,应该是(1,7)。