Keras Multi-class Multi-label image classification:处理独立和相关标签的混合以及非二进制输出
Keras Multi-class Multi-label image classification: handle a mix of independent and dependent labels & non-binary output
我正在尝试为多class 多标签 class 化任务训练来自 Keras 的预训练 VGG16 模型。这些图像来自 NIH 的 Chest X-Ray 8 数据集。该数据集有 14 个标签(14 种疾病)加上一个“未发现”标签。
我理解对于独立标签,比如14种疾病,我应该使用sigmoid激活+binary_crossentropy损失函数;对于相关标签,我应该使用 softmax + categorical_crossentropy.
然而,在我总共 15 个标签中,有 14 个是独立的,但“未发现”的标签在技术上与其余 14 个标签相关 --> “未发现”和患有疾病的概率) 加起来应为 1,但应独立给出患何种疾病的概率。那我应该用什么loss呢?
此外,我的输出是一个浮点数(概率)列表,每一列都是一个标签。
y_true:
[[0. 0. 0. ... 0. 0. 1.]
[0. 0. 0. ... 0. 0. 1.]
[0. 0. 1. ... 0. 0. 0.]
...
[0. 0. 0. ... 0. 0. 1.]
[0. 0. 0. ... 0. 0. 0.]
[0. 0. 0. ... 0. 0. 1.]]
y_predict:
[[0.1749 0.0673 0.1046 ... 0. 0. 0.112 ]
[0. 0.1067 0.2804 ... 0. 0. 0.722 ]
[0. 0. 0.0686 ... 0. 0. 0.5373]
...
[0.0571 0.0679 0.0815 ... 0. 0. 0.532 ]
[0.0723 0.0555 0.2373 ... 0. 0. 0.4263]
[0.0506 0.1305 0.4399 ... 0. 0. 0.2792]]
这样的结果使得无法使用 classification_report()
函数来评估我的模型。我正在考虑获得一个阈值以将其转换为二进制文件,但它将更多地是人工修改而不是 CNN 预测,因为我必须 select 一个阈值。所以我不确定我是否应该做一些硬编码或者是否有任何其他已经存在的方法来处理这种情况?
我对 CNN 和 classification 很陌生,所以如果有人能指导我或给我任何提示,我将非常感激。谢谢!
主体代码如下:
vgg16_model = VGG16()
last_layer = vgg16_model.get_layer('fc2').output
#I am treating them all as independent labels
out = Dense(15, activation='sigmoid', name='output_layer')(last_layer)
custom_vgg16_model = Model(inputs=vgg16_model.input, outputs=out)
for layer in custom_vgg16_model.layers[:-1]:
layer.trainable = False
custom_vgg16_model.compile(Adam(learning_rate=0.00001),
loss = "binary_crossentropy",
metrics = ['accuracy']) # metrics=accuracy gives me very good result,
# but I suppose it is due to the large amount
# of 0 label(not-this-disease prediction),
# therefore I am thinking to change it to
# recall and precision as metrics. If you have
# any suggestion on this I'd also like to hear!
关于我的项目的一些更新,我实际上已经设法解决了这个问题中提到的大部分问题。
首先,由于这是一个多class多标签class化问题,我决定使用 ROC-AUC 分数而不是精度或召回率作为评估指标。它的优点是不涉及阈值——AUC 有点像某个阈值范围内的性能平均值。而且它只关注正预测,因此它减少了数据集中大多数 0 的影响。在我的案例中,这可以更准确地预测模型的性能。
对于输出 class,我决定使用 14 classes 而不是 15 —— 如果所有标签都是 0 那么它意味着“没有找到”。然后我可以愉快地在我的输出层使用 sigmoid 激活。尽管如此,我还是使用焦点损失而不是二元交叉熵,因为我的数据集高度不平衡。
我仍然面临问题,因为我的 ROC 不好(非常接近 y=x,有时低于 y=x)。但我希望我的进步能给任何找到这个的人一些启发。
我正在尝试为多class 多标签 class 化任务训练来自 Keras 的预训练 VGG16 模型。这些图像来自 NIH 的 Chest X-Ray 8 数据集。该数据集有 14 个标签(14 种疾病)加上一个“未发现”标签。
我理解对于独立标签,比如14种疾病,我应该使用sigmoid激活+binary_crossentropy损失函数;对于相关标签,我应该使用 softmax + categorical_crossentropy.
然而,在我总共 15 个标签中,有 14 个是独立的,但“未发现”的标签在技术上与其余 14 个标签相关 --> “未发现”和患有疾病的概率) 加起来应为 1,但应独立给出患何种疾病的概率。那我应该用什么loss呢?
此外,我的输出是一个浮点数(概率)列表,每一列都是一个标签。
y_true:
[[0. 0. 0. ... 0. 0. 1.]
[0. 0. 0. ... 0. 0. 1.]
[0. 0. 1. ... 0. 0. 0.]
...
[0. 0. 0. ... 0. 0. 1.]
[0. 0. 0. ... 0. 0. 0.]
[0. 0. 0. ... 0. 0. 1.]]
y_predict:
[[0.1749 0.0673 0.1046 ... 0. 0. 0.112 ]
[0. 0.1067 0.2804 ... 0. 0. 0.722 ]
[0. 0. 0.0686 ... 0. 0. 0.5373]
...
[0.0571 0.0679 0.0815 ... 0. 0. 0.532 ]
[0.0723 0.0555 0.2373 ... 0. 0. 0.4263]
[0.0506 0.1305 0.4399 ... 0. 0. 0.2792]]
这样的结果使得无法使用 classification_report()
函数来评估我的模型。我正在考虑获得一个阈值以将其转换为二进制文件,但它将更多地是人工修改而不是 CNN 预测,因为我必须 select 一个阈值。所以我不确定我是否应该做一些硬编码或者是否有任何其他已经存在的方法来处理这种情况?
我对 CNN 和 classification 很陌生,所以如果有人能指导我或给我任何提示,我将非常感激。谢谢!
主体代码如下:
vgg16_model = VGG16()
last_layer = vgg16_model.get_layer('fc2').output
#I am treating them all as independent labels
out = Dense(15, activation='sigmoid', name='output_layer')(last_layer)
custom_vgg16_model = Model(inputs=vgg16_model.input, outputs=out)
for layer in custom_vgg16_model.layers[:-1]:
layer.trainable = False
custom_vgg16_model.compile(Adam(learning_rate=0.00001),
loss = "binary_crossentropy",
metrics = ['accuracy']) # metrics=accuracy gives me very good result,
# but I suppose it is due to the large amount
# of 0 label(not-this-disease prediction),
# therefore I am thinking to change it to
# recall and precision as metrics. If you have
# any suggestion on this I'd also like to hear!
关于我的项目的一些更新,我实际上已经设法解决了这个问题中提到的大部分问题。
首先,由于这是一个多class多标签class化问题,我决定使用 ROC-AUC 分数而不是精度或召回率作为评估指标。它的优点是不涉及阈值——AUC 有点像某个阈值范围内的性能平均值。而且它只关注正预测,因此它减少了数据集中大多数 0 的影响。在我的案例中,这可以更准确地预测模型的性能。
对于输出 class,我决定使用 14 classes 而不是 15 —— 如果所有标签都是 0 那么它意味着“没有找到”。然后我可以愉快地在我的输出层使用 sigmoid 激活。尽管如此,我还是使用焦点损失而不是二元交叉熵,因为我的数据集高度不平衡。
我仍然面临问题,因为我的 ROC 不好(非常接近 y=x,有时低于 y=x)。但我希望我的进步能给任何找到这个的人一些启发。