”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 适用于您的实时应用程序的 Supersonic GPU MelSpectrogram

适用于您的实时应用程序的 Supersonic GPU MelSpectrogram

发布于2024-11-08
浏览:607

Supersonic GPU MelSpectrogram for your real-time applications

在 Simli,我们最关心的是延迟。毕竟,这就是我们的目标:低延迟视频。另一方面,音频机器学习中一些最常用的算法的实现速度非常慢。需要明确的是,这些实现通常适合创建模型本身或批量推理。但对于 Simli 的我们来说,几毫秒就可能意味着视频是断断续续的混乱还是流畅。
对我来说幸运的是(以及作为读者的代理),本指南不需要太多数学知识,更聪明的人已经弄清楚如何获得正确的答案,我们只是让计算更加高效。如果您需要更多信息来了解 MelSpectrogram 到底是什么,您可以阅读这篇文章。计算频谱图的方法有多种,这在很大程度上取决于您的应用程序。因此,为了方便作者,我们将重点放在运行内部模型所需的梅尔上。

常见的解决方案:Librosa

您很可能是在遇到使用 Librosa 的存储库后来到这里的。老实说,这是一个非常方便的图书馆。有大量实用程序、读取磁盘上音频的简单方法以及快速访问许多常用功能(例如音频重采样、通道缩混等)。在我们的例子中,我们对一种特定的功能感兴趣:梅尔谱图计算。在 librosa 中,获取梅尔光谱图非常简单。

import librosa

# load in any audio to test
sampleAudio, sr = librosa.load("sample.mp3", sr=None) # sr=None means the original sampling rate
spectrogram = librosa.feature.melspectrogram(
    y=sampleAudio,
    sr=sr,
    n_fft=int(0.05 * sr),  # 50ms
    hop_length=int(0.0125 * sr),  # 12.5ms
    win_length=int(0.05 * sr),
)

很简单,在 GCP g2 虚拟机上平均需要 2 毫秒左右。嗯,主要有两个问题:

  1. 通常,在使用深度学习模型时,您需要在 GPU 上运行模型。这意味着链的一部分在 CPU 上运行,然后将结果复制回 GPU。对于批量推理,这基本上没问题,因为您应该收集 GPU/传输上能够容纳的尽可能多的数据。然而,在我们的例子中,我们经常一次处理一帧以减少等待和处理时间。
  2. 我们的总时间预算约为 33 毫秒/帧。这包括从 API 服务器到 ML 推理服务器的传输延迟、CPU 到 GPU 的复制、预处理和模型后处理(包括梅尔谱图)。当您的预算如此紧张时,每一毫秒都很重要。这两毫秒实际上有助于为 Simli 提供一个可工作的实时渲染视频流(当然,这是许多优化,每个优化都值得一两毫秒)。

网上寻找解决方案

在尝试了解其他人是如何做到这一点时(幸运的是,这对我们来说不是一个独特的问题),我发现这篇文章解释了梅尔谱图的工作原理,并提供了一个参考实现,由于某种原因,该实现仅花费了 1 毫秒(50 % 改进)。这是一个好的开始,但仍然存在第一个问题,并非所有内容都在 GPU 上。我们正在使用 PyTorch,并一直依赖 torch.compile 和 mode=reduce-overhead 来最大程度地提高速度。然而,像这样的数据传输可能会降低性能,因为 PyTorch 编译器也无法优化该函数。解决方案有点繁琐但是相对简单,用torch重写一下即可。 PyTorch 团队已确保其许多语法和功能尽可能接近 NumPy(一些边缘情况通常都有详细记录,除了让我迷失了几天的情况,但这是另一个博客的故事) .

PyTorch 重写

因此,为了成功重写 Pytorch 中的所有内容,我们需要执行几个步骤。梅尔谱图可以分为三个步骤:

  • 计算短时傅立叶变换
  • 生成梅尔标度频率库
  • 生成频谱图。

有好消息也有坏消息。好消息是所有必需的功能都可以在 pytorch 或 torchaudio 中轻松获得。坏消息是默认行为与 librosa 有很大不同,因此需要进行大量配置和反复试验才能使其正确。我经历过这些,我之所以分享这些信息,是因为我什至不希望我最大的敌人遭受这样的厄运。我们需要理解的一件事是,这段代码严重依赖于缓存一些结果以供以后使用。这是在预生成所有静态数组的初始化函数中完成的(例如,梅尔频率库取决于采样率和所需的梅尔数量)。这是我们使用 PyTorch 优化的 Melspectrogram 函数

import torch

if torch.cuda.is_available
    @torch.compile(mode="reduce-overhead")
else:
    @torch.compile
def melspecrogram_torch(wav:torch.Tensor,sample_rate:int, hann_window: torch.Tensor, mel_basis: torch.Tensor):
    stftWav = torch.stft(
            wav,
            n_fft=int(sample_rate*0.05),
            win_length=int(sample_rate*0.05),
            hop_length=int(sample_rate*0.0125),
            window=hann_window,
            pad_mode="constant",
            return_complex=True,
        ).abs()
    stftWav = stftWav.squeeze()
    mel_stftWav = torch.mm(mel_basis, stftWav)
    return mel_stftWav

device = "cuda" if torch.cuda.is_available() else "cpu"

melspectrogram_torch(
    sampleAudio,
    sr,
    torch.hann_window(int(sample_rate*0.05), device=device, dtype=torch.float32),
    torchaudio.functional.melscale_fbanks(
        sample_rate=sr,
        n_freqs=(int(sample_rate*0.05) // 2   1),
        norm="slaney", # this is the normalization algorithm used by librosa
        # this is an example that's related to our own pipeline, check what you need for yours
        n_mels=80,
        f_min=55,
        f_max=7600,
    )
    .T.to(device)
)

初始编译运行后,我们使用 Nvidia L4 GPU(缓存 hann_window 和 melscale_fbanks)测量该函数需要 350 微秒。调整后的调用将如下所示:

hann=torch.hann_window(int(sample_rate*0.05), device=device, dtype=torch.float32),
melscale=torchaudio.functional.melscale_fbanks(
        sample_rate=sr,
        n_freqs=(int(sample_rate*0.05) // 2   1),
        norm="slaney", # this is the normalization algorithm used by librosa
        # this is an example that's related to our own pipeline, check what you need for yours
        n_mels=80,
        f_min=55,
        f_max=7600,
    )
    .T.to(device)
melspectrogram_torch(
    sampleAudio,
    sr,
    hann,
    melscale,
)

这是关于我们如何优化部署的预训练模型、优化预处理和后处理步骤的一系列文章的一部分。您可以查看 https://www.simli.com/demo 查看已部署的模型以及我们提供的最低延迟的头像

版本声明 本文转载于:https://dev.to/simli_ai/supersonic-gpu-melspectrogram-for-your-real-time-applications-gg1?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 处理日期和时区转换:为什么正确的 UTC 转换很重要
    处理日期和时区转换:为什么正确的 UTC 转换很重要
    在检索选定日期范围内的数据时,我们注意到我们的计算存在一定偏差。然而,当我们将日期减少一天时,数据完全匹配! 嗯……我们的代码中处理日期的方式可能存在问题。也许时区处理不正确——是的,我是对的! 当构建涉及来自不同时区的用户的应用程序时,正确处理日期可能很棘手。在 UTC 中存储日期是确保一致性的...
    编程 发布于2024-11-08
  • gRPC:你住在哪里?你吃什么?
    gRPC:你住在哪里?你吃什么?
    A primeira vez que ouvi falar sobre RPC foi em uma aula de sistema distribuídos, ainda quando estava cursando a graduação em Ciência da Computação. Ac...
    编程 发布于2024-11-08
  • 如何为 3D 模型实现平滑的切线空间法线?
    如何为 3D 模型实现平滑的切线空间法线?
    如何实现平滑的切线空间法线修复由于切线、副法线的每面计算而导致的模型的多面外观,和法线向量,必须考虑模型预先提供的法线。每顶点法线平均第一种方法涉及计算每面法线和将其分布在形成面的顶点之间。每个顶点维护一个初始值为零的累加器向量,并且将面法线的 X、Y 和 Z 分量添加到每个涉及顶点的累加器中。此外...
    编程 发布于2024-11-08
  • 通过简单示例了解 JavaScript 中的调用、应用和绑定
    通过简单示例了解 JavaScript 中的调用、应用和绑定
    通过简单示例了解 JavaScript 中的调用、应用和绑定 使用 JavaScript 时,您可能会遇到三种强大的方法:调用、应用和绑定。这些方法用于控制函数中 this 的值,从而更轻松地处理对象。让我们通过简单的示例来分解每种方法,以了解它们的工作原理。 1....
    编程 发布于2024-11-08
  • 大括号放置对 JavaScript 执行有什么影响?
    大括号放置对 JavaScript 执行有什么影响?
    大括号放置和 JavaScript 执行在 JavaScript 中,大括号的放置可以显着改变代码的行为和输出。如提供的代码片段所示,大括号位置的单个更改可能会导致截然不同的结果。自动分号插入和未定义返回当左大括号时被放置在一个新行上,如第一个代码片段中一样,自动分号插入开始。这是 JavaScri...
    编程 发布于2024-11-08
  • 学习弹性搜索
    学习弹性搜索
    Elasticsearch 是一个基于 Apache Lucene 库构建的强大开源搜索和分析引擎。它旨在处理大量数据并有效执行复杂的搜索。 Elasticsearch 的主要特性和功能包括: 分布式架构:Elasticsearch是一个分布式系统,可以水平扩展以处理大量数据和流量。 近实时搜索:E...
    编程 发布于2024-11-08
  • 股息率:基于Python的金融项目的重要指标
    股息率:基于Python的金融项目的重要指标
    股息率:基于Python的金融项目的重要指标 在财务分析领域,股息对许多投资者来说非常重要。特别是如果您正在开发一个处理财务数据或自动化投资策略的Python项目,计算和分析股息率可能是一个关键要素。这篇关于股息率的 Rankia 文章详细解释了该利率的运作方式以及为什么它对投资者...
    编程 发布于2024-11-08
  • 如何通过并行或分布式测试在多个浏览器中执行WebUI功能文件?
    如何通过并行或分布式测试在多个浏览器中执行WebUI功能文件?
    使用并行或分布式测试在多个浏览器中执行 WebUI 功能文件使用并行测试对多个浏览器 (Zalenium) 执行 WebUI 功能文件运行器或分布式测试,使用以下方法:并行运行器和场景大纲:使用场景大纲创建一个表,其中的行代表不同的浏览器配置。向 Karate-config.js 文件添加并行运行器...
    编程 发布于2024-11-08
  • 如何使用 CSS 自定义文本下划线颜色?
    如何使用 CSS 自定义文本下划线颜色?
    使用 CSS 自定义文本下划线颜色在网页设计中,为文本添加下划线是强调或突出显示信息的常见做法。但是,如果您想通过更改下划线的颜色来添加独特的触感该怎么办?这可能吗?是的,可以使用 CSS 更改文本下方线条的颜色。您可以使用以下两种方法:方法 1:使用 text-decoration-color最直...
    编程 发布于2024-11-08
  • 在 JavaScript 中实现点击劫持防御技术
    在 JavaScript 中实现点击劫持防御技术
    点击劫持等复杂攻击的出现使安全成为当今网络世界的首要问题。通过欺骗消费者点击与他们最初看到的内容不同的内容,攻击者部署了一种名为“点击劫持”的邪恶方法,这可能会带来灾难性的后果。此类攻击有可能诱骗人们下载恶意软件、发送私人信息,甚至做他们无意的事情,例如购买任何东西。为了防止此类攻击,JavaScr...
    编程 发布于2024-11-08
  • 为什么我的浮动 Div 不调整后续 Div 的大小?
    为什么我的浮动 Div 不调整后续 Div 的大小?
    Float 不调整 Div 大小之谜当使用 CSS float 时,假设后续元素将左对齐而不是流到新的元素上线。然而,在某些情况下,例如提供的示例,下面的 div 继续跨越整个宽度,而不是从第一个 div 的右侧开始。为了理解这种行为,我们深入研究 float 的复杂性定位。当元素浮动时(在本例中为...
    编程 发布于2024-11-08
  • 使用 PYTHON 将数据导入 MYSQL
    使用 PYTHON 将数据导入 MYSQL
    介绍 手动将数据导入数据库,尤其是当数据库中有多个表时,不仅很烦人,而且还很耗时。通过使用 python 库可以使这变得更容易。 从kaggle下载绘画数据集。绘画数据集由 8 个 csv 文件组成,我们将使用简单的 python 脚本将其导入到数据库中,而不是手动将数据导入到数据...
    编程 发布于2024-11-08
  • MySQL 基本运算符及其应用
    MySQL 基本运算符及其应用
    MySQL 运算符是开发人员的关键工具,可实现精确的数据操作和分析。它们涵盖了一系列功能,包括赋值、数据比较和复杂模式匹配。无论您是处理 JSON 数据还是根据条件过滤记录,了解这些运算符对于高效的数据库管理都至关重要。 本指南介绍了最重要的MySQL运算符,并通过实际示例演示了如何使用它们,使开...
    编程 发布于2024-11-08
  • 如何测试 Cron 作业:完整指南
    如何测试 Cron 作业:完整指南
    Cron 作业在许多系统中对于调度任务、自动化流程和按指定时间间隔运行脚本至关重要。无论您是维护 Web 服务器、自动备份还是运行例行数据导入,cron 作业都能让您的操作顺利运行。但与任何自动化任务一样,它们必须经过彻底测试以确保可靠性和准确性。 在本文中,我们将探讨如何有效地测试 cron 作...
    编程 发布于2024-11-08
  • Next.js 中间件简介:它如何工作并提供示例
    Next.js 中间件简介:它如何工作并提供示例
    我们来谈谈Nextjs中的路由。今天,我们来谈谈最强大的事物中间件之一。 Nextjs 中的中间件提供了一种强大而灵活的方法来拦截来自服务器的请求并控制请求流(重定向、URL 重写)并全局增强身份验证、标头、cookie 持久性等功能。 创建中间件 让我们创建 Middleware ...
    编程 发布于2024-11-08

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3