在 TensorFlow.Keras 中自定义从头开始的多输出多类别分类

我想从头开始训练一个多输出多类别的分类模型(使用自定义的fit()方法)。我希望能得到一些建议。为了学习的机会,这里我将详细展示整个场景。希望这对其他人有帮助。

数据集和目标

我使用的数据来自这里;这是一个孟加拉手写字符识别挑战,每个样本都有3个相互关联的输出,每个输出都有多个类别。请看下面的图示:

a

如上图所示,您可以看到,ক্ট্রো由3个组成部分组成(ক্ট , ো , ‍‍্র),分别称为字根元音符号辅音符号,它们一起被称为字形。此外,字根还有168个不同的类别,其他类别(117)也是如此。这种增加的复杂性导致了约13,000种不同的字形变体(与英语的250个字形单位相比)。

目标是分类每张图像中的字形的组成部分

初始方法(没有问题)

我在这里实现了一个训练管道,其中展示了使用旧的keras(不是tf.keras)及其便利的功能,如model.compilecallbacks等。我定义了一个自定义数据生成器,并定义了一个类似下面的模型架构。

input_tensor = Input(input_dim)curr_output = base_model(input_tensor)oputput1 = Dense(168,  activation='softmax', name='gra') (curr_output)oputput2 = Dense(11,   activation='softmax', name='vow') (curr_output)oputput3 = Dense(7,    activation='softmax', name='cons') (curr_output)output_tensor = [oputput1, oputput2, oputput3]    model = Model(input_tensor, output_tensor)

并按以下方式编译模型:

model.compile(        optimizer = Adam(learning_rate=0.001),         loss = {'gra' : 'categorical_crossentropy',                 'vow' : 'categorical_crossentropy',                 'cons': 'categorical_crossentropy'},        loss_weights = {'gra' : 1.0,                        'vow' : 1.0,                        'cons': 1.0},        metrics={'gra' : 'accuracy',                  'vow' : 'accuracy',                  'cons': 'accuracy'}    )

如您所见,我可以明确控制每个输出的lossloss_weightsaccuracy。使用.fit()方法,可以为模型使用任何callbacks函数。

新方法(有一些问题)

现在,我想使用tf.keras的新功能重新实现它。例如,模型子类化自定义训练。然而,数据加载器没有变化。模型定义如下:

    def __init__(self, dim):        super(Net, self).__init__()        self.efnet  = EfficientNetB0(input_shape=dim,                                     include_top = False,                                      weights = 'imagenet')        self.gap     = KL.GlobalAveragePooling2D()        self.output1 = KL.Dense(168,  activation='softmax', name='gra')        self.output2 = KL.Dense(11,   activation='softmax', name='vow')         self.output3 = KL.Dense(7,    activation='softmax', name='cons')         def call(self, inputs, training=False):        x     = self.efnet(inputs)        x     = self.gap(x)        y_gra = self.output1(x)        y_vow = self.output2(x)        y_con = self.output3(x)        return [y_gra, y_vow, y_con]

现在我主要面临的问题是为每个输出正确定义metricslossloss_weights函数。然而,我开始如下所示:

optimizer        = tf.keras.optimizers.Adam(learning_rate=0.05)loss_fn          = tf.keras.losses.CategoricalCrossentropy(from_logits=True)train_acc_metric = tf.keras.metrics.Accuracy()@tf.functiondef train_step(x, y):    with tf.GradientTape(persistent=True) as tape:        logits = model(x, training=True)  # Logits for this minibatch        train_loss_value = loss_fn(y, logits)    grads = tape.gradient(train_loss_value, model.trainable_weights)    optimizer.apply_gradients(zip(grads, model.trainable_weights))    train_acc_metric.update_state(y, logits)    return train_loss_valuefor epoch in range(2):    # Iterate over the batches of the dataset.    for step, (x_batch_train, y_batch_train) in enumerate(train_generator):        train_loss_value = train_step(x_batch_train, y_batch_train)    # Reset metrics at the end of each epoch    train_acc_metric.reset_states()

除了上述设置外,我还尝试了许多其他方法来处理这种问题情况。例如,我定义了3个损失函数和3个指标,但事情并未正常工作。loss/acc变成了nan类型的东西。

在这种情况下,我的几个直接问题是:

  • 如何定义lossmetricsloss_weights
  • 如何有效使用所有callbacks功能

为了学习的机会,如果它还有额外的回归类型输出(除了其他3个多输出之外,总共4个),如何在自定义fit中处理所有这些?我访问了这个SO,为不同类型的输出(分类+回归)提供了一些提示。


回答:

您只需要执行一个自定义训练循环,但所有操作都需要进行3次(如果您还有一个连续变量,则需要进行4次)。这是一个使用四重输出架构的示例:

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注