如何使用LSTM进行多类别多输出分类

4

我有一个多类别多输出的分类问题(详见https://scikit-learn.org/stable/modules/multiclass.html)。换句话说,我的数据集如下。

node_name, timeseries_1, timeseries_2, label_1, label_2
node1, [1.2, ...], [1.8, ...], 0, 2
node2, [1.0, ...], [1.1, ...], 1, 1
node3, [1.9, ...], [1.2, ...], 0, 3 
...
...
...

因此,我的 label_1 可以是 0 或者 1,而我的 label_2 可以是 01 或者 2
我的当前代码如下。
def create_network():
    model = Sequential()
    model.add(LSTM(200, input_shape=(16,2)))
    model.add(Dense(100))
    model.add(Dropout(0.2))
    model.add(Dense(3, activation='softmax'))
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

    return model

neural_network = KerasClassifier(build_fn=create_network, epochs=100, batch_size=100, verbose=0)

k_fold = StratifiedKFold(n_splits=10, shuffle=True, random_state=0)

scores = cross_validate(neural_network, my_features, label_data_encoded, cv=k_fold, scoring = ('accuracy', 'precision_weighted', 'recall_weighted', 'f1_weighted', 'roc_auc'))

我的问题如下。

  • 由于我有两个标签(即label_1label_2),如何将这些标签适配到lstm模型中?我是否需要做类似于keras.utils.to_categorical(label_1, 2)keras.utils.to_categorical(label_2, 3)的操作?
  • 如何更改模型,使其适用于多分类多输出分类

如果需要更多细节,我很乐意提供。

2个回答

4
如果我理解正确,label_1是二进制的,而label_2是多类别问题,因此我们需要让模型具有两个分别使用不同损失函数的输出;分别是二进制和分类交叉熵。
然而,Sequential API不允许多个输入/输出。
顺序API允许您逐层创建大多数问题的模型。但它的局限性在于它不允许您创建共享层或具有多个输入或输出的模型。
您可以使用Functional API创建两个输出层,并使用所需的损失函数编译模型。
X=Input(input_shape)
X=Layer(X)
'
'
'
'
out1=Dense(1, activation='sigmoid')(X)
out2=Dense(3, activation='softmax')(X)
model = Model(inputs = input, outputs = [out1,out2])
model.compile(loss = ['binary_crossentropy','categorical_crossentropy'], loss_weights = [l1,l2], ...)

model.fit(input,[label_1, label_2_toCategotical]

网络将会最小化的损失函数是两种损失函数的加权和,由l1和l2进行加权。
希望这可以帮到你 :)

非常感谢您的出色回答。这正是我一直在寻找的。然而,我还有一个问题。由于kerasclassifier不支持函数式API,我们如何使用您的方法执行10倍分层交叉验证。如果您有代码/或知道如何编写它,请告诉我。期待您的回复。谢谢 :) - EmJ
1
嗯,不确定我是否有一个优雅的解决方案,但您可以使用sklearn StratifiedKFold生成拆分,然后手动循环遍历这些拆分。 - Aditya Arora
谢谢。如果您有sklearn StratifiedKFold手动循环的代码,请发布出来。如果没有,我会在其他的Stack Overflow问题中查看:) - EmJ
1
关于label_2的形状是正确的。Label_1是二进制的,因此不需要任何转换。关于l1l2权重,我认为将它们视为另一个超参数是公平的。因此,您可以从将两者都设置为1开始,然后尝试调整,如果其中一个输出表现太差。很抱歉我找不到StratifiedKFold的代码,您可以查看官方的sklearn文档,或者确实可以查看其他答案! :) - Aditya Arora
1
对于标签_1,预测的类别为1,假设阈值为0.5,您可以进行调整。标签_2预测类别为2,请注意它是softmax激活,因此将为其中一个类别分配最大概率。 - Aditya Arora
显示剩余3条评论

1
这是一个比较复杂的问题,因为Scikit-Learn API和Keras API在多类多输出方面不直接兼容。此外,TensorFlow v1和v2处理事情的方式甚至也有所不同。现有的Keras包装器对于更复杂的情况并不真正有效。
我创建了一个KerasClassifier扩展,能够处理这些情况,该软件包和文档在这里(GitHub)。完全透明:我是该软件包的创建者,但我没有任何经济利益,它是开源的。
使用这些扩展版本,您可以轻松处理多类多输出问题。我认为对于您的情况,它应该可以直接使用,但如果不行,您可以从KerasClassifier继承并重写target_encoder以将数据从Scikit-Learn格式转换为您的Keras模型所需的格式。更多细节请参见这里(docs)
希望这能帮助到您!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接