CPU 实时人脸识别
看完这篇文章,你就会明白如何利用预先训练好的模型,用 CPU 构建实时人脸识别系统。
Static face recognition with system described in this post
学术和工业领域都投入了巨大的努力来开发既快速又准确的人脸识别算法和模型。由于这些努力,现在可以用 CPU 完成多张人脸的准确、实时的人脸识别。
在这篇文章中,我们将使用林扎尔和 MobileFaceNet 的超轻型人脸检测器构建一个实时人脸识别系统。
人脸检测
为了识别人脸,我们首先需要从图像中检测人脸。有许多方法可以做到这一点。
我已经探索了多种面部检测器。其中包括人脸识别包(包含方向梯度直方图(HOG)和卷积神经网络(CNN)检测器) MTCNN 、 Yoloface 、 Faced ,以及最近发布的超轻人脸检测器。
我发现,虽然 Yoloface 具有最高的准确性和最一致的执行时间,但超轻人脸检测器在速度方面是无与伦比的,并产生了相对较好的准确性。
在这篇文章中,我们将使用超轻型探测器。但是如果你有兴趣应用提到的任何其他检测方法,你可以在这里参考我的 Github 库。
要使用超轻模型,需要以下 python(python 3.6 版)包:
onnx==1.6.0``onnx-tf==1.3.0``onnxruntime==0.5.0``opencv-python==4.1.1.26
使用pip install
安装所有的依赖项。
准备好环境后,我们可以通过以下代码使用 OpenCV 库从我们的网络摄像头获取帧馈送:
对于我们获取的每个帧,我们需要在模型训练阶段遵循精确的预处理流水线,以实现预期的性能。
由于我们将使用预训练的[ultra_light_640.onnx](https://drive.google.com/open?id=1EDOJtWE_rnotlHZBRoYvPotRHr9PghxY)
模型,我们必须将输入图像的大小调整为 640x480。如果您使用的是 320 型号,请相应地重新设置。
代码如下所示:
在预处理图像之后,我们将必须准备 ONNX 模型并创建一个 ONNX 推理会话。想了解更多关于模型推断的内容,可以查看这里的链接。
准备模型和创建推理会话的代码如下所示:
现在是时候用下面的代码检测一些人脸了:
变量confidences
包含了boxes
变量中每个框的置信水平列表。一个置信度对的第一和第二值分别指示包含背景和人脸的概率。
由于boxes
值包含了所有生成的盒子,我们将不得不根据相应的 Jaccard 索引(也称为 Union 上的交集)来识别具有包含面部的高概率的盒子并移除重复的盒子。
获得正确框的代码如下所示:
predict
函数将接受一个盒子数组,以及每个标签对应的置信度。然后,将执行置信度过滤,以保留所有包含人脸的概率较高的框。
之后,计算每个剩余盒子的交集(IOU)值。最后,使用具有硬 IOU 阈值的非最大抑制来过滤方框,以移除相似的方框。
一旦我们有了过滤框,我们就可以在视频流中绘制和显示:
英特尔酷睿 i7–8550 u CPU @ 1.80 GHz 笔记本电脑网络摄像头的结果:
检测部分的完整代码可以在这里找到。
人脸识别
检测到人脸后,下一步是识别它们。面部识别的技术有很多,包括 OpenFace 、 FaceNet 、 VGGFace2 、 MobileNetV2 等。本文中我们将使用的模型是 MobileFaceNet,它的灵感来自于 MobileNetV2。这个网络架构的细节以及如何训练可以在这里找到。
一般来说,识别一张人脸需要三个步骤:(1)数据预处理,(2)人脸特征提取,以及(3)比较目标人脸和数据库中人脸的特征。
预处理
我们将使用的数据是吉米·基梅尔采访詹妮弗·安妮斯顿的视频剪辑。我们将拍摄视频片段并提取詹妮弗·安妮斯顿的面部。您可以在相应的文件夹中添加自己的培训数据。
文件结构如下所示:
train.py
faces
--training
--rachel
--rachel.mp4
--...
--temp
--embeddings
一旦训练数据就绪,我们就可以使用下面的代码对视频剪辑执行人脸提取:
在boxes
里面抓拍人脸。现在,我们可以从人脸预处理开始。
我们将确定五个面部标志,通过适当的变换对齐面部,并将它们的大小调整为 112x112。
我们将使用dlib
和imutils
来完成这些子任务。如果您还没有安装这两个软件包,请使用pip install
进行安装。
满足要求后,我们需要用下面的代码启动shape_predictor
(用于面部标志预测)和FaceAligner
:
shape_predictor_5_landmarks.dat
用过的可以在这里下载。desiredLeftEye
指定你想要提取的人脸的大小。通常该值的范围是从 0.2 到 0.4。值越小,脸就越大。
下面的代码说明了如何在提取的所有面上应用面对齐并写入文件:
结果:
Eyes are aligned and faces are of similar sizes.
为了使用 MobileFaceNet 模型,需要进一步的预处理。我们必须用 127.5 减去对齐的面,然后用 128 除结果,如论文中所述。
用于如上所述的更多预处理的代码:
计算面部嵌入
是时候从预处理过的人脸中获取面部特征了。我们将从加载张量流模型开始:
接下来,我们将定义网络输入,获取嵌入并保存到 pickle 文件:
认出一张脸
要识别人脸,只需加载带有相应标签的嵌入数据集。然后使用欧几里德距离和阈值来确定每个检测到的人脸属于谁。
代码如下所示:
最后
让我们看看我们的结果:
Embeddings acquired for six main characters from Friends series
同样,你可以在这里找到完整的代码。
摘要
据此,我们创建了一个可以用 CPU 进行实时人脸识别的系统。虽然它的运行速度只有大约 13 FPS,但它比使用复杂的 CNN 要快得多。
然而,我们仍然可以做很多事情来提高这个系统的性能(精度和速度)。潜在地,我们可以应用知识提取来压缩当前模型,并使用低位量化来进一步减小模型大小。此外,我们可以使用其他机器学习分类方法来提高嵌入的准确率。
感谢您的阅读!希望这对您有所帮助。
敬请期待,再见~
参考
【2】:桑德勒、马克等《Mobilenetv2:反向残差与线性瓶颈》。IEEE 计算机视觉和模式识别会议录。2018 年
docker+OpenCV:1 分钟实时面部识别
集成 Docker、OpenCV.js 和 Nginx,快速部署实时面部识别机器学习模型。对于 Mac Docker 社区来说,这是一个方便的解决方案,他们正在努力获得网络摄像头的访问,因为 Docker hyper kit 支持的缺点在 Nginx 的帮助下。该解决方案可以很容易地扩展到包括 OpenCV、Keras、Tensorflow 等任何现成的机器学习模型…
动机:
- 虽然推荐从源代码构建 OpenCV.js,但是需要 LLVM-to-JavaScript 编译器和 CMAKE,这相当复杂。
- 由于 Docker 超级工具包支持的缺点,从 Docker 容器访问 Mac 网络摄像头是不可能的。因此,在 Mac 上部署实时面部识别模型是不可能的。
因此,我决定让任何人在 Docker 的帮助下在几秒钟内部署 OpenCV 模型变得尽可能容易。我通过使用夜间构建克服了点 1 ,通过使用 Nginx 克服了点 2 。这完全是为了让读者熟悉 Docker 的机器学习的部署方面,而不是为了建立面部识别的机器学习模型。
**项目结构:**从 Github repo 这里克隆项目。
.
├── Version1
│ ├── Dockerfile #Building the image
│ ├── docker-compose.yml #Defining the files for mounting
│ ├── CV #OpenCV.js soure code
| ├──js_face_recognition.html
| ├──opencv.js
| ├──utils.js
- Dockerfile
2。docker-compose.yml
请更新此文件中项目文件夹的路径。注意 Nginx 服务器被设置为在端口 80 上运行。
docker-compose.yml
CV 文件夹驻留了该项目的源代码,包括 OpenCV.js 的夜间构建。我使用了 OpenCV.js 官方网站的教程中的面部识别代码,也可以从 OpenCV 的官方 GitHub repo 中获得。他们提供的教程真的很有帮助,也是我学习大多数 OpenCV.js 应用程序的地方。
第一步:
#Clone the repo
git clone [git@github.com](mailto:git@github.com):gomesc166/MediumRepo.git#Go to ObjectDetection directory
cd Version1
第二步:
#Build the image
docker build -t object-detection-image .
第三步:
#Start the Container
docker-compose up
**注意:**编辑主机上项目的路径。
第四步:
在浏览器上访问 localhost:80
单击下载模型按钮。模型下载完成后,您可以添加任意多的人进行识别。如果您想要添加自定义的 Keras/Tensorflow 模型,您必须调整 JS 脚本。
如果您对代码有任何疑问,请留下您的回复,我会尽快回复您。我使用了官方 OpenCV.js 教程中的 JS 脚本。请记住,这篇文章的主要目的是让用户了解如何使用 Docker 轻松部署现成的模型,并克服在 Mac 上使用 Docker hyper kit 的限制。干杯…
通过 AWS 上的用户反馈支持票证分类的端到端数据管道
在 AWS 上建模和部署票据分类器
团队——Abhilasha kanit kar、Jitender Phogat、Pankaj Kishore
在本文中,我们将尝试解决一个真实的业务问题。在 IT 界,大多数生产问题都是以 IT 支持票的形式处理的。我们将首先介绍我们用于解决问题的数据集以及我们使用的模型,然后介绍我们如何在 AWS 上部署模型并能够进行实时预测。让我们开始吧。
一.动机
有几个平台用于处理支持票并跟踪它们,如 BMC Remedy、ServiceNow 等。每当提出一个问题,就会有人把票分配给他所知道的最相关的团队。
大多数时间票证没有直接分配给负责解决该问题的正确团队,而是在团队之间不断滚动,在到达相关团队之前,其 SLA 就过期了。有时,问题很严重,需要立即补救,这时候就会影响工作效率。
因此,我们想到使用机器学习来解决这个问题,并建立一个平台,该平台将自动为团队分配门票,并具有随着时间的推移进行学习和改进的能力。
这是整个工作流程的样子。
二。数据
我们使用了微软的支持票数据集,你可以在这里找到。为了简单和计算限制,我们使用这个数据集的一个子集。想法是有一个完整的框架/工作流程准备就绪,然后我们可以增加系统的复杂性。
三。模型
该项目的下一步是建立一个分类器模型,可以将不同的票证分类。我们之前使用 RNN 和 LSTM 做了这个分类,但这次我们选择保持模型简单,因为我们也想将它与 AWS 集成。这是大多数公司遵循的最佳实践,也是从简单模型开始的良好实践。
我们选择多项式朴素贝叶斯模型进行分类。朴素贝叶斯是一组基于应用贝叶斯定理的算法,假设每个特征相互独立,以预测给定样本的类别。它们是概率分类器,因此将使用贝叶斯定理计算每个类别的概率,并且具有最高概率的类别将被输出。
但是,为什么朴素贝叶斯分类器呢?
我们在处理 NLP 问题时确实有其他的替代方案,比如支持向量机(SVM)和神经网络。然而,朴素贝叶斯分类器的简单设计使得它们对此类分类器非常有吸引力。此外,在自然语言处理的许多应用中,它们被证明是快速、可靠和准确的。
四。数据预处理
对于文本分类,如果你自己通过抓取来收集数据,那么你可能会有一个杂乱的数据集,在应用任何模型之前,你必须付出很多努力来清理它并使它保持良好的形式。在我们的例子中,数据集并没有那么乱,所以我们不需要在这方面投入太多精力。因此,我们执行了以下非常常见但至关重要数据预处理步骤-
- 小写并删除停用词 —将整个输入描述转换为小写并删除停用词,因为它们不会给分类添加任何内容
- 词汇归类 —这将相同词汇的不同变化组合在一起,如 organize、organizing、organizing 等。
- n-grams — 使用 n-grams,我们可以计算单词的序列,而不是计算单个单词
为了执行分类,我们必须使用单词包技术以向量的形式表示输入描述。有两种方法可以做到这一点。
- 计算每个单词在文档中出现的次数
- 计算每个单词在文档中所有单词中出现的频率
矢量化(计数矢量化器)
它对词的频率起作用,即计数记号的出现并建立一个文档记号的稀疏矩阵
TF-IDF 变压器
TF-IDF 代表术语频率和逆文档频率。TF-IDF 权重是一种统计度量,用于评估一个单词对集合或语料库中的文档有多重要。重要性与单词在文档中出现的次数成比例增加,但是被单词在语料库中的频率抵消。
词频是一个词在特定文档中的出现频率。
逆文档频率为我们提供了一个术语稀有程度的度量。术语越稀有,IDF 分数越高。
动词 (verb 的缩写)模型拟合
现在我们已经准备好了数据,并将多项式朴素贝叶斯拟合到数据中来训练模型。我们创建了一个包含所有预处理步骤的 sklearn 管道,因为我们希望以向量的形式表示新的传入票证描述,这是在模型经过训练后获得的,而不是基于新的描述创建新的票证描述。
来自 sklearn.pipeline 导入管道
text_clf = Pipeline([('vect ‘,CountVectorizer(ngram_range=(1,2),stop _ words = stop words . words(’ English ‘)),(’ tfidf ‘,TfidfTransformer()),(’ clf ',MultinomialNB()),])
https://github . com/jitender 18/IT _ Support _ Ticket _ Classification _ with _ AWS _ Integration
创建模型后,我们在测试数据集上测试了模型性能,我们获得了相当好的 92.167%的准确率。然后,我们将模型导出到 pickle 文件中。
不及物动词与 AWS 集成
现在是项目最重要的部分,在 AWS 上部署模型并配置 AWS Lambda 函数进行实时预测。这是我们花了很多时间的地方。
首先,什么是 AWS Lambda,我们为什么要使用它?
AWS Lambda 是亚马逊提供的无服务器计算平台。它让我们可以运行代码,而不必担心服务器和资源的供应和管理。当你想运行 lambda 函数时,你必须定义事件触发器,只需上传你的代码,Lambda 就会处理好运行和缩放你的代码所需的一切。lambda 的一个优势是,你只需为代码的计算时间付费,也就是说,只有在代码运行时,你才需要付费,而在代码不运行时,你不需要支付任何费用。
让我们开始这个过程。
设置一个新的 EC2 实例
首先设置一个新的 EC2 实例,在这里你将安装所有你的代码(模型)在 Lambda 上运行时将会用到的库。设置新 EC2 实例的原因是,您将从头开始配置 python 环境并安装所有需要的库。
一旦你完成,你将压缩整个 python 环境以及你将在 Lambda 上运行的代码,并将其下载到你的本地机器,然后我们将把它上传到亚马逊 S3 桶。Lambda 函数将使用这个 zip 文件来执行。
每当发生调用 Lambda 函数的事件时,它将使用您指定的 zip 文件来执行。比方说,在事件上,我指定我将运行已经在 zip 文件中的 sample.py,然后 Lambda 函数将在该 zip 文件中寻找它需要的一切(python 环境和运行代码所需的库),如果缺少什么,那么代码的执行将会失败。
https://github . com/abhilasha 23/awsdata piline/blob/master/forlambdamlmodel . py
创建一个 Lambda 函数
一旦你准备好了 S3 水桶的压缩文件。然后你可以创建一个新的 Lambda 函数。
点击创建函数并提供一个有意义的名称,在运行时选择 Python 3.6,并可以选择最适合您需求的权限。
转到你的 lambda 函数,在函数代码部分,你必须上传一个 zip 文件,或者你可以指定在 S3 桶上存储的 zip 地址,如截图所示。
仅供参考—在屏幕截图中,函数是代码文件名(Function.py ),处理程序是将运行的文件中定义的方法名。
Specify the path of S3 link for the zip file
测试你的代码
您可以测试您的代码是否正确运行。单击右上角的测试选项卡,并配置一个测试事件。你可以传递你的代码需要的输入,然后你可以看到你的代码是否正在运行。
如屏幕截图所示,我们传递描述并运行代码。如果您使用我们的代码来尝试,那么您必须取消注释第 29 行,它将读取测试描述,并注释第 30 行,它从 AWS 队列读取输入,我现在将对此进行解释。
AWS SQS(简单队列服务)
通过从设计器选择框中选择 SQS 来创建 SQS 服务。这很简单。在这个 SQS 中,我们配置了两个队列。一个是将输入传递给 lambda 函数,我们在这个队列上有一个事件触发器,这意味着每当这个队列中有新消息时,它就会触发 Lambda 运行。
第二个是输出队列,它将显示输入消息的预测值。
Input and output queue
选择输入队列,并从队列操作中选择“发送消息”。单击提交按钮后,将触发 Lambda 函数,您的代码将运行并进行预测,然后将其写入输出队列。
正如您在屏幕截图中看到的,输出队列中可用的消息是 7,输入是 0,这意味着输入队列中没有新消息,您的 lambda 函数没有运行您的代码。
七。重新训练模型的用户反馈
我们创建了一个简单的 angular JS UI 来获取用户反馈。用户反馈的想法是,无论分类票正确与否,都要得到用户的认可。如果分类票是错误的类别,那么用户可以选择从下拉列表中选择正确的类别,并点击保存,这将把文件保存到 S3 桶。我们将使用这个文件定期重新训练我们的模型。
为此,我们设置了另一个 Lambda 函数,您可以根据需要安排它每天或每周运行。它将使用模型 pickle 文件来读取模型,重新训练模型并修改 pickle 文件。
结论
AWS Lambda 是可伸缩模型的一个非常好的选择,因为您不必担心服务器的供应和管理。它很容易部署模型,并根据您的需求自动扩展所需的资源,您只需在代码运行时付费,因此非常划算。
GitHub 链接:
https://github . com/jitender 18/IT _ Support _ Ticket _ Classification _ with _ AWS _ Integration
基于张量流的实时移动视频对象检测
全栈数据科学
向您的下一个移动应用程序添加对象检测的分步指南
Photo by GeoHey
随着人们对自动驾驶汽车、人脸识别、智能交通系统等计算机视觉用例的兴趣日益增加。人们正在寻求建立定制的机器学习模型来检测和识别特定的对象。
然而,从零开始构建定制模型需要大量的专业知识、时间和计算资源——从数据标注到模型服务。为了减少障碍,谷歌发布了开源工具,如tensor flow Object Detection API和 Tensorflow Hub ,使人们能够利用那些已经广泛使用的预训练模型,如更快的 R-CNN、R-FCN 和 SSD,使用迁移学习快速构建定制模型。
本文将展示我们如何使用 TensorFlow 的对象检测 API 来训练实时视频对象检测器,并通过以下步骤将其快速嵌入到我们自己的移动应用程序中:
- 设置开发环境
- 准备图像和元数据
- 模型配置和培训
- 将定型模型转换为 TensorFlow Lite
- 在移动应用程序中测试模型
设置环境
本文中的所有代码都基于 macOS & Linux 系统。对于 Windows 用户,你可以在 docker 容器中工作:
或者安装 Windows 子系统用于 Linux (由于主机硬件隔离,这个不支持 TensorFlow GPU)。
对于 VS 代码用户来说,remote WSL 和 Containers 的扩展也给出了更好的开发体验,应该完全兼容本文中的脚本。
设置项目目录
为了便于阅读,我们将在主项目目录中创建三个子文件夹:
数据— 存储模型数据的文件夹(如*。记录,*。csv 等。)
模型— 存储所有预训练模型及其配置文件的文件夹。
tf-models — 一个文件夹,其中包含来自 Tensorflow 的克隆模型代码,我们将在建模中使用这些代码。
使用下面的脚本复制上面的项目文件夹结构。
安装 Tensorflow 对象检测 API 和依赖项
一旦我们有了项目设置,Tensorflow 对象检测 API 现在应该位于rf-models/research/object_detection
中,代码库目前由社区维护,稍后我们将从那里调用模块进行模型训练。
(可选)对于 Tensorflow 对象检测 API 代码基础之上的任何进一步工作,请查看
model_main.py
和model_lib.py
作为起点。
现在我们需要安装其余的依赖项。要安装所需的 python 库:
安装 COCO API
注意:如果您在编译 COCO API 时遇到问题,请确保在编译之前已经安装了 Cython 和 Numpy。
安装 Protobufs — Tensorflow 对象检测 API 使用 Protobufs 来配置模型和训练参数。
向 PYTHONPATH 添加 Tensorflow 库
在本地运行时,rf-models/research/
和rf-models/research/slim
目录需要追加到 PYTHONPATH 中,以便将来自 TensorFlow 对象检测 API 的 python 模块添加到搜索路径中,它们将在稍后阶段从模型脚本中被调用。
注意:上述脚本需要在每个新的终端环境中运行。或者,您可以添加您的~/。以绝对路径作为永久解决方案的 bashrc 文件。
测试安装
要测试一切是否按预期运行:
您应该会看到如下测试输出:
准备图像和元数据
下载图像数据
我们使用的图像数据来自香港中文大学多媒体实验室创建的 DeepFashion 数据库。这是一个大规模的服装数据库,拥有超过 800,000 张不同的时尚图片,从造型优美的商店图片到无拘无束的消费者照片。
数据库中的所有图像都被标注了丰富的信息,包括 50 个不同的类别,1000 个描述性属性,边界框和服装标志。
特别地,我们使用“类别和属性预测基准”类别作为时尚对象检测任务的训练数据。
Photo by DeepFashion
在这里下载数据( Google Drive )并将它们解压到我们项目目录下的data
文件夹中。完成后将有三个子文件夹:
彦俊 —标注包括包围盒标签、时尚地标标签、服装类别标签、服装属性标签。
Eval—分别用于训练、验证和测试集的图像名称。
img—289222 张多样的服装图片。(为了加快开发速度,我们在本文中使用低分辨率图像)
我们先来看看数据
我从数据集中随机挑选了一些图像,并用它们的边框打印出来。
注意:由于 DeepFashion 数据库已经提供了边界框标签,我们不需要标记数据,而如果你想为其他图像创建自己的标签,或者改进当前的标签(正如我们在上面的图像中看到的,一些边界框的质量并不完美。 LabelImg 将是那些工作的工具之一。
我们还将使用图像元数据的聚合视图为训练集和测试集创建汇总表。汇总表将在稍后阶段用于为模型训练生成建模数据。
summary table — training set
可视化上述图像并生成汇总表的 python 脚本可以在这里找到 Jupyter 笔记本。因此,我们现在在data
文件夹中有了汇总表(train_labels.csv
& test_labels.csv
)。
注意:为了简化工作,您将在笔记本中看到我们只选择了前 6 个常用类别。
生成 TF 记录
为了高效地读取数据,TensorFlow 使用 TFRecord 格式,这是一种存储二进制记录序列的简单格式。它对数据进行序列化,使它们能够被线性读取,如果数据是通过网络传输的,这一点尤其正确。
为了将图像数据转换为 TFRecord 格式,我们将使用以下 python 模板,并将我们创建的汇总表作为参考:
注意:通过为新标签更新 class_text_to_int(),我们可以为其他数据集使用相同的模板。
一旦执行完成,你会在data
文件夹下看到两个新文件,分别命名为test.record
和train.record
。
生成标签地图
我们现在需要创建一个标签映射,即将每个使用的标签映射到一个整数值。训练和推理过程都将使用标签映射。
上面的脚本给了我们一个名为label_map.pbtxt
的新文件。如果我们想引入额外的新标签,我们需要相应地更新它。
现在,我们已经在data
文件夹中准备好了所有需要的文件。
模型配置和培训
下载预先训练的模型
正如我们在开始时提到的,我们将使用预训练模型,而不是从头开始设计模型,检测模型动物园收集广泛使用的预训练模型的列表。
例如,我们将使用 SSD mobilenet 量化模型,该模型针对移动设备性能进行了优化,降低了模型推理的复杂性(同时牺牲了一些模型性能)。
模型文件将保存在如下的models
文件夹下。
我们需要了解的一些文件是:
- model.ckpt —您的模型(预训练模型/部分训练模型)的检查点,带有用于进一步训练的估计器。
- pipeline.config —模型、训练数据、评估数据等的配置。
更新模型管道配置
pipeline.config
中有五个主要部分*。**模型*部分定义了网络的预设计架构。 train_config 部分定义模型训练参数,为我们提供调整参数的灵活性,如批量大小、学习速率、学习步骤等。
model {
(... Add model config here...)
}
train_config : {
(... Add train_config here...)
}
train_input_reader: {
(... Add train_input configuration here...)
}
eval_config: {
}
eval_input_reader: {
(... Add eval_input configuration here...)
}
对于我们的试验,我们将模型配置和超参数保留为默认值,仅更新以下配置:
- 数量类 : 6
- 微调检查点:检查点文件的路径
model.ckpt
- label_map_path :上面创建的
label_map.pbtxt
的路径 - tf_record_input_reader :上面创建的
train.record
和test.record
的路径
模特培训
接下来,为了初始化训练,我们现在可以直接使用来自 TensorFlow 对象检测 API 的建模脚本:
训练开始后,我们应该会在下面的控制台中看到训练进度日志。
此外,我们还可以使用 tensorboard 根据可视化的性能指标和验证集对训练步骤的预测来持续监控进度。
注 1:如果在训练过程中出现内存不足错误,请尝试减少
*pipeline.config*
文件中训练步骤的批量。注 2:我们可以随时停止训练,稍后通过更新
*pipeline.config*
中的*fine_tune_checkpoint*
从任何检查点继续。作为一个例子,你可以在这里找到我部分训练的模型检查点。
转换为 TensorFlow Lite
一旦我们有了一个经过训练/部分训练的模型,要为移动设备部署该模型,我们需要首先使用 TensorFlow Lite 将该模型转换为一个针对移动和嵌入式设备优化的轻量级版本。它支持设备上的机器学习推理,具有低延迟和更小的二进制大小。它使用像量化核这样的技术来实现更小更快的(定点数学)模型。
目前仅支持 SSD 型号。目前不支持 faster_rcnn 这样的模型。
安装 Bazel 并生成冻结图
我们需要首先安装 Bazel 构建工具(对于不同的操作系统,请参考安装指南)。
Bazel 安装完成后,我们将选择最新的检查点,以获得 TensorFlow 冻结图,该图具有兼容的操作,可以与 TensorFlow Lite 一起使用。要获得冻结图,我们可以直接从tf-models/research
使用模板脚本export_tflite_ssd_graph.py
。
注意:这是为了简单起见,我们应该总是检查模型评估来决定最佳的检查点/步骤。
这将给我们指定输出目录(/tmp/tflite
)中的两个文件(tflite_graph.pb
& tflite_graph.pbtxt
)。
之后,我们将使用 TensorFlow Lite 优化转换器到从 TensorFlow 冻结图源文件(tflite_graph.pb
)中获取优化的模型。我们将通过运行下面来自tensorflow
目录的脚本,为更好的移动性能生成一个量化模型。
如果脚本运行成功,您现在应该会在/tmp/tflite
目录下看到一个新文件— detect.tflite
。该文件包含图表和所有模型参数,可通过 Andriod & iOS 设备上的 TensorFlow Lite 解释器运行。
在移动设备上运行 TensorFlow Lite 模型
现在,我们剩下的最后一步是将我们的模型嵌入到我们的移动应用程序中,这应该很简单,因为 TensorFlow 已经提供了示例应用程序,使人们更容易测试模型。
要下载示例应用程序代码并以 ios 为例:
注意:构建 iOS 应用程序超出了本文的范围,本质上,上面的脚本是安装 Podfile 中列出的 iOS 应用程序的所有依赖项。一旦脚本完成,就会在
ios
目录下创建一个*.xcworkspace
文件。
实际模型文件保存在ios/ObjectDetection/Model
下,其中包含模型文件(detect.tflite
)和一个标签映射文件。我们需要从我们的模型中覆盖模型文件和标签映射。
接下来,要构建应用程序:
- 在 Xcode 中打开
ObjectDetection.xcworkspace
。 - 首次编译应用程序时,请更新捆绑包标识符,并在“常规->签名”中选择您的开发团队。
- 将您的移动设备连接到笔记本电脑
- 在 Xcode 中构建并运行应用程序。
一旦项目建立,应用程序现在应该在您的移动设备上运行,并测试我们的模型执行得有多好!
下一步是什么
到目前为止,我们已经完成了使用实时视频对象检测的自定义模型创建 iOS 应用程序的过程,这也是一个很好的起点,可以通过利用一些现有的预训练模型来快速原型化这些想法。
可以通过以下方式进一步实施应用程序:
- 手动标记原始图像数据以获得训练集的更好质量(例如,标记如下 )
- 模型选择和超参数调整以获得更好的模型性能。
- 将应用容器化,并利用云服务(例如 TPU)进一步扩展建模。
GitHub 资源库为教程。
参考
[## TensorFlow Lite 示例| TensorFlow
面向移动和嵌入式设备的 TensorFlow Lite
www.tensorflow.org](https://www.tensorflow.org/lite/examples) [## 培训自定义对象检测器- TensorFlow 对象检测 API 教程文档
所以,到目前为止你应该已经做了以下事情:现在我们已经做了以上所有的事情,我们可以开始做一些酷…
tensor flow-object-detection-API-tutorial . readthedocs . io](https://tensorflow-object-detection-api-tutorial.readthedocs.io/en/latest/training.html#training-the-model)
使用深度学习的人脸属性检测
一个快速的 4 部分演练,通过使用深度学习进行实时多面部属性检测(ResNet50 与 FastAI & Pytorch),使用 Haar 级联进行面部检测和定位(OpenCV)。
The final output of the multi facial attribute detection project.
在这篇文章中,我们试图达到上述结果。这篇文章用一个端到端的过程来指导我如何构建它。复制项目的全部代码都在我的 GitHub 库中。
第 1 部分—数据采集和理解
对于任何深度学习模型来说,要给出合理的准确率,我们都需要依赖大量的标注数据。我发现大多数关于面部特征检测的报告都只集中在多类分类上,如情感检测、微笑检测等。我在寻找一个带有多个标签的面部图像数据集,这样我就可以实现一个谷歌视觉 API 实现的东西,如下所示—
Example of a facial detection output from Google vision API
为此,我在 Kaggle 数据集网站上找到了一个名为CelebA 属性(CelebA)数据集的数据集,其中包含-
- 202,599 个各种名人的面部图像
- 10,177 个独特的身份,但没有给出名人的名字
- 每个图像 40 个二元属性注释
- 5 个地标位置
对于处理计算机视觉中的各种令人兴奋的问题来说,这是一个相当不错的数据集,因为我只对面部图像和这些图像的 40 个二进制属性注释感兴趣。这里列出了 40 个二元属性(是/否)——5 点钟形阴影、拱形眉毛、迷人、眼袋、秃头、刘海、大嘴唇、大鼻子、黑发、金发、模糊、棕色头发、浓密的眉毛、胖乎乎的、双下巴、眼镜、山羊胡、灰色头发、浓妆、高颧骨、男性、嘴巴微张、小胡子、窄眼睛、无胡须、椭圆形脸、苍白的皮肤、尖鼻子、后移的发际线这里有一个例子-
Example from CelbeA dataset
上面的图片标注了这些特征——拱形眉毛,迷人,大嘴唇,浓妆,窄眼睛,没有胡子,尖鼻子,涂着口红,年轻。因为雄旗是假的,我们可以说标签是雌的。
第 2 部分—数据预处理
数据预处理的全部代码都在这个笔记本里。
2.1)在图像上-
当我为 CelebA 数据集进行数据处理时,我的主要想法是考虑如何使用建立在真实视频/网络摄像头流/图像上的模型。CelebA 数据紧密地裁剪在脸部周围,但是在视频/网络摄像头/图像中,脸部可以在任何地方,并且必须首先被检测到。有许多预先构建的工具可以在图像中定位人脸,例如人脸识别,它使用深度学习网络来检测人脸。我想保持这一步简单,所以我使用了哈尔级联,这是一种传统的计算机视觉方法来检测物体。Haar cascade 返回检测到人脸的图像上的边界框坐标,下面是使用 Haar cascade 的输出示例
An example of Haar Cascade output.
要了解更多关于哈尔瀑布的信息,请参考这篇博客。 OpenCV 中有预置的 haar 级联滤镜。我用其中一个进行正面人脸检测。因此,一旦决定了人脸检测的方法,下一步就是在 CelebA 数据集上应用相同的方法来检测人脸,并只裁剪图像的面部区域(增加一些边距),这一步将有助于确保
- 我们使用 Haar 级联来移除正面人脸未被检测到的任何人脸,例如人侧脸的情况
- 这将确保我们的训练图像符合模型的实际使用
Example of Haar cascade processing on CelebA dataset
请注意,在上面的例子中,在哈尔级联裁剪后,左边的图片被转换为右边的图片(看起来更放大了)。我们还从 202,599 张图像过滤到 175,640 张图像,因为过滤后的图像不包含正面人脸。过滤后的图像示例如下-
Example of a filtered image.
2.2)在标签文件上-
除了对图像进行预处理,我们还需要创建我们的标签文件,供 FastAI 数据集加载器使用。
Original label file
在原始标签文件中,多属性标签每 40 个属性包含 1 /-1 个值,其中 1 表示该特征是否存在,而-1 表示该特征不存在。我只是写了一个简单的函数来转换这个文件,这样我们只有一个标签列,用空格分隔标签(如下图)
Modified Label file
第 3 部分—模型培训
一旦我们预处理了我们的数据,下一步是建立一个模型,它可以检测给定面部图像的 40+个属性。为此,我们将使用由 Pytorch 1.0 编写的 FastAI v1 库。模特训练笔记本可以在我的 Github 这里找到。我根据对图像编号的建议划分,从 1–182637(用于训练)到 182638(用于验证)对训练和验证集中的数据进行了划分。在 FastAI 库中用几行代码训练世界级的模型是不可思议的容易,所以让我们来看看代码-
锅炉钢板库导入命令—
**import** **pandas** **as** **pd**
**import** **numpy** **as** **np**
**from** **fastai.vision** **import** *
**import** **matplotlib.pyplot** **as** **plt**
数据集加载
path = Path('../data/celeba/faces/')
*## Function to filter validation samples*
**def** validation_func(x):
**return** 'validation' **in** xtfms = get_transforms(do_flip=**False**, flip_vert=**False**, max_rotate=30, max_lighting=0.3)src = (ImageItemList.from_csv(path, csv_name='labels.csv')
.split_by_valid_func(validation_func)
.label_from_df(cols='tags',label_delim=' '))data = (src.transform(tfms, size=128)
.databunch(bs=256).normalize(imagenet_stats))
第 1 行 —定义数据集文件夹的路径。
第 2–4 行 —定义我们将如何找到训练和验证图像。
第 6–7 行 —定义我们想要对数据进行的变换,例如将图像随机旋转最大 30 度,以及最大 0.3 的光照调整。
第 8 行 —将图像定义为标签 CSV 中的项目列表
第 9 行 —使用第 2–4 行的验证函数拆分训练和验证中的数据
第 10 行 —帮助我们从 labels.csv 的 tags 列获取标签,并帮助我们定义它是一个多标签列,其中用空格分隔标签。
第 12 行 —传递第 6–7 行的转换函数,将图像大小调整为 3128128
第 13 行 —定义 256 张图像的批量大小,并使用 ImageNet 平均值对数据进行标准化
请注意,我们使用较小的图像大小进行模型的初始训练,稍后我们将图像大小增加到 3256256。这个技巧通过允许更大的批量帮助我们更快地训练我们的模型,并且更快地试验什么模型配置有效。
模型定义—
在本次建模练习中,我们将使用预先训练好的 ResNet 50 模型进行迁移学习。
arch = models.resnet50
acc_02 = partial(accuracy_thresh, thresh=0.2)
acc_03 = partial(accuracy_thresh, thresh=0.3)
acc_04 = partial(accuracy_thresh, thresh=0.4)
acc_05 = partial(accuracy_thresh, thresh=0.5)
f_score = partial(fbeta, thresh=0.2)
learn = create_cnn(data, arch, metrics=[acc_02, acc_03, acc_04, acc_05, f_score])
Line1 —下载预训练的 Resnet 50 模型
第 2–6 行 —在 FastAI 中,我们可以跟踪尽可能多的验证数据的准确性度量;这些指标仅用于监控,不用于训练模型。我们使用部分函数来定义不同阈值的准确性,并跟踪阈值为 0.2 时的 F 值
第 7 行 —通过使用 ResNet 50 模型的预训练卷积部分并在顶部添加两个新的全连接层,帮助创建 CNN 架构。
FastAI 的好处是,它通过为特定的兴趣练习找到理想的学习速度,节省了大量的训练时间。
learn.lr_find()
learn.recorder.plot()
Learning rate finder from FastAI
第 1 行——通过在数据样本上尝试多个学习率来找到理想的学习率
第 2 行— 让我们画出不同学习速率下的损失。
我们需要在上面的函数中选择一个斜率最大的学习率。在这种情况下,它是 1e-2。
lr = 1e-2
learn.fit_one_cycle(4, slice(lr))
Training snapshot
现在我们已经训练了最后一个全连接层。让我们解冻所有的层,并训练完整的模型。我们将使用学习率查找器再次确定理想的学习率。
learn.unfreeze()
learn.lr_find()
learn.recorder.plot()
Snapshot of learning rate finder in FastAI
线 1 —解冻所有层
第 2–3 行 —帮助我们找到理想的学习速度。
现在,我们将对模型中的每一层使用不同的学习速率,方法是当我们回到各层时,按指数规律衰减学习速率。
learn.fit_one_cycle(5, slice(1e-5, lr/5))
learn.save('ff_stage-2-rn50')
第 1 行 —以可变学习率使用一个周期学习
第 2 行 —用指定的名称保存我们的模型。
Training snapshot
现在,我们可以将输入图像大小增加到 3256256,并在上面训练的模型上使用迁移学习来适应新的输入图像大小。
data = (src.transform(tfms, size=256)
.databunch(bs=64).normalize(imagenet_stats))acc_05 = partial(accuracy_thresh, thresh=0.5)
f_score = partial(fbeta, thresh=0.5)
learn = create_cnn(data, models.resnet50, pretrained=**False**,metrics=[acc_05, f_score])learn.load("ff_stage-2-rn50")
第 1–2 行 —创建一个新的数据加载器,将图像大小调整为 3256256,并将批量大小减少到 64。
第 4–6 行 —定义我们需要跟踪的指标,并创建一个与之前模型相似的 ResNet 50 模型。
第 8 行 —将权重从我们之前训练的模型加载到新创建的模型中。
现在,我们可以按照上面提到的类似步骤对模型进行更多的训练。培训笔记本还提供了可视化中间层激活的代码,以帮助理解图像的哪一部分驱动模型的最终结果。
Models Intermediate Activation layers heatmap over the actual image.
正如我们可以从上面的图像中看到的,该模型在图像中人脸所在的位置最活跃,这正是我们想要的,因为它是一个面部特征检测模型。
第 4 部分—组合一切
现在我们已经训练好了我们的模型,让我们写一个可以进行面部属性检测的脚本,最后一部分是把它们放在一起。这部分的代码在我的 Github 这里。
Detection script process flow
该脚本执行以下任务-
- 使用 OpenCV 访问网络摄像头拍摄输入视频并转换成一系列图像帧。
- 对于每一帧,我们从 OpenCV 运行 Haar 级联模型来定位面部并将其从帧中裁剪出来。
- 将这些裁剪出来的检测到的人脸帧传递到我们训练过的模型中,以找到相关的面部特征
- 运行脚本时,显示边界框以及在帧上检测到的所有特征
- 可选地保存视频流
结论
在上面的博客中,我们看到了如何通过将从传统机器视觉到深度学习的各种技术结合在一起,来完成端到端的面部属性检测问题。
我希望你喜欢阅读,并随时使用我在 Github 上的代码来为你的目的进行试验。此外,如果对代码或博客有任何反馈,请随时联系 aayushmnit@gmail.com 的 LinkedIn 或给我发电子邮件。您也可以在 Medium 和 Github 上关注我,了解我将来可能会写的博客文章和探索项目代码。
无需机器学习的实时目标检测
深度学习与启发式
今年早些时候,IBM 的软件开发人员 Nick Bourdakos 发布了一系列视频,演示在网络浏览器中进行实时物体检测。他早期的一个视频迅速走红,在 LinkedIn 上获得了超过 16000 个赞和 900 多条评论。以下是原帖:
[## LinkedIn 上的 Nicholas Bourdakos:“在您的浏览器中实时可定制的对象检测…
2019 年 1 月 30 日:尼古拉斯·布尔达科斯在 LinkedIn 上发帖
www.linkedin.com](https://www.linkedin.com/posts/nicholasbourdakos_machinelearning-javascript-activity-6496499508409561088-1M00)
视频显示,三个瓶子(可口可乐、百事可乐和激浪)被举到摄像机前,计算机实时识别。当检测到每个瓶子时,会给它一个文本标签,并在其周围绘制一个边界框。如果举起一个以上的瓶子,系统将正确标记不同的瓶子。
Nick 的系统现在已经进化成了 IBM cloud annotations ,但是上面的演示使用了 TensorFlow.js 以及 COCO-SSD 深度学习模型。SSD,或单次多盒探测器,是一种广泛使用的技术,用于检测一帧中的多个子图像,详细描述这里。这是深度学习擅长的任务,这些技术现在非常普遍,你可能在口袋里有一个深度学习网络,为照片或社交网络应用程序运行手机的对象检测。
“没有机器学习”的挑战
受到尼克帖子的启发,我决定挑战自己,探索是否可以在不使用机器学习的情况下取得类似的结果。我突然想到,最初演示中使用的瓶子可以根据它们的颜色或其他特征以及一些简单的匹配规则来检测。这被称为解决问题的启发式方法。
这样做的潜在优势包括:
- 易于开发和概念化
- 降低 CPU 和内存使用
- 更少的依赖性
在 CPU 和内存方面,在我的 i5 MacBook Pro 上,IBM Cloud Annotations 演示使用了超过 100%的 CPU 和超过 1.5 GB 的 RAM。它还依赖于一个网络浏览器和一些严重的依赖,包括 Tensorflow,React.js,node.js 和 COCO-SSD 本身。
我自己定的规则是:
- 可口可乐、百事可乐和激浪瓶必须贴上正确的标签
- 当瓶子移动时,应该在每个瓶子周围画一个矩形
- 最小代码
- 没有机器学习技术!
最初的演示声称只使用了 10 行代码,然而包括样板文件,当前的演示是 107 行 JavaScript。我认为低于 100 行是这个任务的一个很好的目标。
方法和解决方案
首先,我决定将我的项目建立在 OpenCV 的基础上,因为我以前在工作项目中使用过它,它有相对简单的设置,并且是专门为计算机视觉设计的*。OpenCV 是用 C++写的,有 Python 和 JavaScript 的绑定。为了方便起见,我决定使用 Python 版本。*
我开始只是认出一个可乐瓶子。为此,一个简单的解决方案是分析视频帧中的颜色,并在发现可乐红的地方贴上标签。这里的一个问题是,根据照明条件和相机颜色精度,瓶子标签不太可能准确地为RGB 244 0 0。**
为了解决这个问题,我们可以使用一个 HSV 颜色表示以及 cv::inRange 来查找图像中给定范围内的颜色。想想“红色的深浅”。这给了我们一个图像遮罩,所有红色区域为白色,其他区域为黑色。然后,我们可以使用 cv::findContours 来提供一个定义框架内每个“红色区域”的点列表。基本代码如下所示:
*mask = cv2.inRange(hsv, colour.lower, colour.upper)
conts, heirarchy = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
biggest = sorted(conts, key=cv2.contourArea, reverse=True)[0]*
第三行代码对检测到的“红色”轮廓进行排序,并返回最大的轮廓。搞定了。…对吗?不幸的是没有。像这样,程序经常在图像中找到可乐,即使图像中没有可乐。
Coke false positive
为了解决这个问题,我们需要一个额外的启发。我发现简单地排除任何小于 50×50 的轮廓就足够了。
*if w < 50 or h < 50:
continue*
最后,为了让我们的检测系统工作良好,我们需要排除在其他颜色“内部”的颜色。例如,百事可乐和激浪标签都含有红色,除非我们排除它,否则它会被检测为可口可乐。因此,我们为可乐添加了一个特殊的试探法,如果它在另一个瓶子的垂直边界内,则忽略检测。
*if name == "Coke":
if any([contains_vertical(rects[n], rect) for n in rects]):
continue*
示范
综上所述,这是最终系统的工作演示。
在我的 i5 MacBook Pro 上,它在 45%左右的 CPU 和略高于 50MB 的 RAM 下运行顺畅。完整的源代码有 85 行,可以在这里找到。
限制
这种基于颜色的方法的一个限制是,它不在瓶子周围放置边界框,而只在着色区域放置。我们可以定义额外的规则来考虑检测区域上方或下方的颜色,或者尝试猜测边界框应该在哪里,但是代码会很快变得复杂。
另一个限制是,虽然我们的系统可以同时识别可乐和百事可乐瓶,但它不能检测两个可乐瓶。我们可以添加进一步的启发式方法来处理这个问题,但是如果需要添加这么多的复杂性,我会质疑启发式方法是否是正确的选择。
深度学习 vs 启发式
我已经展示了为高度受限的任务构建一个与基于深度学习的系统精度相当的启发式检测器是很简单的。此外,启发式对象检测器在概念上更简单,具有更少的依赖性,占用更少的 CPU,并且使用更少数量级的存储器。
然而,启发式方法不像使用深度学习那样健壮或准确。深度学习系统可以很容易地识别同一物体在不同比例和旋转下的多个实例,这取决于它的训练方式。它还可以做一些事情,比如即使关键特征缺失也能识别部分物体。
结论
对我来说,这不是深度学习的明显胜利,我认为启发式方法仍然有一席之地。可以对检测条件(一致的背景和/或比例、受约束的对象类型、诸如颜色的区别特征)做出的假设越多,试探法就越有吸引力。作为一名开发人员,如果时间和资源紧张,并且输入约束明确,我会考虑基于启发式的解决方案。如果我想要增加健壮性和灵活性,我会选择机器学习。这两种方法肯定都有它们的位置,问题是要为工作选择正确的工具。
使用 TensorFlow、Raspberry Pi 和 Pan-Tilt HAT 进行实时对象跟踪
Pictured: Raspberry Pi 4GB, Pi Camera v2.1, Pimoroni Pan-Tilt HAT, Coral Edge TPU USB Accelerator
便携式计算机视觉和运动跟踪的预算。
第 1 部分—简介👋
你是刚入门机器/深度学习,TensorFlow,还是 Raspberry Pi?太好了,这篇博文是给你的!我创建了rpi-deep-pantilt作为野外物体检测的交互演示。🦁
更新— 新增人脸检测和跟踪!
我将向您展示如何复制下面的视频,它描绘了一个摄像机平移和倾斜来跟踪我在房间中的移动。
我将介绍以下内容:
- 建筑材料和硬件组装说明。
- 将 TensorFlow Lite 对象检测模型 (MobileNetV3-SSD) 部署到 Raspberry Pi。
- 使用比例-积分-微分控制器(PID)控制器向平移/倾斜伺服电机发送跟踪指令。****
- 使用 Coral 的 USB Edge TPU 加速器和 Edge TPU 编译器加速任何 TensorFlow Lite 模型的推理。
术语和参考📚
树莓派——一款受教育者、硬件爱好者和机器人爱好者欢迎的小型平价电脑。🤖
Raspbian——树莓派基金会的官方操作系统为 Pi。Raspbian 源自 Debian Linux。
TensorFlow —用于数据流编程的开源框架,用于机器学习和深度神经学习。
tensor flow Lite—一个在移动和嵌入式设备上部署 TensorFlow 模型的开源框架。
卷积神经网络——一种非常适合图像分类和对象检测任务的神经网络架构类型。****
【SSD】—一种卷积神经网络 (CNN)架构,专门用于实时物体检测、分类、包围盒定位。
**MobileNetV3**—一款最先进的计算机视觉模型,针对普通手机处理器的性能进行了优化。
MobileNet v3-SSD—基于 MobileNet 架构的单次探测器。本教程将使用通过 TensorFlow 的对象检测模型 zoo 提供的 MobileNetV3-SSD 模型。
Comparison of computer vision neural networks. Image Credit and Paper: Searching for MobileNetV3
****边缘 TPU —张量处理单元(TPU)是一个集成电路,用于加速 TensorFlow 执行的计算。边缘 TPU 是为“在边缘”的移动和嵌入式设备开发的,占地面积小
Cloud TPUv1, TPUv2 (left, middle) at Google Cloud Next ’18. Cloud TPUs accelerate TensorFlow model training and inference. Edge TPUs on a United States penny (right). Edge TPUs accelerate inferences in mobile devices. Image credit: Google)
第 2 部分—🛠构建列表
基本
- 树莓 Pi 4(推荐 4GB)
- 树莓派相机 V2
- 皮莫尔尼云台套装
- Micro SD 卡 16+ GB
- 微型 HDMI 电缆
可选
- 12 英寸 CSI/DSI 色带,用于 Raspberry Pi 摄像机。
Pi 摄像机的标准电缆对于云台帽子的全范围运动来说太短。 - RGB NeoPixel Stick
这个组件为你的项目增加了一致的光源。 - 珊瑚缘 TPU USB 加速器
在树莓派上加速推断(预测)速度。你不需要这个来重现演示。
👋找一个动片少的项目 s?
查看便携式计算机视觉:树莓 Pi 上的 tensor flow 2.0以创建手持图像分类器。✨
第 3 部分— Raspberry Pi 设置
有两种方法可以将 Raspbian 安装到您的 Micro SD 卡上:
- NOOBS (新的开箱即用软件)是一个 GUI 操作系统安装管理器。如果这是你的第一个 Raspberry Pi 项目,我建议从这里开始。
- 将 Raspbian 图像写入 SD 卡。
****本教程及配套软件使用Raspbian(Buster)编写。如果您使用的是不同版本的 Raspbian 或另一个平台,您可能会经历一些痛苦。
在进行之前,您需要:
第 4 部分—软件安装
- 安装系统依赖项
**$ sudo apt-get update && sudo apt-get install -y python3-dev libjpeg-dev libatlas-base-dev raspi-gpio libhdf5-dev python3-smbus**
2.创建新的项目目录
**$ mkdir rpi-deep-pantilt && cd rpi-deep-pantilt**
3.创建新的虚拟环境
**$ python3 -m venv .venv**
4.激活虚拟环境
**$ source .venv/bin/activate && python3 -m pip install --upgrade pip**
5.从社区构建的轮子安装 TensorFlow 2.0。
**$ pip install [https://github.com/bitsy-ai/tensorflow-arm-bin/releases/download/v2.4.0/tensorflow-2.4.0-cp37-none-linux_armv7l.whl](https://github.com/bitsy-ai/tensorflow-arm-bin/releases/download/v2.4.0/tensorflow-2.4.0-cp37-none-linux_armv7l.whl)**
6.安装rpi-deep-pantiltPython 包
**$ python3 -m pip install rpi-deep-pantilt**
第 5 部分—云台帽硬件组件
如果您购买了预组装的云台套件,您可以跳到下一部分。
否则,在继续之前,遵循装配云台中的步骤。
第 6 部分—连接 Pi 摄像机
- 关掉树莓派
- 找到 USB 模块和 HDMI 模块之间的摄像头模块。
- 向上(轻轻地)拉,打开黑色塑料夹
- 插入摄像头模块带状电缆(金属连接器朝向远离 Raspberry Pi 4 上以太网/ USB 端口的)
- 锁定黑色塑料夹
Image Credit: Getting Started with the Pi Camera
第 7 部分—启用 Pi 摄像机
- 打开树莓派
- 运行
sudo raspi-config
并从 Raspberry Pi 软件配置工具的主菜单中选择Interfacing Options
。按回车键。
3.选择Enable Camera
菜单选项并按下回车键。
4.在下一个菜单中,使用右箭头键高亮显示ENABLE
并按 ENTER 键。
第 8 部分—测试云台
接下来,测试 Pan-Tilt HAT 模块的安装和设置。
- 嘘到你的树莓皮
- 激活你的虚拟环境:
source .venv/bin/activate
- 运行以下命令:
rpi-deep-pantilt test pantilt
- 用 Ctrl+C 退出测试
如果你安装了正确的帽子,你应该看到两个伺服移动在一个平稳的正弦运动,而测试正在运行。
第 9 部分—测试 Pi 摄像机
接下来,通过启动摄像机的预览覆盖来验证 Pi 摄像机是否安装正确。叠加将在 Pi 的主显示器(HDMI)上呈现。
- 将您的 Raspberry Pi 插入 HDMI 屏幕
- 嘘到你的树莓皮
- 激活你的虚拟环境:
$ source .venv/bin/activate
- 运行以下命令:
$ rpi-deep-pantilt test camera
- 用 Ctrl+C 退出测试
如果您正确安装了 Pi 摄像机,您应该会看到摄像机中的素材渲染到您的 HDMI 或复合显示器上。
第 10 部分—测试对象检测
接下来,验证您可以在您的 Raspberry Pi 上运行对象检测模型( MobileNetV3-SSD )。
- 嘘到你的树莓皮
- 激活你的虚拟环境:
$ source .venv/bin/activate
- 运行以下命令:
**$ rpi-deep-pantilt detect**
您的 Raspberry Pi 应该检测对象,尝试对对象进行分类,并在其周围绘制一个边界框。
**$ rpi-deep-pantilt face-detect**
****注意:使用默认的 MobileNetV3-SSD 模型,只能检测和跟踪以下对象。
**$ rpi-deep-pantilt list-labels
[‘person’, ‘bicycle’, ‘car’, ‘motorcycle’, ‘airplane’, ‘bus’, ‘train’, ‘truck’, ‘boat’, ‘traffic light’, ‘fire hydrant’, ‘stop sign’, ‘parking meter’, ‘bench’, ‘bird’, ‘cat’, ‘dog’, ‘horse’, ‘sheep’, ‘cow’, ‘elephant’, ‘bear’, ‘zebra’, ‘giraffe’, ‘backpack’, ‘umbrella’, ‘handbag’, ‘tie’, ‘suitcase’, ‘frisbee’, ‘skis’, ‘snowboard’, ‘sports ball’, ‘kite’, ‘baseball bat’, ‘baseball glove’, ‘skateboard’, ‘surfboard’, ‘tennis racket’, ‘bottle’, ‘wine glass’, ‘cup’, ‘fork’, ‘knife’, ‘spoon’, ‘bowl’, ‘banana’, ‘apple’, ‘sandwich’, ‘orange’, ‘broccoli’, ‘carrot’, ‘hot dog’, ‘pizza’, ‘donut’, ‘cake’, ‘chair’, ‘couch’, ‘potted plant’, ‘bed’, ‘dining table’, ‘toilet’, ‘tv’, ‘laptop’, ‘mouse’, ‘remote’, ‘keyboard’, ‘cell phone’, ‘microwave’, ‘oven’, ‘toaster’, ‘sink’, ‘refrigerator’, ‘book’, ‘clock’, ‘vase’, ‘scissors’, ‘teddy bear’, ‘hair drier’, ‘toothbrush’]**
第 11 部分—以约 8 FPS 的速度跟踪物体
这是我们期待已久的时刻!采用以下步骤,使用云台以大约 8 帧/秒的速度跟踪物体。
- 嘘到你的树莓皮
- 激活你的虚拟环境:
$source .venv/bin/activate
- 运行以下命令:
$ rpi-deep-pantilt track
默认情况下,这将跟踪标签为person
的对象。您可以使用--label
参数跟踪不同类型的物体。
例如,要跟踪一只香蕉,您需要运行:
$ rpi-deep-pantilt track --label=banana
在一台 Raspberry Pi 4 (4 GB) 上,我对我的模型进行了大约每秒 8 帧的基准测试。
**INFO:root:FPS: 8.100870481091935
INFO:root:FPS: 8.130448201926173
INFO:root:FPS: 7.6518234817241355
INFO:root:FPS: 7.657477766009717
INFO:root:FPS: 7.861758172395542
INFO:root:FPS: 7.8549541944597
INFO:root:FPS: 7.907857699044301**
第 12 部分—使用边缘 TPU 实时跟踪物体
我们可以用 Coral 的 USB 加速器来加速模型推理速度。USB 加速器包含一个 Edge TPU,它是一个专用于 TensorFlow Lite 操作的 ASIC 芯片。欲了解更多信息,请查看开始使用 USB 加速器。
- 嘘到你的树莓皮
- 安装边缘 TPU 运行时
**$ echo "deb https://packages.cloud.google.com/apt coral-edgetpu-stable main" | sudo tee /etc/apt/sources.list.d/coral-edgetpu.list
$ curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
$ sudo apt-get update && sudo apt-get install libedgetpu1-std**
3.插入 Edge TPU(最好是一个 USB 3.0 端口)。如果您的 Edge TPU 已经插入,移除并重新插入,以便 udev 设备管理器可以检测到它。
4.使用--edge-tpu
选项尝试检测命令。你应该能够实时检测物体!🎉
**$ rpi-deep-pantilt detect --edge-tpu --loglevel=INFO**
注意: **loglevel=INFO**
将向您显示检测对象和将边界框渲染到 Raspberry Pi 相机覆盖图的 FPS。
您应该看到大约 24 FPS,这是帧从 Pi 相机采样到帧缓冲区的速率。
**INFO:root:FPS: 24.716493958392558
INFO:root:FPS: 24.836166606505206
INFO:root:FPS: 23.031063233367547
INFO:root:FPS: 25.467177106703623
INFO:root:FPS: 27.480438524486594
INFO:root:FPS: 25.41399952505432**
5.使用--edge-tpu
选项尝试跟踪命令。
**$ rpi-deep-pantilt track --edge-tpu**
第 13 部分—检测和跟踪人脸(v1.1.x 中的新功能)
我在rpi-deep-pantilt
的 v1.1.x 版本中添加了一个全新的人脸检测模型🎉
该模型来源于 TensorFlow 的研究模型 zoo 中的faces SD _ mobilenet _ v2 _ quantified _ 320 _ open _ image _ v4。
新命令是rpi-deep-pantilt face-detect
(检测所有人脸)和rpi-deep-pantilt face-track
(戴着潘迪特帽子追踪人脸)。这两个命令都支持--edge-tpu
选项,如果使用 Edge TPU USB 加速器,这将加速推理。
**rpi-deep-pantilt face-detect --help
Usage: cli.py face-detect [OPTIONS]
Options:
--loglevel TEXT Run object detection without pan-tilt controls. Pass
--loglevel=DEBUG to inspect FPS.
--edge-tpu Accelerate inferences using Coral USB Edge TPU
--help Show this message and exit.**
**rpi-deep-pantilt face-track --help
Usage: cli.py face-track [OPTIONS]
Options:
--loglevel TEXT Run object detection without pan-tilt controls. Pass
--loglevel=DEBUG to inspect FPS.
--edge-tpu Accelerate inferences using Coral USB Edge TPU
--help Show this message and exit.**
包扎🌻
恭喜你!你现在自豪地拥有了一个 DIY 对象跟踪系统,该系统使用单次检测器(一种卷积神经网络)来分类和定位对象。
PID 控制器
平移/倾斜跟踪系统使用 比例-积分-微分控制器(PID)控制器 来平滑地跟踪边界框的质心。
PID Controller Architecture, Leigh Johnson 2019
张量流模型动物园
本教程中的模型来源于 TensorFlow 检测模型 Zoo 中的SSD _ mobilenet _ v3 _ small _ coco和SSD _ mobilenet _ edge TPU _ coco。🦁🦄🐼********
我的模型可以通过 Github 发布说明@Leigh-Johnson/rpi-deep-pantilt下载。
我添加了自定义的TF lite _ Detection _ PostProcess操作,它在模型输出上实现了非最大抑制(NMS) 的变体。非最大抑制是使用 集合操作过滤许多包围盒提议的技术。
Image Credit: Non-maximum Suppression (NMS)
感谢您的阅读!
寻找更多针对 Raspberry Pi 和其他小型设备的机器学习实践示例?报名我的简讯!
我发布了真实世界的 ML 应用程序的例子(带有完整的源代码)和漂亮的小技巧,如自动消除边框注释的痛苦。
特别感谢和致谢🤗
撰稿人:熊云阳、、苏约格·古普塔、、加布里埃尔·本德、谭明星、伯金·阿金、、郭乐。
MobileNetV3 SSDLite 供稿人:、、Vivek Rathod、Jonathan Huang。
特别感谢 Adrian Rosebrock 用树莓 Pi 和 OpenCV编写了 云台人脸跟踪,这是整个项目的灵感来源!
特别感谢 Jason Zaman 审阅本文和提前发布候选人。💪
实时推荐系统:滚动特征矩阵
在许多应用中,速度比质量更有价值。当一篇文章发表后,推荐系统没有时间提出完全相关的建议。流量高峰出现在最初几分钟。这里有一个如何应对这种情况的想法。
如今,很难找到一个新闻网站不会试图通过一些推荐系统来吸引你的注意力。
如果你碰巧在互联网上的任何地方阅读了一篇文章,那么“下一篇”、“最多人阅读”、“趋势”或类似的东西将不可避免地在下面遇到你。有时我们仍然会看到《编辑文摘》——不管上下文如何,推荐的文章都不会改变。更先进的将使用标签,基于内容或另一种手工制作的相似性。但是当一个人读到今天的火灾事故时,并不一定意味着“火灾”或“事故”是他或她的兴趣所在。比如说 11.3%可能是真的,但今天的其他新闻可能比一个月前的另一场火灾事故更有趣,比如说概率为 24.6%,其余的可能兴趣是过去三天的信息背景形成的思想和感觉的复杂组合。
当然,人们可以以某种方式理解和衡量所有可能因素的影响,并为排名函数列出非常精确的系数,但明天世界将会不同。一项实证研究表明,任何形式的协同过滤在推荐方面都更有效。也就是说,我们永远不应该试图把集体意识解释成人类可读的表达。现代推荐系统应该寻找的不是关键词和日期,而是行为模式。被证明有效的简单方法是依靠文章的余弦相似度。
为了使用余弦相似度,你必须将文章表示为访问向量。为简单起见,当第 n 个读者访问了给定的文章时,假设第 n 个系数为 1,否则为 0。在浏览多篇文章时,您可以将这些向量堆叠成一个矩阵,其中每行代表一篇文章,每列代表一个读者。如果你在一个网站的访问日志中选择一个窗口,你可以用如下方式表示它。
d — document, p — person (which are more general terms for an article and a reader)
现在,要知道每对文章之间的余弦相似性,可以使用以下方法。
得到的对称矩阵具有 M 乘 M 的形状,其中 M 是项目的数量。每个系数表示第 I 篇和第 j 篇文章之间的相似性度量。不用说,当 i = j 时,系数是 1,因为这是一篇文章与其自身的相似性。
上面的例子是一种批处理。也就是说,当您加载一段适当的原始输入数据、进行计算并存储结果时,可以在以后请求推荐时检索它们。这种方法在推荐系统中广泛使用,因为它使您能够使用更复杂的数据表示和更精确的算法。它在新出版物频率较低、生命周期较长的应用程序中工作得非常好,比如在线商店或娱乐平台。但是对于一个新闻网站来说,间歇性的运行就成了一个大问题。
想象一下,一个病毒式的出版物在几分钟内被成千上万的人访问。如果这种波动恰好出现在每 10 分钟运行一次批处理的推荐系统的工作周期之间,该怎么办呢?为了充分利用高峰期的出席人数,你必须向那些人推荐一些东西,以便让他们留下来。当您试图在计算能力有限的情况下增加批处理的频率时,您可能需要减少批处理的大小,这反过来会降低结果的质量,并且仍然不能完全消除间歇性的负面影响。那么,如何让一个新闻网站的推荐系统持续工作呢?
关键思想是始终将文档/人员矩阵保存在内存中,当它到来时用数据填充它,并按需执行计算。同时,我们仍然希望能够控制矩阵的大小。因此,在任何给定时刻,矩阵必须只包含最重要的数据。就好像每次发送建议请求时都会加载批处理一样。我们想到的是利用一些缓存替换策略。
假设我们有一个由 document_id,person_id 对组成的输入流。当下一对到达时,我们将它的 document_id 放入缓存 1,将 person_id 放入缓存 2。当命中发生时,我们根据策略调整相应的缓存,并在矩阵中分配相应的系数。对于未命中的情况,我们替换高速缓存中最不重要的(例如,最近最不重要的)记录,并用除了该对的交集之外的全零来重新初始化矩阵中的相应行或列。胜过千言万语的 GIF 如下图。
在这个例子中,我使用了自适应替换缓存算法。该算法通过从驱逐历史中学习来考虑被缓存的元素的频率和新近度。最频繁元素与最近元素的比值是自适应的,是算法的核心知识。它有助于只将最重要的元素保留在内存中,也就是说,这些元素在不久的将来可能会再次被访问。我所使用的实现的关键特性是为缓存中的每条记录分配一个惟一的 ID,取值范围为 0 到 N - 1,其中 N 是缓存中记录的最大数量。这些 id 没有告诉我们任何关于记录顺序的信息,只是保证在缓存实例中是唯一的。因此,id 可以用作矩阵中行和列的索引。当一条记录被收回时,ID 被重用,我们知道哪一行或哪一列需要重新初始化。现在我们有了一个“滚动特征矩阵”。这意味着它包含准备用于实时计算推荐的输入数据的滑动批次。当然,这种方法可能有更多的应用。我只是用一个推荐系统给你一个思路。
实现的细微差别
使用 lil_matrix 加快计算速度,同时保持变异(稀疏度变化)的效率,在对某个文档执行推荐计算之前删除不需要的列。也就是说,切掉对应行有零的所有列。
如果您有一个 2k 乘 2k 的矩阵,其中大约有 10k 个非零值(这在许多情况下是足够的数据量),上述代码在任何现代 CPU 上的单个线程中每秒运行数百次,这使得这种方法适合于实时应用程序。
为了证明我的观点,我实现了 Recom.live ,这个推荐系统利用了“滚动特征矩阵”。这是一个生产就绪的实时推荐系统。您可以在 docker 容器中安装并运行它。请查看包含 Dockerfile 文件和说明的库。简而言之,安装非常简单:
这将启动一个 UDP 服务器(默认端口是 5005)。您可以开始将 document_id,person_id 对注入其中,并通过提供相同的上下文(这对 document_id,person_id )从其中检索推荐。API 非常简单,尽管为了让它更简单,我用 python 写了一个小小的客户端库。
在该负载下,Recom.live 在英特尔酷睿 i5 CPU 上运行时,每秒钟可处理 700 个记录/推荐请求。使用默认的矩阵形状(2000 X 2000)时,Recom.live 服务器会消耗大约 100 Mb 的 RAM。Docker 镜像是从 debian:stretch-slim 构建的,需要大约 350 Mb 的磁盘空间。总而言之,它绝对不会让您的服务器停机。
所以,欢迎每个人使用,留下反馈,为 Recom.live 的发展做出贡献。祝你有一个美好的一天/周末/生活,永远不要犹豫去联系!
自然语言处理的基础和使用开源工具的实时情感分析
Trinity College, Dublin | source: link
Image credit: Domo
Instagram 上每天有 5 亿条推文,每月有 8 亿活跃用户,其中 90%的人不到 35 岁。用户每天在 Reddit 上发表 280 万条评论,68%的 T2 人使用脸书。每时每刻都有数量惊人的数据生成,从这些杂乱的数据中获取相关的见解变得极其困难。有没有一种方法可以让你实时掌握这一点?如果您阅读了本文的其余部分,我将向您展示一种方法:)我还在我的社交收听网站上部署了一个简单的真实例子,供您试用…
什么是 NLP,为什么它很重要?
自然语言处理 (NLP) 是计算机科学、人工智能、语言学交叉的领域。目标是让计算机处理或“理解”自然语言,以执行各种类似人类的任务,如语言翻译或回答问题。
随着语音接口和聊天机器人的兴起,自然语言处理是第四次工业革命的最重要技术之一,并成为人工智能的一个热门领域。从 NLP 领域衍生出来的有用的应用程序正在快速增长。它们从简单到复杂。以下是其中的一些:
- 搜索、拼写检查、关键字搜索、查找同义词、复杂问题回答
- 从网站提取信息,例如:产品、价格、日期、地点、人物或姓名
- 机器翻译(即谷歌翻译)、语音识别、个人助理*(想想亚马逊 Alexa、苹果 Siri、脸书 M、谷歌助理或微软 Cortana)*
- 用于客户支持、控制设备、订购商品的聊天机器人/对话代理
- 匹配网络广告, 情感分析 用于营销或金融/贸易
- 识别财务风险或欺诈
NLP 是如何表示单词/句子的?
NLP 背后的天才是一个叫做 字嵌入 **的概念。**单词嵌入是将单词表示为向量,通过利用大量文本来学习。每个单词被映射到一个向量,向量值以类似于人工神经网络的方式被学习。
每个单词都由一个实值向量来表示,这个向量通常有几十或几百维。这里的 单词向量是一行实数值 ,其中每个数字是单词含义的维度和 ,其中语义相似的单词具有相似的向量 。即女王和公主会不会是更近的媒介物。
如果我们在一个假设的单词向量中用一些虚构的维度来标记 4 个单词(国王、王后、女人、公主),它可能看起来有点像下面这样:
Source: the morning paper
单词向量中的数字表示单词在各个维度上的分布权重。单词的 语义 都嵌入在这些 维度 的向量中。另一个跨越 4 个维度的简化示例如下:**
Source: medium / Jayesh Bapu Ahire
这些假设的向量值代表了一个词的抽象“意义”。将单词表示为向量的美妙之处在于,它们有助于数学运算符,因此我们可以对它们进行编码!然后它们可以被用作人工神经网络的输入!
我们可以通过将学习到的向量投影到简化的二维空间来可视化它们,如下所示,很明显,向量捕获了关于单词及其相互关系的有用语义信息。
Source: Google TensorFlow blog
这些是d 分布向量,基于出现在相似语境中的单词具有相似含义的假设。比如下图中,所有的大型猫科动物(即猎豹、美洲豹、黑豹、老虎和豹子)在向量空间中确实很接近。
Source: medium / Jose Camacho Collados
单词嵌入算法从大型文本语料库中获取输入,并产生这些向量空间,通常具有数百个维度。在大语料库(文本主体)上训练神经语言模型,并且网络的输出用于将每个唯一的单词分配给相应的向量。最流行的单词嵌入算法有谷歌的 Word2Vec ,斯坦福的 GloVe 或者脸书的 FastText 。****
单词嵌入代表了无监督学习最成功的人工智能应用之一。
潜在的缺点
也有缺点,比如不能区分一个词的不同意思。例如,单词“ bat ”至少有两个不同的意思:一个会飞的动物,和一件运动器材。另一个挑战是文本可能同时包含多种情感。例如(源)
“这部电影背后的意图很棒,但它本可以做得更好”。
上面这句话由正反两个极性组成。那么,我们如何断定该评论是正面的还是负面的呢?
好消息是,人工智能(AI)现在可以(几乎)实时地对复杂的人类语言及其细微差别进行足够好的理解。感谢 预训练 和深度学习驱动的算法,我们开始将 NLP 案例视为我们日常生活的一部分。
NLP 上最新最受欢迎的新闻
预先训练的 NLP 模型可以像人类一样行动,并且可以使用合理的计算资源更快地部署。比赛开始了!
source: the Verge
NLP 上最近的一条热门新闻是关于 OpenAI 发布了一个新的 GPT-2 语言模型的争议,但是他们拒绝开源完整的模型,因为它有潜在的黑暗用途。它通过 800 万个网页进行训练,GPT-2 可以生成长段类似人类的连贯文本,并有可能创建假新闻或欺骗在线身份。基本上是发现太危险不敢张扬。这只是开始。我们将会看到更多关于自然语言领域不受监管的人工智能方法的危险的讨论。
source: Vice — Chris Kindred
最近还有消息称谷歌已经开源了其自然语言处理(NLP)预训练模型,名为来自变形金刚的双向编码器表示(BERT) 。然后百度(有点像“中国的谷歌”)公布了自己预先训练好的 NLP 模型,名为“ERNIE”。
最后,包括脸书或谷歌拼图 T21 在内的大型科技公司和出版商正试图找到消除互联网上大量辱骂和骚扰的方法。尽管在人工智能和 NLP 赶上来之前,仍然需要数千名人类主持人来避免丑闻。敬请关注 NLP 的更多进展&新闻!
社交媒体情感分析
一个人能读多少书或者能跟多少人走才能找到问题的关键?也许你正在看超级碗,好奇休息时间其他人对最新广告的看法。也许你想发现潜在的社交媒体危机,联系不满意的客户,或者帮助开展营销/政治活动。也许你想避免(网上)危机或确定最有影响力的人…
情感分析(也称为意见挖掘或情感 AI** )是 NLP 的一个子领域,它试图在博客、评论、社交媒体、论坛、新闻等给定文本中识别和提取意见。使用 NLP 和开源工具,情感分析可以帮助将所有这些指数级增长的非结构化文本加工成结构化数据。例如,Twitter 是一个情感宝库,用户可以对世界上的每个话题发表自己的反应和意见。**
Source: talkwalker
好消息是,在人工智能驱动的新世界中,在几秒钟内分析这些文本片段是可能的,而且每天都在变得更好。实际上,有很多现成的类似商业工具可用,尽管你可以自己创建一个自己的应用程序,只是为了好玩!
在数据挖掘中,流式推文是一项有趣的练习。爱好者通常使用一个名为 tweepy 的强大 Python 库来实时访问(公共)推文。简单的想法是,我们首先(1)在线生成 Twitter API 凭证,然后(2)使用 tweepy 和我们的凭证,根据我们的过滤器设置来传输推文。然后,我们可以(3)将这些流推文保存在数据库中,以便我们可以执行自己的搜索查询、NLP 操作和在线分析。大概就是这样!
什么是 VADER?
好消息是,你不需要成为深度学习或 NLP 专家就可以开始为你的想法编码。其中一个现成的预训练算法叫做VADER(ValenceAwareDictionary 和 sEntimentR它的算法针对 Twitter、在线新闻、电影/产品评论等社交媒体中表达的观点进行了优化。VADER 可以给我们一个积极和消极的分数,可以在-1 到 1 的范围内标准化。VADER 能够包含来自表情符号(例如,😃、与情绪相关的首字母缩写词(例如 LoL)和俚语(例如 meh)的情绪,而算法通常会在这些地方挣扎。因此,维德是一个可怕的工具,新鲜的在线文本。
Source: Medium — David Oti
虽然 VADER 在社交媒体类型的文本上有优势,但它也不需要任何训练数据,因为它是基于化合价的、人类策划的标准情感词典。对我来说同样重要的是,它的速度足够快,可以在线使用实时流数据。VADER 的开发者使用了亚马逊的机械土耳其人来获得他们的大部分评分,该模型在一篇名为“ VADER:一个基于规则的社交媒体文本情感分析的简约模型”的学术论文中有完整描述。”。
输入的句子首先通过一个叫做“”的过程被拆分成几个单词。然后,通过在情感词典内进行比较,查看每个单词句子的情感值会容易得多。实际上,这里没有进行机器学习,但是这个库解析每个标记化的单词,与它的词典进行比较,并返回极性得分。这将显示推文的总体情绪得分。VADER 也有一个开源 python 库,可以使用常规的 pip 安装来安装。它不需要任何训练数据,并且可以足够快地处理几乎实时的流数据,因此对于我的手来说,它是一个简单的选择。****
基础数据清理
任何 NLP 代码都需要做一些实时清理,以删除停用词和标点符号,降低大写字母,并根据感兴趣的语言过滤推文。Twitter API (tweepy)有一个自动检测常用语言的功能,我只过滤了英语。还有一些其他流行的 NLP 技术可以进一步应用,包括(将单词转换为词典形式)或 词干 (将单词简化为其词根形式),以进一步改善结果。**
Source: hands on example — Vader sentiment for the “Game of Thrones”
使用实时 Twitter 数据的 MVP 实践示例:
最后,我在我的演示网站上部署了一个示例模型来展示预训练的 NLP 模型的威力,该模型只使用实时 twitter 数据和英语推文。这个最小可行的产品是只用开源工具完成的。灵感和原代码来自于 python 编程中的sendex这个环节。我添加了一些额外的功能,比如类似谷歌的搜索体验,美国各州情感地图,以捕捉带有用户位置元数据的推文,搜索词汇的词云,以及避免崩溃的错误处理。我发现 Twitter 用户不太维护他们的“位置”,因此美国地图包含的 tweets 更少。您可以从我的 GitHub 库下载修改后的代码,并按照这些指令在云上部署。代码是混乱的,因为我在有限的时间内编辑它,并开放任何帮助,使它看起来更好。
A wordcloud at my blog for “cobra kai”
依赖性:开源技术和云
工作的重要部分是安装所有这些组件并协同工作,清理数据并集成开源分析库,而 Vader 模型本身只有几行基本代码。
Example: location based sentiments for the tweets including the word “twitter” at a random time in mid-April
****开源技术:我把 Python 3.7 和各种开源库一起用。主要的有(1) Tweepy : Twitter API 库,以 JSON 格式传输公共推文(2) SQlite3 :广泛使用的轻量级关系数据库(3) Panda :非常适合读取和操作数字表和 Twitter 时间序列(4) NLTK :自然语言工具包(5) wordcloud:显而易见哈!(6) Flask :用于 web 部署的微 web 框架。爱死了!(7) Dash :使您能够使用纯 python 构建令人惊叹的仪表盘(8) Plotly :流行的 Python 图形库,用于交互式和在线绘制折线图、散点图、面积图、条形图……首先,您需要注册 Twitter API,安装依赖项,编写代码,并将其部署到您的笔记本电脑或云上。
**云部署:我使用 数字海洋 (声明:这是一个推荐链接)作为我的虚拟专用服务器(VPS)提供商。我使用了一个低层次的节俭服务器,因此我的演示的速度/性能不是超级快,但它的工作和 SSL 相对安全。最初我部署了 AWS Beantalks,但我不得不转向,因为可用的 Amazon Linux 发行版与我希望与我的代码集成的最新 SQlite3 数据库版本不兼容。实际上,当您处理开源工具时,这些都是典型的挑战,需要数据科学家以极大的耐心保持灵活性。有趣的是,在这种情况下,数字海洋给了我更多的控制权,而且很容易设置。另一个不错的选择是 Heroku。如果你使用 AWS,我建议使用 mySQL、MongoDB 等数据库服务(相对于 SQLite3)。如果有问题,请告诉我。
结论
维德模型表明,它并不完美,但安静的象征。尽管更先进、更精确的 ML 算法正在向我们走来,但任何算法都会有一些假阴性或假阳性。
Source: Michael could override KITT’s AI when needed 😃
这些预先训练的自然语言处理能力可以很容易地重新应用于电子邮件、脸书、推特、Instagram、YouTube、Reddit、IMDB、电子零售商评论、新闻博客和公共网络。这些见解可以通过位置、人口统计、受欢迎程度、影响来分析…测量网络脉搏或生成类似人类的内容从未如此简单!可怕的是,这些很容易被社交媒体机器人或其他人用于计算宣传…小心!
人工智能/机器学习实现了民主化,并使您能够实时获得针对您所在领域的关键见解。尽管如果你不打算根据洞察力采取行动,跟踪本身可能不值得。
未来的幸存者将需要转变他们的流程和资源,以适应这个数据和算法丰富的新时代。
2019 年快乐学习!还有…
不要忘记活在当下!
John Blanding/The Boston Globe via Getty Image
资源:
Source: Sentiment analysis video
**** [## 使用 Python 中的 VADER 简化情感分析(在社交媒体文本上)
一个易于使用的 Python 库,专为社交媒体文本的情感分析而构建。
medium.com](https://medium.com/analytics-vidhya/simplifying-social-media-sentiment-analysis-using-vader-in-python-f9e6ec6fc52f) [## 改变你未来沟通方式的 7 种 NLP 技术(上)
什么是 NLP?
heartbeat.fritz.ai](https://heartbeat.fritz.ai/the-7-nlp-techniques-that-will-change-how-you-communicate-in-the-future-part-i-f0114b2f0497) [## 深度学习 NLP 的十大趋势
2018 年是基于深度学习的自然语言处理(NLP)研究繁忙的一年。在此之前最高…
blog.floydhub.com](https://blog.floydhub.com/ten-trends-in-deep-learning-nlp/) [## 单词向量简介
词向量
medium.com](https://medium.com/@jayeshbahire/introduction-to-word-vectors-ea1d4e4b84bf) [## 使用 Python 中的 VADER 简化情感分析(在社交媒体文本上)
一个易于使用的 Python 库,专为社交媒体文本的情感分析而构建。
medium.com](https://medium.com/analytics-vidhya/simplifying-social-media-sentiment-analysis-using-vader-in-python-f9e6ec6fc52f) [## VADER 情绪分析解释-数据与媒体相遇
VADER(情感推理的效价感知词典)是一个用于文本情感分析的模型
datameetsmedia.com](http://datameetsmedia.com/vader-sentiment-analysis-explained/)****
实时声音事件分类
我在之前的一篇文章中介绍了一种使用机器学习对声音事件进行分类的方法。在之前的帖子中,声音事件是作为小音频片段单独捕获的。因此,不需要分割过程。这些独立的音频片段被用来训练神经网络并对其进行测试。在这篇文章中,我将介绍一种对声音事件进行分类的方法,这些声音事件在一个音频片段(或一个音频流)中按顺序连接在一起。我们必须对事件进行分类,并给它们一个标签,以及相关音频片段或音频流的时间戳。让我们称之为时间标签。注意,这里将重复使用用于分类孤立声音事件的相同程序。所以我强烈推荐你先看完上一篇。
让我们来看看一个样本音频片段的波形,我们将对其进行时间标记。
A sequence of sound events
时间标记的建议方法如下。
1.使用普通噪声样本降低噪声
2.将音频剪辑拆分成包含音频剪辑的单个声音事件
3.修剪单个声音事件音频片段的开头和结尾静音。
4.使用先前训练的神经网络对单个声音事件片段进行分类
5.输出时间标签。
该过程适用于没有两个声音事件同时发生的情况。这是因为我们在这里使用的预测模型只针对孤立的声音事件进行训练。让我们假设噪声在整个声音事件系列中保持不变。让我们来看看用单个声音事件连接片段执行上述步骤。然后,在文章的最后,我将介绍一种使用麦克风的音频流实时分类声音事件的方法。
您可以通过连接一些单个音频片段来准备样本,如下所示。
raw_audio = numpy.concatenate((raw_audio,data))
按如下方式降低均匀分布的噪声。
noisy_part = raw_audio[0:50000] # Empherically selected noisy_part position for every sample
nr_audio = nr.reduce_noise(audio_clip=raw_audio, noise_clip=noisy_part, verbose=False)
分割音频剪辑
现在,我们已经到了连续声音事件识别的核心思想。对声音事件序列进行分类的挑战在于确定这些声音事件的起点和终点。几乎总是在两个声音事件之间有一个无声部分。请注意,在一些声音事件中,可能会有静默。我们可以用这些无声部分来分割一系列声音事件。看看下面用来完成任务的代码。注意到参数tolerence
用于调整分割灵敏度。从而一个声音事件内的小无声部分不会被用来进一步分割相应的声音事件。
# Split a given long audio file on silent parts.
# Accepts audio numpy array audio_data, window length w and hop length h, threshold_level, tolerence
# threshold_level: Silence threshold
# Higher tolence to prevent small silence parts from splitting the audio.
# Returns array containing arrays of [start, end] points of resulting audio clips
def split_audio(audio_data, w, h, threshold_level, tolerence=10):
split_map = []
start = 0
data = np.abs(audio_data)
threshold = threshold_level*np.mean(data[:25000])
inside_sound = False
near = 0
for i in range(0,len(data)-w, h):
win_mean = np.mean(data[i:i+w])
if(win_mean>threshold and not(inside_sound)):
inside_sound = True
start = i
if(win_mean<=threshold and inside_sound and near>tolerence):
inside_sound = False
near = 0
split_map.append([start, i])
if(inside_sound and win_mean<=threshold):
near += 1
return split_map
该算法使用具有跳跃长度h
的固定大小的窗口w
。窗口在给定音频上滑动,检查窗口的平均振幅。如果振幅低于给定的threshold_level
,算法会增加一个名为near
的内部参数。当参数near
获得大于参数tolerence
的值时,确定音频剪辑结束分割点。同样,音频剪辑起始分割点也是使用窗口平均振幅来确定的。注意,内部布尔参数inside_sound
被维护以区分开始和结束分割点。
修剪单个声音事件音频片段
现在,我们已经将我们的音频剪辑分成单个声音事件。小音频片段需要修剪它们的前导和拖尾无声部分。让我们使用librosa
来完成任务。
sound_clips = split_audio(nr_audio, 10000, 2500, 15, 10)
for intvl in sound_clips:
clip, index = librosa.effects.trim(nr_audio[intvl[0]:intvl[1]], top_db=20, frame_length=512, hop_length=64)
注意split_audio
仅提供时间标记间隔。我们需要在nr_audio[intvl[0]:intvl[1]]
之前获得实际的音频剪辑。
对声音事件进行分类
为了对孤立的声音片段进行分类,我们可以使用来自先前帖子的经过训练的神经网络模型。
#Load segment audio classification model
model_path = r"best_model/"
model_name = "audio_NN3_grouping2019_10_01_11_40_45_acc_91.28"# Model reconstruction from JSON file
with open(model_path + model_name + '.json', 'r') as f:
model = model_from_json(f.read())# Load weights into the new model
model.load_weights(model_path + model_name + '.h5')
创建该模型是为了使用标签编码器预测标签。我们还需要在这里复制标签编码器。
# Replicate label encoder
lb = LabelEncoder()
lb.fit_transform(['Calling', 'Clapping', 'Falling', 'Sweeping', 'WashingHand', 'WatchingTV','enteringExiting','other'])
为了使用加载的模型对音频剪辑进行分类,我们需要绝对平均 STFT 特征。看看下面完成这项任务的代码。注意,该函数接受标签编码器lb
作为输入,以产生一个有意义的标签作为声音事件。
def predictSound(X, lb):
stfts = np.abs(librosa.stft(X, n_fft=512, hop_length=256, win_length=512))
stfts = np.mean(stfts,axis=1)
stfts = minMaxNormalize(stfts)
result = model.predict(np.array([stfts]))
predictions = [np.argmax(y) for y in result]
return lb.inverse_transform([predictions[0]])[0]
现在,我们可以在上述修剪操作后立即对隔离的剪辑使用predictSound
功能。访问 GitHub 库获取完整代码和分类示例。
实时声音事件识别
到目前为止,我们一直在研究声音事件的记录序列。如果我们想做同样的事情,但不需要记录,而是实时的。为此,我们可以使用麦克风输入流缓冲到一个临时缓冲区,并在缓冲区上工作。IO 可以用 python 库轻松处理,比如 PyAudio (文档这里)。查看 GitHub 库的实现。
希望这篇文章对你有用。
用于品牌提升和话题跟踪的实时 Twitter 情感分析(第 1/3 章)
行业中的数据科学
通过 Tweepy、MySQL 和 Python 使用流 Twitter API 收集 Twitter 数据
Photo by Riccardo Chiarini on Unsplash
这是一个全面的分步教程,教你如何建立一个端到端的实时 Twitter 监控系统,通过识别情绪波动,分析趋势话题和地理细分,检测丑闻的异常,跟踪客户对品牌的行为,并考虑提高品牌的客户参与度和保留率。
https://twitter-analysis-web-app.herokuapp.com
技术栈: Python,Tweepy,Numpy,Pandas,Seaborn,Plotly,Dash,Scala Kafka,Spark,MySQL,RE,TextBlob,NLTK,HTML,CSS,Flask,JavaScript,React.js 和 Git
由于这是一个全面的端到端 Twitter 监控系统,我将把它分成 3 章来解释引擎盖下的细节和行动背后的直觉。
- **第 1 章(你来了!)😗*通过 Tweepy、MySQL、& Python 使用流 Twitter API 收集 Twitter 数据
- 第二章 : 使用 RE、TextBlob、NLTK 和 Plotly 的 Twitter 情感分析和交互式数据可视化
- 第三章 : 使用 Python 中的 Dash & Plotly 在 Heroku 上部署一个实时的 Twitter 分析 Web App
- 第 4 章(可选) : 使用 Scala、Kafka 和 Spark 流媒体实现流媒体 Twitter 情感分析的并行化
这个系统是什么?这个实时的端到端 Twitter 监控系统是为企业设计的,用于评估 Twitter 数据,为商业决策提供信息。正如我们所知,twitter 是一个实时高通量数据源的好地方,平均每秒 6000 条推文,我们可以用它来发现突发新闻故事,识别行业趋势,并及时采取行动。在实践中,实时跟踪关于某个品牌的所有相关 Twitter 内容,随着话题或问题的出现进行分析,并通过警报检测异常情况。通过监控 Twitter 上的品牌提及,品牌可以通知执行机构,并为全球客户提供更好的体验。
访问 Twitter API——成为一名出色的 Twitter 开发者
Apply for a developer account
为了开始使用 Twitter APIs,我们需要先申请一个开发者账户。它允许你访问 Twitter APIs 和其他工具。
Create an app
然后我们创建一个应用来生成两个 API 密匙和两个访问令牌。这是调用 Twitter APIs 最重要的部分。整个过程可能需要几分钟,但应该很容易完成。
Consumer API keys and Access token & access token secret
现在,在右上角您的 Twitter 名称下的应用程序中,点击您的应用程序右侧的详细信息按钮(这不是仪表板按钮)。然后点击副标题中的键和令牌。创建一个名为 credentials.py 的文件,并将&粘贴到该文件中。
#credentials.py
API_KEY = 'XXXXXXXXXX'
API_SECRET_KEY = 'XXXXXXXXXXXXXXXXXXXX'ACCESS_TOKEN = 'XXXXXXXXXXXXXXXXXXXXXXX'
ACCESS_TOKEN_SECRET = 'XXXXXXXXXXXXXXXXXXX'
Photo by Sebastian B on Unsplash
使用 Tweepy、MySQL 和 Python 流式传输 Twitter 数据
我们将使用一个名为 Tweepy 的 python 库来监听流 Twitter 数据。创建一个名为 Main.ipynb 的新文件,让我们开始吧。注:我用 Jupyter 笔记本是为了更好的开发探索,你也可以用。改为 py。如果你感兴趣,你可以通过 Tweepy 的 Tweepy 在线文档来查看这个流。你可以在这里查看我的全代码版本。
首先,我们需要创建一个 Tweepy 的 StreamListener ,它具有用于接收 tweets 的 on_status 方法和用于由于速率限制而停止抓取数据的 on_error 方法。推文被称为“状态更新”。因此
Tweepy 中的状态类具有描述 tweet 的属性。
# Part of **MyStreamListener** in *Main.ipynb*
*# Streaming With Tweepy*
*# Override tweepy.StreamListener to add logic to on_status*
**class** **MyStreamListener**(tweepy.StreamListener):
**def** on_status(self, status):
*# Extract info from tweets*
id_str = status.id_str
created_at = status.created_at
user_created_at = status.user.created_at
# ...... and more!
# I'll talk about it below! (Or check full-code link above) **def** on_error(self, status_code):
*'''*
*Since Twitter API has rate limits,
stop srcraping data as it exceed to the thresold.*
*'''*
**if** status_code == 420:
*# return False to disconnect the stream*
**return** **False**
然后,使用 Tweepy 中的 Oauth 进行认证,向 Twitter 注册我们的应用程序。
# **Oauth** part in *Main.ipynb* # *Import api/access_token keys from* credentials.pyimport credentials.py
auth = tweepy.OAuthHandler(credentials.API_KEY, \
credentials.API_SECRET_KEY)
auth.set_access_token(credentials.ACCESS_TOEKN, \
credentials.ACCESS_TOKEN_SECRET)
api = tweepy.API(auth)
现在,用 Oauth 启动流线型监听器。在过滤器方法中,设置推文语言偏好和跟踪单词,后者是一个单词列表(例如[‘脸书’])。目前,我们使用 Twitter 的免费标准流。查看 Twitter 流 API 文档以了解不同的流具有不同的功能和限制。
myStreamListener = MyStreamListener()
myStream = tweepy.Stream(auth = api.auth, listener = myStreamListener)
myStream.filter(languages=["en"], track = settings.TRACK_WORDS)*# However, this part won't be reached as the stream listener won't stop automatically. Press STOP button to finish the process.*
然后,创建并连接 MySQL 本地数据库,以便进一步分析和存储。你可以在这里下载最新版本的。我们用的版本是 MySQL 社区版,非常流行的开源数据库。根据内置指南设置 MySQL 数据库,数据库信息如下。
mydb = mysql.connector.connect(
host="localhost",
user="root",
passwd="password",
database="TwitterDB",
charset = 'utf8'
)
如果表不存在,我们需要创建一个新表。当然第一次的时候应该是不存在的。所以我们用下面的自动检查代码创建它。
**if** mydb.is_connected():
mycursor = mydb.cursor()
mycursor.execute("""
SELECT COUNT(*)
FROM information_schema.tables
WHERE table_name = '**{0}**'
""".format(TABLE_NAME))
**if** mycursor.fetchone()[0] != 1:
mycursor.execute("CREATE TABLE **{}** (**{}**)" \
.format(TABLE_NAME, TABLE_ATTRIBUTES))
mydb.commit()
mycursor.close()
在 on_status 方法中指定接收和预处理 Twitter 数据的细节。状态中的属性与推文对象中的属性相同。
- id_str 是 Tweets Id 的字符串格式
- created_at 是创建推文的时间
- 文字是推文的内容
- 极性&主观性是使用 TextBlob NLP 库进行核心情感分析的情感值
像 user_created_at 、 user_location 、 user_description 和 user_followers_count 这样的属性在用户对象中,它是 Tweet 对象的一部分。此外,c 坐标包括经度和纬度是 JSON 格式的另一个对象 Geo 对象。
*# Extract info from tweets* **def** on_status(self, status):
**if** status.retweeted:
*# Avoid retweeted info, and only original tweets will
# be received*
**return** **True**
*# Extract attributes from each tweet*
id_str = status.id_str
created_at = status.created_at
text = deEmojify(status.text) *# Pre-processing the text*
sentiment = TextBlob(text).sentiment
polarity = sentiment.polarity
subjectivity = sentiment.subjectivity
user_created_at = status.user.created_at
user_location = deEmojify(status.user.location)
user_description = deEmojify(status.user.description)
user_followers_count =status.user.followers_count
longitude = **None**
latitude = **None**
**if** status.coordinates:
longitude = status.coordinates['coordinates'][0]
latitude = status.coordinates['coordinates'][1]
retweet_count = status.retweet_count
favorite_count = status.favorite_count # Quick check contents in tweets
print(status.text)
print("Long: **{}**, Lati: **{}**".format(longitude, latitude))
*# Store all data in MySQL*
**if** mydb.is_connected():
mycursor = mydb.cursor()
sql = "INSERT INTO **{}** (id_str,created_at,text,polarity,\
subjectivity, user_created_at, user_location,\
user_description, user_followers_count, longitude,\
latitude, retweet_count, favorite_count) VALUES \
(**%s**, **%s**, **%s**, **%s**, **%s**, **%s**, **%s**, **%s**, **%s**, **%s**, **%s**, **%s**, **%s**)" \
.format(TABLE_NAME)
val = (id_str, created_at, text, polarity, subjectivity,\
user_created_at, user_location, user_description,\
user_followers_count, longitude, latitude,\
retweet_count, favorite_count)
mycursor.execute(sql, val)
mydb.commit()
mycursor.close()
最后,为了允许 tweet 文本存储在 MySQL 中,我们需要做一点处理,通过剥离所有非 ASCII 字符来删除表情符号,即使数据库的字符集是 utf8。
**def** deEmojify(text):
**if** text:
**return** text.encode('ascii', 'ignore').decode('ascii')
**else**:
**return** **None**
这是我的第一篇技术文章,我感谢任何反馈!
用于品牌提升和话题跟踪的实时 Twitter 情感分析(第 2/3 章)
行业中的数据科学
使用 RE、TextBlob、NLTK 和 Plotly 进行 Twitter 情感分析和交互式数据可视化
Photo by Jonatan Pie on Unsplash
教程将教你如何一步一步地在 Twitter 数据上应用 1) 自然语言处理和情感分析,2)利用 Plotly 构建一个交互式数据可视化。
这是一个独立的组件,用于执行情绪分析和话题跟踪,并在 Jupiter Notebook 上构建分析仪表板,尽管它是我的综合实时 Twitter 监控系统教程的第二部分。在前一章中解释并实现了流 Twitter 数据收集。
- 第 1 章 : 使用 Tweepy、MySQL、& Python 的流 Twitter API 收集 Twitter 数据
- **第二章(你来了!)😗*使用 RE、TextBlob、NLTK 和 Plotly 进行 Twitter 情感分析和交互式数据可视化
- 第三章 : 使用 Python 中的 Dash & Plotly 在 Heroku 上部署一个实时的 Twitter 分析 Web App
- 第 4 章(可选) : 使用 Scala、Kafka 和 Spark Streaming 实现流媒体 Twitter 情感分析的并行化
Data Visualization based on Plotly in this Chapter
上面的分析仪表板(带完整代码)就是我们今天要做的,它为下一章的 实时 Twitter 监控 Web App 奠定了基础,因为 Dash(python framework for analytical Web apps)是在 Plotly 之上编写的。查看我的 GitHub 回购 了解更多详情。
Web App based on Dash-Plotly in next chapter
****第章的技术栈:RE,NLTK,TextBlob,Plotly,MySQL,Python (time,datetime,math,itertools)
- RE : 正则表达式识别给定字符序列中是否存在模式的操作
- NLTK : 自然语言工具包,构建 Python 程序处理人类语言数据的领先平台
- TextBlob : 自然语言处理库,用于处理文本数据,提供一个简单的 API** 用于潜入普通的 NLP。**
- :一个交互式,开源的,基于浏览器的Python 图形库****
加载和准备 Twitter 数据
首先,我们需要从数据源中提取 Twitter 数据。简单起见可以直接从sample_data.csv
开始读。
**df = pd.read_csv("sample_data.csv")**
或者以一种更正式的方式,从我们的 MySQL 数据库中提取数据,该数据库已经在第 1 章中建立并填充了实时 Twitter 数据。
**db_connection = mysql.connector.connect(
host="localhost",
user="root",
passwd="password",
database="TwitterDB",
charset = 'utf8'
)
time_now = datetime.datetime.utcnow()
time_10mins_before = datetime.timedelta(hours=0,minutes=10)) \
.strftime('%Y-%m-%d %H:%M:%S'
time_interval = time_now - time_10mins_before**
读取过去 30 分钟内发布的数据,并通过 SQL 查询将其加载到 Pandas DataFrame 中。
**query = "SELECT id_str, text, created_at, polarity, \
user_location FROM **{}** WHERE created_at >= '**{}**'" \
.format(settings.TABLE_NAME, time_interval)
df = pd.read_sql(query, con=db_connection)**
然后把 DATETIME (MySQL 数据类型)转换成 Datetime (Pandas 数据类型)。
***# UTC for date time at default*
df['created_at'] = pd.to_datetime(df['created_at'])**
使用文本块进行情感分析
情感分析的核心是使用 TextBlob,以便从 tweet 文本中提取极性 & 主观性,这实际上是上一章为了更好地存储数据而进行的数据预处理。负面推文代表-1,正面推文代表+1,中性推文代表 0。
**from **textblob** import TextBlob
sentiment = TextBlob(tweet_text).sentiment
polarity = sentiment.polarity
subjectivity = sentiment.subjectivity**
将整个时间序列转换为 2 秒一组,并计算每个时间间隔组中每种极性(例如-1、0 和 1)的情绪数量。
应用拆栈技术以确保每组中的所有类别都被显示,即使其中一个类别没有任何值。因为我们只显示最近 30 分钟内发布的实时推文,所以在实践中,2 秒间隔的组最好显示在屏幕上。之后,重命名这些列,使它们能够自我解释。
***# Clean and transform data to enable time series*
result = df.groupby( \
[pd.Grouper(key='created_at', freq='2s'), 'polarity'] \
).count().unstack(fill_value=0).stack().reset_index()
result = result.rename(columns= \
{ "id_str": "Num of '{}' mentions".format(TRACK_WORD), \
"created_at":"Time in UTC" })**
以 2 秒的间隔记录时间序列,以便进一步使用索引。
**time_series = result["Time in UTC"][result['polarity']==0] \
.reset_index(drop=**True**)**
使用简单的Plotly Express快速可视化折线图。注意:Plotly Express 是一个简洁、一致、高级的plotly.graph_objects
包装器,用于快速数据探索和图形生成。
**import **plotly.express** as px
fig = px.line(result, x='Time in UTC', \
y="Num of '{}' mentions".format(TRACK_WORD), \
color='polarity')
fig.show()**
Line Chart for Sentiment Analysis
使用 RE 的自然语言处理的主题跟踪& NLTK
为了跟踪推文中最热门的词或最常用的符号,我们加入所有推文,删除 URL,清除“RT”和“T36”(也称为“T37”)amp;。)符号,并将所有字符转换成小写。
**content = ' '.join(df["text"])
content = re.sub(r"http\S+", "", content)
content = content.replace('RT ', ' ').replace('&', 'and')
content = re.sub('[^A-Za-z0-9]+', ' ', content)
content = content.lower()**
第一次使用 python 脚本从 NLTK 下载这两个文件。 Punkt 句子分词器 用于通过使用无监督算法将文本分成一系列句子。
***import nltk
nltk.download('punkt')*
*nltk.download('stopwords')***
然后从所有推文中对整个文本进行分词,使用 停用词 去除常用词,并提取所有词的 频率分布 中最常见的 10 个词。
**from **nltk.probability** import FreqDist
from **nltk.tokenize** import word_tokenize
from **nltk.corpus** import stopwordstokenized_word = word_tokenize(content)
stop_words=set(stopwords.words("english"))
filtered_sent=[]
**for** w **in** tokenized_word:
**if** w **not** **in** stop_words:
filtered_sent.append(w)
fdist = FreqDist(filtered_sent)
fd = pd.DataFrame(fdist.most_common(10), \
columns = ["Word","Frequency"]).drop([0]).reindex()**
再次使用简单的 图形表达 快速可视化条形图。
**import **plotly.express** as px
fig = px.bar(fd, x="Word", y="Frequency")
fig.update_traces(marker_color='rgb(240,128,128)', \
marker_line_color='rgb(8,48,107)', \
marker_line_width=1.5, opacity=0.8)
fig.show()**
Bar Chart for Topic Tracking
文本处理中的地理分割识别
为了探索用户的地理分布,我们需要通过他们的用户资料来识别他们的位置,而不是附有推文的位置,因为只有不到 1%的人会附上他们的推文位置。然而,根据用户简档中的位置,它们可能包括一个或多个县、城市、州、国家或星球。因此,将这些数据过滤成美国州级位置是地理分段识别的核心。
将所有状态名及其缩写设置为常量,用于进一步的缩写-名称转换。
**STATES = ['Alabama', 'AL', 'Alaska', 'AK', \
...... # Text hided for readability \
'WV', 'Wisconsin', 'WI', 'Wyoming', 'WY']STATE_DICT = dict(itertools.zip_longest(*[iter(STATES)] * 2, fillvalue=""))
INV_STATE_DICT = dict((v,k) **for** k,v **in** STATE_DICT.items())**
通过迭代州名列表和用户位置列表,从他们的位置提取州信息。
**is_in_US=[]
geo = df[['user_location']]
df = df.fillna(" ")
**for** x **in** df['user_location']:
check = **False**
**for** s **in** STATES:
**if** s **in** x:
is_in_US.append(STATE_DICT[s] **if** s **in** STATE_DICT **else** s)
check = **True**
**break**
**if** **not** check:
is_in_US.append(**None**)
geo_dist = pd.DataFrame(is_in_US, columns['State']) \
.dropna().reset_index()**
统计美国各州发布的推文数量,用对数数字避开极值(如加州 500+,北达科他州 3)更好的可视化。
**geo_dist = geo_dist.groupby('State').count(). \
rename(columns={"index": "Number"}).sort_values( \
by=['Number'], ascending=**False**).reset_index()
geo_dist["Log Num"] = geo_dist["Number"] \
.apply(**lambda** x: math.log(x, 2))**
为稍后仪表板上的悬停文本添加说明性文本信息。
**geo_dist['Full State Name'] = geo_dist['State'] \
.apply(**lambda** x: INV_STATE_DICT[x])
geo_dist['text'] = geo_dist['Full State Name'] + '<br>' + \
'Num: ' + geo_dist['Number'].astype(str)**
这一次,我们使用 Plotly (不是 Plotly Express)来可视化美国地图。
注 : plotly.graph_objects
是 Plotly 库的核心,包含更多通用函数,用于更复杂的用途。locationmode
是“仓位”中仓位匹配条目的集合。text
是悬停文本。marker_line_color
是状态间线条标记的颜色。设置geo_scope
将地图范围限制在美国。
**import **plotly.graph_objects** as go
fig = go.Figure(data=go.Choropleth(
locations=geo_dist['State'], *# Spatial coordinates*
z = geo_dist['Log Num'].astype(float), *# Data to be color-coded*
locationmode = 'USA-states',
colorscale = "Reds",
text=geo_dist['text'],
marker_line_color='white', *# line markers between states*
colorbar_title = "Numbers in Log2"
))
fig.update_layout(
geo_scope='usa',
)
fig.show()**
********
Photo by Karsten Würth (@karsten.wuerth) on Unsplash
带有 Plotly 的交互式分析仪表板
现在我们可以使用Plotly.subplots
将所有数据可视化部分集成到一个仪表板中。同时显示多个图形可以大大提高阅读效率,增强多个见解之间的可比性。
首先创建一个包含 2 个 × 2 个支线剧情的剧情图,左边是线图,右上角是贴图,右下角是条形图。
**from **plotly.subplots** import make_subplots
fig = make_subplots(
rows=2, cols=2,
column_widths=[1, 0.4],
row_heights=[0.6, 0.4],
specs=[[{"type": "scatter", "rowspan": 2},
{"type": "choropleth"}],
[**None**, {"type": "bar"}]]
)**
使用add_trace
和go.Scatter
在第一个子情节中添加三行负片、中性片和正片。另外,row
和col
代表这个支线剧情在大图中的位置。
**fig.add_trace(go.Scatter(
x=time_series,
y=result["Num of '**{}**' mentions" \
.format(settings.TRACK_WORDS[0])] \
[result['polarity']==0].reset_index(drop=**True**), \
name="Neural",
opacity=0.8), row=1, col=1) fig.add_trace(go.Scatter(
x=time_series,
y=result["Num of '**{}**' mentions" \
.format(settings.TRACK_WORDS[0])] \
[result['polarity']==-1].reset_index(drop=**True**),
name="Negative",
opacity=0.8), row=1, col=1)fig.add_trace(go.Scatter(
x=time_series,
y=result["Num of '**{}**' mentions" \
.format(settings.TRACK_WORDS[0])] \
[result['polarity']==1].reset_index(drop=**True**), \
name="Positive",
opacity=0.8), row=1, col=1)**
使用add_trace
和go.Bar
添加主题频率分布的条形图。您可以使用rgb(xx,xx,xx)
或rgba(xx,xx,xx,x)
改变图中某些元素的颜色。
**fig.add_trace(go.Bar(x=fd["Word"], y=fd["Frequency"], \
name="Freq Dist"), row=2, col=2)
fig.update_traces(marker_color='rgb(59, 89, 152)', \
marker_line_color='rgb(8,48,107)', \
marker_line_width=0.5, opacity=0.7, row=2, col=2)**
然后在右上角插入地图,并设置位置和每个位置的编号。
**fig.add_trace(go.Choropleth(
locations=geo_dist['State'], *# Spatial coordinates*
z = geo_dist['Log Num'].astype(float), *# Data to be color-coded*
locationmode = 'USA-states',
colorscale = "Blues",
text=geo_dist['text'], *# hover text*
showscale=**False**,
geo = 'geo'
), row=1, col=2)**
在我们的图的布局中添加标题,缩小我们地图的地理范围,将模板主题变为暗,使用go.layout.Annotation
为布局添加 标注 。
**fig.update_layout(
title_text = \
"Real-time tracking '**{}**' mentions on Twitter **{}** UTC" \
.format(settings.TRACK_WORDS[0]
,datetime.datetime.utcnow().strftime('%m-%d %H:%M') \
),
geo = dict(
scope='usa',
),
template="plotly_dark",
margin=dict(r=20, t=50, b=50, l=20),
annotations=[
go.layout.Annotation(
text="Source: Twitter",
showarrow=**False**,
xref="paper",
yref="paper",
x=0,
y=0)
],
showlegend=**False**,
xaxis_rangeslider_visible=**True** )**
最后,显示单一图形中的所有支线剧情。
**fig.show()**
作者的话:这一章有点复杂,因为它使用 NLP 和情感分析方法将数据点转化为洞察力。通过使用先进的自然语言处理方法,可以实现对主题跟踪的进一步改进。
下一章将是最激动人心的部分,使用 Dash 在 Heroku 服务器上集成和部署所有功能。一如既往,我感谢您的任何反馈!😃
9 月 20 日更新: 第三章已出版!
用于品牌改进和话题跟踪的实时 Twitter 情感分析(第 3/3 章)
行业中的数据科学
使用 Python 中的 Dash & Plotly 在 Heroku 上部署一个实时 Twitter 分析 Web 应用程序
Photo by Kalen Emsley on Unsplash
本教程将教你 1)如何在 Heroku 云应用平台上部署所有数据分析,以及 2)如何使用 Python 中的 Dash 将基于 Plotly 的数据可视化迁移到分析仪表板 web 应用。
https://twitter-analysis-web-app.herokuapp.com
注 : 实时 Twitter 数据收集和数据分析&情感分析在前面章节已经完成。
- 第 1 章 : 使用 Tweepy、MySQL、& Python 的流 Twitter API 收集 Twitter 数据
- 第二章 : 使用 RE、TextBlob、NLTK 和 Plotly 的 Twitter 情感分析和交互式数据可视化
- **第三章(你来了!)😗*使用 Python 中的 Dash & Plotly 在 Heroku 上部署一个实时 Twitter 分析 Web 应用程序
- 第 4 章(可选) : 使用 Scala、Kafka 和 Spark Streaming 实现流媒体 Twitter 情感分析的并行化
为什么是 Dash?
- Dash 是一个用于构建 web 应用程序的高效 Python 框架。Dash 基于 Flask 、 Plotly.js 和 React.js 编写,非常适合用纯 Python 构建具有高度定制用户界面的数据可视化应用。
- Dash 核心组件**【DCC】**为交互用户界面提供增压组件。
- Dash Html 组件 (html) 围绕 Html、CSS、JavaScript 提供纯 Python 抽象。
为什么是 Heroku?
- Heroku 是一个平台即服务(PaaS),使开发者能够完全在云中构建、运行和操作应用。
为了运行实时 twitter 监控系统,我们将使用两个脚本(或者两个 dynos,或者两个 app)。一个用于采集流数据,另一个用于数据分析和实时可视化。在处理高吞吐量的 Twitter 文本数据时,这种方法可以有效地减少数据管道的延迟。
创建 Heroku 账号&设置环境
这部分是写给初学者如何从头开始建立新的 Heroku 应用程序环境。如果你熟悉 Heroku 平台,你可以考虑跳过这一部分。
两份重要部署指南供参考:
- Dash App 部署指南:https://dash.plot.ly/deployment
- Heroku 部署指南:https://devcenter.heroku.com/articles/git
在 Heroku:云应用平台 上注册你的账号
查看您的电子邮件确认您的帐户,然后登录 Heroku 平台。
点击新建按钮创建新的 app 。应用程序名称必须是唯一的,因为应用程序发布后,每个人都可以通过该名称访问 web 应用程序。
1.安装 Heroku CLI
首先下载并安装 Heroku CLI 。Heroku 命令行界面(CLI)是一个基本组件,允许我们通过终端创建和管理 Heroku 应用程序。
然后,登录您的 Heroku 帐户,按照提示创建一个新的 SSH 公钥。
$ heroku login
2.创建一个新的 Git 仓库
Heroku 使用 Git 对应用程序的开发进行版本控制。
$ mkdir Real-time-Twitter-Monitoring-System
$ cd Real-time-Twitter-Monitoring-System
2.用git
和virtualenv
初始化文件夹
$ git init *# initializes an empty git repo*
$ virtualenv venv *# creates a virtualenv called "venv"*
$ source venv/bin/activate *# uses the virtualenv*
$ Heroku git: remote -a **THIS-IS-YOUR-APP-NAME**
virtualenv
创建一个新的 Python 实例。你将需要使用此虚拟重新安装你的应用的依赖项新:
$ pip install dash
$ pip install plotly
$ pip install gunicorn
注意:gunicorn
是部署 app 的新依赖项。
3.设置几个必需的文件
用一个示例应用程序(app.py
)、一个.gitignore
文件、requirements.txt
和一个Procfile
来初始化文件夹,以便进行部署
一、创建一个名为 **app.py**
的文件,填写样例演示代码。
# Simple demo app only
import dash
app = dash.Dash(__name__)
server = app.server # the Flask app
二。创建 **.gitignore**
venv
*.pyc
.DS_Store
.env
三世。创建和**Procfile**
web: gunicorn app:server
(注意app
指的是文件名app.py
。server
是指该文件内的变量server
。
四。创建和**requirements.txt**
然后让我们添加这个长依赖项。注意:其中一些可能不会直接使用,但在您尝试调整应用程序时会很有用。
Click==7.0
dash==1.1.1
dash-core-components==1.1.1
dash-html-components==1.0.0
dash-renderer==1.0.0
dash-table==4.1.0
Flask==1.1.1
Flask-Compress==1.4.0
gunicorn==19.9.0
itsdangerous==1.1.0
Jinja2==2.10.1
MarkupSafe==1.1.1
plotly==4.1.0
PyYAML==5.1.2
retrying==1.3.3
six==1.12.0
Werkzeug==0.15.5
pandas==0.25.0
nltk==3.4.4
textblob==0.15.2
tweepy==3.8.0
psycopg2-binary==2.8.3
Flask==1.1.1
4.部署应用程序
初始化 Heroku app,向 repo 添加并提交代码,使用 Git 推送到 Heroku cloud。
$ heroku create **THIS-IS-YOUR-UNIQUE-APP-NAME**
$ git add .
$ git commit -m 'Initial the app'
$ git push heroku master # deploy code to heroku
Heroku cloud 应该已经在一开始为你设置了一个 dyno ,一个运行你的应用的集群。如果没有,则手动创建一个 dyno。
$ heroku ps:scale web=1 # run the app with a 1 heroku "dyno"
5.更新代码并重新部署
为了将来在 Heroku cloud 上更新我们的应用程序,我们只需要添加、提交并再次推送我们的新代码。
$ git status # view the changes
$ git add .
$ git commit -m 'a description of the changes'
$ git push heroku master
现在我们需要写一些真正的代码。
Photo by Jace & Afsoon on Unsplash
将数据分析&可视化从 Plotly 迁移到 Dash
为了将我们上一章的数据可视化放到 Heroku 应用程序上,我们需要用 Dash 框架包装我们基于 Plotly 的仪表板。所有的数据分析和可视化都将在文件**app.py**
中进行处理,您可以在这里 查看我的完整代码。
从一个新的应用服务器开始,使用 Dash 默认 CSS 表。注意:我推荐使用 Bootstrap 来改善 web app 的外观。
external_stylesheets=['https://codepen.io/chriddyp/pen/bWLwgP.css'] app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.title = 'Real-Time Twitter Monitor'server = app.server
Dash web app 的核心框架是使用 app.layout 作为背景布局。注意:点击下面的两个链接了解它们是如何工作的,并检查一些典型样品,因为它们对于使用 Dash非常重要。
仪表板布局
由于 Dash 构建在 HTML 之上,它以自己的方式使用 HTML(Dash HTML 组件)。但是一些 HTML 特性在 Dash 中是不允许的。
html.Div(id='live-update-graph')
描述应用程序中仪表板的顶部部分,包括对推文数量和潜在印象的描述。html.Div(id='live-update-graph-bottom')
描述 web app 中仪表板的底部部分。
dcc.Interval
是允许应用程序定期更新信息的关键。虽然数据收集器、将在后面解释,但在另一个 dyno 上分析仪表板实时工作,由于利用聚合数据进行可视化,并考虑到的成本效益,所以只分析和可视化每 10 秒的数据。
app.layout = html.Div(children=[
*# Parts of Title hided*
html.H2('This-is-your-tittle'), html.Div(id='live-update-graph'),
html.Div(id='live-update-graph-bottom'),
# Parts of Summary hided
html.Div(
dcc.Markdown("Author's Words: ...... ")
) # Timer for updating data per 10 seconds
dcc.Interval(
id='interval-component-slow',
interval=1*10000, # in milliseconds
n_intervals=0
)
], style={'padding': '20px'})}
对于 Dash 的 HTML 中的每个 Div,它都有className
、children
和style
。children
是dcc.Graph
(仪表板核心部件 中的图形)、dcc.Markdown
、html.Div
、html.H1
以及其他交互按钮(如dcc.Dropdown
、dcc.Slider
)的列表。
html.Div(
className='row',
children=[
dcc.Markdown("..."),
dcc.Graph(...),
html.Div(...)
],
style={'width': '35%', 'marginLeft': 70}
)
style
对于构建良好的布局和确保几个可视化图形之间的适当距离很重要,但调整细节可能很耗时。
下面举一个dcc.Graph
的例子( 仪表板核心部件 中的图形)。dcc.Graph
有属性id
和figure
。在figure
下有'data'
,包含 Plotly 中不同种类的图形(如go.Scatter
和go.Pie
),'layout'
,它只是这个图形的布局而不是app.layout
。
# import dash_core_components as dcc
# import plotly.graph_objs as godcc.Graph(
id='pie-chart',
figure={
'data': [
go.Pie(
labels=['Positives', 'Negatives', 'Neutrals'],
values=[pos_num, neg_num, neu_num],
)
],
'layout':{
'showlegend':False,
'title':'Tweets In Last 10 Mins',
'annotations':[
# ...
]
}
}
)
'[**annotations**](https://plot.ly/python/text-and-annotations/)'
是保证当前标签的另一个重要部分。注意:Dash 中标注 的引用相当**、**由于参数可能需要表示为go.layout.Annotation
、一个字典dict(...)
,有时还有一个列表。
破折号回调
在 Dash app 布局中,反应型和功能型 Python 回调提供输入和输出之间的连接,允许可定制的声明型 ui。
注:我们跳过了上一章解释的所有数据分析部分,尽管可能会有一点点差异(或改进)。因此,我们直接进入基于 Dash 的数据可视化部分,它是通过复杂的 Plotly graphs **plotly.graph_objs**
实现的(又名 go )。
# Multiple components can update everytime interval gets fired.
@app.callback(
Output('live-update-graph', 'children'),
[Input('interval-component-slow', 'n_intervals')]
)
def update_graph_live(n): # Lots of nested Div to ensure the proper layout
# Graphs will be explained later
# All codes are hided return children
三个线图都使用go.Scatter
和堆栈组来确保同一图形中线下的重叠区域。
# import plotly.graph_objs as go
go.Scatter(
x=time_series,
y=result["Num of A-Brand-Name mentions",
name="Neutrals",
opacity=0.8,
mode='lines',
line=dict(width=0.5, color='rgb(131, 90, 241)'),
stackgroup='one'
)
饼状图在上面dcc.Graph
的例子中解释过。
对于文本描述(例如每 10 分钟的 Tweet 数量变化),我们使用两个 HTML 段落来嵌入数据信息。通过比较之前的 10 分钟间隔和当前的 10 分钟间隔,我们可以生成这样的结果。
html.P(
'Tweets/10 Mins Changed By',
style={'fontSize': 17}
),html.P(
'{0:.2f}%'.format(percent) if percent <= 0 \
else '+{0:.2f}%'.format(percent),
style={'fontSize': 40}
)
对于今天的潜在印象,我们想知道最多有多少人有机会看到这些推文。通过计算发布这些推文的人的追随者数量的总和,我们可以得到潜在的印象。增加一个动态数字单元以更好地在非常大的范围内显示该值。
html.P(
'{0:.1f}K'.format(daily_impressions/1000) \
if daily_impressions < 1000000 else \
('{0:.1f}M'.format(daily_impressions/1000000)
if daily_impressions < 1000000000 \
else '{0:.1f}B'.format(daily_impressions/1000000000)), style={'fontSize': 40}
)
通过在每次应用数据更新中存储和累加推文数量,计算每日推文数量是一种简单的方法。并且该值将在午夜重置为零。
html.P(
'{0:.1f}K'.format(daily_tweets_num/1000),
style={'fontSize': 40}
)
底部仪表盘的回调函数与第一个类似。
@app.callback(Output('live-update-graph-bottom', 'children'),
[Input('interval-component-slow', 'n_intervals')])
def update_graph_bottom_live(n): # Lots of nested Div to ensure the proper layout
# Graphs will be explained later
# All codes are hidedreturn children
最热门话题追踪条形图。将orientation
设置为水平,以便更好地显示条形和相关的单词名称
go.Bar(
x=fd["Frequency"].loc[::-1],
y=fd["Word"].loc[::-1],
name="Neutrals",
orientation='h',
marker_color=fd['Marker_Color'].loc[::-1].to_list(),
marker=dict(
line=dict(
color=fd['Line_Color'].loc[::-1].to_list(),
width=1
),
)
)
通过设置'layout': {'geo':{'scope':'usa'}}
将范围聚焦在州级地图上
go.Choropleth(
locations=geo_dist['State'], # Spatial coordinates
z = geo_dist['Log Num'].astype(float), # Color-coded data
locationmode = 'USA-states',
text=geo_dist['text'], # hover text
geo = 'geo',
colorbar_title = "Num in Log2",
marker_line_color='white',
colorscale = ["#fdf7ff", "#835af1"]
)
为了在一行中并行多个图形,您可以考虑使用以下。width
应该是 1/N 百分比(N =图形数量),我们可以减去 1%以给出图形之间足够的间隙。
style={'display': 'inline-block', 'width': '33%'}
Photo by Banter Snaps on Unsplash
实现实时 Twitter 数据收集器
为了在不支付的情况下运行另一个与 web(用于互联网连接)连接的脚本,我们需要设置另一个应用**,除了app.py
和gunicorn
之外,配置完全相同。或者你可以花钱买一个新的 dyno 在原来的应用程序中运行。**
注意:由于两个应用程序的消耗,免费计划每月只能运行大约 3 周,如果 30 分钟不活动,web 应用程序可能会休眠,尽管数据收集器不会。
- 在新应用程序中创建一个新的应用服务器
scraping_server.py
,并在下面添加。
from os import environ
from flask import Flaskapp = Flask(__name__)
app.run(environ.get('PORT'))
2.在新应用程序中创建一个数据采集器文件scraping.py
,该文件与第 1 章中的文件非常相似。然而,这次我们将使用Heroku PostgreSQL而不是 MySQL,这也要求我们对 SQL 查询进行一点点更新。您可以在这里查看 代码 。
# Due to the similar code, check [Chapter 1](http://bit.ly/2Zohn01) for detailed explanation.
3.移除app.py
,更新gunicorn
如下。
worker: python scraping.py
web: python scraping_server.py
***注意:**别忘了创建credentials.py
和settings.py
,就像第一章中的一样。
通过 Heroku PostgreSQL 连接两个服务器/脚本/dyno
要在应用程序之间共享同一个 Postgres 数据库,请遵循本 指南 :
$ heroku addons:attach my-originating-app::DATABASE --app sushi
新方法:
Heroku 现在允许一个新的数据管道特性,所以你可以考虑利用这个优势,而不是使用我的两个应用程序连接一个 PostgreSQL 的方法。
作者的话:
感谢阅读!针对我的实时 Twitter 监控系统的这一系列文章已经结束,但是新技术的开发不会停止。第 4 章将在 10 月份作为独立文章发表。希望下次能见到你!