我正在使用这个类似 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%。
那么我做错了什么?