首页 > 解决方案 > keras:具有外部约束的无监督学习

问题描述

我必须在二进制类型(真/假)的未标记数据上训练一个网络,这听起来像是无监督学习。这是标准化数据的样子:

array([[-0.05744527, -1.03575495, -0.1940105 , -1.15348956, -0.62664491,
    -0.98484037],
   [-0.05497629, -0.50935675, -0.19396862, -0.68990988, -0.10551919,
    -0.72375012],
   [-0.03275552,  0.31480204, -0.1834951 ,  0.23724946,  0.15504367,
     0.29810553],
   ...,
   [-0.05744527, -0.68482282, -0.1940105 , -0.87534175, -0.23580062,
    -0.98484037],
   [-0.05744527, -1.50366446, -0.1940105 , -1.52435329, -1.14777063,
    -0.98484037],
   [-0.05744527, -1.26970971, -0.1940105 , -1.33892142, -0.88720777,
    -0.98484037]])

但是,我确实对数据中 True 标签的总数有限制。这并不意味着我可以(y_true, y_pred)根据需要在 Keras 中构建一个经典的自定义损失函数:我的外部约束只是在 和 的预测总数上,TrueFalse不是在单个标签上。

我的问题是这种问题是否有某种“标准”方法,以及如何在 Keras 中实现。

可能的解决方案

我是否应该y_true随机分配为 0/1,y_pred使用 sigmoid 激活函数将网络返回为 1/0,然后将我的损失函数定义为

sum_y_true = 500 # arbitrary constant known a priori

def loss_function(y_true, y_pred):
    loss = np.abs(y_pred.sum() - sum_y_true)
    return loss

标签: kerasconstraintsloss-functionunsupervised-learning

解决方案


最后,我采用了以下解决方案,该解决方案有效。

df1)在数据框中用一列定义批次batch_id,以便在每个批次Y_train中都是相同的“批次基本事实”(在我的情况下,批次中真实标签的总数)。然后,您可以将这些实例一起传递到网络。这可以通过生成器来完成:

def grouper(g,x,y):
    while True:
        for gr in g.unique():
            # this assigns indices to the entire set of values in g,
            # then subsects to all the rows in which g == gr
            indices = g == gr
            yield (x[indices],y[indices])

# train set
train_generator = grouper(df.loc[df['set'] == 'train','batch_id'], X_train, Y_train)
# validation set
val_generator = grouper(df.loc[df['set'] == 'val','batch_id'], X_val, Y_val)

2)定义一个自定义损失函数,以跟踪预测为真实的实例总数与基本事实的接近程度:

def custom_delta(y_true, y_pred):

loss = K.abs(K.mean(y_true) - K.sum(y_pred))

return loss


def custom_wrapper():

    def custom_loss_function(y_true, y_pred):
        return custom_delta(y_true, y_pred)

    return custom_loss_function

注意这里

a)每个y_true标签已经是我们批次中基本事实的总和(因为我们没有单独的值)。这就是为什么y_true不总结的原因;

b)K.mean实际上从这个统一张量中提取单个标量有点矫枉过正,其中每批中的所有 y_true 值都是相同的 -K.min或者K.max也可以工作,但我没有测试它们的性能是否更快。

3)使用fit_generator代替fit

fmodel = Sequential()
# ...your layers...
# Create the loss function object using the wrapper function above
loss_ = custom_wrapper()
fmodel.compile(loss=loss_, optimizer='adam')

history1 = fmodel.fit_generator(train_generator, steps_per_epoch=total_batches, 
    validation_data=val_generator,
    validation_steps=df.loc[encs.df['set'] == 'val','batch_id'].nunique(),
    epochs=20, verbose = 2)

通过这种方式,该问题基本上被视为监督学习之一,尽管没有单独的标签,这意味着像真/假阳性这样的概念在这里毫无意义。

这种方法不仅设法给我一个y_pred与我知道的每批总数非常匹配的结果。它实际上找到了两个组(真/假),它们占据了参数空间的预期不同部分。


推荐阅读