Build an Action Classifier with Create ML
Machine Learning & AI 入门 26m

用 Create ML 构建动作分类器

Build an Action Classifier with Create ML

2020年6月24日

在 Apple 官方观看视频

一句话判断

Create ML 的动作分类器模板让没有机器学习背景的开发者也能训练出识别健身动作、手势等身体动作的模型——你只需要准备视频数据,剩下的交给 Create ML。

这场 Session 讲了什么

Create ML 在 2020 年新增了 Action Classification(动作分类)模板。它基于 Vision framework 的 Body Pose Estimation(身体姿态估计)提取视频中的骨骼关键点,然后用这些关键点训练一个分类模型。

工作流程分三步:第一步,准备训练数据——多段标注了动作类型的视频(如”深蹲”、“跳跃”、“俯卧撑”);第二步,在 Create ML 中配置训练参数(如动作窗口大小、验证集比例),点击训练;第三步,导出 Core ML 模型文件,在 App 中通过 Vision framework 使用。

Session 还介绍了如何提高模型质量:数据增强(镜像翻转)、调整动作窗口大小(短动作用小窗口、长动作用大窗口)、以及如何评估模型的混淆矩阵。

值得深挖的点

为什么用骨骼关键点而不是直接用视频帧。 直接从视频帧训练分类模型需要大量数据,且容易受到背景、衣着、光照等无关因素的干扰。骨骼关键点(17 个身体关节的 2D 坐标)是更高层次的特征表示,数据量需求小、泛化能力强。一个动作通常只需要几十个样本视频就能训练出不错的模型。

动作窗口大小的选择。 分类器不是对单帧做判断,而是对一段连续帧的序列做判断。“窗口大小”决定了模型看多长的时间序列。深蹲这种慢动作需要较大的窗口(如 60 帧),而拍手这种快动作用小窗口(如 20 帧)效果更好。

代码片段

import Vision
import CoreML

// 使用训练好的动作分类模型
class ActionClassifier {
    private var requests: [VNRequest] = []
    
    func setup() {
        // 加载 Core ML 模型
        guard let model = try? VNCoreMLModel(for: MyActionClassifier().model) else { return }
        
        let request = VNCoreMLRequest(model: model) { request, error in
            guard let results = request.results as? [VNClassificationObservation] else { return }
            
            // 获取分类结果
            if let topResult = results.first {
                print("识别到动作: \(topResult.identifier),置信度: \(topResult.confidence)")
                // 在 UI 上更新动作标签
            }
        }
        requests = [request]
    }
}
// 处理视频帧序列
class VideoActionProcessor {
    let sequenceRequestHandler = VNSequenceRequestHandler()
    
    func processFrame(_ sampleBuffer: CMSampleBuffer) {
        guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }
        
        // 先检测身体姿态
        let poseRequest = VNDetectHumanBodyPoseRequest { request, error in
            guard let observations = request.results as? [VNHumanBodyPoseObservation] else { return }
            
            // 将关键点传给动作分类器
            for observation in observations {
                do {
                    let keypoints = try observation.recognizedPoints(.all)
                    // 处理关键点序列...
                } catch {
                    print("获取关键点失败: \(error)")
                }
            }
        }
        
        try? sequenceRequestHandler.perform([poseRequest], on: pixelBuffer)
    }
}
// 实时处理摄像头画面中的动作
struct CameraView: UIViewRepresentable {
    func makeUIView(context: Context) -> UIView {
        let view = UIView()
        // 设置 AVCaptureSession...
        return view
    }
    
    func updateUIView(_ uiView: UIView, context: Context) {}
}

// 在 SwiftUI 中展示动作识别结果
struct WorkoutView: View {
    @State var currentAction = "等待检测..."
    @State var confidence: Float = 0
    
    var body: some View {
        VStack {
            CameraView()
                .frame(maxWidth: .infinity, maxHeight: .infinity)
            
            VStack(spacing: 8) {
                Text(currentAction)
                    .font(.title2)
                    .bold()
                Text("置信度: \(Int(confidence * 100))%")
                    .foregroundColor(.secondary)
            }
            .padding()
        }
    }
}

最佳实践

  • 每个动作类型至少 30 个样本视频。 样本太少模型容易过拟合,太多则训练时间过长。
  • 样本中包含不同的人。 如果所有样本都是同一个人,模型可能无法泛化到其他用户。
  • 调整动作窗口匹配实际动作时长。 窗口太小会丢失动作信息,太大可能混入相邻动作的帧。
  • 用 Create ML 的评估面板检查混淆矩阵。 如果两个动作经常被混淆,考虑增加更多区分度高的样本。

还有什么值得关注

  • Create ML 的动作分类器支持导出为 Core ML 格式,兼容所有 Apple 平台
  • 训练过程中可以实时预览模型在验证集上的表现
  • Vision 的 Body Pose Estimation 最多检测 19 个身体关键点
  • 配合 ARKit 可以在增强现实中叠加动作反馈
WWDC 2020