具有多个独立输出的二进制分类

时间:2019-07-17 22:27:41

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

我正在使用类似VGG的模型,输入形状为:(num_samples,96,144,3)(96x144个“图像”和3个“通道”)

输出形状不是(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%。

那么我在做什么错了?

1 个答案:

答案 0 :(得分:0)

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

我认为您的数据采用

这样的形式
[features....][0]
[features....][1]
[features....][-1]

对标签进行一次热编码,使其变为

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

所以更喜欢使用

  1. 分类交叉萎缩症

  2. Softmax激活功能,而不是最后一层中的S型激活功能。