来源
:Kranky Geek WebRTC 2022

主讲人
:Dan Gunnarsson,Arman Jivanyan

内容整理
:张一炜

Kranky Geek 是一个关于如何使用 WebRTC 构建实时通信应用的免费开发者大会,成立七年以来,该大会致力于帮助开发者将实时音视频纳入应用。本文介绍 Kranky Geek WebRTC 2022 秋季大会的 3-4 节(共 10 节)内容。
相关系列文章:
目录
  • Google 会议中的 AI 技术
    • web 上部署机器学习方法
    • 视频会议中的机器学习部署
    • 视频会议中的背景模糊与亮度调整
  • 浏览器中执行实时音频机器学习应用
    • krisp 音频 SDK
    • 网页端部署存在的挑战
    • 网页端 Krisp SDK 架构

Google 会议中的 AI 技术

web 上部署机器学习方法

在浏览器上使用机器学习会存在一些额外的性能上的挑战,包括如何在浏览器内部运行,并确保在各种不同的终端设备上实时运行。另一方面,在视频会议场景下,同样还需要确保能够实时运行,即达到 30 fps(每一帧 33 ms 的处理时间)。
在 google meet 中,最初的原型可以在一台 macbook pro 上达到 60 ms 每帧的处理速度。后续的改进主要在于使用 WASM SIMD 的单指令多数据方式来达到 2 倍的加速,并进一步减小模型的大小并确保能够实时呈现高清晰度高分辨率的画面。
在 google meet 中,实际采用的部署方案为 Meidapipe。Mediapipe 是一个跨平台的机器学习解决方案。Mediapipen 能够搭建世界级的定制化端侧机器学习解决方案和应用。并且已经在 mediapipe.dev 中开源。Mediapipe 也广泛应用在 google 的各种产品和研究的机器学习解决方案中。
Mediapipe 具有以下特性:
  • 模块化,可重复使用和定制。包含了常见的机器学习流程和模块的接口。
  • 设计用于媒体以及传感器等的流数据。内部包含了对针对时间序列数据流的同步支持(视频、音频)。
  • 对通用硬件的加速支持。对机器学习部分以及非机器学习部分都进行了端到端的硬件加速以实现最好的性能。
  • 搭建一次即可在不同的设备部署。已对移动端、网页端、物联网设备、桌面PC以及服务器进行了配置优化和部署。
Meidapipe 中已经包含了目前常见的一些机器学习应用的示例,包括了分割、人脸网格、3D 姿态识别以及目标检测和跟踪等。可以在 mediapipe 的网页介绍中进行查看。
Mediapipe 示例应用

视频会议中的机器学习部署

在 google meet 中的将机器学习集成到其中的部署流程如下图所示。所有的处理都在发送端进行,将摄像头拍摄到的内容送入到处理模块中进行处理,并可以把处理后的结果发送给使用者。随后视频流经过编码传输到云端,经由 WebRTC 等协议进行分发到接收端进行解码观看。一些 AR 特效等保存在云端,用户需要的时候可以从云端下载到处理模块中。
视频会议中的机器学习部署

视频会议中的背景模糊与亮度调整

视频会议中去除背景是一个很重要的特性。在 google meet 中,这一功能也可以在浏览器上实现。另一方面,也存在部分参会者所在的场景光线不足的情况,这也导致视频会议中无法清晰的看到人像,并带来了技术上的挑战。
在 goole meet 中,同样采用了 Mediapipe 来进行部署。为了确保跨平台的使用以及实时处理的性能,使用了 WASM 的移动端版本,并通过 XNNPACK 来进行推理。为了进行背景模糊,整个流程中需要包含一个分割模型来得到一个前景的分割 mask,并通过 rendering 模块来进行细化。整个流程如下图所示。
基于 Mediapipe 的视频会议背景模糊
在 rendering 模块中,通过联合双边滤波进行上采样,并使用具有不同卷积核的 1D 可分离卷积来对背景进行非均匀模糊处理,以实现平滑和均匀的模糊效果。最后在背景替换中还通过使用 light wrap 来取代一些光晕以实现更好的视觉效果。
在模型推理的加速方面,google meet 使用了稀疏性来进行 CPU 上的推理加速。主要的原理是通过促使部分模型权重为 0 来实现,并使用 XNNPACK WASM 来优化稀疏卷积,这种方式能够使得模型的大小减小 25%,推理速度提高 25%。
对于低光场景下的人脸无法看清的情况,google meet 中包含了一个光线调整模块来调整前景的亮度。在检测到人脸处亮度较低时,通过利用分割 mask,将曝光计算限制在前景分割的范围内来提高前景人像的亮度。整个流程分为了两个阶段,首先计算前景和背景的曝光直方图,并基于前景曝光计算应用全局对比度曲线;最后在 CPU 上计算色调曲线,并通过 Web GL 应用曝光调整。
最后,演讲者也介绍了在基于 Mediapipe 使用这些技术时的 CPU 功耗和负载情况,如下图所示。光照调整对于 CPU 负载的增加很少,而使用背景模糊时的计算量更大一些,CPU 的功耗会增加 5W 左右,CPU 的负载也大约提高了 10%。
不同场景下的 CPU 功耗与负载
演讲者也展示了 google meet 中的背景模糊与亮度调整的效果,从示例中可以看出该方案在不同的光照和场景下都可以有效的区分出前景与背景,并对背景进行平滑均匀的模糊处理。并且,在光照调整方面,该方法也可以在不同场景下实现较好的效果,并正确保留前景的色调信息。
附上演讲视频:

浏览器中执行实时音频机器学习应用

krisp 音频 SDK

Krisp 的音频 SDK 包括了音频去噪、行为检测、背景音消除的功能。目前 Krisp 的 SDK 已经可以在各种设备和平台上进行部署,但目前还存在的挑战是在网页端还不可用。
在网页端部署的挑战主要在于不能直接运行 C++ 实现的应用,不能使用较大的模型权重文件,以及视频中每一帧的音频 Sample 数量都是固定的 128 的问题。

网页端部署存在的挑战

对于在网页端使用由 C++ 编写的程序,一个成熟的解决方案是使用 WebAssembly(WASM) 来实现,如下图所示。WASM 是一种二进制指令格式,可以将 C++ 或其他代码编译成 WASM,并实现在浏览器中运行。而将 C++ 编译成 WASM 则是通过使用 Emscripten 来实现。Emscripten 是一个完整的 WebAssembly 的编译器工具链,专注于速度、大小和并适配于的网络平台
在网页端运行 C++ 应用
由于考虑到在网页端和移动设备的使用需求,网页端不能使用较大的模型权重文件。因此在 Krisp SDK 中,其桌面端版本使用正常的模型,大小在 30~40MB 左右,而网页端则使用小模型,其大小在 2~6MB 左右。
另一方面,由于在于 web 端的音频每帧有 128 个 sample。在 web 中,音频输入和输出是以帧为单位的,每一帧由 128 个音频 sample 组成。而音频的采样率决定了在每秒会收到多少个样本,这个数值取决于所用的设备。根据采样率和采样数计算持续时间很简单,假设当前的采样率是 44100,则可以得到每一帧音频的时间为 128/44100=2.902ms。
而在浏览器与 128 个音频 sample 通信时,需要至少 10 ms 长度的音频来处理。Krisp SDK 采用的解决方案为使用两个 buffer 来进行处理,如下图所示。首先由第一个 buffer 收集从浏览器提供的每帧的 128 个 sample,并直到这些音频数据达到能够播放 10 ms 的长度后,送入到 Krisp SDK 中进行处理。随后处理完成的 10 ms 的音频输入到第二个 buffer 中,并将其分割成 128 块,构成浏览器播放所需要的 128 个 sample,最后在输入到浏览器中进行播放。
Krisp SDK 音频处理流程

网页端 Krisp SDK 架构

在 Java script 版本的 Krisp SDK 中,其关键模块主要包括了 C++ 部分与 JS 部分其架构图如下所示。
  • C++处理模块
    • XNNPACK:为 WebAssembly 平台优化的 BLAS(基本线性代数子程序)库
    • Emscripten 编译器(编译 WASM 模块)
    • C++ 端的缓冲系统(处理浏览器的 128 个样本数)
  • JS 模块
    • 网络音频 Api,与 WASM 模块一起工作
最初版本简化架构图
该架构中仍然存在一定的缺陷。使用 WASM 的缓冲系统增加了额外的中间件,存在丢失音频数据块的风险。并且该架构中可能存在多个内存泄漏问题,如终止 AudioWorkletNode 时,以及处理采样率变化(设备变化)时。并且只能通过在客户端提供静态 URL 的方式分别提供权重文件。
因此,在后续的改进版本中尝试解决这些问题,改进后的架构图如下所示。新的架构中将所有的缓冲区移到了 JS 端,这样 SDK 就能以预期的形式接收数据,以及将所有的音频处理转移到一个新的 web worker 线程中。对 C++ 端,则使用 1tol 方法绑定以赋予 JS 端更多的灵活性。另外,修改了加载权重的方式,使用 emscripten.data 文件;增加了会话 Ids,与 web worker 一起可以同时运行多个噪声处理器。最后,为了方便起见,也将 git 子模块移至 conan 包中。
改进后的架构
改进后的架构将所有的缓冲过程放入到了一个 JS 实现的 web worker 线程中,关闭 worker 时可以关闭其中的所有运行内容。这也解决了最初版本无法完全关闭存在内存泄漏的问题。新的架构可以针对不同的设备进行处理,并能够同时并行运行多个实例。
在后续的改进空间方面,主要集中减少 POST 信息的数量。这可以通过使用 SharedArrayBuffer 来实现,但它有一些安全问题,而且需要用户设置一些特定的头文件来工作。演讲者表示目前正试图通过缓冲系统来减少 POST 信息的数量。
附上演讲视频:
继续阅读
阅读原文