我在使用Keras处理一个二分类问题。我使用了LeNet的以下改编版本:
lenet_model = models.Sequential()lenet_model.add(Convolution2D(filters=filt_size, kernel_size=(kern_size, kern_size), padding='valid', input_shape=input_shape))lenet_model.add(Activation('relu'))lenet_model.add(BatchNormalization())lenet_model.add(MaxPooling2D(pool_size=(maxpool_size, maxpool_size)))lenet_model.add(Convolution2D(filters=64, kernel_size=(kern_size, kern_size), padding='valid'))lenet_model.add(Activation('relu'))lenet_model.add(MaxPooling2D(pool_size=(maxpool_size, maxpool_size)))lenet_model.add(Convolution2D(filters=128, kernel_size=(kern_size, kern_size), padding='valid'))lenet_model.add(Activation('relu'))lenet_model.add(MaxPooling2D(pool_size=(maxpool_size, maxpool_size)))lenet_model.add(Flatten())lenet_model.add(Dense(1024, kernel_initializer='uniform'))lenet_model.add(Activation('relu'))lenet_model.add(Dense(512, kernel_initializer='uniform'))lenet_model.add(Activation('relu'))lenet_model.add(Dropout(0.2))lenet_model.add(Dense(1, kernel_initializer='uniform'))lenet_model.add(Activation('sigmoid'))lenet_model.compile(loss='binary_crossentropy', optimizer=Adam(), metrics=['accuracy'])
但我得到了以下错误:
ValueError: Error when checking model target: expected activation_6 to have shape (None, 1) but got array with shape (1652, 2). It gets resolved if I use 2 in the final Dense layer.
回答:
看起来在你的预处理步骤中,你使用了函数将数值类别标签转换为分类标签,即使用独热编码方案表示数值类别(在Keras中,to_categorical(y, num_classes=2)
可以完成这项工作)。
由于你处理的是二分类问题,如果原始标签是0和1,那么编码后的分类标签将是01和10(在独热编码方案中,从右到左数,第n位如果是1,则表示该实例的数值类别为n,其余位为0)。这可以解释为什么错误追踪中的数据维度是(1652, 2)
。
然而,由于你在模型中设置了输出维度为1,你的输出层期望数据中的目标标签只有一位,这对应于你应用上述预处理步骤之前的原始数据。
因此,你可以通过取消标签的预处理或将输出维度更改为2来解决这个问题。如果你坚持使用独热编码的分类标签,你还应该将最后一层的sigmoid激活函数改为softmax激活函数,因为sigmoid只能处理二进制数值类别,即0或1。对于二分类问题,这两种选择在性能上应该没有太大差异。
值得一提的是,在编译这个模型时,你还应该注意你使用的成本函数。一般来说,分类标签与分类交叉熵这样的成本函数配合得最好。特别是对于多类分类(超过2个类别)问题,你需要将分类标签与softmax激活函数一起使用,分类交叉熵几乎应该是你的默认选择,因为它相对于其他常见的成本函数(如MSE和原始错误计数)有很多优势。
分类交叉熵的众多优势之一是,它对“非常自信的错误”惩罚得比分类器“几乎正确”的情况要多得多,这是有道理的。例如,在使用分类交叉熵作为成本函数的二分类设置中,一个分类器如果对某个实例属于类别0有95%的把握,而该实例实际上属于类别1,那么这个分类器将比另一个在犯同样错误时只有51%把握的分类器受到更大的惩罚。其他一些成本函数,如原始错误计数,对分类器在做出决策时的“把握程度”不敏感,这些成本函数只考虑最终的分类结果,这实际上意味着丢失了大量有用的信息。其他一些成本函数,如MSE,会更加强调错误分类的实例,这并不总是我们想要的特征。