AssemblyAI-博客中文翻译-二-

AssemblyAI 博客中文翻译(二)

原文:AssemblyAI Blog

协议:CC BY-NC-SA 4.0

如何使用 JavaScript 将语音转换成文本

原文:https://www.assemblyai.com/blog/voice-to-text-javascript/

本文展示了如何通过几行代码将麦克风录音中的实时语音识别集成到您的 JavaScript 应用程序中。

使用 AssemblyAI 在 JavaScript 中实现实时语音转文本

最简单的解决方案是一个语音转文本 API ,可以用每种编程语言的简单 HTTP 客户端访问它。最容易使用的 API 之一是 AssemblyAI,它不仅为音频文件提供传统的语音转录服务,还提供了一个实时语音识别端点,它可以在几百毫秒内通过 WebSockets 将转录文本传输给你。

在开始之前,我们需要获得一个有效的 API 密钥。您可以在此获得一个,并免费开始使用:

Get a free API Key

步骤 1:设置 HTML 代码和麦克风记录器

创建一个文件index.html并添加一些 HTML 元素来显示文本。为了使用麦克风,我们嵌入了 RecordRTC ,这是一个用于音频和视频录制的 JavaScript 库。

此外,我们嵌入了index.js,它将是处理前端部分的 JavaScript 文件。这是完整的 HTML 代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="./css/reset.css">
  <link rel="stylesheet" href="./css/styles.css"> 
</head>
<script src="https://www.WebRTC-Experiment.com/RecordRTC.js"></script>
<body>
  <header>
    <h1 class="header__title">Real-Time Transcription</h1>
    <p class="header__sub-title">Try AssemblyAI's new real-time transcription endpoint!</p>
  </header>
  <div class="real-time-interface">
    <p id="real-time-title" class="real-time-interface__title">Click start to begin recording!</p>
    <p id="button" class="real-time-interface__button">Start</p>
    <p id="message" class="real-time-interface__message"></p>
  </div>
  <script src="./js/index.js"></script>
</body>
</html> 

步骤 2:用 JavaScript 设置带有 WebSocket 连接的客户机

接下来,创建index.js并访问相应 HTML 文件的 DOM 元素。此外,我们使用全局变量来存储记录器、WebSocket 和记录状态。

// required dom elements
const buttonEl = document.getElementById('button');
const messageEl = document.getElementById('message');
const titleEl = document.getElementById('real-time-title');

// initial states and global variables
messageEl.style.display = 'none';
let isRecording = false;
let socket;
let recorder; 

然后我们只需要创建一个函数来处理所有的逻辑。每当用户点击按钮开始或停止录制时,都会执行该功能。我们切换记录状态,并为这两种状态实现一个 if-else 语句。

如果记录停止了,我们就停止记录器实例并关闭套接字。在关闭之前,我们还需要发送一个包含{terminate_session: true}的 JSON 消息:

const run = async () => {
  isRecording = !isRecording;
  buttonEl.innerText = isRecording ? 'Stop' : 'Record';
  titleEl.innerText = isRecording ? 'Click stop to end recording!' : 'Click start to begin recording!'

  if (!isRecording) { 

    if (recorder) {
      recorder.pauseRecording();
      recorder = null;
    }

    if (socket) {
      socket.send(JSON.stringify({terminate_session: true}));
      socket.close();
      socket = null;
    }

  } else {
    // TODO: setup websocket and handle events
  }
};

buttonEl.addEventListener('click', () => run()); 

然后我们需要实现录音开始时执行的else部分。为了不在客户端暴露 API 密钥,我们向后端发送一个请求并获取一个会话令牌。

然后我们建立一个与wss://api.assemblyai.com/v2/realtime/ws连接的 WebSocket。对于套接字,我们必须处理事件onmessageonerroroncloseonopen。在onmessage事件中,我们解析传入的消息数据,并设置相应 HTML 元素的内部文本。

onopen事件中,我们初始化 RecordRTC 实例,然后将音频数据作为 base64 编码的字符串发送。其他两个事件可用于关闭和重置套接字。这是else块的剩余代码:

// get session token from backend
const response = await fetch('http://localhost:8000');
const data = await response.json();

if(data.error){
    alert(data.error)
}

const { token } = data;

// establish wss with AssemblyAI at 16000 sample rate
socket = new WebSocket(`wss://api.assemblyai.com/v2/realtime/ws?sample_rate=16000&token=${token}`);

// handle incoming messages to display transcription to the DOM
const texts = {};
socket.onmessage = (message) => {
    let msg = '';
    const res = JSON.parse(message.data);
    texts[res.audio_start] = res.text;
    const keys = Object.keys(texts);
    keys.sort((a, b) => a - b);
    for (const key of keys) {
        if (texts[key]) {
            msg += ` ${texts[key]}`;
        }
    }
    messageEl.innerText = msg;
};

// handle error
socket.onerror = (event) => {
    console.error(event);
    socket.close();
}

// handle socket close
socket.onclose = event => {
    console.log(event);
    socket = null;
}

// handle socket open
socket.onopen = () => {
    // begin recording
    messageEl.style.display = '';
    navigator.mediaDevices.getUserMedia({ audio: true })
    .then((stream) => {
        recorder = new RecordRTC(stream, {
        type: 'audio',
        mimeType: 'audio/webm;codecs=pcm', // endpoint requires 16bit PCM audio
        recorderType: StereoAudioRecorder,
        timeSlice: 250, // set 250 ms intervals of data
        desiredSampRate: 16000,
        numberOfAudioChannels: 1, // real-time requires only one channel
        bufferSize: 4096,
        audioBitsPerSecond: 128000,
        ondataavailable: (blob) => {
            const reader = new FileReader();
            reader.onload = () => {
                const base64data = reader.result;

                // audio data must be sent as a base64 encoded string
                if (socket) {
                    socket.send(JSON.stringify({ audio_data: base64data.split('base64,')[1] }));
                }
            };
            reader.readAsDataURL(blob);
        },
    });

    recorder.startRecording();
    })
    .catch((err) => console.error(err));
}; 

步骤 3:用 Express.js 设置一个服务器来处理认证

最后,我们需要创建另一个文件server.js来处理认证。这里我们创建一个服务器,它有一个端点,通过向https://api.assemblyai.com/v2/realtime/token发送 POST 请求来创建一个临时认证令牌。

要使用它,我们必须安装 Express.jsAxioscors :

$ npm install express axios cors 

这是服务器部分的完整代码:

const express = require('express');
const axios = require('axios');
const cors = require('cors');

const app = express();
app.use(express.json());
app.use(cors());

app.get('/', async (req, res) => {
  try {
    const response = await axios.post('https://api.assemblyai.com/v2/realtime/token', 
      { expires_in: 3600 },
      { headers: { authorization: 'YOUR_TOKEN' } });
    const { data } = response;
    res.json(data);
  } catch (error) {
    const {response: {status, data}} = error;
    res.status(status).json(data);
  }
});

app.set('port', 8000);
const server = app.listen(app.get('port'), () => {
  console.log(`Server is running on port ${server.address().port}`);
}); 

每当记录开始时,后端的这个端点将向前端发送有效的会话令牌。就是这样!你可以在我们的 GitHub 库中找到完整的代码。

运行 JavaScript 文件进行实时语音识别

现在我们必须运行后端和前端部分。使用以下命令启动服务器

$ node server.js 

然后用服务包服务前端站点:

$ npm i --global serve
$ serve -l 3000 

现在你可以访问http://localhost:3000,开始语音记录,并看到实时转录在行动中!

什么是 BERT,它是如何工作的?

原文:https://www.assemblyai.com/blog/what-is-bert-and-how-does-it-work/

BERT 是一个通用的语言模型,可以很容易地针对许多语言任务进行微调。但是它是怎么把语言学得这么好的呢?什么是语言模型?而微调一个模型是什么意思?

我们在这个视频中学到了这些:

https://www.youtube.com/embed/6ahxPTLZxU8?feature=oembed

什么是 GPT-3,它是如何工作的?

原文:https://www.assemblyai.com/blog/what-is-gpt-3-and-how-does-it-work/

你可能听说过 GPT 3 号及其引人入胜的发展。但你知道 GPT 3 号为什么或如何给这么多人留下深刻印象吗?

在这个视频中,我们将了解为什么 GPT-3 如此独特,以及它如何设法帮助人工智能带来新的兴奋浪潮。我们也将简要地看看 GPT 3 号的引擎盖下,了解它的架构和一些潜在的危险。

立即观看:

https://www.youtube.com/embed/xB6hZwYsV2c?feature=oembed

什么是神经网络的梯度裁剪?

原文:https://www.assemblyai.com/blog/what-is-gradient-clipping-for-neural-networks/

不稳定梯度是神经网络的主要问题之一。当谈到递归神经网络时,由于它们的递归性质,我们需要一种不同的方法。

在这个视频中,我们将学习渐变剪辑,一种解决渐变爆炸问题的技术。

看这里:

https://www.youtube.com/embed/KrQp1TxTCUY?feature=oembed

什么是图层规范化?

原文:https://www.assemblyai.com/blog/what-is-layer-normalization/

您可能以前听说过批处理规范化。这是一个伟大的方式,使您的网络更快,更好,但有一些缺点批量规范化。这就是为什么研究人员提出了一种对批处理规范化的改进,称为层规范化。

在本视频中,我们将了解图层规范化的工作原理、它与批量规范化的比较以及它在什么情况下最有效。

看这里:

https://www.youtube.com/embed/2V3Uduw1zwQ?feature=oembed

什么是神经网络的权重初始化?

原文:https://www.assemblyai.com/blog/what-is-weight-initialization-for-neural-networks/

权重初始化,即使是一个小问题,也会对我们训练的深度前馈神经网络产生严重影响。

感谢 Xavier Glorot 和 Yoshua Bengio,我们意识到使用正态分布初始化平均值为 0、方差为 1 的权重会导致不稳定的梯度问题。这就是为什么提出了新技术来克服这些问题。

在这个视频中,我们了解这些技术是什么,它们之间有什么不同,以及它们的完美激活功能匹配是什么。

https://www.youtube.com/embed/tYFO434Lpm0?feature=oembed

为什么你应该(或不应该)在 2023 年使用谷歌的 JAX

原文:https://www.assemblyai.com/blog/why-you-should-or-shouldnt-be-using-jax-in-2022/

自从谷歌的 JAX 在 2018 年末亮相以来,它的受欢迎程度一直在稳步增长,这是有充分理由的。DeepMind 在 2020 年宣布,它正在使用 JAX 加速其研究,越来越多的出版物和项目从谷歌大脑和其他人都在使用 JAX。伴随着所有这些讨论,JAX 似乎是下一个大的深度学习框架,对吗?

不对。在这篇文章中,我们将阐明 JAX 是什么(不是),为什么你应该关心(或者不应该,但是你可能应该),以及你是否应该(或者不应该)使用它。

让我们开始吧!

建议说明

如果你已经熟悉 JAX,并且想跳过基准测试,你可以跳到我们关于何时使用它的建议

谷歌的 JAX 是什么?

也许最好从 JAX 是什么开始而不是。JAX 是不是深度学习框架或库,它本身也不是被设计成深度学习框架或库。总而言之, JAX 是一个高性能的数值计算库,它包含了可组合的函数转换[1。正如我们所见,深度学习只是 JAX 所能做的一小部分:

JAX lies at the intersection of Scientific Computing and Function Transformations, yielding a wide range of capability beyond the ability to train Deep Learning models

我为什么要关心 JAX?

简而言之-。这是 JAX 与任何用例相关的普遍方面。

让我们用 NumPy 和 JAX 对一个矩阵的前三次幂求和。首先是我们的 NumPy 实现:

`def fn(x):
  return x + x*x + x*x*x

x = np.random.randn(10000, 10000).astype(dtype='float32')
%timeit -n5 fn(x)` 
`5 loops, best of 5: 478 ms per loop` 

我们发现这个计算大约需要 478 ms 。接下来,我们用 JAX 实现这个计算:

`jax_fn = jit(fn)
x = jnp.array(x)
%timeit jax_fn(x).block_until_ready()`
`100 loops, best of 5: 5.54 ms per loop` 

JAX 完成这个计算只用了 5.54 毫秒,比 T2 快了 86 倍。

...那就是 8600%。

**

JAX has the potential to be orders of magnitude faster than NumPy (n.b. JAX is using TPU and NumPy is using CPU in order to highlight that JAX's speed ceiling is much higher than NumPy's)**

观点

事情并不像“使用 JAX,你的程序会快 86 倍”那么简单,但是仍然有大量的理由使用 JAX。由于 JAX 为高性能科学计算提供了一个通用基础,它将因不同原因对不同领域的不同人有用。从根本上说,如果你在任何与科学计算相关的领域,你都应该关心 JAX** 。**

以下是您可能希望使用 JAX 的一些原因:

1。加速器上的 NumPy**-NumPy 是使用 Python 进行科学计算的基础包之一,但是它只与 CPU 兼容。JAX 提供了一个 NumPy 的实现(有一个几乎相同的 API ),可以非常容易地在 T2 的 GPU T4 和 TPU T5 上运行。对于许多用户来说,光是这个就足以证明使用 JAX 的合理性。

2。XLA - XLA,或加速线性代数,是一个全程序优化编译器,专为线性代数设计。JAX 建立在 XLA 的基础上,大大提高了计算速度的上限1

3。JIT - JAX 允许你使用 XLA7 将你的自己的函数转换成即时(JIT)编译版本。这意味着你可以通过在你的计算函数中添加一个简单的函数装饰器来提高计算速度。**

****4。自动分化——JAX 文献称 JAX 为“亲笔签名和 XLA,走到一起”1 。自动微分的能力在科学计算的许多领域是至关重要的,JAX 提供了几个强大的自动微分工具。

****5。深度学习——虽然它本身不是一个深度学习框架,但 JAX 无疑为深度学习提供了一个绰绰有余的基础。有许多建立在 JAX 之上的图书馆寻求建立深度学习能力,包括亚麻俳句挽歌。在我们最近的 PyTorch vs TensorFlow 文章中,我们甚至强调 JAX 是一个值得关注的“框架”,建议将其用于基于 TPU 的深度学习研究。JAX 对黑森的高效计算也与深度学习相关,因为它们使高阶优化技术更加可行。

6。通用可区分编程范式**——虽然使用 JAX 来构建和训练深度学习模型肯定是可能的,但它也为通用可区分编程提供了一个框架。这意味着 JAX 可以通过使用基于模型的机器学习方法来解决问题,利用在给定领域通过几十年的研究建立起来的先验知识**

**想了解更多关于基于模型的差异化编程吗?

查看我们对差异化编程的介绍!

Check it out**

XLA

点击此处跳转到本节的摘要。

什么是 XLA?

XLA,或加速线性代数,是 JAX 如此强大的基础。XLA 由谷歌开发,是一个特定领域、基于图形的实时编译器2 ,用于线性代数,可以通过各种全程序优化3 显著提高计算速度。

在一个例子2 中,仅从*计算的角度来看,XLA 将 BERT 训练速度提高了几乎的 7.3 倍,但由于使用了 XLA 而降低了内存使用量还支持梯度累加,导致计算吞吐量惊人地提高了 12 倍*

**

XLA can significantly improve the training process for neural networks**

XLA 已经融入了 JAX 的 DNA 单从他们的商标就可以看出 JAX 的成功有多依赖 XLA。

为什么 XLA 如此重要?

回答 XLA 为何如此重要,可能会引发一场技术性很强(也很长)的讨论。出于我们的目的,可以说 XLA 很重要,因为它通过融合低级操作显著提高了执行速度并降低了内存使用。

**其他详细信息

XLA 并不将单个操作预编译成计算内核,而是将整个图编译成一系列计算内核,这些计算内核是专门为图生成的

这种方法通过不执行不必要的内核启动来提高速度,并利用本地信息进行优化【3】。由于 XLA 没有在操作序列中物化中间数组(而是将值保存在 GPU 寄存器中,并将它们流式传输【3】),使用 XLA 也减少了内存消耗。

考虑到(I)内存通常是 GPU 计算的限制因素,以及(ii) XLA 不会浪费时间来执行无关的数据移动,这种降低的内存消耗带来了进一步的速度提升。**

虽然操作融合(或内核融合)是 XLA 的旗舰功能,但应该注意的是,XLA 还执行了一系列其他全程序优化,如专门针对已知的张量形状(允许更积极的常数传播),分析和调度内存使用以消除中间存储缓冲区4 ,执行内存布局操作,如果不是所有的值都被返回,则只计算请求值的子集[5

由于所有 JAX 操作都是根据 XLA 的操作实现的,JAX 有一个统一的计算语言,允许它在 CPU、TPU 和 GPU 之间无缝运行,库调用得到及时编译和执行1

摘要

如果上面的行话对你没有意义,不要担心-只要知道 XLA 是一个非常快速的编译器,它是使 JAX 在各种硬件上使用起来独特强大和简单的基础。

JAX 变换

点击此处跳转到本节的摘要。

什么是函数变换?

到目前为止,我们已经讨论了 XLA 以及它如何允许 JAX 在加速器上实现 NumPy 但请记住,这只是我们对 JAX 定义的一半。JAX 不仅为强大的科学计算提供工具,也为可组合函数转换提供工具。

很简单,函数转换是函数上的操作符,其输出是另一个函数。如果我们对一个标量值函数 f(x) 使用梯度函数变换,那么我们得到一个向量值函数f’(x),它给出了函数在 f(x) 的定义域中任意一点的梯度。

**

Using grad() on our function allows us to get the gradient at any point in the domain**

****JAX 为这种功能转换引入了一个可扩展的系统,并且有四个典型用户感兴趣的主要转换:

  1. grad()用于评估输入函数的梯度函数
  2. vmap()用于自动矢量化的操作
  3. pmap()便于并行计算,以及
  4. 将函数转换成即时编译版本

让我们依次看看这些转变,并谈谈它们为什么如此令人兴奋。如果你想玩一些互动的例子,可以在 YouTube 上免费查看我们的 JAX 速成班,或者是与相关的 Colab 笔记本

grad()自动微分

为了能够训练机器学习模型,人们需要能够执行反向传播。与 TensorFlow 或 PyTorch 通过计算图反向传播来计算损失函数在某个的梯度不同,JAX grad()函数变换输出梯度函数,然后可以在其域中的任何点对其进行评估。

哪里可以区分?

自动微分在 JAX 非常强大,部分源于 JAX 在计算梯度时的灵活性。有了grad(),可以通过原生 Python 和 NumPy 函数6 进行区分,比如循环、分支、递归、闭包和“ PyTrees ”(比如字典)。

让我们看一个例子——我们将使用 Python 控制流定义一个修正的立方体函数f(x) = abs(x3)。这个实现显然不是计算效率最高的方法,但是它帮助我们突出了grad()如何通过本地 Python 控制流和嵌套在条件中的循环工作。

`def rectified_cube(x):
  r = 1

  if x < 0.:
    for i in range(3):
      r *= x
    r = -r
  else:
    for i in range(3):
        r *= x

  return r

gradient_function = grad(rectified_cube)

print(f"x = 2   f(x) = {rectified_cube(2.)}   f'(x) =  3*x^2 = {gradient_function(2.)}")
print(f"x = -3  f(x) = {rectified_cube(-3.)}  f'(x) = -3*x^2 = {gradient_function(-3.)}")`
`x = 2   f(x) = 8.0   f'(x) =  3*x^2 = 12.0
x = -3  f(x) = 27.0  f'(x) = -3*x^2 = -27.0`

我们可以看到,在x=2x=-3 求函数及其导数时,得到了预期的结果。

什么程度我能区分?

通过重复应用grad(),JAX 可以很容易地将区分为任何订单

`# for x >= 0: f(x)=x^3 => f'(x)=3*x^2 => f''(x)=3*2*x => f'''(x)=6
third_deriv = grad(grad(grad(rectified_cube)))
for i in range(5):
  print(third_deriv(float(i)))`
`6.0
6.0
6.0
6.0
6.0`

我们可以看到,对我们的函数的三阶导数的几个输入的评估给出了f '''(x)=6 的恒定期望输出。

从更一般的角度来看,以快速和简单的方式获取多重导数的能力对于深度学习之外的许多更一般的计算领域具有实际用途,例如动力系统的研究。

我能区分什么

标量值函数

如您所料,grad()采用标量值函数梯度,这意味着一个将标量/向量映射到标量的函数。这种函数的梯度对于例如反向传播是有用的,其中我们通过从(标量)损失函数反向传播来训练模型,以更新我们的模型权重。

虽然grad()对于各种各样的项目来说已经足够,但这并不是 JAX 能够实现的唯一差异化。

向量值函数

对于将向量映射成向量的向量值** 函数,与梯度类似的是雅可比矩阵。通过对应于正向模式微分和反向模式微分的函数变换jacfwd()jacrev(),JAX 返回一个函数,该函数在对域中的一点求值时产生雅可比矩阵。**

`def mapping(v):
  x = v[0]
  y = v[1]
  z = v[2]
  return jnp.array([x*x, y*z])

# 3 inputs, 2 outputs
# [d/dx x^2 , d/dy x^2, d/dz x^2]
# [d/dx y*z , d/dy y*z, d/dz y*z]

# [2*x , 0, 0]
# [0 , z, y]

f = jax.jacfwd(mapping)
v = jnp.array([4., 5., 9.])
print(f(v))`
`[[8\. 0\. 0.]
 [0\. 9\. 5.]]`

例如,您也可以使用雅可比矩阵,以便更有效地计算数据矩阵中每个数据相对于权重矩阵的函数梯度。

黑森人

从机器学习的角度来看,JAX 最令人兴奋的一个方面可能是它让计算变得非常简单,让 T2 变得非常容易,让 T4 变得高效。因为有了 XLA, JAX 计算黑森的速度比 PyTorch 快得多,这使得实现高阶优化技术,如 AdaHessian 更加实际。这个事实本身就足以成为一些实践者使用 JAX 的理由。**

让我们尝试在 PyTorch 中计算输入平方和的 Hessian 值:

****`def torch_fn(X):
  return pt.sum(pt.mul(X,X))

X = pt.randn((1000,))
%timeit -n 10 -r 5 pt.autograd.functional.hessian(torch_fn, X, vectorize=False)
%timeit -n 100 -r 10 pt.autograd.functional.hessian(torch_fn, X, vectorize=True)`****
****`10 loops, best of 5: 107 ms per loop
100 loops, best of 10: 3.33 ms per loop`****

计算需要大约 107 毫秒,但是使用实验矢量化功能将执行时间减少到 3.33 毫秒。让我们在 JAX 尝试同样的计算:

**`def jax_fn(X):
  return jnp.sum(jnp.square(X))

jit_jax_fn = jit(jacfwd(jacrev(jax_fn)))

X = jnp.array(X)
%timeit jit_jax_fn(X).block_until_ready()`**
**`The slowest run took 47.27 times longer than the fastest. This could mean that an intermediate result is being cached.
1000 loops, best of 5: 90.5 µs per loop`**

使用 JAX,计算只需要 90.5 秒,比 PyTorch 的矢量化版本快 36 倍。

****

JAX can be very fast at calculating Hessians, making higher-order optimization much more feasible****

向前推/向后拉

JAX 甚至可以计算出雅可比向量乘积向量雅可比乘积。考虑光滑流形之间的光滑映射。JAX 可以计算这个地图的向前推进,将一个流形上的点的切向量映射到另一个流形上的切向量。

****

Image source****

如果这部分比较混乱或者不熟悉,不用担心!这是一个高级主题,可能对一般用户来说(就其本身而言)不相关或不感兴趣。我们指出这种能力的存在只是为了强调这样一个事实,即 JAX 为各种各样的计算任务提供了非常强大的基础。例如,前推在微分几何领域很重要,我们可以用 JAX 来研究。****

使用vmap()自动矢量化

越过数学到更实际/计算的转换,我们到达vmap()。考虑这样一种情况,我们希望对一组对象重复应用一个函数。例如,让我们考虑将两个数字列表相加的任务。实现这种操作的简单方法是简单地利用一个for循环——即对于第一个列表中的每个数字,将它添加到第二个列表中的相应值,并将结果写入一个新列表。

****https://www.assemblyai.com/blog/content/media/2022/02/not_vectorized-1.mp4


Unvectorized vector-addition

通过vmap()转换,JAX 执行相同的计算,但是将循环下推到原始操作以获得更好的性能6 ,从而产生计算的自动矢量化版本。

****https://www.assemblyai.com/blog/content/media/2022/02/vectorized.mp4


Vectorized vector-addition

当然,我们可以简单地将我们的列表定义为 JAX 数组,并使用 JAX 的数组加法,但是由于许多原因,vmap()仍然很有用。

一个基本原因是,我们可以用更原生的 Python 代码编写操作,然后vmap()它,导致高度 Python 化和可能更可读的代码。另一个原因当然是推广到没有简单的矢量化替代方案可以实现的情况。**

使用pmap()自动并行化

分布式计算逐年变得越来越重要,尤其是在深度学习领域,SOTA 模型已经发展到绝对天文数字的规模,如下图所示。例如,GPT-4 号将拥有超过 100 万亿个参数

****

Data source****

我们已经在上面讨论过,由于 XLA,JAX 可以在一个加速器上轻松计算,但是 JAX 也可以用多个加速器轻松计算,用单个命令 - pmap()执行 SPMD 程序的分布式训练。****

考虑向量矩阵乘法的例子。假设我们通过顺序计算向量与矩阵每一行的点积来执行这个计算。我们需要通过硬件一次一个地推进这些计算。

****https://www.assemblyai.com/blog/content/media/2022/02/not_parallel-2.mp4


Unparallelized vector-matrix multiplication

有了 JAX,我们可以轻松地通过简单地将我们的操作包装在pmap() 中,将这些计算分布在 4 个 TPU 上。这允许我们在每个 TPU 上同时执行一个点积,显著提高了我们的计算速度(对于大型计算)。**

****https://www.assemblyai.com/blog/content/media/2022/02/parallelized.mp4


Parallelized vector-matrix multiplication

这里非常值得注意的是对我们代码的改变是多么的小。由于 JAX 是建立在 XLA 上的,我们可以轻松地改变我们将计算映射到硬件的方式。

jit()进行实时编译

什么是实时编译?

实时编译(JIT compilation)是一种介于解释和提前(AOT)编译之间的代码执行方法。重要的事实是, JIT 编译器会在运行时将代码编译成快速的可执行文件,代价是第一次运行较慢。

****其他详细信息

使用 JIT 编译,代码是在运行时编译的,所以在程序第一次运行时会有一些初始开销,因为代码需要编译和执行。因此,AOT 编译可能在第一遍就胜过 JIT 然而,对于重复执行,JIT 编译的程序将使用先前编译的缓存代码非常快速地执行

如果 JIT 编译的程序是 AOT 编译的,那么从理论上讲,JIT 编译的程序甚至可以比相同的程序运行得更快(T0 )( T1 ),因为 JIT 编译器可以利用代码在执行它的同一台机器上编译的事实,使用本地信息来提高优化。

界线会变得模糊。例如,当 Python 运行时,它被编译成字节码,然后被 Python 的虚拟机(例如 CPython)解释,或者被编译成机器码(PyPy)。如果这些细节令人困惑,不要担心。重要的一点是,JIT 编译的 JAX 程序允许它们极快地执行。****

JAX 的及时编辑

XLA 原语是 JIT 编译的,但是 JAX 让你 JIT 编译你自己的 Python 函数到 XLA 优化的内核,要么作为函数装饰器@jit,要么作为函数本身jit()1

JIT 不是一次一个操作地将内核分派到 GPU,而是使用 XLA 将操作序列一起编译到一个内核中,给出一个端到端编译的高效 XLA 实现67

举个例子,让我们定义一个函数来计算一个矩阵值的前三次幂的和。我们在一个 5000 x 5000 的矩阵上计算这个函数三次——一次用 NumPy,一次用 JAX,一次用 JAX 在这个函数的 JIT 编译版本上。首先,我们在 CPU 上进行实验:

**`def fn(x):
  return x + x*x + x*x*x

x_np = np.random.randn(5000, 5000).astype(dtype='float32')
x_jnp = jnp.array(x_np)

%timeit -n5 -r5 fn(x_np)
%timeit fn(x_jnp).block_until_ready()
jitted = jit(fn)
jitted(x_jnp)
%timeit jitted(x_jnp).block_until_ready()`**
**`WARNING:absl:No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
5 loops, best of 5: 151 ms per loop
10 loops, best of 5: 109 ms per loop
100 loops, best of 5: 17.7 ms per loop`**

****

JAX is significantly faster for element-wise computations, especially when jit is used****

我们看到 JAX 几乎比 NumPy 快 40%,当我们 JIT 这个函数时,我们发现 JAX 比 NumPy 快 8.5 倍。这些结果已经令人印象深刻,但让我们加大赌注,让 JAX 在 TPU 上计算:

****

When JAX performs the same calculation on a TPU, its relative performance jumps even further (NumPy computations still performed on CPU given that it does not support TPU computation)****

在这种情况下,我们看到 JAX 比 NumPy 快 9.3 倍,如果我们在 TPU 上运行 JIT 函数和计算,我们会发现 JAX 比 NumPy 快 57 倍。

当然,这种速度的大幅提高并不是没有代价的。JAX 对 JIT 允许哪些函数进行了限制,尽管像上面这样只涉及 NumPy 操作的函数通常是允许的。此外,通过 Python 控制流进行 JIT 还有一些限制,所以在编写函数时,您必须记住这一点。

****提醒一句

在使用jit之前,你应该确保你了解它是如何工作的,以及在什么情况下允许使用它。如果你没有这种理解,但还是试图使用jit,你要么会得到令你困惑的错误消息(如果你幸运的话),要么会得到未被跟踪的、不受欢迎的副作用,这些副作用会悄悄地破坏你结果的准确性(如果你不幸的话)。****

要了解更多关于 JIT 及其局限性的信息,请查阅 JAX 文档

摘要

JAX 有 4 个主要的函数转换- grad()用于自动微分函数,vmap()用于自动矢量化运算,pmap()用于 SPMD 程序的并行计算,以及jit()用于将函数转换成 JIT 编译版本。这些转换(大部分)是可组合的,非常强大,并且有可能将您的程序加速几倍。

有什么条件?

点击此处跳转到本节的摘要。

我们在上面看到了 XLA 和基本 JAX 变换如何有潜力显著提高程序的性能。虽然 JAX 非常强大,有潜力在许多领域大幅提高生产率,但它的使用需要谨慎。尤其是如果你正在考虑从 PyTorch 或 TensorFlow 转移到 JAX,你应该明白 JAX 的底层哲学与这两个深度学习框架截然不同。我们现在来说说主要区别。

功能范式

使 JAX 与众不同的主要特征是它的转换和编译被设计成只为功能纯的程序工作。虽然如果您只是想使用 JAX 在 GPU 或 TPU 上进行 NumPy 计算,这一事实可能不相关,但它与大量潜在的 JAX 应用程序相关,因此您应该确保在开始之前理解采用这一范式的含义。

一个纯函数的核心特征,有时称为数值函数,是参照透明性的特征——一个纯函数可以在任何时候用它的求值结果替换,而程序不能分辨出其中的区别。在给定相同输入*的情况下,函数应该总是对程序产生相同的影响,而不管它执行的时间或环境。*****

原则上这听起来很简单,但是如果您没有函数式编程的经验,那么肯定存在一个学习曲线。下面是一些必要(但不充分!)函数为纯函数的条件:

  • 它不能通过访问或分配其作用域之外的变量来改变程序的状态
  • 它不能有 I/O 流——所以不能打印、请求输入或访问时间
  • 它不能有可变函数作为参数(并发进程可以修改)

JAX 的函数式方法导致了一些新来者应该做好准备的特性,比如不能就地修改数组和显式 PRNG 处理

未追踪的副作用

在 JAX 运行一个不纯的函数时,副作用可能不会表现出来。如果你不小心,像作用域外封装这样的副作用会悄悄地抛出你的计算结果。这在某些行业(医疗保健、自主系统等)有可能是灾难性的。),所以如果你打算利用 JAX,你应该确定你了解如何写纯函数。

摘要

JAX 的函数变换被设计成只与函数(有时被称为数字函数)一起工作。如果你不小心,未被追踪的副作用可能会悄悄地破坏你预期计算的准确性。****

我应该在 2023 年使用 JAX 吗?

一如既往,这个问题的答案是“看情况”。移民 JAX 是否明智取决于你的环境和目标。为了帮助你决定你是否应该在 2023 年使用 JAX,我们将我们的建议编辑成了下面的流程图,不同的图表代表不同的兴趣领域。

科学计算

如果你对 JAX 的通用科学计算感兴趣——你应该问自己的第一个问题是,你是否只是想在加速器(即 GPU 和 TPU)上运行 NumPy。如果答案是肯定的,那么你昨天就应该使用 JAX。在这种情况下,这真的很容易,你应该开始移民到 JAX。

如果你不只是处理数字,而是参与动态计算建模,那么你是否应该使用 JAX 将取决于你的用例。如果你的大部分工作是使用大量定制代码的 Python,那么为了提高你的工作流程,开始学习 JAX 是值得的。

如果你的大部分工作不是用 Python 做的,但是你想建立某种混合的基于模型/神经网络的系统,那么使用 JAX 可能是值得的。

如果你的大部分工作不是用 Python 做的,或者你在研究中使用了一些专门的软件(热力学、半导体等)。)那么 JAX 可能不适合你,除非你想从这些程序中导出数据进行某种定制的计算处理。如果你感兴趣的领域更接近物理/数学,并且结合了计算方法(动力系统、微分几何、统计物理),并且你的大部分工作都是在 Mathematica 中完成的,那么坚持使用你正在使用的可能是值得的,特别是如果你有一个大的定制代码库。

深度学习

虽然我们强调 JAX 是一个通用框架,而不是专门为深度学习而构建的,但 JAX 速度很快,具有自动区分能力,这意味着很多读者肯定想知道他们是否应该开始使用 JAX 进行深度学习**

如果你想在 TPUs 上接受培训,那么你或许应该开始使用 JAX* ,尤其是如果你目前正在使用 PyTorch 的话。虽然 PyTorch-XLA 存在,但使用 JAX 进行 TPU 训练绝对是天衣无缝的,整体体验要好得多。如果你正在从事“非标准”的架构/建模,比如 SDE 网,那么你绝对应该让 JAX 试试。此外,如果你想利用高阶优化技术,JAX 绝对应该是你的实验对象。*******

如果你不是在构建奇异的架构,只是在 GPU 上训练常见的架构,那么你可能应该暂时坚持使用 PyTorch 或者 tensor flow;然而,这一建议在未来一两年内很容易改变。虽然 PyTorch 仍然主导着研究领域,但使用 JAX 的论文数量一直在稳步增长,随着 DeepMind 和谷歌等重量级公司持续为 JAX 开发高级深度学习 API,在短短几年内 JAX 可以轻松看到爆炸性的采用率**

与此同时,你至少应该熟悉 JAX 的基础知识,尤其是如果你从事任何类型的机器学习研究的话。

初级深度学习

如果你刚刚开始深度学习并且正在考虑使用 JAX,有几件事需要考虑。

如果你对学习深度学习感兴趣为了你自己的启迪,那么我们推荐你使用 JAX 或者 PyTorch 。如果你想从自上而下学习深度学习和/或有一些 Python/软件经验,那么我们推荐你从 PyTorch 开始。如果你想从自下而上学习深度学习,或者有数学背景,你可能会发现 JAX 直觉,应该试一试。在这种情况下,在着手任何大项目之前,确保你了解如何与 JAX 合作。

如果你对潜在职业变化的深度学习感兴趣,那么你会想使用 T2 的 PyTorch 或 TensorFlow。点击这里查看我们的指南,帮助你选择最适合你的框架。尽管最好熟悉这两个框架,但是您应该知道 TensorFlow 被认为是“行业”框架,下面每个框架的职位发布数量证明了这一点:

****

PyTorch vs TensorFlow: Job Postings****

如果你是一个完全的初学者,没有数学或软件背景,但想学习深度学习和神经网络,那么你是 T2,而不是 T3,不会想使用 JAX。相反,你会想从 Keras 开始——查看我们的指南这里了解更多信息。

不应该使用 JAX 的理由**

虽然我们已经讨论过 JAX 有可能极大地提高你的程序的性能,但是这里有一些你不应该使用 JAX 的理由:

1。JAX 仍然被官方认为是一个实验框架。 JAX 是一个相对年轻的项目——tensor flow 的历史几乎是 JAX 的两倍。目前,JAX 仍然被认为是一个研究项目,而不是一个成熟的谷歌产品,所以如果你正在考虑搬到 JAX,请记住这一点。

2。使用 JAX 时,你必须勤奋。调试的时间成本,或者更严重的是,未被跟踪的副作用的风险,可能会使那些没有牢固掌握函数式编程的人不值得使用 JAX。在您开始将 JAX 用于严肃的项目之前,请确保您了解使用它的常见陷阱。

3。 JAX 没有针对 CPU 计算进行优化。由于是以“加速器优先”的方式开发的,因此针对 JAX 的每项操作调度并未完全优化5 。正因为如此,NumPy 在某些情况下实际上可能比 JAX 更快,特别是对于小程序,由于 JAX 引入的开销。在特定情况下,你能否期望 NumPy 或 JAX 更快取决于几个因素——查看页面了解更多细节。

4。JAX 与 Windows 不兼容。目前不支持 Windows 上的 JAX。如果你在 Windows 机器上工作,但仍然想尝试 JAX,使用 Colab 或将其安装在虚拟机上。

最后的话

JAX 是一个非常有前途的项目,并且越来越受欢迎,尽管它的函数式范例引入了学习曲线。观察 JAX 在未来几年的发展将会很有趣,尤其是在研究领域。已经有很多项目在各种领域使用 JAX:

如果你想探索 JAX 的生态系统,你可以看看下面这些项目的链接:

***** 深度学习
* DeepMind 的俳句RLax
* 谷歌的亚麻TraxObjax ,还有 Stax
* 谷歌的景区
* 悲歌

在未来几个月,我们将推出更多 JAX 内容,包括深入研究函数转换,测试 JAX 如何与 PyTorch 和 TensorFlow 相抗衡的实验,以及 JAX 深度学习 API 的比较。请务必订阅我们的时事通讯,这样你就不会错过了!

****寻找更多这样的内容?

请务必订阅我们的时事通讯!

Subscribe****

参考

  1. JAX 自述
  2. TensorFlow 2 MLPerf 提交
  3. 张量流 XLA
  4. tensorlow xla 体系结构
  5. JAX:通过可组合转换加速 ML 研究
  6. JAX 自述——转变
  7. JAX 快速入门

单词错误率有用吗?

原文:https://www.assemblyai.com/blog/word-error-rate/

什么是单词错误率?

单词错误率是自动语音识别(ASR)系统执行的准确程度的度量。从字面上看,它可以计算出与人类转录相比,ASR 系统产生的转录文本中有多少“错误”。

从广义上讲,衡量任何机器学习系统的准确性都很重要。无论是自动驾驶汽车,亚马逊 Alexa 这样的 NLU 系统,还是我们在 AssemblyAI 开发的自动语音识别系统,如果你不知道你的机器学习系统有多准确,你就是在瞎飞!

在自动语音识别领域,单词错误率已经成为衡量语音识别模型准确程度的事实标准。我们从客户那里得到的一个常见问题是“你的 WER 是什么?”。事实上,当我们公司在 2017 年被 Y Combinator 接受时,YC 合伙人问我们的第一个问题是“你的 WER 是什么?”

如何计算单词错误率(WER)

计算单词错误率背后的实际数学过程如下:

Word Error Rate Algorithm

我们在这里做的是将删除(D)插入(N)**** 的数量组合起来,除以 字数(N)

所以比如说,我们说下面这句话是口语:

`"Hello there"`

如果我们的自动语音识别(ASR)不是很好,并预测以下转录:

`"Hello bear"` 

那么我们的单词错误率(WER)将是 50%!那是因为有 1 个 替换 ,“有”被替换成了“熊”。假设我们的 ASR 系统只能预测:

`"Hello"`

出于某种原因,甚至没有预测到第二个词。在这种情况下,我们的单词错误率(WER)也将是 50%!那是因为只有一个缺失——我们的 ASR 系统只预测到 1 个单词,而实际说的是 2 个单词。 单词错误率越低越好 。你可以把单词准确率想象成 1 减去单词错误率。因此,如果你的单词错误率是 20%,那么你的单词准确率,即你的转录有多准确,是 80%😗***

单词错误率是衡量语音识别系统的一个好方法吗?

和所有事情一样,它不是非黑即白的。总的来说,单词错误率可以告诉你自动转录与人工转录相比有多“不同”,通常,这是确定自动转录有多“好”的可靠指标。

例如,以下面的例子为例:

`Spoken text:
“Hi my name is Bob and I like cheese. Cheese is very good.”

Predicted text by model 1:
"Hi my frame is knob and I bike leafs. Cheese is berry wood"
WER: 46%

Predicted text by model 2:
"Hi my name is Bob and I bike cheese. Cheese is good."
WER: 15%`

正如我们所见,模型 2 的 wer 较低,为 15%,对于我们人类来说,显然比模型 1 的预测文本更准确。这就是为什么一般来说,WER 是用于确定自动语音识别系统的准确性的良好度量。

然而,以下面的例子为例:

`Spoken:
"I like to bike around"

Model 1 prediction:
"I liked to bike around"
WER: 20%

Model 2 prediction:
"I like to bike pound"
WER: 20%`

在上面的例子中, 模型 1 文本和 模型 2 文本都有 20%的 WER。但是 模型 1 显然比 模型 2 更容易理解。这是因为即使有 型号 1 所犯的错误,它仍然会产生更清晰、更易于理解的转录。这与 模式 2 相比,在转录中出现错误,导致转录文本难以辨认(即“字汤”)。

为了进一步说明单词错误率的下降,举下面的例子:

`Spoken:
"My name is Paul and I am an engineer"

Model 1 prediction:
"My name is ball and I am an engineer"
WER: 11.11%

Model 2 prediction:
"My name is Paul and I'm an engineer"
WER: 22.22%`

在这个例子中, Model 2 在生成可理解的转录方面做得更好,但是它有两个(!!)把 WER 比作 型号 1 。WER 的这种差异在这个例子中尤其明显,因为文本包含的单词很少,但这仍然说明了在回顾 WER 时需要注意的一些“问题”。

以上这些例子说明的是,文字错误计算并不“聪明”。从字面上看,它只是在自动转录中出现的替换、删除和插入的数量,与人类转录进行比较。这就是为什么“真实世界”中的 WER 会如此成问题。

举一个简单的例子,在人类转录和自动转录中没有规范化大小写。

`Human transcription:
"I live in New York"

Automatic transcription:
"i live in new york"
WER: 60%`

在这个例子中,我们看到自动转录的 WER 为 60% (!!)即使它完美地转录了所说的内容。仅仅是因为我们将人类的转录与大写的 、纽约的 和小写的 、纽约的 进行比较,WER 算法将这些视为完全不同的单词!

这是我们在野外看到的一个主要“陷阱”,这也是为什么我们在计算 WER 时,总是在内部将人类转录和自动转录标准化,例如:

  • 小写所有文本
  • 删除所有标点符号
  • 将所有数字转换成书面形式(“7”->“7”)
  • 等等。

单词错误率的替代方法

不幸的是,单词错误率是我们今天用来确定自动语音识别系统准确性的最佳度量。已经提出了一些替代方案,但没有一个停留在研究或商业社区。一种常用的技术是对替换的 ****、插入的和删除的进行不同的加权。例如,每删除一个就增加 0.5,而不是 1.0。****

然而,除非权重被标准化,否则这并不是一个真正“公平”的计算 WER 的方法。例如,与系统 2 相比,系统 1 可以报告低得多的 wer,因为它对 替换 使用了更低的“权重”。

这就是为什么,就目前而言,单词错误率仍然存在,但是在您自己计算 WER 时,记住我们演示的陷阱是很重要的!

如何用 Zoom API 获得 Zoom 脚本

原文:https://www.assemblyai.com/blog/zoom-transcription-zoom-api/

在这篇文章中,我们将向您展示如何通过用 Python 连接 Zoom 的 API 和 AssemblyAI 的自动语音识别 API 来转录您的 Zoom 录音。更具体地说,我们将带您了解:

  • 在缩放时创建云记录
  • 使用您自己的帐户访问 Zoom 的 API
  • 从 Zoom 的 API 获取云记录
  • 将云记录提交给 AssemblyAI 进行快速自动转录

准备好你的编码手指,让我们开始吧!

在缩放时创建云记录

在 Zoom 中创建云录制首先要知道的是,你必须有一个 Pro,Business,或者企业账号 。基本免费缩放计划没有启用会议录制功能。你可能已经有这样的计划,可能已经有云录音准备转录,这种情况下,你可以跳到下一个头,继续滚动。

但是如果你刚刚为你的项目获得了一个升级的 Zoom 帐户,并且你仍然需要创建一个云记录,一些事情要记住。首先,您不需要让另一个人参加会议,云录制就可以工作。不需要和别人一起安排。

如果您使用的是台式机、笔记本电脑或大型平板电脑,则开始录制的按钮如下所示:

录制结束后,会有一个弹出框告诉你,一旦录制完成,你会收到一封电子邮件。Zoom 的帮助页面谨慎地警告用户,它可能需要 24-48 小时才能准备好,但这可能是 2020 年初的现实,当时全世界都涌向 Zoom,而他们的系统还没有准备好应对这种流量水平。较长的录音可能还需要一段时间,但我发现在 2021 年,它们几乎马上就准备好了。

要查找您的录像,请登录 Zoom,然后导航至 我的帐户

向左,点击标签。

现在,应许之地!在那里你会看到你的云录音,为你准备好了 mp4 和 m4a 格式。

访问您的缩放 API 密钥

现在,让我们一步一步地完成获取 Zoom 后门钥匙的过程。我想为 Billy Harmawan 向我展示了这个有点复杂的过程。这里我也给你讲一下它的要点。

首先,你需要在一个新标签中导航到 Zoom 的应用市场。您可能已经从您的主帐户页面登录,但如果没有,您可以使用相同的凭据登录,然后在登录后导航回 Zoom 应用程序市场。

二、点击右上角的 【开发】 ,下拉菜单中的 【构建 App】

第三,你需要选择 ****【创建】****【JWT】****下的 app 类型。我们将使用 JSON Web Tokens ( JWT 的)用于这个转录连接,因为它们易于再生,在代码中使用,并且可以附加到 url。

第四,为你的 Zoom 应用取一个独特的名字。

第五,您需要填写它将带您进入的信息页面上的必填字段。

第六,在接下来的页面上,应该会生成您的 API 凭证!

从这里,创建一个 tokens.env 文本文件,并将每个凭证保存在一个变量名下,如下所示。你会需要这个。env 文件放在代码中。

`ZOOM_API_KEY = USE_STEPS_ABOVE_TO_GET_YOUR_VERY_OWN_ZOOM_API_KEY
ZOOM_API_SECRET = USE_STEPS_ABOVE_TO_GET_YOUR_VERY_OWN_ZOOM_API_SECRET
ZOOM_IM_CHAT_HISTORY_TOKEN = USE_STEPS_ABOVE_TO_GET_YOUR_VERY_OWN_ZOOM_IM_CHAT_HISTORY_TOKEN
ZOOM_JWT = USE_STEPS_ABOVE_TO_GET_YOUR_VERY_OWN_ZOOM_JWT`

注意:在凭证页面上生成的第一个JWT 令牌最好放在dotenv文件中以防万一,但是我们的代码将会生成新的 JWT 令牌。所以把它复制下来,但是要知道这可能是不必要的。

最后,您可以跳过此应用程序创建页面上可选的 “功能” 选项卡,直接进入 “激活” 以确认您已经完成。

接下来的几个步骤只是双重和三重检查,以确保应用程序存在于您的帐户中,并且如果您需要,可以在未来管理凭据。

导航回 Zoom 的应用市场,点击右上角的“管理”按钮。

你会看到你的应用程序列表。

单击应用程序的名称,当您再次看到此屏幕时...

...你可以放心,因为你知道 Zoom 的 API 已经为你准备好了。

注册一个汇编 api 令牌

只需输入你的电子邮件地址,你就可以在几秒钟内注册一个免费的 AssemblyAI 账户。从您的电子邮件地址验证您的帐户后,您将直接返回到您的新帐户,您可以在您的仪表板中看到您的 API 令牌。

获取 API 令牌并将其添加到您的tokens.env文件中,就像您为 Zoom 的 API 密钥所做的一样,并使用它自己唯一的变量名。

`ZOOM_API_KEY = USE_STEPS_ABOVE_TO_GET_YOUR_VERY_OWN_ZOOM_API_KEY

ZOOM_API_SECRET = USE_STEPS_ABOVE_TO_GET_YOUR_VERY_OWN_ZOOM_API_SECRET

ZOOM_IM_CHAT_HISTORY_TOKEN = USE_STEPS_ABOVE_TO_GET_YOUR_VERY_OWN_ZOOM_IM_CHAT_HISTORY_TOKEN

ZOOM_JWT = USE_STEPS_ABOVE_TO_GET_YOUR_VERY_OWN_ZOOM_JWT

ASSEMBLYAI_TOKEN = SIGN_UP_AT_ASSEMBLYAI_TO_GET_YOUR_VERY_OWN_ASSEMBLYAI_TOKEN`

用 Python 从 Zoom 的 API 获取云记录

旋转一个zoom.py文件,将这些导入语句放在顶部:

`import sys
import time
import requests
import authlib
import os
import urllib.request
from dotenv import load_dotenv
from pathlib import Path
from typing import Optional, Dict, Union, Any
from authlib.jose import jwt
from requests import Response
import http.client
import json`

现在找到您的tokens.env文件的目录路径,或者将tokens.env文件移动到您的zoom.py所在的目录,然后将这段代码添加到您的zoom.py脚本中:

`env_path = Path('.')/'tokens.env'
load_dotenv(dotenv_path=env_path)`

接下来,您将通过给一些变量命名来从tokens.env文件中获取凭证。您将在后续代码中使用的变量位于“=”的左侧,您在 tokens.env 文件中用于该 API 凭证的别名变量将是“=”分配器右侧的字符串。

`API_KEY= os.getenv("ZOOM_API_KEY")
API_SECRET= os.getenv("ZOOM_API_SECRET")
ASSEMBLY_AI_TOKEN = os.getenv("ASSEMBLYAI_TOKEN")`

现在,您将创建一个 Zoom 类,该类将生成实时 JWT,您将需要该类来解锁其余代码中的云记录。再次,大声喊出来比利·哈曼设计了这个。

`class Zoom:
    def __init__(self, api_key: str, api_secret: str):
        self.api_key = api_key
        self.api_secret = api_secret
        self.jwt_token_exp = 518400
        self.jwt_token_algo = "HS256"

    def generate_jwt_token(self) -> bytes:
        iat = int(time.time())

        jwt_payload: Dict[str, Any] = {
            "aud": None,
            "iss": self.api_key,
            "exp": iat + self.jwt_token_exp,
            "iat": iat
        }

        header: Dict[str, str] = {"alg": self.jwt_token_algo}

        jwt_token: bytes = jwt.encode(header, jwt_payload, self.api_secret)

        return jwt_token`

然后,您将创建一个 Zoom 类的实例,并使用它来生成一个实时 JWT。

`zoom = Zoom(API_KEY, API_SECRET)
jwt_token: bytes = zoom.generate_jwt_token()
jwt_token_str = jwt_token.decode('UTF-8')
print(jwt_token_str)`

使用下面的代码,它直接来自 Zoom 的 API 文档,来获得你的USER_ID

如果您与多个用户使用一个共享帐户,您可能需要登录您的 zoom 帐户,然后导航至 【我的帐户】 ,以明确哪些用户拥有您想要录制的云录像。下面的代码使用["users"][0](返回的第一个用户)作为示例,但是您可能需要根据哪个用户拥有您需要访问的云记录来调整索引号。

`conn = http.client.HTTPSConnection("api.zoom.us")

headers = { 'authorization': 'Bearer ' + jwt_token_str}

conn.request("GET", "/v2/users?page_size=30&status=active", headers=headers)

res = conn.getresponse()
data = res.read()
user_dict = json.loads(data.decode("utf-8"))
USER_ID = user_dict['users'][0]['id']

print(USER_ID)`

对于下一步,您可能需要在 url 请求中指定日期范围, Zoom API 文档中的自动生成向您展示了如何做。默认情况下,只返回最后一天的会议记录,因此,如果您想要录制的会议记录发生在那之前,您必须指定 per 格式。

‍From 在这里,你可以用下面的代码找到你想要访问的云录音的MEETING_ID。注意:meeting_dict['meetings']访问会议列表,但是我们将只使用第一个会议meeting_dict['meetings'][0]作为例子。

`conn = http.client.HTTPSConnection("api.zoom.us")

conn.request(
    'GET', '/v2/users/' + USER_ID +
    '/recordings?trash_type=meeting_recordings&mc=false&page_size=30',
    headers=headers
    )

res = conn.getresponse()
data = res.read()
meeting_dict = json.loads(data.decode("utf-8"))
MEETING_ID = str(meeting_dict['meetings'][0]['id'])

print(MEETING_ID)`

要获得download_url,添加下面的代码。

`conn.request(
    "GET", '/v2/meetings/' + MEETING_ID + '/recordings', headers=headers
    )

res = conn.getresponse()
data = res.read()

response_obj = (data.decode("utf-8"))

print(response_obj)`

之后,您现在可以将download_url据为己有了!

`meeting_dict = json.loads(response_obj)
download_url = meeting_dict['recording_files'][0]['download_url']
print(download_url)`

最后一次感谢 TriBloom 和 Caleb Spraul 帮助我找到了下一行代码,它让你的下载 URL 可以被 Zoom 和 AssemblyAI API 相互理解...

`authorized_url = download_url + "?access_token=" + jwt_token_str`

将音频文件提交给 assembleia 进行转录

下面的代码使用authorized_url变量将缩放云记录 mp4 直接输入 AssemblyAI 的语音识别 API。

`endpoint = 'https://api.assemblyai.com/v2/transcript'

json = {
    'audio_url': authorized_url
}

heads = {
    'authorization': ASSEMBLY_AI_TOKEN,
    'content-type': 'application/json'
}

resp = requests.post(endpoint, json=json, headers=heads)
print(resp.json())`

成功的响应应该是这样的,显示"status": "queued"‍

`{
    # keep track of the id for later
    "id": "5551722-f677-48a6-9287-39c0aafd9ac1",
    # note that the status is currently "queued"
    "status": "queued",    
    "acoustic_model": "assemblyai_default",
    "audio_duration": null,
    "audio_url": "some/obscenely/long/zoom/api/url/",
    "confidence": null,
    "dual_channel": null,
    "format_text": true,
    "language_model": "assemblyai_default",
    "punctuate": true,
    "text": null,
    "utterances": null,
    "webhook_status_code": null,
    "webhook_url": null,
    "words": null
}`

获得您一直渴望的转录!

下面的代码将检查转录的状态,并为您将转录 id resp.json()['id']连接到 url,因此它将与前面的代码顺序运行。

`status_point = 'https://api.assemblyai.com/v2/transcript/' + resp.json()['id']

status_header = {'authorization':ASSEMBLY_AI_TOKEN} 

status_check = requests.get(status_point, headers=status_header)

print(status_check.json())`

音频文件需要大约 25%的音频时间来完成,因此 10 分钟的音频文件将在 2.5 分钟内完成。您将希望循环运行上面的代码,直到status键显示"completed"为止。

`import time

while status_check.json()['status'] in ['queued', 'processing']:
  status_check = requests.get(status_point, headers=status_header)
  time.sleep(5)
  continue

print(status_check.json()['status'])
print('\n', status_check.json()['text'])
print('\n', status_check.json())`

一旦status"completed",第二个打印语句print(status_check.json()['text'])将打印出实际的转录文本。第三个 print 语句打印出整个 API 响应,其中包含大量元数据,比如每个单词的发音时间、每个单词的置信度等等!你可以在的 AssemblyAI 文档上看到 API 响应 JSON 的完整示例。

现在你知道如何转录变焦记录!

posted @ 2024-10-31 16:48  绝不原创的飞龙  阅读(3)  评论(0编辑  收藏  举报