Alexa、Siri、小度……各种语音助手令人眼花缭乱,但这些设备多是针对能力健全的用户,忽略了听、说能力存在障碍的人群。本文作者敏锐地发现了这一 bug,并训练亚马逊语音助手 Alex 学会识别美式手语。项目发布之后受到社交媒体的热捧。本博文将介绍项目的底层技术以及如何使用 TensorFlow.js 构建该系统。
数月前的某个夜晚,我躺在床上时,一个念头闪过我的脑海——「如果语音是计算接口的未来,那么那些听不见或看不见的人该怎么办?」我不知道究竟是什么触发了这个想法。我自己能听、能说,周围也没有聋哑人,而且我也没有语音助手。也许是因为无数语音助理方面的文章突然出现,也许是因为各大公司争相让你选择它们的语音助手产品,或许只是因为经常在朋友的桌上看到这些设备。由于这个问题无法从记忆中消失,我知道我需要仔细考虑它。
上面提到的念头最终成为了这一项目的引子。这是一个概念的证明,其中我利用 Amazon Echo 对手语产生应答——更准确的说是美式手语(ASL),因为正如口语一样,手语也有很多种类。
虽然我可以简单地公布代码,但我选择发布一个演示系统的视频,因为我觉得很多机器学习项目缺乏视觉元素,这使得人们难以使用和理解它们。此外,我希望这种方法能让人们不过度关注项目的技术元素,而关注人类元素——不看重项目的底层技术,而重视这种技术为我们人类提供的能力。
既然该视频已经发布,本博文将介绍项目的底层技术以及如何使用 TensorFlow.js (http://js.tensorflow.org/) 构建该系统。你还可以使用现场 demo 演示。我把它们放在一起,这样你就可以用自己的单词—符手势/姿态集来训练它。你可以自行选择附近是否放一个 Echo 来响应你的请求。
早期研究
很早之前我就明白这个实验所需要组合的大模块是什么。我知道我需要:
1. 用于解释手势的神经网络(即将手势视频转换为文本)
2. 文本到语音系统,向 Alexa 说出理解到的手势
3. 语音到文本系统,为用户转录 Alexa 的响应
4. 运行此系统的设备(笔记本电脑/平板电脑)和与之交互的 Echo
5. 将这一切联系在一起的接口
我好像花了很多时间来决定哪种神经网络架构最适合这个任务。我提出了以下几个选择:
1) 由于手势有视觉和时间两个方面,我的直觉是将 CNN 与 RNN 进行组合,其中最后一个卷积层的输出(在分类之前)作为序列馈入 RNN。我后来发现,这种网络的技术术语是长期循环卷积网络(LRCN)。
2) 使用 3D 卷积网络。其中卷积将以三维方式应用,前两个维度是图像,第三个维度是时间。然而,这些网络需要大量的内存,但我希望在用了 7 年的 macbook pro 上实现这个训练。
3) 不在视频流中对各个帧进行 CNN 训练,而是仅在光流表征上训练。该光流表征将表示两个连续帧之间的表观运动(apparent motion)的模式。对此我的想法是,它会对动作进行编码,形成更为通用的手语模型。
4) 使用双流 CNN,其中空间流将是单帧(RGB),时间流将使用光流表征。
在进一步研究中,我发现了一些论文,这些论文至少使用了上述视频活动识别方法中的几种(最常用于 UFC101 数据集)。然而,我很快就意识到我无法做到这一点。不仅仅是因为我的计算能力有限,而且我从头开始学习和实现这些论文的能力也有限。经过几个月断断续续的研究,而且因为其他项目的原因时常将这个项目搁置,我没有可以展示的预期输出。
最后我使用的方法是完全不同的。
使用 Tensorflow.js
TensorFlow.js(https://js.tensorflow.org/)团队已经开展了基于浏览器的有趣实验。它既可以让人们熟悉机器学习的概念,又鼓励人们把这些项目用作自己项目的组成部分。对于那些不熟悉它的人来说,TensorFlow.js 是一个开源库,允许你使用 Javascript 直接在浏览器中定义、训练和运行机器学习模型。可以从以下两个 demo 入手:Pacman Webcam Controller和 Teachable Machine。
虽然它们都从网络摄像头获取输入图像并根据训练数据输出预测,但在内部,每个操作都不同:
1) Pacman Webcam - 它使用卷积神经网络(CNN),来自网络摄像头的图像输入之后,经过一系列卷积层和池化层传递出去。使用它可以提取图像的主要特征,并根据已经训练好的例子预测其标签。由于训练过程开销很大,它使用一个名为 MobileNet 的预训练模型进行迁移学习。该模型在 1000 个 ImageNet 类上进行了训练,但经过优化,可在浏览器和移动应用程序中运行。
2) Teachable Machine - 使用 kNN(k-Nearest-Neighbors)方法。它非常简单,从技术上讲根本不执行任何「学习」。它采用输入图像(来自网络摄像头),并通过使用相似度函数或距离度量的方法找到最接近该输入图像训练样本的标签来对其进行分类。然而,在馈入 kNN 之前,图像首先通过名为 SqueezeNet 的小型神经网络。然后,将该网络倒数第二层的输出馈入 kNN,这样就可以训练自己的类了。这种做法的好处是,我们可以使用 SqueezeNet 已经学习过的高级抽象馈入 kNN,而不是直接从网络摄像头向 kNN 提供原始像素值,从而能训练出结果更好的分类器。
现在,你可能想知道,这些手势的时间性质该如何处理呢?这两个系统都逐帧拍摄输入图像,并在不考虑之前帧的情况下进行预测。难道真正了解手势并不必要?当我从在线资源中为了此项目学习 ASL 时,我发现在表示一个手势的时候,不同手势之间开始和结束的手的姿势和位置变化非常大。虽然一个手势中间的变化过程对于人类间的交流而言是必要的,对于机器而言只使用手势的开始和结束却已经足够了。因此,与流行的语言相反,我不再专注于手势的变化过程,而是只在乎起点和终点。
决定使用 TensorFlow.js 被证明在其他方面也有作用:
1. 我可以在没有编写任何代码的情况下使用这些演示原型。通过简单地在浏览器中运行原始示例,我开始早期原型设计,对我打算使用的手势进行训练,并查看系统如何执行 - 即使输出意味着「吃豆人」在屏幕上移动。
2. 我可以使用 TensorFlow.js 在浏览器中直接运行模型。从可移植性、发展速度和与网页接口之间交互能力的角度来看,这个模型很大。另外,这些模型可以直接在浏览器中运行,而不需要将数据传到服务器中去。
3. 因为它将在浏览器中运行,所以我可以很好地将它与语音到文本以及文本到语音的 API 相连接,这正是现代浏览器支持和我需要使用的。
4. 它加快了测试、训练和调试的过程,这往往是机器学习中的一个挑战。
5. 由于我没有手语数据集,训练样本基本上是我重复地执行这些手势,所以使用网络摄像头来收集训练数据是方便的。
在彻底测试并发现这两个系统在我的测试中表现相当之后,我决定使用 Teachable Machine 作为我的基础系统,因为:
1. 在较小的数据集上,kNN 实际上可以比 CNN 运行地更快/更好。但是当使用大数据集进行训练时,它们就会消耗大量内存,性能下降,但是我知道我的数据集很小,所以这不是问题。
2. 由于 kNN 并未真正从示例中学习,所以它们的泛化能力很差。因此,对完全由某一个人创建的数据集上训练的模型的预测能力将不会很好地迁移到另一个人的数据集上。这对我来说也不是问题,因为训练集和测试集都是我自己反复给出的手势。
3. 团队已经开源了一个良好的项目简化样板(https://github.com/googlecreativelab/teachable-machine-boilerplate),可以作为一个有用的起点。
工作原理
以下是该系统工作流程的高级视图:
1. 在浏览器中进入网站后,第一步是提供训练样例。这意味着你要使用摄像头捕捉自己反复执行的每个手势。这是相对较快的方法,因为按住特定的捕获按钮可以连续捕获帧,直到你松开按钮并使用适当的标签标记捕获的图像。我训练的系统包含 14 个单词,这些单词可以有多种组合,这就允许我为 Alexa 创建各种请求。
2. 训练完成后,进入预测模式。它现在通过网络摄像头读取图像并跑一遍分类器,再根据上一步中提供的训练集和标签找到其最近的帧。
3. 如果超过某个预测阈值,它会将标签追加到屏幕的左侧。
4. 然后,我使用网页端 API 进行语音合成,用以说出检测到的标签。
5. 如果说出的单词是 ‘Alexa‘,它会唤醒附近的 Echo 并开始监听指令。另外值得注意的是 - 我创造了一个任意的标志(举起右拳)来表示 Alexa 这个词,因为这一动作并不对应 ASL 中已有的单词,并且反复拼写 A-L-E-X-A 用户体验不好。
6. 一旦整个手势短语完成,我再次使用网络语音 API 来转录 Echo 的响应,该响应用于回复查询而不知道它来自另一台机器。转录的响应显示在屏幕的右侧,供用户阅读。
7. 再次输入唤醒关键字,清除屏幕并开始重复查询的过程。
虽然系统工作得相对较好,但确实需要一些技术人员帮助它获得理想的结果并提高准确性,例如:
1. 确保不会检测到任何符号,除非已经说过唤醒词 Alexa。
2. 添加一个完整的全部类别的训练集,我将空闲状态归类为「其他」(空背景,我懒散地垂着手臂站着等等)。这可以防止误检单词。
3. 在接受输出之前设置高阈值以减少预测错误。
4. 降低预测率。不要以最大帧速率进行预测,控制每秒的预测量有助于减少错误的预测。
5. 确保已在该短语中检测到的单词不再用于预测。
6. 由于手语通常会忽略手势说明,依赖语境来传达相同的内容,因此我使用某些单词训练模型,其中包括适当的说明或介词,例如天气、列表等。
另一个挑战是如何准确预测用户何时完成手势指令。这对于准确的转录不可或缺。如果过早触发转录(在用户完成手势之前),系统会开始将其转录成对应的语音。另一方面,过晚触发可能会导致它错过 Alexa 的部分响应。为了克服这个问题,我实现了两种独立的技术,每种技术都各有优缺点:
1. 第一种选择是在将某些单词添加到训练阶段并将其标记为结束词。结束词即出现在用户手势短语末尾的单词。例如,如果查询指令是「Alexa,what』s the weather?(今天天气如何?)」,那么通过将「weather」标记为终端词,可以在检测到该词时正确地触发转录。虽然很有效,但这意味着用户必须在训练期间将单词标记为终端,并且假设这个单词仅出现在查询指令的结尾。这意味着将你的查询指令改成「Alexa,what』s the weather in New York?(纽约的天气怎么样?)」将会导致问题。演示中使用了这种方法。
2. 第二种选择是让用户指定一个结束词,作为让系统知道他们已经完成查询的引导方式。在识别出这个结束词时,系统可以触发转录。因此,用户将遵循 Wakeword> Query> Stopword。这种方法存在用户完全忘记给出结束词的风险,导致转录根本没有触发。我已经在一个独立的 github branch (https://github.com/shekit/alexa-sign-language-translator/tree/stopword) 中实现了这种方法,你可以使用唤醒词 Alexa 作为你的查询的结束词,即「Alexa,what』s the weather in New York (Alexa)?(纽约天气如何(Alexa))?」。
当然,如果有一种方法可以准确区分来自内部源(笔记本电脑)的语音和来自外部源(附近的 Echo)的语音,那么整个问题就可以解决,但这完全是另一个挑战。
进一步探讨,我认为还有很多其他方法可以解决这个问题,这可能是为你自己的项目创建更鲁棒更通用模型的良好起点:
1. Tensorflow.js 还发布了 PoseNet,使用它可能是一种有趣的方法。从机器的角度来看,跟踪手腕、肘和肩膀在图片中的位置应足以用大多数单词进行预测。在拼写出某些东西时,手指的位置往往很重要。
2. 使用基于 CNN 的方法(如「吃豆人」示例)可以提高准确性并使模型更能抵抗平移不变性。它还有助于更好地泛化到不同的人。还可以包括保存模型或加载预先训练的 Keras 模型的能力,该模型已被存档。这样每次重启浏览器时都不必重新训练系统。
3. 考虑时间特征的 CNN + RNN 或 PoseNet + RNN 的某种组合可能会提高准确性。
4. 使用 tensorflow.js 中包含的较新的可重用 kNN classifier (https://github.com/tensorflow/tfjs-models/tree/master/knn-classifier)。
自我第一次发布这个项目以来,它已在社交媒体上广泛分享,被媒体热捧,甚至亚马逊在 Echo Show 上为那些可能难以说话的人实现了一个辅助功能(Tap to Alexa)。虽然我没有证据表明我的项目是否影响他们实现了这个功能(时间非常巧合),但如果确实如此,那将是非常不错的。我希望将来 Amazon Show 或其他基于摄像头和屏幕的语音助手可以直接构建此功能。对我来说,这可能是这个原型展示的最终用例,并且能够向数百万新人开放这些设备。
降低网络的复杂性,同时建立一个简单的架构来创建我的原型架构肯定有助于快速实现这个项目。我的目的不是解决整个手语转化文本的问题。相反,它围绕包容性设计开展对话,以平易近人的方式呈现机器学习,并激励人们探索这个问题空间 - 我希望这个项目能实现这一点。
原文地址:https://medium.com/tensorflow/getting-alexa-to-respond-to-sign-language-using-your-webcam-and-tensorflow-js-735ccc1e6d3f?linkId=55302800
原文地址:https://www.cnblogs.com/alan-blog-TsingHua/p/9827685.html