0

0

优化自定义分类器:实现未知类别检测的二阶段策略

聖光之護

聖光之護

发布时间:2025-11-30 15:48:02

|

415人浏览过

|

来源于php中文网

原创

优化自定义分类器:实现未知类别检测的二阶段策略

本文探讨了多类别分类器在处理不属于任何已知类别的输入时,总是返回一个预测结果的常见问题。针对这一挑战,文章提出了一种有效的二阶段分类策略:首先进行二元分类以判断目标是否存在,然后仅在目标存在时执行多类别分类。这种方法能显著提高模型的鲁棒性,并支持“无目标检测”的提示,避免误报。

在构建自定义图像分类应用时,一个常见的问题是,即使上传的图片不属于任何已训练的类别,分类器也总会返回一个预测结果。例如,一个水果检测应用在用户上传非水果图片时,仍然会显示某种水果的检测结果,这显然不符合预期。为了解决这个问题,并实现如“未检测到植物”之类的提示,我们需要对传统的单阶段多类别分类方法进行优化。

深入理解问题根源

当前的多类别分类模型,如提供的代码片段所示,其工作原理是计算输入图片属于每个已知类别的概率(置信度),然后选择置信度最高的类别作为最终预测。

// ... (图像预处理代码) ...

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 数组中的类别。当输入图片是完全不相关的物体(例如,一张桌子或一辆车)时,模型仍然会计算出对所有水果类别的置信度,并从中选出最高的一个,即使这个“最高”的置信度可能非常低,也依然会被当作有效预测。这导致了“假阳性”的检测结果,即模型错误地识别出不存在的目标。

解决方案:二阶段分类策略

为了解决上述问题,最有效且推荐的方法是采用二阶段分类策略。这种方法将问题分解为两个独立的、更易于管理和优化的子任务:

  1. 二元分类(目标存在性检测):首先判断图片中是否存在我们感兴趣的目标(例如,是否存在水果)。
  2. 多类别分类(具体目标识别):如果第一阶段确认存在目标,则进一步识别具体是哪种目标(例如,是哪种水果)。

阶段一:二元分类(存在性检测)

在这个阶段,我们需要训练一个独立的二元分类模型。这个模型的任务非常简单:判断输入图片是属于“目标类别”(例如,“水果”)还是“非目标类别”(例如,“非水果”)。

训练数据准备:

  • 正样本:包含目标物体的图片(例如,各种水果的图片)。
  • 负样本:不包含任何目标物体的图片(例如,风景、人物、日常物品等,这些是用户可能上传的“无关”图片)。负样本的多样性至关重要,以确保模型能够有效地区分出与目标完全不相关的图片。

模型输出: 这个模型会输出一个概率值,表示图片中存在目标的可能性。我们可以设定一个阈值(例如,0.7),如果概率超过此阈值,则认为图片中存在目标,并进入第二阶段;否则,显示“未检测到目标”的消息。

阶段二:多类别分类(具体目标识别)

如果第一阶段的二元分类器判断图片中存在目标,那么我们才将图片输入到现有的多类别分类器中,以识别具体的类别。这正是您当前代码所实现的功能。

集成优势:

喵记多
喵记多

喵记多 - 自带助理的 AI 笔记

下载
  • 避免误报:只有当图片被确认为包含目标时,才会进行具体的类别识别,从而避免了对无关图片的错误分类。
  • 提高鲁棒性:两个模型各司其职,可以分别进行优化,提高了整个系统的鲁棒性。
  • 清晰的用户反馈:可以根据第一阶段的结果,清晰地向用户展示“未检测到目标”或具体的检测结果。

替代方案:N+1 类分类(不推荐)

另一种可能的方案是在现有的多类别分类器中添加一个额外的“无目标”或“非水果”类别。

优点:

  • 概念上简单,只需要一个模型。

缺点(通常不推荐):

  • 类别不平衡:如果“无目标”类别涵盖了所有非水果的图片,那么这个类别的样本空间将是无限的,且其内部多样性远超其他具体水果类别。这会导致严重的类别不平衡问题,使得模型难以有效地学习“无目标”的特征。
  • 定义困难:很难收集到足够全面且代表性的“无目标”训练数据。模型可能会将训练集中未见过的非目标图片错误地分类为某个水果,或者将新的水果图片错误地分类为“无目标”。
  • 性能下降:由于“无目标”类别的复杂性,可能会影响模型对具体目标类别的识别精度。

基于以上原因,二阶段分类策略通常是处理未知类别输入的更优选择。

实施二阶段策略的示例代码结构

以下是根据二阶段策略修改后的 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);
    }
}

注意事项:

  1. 模型训练:您需要单独训练一个 FruitPresenceModel 二元分类器。这通常意味着准备一个专门的数据集,包含“水果”和“非水果”两类图片。
  2. 置信度阈值:presenceThreshold 和 multiClassConfidenceThreshold 的设定至关重要。它们需要根据您的模型性能和实际应用需求进行调优。过高的阈值可能导致漏报,过低的阈值可能导致误报。
  3. 模型资源管理:确保在不再需要模型时正确关闭它们,以释放内存和其他系统资源。在 Android 开发中,通常在 onDestroy() 或适当的生命周期回调中关闭模型。

总结

通过采用二阶段分类策略,我们可以有效解决多类别分类器在处理未知输入时总是返回预测结果的问题。这种方法不仅提高了模型的准确性和鲁棒性,还使得应用程序能够提供更智能、更符合用户预期的反馈,例如在未检测到目标时显示“未检测到水果”的消息。虽然这需要额外训练一个二元分类模型,但其带来的系统稳定性提升和用户体验优化是显而易见的。

相关专题

更多
android开发三大框架
android开发三大框架

android开发三大框架是XUtil框架、volley框架、ImageLoader框架。本专题为大家提供android开发三大框架相关的各种文章、以及下载和课程。

269

2023.08.14

android是什么系统
android是什么系统

Android是一种功能强大、灵活可定制、应用丰富、多任务处理能力强、兼容性好、网络连接能力强的操作系统。本专题为大家提供android相关的文章、下载、课程内容,供大家免费下载体验。

1736

2023.08.22

android权限限制怎么解开
android权限限制怎么解开

android权限限制可以使用Root权限、第三方权限管理应用程序、ADB命令和Xposed框架解开。详细介绍:1、Root权限,通过获取Root权限,用户可以解锁所有权限,并对系统进行自定义和修改;2、第三方权限管理应用程序,用户可以轻松地控制和管理应用程序的权限;3、ADB命令,用户可以在设备上执行各种操作,包括解锁权限;4、Xposed框架,用户可以在不修改系统文件的情况下修改应用程序的行为和权限。

2002

2023.09.19

android重启应用的方法有哪些
android重启应用的方法有哪些

android重启应用有通过Intent、PendingIntent、系统服务、Runtime等方法。本专题为大家提供Android相关的文章、下载、课程内容,供大家免费下载体验。

267

2023.10.18

Android语音播放功能实现方法
Android语音播放功能实现方法

实现方法有使用MediaPlayer实现、使用SoundPool实现两种。可以根据具体的需求选择适合的方法进行实现。想了解更多语音播放的相关内容,可以阅读本专题下面的文章。

343

2024.03.01

Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

61

2026.01.14

php与html混编教程大全
php与html混编教程大全

本专题整合了php和html混编相关教程,阅读专题下面的文章了解更多详细内容。

31

2026.01.13

PHP 高性能
PHP 高性能

本专题整合了PHP高性能相关教程大全,阅读专题下面的文章了解更多详细内容。

72

2026.01.13

MySQL数据库报错常见问题及解决方法大全
MySQL数据库报错常见问题及解决方法大全

本专题整合了MySQL数据库报错常见问题及解决方法,阅读专题下面的文章了解更多详细内容。

20

2026.01.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Excel 教程
Excel 教程

共162课时 | 11.9万人学习

Java 教程
Java 教程

共578课时 | 46.4万人学习

Uniapp从零开始实现新闻资讯应用
Uniapp从零开始实现新闻资讯应用

共64课时 | 6.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号