https://blog.tensorflowcn.cn/2018/08/getting-alexa-to-respond-to-sign-language-using-webcam-tensorflow-js.html
作者 Abhishek Singh
几个月前,我躺在床上,一个想法突然出现在我的脑海中——“如果语音是未来计算界面的方向,那么那些无法听到或说话的人怎么办?”。我不知道是什么触发了这个想法,我自己可以说话和听,也没有任何聋哑的亲近的人,也没有语音助手。也许是无数的关于语音助手激增的文章,或者大型公司之间争夺成为您首选的语音激活家庭助手的竞争,或者仅仅是在朋友家的柜台上更频繁地看到这些设备。由于这个问题始终无法从我的记忆中消失,我知道我需要解决它。
最终,它促成了这个项目,一个概念验证,我让一个
Amazon Echo 响应手语——更准确地说是美国手语(ASL),因为与口语类似,手语也有多种形式。
VIDEO
虽然我本可以简单地发布代码,但我选择发布一个演示系统的视频,因为我觉得很多机器学习项目都缺乏视觉元素,这使得人们难以与它们产生联系和理解它们。我还希望这种方法能够帮助将注意力从项目的科技元素转移到人性元素上——重点不是底层的技术,而是这种技术为我们人类提供的功能。
现在视频已经发布了,这篇博文将探讨底层技术以及如何使用
TensorFlow.js 构建系统。您还可以玩一个
实时演示 。我把它放在一起,这样您就可以用您自己的词语和手语/姿势组合来训练它。附近有一个可以响应您的请求的 Echo 是完全可选的。
早期研究 对于这个实验,我想要组合起来系统的更广泛的部分,很早就出现在我的脑海中。我知道我需要
一个神经网络来解释手势(即,将手语视频转换为文本)。
一个文本到语音系统,将解释后的手势说给 Alexa 听
一个语音到文本系统,将 Alexa 的响应转录给用户
一个设备(笔记本电脑/平板电脑)来运行这个系统,以及一个 Echo 来进行交互
一个将所有这些结合在一起的界面
我可能在早期花了最多的时间来决定哪种神经网络架构最适合这种情况。我想出了几个选项
1) 由于手势既有视觉方面也有时间方面,我的直觉是将 CNN 与 RNN 结合起来,其中最后一个卷积层的输出(在分类之前)作为序列馈送到 RNN。我后来发现这些的专业术语是长期循环卷积网络(LRCN)。
2) 使用一个 3D 卷积网络,其中卷积将在三个维度上应用,前两个维度是图像,第三个维度是时间。但是这些网络需要大量的内存,而我希望能够在我的 7 年历史的 macbook pro 上训练任何我能训练的东西。
3) 而不是在视频流中的单个帧上训练 CNN,而是仅在光流表示上训练它,光流表示将表示两个连续帧之间明显的运动模式。我这样想的目的是,它将编码运动,从而产生一个更通用的手语模型。
4) 使用一个双流 CNN,其中空间流将是一个单帧(RGB),而时间流将使用光流表示。
进一步的研究让我发现了一些论文,这些论文至少使用了一些上述方法来进行视频活动识别(最常见的是在 UFC101 数据集 上)。然而,我很快意识到,限制我的不仅仅是我的计算能力,还有我从头开始解读和实现这些论文的能力,经过几个月的偶尔研究和定期放弃项目去做其他项目,我没有任何有希望的成果可以展示。
我最终选择的方案完全不同。
进入 TensorFlow.js TensorFlow.js 团队一直在发布有趣的小型基于浏览器的实验,既是为了让人们熟悉机器学习的概念,也是为了鼓励人们将它们用作自己项目的构建块。对于那些不熟悉它的人来说,TensorFlow.js 是一个开源库,它允许您使用 Javascript 直接在浏览器中定义、训练和运行机器学习模型。有两个演示似乎特别有趣,可以作为起点——
吃豆人网络摄像头控制器 和
可教学机器 .
虽然它们都从网络摄像头获取输入图像并根据训练数据输出预测,但内部机制却有所不同
1) 吃豆人网络摄像头——这使用了一个卷积神经网络 (CNN),它接收一个输入图像(来自网络摄像头),并将其通过一系列卷积层和最大池化层。利用它,它能够提取图像的主要特征,并根据它所训练的示例预测其标签。由于训练是一个昂贵的过程,它使用了一个名为 MobileNet 的预训练模型进行迁移学习。该模型是在 1000 个 ImageNet 类上训练的,但经过优化,可以在浏览器和移动应用程序中运行。
2) 可教学机器——这使用了一个 kNN(k-近邻),它非常简单,从技术上来说根本没有执行任何“学习”。它接收一个输入图像(来自网络摄像头),并通过查找最接近该输入图像的训练示例的标签(使用相似度函数或距离度量)来对其进行分类。但是,在馈送到 kNN 之前,图像首先会通过一个小型的称为 SqueezeNet 的神经网络。然后,来自该网络倒数第二层的输出被馈送到 kNN,这使您能够训练自己的类。这样做的好处,而不是直接将网络摄像头中的原始像素值馈送到 kNN,在于我们可以使用 SqueezeNet 已经学习到的高级抽象,从而训练出一个更好的分类器。
现在您可能想知道,手势的时间特性如何?这两个系统都每帧接收一个输入图像,并做出预测,而不会考虑之前的帧。这难道不是之前研究 RNN 的主要目的吗?这难道不是真正理解手势所必需的吗?好吧,在从在线资源学习 ASL 期间,我意识到,在执行手势时,您手部的起始和结束手势和位置在不同的手势之间差异很大。虽然发生在两者之间的所有内容对于与另一个人进行交流可能都是必要的,但对于仅使用起始和结束位置的机器来说,应该是足够的。因此,与流行的说法相反,我决定不关注旅途,而是关注目的地。决定使用 TensorFlow.js 也在其他方面 proved 很有帮助
我可以在不编写任何代码的情况下使用这些演示进行原型设计。我通过在浏览器中运行原始示例来开始早期原型设计,用我打算使用的姿势对其进行训练,并查看系统的性能——即使输出意味着吃豆人会在屏幕上移动。
我可以使用 TensorFlow.js 直接在浏览器中运行模型。从可移植性、开发速度和轻松与 Web 界面交互的角度来看,这意义重大。此外,模型完全在浏览器中运行,无需将数据发送到服务器。
由于它将在浏览器中运行,我可以很好地将它与现代浏览器支持的语音到文本和文本到语音 API 结合起来,而我需要使用这些 API。
它使测试、训练和调整变得非常快,而这在机器学习中往往是一个挑战。
由于我没有手语数据集,而且训练示例基本上是我反复执行手势,因此使用网络摄像头来收集训练数据非常方便。
在彻底测试了这两种方法,并意识到这两个系统在我的测试中表现相当后,我决定使用可教学机器作为我的基础,因为
kNN 在较小的数据集上实际上比 CNN 运行得更快/更好。它们在使用大量示例进行训练时会变得内存密集型,性能也会下降,但由于我知道我的数据集将很小,所以这不是问题。
由于 kNN 实际上并没有从示例中学习,因此它们在泛化方面的表现很差。因此,在完全由一个人做出的示例上训练的模型的预测不会很好地转移到另一个人身上。由于我将通过反复执行手势来训练和测试模型,所以这对我来说也不是问题。
团队开源了一个精简的项目模板 ,作为有用的起点。
工作原理 以下是系统从开始到结束的工作原理的概述
在浏览器中启动网站后,第一步是提供训练示例。这意味着使用网络摄像头重复捕获自己执行每个手语的动作。这相对比较快,因为持续按住特定的捕获按钮会持续捕获帧,直到您释放它,并将捕获的图像标记为相应的标签。我训练的系统包含 14 个单词,这些单词以各种组合可以让 我创建各种对 Alexa 的请求。
训练完成后,您进入预测模式。它现在使用来自网络摄像头的输入图像,并将其通过分类器运行,以根据之前步骤中提供的训练示例和标签找到其最近邻。
如果某个预测阈值被超过,它将在屏幕左侧添加标签。
然后我使用 Web 语音 API 进行语音合成 ,以说出检测到的标签。
如果说出的词是“Alexa”,它会导致附近的 Echo 唤醒并开始监听查询。另外值得注意的是,我创建了一个任意手势(右手握拳举在空中)来表示单词 Alexa,因为 ASL 中没有这个词的手势,而且反复拼写 A-L-E-X-A 会很烦人。
完成整个手语短语后,我再次使用 Web 语音 API 对 Echo 的响应进行转录 ,Echo 对查询做出响应,不知道它来自另一台机器。转录的响应显示在屏幕右侧,供用户阅读。
再次打出唤醒词,将清空屏幕并重新开始重复查询过程。
我还将所有
代码上传到 github ,并包含
实时演示 。随意使用和修改。
虽然系统运行得相当不错,但它确实需要一些粗略的技巧来帮助获得理想的结果并提高准确性,例如
确保只有在说出唤醒词 Alexa 后才能检测到手语。
添加一个包含所有训练示例的类别,我将其归类为“其他”,用于空闲状态(空背景、我站在旁边什么也不做等)。这可以防止错误地检测到单词。
在接受输出之前设置一个高阈值,以减少预测错误。
降低预测速率。而不是以最大帧速率进行预测,控制每秒的预测数量有助于减少错误预测。
确保已在该短语中检测到的词不会再次被视为预测对象。
由于手语通常会忽略对冠词和介词的手语,而是依靠语境来表达相同的意思,因此我在训练模型时加入了一些包含相应冠词或介词的词,例如天气、到列表等。
另一个挑战是准确地预测用户何时完成手语查询。这对准确转录至关重要。如果过早触发转录(在用户完成手语之前),系统将开始转录它自己的语音。另一方面,过晚的触发可能会导致它错过转录 Alexa 响应的一部分。为了克服这个问题,我实现了两种独立的技术,每种技术都有各自的优缺点
第一个选项是在添加单词进行训练时将某些单词标记为终止词。终止词是指用户只会在短语末尾打的手语。例如,如果查询是“Alexa,天气怎么样?”,那么将“天气”标记为终止词,就可以在检测到该词时正确触发转录。虽然这很有效,但它意味着用户必须记住在训练期间将单词标记为终止词,并且还依赖于该词只出现在查询末尾的假设。这意味着重新构建您的查询以改为询问“Alexa,纽约的天气怎么样?”将是一个问题。演示使用了这种方法。
第二个选项是让用户打一个停止词,作为明确告诉系统他们已经完成查询的一种方式。识别到这个停止词后,系统就可以触发转录。因此,用户会打出 *唤醒词>*查询>*停止词*。这种方法的风险是用户可能会忘记完全打出停止词,导致转录根本无法触发。我在一个单独的github 分支 中实现了这种方法,您可以在其中使用唤醒词 Alexa 作为查询的书名号,即“Alexa,纽约的天气怎么样 *(Alexa)*?”。
当然,如果有一种方法可以准确地区分来自内部来源(笔记本电脑)的语音和来自外部来源(附近的 Echo)的语音,那么整个问题就可以解决,但这完全是另一个挑战。
展望未来,我认为还有许多其他方法可以解决这个问题,这可以作为您创建更健壮和更通用模型的项目的良好起点
Tensorflow.js 还发布了PoseNet ,使用它可能是一个有趣的方法。从机器的角度来看,跟踪帧中手腕、肘部和肩膀的位置应该足以对大多数单词进行预测。手指的位置在拼写时才重要。
使用基于 CNN 的方法(如吃豆人示例)可能会提高准确性,并使模型更能抵抗平移不变性。它还有助于更好地推广到不同的人身上。还可以包括保存模型或加载预先训练的 Keras 模型的能力,这一点在文档中得到了很好的说明。这样就不需要每次重启浏览器时都训练系统。
一些 CNN+RNN 或 PoseNet+RNN 的组合,用于考虑时间特征,可能会导致准确性提高。
使用 tensorflow.js 中包含的较新的可重用kNN 分类器 。
自从我第一次发布这个项目以来,它在社交媒体上被广泛分享,在媒体上被广泛报道,亚马逊甚至在 Echo Show 上为那些可能难以说话的人实现了一个辅助功能(点击 Alexa)。虽然我没有证据证明我的项目导致了他们实施该功能(时间非常巧合),但如果真是这样,那将非常酷。我希望将来,亚马逊 Show 或其他基于摄像头和屏幕的语音助手能够直接构建此功能。对我来说,这可能是我这个原型所展示的终极用例,并且能够让数百万新用户使用这些设备。
简化网络的复杂性并确定一个简单的架构来创建我的原型,这确实有助于快速将这个项目发布出去。我的目标不是解决整个手语到文本的问题。相反,它是为了开启关于包容性设计的对话,以一种平易近人的方式展现机器学习,并激励人们探索这个问题空间——我希望这个项目已经实现了这一点。
您可以在
shek.it 上查看我的更多项目,在
@shekitup 上关注我,或者在我的
github 上找到该项目的代码