伴随着这篇文章的代码可以在订阅后收到
*表示需要
电子邮件地址*
当我还是个孩子时,几乎每个超级英雄都有一台语音控制的电脑。因此,你可以想象我第一次遇到Alexa时,对我来说是多么深刻的体验。我心中的那个孩子是如此的高兴和兴奋。当然,后来我的工程本能开始发挥作用,我分析了这些设备的工作原理。
结果发现他们有神经网络来处理这个复杂的问题。事实上,神经网络将问题简化了很多,以至于今天在你的电脑上用Python做一个这样的应用程序是很容易的。但它并不总是这样。早在1952年,三个贝尔实验室的研究人员就进行了首次尝试。
然而今天我们可以用Tensorflo.js在浏览器中进行语音识别。在这篇文章中,我们将介绍:
- 转移学习
- 语音识别是如何工作的?
- 演示
- 用Tensorflow.js实现
1.转移学习
卷积神经网络(CNN).今天,转移学习被用于其他类型的机器学习任务,如NLP和语音识别。我们将不详细讨论什么是CNN以及它们如何工作。然而,我们可以说,CNN在2012年打破了ImageNet大规模视觉识别挑战赛(ILSVRC)的记录之后,就开始流行起来。
这个比赛评估了大规模的物体检测和图像分类的算法。他们提供的数据集包含1000个图像类别和超过120万张图像。图像分类算法的目标是正确预测物体属于哪个类别。自2012年以来,这个比赛的每个获胜者都使用了CNN。

训练**深度神经网络**可能需要计算和耗费时间。为了获得真正的好结果,你需要大量的计算能力,这意味着大量的GPU,这意味着......嗯,大量的钱。当然,你可以训练这些大的架构,并在云环境中获得SOTA结果,但这也是相当昂贵的。
有一段时间,这些架构对普通开发者来说是不可用的。然而,转移学习的概念改变了这一点。特别是,对于我们今天要解决的问题--图像分类。今天我们可以使用最先进的架构,这些架构在ImageNet 比赛中获胜, ,这要归功于迁移学习和预训练模型。
1.1 预训练模型
此刻人们可能会问:"什么是预训练模型?"。从本质上讲, 预训练模型 是一个保存的网络,它之前在一个大型数据集上训练过,例如在 ImageNet 数据集上。 你可以通过两种方式来使用这些模型。你可以把它作为开箱即用的解决方案,或者你可以把它与 迁移学习一起使用 。 由于大型数据集通常用于一些全局性的解决方案,你可以定制一个预训练的模型,并 为某些问题专门 。
这样你就可以利用一些最著名的神经网络,而不会在 训练上损失太多的时间和资源 。此外,你还可以 通过修改所选层的行为,对这些模型进行微调 。整个想法围绕着使用预训练的CNN模型的低层,并添加额外的层,为特定的问题定制架构。

从本质上讲,严重的转移学习模型通常由 两个部分组成。我们称它们为骨干和头部。 骨干 ,通常是在 ImageNet 数据集上预训练的深度架构,没有顶层。Head 是图像分类模型的一部分,用于预测自定义的类别。
这些层是在预训练的模型之上添加的。通过这些系统,我们有两个阶段:瓶颈期和训练期。在瓶颈阶段,特定数据集的图像通过骨干架构运行,并存储结果。在训练阶段,骨干网的存储输出被用来训练自定义层。

有几个领域适合使用预训练的模型,语音识别就是其中之一。这个模型被称为语音命令识别器。本质上,它是一个JavaScript模块,能够识别由简单的英语单词组成的口语命令。
默认词汇 "18w "包括以下词汇:从 "0 "到 "9 "的数字、"上"、"下"、"左"、"右"、"走"、"停"、"是"、"否"。另外还有 "未知词 "和 "背景噪音 "的类别。除了已经提到的"18w "词典外,还有更小的" *directional4w "*词典可用。它只包含四个方向性的词("上"、"下"、"左"、"右")。
2.语音识别是如何工作的?
当涉及到神经网络和音频的结合时,有很多方法。语音通常使用某种递归神经网络或LSTM来处理。然而,语音命令识别器使用的是简单的架构,被称为卷积神经网络,用于小范围的关键词识别。
这种方法是基于图像识别和卷积神经网络,我们在上一篇文章中研究过。乍一看,这可能令人困惑,因为音频是一个跨时间的一维连续信号,而不是一个二维空间问题。
2.1 频谱图
这个架构是利用频谱图的。那是一个信号的频率频谱随时间变化的可视化表示。从本质上讲,词应该适合的时间窗口被定义。
这是通过将音频信号样本分组为片段来完成的。完成后,对频率的强度进行分析,并定义可能的词段。然后,这些片段被转换为频谱图,例如,用于单词识别的单通道图像。

使用这种预处理方法制作的图像然后被送入多层卷积神经网络。
3.演示
你可能已经注意到,这个页面要求你允许使用麦克风。这是因为我们在这个页面中嵌入了实施演示。为了使这个演示能够工作,你必须允许它使用麦克风。

现在,你可以使用 "上"、"下"、"左 "和 "右 "命令在下面的画布上作画。来吧,试试吧。
4.用TensorFlow.js实现
4.1 HTML文件
首先,让我们看看我们实现的index.html文件。在之前的一篇文章中,我们介绍了几种安装TensorFlow.js的方法。其中之一是将其集成到HTML文件的脚本标签中。这也是我们在这里要做的。除此之外,我们需要为预训练的模型添加一个额外的脚本标签。下面是index.html的样子。
<html>
<head>
<script src="https://unpkg.com/@tensorflow/tfjs@0.15.3/dist/tf.js"></script>
<script src="https://unpkg.com/@tensorflow-models/speech-commands@0.3.0/dist/speech-commands.min.js"></script>
</head>
<body>
<section class='title-area'>
<h1>TensorFlow.js Speech Recognition</h1>
<p class='subtitle'>Using pretrained models for speech recognition</p>
</section>
<canvas id="canvas" width="1000" height="800" style="border:1px solid #c3c3c3;"></canvas>
<script src="script.js"></script>
</body>
</html>
包含这个实现的JavaScript代码位于script.js中*。这个文件应该与index.html文件位于同一个文件夹中。为了运行这整个过程,你所要做的就是在你的浏览器里面打开index.html*,并允许它使用你的麦克风。
4.2 脚本文件
现在,让我们来看看script.js文件,整个实现都在这里。以下是主函数的情况 运行函数的样子。
async function run() {
recognizer = speechCommands.create('BROWSER_FFT', 'directional4w');
await recognizer.ensureModelLoaded();
var canvas = document.getElementById("canvas");
var contex = canvas.getContext("2d");
contex.lineWidth = 10;
contex.lineJoin = 'round';
var positionx = 400;
var positiony = 500;
predict(contex, positionx, positiony);
}
这里我们可以看到应用程序的工作流程。首先,我们创建一个模型的实例,并把它分配给全局变量识别器。我们使用 'directional4w' 字典,因为我们只需要 '上'、'下'、'左'和'右'命令。
然后我们等待模型被加载。如果你的网络连接很慢,这可能需要一些时间。一旦完成,我们就初始化画布,在上面进行绘画。最后,调用predictmethod。下面是该函数内部发生的事情。
function calculateNewPosition(positionx, positiony, direction)
{
return {
'up' : [positionx, positiony - 10],
'down': [positionx, positiony + 10],
'left' : [positionx - 10, positiony],
'right' : [positionx + 10, positiony],
'default': [positionx, positiony]
}[direction];
}
function predict(contex, positionx, positiony) {
const words = recognizer.wordLabels();
recognizer.listen(({scores}) => {
scores = Array.from(scores).map((s, i) => ({score: s, word: words[i]}));
scores.sort((s1, s2) => s2.score - s1.score);
var direction = scores[0].word;
var [x1, y1] = calculateNewPosition(positionx, positiony, direction);
contex.moveTo(positionx,positiony);
contex.lineTo(x1, y1);
contex.closePath();
contex.stroke();
positionx = x1;
positiony = y1;
}, {probabilityThreshold: 0.75});
}
这个方法正在做繁重的工作。实质上,它运行了一个无尽的循环,在这个循环中,识别器在听你所说的话。请注意,我们使用的参数是probabilityThreshold。
这个参数定义了回调函数是否应该被调用。基本上,只有当最大的概率分数大于这个阈值时,才会调用回调函数。当我们得到这个词时,我们会得到我们应该绘制的方向。

然后我们用函数calculateNewPosition计算出线的末端的坐标。这一步是10像素,意味着线的长度将是10像素。你可以在概率阈值和这个长度值上做文章。一旦我们得到新的坐标,我们就用canvas来画线。就这样了。很简单,对吗?
总结
在这篇文章中,我们看到了我们如何能够轻松地使用TensorFlow.js的预训练模型。它们是一些简单应用的良好起点。我们甚至建立了一个此类应用的例子,你可以用语音命令来绘画。这是非常酷的,可能性是无限的。当然,你可以进一步训练这些模型,获得更好的结果,并将它们用于更复杂的解决方案。这意味着,你可以真正利用转移学习。然而,这是另一个故事了。
谢谢您的阅读!