我之前在 Python 中遇到过类似的问题。希望这对您有所帮助,如果您正在使用,您可以在 Matlab 中提出一个替代实现。
说了这么多,我最终选择了一个模型来进行所有预测。出于您的目的,您可以有一个用于狗与猫的二进制输出,另一个用于狗品种的多类输出,以及另一个用于猫品种的多类输出。
使用 Tensorflow,我为不相关的类创建了一个掩码。例如,如果图像是一只猫,那么所有的狗品种都是不相关的,它们不应该影响该示例的模型训练。这需要一个自定义的 TF 数据集(将掩码的 0 转换为 -1)和一个自定义的损失函数,当该示例存在掩码时返回 0 错误。
最后是训练过程。 具体到您的问题,您必须创建自定义精度函数,以按照您的要求处理掩码值,否则这部分过程应该是标准的。最佳做法是在训练数据中均匀分布类,但它们都可以一起训练。
如果您在 Google 上搜索“多任务训练”,您可以找到解决此问题的其他资源。
如果您有兴趣,这里有一些代码片段:
对于隐藏不相关标签的自定义 TF 数据集...
# Replace 0's with -1 for mask when there aren't any labels
def produce_mask(features):
for filt, tensor in features.items():
if "target" in filt:
condition = tf.equal(tf.math.reduce_sum(tensor), 0)
features[filt] = tf.where(condition, tf.ones_like(tensor) * -1, tensor)
return features
def create_dataset(filepath, batch_size=10):
...
# **** This is where the mask was applied to the dataset
dataset = dataset.map(produce_mask, num_parallel_calls=cpu_count())
...
return parsed_features
自定义损失函数。我使用的是二元交叉熵,因为我的问题是多标签。您可能希望将其调整为分类交叉熵。
# Custom loss function
def masked_binary_crossentropy(y_true, y_pred):
mask = backend.cast(backend.not_equal(y_true, -1), backend.floatx())
return backend.binary_crossentropy(y_true * mask, y_pred * mask)
然后是自定义准确度指标。我使用的是 top-k 精度,您可能需要根据您的目的进行修改,但这会给您一个大致的想法。将其与损失函数进行比较时,该函数不会将所有值都转换为 0,否则会过度夸大准确性,而是将这些值完全过滤掉。之所以可行,是因为输出是单独测量的,因此每个输出(二进制、猫品种、狗品种)都会有不同的准确度度量,仅过滤到相关示例。
backend 是 keras 后端。
def top_5_acc(y_true, y_pred, k=5):
mask = backend.cast(backend.not_equal(y_true, -1), tf.bool)
mask = tf.math.reduce_any(mask, axis=1)
masked_true = tf.boolean_mask(y_true, mask)
masked_pred = tf.boolean_mask(y_pred, mask)
return top_k_categorical_accuracy(masked_true, masked_pred, k)
编辑
不,在我上面描述的场景中,只有一个模型,它是用所有数据一起训练的。单个模型有 3 个输出。掩码是其中的主要部分,因为它允许网络仅调整与示例相关的权重。如果图像是猫,那么狗品种预测不会导致损失。