
本文探讨了多类别分类器在处理不属于任何已知类别的输入时,总是返回一个预测结果的常见问题。针对这一挑战,文章提出了一种有效的二阶段分类策略:首先进行二元分类以判断目标是否存在,然后仅在目标存在时执行多类别分类。这种方法能显著提高模型的鲁棒性,并支持“无目标检测”的提示,避免误报。
在构建自定义图像分类应用时,一个常见的问题是,即使上传的图片不属于任何已训练的类别,分类器也总会返回一个预测结果。例如,一个水果检测应用在用户上传非水果图片时,仍然会显示某种水果的检测结果,这显然不符合预期。为了解决这个问题,并实现如“未检测到植物”之类的提示,我们需要对传统的单阶段多类别分类方法进行优化。
当前的多类别分类模型,如提供的代码片段所示,其工作原理是计算输入图片属于每个已知类别的概率(置信度),然后选择置信度最高的类别作为最终预测。
// ... (图像预处理代码) ...
FruitDisease.Outputs outputs = model.process(inputFeature);
TensorBuffer outputFeature0 = outputs.getOutputFeature0AsTensorBuffer();
float[] confidences = outputFeature0.getFloatArray();
int maxPos = 0;
float maxConfidence = 0;
for (int i = 0; i < confidences.length; i++) {
if (confidences[i] > maxConfidence) {
maxConfidence = confidences[i];
maxPos = i;
}
}
String[] classes = {"Watermelon Healthy", "Watermelon Blossom End Rot", "Watermelon Anthracnose", /* ... 其他类别 ... */};
result.setText(classes[maxPos]); // 总是会显示一个类别这段代码的问题在于,它假设输入图片 一定 属于某个已知的 classes 数组中的类别。当输入图片是完全不相关的物体(例如,一张桌子或一辆车)时,模型仍然会计算出对所有水果类别的置信度,并从中选出最高的一个,即使这个“最高”的置信度可能非常低,也依然会被当作有效预测。这导致了“假阳性”的检测结果,即模型错误地识别出不存在的目标。
为了解决上述问题,最有效且推荐的方法是采用二阶段分类策略。这种方法将问题分解为两个独立的、更易于管理和优化的子任务:
在这个阶段,我们需要训练一个独立的二元分类模型。这个模型的任务非常简单:判断输入图片是属于“目标类别”(例如,“水果”)还是“非目标类别”(例如,“非水果”)。
训练数据准备:
模型输出: 这个模型会输出一个概率值,表示图片中存在目标的可能性。我们可以设定一个阈值(例如,0.7),如果概率超过此阈值,则认为图片中存在目标,并进入第二阶段;否则,显示“未检测到目标”的消息。
如果第一阶段的二元分类器判断图片中存在目标,那么我们才将图片输入到现有的多类别分类器中,以识别具体的类别。这正是您当前代码所实现的功能。
集成优势:
另一种可能的方案是在现有的多类别分类器中添加一个额外的“无目标”或“非水果”类别。
优点:
缺点(通常不推荐):
基于以上原因,二阶段分类策略通常是处理未知类别输入的更优选择。
以下是根据二阶段策略修改后的 classifyImage 方法的伪代码结构,以展示其逻辑:
private void classifyImage(Bitmap image) {
try {
// 1. 图像预处理 (与原代码相同)
// ... (省略预处理细节) ...
TensorBuffer inputFeature = TensorBuffer.createFixedSize(new int[]{1, 224, 224, 3}, DataType.FLOAT32);
// ... (加载图片到 inputFeature) ...
// 阶段一:二元分类 - 检测是否存在目标 (例如,是否存在水果)
// 假设您有一个名为 FruitPresenceModel 的二元分类模型
FruitPresenceModel presenceModel = FruitPresenceModel.newInstance(getApplicationContext());
FruitPresenceModel.Outputs presenceOutputs = presenceModel.process(inputFeature);
TensorBuffer presenceOutputBuffer = presenceOutputs.getOutputFeature0AsTensorBuffer(); // 假设输出是 [1, 2] 或 [1, 1]
float[] presenceConfidences = presenceOutputBuffer.getFloatArray();
// 假设 presenceConfidences[0] 是“非水果”的置信度,presenceConfidences[1] 是“水果”的置信度
// 或者如果模型只输出一个值,比如“水果”的概率
float fruitProbability = presenceConfidences.length > 1 ? presenceConfidences[1] : presenceConfidences[0]; // 根据模型实际输出调整
float presenceThreshold = 0.7f; // 设置一个阈值,判断是否为水果
if (fruitProbability > presenceThreshold) {
// 阶段二:多类别分类 - 识别具体是哪种水果
FruitDisease multiClassModel = FruitDisease.newInstance(getApplicationContext());
FruitDisease.Outputs multiClassOutputs = multiClassModel.process(inputFeature);
TensorBuffer multiClassOutputBuffer = multiClassOutputs.getOutputFeature0AsTensorBuffer();
float[] confidences = multiClassOutputBuffer.getFloatArray();
int maxPos = 0;
float maxConfidence = 0;
for (int i = 0; i < confidences.length; i++) {
if (confidences[i] > maxConfidence) {
maxConfidence = confidences[i];
maxPos = i;
}
}
// 再次检查多类别分类的置信度,确保不是一个非常低的预测
float multiClassConfidenceThreshold = 0.6f; // 可以根据实际情况调整
String[] classes = {"Watermelon Healthy", "Watermelon Blossom End Rot", /* ... 其他水果类别 ... */};
if (maxConfidence > multiClassConfidenceThreshold) {
result.setText(classes[maxPos]);
// 显示所有类别的置信度
StringBuilder s = new StringBuilder();
for (int i = 0; i < classes.length; i++) {
s.append(String.format("%s: %.1f%%\n", classes[i], confidences[i] * 100));
}
confidence.setText(s.toString());
confidence.setVisibility(View.VISIBLE);
} else {
// 虽然第一阶段认为是水果,但第二阶段的置信度太低,可能是模糊或难以识别的图片
result.setText("未检测到明确的水果类别。");
confidence.setVisibility(View.GONE);
}
} else {
// 第一阶段判断为非水果
result.setText("未检测到水果。");
confidence.setVisibility(View.GONE);
}
// 释放模型资源
presenceModel.close();
// 如果在条件块内创建,则在条件块内关闭,或者确保在finally块中关闭所有模型
// multiClassModel.close(); // 需要根据实际模型生命周期管理
} catch (Exception e) {
// 处理异常
result.setText("分类失败:" + e.getMessage());
confidence.setVisibility(View.GONE);
}
}注意事项:
通过采用二阶段分类策略,我们可以有效解决多类别分类器在处理未知输入时总是返回预测结果的问题。这种方法不仅提高了模型的准确性和鲁棒性,还使得应用程序能够提供更智能、更符合用户预期的反馈,例如在未检测到目标时显示“未检测到水果”的消息。虽然这需要额外训练一个二元分类模型,但其带来的系统稳定性提升和用户体验优化是显而易见的。
以上就是优化自定义分类器:实现未知类别检测的二阶段策略的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号