大多数浏览器和
Developer App 均支持流媒体播放。
-
用 Create ML 构建 Action Classifier
了解如何在 Create ML 中构建动作分类模型。使用自定义动作分类器,你的 app 可以从视频中或通过相机实时识别肢体运动。我们将向你展示如何使用示例轻松地训练 Core ML 模型,从而识别人类的动作,如跳跃、下蹲和舞蹈动作。 了解这是如何由计算机视觉框架内的身体位姿预测功能驱动的。你可以获取灵感,从而开发能够提供常规健身指导和对运动形式进行反馈等功能的app。要想充分利用此会议,建议先熟悉 “介绍Create ML app”。你也可以通过观看 “在 Creat ML 中构建健身运动分类模型”从而区分动作分类和基于传感器的健身记录分类。 要想进一步了解更多有关实现动作分类功能的相关技术的信息,记得查看 “使用计算机视觉技术检测肢体和双手位姿”,同时,你也可以观看 “探索 Action & Vision app”了解我们如何结合分类功能与其他技术,从而创建我们自己的示例应用程序。
资源
相关视频
WWDC22
WWDC21
WWDC20
WWDC19
-
下载
(你好) (2020 全球开发者大会) 你好 欢迎参加全球开发者大会 (用 CREATE ML 构建 ACTION CLASSIFIER) 我叫 Yuxin 是一名 Create ML 团队的工程师 今天我很高兴将与我的同事 Alex 为你介绍一个新模板 Create ML 中的 Action Classification (ACTIVITY CLASSIFICATION) 我们在去年引入了 Activity Classification 它允许你使用动态数据创建分类器
但如果你想用它分类视频中的动作呢? 如今相机无处不在 而用手机录制自己的视频变得如此简单 不管我们是在健身房还是在家 自我指导的体能训练总能让我们心情愉快
其他活动 例如体操 揭示了人体运动的复杂性 对这些动作的自动理解 有助于运动员的训练和比赛
今年 我们创建了 Action Classification 来学习人体姿势 看看这个美妙舞蹈的一系列动作 识别这些动作 甚至围绕这些动作构建一个娱乐 app 将会很有趣
那么 Action Classification 是什么? (Action Classification 是什么?) 首先 它是一个标准的分类任务 目标是从预定义类的列表中 分配一个动作标签
今年 该模型由 Vision 的 人体姿势估计支持
因此 它最适用于人体动作 而不是动物或物体的动作
要识别一个延续一段时间的动作 仅凭一个图像是不够的
相反 预测发生在由一系列帧 组成的时间窗口中
对于相机或视频流 可以连续地逐窗口进行预测
更多了解 Vision 的关于姿势的详情 请查看我们的“身体和手部姿势估计”视频
现在 让我们看看借助 Create ML 是如何运作的 (运作方式) 假设我们想创建一个健身分类器 来识别一个人的体能训练程序 比如开合跳、弓箭步、深蹲等
首先 我需要为每个类准备一些视频短片 然后启动 Create ML 进行训练
最后保存 Fitness Classifier 模型 构建我们的健身训练 app
现在 让我们深入到每个步骤 我的同事 Alex 将先讨论关于 Action Classification 的数据和训练
谢谢你 Yuxin 因为我现在不能去上健身课 所以一个可以响应我锻炼方式的锻炼 app 似乎是保持健康的好方法 我叫 Alex 我是一名 Create ML 团队的工程师 (在 CREATE ML 中训练 ACTION CLASSIFIER) 今天我将向你展示如何捕捉动作视频 并使用 Create ML app 训练新的 Action Classifier 模型 让我们从捕捉视频上的动作开始 我们希望模型能辨别我们什么时候锻炼 以及我们在做什么运动 我们需要分别收集这五项训练的视频 开合跳、深蹲以及其他三项 (捕捉动作) 每个视频应只包含一种动作类型 并且只有一个人类主体 拍完视频后 如果在视频的开始或结束时有额外的动作 你可能需要在照片 app 中修剪掉它们
我们用全身来识别动作 因此确保相机可以在整个运动范围内 拍摄到手臂和腿 你可能需要往后站一点 (数据源) 现在 创建一个文件夹来保存每个动作类型 文件夹名称 是模型将对此类动作进行预测的标签 (命名文件夹中的单项动作视频) 如果你收集了一些 休息、拉伸和坐下的示例 你可以把这些 放在一个叫做“其他”的文件夹里
我们现在可以训练了 但我想花点时间考虑一下 如果我们有不同类型的数据该怎么办 (蒙太奇视频) 也许是别人准备的视频 或者是我们从网上下载的视频 在这种情况下 我们就有了一个蒙太奇 在蒙太奇中 一个视频包含我们需要的多个不同动作 以及标题、定场镜头或者人物仅仅在休息 (使用蒙太奇视频) 按顺序看这段视频 我们会看到一段没有动作的时间 其中混杂着我们想要训练的特定动作 我们有两个选择 我们可以使用视频编辑软件 将视频剪辑或拆分为我们需要的动作 然后像刚才一样将它们放入文件夹
或者我们可以在视频中 找到动作开始和停止的时间 并以 CSV 或 JSON 格式 将其记录在注释文件中 这里有一个例子
你可以 在 developer.apple.com 上的 Create ML Documentation 中了解更多
不过 我们先把这个放在一边 继续看我们已经准备好的锻炼录像
我将在我的 Mac 上 启动 Create ML app
如果你在使用 Mac OS Big Sur 它有一个新模板 Action Classification
让我们为锻炼模型 创建一个 Action Classification 项目
我们给它取个合适的名字
我将添加一个描述 这样我就可以在以后识别它
我们的 Action Classification 项目 将在 Model Source Settings 页上打开 我们要在此处为训练做准备 通过添加我们捕捉的数据 并对训练过程做出一些决定
我们需要将已经准备好的视频文件夹 拖动到训练数据源中 我们现在来看一下
我已经将所有的视频 收集到了“训练”文件夹中 该文件夹中有为我们要训练的每个动作 命名的子文件夹
让我们看看“开合跳”文件夹 里面包含了所有的开合跳视频
让我们把“训练”文件夹拖到训练数据井中
Create ML app 检查数据的正确格式 并告诉我们一些关于它的信息 上面显示我们录了七个类 那是五个运动项目加上两个负类 “其他”和“无”
它还显示我们录了 362 个视频 我们可以使用数据源视图进行深入研究
在这里我们可以看到 每个动作都有大约 50 个视频
这就是你在构建项目时应该瞄准的目标
数据输入信息的下面 是一些我们可以设置的参数 我想在这里谈两个参数 Action Duration 和 Augmentations
Action Duration 是一个非常重要的参数 它表示我们试图识别的动作的长度 如果我们在识别一个复杂的动作 比如舞步 它的时间需要足够长 才能捕捉整个动作 可能是十秒
但对于简短、重复的动作 比如我们的锻炼重复动作 我们应该把窗口设置为两秒钟左右
动作的长度 也称为预测窗口 实际上是以帧为单位测量的 因此 Create ML根据帧速率和动作时长 自动计算帧数为 60
Augmentations 是一种增强训练数据的方法 无需外出录制更多视频 只需将已有的视频 以表示真实场景的方式进行转换
如果我们所有的视频 都是在人物面朝左的情况下拍摄的 那么“水平翻转”会生成一个镜像视频 使模型在两个方向上都有更好的效果 我们来打开它
你会注意到另外两个可以添加数据的框 它们是 Validation 和 Testing 如果你有多余的数据来测试模型 现在可以将其添加到测试数据井中 Create ML 将在模型完成训练后 自动对其执行测试
机器学习技术老手 可能会选择自己的验证数据 但是 默认情况下 Create ML 会自动使用你的一些训练数据
让我们按一下“训练”按钮开始制作模型
当你的 Mac 正用视频 训练 Action Classifier 时 这个过程分为两部分 首先 进行特征提取 提取视频并计算出人体姿势 一旦完成 就可以训练模型了
特征提取是一项艰巨的任务 可能需要一段时间 那么让我们更深入一点 (特征提取) 利用 Vision API 的强大功能 我们可以查看视频的每一帧 并对身体上 18 个目标位置进行编码 包括手、腿、臀部、眼睛等
对于每个目标 记录 x 和 y 坐标 加上一个置信度 这些构成了我们用于训练的特征
我们回去看看进展如何
特征提取大约需要半个小时 我们并不想等待 所以我将停止这个训练过程 并打开一个项目 其中包含我们之前制作的模型
该模型已经完成了 用我们之前使用的相同数据的训练 我还添加了一些验证数据
你可以在训练和评估标签中看到最终报告
我们可以看到模型的性能 是如何随着时间的推移提高的 看起来 80 次迭代是一个合理的选择 这条线向上向右走然后变平 意味着训练已经达到了一个稳定的状态
我可以使用评估选标签查看每个类的表现 这允许我检查模型在我们想要识别的 每种动作中的表现是否相同 如果我们添加了验证或测试数据 你可以在这里看到结果
但我真正想看到的是模型的实际应用 让我们转到预览标签 我们可以在还没有用于培训的新视频上 试用这个模型 这是我昨天在花园里录制的
视频经过处理以找到姿势 然后模型将这些姿势分类为动作 现在 它正在对整个视频进行预先分类 但是当你制作自己的 app 时 如果处理的是实时视频 或想要快速响应的体验 你可以选择将其流式传输
让我们按“播放”查看检测了到什么
注意视频上的标签 当视频中的动作展开时 可以看到分类的变化
让我们再看一次
你可以看到这个姿势骨架叠映在视频上 我们可以把它关掉
或者可以只观看姿势骨架在黑暗中运动
我们可以在视频下方看见时间线 它将视频分成多个两秒窗口 还记得我们是什么时候选择它的吗? 它在下面显示了每个窗口的最佳预测 以及其他概率较低的预测
我想我们已经准备好用这个模型 来制作一个很棒的 app了 为此 我需要从项目中导出模型 我们可以在输出标签上执行此操作 在输出标签上 我们还可以看到有关模型的一些事实 包括尺寸 它是移动 app 的资源的一个重要考量 你可以了解支持此模型的操作系统版本
通过把图标拖动到查找器中保存模型
FitnessClassifier.MLmodel
现在我们可以将它分享给 Yuxin 她将向我们展示 如何构建一个很棒的 iOS 健身 app 现在 我们从 Alex 那里得到一个分类器 来驱动我们的健身训练 app (创建一个健身训练 App) 让我们先看看如何使用模型进行预测 (使用视频或相机流) 例如 我们想从相机或视频文件中 识别开合跳
(获取姿势) 然而 模型以姿势而不是视频作为输入 我们使用 Vision 的 API 提取姿势 VNDetectHumanBodyPoseRequest (从视频中获取姿势) 如果我们使用视频 URL VNVideoProcessor 可以处理整个视频的姿势请求 并且可以在一个完成处理程序中 获得每帧的姿势结果 (从图像中获取姿势) 或者 当使用相机流时 我们可以使用 VNImageRequestHandler 对每个捕获的图像执行相同的姿势请求 (做出预测) 无论我们如何从每一帧中获得姿势 我们都需要将它们作为模型输入 聚合到三维数组中的预测窗口中
这看起来很复杂 但是如果我们使用 Vision 方便的 keypointsMultiArray API 就不必处理细节
由于我们的健身模型的窗口大小是 60 我们可以简单地将 60 帧的姿势串联起来 形成一个预测窗口
备有这样一个窗口 它可以作为输入传递给我们的模型 最后 模型的输出结果包括 一个顶级预测动作名和一个置信度得分
现在让我们在 Xcode 中看看这些步骤
这是我们的健身训练 app 我们来打开它
这是我们刚刚 训练的 Fitness Classifier
此元数据页显示了相关的用户和模型信息 例如作者、描述、类标签名称 甚至层分布
预测页显示了 详细的模型输入和输出信息 例如所需的输入多数组维度 以及输出的名称和类型
现在让我们跳过另一个 app 逻辑 直接跳到模型预测
在我的预测器中 我首先初始化 Fitness Classifier 模型 以及 Vision 身体姿势请求 这个操作最好只做一次
由于模型以一个预测窗口作为输入 我还保留了一个窗口缓冲区 来保存过去两秒的最后 60 个姿势 六十 是我们用于训练的模型的预测窗口尺寸
当从相机接收到帧时 我们需要提取姿势
这包括调用 Vision API 和执行我们已经在幻灯片上 看到的姿势请求
在我们将提取的姿势势添加到窗口之前
记住 Action Classifier 只识别一个人 所以如果 Vision 检测到多人 我们需要实施一些人物选择逻辑 在这个 app 中 我仅仅根据他们的大小选择最主要的人 你也可以选择其他方式
现在 让我们将姿势添加到窗口
一旦窗口完整了 我们就可以开始预测 此 app 每半秒进行一次预测 但你可以根据自己的使用情况 决定不同的间隔或触发点 现在让我们继续做一个模型预测
为了准备模型输入 我需要使用 Vision 方便的 API keypointsMultiArray 将窗口中的每个姿势转换成一个多数组 如果没有检测到人 则只需输入 0
然后我们将 60 个这样的多数组 连接成一个数组 这就是我们的模型输入
最后 只要一行代码就可以进行预测
输出包括一个最高预测标签名 和代码字典中所有类的置信度 最后 不要忘记重置姿势窗口 这样一旦再次将其填充 我们就可以进行另一个预测了
这就是用 Action Classifier 进行预测的全部内容 现在让我们试试这个 app 看看它实际是如何工作的
今天我感觉体力格外好 我想挑战一下自己去做一些体能训练
让我们打开 app
然后按“开始”按钮开始体能训练
现在将我的姿势 从每一个传入的帧中提取出来 预测是连续做出的 如 app 底部所示 这就是我们的 Debugging View 置信度和标签 现在 让我开始 (开合跳 5 秒挑战) (进行中)
(完成)
我完成了一个五秒挑战 正如你所看到的 模型一识别出我的动作 计时器就开始计时 我一停下来 模型就将我的动作识别为“其他动作”类 并开始等待下一个挑战 弓箭步 我准备好了 (弓箭步 5 秒挑战) (进行中)
(完成)
我完成了弓箭步 但我还不急着进行下一个动作 我想休息一下 喝点水
一切都是互动的
而且我不用回去操作设备 这对居家锻炼而言非常方便 (深蹲 5 秒挑战)
最后 让我们来试试深蹲 (进行中)
(完成)
现在三项挑战都已经完成了 以下是我在每个挑战中花费的时间总结 今天运动量很大 (总结 开合跳 8.0 秒 弓箭步 9.0 秒 深蹲 8.0 秒) 现在我们已经介绍了如何 训练 Action Classifier 来进行预测 (最佳实践) 让我们邀请 Alex 回来 并以一些最佳实践结束本次视频 谢谢你 Yuxin 我喜欢这个 app 会等待我开始体能训练 我经常需要时间 来记住一项运动是如何进行的 或者是哪只胳膊或腿先动 创建这样的功能需要大量的数据 因此请确保从运动员、玩家和孩子 那里获得最佳表现 是他们让我们的视频更为生动
如果你的模型不断接收重复和变化 它将得到最好的训练 (数据收集) 早些时候 我确定了每一个我想要分类的运动 都有大约 50 个视频 你也应该在你的 app 中做到这一点 请确保用各种不同的人进行训练 他们将有不同的风格、能力和速度 这是你的模型需要识别的内容
如果你认为你的用户会经常移动 则考虑从侧面、背面以及正面捕捉动作
模型确实需要理解锻炼 但它也需要理解我们什么时候不锻炼 或完全不动 你可以创建两个额外的文件夹 一个用于走动和拉伸 另一个用于安静地坐着或什么都不做
(捕捉动作) 让我们考虑一下 如何为 Action Classifier 捕捉好的视频
拍摄的人所进行的任何动作 都可能被理解为拍摄对象在移动 所以我们用三脚架保持相机的稳定 或者让它固定在某个地方
姿势检测器 需要清楚地看到身体的各个部分 所以如果你的衣服与背景融为一体 它的效果就不会太好 飘逸的衣服则可能会 掩盖你试图检测到的动作
现在你知道如何为你的 Action Classifier 拍摄最好的视频了 Yuxin 你能告诉我们如何 在 Create ML 中充分利用训练吗?
当然可以 Alex 获得数据后 请花点时间配置训练参数 (选择训练参数) 一个关键参数是动作持续时间 以秒为单位 或预测窗口尺寸 即时间窗口中的帧数 长度应与视频中的动作长度匹配 请试着使所有动作有大致相同的时长
视频中的帧速率 会影响预测窗口的有效长度
因此 保持训练视频 和测试视频的平均帧速率一致 对于获得准确的结果是非常重要的 (在你的 APP 中使用模型) 在你的 app 中使用模型时 请确保只选择一个人 你的 app 可能会在检测到多人时 提醒用户只在视窗中保留一个人 或者你可以执行自己的选择逻辑 根据他们的大小 或在帧内的位置来选择一个人 这可以通过使用 姿势目标位置的坐标来实现
如果你想计算动作的重复次数 则可能需要为单个动作的单次重复 准备每个视频 当你在 app 中进行预测时 应找到一个可靠的触发点 在正确的时间开始预测 或者执行一些平滑逻辑 来正确地更新计数器
最后 你可以使用 Action Classifier 来评分或判断动作的质量 例如 与训练视频中的示例动作相比 你的 app 可以使用预测的置信值 来给动作的质量评分 (来跳舞吧!) 这就是 Create ML 中的 Action Classification (向前滑动) 我们迫不及待地想看到你将用它创建出 什么样惊人的 app (锁颚舞) 感谢你观看我们的视频 请享受全球开发者大会的其余内容
-
-
5:28 - Working with montage videos
[ { "file_name": "Montage1.mov", "label": "Squats", "start_time": 4.5, "end_time": 8 } ]
-
14:05 - Getting poses
import Vision let request = VNDetectHumanBodyPoseRequest()
-
14:10 - Getting poses from a video
import Vision let videoURL = URL(fileURLWithPath: "your-video-file.MOV") let startTime = CMTime.zero let endTime = CMTime.indefinite let request = VNDetectHumanBodyPoseRequest(completionHandler: { request, error in let poses = request.results as! [VNRecognizedPointsObservation] }) let processor = VNVideoProcessor(url: videoURL) try processor.add(request) try processor.analyze(with: CMTimeRange(start: startTime, end: endTime))
-
14:26 - Getting poses from an image
import Vision let request = VNDetectHumanBodyPoseRequest() // Use either one from image URL, CVPixelBuffer, CMSampleBuffer, CGImage, CIImage, etc. in image request handler, based on the context. let handler = VNImageRequestHandler(url: URL(fileURLWithPath: "your-image.jpg")) try handler.perform([request]) let poses = request.results as! [VNRecognizedPointsObservation]
-
14:57 - Making a prediction
import Vision import CoreML // Assume pose1, pose2, ..., have been obtained from a video file or camera stream. let pose1: VNRecognizedPointsObservation let pose2: VNRecognizedPointsObservation // ... // Get a [1, 3, 18] dimension multi-array for each frame let poseArray1 = try pose1.keypointsMultiArray() let poseArray2 = try pose2.keypointsMultiArray() // ... // Get a [60, 3, 18] dimension prediction window from 60 frames let modelInput = MLMultiArray(concatenating: [poseArray1, poseArray2], axis: 0, dataType: .float)
-
16:27 - Demo: Building the app in Xcode
import Foundation import CoreML import Vision @available(iOS 14.0, *) class Predictor { /// Fitness classifier model. let fitnessClassifier = FitnessClassifier() /// Vision body pose request. let humanBodyPoseRequest = VNDetectHumanBodyPoseRequest() /// A rotation window to save the last 60 poses from past 2 seconds. var posesWindow: [VNRecognizedPointsObservation?] = [] init() { posesWindow.reserveCapacity(predictionWindowSize) } /// Extracts poses from a frame. func processFrame(_ samplebuffer: CMSampleBuffer) throws -> [VNRecognizedPointsObservation] { // Perform Vision body pose request let framePoses = extractPoses(from: samplebuffer) // Select the most promiment person. let pose = try selectMostProminentPerson(from: framePoses) // Add the pose to window posesWindow.append(pose) return framePoses } // Make a prediction when window is full, periodically var isReadyToMakePrediction: Bool { posesWindow.count == predictionWindowSize } /// Make a model prediction on a window. func makePrediction() throws -> PredictionOutput { // Prepare model input: convert each pose to a multi-array, and concatenate multi-arrays. let poseMultiArrays: [MLMultiArray] = try posesWindow.map { person in guard let person = person else { // Pad 0s when no person detected. return zeroPaddedMultiArray() } return try person.keypointsMultiArray() } let modelInput = MLMultiArray(concatenating: poseMultiArrays, axis: 0, dataType: .float) // Perform prediction let predictions = try fitnessClassifier.prediction(poses: modelInput) // Reset poses window posesWindow.removeFirst(predictionInterval) return ( label: predictions.label, confidence: predictions.labelProbabilities[predictions.label]! ) } }
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。