Discover built-in sound classification in SoundAnalysis
Machine Learning & AI 进阶 22m

发现 SoundAnalysis 中的内置声音分类

Discover built-in sound classification in SoundAnalysis

2021年6月10日

在 Apple 官方观看视频

一句话判断

SoundAnalysis 框架现在内置了一个预训练的声音分类器——不需要你自己训练模型,300+ 种日常声音的识别开箱即用,延迟低到可以实时运行。

这场 Session 讲了什么

SoundAnalysis 框架在 iOS 15 中获得了一个重大更新:内置的声音分类器(Built-in Sound Classifier)。之前要用 SoundAnalysis,你需要自己用 Create ML 训练一个模型,然后导入到 app 中。现在 Apple 提供了一个预训练好的模型,可以直接识别超过 300 种日常声音。

覆盖的声音类别非常广:人声(说话、笑声、哭泣)、环境音(雨声、风声、雷声)、动物叫声(狗叫、猫叫、鸟鸣)、乐器(钢琴、吉他、鼓)、交通工具(汽车、火车、飞机)、警报声(火警、警笛、闹钟)等。

使用方式极其简单。你只需要创建一个 SNAudioStreamAnalyzer,然后添加一个 SNClassifySoundRequest,设置好回调就能开始接收分类结果。整个流程不需要一行 Core ML 代码。

值得深挖的点

实时分析的能耗与精度平衡

内置分类器支持两种精度模式:SNClassifySoundRequest 默认使用标准精度,在 Apple Neural Engine 上运行,功耗非常低。如果你需要更高的精度(比如区分不同类型的乐器),可以使用自定义 Core ML 模型替代内置分类器。

实时分析的推荐缓冲区大小是 1.5 秒,每次分析间隔 0.5 秒。这意味着延迟大约 1.5 秒,对于大多数应用场景足够了。但如果你需要更低延迟(比如节拍检测),需要自定义分析管线。

隐私敏感的使用场景

声音分类能力很强,但也意味着隐私风险。Session 特别强调:你的 app 在使用麦克风录音进行声音分类之前,必须获得用户的明确授权(AVAudioApplication.shared.requestRecordPermission)。如果你的 app 在后台持续监听声音,需要在 Info.plist 中声明 audio 后台模式,并且向用户解释为什么需要这个权限。

代码片段

// 使用内置声音分类器进行实时识别
import SoundAnalysis

class SoundClassifier: NSObject, SNResultsObserving {
    let audioEngine = AVAudioEngine()
    var analyzer: SNAudioStreamAnalyzer?
    
    func startListening() {
        let audioSession = AVAudioSession.sharedInstance()
        try? audioSession.setCategory(.record, mode: .measurement)
        try? audioSession.setActive(true)
        
        let inputNode = audioEngine.inputNode
        let format = inputNode.outputFormat(forBus: 0)
        
        analyzer = SNAudioStreamAnalyzer(format: format)
        
        // 创建内置分类请求
        let request = try! SNClassifySoundRequest()
        request.windowDuration = CMTime(seconds: 1.5, preferredTimescale: 44100)
        request.overlapFactor = 0.5  // 50% 重叠,提高检测灵敏度
        
        try! analyzer?.add(request, withObserver: self)
        
        // 安装音频处理节点
        inputNode.installTap(onBus: 0, bufferSize: 8192, format: format) { 
            [weak self] buffer, time in
            self?.analyzer?.analyze(buffer, atAudioFramePosition: time.sampleTime)
        }
        
        try? audioEngine.start()
    }
    
    // SNResultsObserving 回调
    func request(_ request: SNRequest, didProduce result: SNResult) {
        guard let classificationResult = result as? SNClassificationResult else { return }
        
        // 获取置信度最高的三个分类
        let topResults = classificationResult.classifications
            .filter { $0.confidence > 0.5 }
            .prefix(3)
        
        for classification in topResults {
            print("识别到: \(classification.identifier), 置信度: \(classification.confidence)")
        }
    }
}
// 分析音频文件中的声音(非实时)
func classifyAudioFile(url: URL) {
    let request = try! SNClassifySoundRequest()
    
    SNClassifySoundRequest.classifySound(
        at: url,
        with: request
    ) { result in
        switch result {
        case .success(let classificationResult):
            // 打印所有时间段的分类结果
            for interval in classificationResult.classificationsByTime {
                print("时间段: \(interval.timeRange)")
                for classification in interval.classifications.prefix(3) {
                    print("  \(classification.identifier): \(classification.confidence)")
                }
            }
        case .failure(let error):
            print("分析失败: \(error)")
        }
    }
}

最佳实践

不要在后台持续运行声音分类器而不告诉用户。如果你的 app 需要后台监听(比如婴儿哭声检测),在 UI 上必须显示一个持续的指示器,告诉用户麦克风正在工作。Apple 的审核对这类 app 的隐私审查非常严格。

对于需要识别特定声音的场景(比如只关心「警笛声」),在回调中过滤 confidence > 0.6 的结果,避免误报。内置分类器在安静环境下准确率很高,但在嘈杂环境中会有明显的误分类。

还有什么值得关注

  • 内置分类器支持离线运行,不需要网络连接。
  • 如果内置的 300+ 种类别不满足需求,可以用 Create ML 训练自定义声音分类模型,然后通过 SNClassifySoundRequest(mlModel:) 加载。
  • SNResultsObserving 的回调不在主线程,UI 更新需要手动 DispatchQueue.main.async
WWDC 2021