我有一个带有单热编码标签的 CNN 二进制分类器,它是我使用 Keras 编写的,它只是没有训练到我想要鼓励的指标。我的数据非常不平衡(91% 0 类,9% 1 类),无论我做什么,它总是有利于大多数类的准确性。我玩过班级重量。我试过创建平衡的测试和训练文件。我的 CNN 似乎更难在少数类中找到模式,所以它总是返回多数类的改进。我想做的是创建一个自定义损失,允许我定义一个分数,奖励少数类的真阳性 (TP) 并惩罚其假阳性 (FP)。类似于以下内容:
def minority_score(y_true, y_pred):
max_value_true = K.argmax(y_true, -1)
max_value_pred = K.argmax(y_pred, -1)
FP = np.logical_and(K.eval(max_value_pred) == 1, K.eval(max_value_true) == 0)
TP = np.logical_and(K.eval(max_value_pred) == 1, K.eval(max_value_true) == 1)
score = (TP *3) - FP # punish each FP with a -1 and reward each TP with a +3
return score # invert if using as loss function
model = build_model()
model.compile(loss=minority_score,
optimizer=keras.optimizers.Adam(lr=0.0001),
metrics=[minority_score, metrics.categorical_accuracy])
我尝试了各种方法,但由于我的标签是单热编码的,我总是在解码它们时遇到问题。y_pred
并且y_true
是上例中的张量。在该示例中,我收到此错误:
InvalidArgumentError (see above for traceback): You must feed a value for placeholder tensor 'conv2d_1_input' with dtype float and shape [?,28,28,1]
这是所有放在一起的相关代码。谢谢你。
def minority_score(y_true, y_pred):
max_value_true = K.argmax(y_true, -1)
max_value_pred = K.argmax(y_pred, -1)
# below line errors out
FP = np.logical_and(K.eval(max_value_pred) == 1, K.eval(max_value_true) == 0)
TP = np.logical_and(K.eval(max_value_pred) == 1, K.eval(max_value_true) == 1)
score = (TP *3) - FP # punish each FP with a -1 and reward each TP with a +3
return score
class Modeler:
def build_model(self):
"""
this method only builds the scaffolding
weights should be set and/or loaded
outside of it
"""
model = Sequential()
# layerset 1
model.add(Conv2D(
filters=32,
kernel_size=[3, 3],
strides=(1, 1),
input_shape=(28, 28, 1),
padding='same'
))
model.add(BatchNormalization())
model.add(Activation("relu"))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
model.add(Dropout(0.2))
# layerset 2
model.add(Conv2D(
filters=64,
kernel_size=[3, 3],
padding='same'
))
model.add(BatchNormalization())
model.add(Activation("relu"))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.2))
# layerset 3
model.add(Conv2D(
filters=128,
kernel_size=[3, 3],
padding='same'
))
model.add(BatchNormalization())
model.add(Activation("relu"))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(2048, activation='relu'))
model.add(Dense(self.num_classes, activation='softmax'))
return model
def compile_model(self, model, learning_rate):
model.compile(loss=minority_score,
optimizer=keras.optimizers.Adam(lr=learning_rate),
metrics=[minority_score, metrics.categorical_accuracy)
return model
def one_hot_encode_labels(self, data):
return keras.utils.to_categorical(data, self.num_classes)
modeler = modeler.build_model()
model = modeler.compile_model()
# load model weights from checkpoint here
# load and shape data here
# create class weight dictionary here
model.fit(x_train, y_train,
batch_size=batch_size,
epochs=num_epochs,
verbose=1,
validation_data=(x_test, y_test),
callbacks=callbacks_list,
class_weight=weight_dict)
```