我想为一个具有4个不同类别的多类分类问题设置一个Keras模型(使用TensorFlow后端)。我有标记和未标记的数据。
我已经处理了只使用标记数据进行训练的情况,我的模型看起来像这样:
# create modelinputs = keras.Input(shape=(len(config.variables), )) X = layers.Dense(units=200, activation="relu")(inputs)output = layers.Dense(units=4, activation="softmax", name="output")(X)model = keras.Model(inputs=inputs, outputs=output)model.compile(optimizer=optimizers.Adam(1e-4), loss=loss_function, metrics=["accuracy"])# train modelmodel.fit( x=train_data, y=train_class_labels, batch_size=200, epochs=200, verbose=2, validation_split=0.2, sample_weight = class_weights )
我已经有使用两种不同损失函数的功能模型,即categorical_crossentropy
和sparse_categorical_crossentropy
。根据损失函数的不同,我的train_class_labels
使用的是独热编码表示(例如[[0,1,0,0], [0,0,0,1], …])或整数表示(例如[0,0,2,1,0,3, …]),一切正常运作。class_weights
是一些权重向量([0.78, 1,34, …])
现在,为了进一步的计划,我需要在训练过程中包含未标记的数据,但这些数据需要被损失函数忽略。
我尝试过以下方法:
- 当使用
categorical_crossentropy
作为损失函数时,将未标记数据的标签设置为[0,0,0,0],因为我认为这样我的未标记数据就会被损失函数忽略。但这在训练后改变了预测结果。 - 我也尝试将未标记数据的权重设置为0,但这也没有效果
我得出结论,我需要以某种方式标记我的未标记数据,并定制我的损失函数,以便它可以被告知忽略这些样本。类似于这样
def custom_loss(y_true, y_pred): if y_true == labeled data: return normal loss function if y_true == unlabeled data: return 0
这些是我找到的一些代码片段,但它们似乎不起作用:
def custom_loss(y_true, y_pred): loss = losses.sparse_categorical_crossentropy(y_true, y_pred) return K.switch(K.flatten(K.equal(y_true, -1)), K.zeros_like(loss), loss)def custom_loss2(y_true, y_pred): idx = tf.not_equal(y_true, -1) y_true = tf.boolean_mask(y_true, idx) y_pred = tf.boolean_mask(y_pred, idx) return losses.sparse_categorical_crossentropy(y_true, y_pred)
在这些例子中,我将未标记数据的标签设置为-1,所以train_class_labels
看起来像这样:[0,-1,2,0,3, … ]
但当使用第一个损失函数时,我只得到Nans,而使用第二个时,我得到以下错误:Invalid argument: logits and labels must have the same first dimension, got logits shape [1,5000] and labels shape [5000]
回答:
我认为将标签设置为[0,0,0,0]是可以的。因为损失是通过每个类别的实例的对数损失的总和来计算的(在你的情况下,没有标签的实例的损失将为0)。
我不明白为什么你在监督设置中将未标记的数据插入到训练中。
我认为你得到的差异是由于批量大小和梯度步骤造成的。如果有不参与梯度下降的实例,计算出的损失将与之前不同,然后你会在预测中看到差异。
基本上,每个批次中包含的信息量较少的实例会减少。
如果你使用的数据集大小作为批量大小,那么与之前没有未标记实例的训练(但始终使用批量大小=数据集大小进行训练)将没有区别