1

我正在使用这个类似 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

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,activation='sigmoid') 并且模型工作得很好。最终准确率超过90%。

那么我做错了什么?

4

1 回答 1

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 激活函数而不是 sigmoid 激活函数。

于 2019-07-19T05:21:12.907 回答