收到一个标签值为1,超出了有效范围[0, 1) - Python,Keras。

52

我正在使用Tensorflow背景下的Keras开发一个简单的卷积神经网络分类器。

def cnnKeras(training_data, training_labels, test_data, test_labels, n_dim):
  print("Initiating CNN")
  seed = 8
  numpy.random.seed(seed)
  model = Sequential()
  model.add(Convolution2D(64, 1, 1, init='glorot_uniform', 
   border_mode='valid',input_shape=(16, 1, 1), activation='relu'))
  model.add(MaxPooling2D(pool_size=(1, 1)))
  model.add(Convolution2D(32, 1, 1, init='glorot_uniform', 
   activation='relu'))
  model.add(MaxPooling2D(pool_size=(1, 1)))
  model.add(Dropout(0.25))
  model.add(Flatten())
  model.add(Dense(128, activation='relu'))
  model.add(Dropout(0.5))
  model.add(Dense(64, activation='relu'))
  model.add(Dense(1, activation='softmax'))
  # Compile model
  model.compile(loss='sparse_categorical_crossentropy',
              optimizer='adam', metrics=['accuracy'])
  model.fit(training_data, training_labels, validation_data=(
    test_data, test_labels), nb_epoch=30, batch_size=8, verbose=2)

  scores = model.evaluate(test_data, test_labels, verbose=1)
  print("Baseline Error: %.2f%%" % (100 - scores[1] * 100))
  # model.save('trained_CNN.h5')
  return None

这是一个二分类问题,但我一直收到信息收到了一个超出有效范围[0, 1)的标签值1,这对我来说毫无意义。有什么建议吗?

8个回答

72

区间 [0, 1) 表示介于0到1之间的所有数字,不包括1。因此,1不是区间[0, 1)中的值。

我不是100%确定,但问题可能是由您选择的损失函数导致的。对于二元分类,binary_crossentropy 应该是更好的选择。


32

在最后一个密集层中,您使用了model.add(Dense(1, activation='softmax'))。这里的1将其值限制为[0,1),将其形状更改为最大输出标签。例如,如果您的输出来自标签[0,7),则使用model.add(Dense(7, activation='softmax'))


4
根据文档(https://keras.io/layers/core/),这里的“1”是输出维度(等级),而不是输出范围。 - Luis Kabongo
这里的输出将是7层的,它是什么意思?是否每一层都会给出对应类别的概率? - fahd

23

稀疏分类交叉熵的特殊性质

损失函数稀疏分类交叉熵将分类器的最终层解释为每个可能类别的概率集,并将输出值解释为类别的编号。(Tensorflow/Keras 文档提供了更多详细信息。)因此,输出层的 x 个神经元与在范围从 0 到 x-1 的输出值进行比较;只有一个神经元的输出层是一种不合理的“一元”分类器。

如果这是一个分类任务并且您希望以从0到x-1的形式得到输出数据,则可以使用稀疏分类交叉熵,但需要将输出层中的神经元数设置为您拥有的类别数。或者,您可以对输出进行 one-hot 编码,并使用分类交叉熵损失函数代替稀疏分类交叉熵。

如果这不是分类任务,并且您希望像回归问题那样预测任意实数,则分类交叉熵根本不是一个适合的损失函数。


如果想预测第六个数字,在训练数据为 [1,2,3,4,5],且只有一个分类 [6] 的情况下,你会采用什么分类方法?我认为可以使用分类交叉熵,对于这种特殊情况,'一元'分类器可能是合理的选择。 - spencer741
如果这是一个分类任务,那么你正在学习(即调整参数)的函数的可能输出集合(即函数的范围,在技术数学定义中的函数)是类别列表。如果只有一个类别,则这是退化形式,其中范围由单个值组成,并且您拥有的函数根据定义无法输出除该单个类别之外的任何内容,无论给出什么输入,无论是否训练,它始终输出唯一可能的答案。 - Peteris
所以,一元分类器从来没有意义,只是一个可能在技术上算作“可学习函数”的退化边缘情况的例子。这个评论似乎说明了对分类的基本误解——分类器将尝试预测(预定义的)可能答案之一。如果只有一个类别,就没有什么可以预测的了,不可能给出错误的答案,因为没有其他答案可供选择——“有一个类别:[6]”字面上意味着您正在明确假设[6]是唯一可能的输出,无论如何。 - Peteris
如果想要预测第六个数字,训练数据为[1,2,3,4,5],只有一个类别:[6]。如果我将其理解为预测序列中的下一个数字的任务(因此它也必须适用于[11,12,13,14,15]->[16]),那么没有分类方法是合适的,因为它(就像任何其他预测任意实数或自然数的任务一样)非常不是分类问题,违反了分类问题的核心假设。 - Peteris
1
这个网站帮助我选择了我的损失函数 https://machinelearningmastery.com/how-to-choose-loss-functions-when-training-deep-learning-neural-networks/ - Stevo

3

错误在 [0,4) 范围内,你可以将类别(标签)数量加一。 例如,将此修改为:

layers.Dense(4)

致:

layers.Dense(5)

对于[0,1)同样适用


2
Cray和Shaili的回答是正确的!我得到了从1到6的结果范围,而这行代码是:


tf.keras.layers.Dense(6, activation = 'softmax') 

出现了错误消息,提示某些事物超出了范围[0,6)。我曾认为这是标签问题(训练和验证标签集中是否都有相应的值?),并一直在检查它们。

)


1
当我使用“float”类型的标签时,遇到了这个问题,将它们转换为“int”类型,问题就解决了...

0

这个问题的另一个可能答案与工作区有关。如果不是像其他答案所建议的逻辑/稀疏性/熵错误,请继续阅读:

如果您创建了一个工作区来保存模型训练的数据,旧的工作区数据可能会在使用新样本重新训练数据时导致此错误,特别是在使用文件夹作为分类标签并且文件夹数量不同的情况下。

示例:

我最初的训练集如下:

Original Sample Set

当我尝试在新的样本集上重新训练时:

New Sample Set

我收到了以下错误信息: Received a label value of 3 which is outside the valid range of [0, 3)

这很可能是因为旧的样本集缓存了4个文件夹,而新的样本集只有3个文件夹,导致了某种问题。我唯一确定的是,一旦我清除了工作区中的旧信息,并重新运行程序,它就可以成功运行。这是在多次失败后进行的孤立更改,所以我确信这是解决问题的方法。

免责声明:我正在使用C#和ML.NET,但仍然使用TensorFlow,这就是我们两个产生错误的地方,所以它绝对适用于这个问题。


0

对我来说,问题在于传递给模型的类数量少于数据中实际的类数量。因此,模型对大多数情况预测为-1,从而导致超出范围的错误。


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