【问题标题】:Binary classification with multiple independent outputs具有多个独立输出的二进制分类
【发布时间】:2019-11-26 19:32:00
【问题描述】:

我正在使用这个类似 VGG 的模型,输入形状是:(num_samples,96,144,3) (96x144 "image" and 3 "channels")

输出形状,而不是 (num_samples,)(这意味着,对于每个输入图像都有一个二进制输出:1 或 0)我有 (num_samples, 122)。所以这意味着对于每个输入,我都有一个输出向量(122 个输出,每个输出可以是 1 或 0)。我明白这是一个多标签分类问题,不是吗?

我有一个小问题,我的数据有无效值(输出不是 1 或 0,而是 -1,表示在输出向量的那个位置没有该样本的数据,这可能只是122 个位置中的一个或多个)。 我用代码中定义的屏蔽损失函数屏蔽了这些值。但不知道做得好不好。 (掩蔽损失来源:https://groups.google.com/forum/#!topic/keras-users/pg5Vr-obd_E)

更多数据上下文:ConvNet with missing output data for weather forecast

def masked_binary_crossentropy(y_true, y_pred):
    return K.mean(K.binary_crossentropy(tf.multiply(y_pred, tf.cast(tf.not_equal(y_true, -1), tf.float32)),
                                    tf.multiply(y_true, tf.cast(tf.not_equal(y_true, -1), tf.float32))), axis=-1)

def get_vgg16():
# we initialize the model
model = Sequential()

# Conv Block 1

model.add(Conv2D(64, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(64, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))

# Conv Block 2

model.add(Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))

# Conv Block 3
model.add(Conv2D(256, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(256, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(256, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))

# Conv Block 4
model.add(Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))

# Conv Block 5
model.add(Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))

# FC layers
model.add(Flatten())
model.add(Dense(4096, activation='relu'))
model.add(Dense(4096, activation='relu'))
model.add(Dense(122, activation='sigmoid'))

sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss=masked_binary_crossentropy, optimizer=sgd, metrics=[metrics.binary_accuracy])

return model

model = get_vgg16()

model.fit(x_train, y_train, batch_size=tam_batch, epochs=cant_epocas, verbose=1, validation_data=(x_test, y_test))

训练是这样的:

Epoch 1/20 loss: 0.8437 - binary_accuracy: 0.4365 - val_loss: 1.5494 - val_binary_accuracy: 0.7706
Epoch 2/20 loss: 0.3512 - binary_accuracy: 0.4386 - val_loss: 1.5494 - val_binary_accuracy: 0.7706
Epoch 3/20 loss: 0.3512 - binary_accuracy: 0.4386 - val_loss: 1.5494 - val_binary_accuracy: 0.7706
Epoch 4/20 loss: 0.3512 - binary_accuracy: 0.4386 - val_loss: 1.5494 - val_binary_accuracy: 0.7706

等等…… 可能是什么问题呢?模型中的层是解决此类问题的正确方法吗?或者我应该改变最后一个 Dense(122,activation='sigmoid') 层???

我已经尝试过这个完全相同的模型,但是:a) 没有无效数据(所有样本都有对应的有效 0 或 1); b) 常规的、非掩码的、binary_crossentropy 损失,c) 单个输出 (shape = num_samples,1)(我只使用 122 个中的一个,即无效样本为零的那个)和 d)最后一层 Dense( 1,激活='sigmoid') 该模型工作得很好。最终准确率达到90%以上。

那么我做错了什么?

【问题讨论】:

    标签: tensorflow keras classification conv-neural-network vgg-net


    【解决方案1】:

    如果它也无效,则类别变为正 (1)、负 (0) 和无效 (-1)。

    我假设你的数据是正式的,比如

    [features....][0]
    [features....][1]
    [features....][-1]
    

    标签的一种热编码也是如此,

    [features][1,0,0]
    [features][0,1,0]
    [features][0,0,1]
    

    所以更喜欢使用

    1. 分类交叉熵损失

    2. 在最后一层使用 Softmax 激活函数而不是 sigmoid 激活函数。

    【讨论】:

    • 是的,但是在同一个特征中可以存在超过 1 个类,即:[features][1, 1, 0, -1, 1...., -1](第二维是 122)。所以是多标签案例
    • 您可以尝试使用单个节点输出,然后这将成为预测 1,0,-1 值的回归问题,这不会给您带来更好的准确性。由于您需要分类,最好为每个类设置一个节点。
    猜你喜欢
    • 2020-11-22
    • 2021-05-02
    • 2018-05-30
    • 2019-07-14
    • 2018-04-09
    • 1970-01-01
    • 2021-04-01
    • 1970-01-01
    • 2020-07-20
    相关资源
    最近更新 更多