TensorFlow vs PyTorch:战斗仍在继续
本周,脸书宣布 PyTorch 1.5 的发布
照片由 @evanthewise 在 Unsplash 上拍摄
上周我们回答了问题 哪个是编程深度学习网络的最佳框架? *。*而今天呢?脸书发布了新的 PyTorch 1.5,其中包括几个基于脸书和 AWS 合作的项目?
领先的深度学习框架
张量流
如今有许多可用的深度学习框架,然而, TensorFlow (由谷歌开发并于 2015 年 11 月作为开源发布)是目前业界使用最多的。
几周前 TensorFlow 发布了 TensorFlow 2.2 的发布候选。在这个候选版本中,我将重点介绍已宣布的性能改进和帮助测量性能的新工具的引入,如新的性能分析器。他们还增加了 TensorFlow 生态系统的兼容性,包括像 TensorFlow Extended 这样的关键库。
PyTorch
三年前出现了 PyTorch 的第一个版本,毫无疑问,它正在获得巨大的发展势头。PyTorch 最初由脸书孵化,作为快速实验和原型制作的理想灵活框架,迅速赢得了声誉,在深度学习社区中赢得了成千上万的粉丝。例如,我的研究团队中的博士生选择使用 PyTorch,因为它很简单。它允许他们编写具有本机外观的 Python 代码,并且仍然可以获得良好框架的所有好处,如自动微分和内置优化。
深度学习框架领域的明确领导者现在是谷歌开发的 TensorFlow 和脸书开发的 PyTorch,他们正在从使用量、份额和势头上拉开市场的距离。
模型部署
然而,构建和训练模型只是故事的一半。在生产中部署和管理模型通常也是一个困难的部分,例如,构建定制的预测 API 并扩展它们。
处理模型部署过程的一种方法是使用一个模型服务器,以便于加载一个或多个模型,自动创建一个由可伸缩 web 服务器支持的预测 API。到目前为止,生产环境中的可部署性仍然是 TensorFlow 的强项,而服务于的 TensorFlow 是最受欢迎的模型服务器。
正如我们已经说过的,本周脸书发布了 PyTorch 1.5。新版本的重点是提供工具和框架,使 PyTorch 工作流可以投入生产。这篇文章中最引人注目的方面是 AWS 和脸书在项目 TorchServe 中的合作,这是 PyTorch 的开源模型服务器。
据 AWS 博客报道,一些客户已经享受到了 TorchServe 的好处。丰田研究所高级开发公司正在丰田汽车公司开发自动驾驶软件。或者是 Matroid ,一家检测视频片段中的物体和事件的计算机视觉软件制造商。
随着 PyTorch 不可阻挡的崛起,TensorFlow 在深度学习方面的主导地位可能正在减弱。
PyTorch 1.5 版本
显然,这个新的 PyTorch 版本包含了更多的特性。亮点是 torch_xla、torchaudio、torchvision、torchtext 的更新包以及与 TorchElastic 集成的新库。我来简单总结一下:
- TorchElastic 是一个用于大规模训练大规模深度神经网络的库,具有动态适应服务器可用性的能力。在这个版本中,AWS 和脸书合作扩展 TorchElastic 的功能,将它与 Kubernetes 集成在一起,成为 Kubernetes 的 TorchElastic 控制器。要了解更多信息,请参见火炬信贷回购。
- torch_xla 是使用 XLA 线性代数编译器在云 TPUs 和云 TPU Pods 上加速 PyTorch 深度学习框架的 Python 包。torch_xla 旨在让 PyTorch 用户能够在云 TPU 上做他们在 GPU 上能做的一切,同时最大限度地减少用户体验的变化。完整的文档和教程可以在这里和这里找到。
- torchvision 0.6 版本包括对数据集、模型和大量错误修复的更新。完整的文档可以在这里找到。
- torchaudio 0.5 版本包括新的变换、泛函和数据集。参见这里的发布完整说明。
- torchtext 0.6 版本包括许多错误修复,对文档的改进,根据用户的反馈,数据集抽象目前也正在重新设计。完整的文档可以在这里找到。
- 这个版本包含了重要的核心特性,比如对 C++前端的重大更新,或者用于模型并行训练的分布式 RPC 框架的稳定版本。该版本还有一个 API,允许创建定制的 C++类。你可以在这里找到详细的发行说明。
PyTorch 1.5 版本暗示,AWS-脸书的合作可能是使 AWS 成为运行 PyTorch 程序的首选云运行时的第一步。
综上
虽然 PyTorch 在脸书(和 AWS)的帮助下在市场上获得了发展势头,但 TensorFlow 继续在各个方面保持领先,例如已经推出的认证计划就是证明。
谷歌继续在加强其 TensorFlow 平台堆栈方面进行大量投资。但仍有待观察的是,脸书是否会继续以同样的节奏投资 PyTorch,以保持其至少与 TensorFlow 在功能上旗鼓相当。
展望未来,这些框架之间的功能差距将继续缩小,正如我们在之前的文章中已经讨论过的那样。
2021 年 5 月 29 日更新:本周我们看到了微软和脸书合作推出的 PyTorch 企业支持计划,为在 PyTorch 中构建生产应用的企业用户提供支持。作为计划的一部分,微软宣布在微软 Azure 上发布 PyTorch Enterprise。
深度学习网络编程的最佳框架是什么?
towardsdatascience.com](/tensorflow-or-pytorch-146f5397278a)
数据科学家的终端
学习你的第一个命令
简介
如果您还没有使用过命令行工具,那么是时候开始使用了。
本文介绍了让您开始这一旅程的第一批命令。
您将学习如何浏览文件夹和文件,并在不打开任何编辑软件或使用图形用户界面的情况下修改它们。
这将使你成为一个更有生产力和更好的数据科学家。
午餐你的终端窗口
如你所见,我把终端放在 Mac 的 Dock 中,所以我可以在那里吃午饭。
应用程序打开后,您应该会看到类似下面的终端窗口。它应该在当前用户空间中打开。我这里的用户叫‘konki’。
这是您将要输入命令的窗口!!!
** * 注意,我将在这里展示的命令对 MacOS 和其他 Unix 操作系统有效。如果您使用的是 Windows 命令提示符,这些命令中的大部分应该可以工作,但是其他的可能需要一些替换。
- pwd(打印工作目录)
第一个命令将显示您当前所在的目录。只需键入“pwd ”,如下所示:
konkis-MacBook-Air:~ konki$ pwd
/Users/konki
你可以看到我现在在’/Users/konki '目录中。
2。ls(列表)
这个命令列出了一个目录中所有文件。让我们看一看。
konkis-MacBook-Air:~ konki$ ls
Applications Downloads Music cd
Desktop Library Pictures seaborn-data
Documents Movies Public
你可以看到我有 11 个目录,没有文件(如果我有一些文件,你会看到一些扩展名的名称。例如 txt. or。py)
您可以使用带-a 参数的 ls 来显示隐藏文件:
konkis-MacBook-Air:~ konki$ ls -a
. .ipython Downloads
.. .jupyter Library
.CFUserTextEncoding .matplotlib Movies
.DS_Store .pgAdmin4.startup.log Music
.Trash .pgadmin Pictures
.astropy Applications Public
.bash_history Desktop cd
.bash_sessions Documents seaborn-data
看起来我有相当多的隐藏文件。那些是以点开头的(。).
还可以通过传递相对路径来检查当前不在的文件夹的内容。
ls Desktop/
上面的命令应该列出桌面目录的内容。
3。mkdir ( 制作目录)
该命令用于创建新目录。以下代码行在名为 test 的当前文件夹中创建一个新目录。
konkis-MacBook-Air:~ konki$ mkdir test
您可以使用’ ls '命令来检查它是否已被创建。
4。光盘(更改目录)
该命令用于将目录更改为给定路径的目录。一旦你创建了“测试”目录,你应该能够进入它。
konkis-MacBook-Air:~ konki$ cd test/
konkis-MacBook-Air:test konki$ pwd
/Users/konki/test
您可以使用上面的“pwd”命令来确认您的位置。
“cd”命令的其他有用变体是“cd”(不带参数)和“cd~”。它们都将带您到主目录。
cd
cd~
同样,“cd”的常见用法是返回到父目录,这可以用两个点来完成。
cd ..
5。触摸
您可以用它来创建一个新文件。下面的代码创建 my_file.py .然后使用’ ls '命令检查目录的内容。
konkis-MacBook-Air:test konki$ touch my_file.py
konkis-MacBook-Air:test konki$ ls
my_file.py
我们创建的文件只是一个空文件。py 扩展名。稍后我们可以添加一些 python 代码。
6。rm(删除)
我们可以用 remove 命令删除文件或目录。有了文件,用如下所示的文件名调用这个命令就足够了。
konkis-MacBook-Air:test konki$ rm my_file.py
konkis-MacBook-Air:test konki$ ls
konkis-MacBook-Air:test konki$
您总是可以确认文件是否是用上面的’ ls '命令删除的。
如果您想删除整个目录,您必须添加-r 参数。这将使 remove 命令递归地工作,并进入所有子目录来删除它们的内容。
rm -r <directory_name>
7。mv(移动)
你可以用“mv”命令移动文件和目录。您只需要指定要移动的文件或文件夹名称以及新的所需位置(文件夹或文件名)。
mv <file_name> <new_location>
让我们创建一个新文件,并将其移动到父目录。
konkis-MacBook-Air:Downloads konki$ touch file.txt
konkis-MacBook-Air:Downloads konki$ mv file.txt ..
最后一行将 file.txt 移动到父目录。记住,两个点**(…)**是父目录的快捷方式。
8。cp(副本)
您也可以复制文件和文件夹,而不是移动它们。该命令的结构类似于 move 命令。您需要指定要复制的文件和目的地。
cp <file_name> <new_location>
让我们创建一个新文件,并将其复制到父目录。
konkis-MacBook-Air:Downloads konki$ touch file_to_copy.txt
konkis-MacBook-Air:Downloads konki$ cp file_to_copy.txt ..
现在,如果您使用’ ls '命令,您将看到该文件仍然在它的原始位置。
如果您返回到带有“cd …”的父文件夹再次使用“ls ”,您会看到“file_to_copy.txt”也在那里。它在没有删除原始文件的情况下被复制到了那里。
9。man(手动)
当您忘记如何使用上述任何命令时,此命令非常有用。它会调出特定命令的手册。
man <command>
您可以使用“pwd”命令进行测试。
man pwd
这将打开对“pwd”命令的描述,如下图所示。
您可以使用箭头向下滚动访问底部的文本,并键入“q”退出文本文件。
总结
我想这是我在浏览 Macbook 和处理项目时最常使用的命令列表。与使用图形用户界面相比,它节省了我大量的时间和精力。
从学习这九条开始,努力做到每天都使用命令行。
原载于 aboutdatablog.com: 数据科学家终端,2020 年 8 月 26 日。
PS:我正在 Medium 和上撰写深入浅出地解释基本数据科学概念的文章。你可以订阅我的 邮件列表 每次我写新文章都会收到通知。如果你还不是中等会员,你可以在这里加入。**
下面是一些你可能会喜欢的帖子
数据科学家的最佳生产力工具,如果您还没有使用它,您应该使用它…
towardsdatascience.com](/jupyter-notebook-autocompletion-f291008c66c) [## 9 大 Jupyter 笔记本扩展
改进笔记本电脑功能,提高您的工作效率
towardsdatascience.com](/top-9-jupyter-notebook-extensions-7a5d30269bc8) [## 作为一名有抱负的数据科学家,你应该关注的中型作家
我最喜欢的 10 个数据科学博主,让你的学习之旅更轻松。
towardsdatascience.com](/medium-writers-you-should-follow-as-an-aspiring-data-scientist-13d5a7e6c5dc)**
白蚁第一部分:对隐私难题的回应
没有人真正阅读的隐私政策的数据科学解决方案
为什么是隐私?
“如果你没什么好隐瞒的,就不该担心。”这种经常听到的论点是一种错误的尝试,试图证明一个人的隐私受到损害是合理的。此外,我认为正是像这样的旁观者逻辑使得强者逐渐侵犯你的权利,直到为时已晚。
在加州大学伯克利分校信息学院的数据科学硕士(MIDS)项目的最后一个学期,学生们的任务是构建一个最小可行产品(MVP)。进入研究生院的最后阶段,我对有机会使用我在过去一年中发展的数据科学技能来促进我对一项有价值的事业的理解感到乐观。我和我的团队(詹妮弗·帕特森、朱利安·佩尔茨纳和奥利·唐斯)选择追求的目标是互联网隐私。
我对隐私的探索是由我同时受雇于安全与技术研究所而激发的。在对数字平台如何影响人类认知以及如何反过来影响民主制度进行初步研究时,我发现自己一直在想,为什么人们如此信任在线平台。反过来,为什么要对网络论坛持怀疑态度?(免责声明:对我设计的产品/插件的任何提及都不以任何方式隶属于安全与技术研究所,或他们的任何项目或程序。)虽然我仍然无法完全回答这些问题,但我参与的顶点项目为我提供了一个解决这些问题的机会。
在全球化的新冠肺炎疫情中,我们花在网上的时间比以往任何时候都多。因此,数据收集和监测也在增加。关于接触者追踪和监视的权衡的辩论正在我们眼前展开。一方面,追踪接触者可能有助于减少病毒的传播。另一方面,在我们战胜疫情后,政府将如何使用同样的监控技术?我们真的相信政府会放弃使用这些先进工具的特权吗?谁敢说权力机构不会转而使用类似的技术来驱逐移民或识别和骚扰表达其第一修正案抗议权利的公民?
我 11 年级的历史老师安迪·欧文斯曾经说过,“特权永远不会自动放弃。”我认为在这个不确定的时代,这仍然是真理。关于在线隐私的讨论再恰当不过了。这不是一个新问题。有关隐私风险规避和隐私行为的更深入讨论,请阅读与我们在一起很安全!消费者隐私科学作者亚里沙·弗里克和玛蒂尔达·拉克。本文中提到了几个有趣的发现:
- 十分之六的美国成年人认为日常生活中不可能不收集他们的数据,81%的人认为潜在的风险大于好处。
- 全球 69%的人表示,如果某个品牌的数据使用太具侵犯性,他们会避免与该品牌做生意。
- 在英国、美国、法国和德国,78%的人表示他们会保护自己的财务信息,相比之下,只有 57%的人会保护自己的联系信息。
- 只有 9%的美国人在签署条款和条件(T & Cs)之前会阅读隐私政策,47%的人表示对围绕欧盟一般数据隐私法规的信息感到厌倦。
- 72%的美国人觉得他们在网上或手机上做的几乎所有或大部分事情都被广告商和科技公司追踪。
- 48% 关心隐私的消费者因为公司或服务提供商的数据政策和做法而转向他们。
- 14%的英国人愿意分享数据,如果他们能得到报酬的话。但这些回报也可能是间接的。来自约克大学的研究表明 54%的英国人愿意牺牲一些数据隐私来缩短封锁期*。此外,如果一家公司在如何使用数据方面更加透明,73%的人会愿意分享数据。*
我们通过自己的用户研究证实了这些统计数据,研究显示,50%的受访者表示他们从未阅读过网站的隐私政策,我们的受访者中没有人表示他们总是阅读政策。此外,当被问及是否对互联网负有责任时,67.2%的受访者回答“不”或“我不知道”这不仅向我们表明互联网用户没有感觉到他们的安全需求得到了满足,也向我们表明许多用户只是不知道他们的信息是否安全。
我们寻求解决的问题与隐私政策有关,理想情况下,隐私政策应该是让用户对一家公司的安全数据收集做法感到放心的地方。然而,这种情况很少发生。隐私政策的主要问题是它们太长,充满了技术术语和“法律术语”隐私政策通常是由寻求使公司免受诉讼的律师撰写的。它们很少是为了保护用户利益和促进他们的意识而写的。最近,从公共关系的角度来看,构建更加透明的隐私政策变得越来越流行。然而,这些都是边缘案例,隐私政策对于普通互联网用户来说仍然难以阅读、理解、总结和分析。事实是大部分人都不看,不知不觉就同意了。
白蚁
这就是我们推出白蚁的原因:这是一款免费的浏览器附加工具,使用网页抓取和 NLP 方法来自动化和扩展在线服务条款、条款和合同以及隐私政策的评估和评级。白蚁还为用户提供定制的网络卫生报告,并使用户能够跟踪他们的在线协议,所有这些都是实时的。我们的目标是优化用户界面、感知和可操作性。当隐私政策和条款和条件是不可读的,白蚁率和跟踪他们。当用户对他们的信息安全感到不确定时,白蚁赋予他们权力。当网站利用用户不阅读他们的政策,白蚁让用户知道,保护他们。点击这里查看我们的简短演示!
克里斯·里瓦斯的标志(@the_hidden_talents)
有一些工具和服务,都服务于自己的领域。他们每个人在解决各自的问题空间方面都做得很好。总的来说,风景仍然不完美。在这些不同的努力之间缺乏一个哲学上的桥梁,留下了进一步连接这些点的机会。以下是我们当前隐私问题的一些现有解决方案及其各自的缺点:
Mozilla Firefox
Mozilla Firefox 是一款开源的网络浏览器,具有展示的 隐私第一 的精神,是市场份额第二大的浏览器。2018 年,Mozilla 基金会和 Mozilla 公司的总收入为 4.36 亿美元。他们目前占据了浏览器市场 7.58%的份额。相比之下,谷歌 Chrome 是最大的浏览器,目前占浏览器市场的 68.81%。Mozilla Firefox 培养了一家在隐私问题上言行一致的公司。
达克达克戈
DuckDuckGo 是一个搜索引擎,它会在可能的情况下自动加密用户与网站的连接(这样你的个人信息就不会被收集或泄露),阻止广告追踪器,并警告用户不良的隐私做法。按市场份额计算,他们是第六大搜索引擎,拥有超过 5000 万用户。2018 年,他们的估值在1000 万至 5000 万美元之间,目前他们代表着 1.36%的搜索引擎市场。相比之下,谷歌是最大的搜索引擎,目前占据 70.37%的市场份额。DuckDuckGo 代表了最全面、最成功的解决方案。
来源:https://duckduckgo.com/traffic
服务条款;没读过(ToS;博士)
服务条款;没读过(ToS;DR) 的成立是为了众包在线隐私政策分析和隐私等级。它值得被认为是对用户进行在线隐私教育的最佳尝试。对 ToS 的公正批评;然而,DR 认为,通过众包政策分析和评级,他们的网站得分缺乏一致性。此外,他们的隐私主题索引跨越了 24 个类别,太多了以至于没有帮助和用户友好。此外,他们的分析是用户生成的,这意味着由人类手动进行,导致站点分析的范围有限。
来源:https://tosdr.org/topics.html#topics
波利西斯
Polisis 是一个 chrome 扩展,为用户提供人工智能驱动的任何隐私政策摘要。作为一种可视化隐私政策的独特方式,Polisis 利用深度学习和人工智能来教育用户公司正在收集关于你的哪些数据,它正在分享什么,等等。你不必阅读完整的隐私政策和所有的法律术语来理解你在注册什么。用 Polisis 的话说,他们认为他们的产品“实现了对自然语言隐私政策的可扩展、动态和多维查询。Polisis 的核心是一个以隐私为中心的语言模型,由 13 万个隐私策略和一个新颖的神经网络分类器层次结构构建而成,既考虑了隐私实践的高级方面,也考虑了隐私实践的精细细节。”据 Chrome 扩展商店称,Polisis 拥有 1000 多名用户。他们将其隐私类别分为以下 10 类:1)第一方收集,2)第三方收集,3)访问、编辑、删除,4)数据保留,5)数据安全,6)特定受众,7)不跟踪,8)政策变化,9)其他,以及 10)选择控制。尽管 Polisis 是一个很好的工具,它采用了非常有趣的数据可视化,但我的经验是它很慢,而且不太用户友好。
特权者
Privee 是一个概念验证浏览器扩展,旨在自动分析隐私政策。他们夸口说他们已经分析了 38522 个网站,而且还在继续。Privee 自 2014 年以来一直没有被开发,在谷歌 chrome 扩展商店上只有 42 个用户。为了训练他们的模型,他们依靠 ToS;灾难恢复策略摘录注释。为了开发和测试他们的模型,他们使用正则表达式从新网站中提取适当的政策摘录。它们涵盖的以下六个隐私类别包括:1)收集、2)加密、3)广告跟踪、4)有限保留、5)剖析和 6)广告披露。
DuckDuckGo 等工具的创新,以及众包努力的相对成功(包括财务和分析服务形式)标志着一种趋势的开始。越来越多的公司要求在设计时考虑隐私原则。在缺乏足够广泛的监管和合规的情况下,学术界、私营部门和公民社会已经表明,他们愿意一点一点地解决隐私问题。尽管如此,还需要在尚未充分覆盖的领域取得更多进展。
作者图片
这篇博客是五篇博文的开始。在“白蚁第二部分:模型和特性选择”中,我讨论了我们团队面临的困境,以及我们不可避免要做出的决定。访问超链接中的零件三个、四个、五个。
特里纳尔伯特:量子化与蒸馏相遇
华为对 BERTology 的贡献
建造像伯特和 GPT-3 这样越来越大的模型的趋势一直伴随着一种互补的努力,即以很少或没有精度成本来减小它们的尺寸。有效的模型要么通过蒸馏(预训练蒸馏、蒸馏伯特、移动伯特、 TinyBERT )、量化( Q-BERT 、 Q8BERT )或者参数修剪来建立。
9 月 27 日,华为推出了 TernaryBERT ,这是一种利用蒸馏和量化来实现与原始 BERT 模型相当的精度的模型**,尺寸缩小了约 15 倍**。TernaryBERT 真正值得注意的是,它的权重是三进制的,即具有三个值之一:-1、0 或 1(因此只能存储在两位中)。
TernaryBERT 巧妙地将现有的量化和提炼技术结合在一起。这篇论文大量引用了以前的工作,因此相当密集。本文的目标是提供一个自包含的演练,并在需要时提供额外的上下文。
马库斯·斯皮斯克在 Unsplash 上拍摄的照片
量化
量化是减少用于表示单个标量参数的位数的过程。
当成功时,量化相对容易,因为它允许模型设计者保持原始模型的体系结构和配置不变:通过从 32 位切换到 8 位参数表示,可以实现 4 倍的大小缩减,而不必重新访问像层数或隐藏大小这样的设置。量化一般把实数值映射到整数值,可以有效得多的相加相乘。
量化方案
量化方案是确定一个实值 r 如何映射到一个可以由目标比特数(对于 8 比特:-128 到 127 包括在内,或者 0 到 255 不包括在内)表示的整数(或量子) q 的算法。最常见的是,量化方案是线性的。 r 和 q 之间的关系可以用比例因子 S 和零点 Z 来表示:
线性量化:用比例因子 S 和零点 Z 表示的真实值 r 与其量化值 q 之间的线性关系。方程式(1)来自 Jacob 等人[Q1]
在实值模型参数均匀分布在区间[-1,1]且量程从-127 到 127(暂时忽略-128 桶)的最简单情况下, r = 1/127 * q. 换句话说,比例因子 S 为 1/127 ,零点 Z 为 0 。当 r 不均匀分布时(假设其值主要为负值),零点会相应移动。例如,当 Z=10 时,我们将 10 个量子重新分配给负值,从而提高大多数 r 值所在区域的精度。
TernaryBERT 对其权重和激活都应用了线性量化(下面将详细介绍)。但就上下文而言,你应该知道还有其他方案。例如,在神经网络[Q2]的上下文中介绍了三值化(即量化为-1,0 和 1)的论文提出了一种随机算法,用于将实数 r ∈ [-1,1]转换为量化值 q ∈ {-1,0,1}:
- 如果 r ∈ (0,1)*q =*1 以概率 r 和 q =0 以概率 1-r.
- 如果 r ∈ [-1,0], q =-1 以概率 -r , q =0 以概率 1+r.
量子化应该在什么时候发生?
应用量化的最方便的时间是后训练:在用 32 位实值参数训练模型之后,应用标准量化方案之一,然后使用量化的模型进行有效的推断。然而,在实践中,这种天真的方法往往会导致精度大幅下降,尤其是针对超低精度(2 或 4 位)时。即使我们在这种训练后量化之后执行额外的微调步骤,结果仍然不能令人满意;量化降低了模型参数及其梯度的分辨率(即可以表示多少不同的值),从而阻碍了学习过程。
为了解决这个问题,Jacob 等人【Q1】提出了用模拟量子化进行训练:在正向传递过程中,模型的行为就好像它已经被量子化了一样。因此,损失和梯度是相对于这种位约束模型来计算的,但是反向传递照常在全精度权重上发生。这鼓励模型在量化正向传递期间表现良好(这是在推断时发生的),同时继续利用较长位参数和梯度的更好的表示能力。Q8BERT [Q3]使用这种技术(也称为量化感知训练)将原始的 BERT 模型从 32 位减少到 8 位整数表示。TernaryBERT 采用了类似的策略。
三元伯特中的权重三元化
TernaryBERT 通过如上所述的线性量化方案将其 32 位实值权重转换成具有来自集合{-1,0,1}的值的 2 位三进制表示。当零点固定为 Z=0 时,比例因子 S > 0 (从这里开始用 α 表示)与模型参数一起被学习。
由 Florencia Viadana 在 Unsplash 上拍摄的照片
不用说,将参数从 32 位降级到 2 位会带来精度的巨大损失。为了恢复模型的一些失去的表达能力,通常的做法是使用多个比例因子 αᵢ (而不是用于整个网络的单个 α ),一个用于参数(矩阵、向量、核、层等)的每个自然分组 i 。).例如,Rastegari 等人[Q4]在其卷积神经网络的每一层上为每个滤波器使用了单独的比例因子。类似地,TernaryBERT 为 BERT 的每个变换层添加一个 αᵢ ,并为令牌嵌入矩阵添加单独的每行缩放因子。
那么这些比例因子是如何习得的呢?如上所述,比例因子 αᵢ、全精度权重 w 和量化权重 b 都是在训练过程中学习的。TernaryBERT 比较了两种用于近似这些参数的现有方法:三元权重网络(TWN)【Q5】和损失感知三元化(LAT)【Q6】。虽然这两者具有看似不同的公式,但它们都归结为最小化量化前向传递的预测损失,并具有附加约束,其中在每个训练步骤期间,鼓励量化权重αb保持接近全精度权重 w 。
如果你时间不够,你可以直接跳到“激活量化”部分,确信 TWN 和拉特在 GLUE 基准(主要包含分类任务)和 SQuAD (一个流行的问题回答数据集)上得分相当。
选项 1: TWN(三元加权网络)
三进制权重网络 (TWN)将问题公式化为最小化全精度和量化参数之间的距离:
“基于近似的量子化”。在训练步骤 t 期间,选择量化参数 b 和比例因子 α ,使得它们最小化到全精度权重 w 的距离。这是来自三元伯特的方程式(5)。
因为这种最小化是在每个训练步骤上执行的,所以有效的实现是至关重要的。幸运的是,有一个近似的解析解,所以计算 b 和 α 就像应用一个依赖于 w 的公式一样简单(为简单起见,本文不包括)。
选项#2: LAT(损失感知三值化)
另一种方法,损失感知三值化 (LAT),是直接最小化相对于量化权重计算的损失;这个表达式完全避开了全精度参数(注意下面没有 w ):
“有损量化”。在整个训练过程中,选择量化参数 b 和比例因子 α ,使得它们最小化训练数据上的损失 L (关于 L 的定义,参见蒸馏部分)。来自三元贝的方程式(6)。
首先,上面的表达式应该看起来有些可疑:我们已经确定,以低位表示训练模型会受到精度损失的阻碍。当然,全精度权重 w 需要以某种方式参与进来。事实证明,该表达式可以根据每次迭代最小化子问题来重新表述,其中量化权重再次被鼓励接近全精度权重,但是以还考虑当前时间步长的损失的方式:
每迭代损失感知量化。在训练步骤 t 期间,选择量化参数 b 和比例因子 α ,使得它们最小化到全精度权重 w 的特定距离。这是来自三元伯特的方程式(7)。注意与等式(5)的相似性。这里的距离是以 v 表示的,即等式(6)中损耗 L 的对角近似值。
该表达式与等式(5)非常相似,不同之处在于它包括 v ,这是等式(6)中的损失的统计。与等式(5)类似,它有一个近似的解析解,是 w 的函数,可以有效地计算(同样,为了简单起见,不包括在本文中)。
激活量子化
在权重量化之后,该模型可以被描述为被分组为逻辑单元(例如矩阵)的一组三元权重,它们中的每一个都具有其自己的实值缩放因子 αᵢ 。因此,流经网络的值(层的输入和输出),也称为激活、是实值。为了加速矩阵乘法,激活也可以被量化。然而,正如在以前的工作[Q7]中提到的,激活对量子化更敏感;这很可能是为什么 TernaryBERT 决定将激活量化到 8 位而不是 2 位的原因。
西蒙·哈默在 Unsplash 上拍摄的照片
基于对变压器激活倾向于负向多于正向的观察,TernaryBERT 的作者选择了一种非对称量化算法,或者,根据高于r = S(q-Z)的线性量化表达式,零点 Z 不固定为 0,而是 r 的最小和最大可能值的中点
蒸馏
从最初天真的提议到执行训练后量化,我们已经走了很长的路。我们确定量化需要成为训练的一部分,需要多个比例因子来衰减由从 32 位降级到 2 位引起的精度损失,并探索了使量化权重接近全精度权重的两种不同方法。但是 TernaryBERT 告诉我们,通过利用机器学习工具箱中的另一种技术,我们可以做得更好。
提炼(或称知识提炼)是一个大而精确的模型(老师)将其知识转移到一个代表性力量较小的模型(学生)的过程。
换句话说,蒸馏是一个两步走的过程:1)训练一个大的老师使用金标签,2)训练一个小的学生使用老师制作的标签,也称为软标签*。辛顿等人[D1]解释说,蒸馏优于标准训练,因为软标签携带额外的信息,或暗知识。例如,在句子“我喜欢散步”中,考虑用单词“散步”的正确词性来标记它。形式为 p(名词)=0.9 的软标签比形式为 p(名词)=1.0 的硬标签更能提供信息,硬标签未能捕捉到“walk”在其他上下文中可能是动词的事实。TernaryBERT 在微调过程中使用相同的技术,从一个大得多的教师产生的软分布中学习:*
蒸馏损失第 1 部分:学生和教师预测之间的软交叉熵。来源:特里纳尔伯特。
诸如 FitNets [D2]等更精细的提炼公式鼓励教师和学生的内部表征之间的直接一致。TernaryBERT 也这样做,将完全精确的学生的隐藏层拉近教师的隐藏层,并鼓励两个转换网络的注意力分数相似:
蒸馏损失第 2 部分:学生/教师隐藏权重和注意力分数之间的均方误差。来源:三月伯特。
端到端:蒸馏感知三值化
蒸馏感知三值化。图 2 来自三月伯特。
TernaryBERT 将来自量化和提炼的既定技术放在一个单一的端到端配方下,用于训练三值化模型。在每个训练步骤中:
- 完全精确的学生是三位一体的。实际上,这相当于模拟量化,Jacob 等人[Q1]介绍的方法:正向传递在低表示中执行,以模拟在推断期间将真正发生的事情。使用前面描述的两种方法之一(TWN 或 LAT)来执行三值化。
- 蒸馏损失( L_pred + L_trm 根据量化模型所做的预测进行计算,但是梯度更新(即反向传递)应用于全精度参数。
在训练结束时,量化模型已准备好进行推断,无需进一步调整。
量化参考
- [Q1]雅各布等人,用于高效整数算术推理的神经网络的量化和训练 (2017)
- [Q2]林等,少乘法神经网络 (2016)
- [Q3] Zafrir 等人, Q8BERT:量化的 8 位 BERT (2019)
- [Q4] 拉斯特加里等人,XNOR 网络:使用二进制卷积神经网络的图像网络分类 (2016)
- 李等,三元权重网络 (2016)
- [Q6]侯,郭,深度网络的损失感知权重量化 (2018)
- [Q7]周等,DoReFa-NET:用低位宽梯度训练低位宽卷积神经网络(2018)
蒸馏参考
- [D1]辛顿等,在神经网络中提取知识 (2015)
- [D2]罗梅罗等人, FitNets:提示薄深网 (2014)
机器人可能会接管你的公司,但还不是时候
意见
利用最新的科学来辨别炒作和真相
摄影爱好在 Unsplash 上
这里有很多关于奇点事件和人工智能接管世界的讨论。他们自己的电脑会很快取代杰夫·贝索斯或马克·扎克伯格吗?
由于我是一名为经理开发卫星导航工具的首席执行官,并且卫星导航是走向无人驾驶汽车的第一步,这些天我经常被问及天网问题——科学家会让公司由机器人管理吗?
答案是绝对没有。原因如下。
奇点事件:炒作
当然,人工智能在过去的 30 年里突飞猛进。然而,我们甚至还没有接近机器可以复制或超越人类推理的奇点事件。
从本质上来说,这个新的数据科学术语是一个对大量数据处理活动的高贵称呼,这些活动大多是很久以前 发明的 。他们最近获得了新的生命,因为应用了大大增强的技术设备:更多的数据,更强的处理能力,更合理的结果,更便宜的价格。
随着存储和处理数据的成本下降,收集的数据量上升:非常简单的供求定律,或者你可以称之为数据的价格弹性。价格下降,交易量上升。这意味着 新数据的 值比旧数据小。纯经济学。然后,有人将不得不对所有这些东西做些什么。进入数据科学。
数据科学大多是老科学;有人记得专家系统吗?尽管大肆宣传,这项科学即使在今天也有严重的技术局限性:
- 仅自下而上,从数据向上。例如,图像被扫描成数百万或数十亿像素的集合,这些像素是数字的向量。低效:今天对某些问题有效,因为它很便宜,然而,它在学习上仍然慢得多,并且比使用人脑做任何其他事情都更昂贵。一个 3 岁的孩子能说出什么是香蕉当连续看到两张时,一个昂贵的系统需要 100 万张图像来训练自己,有 95%的信心,并且仍然会每 20 张图像犯一次错误。
- 只有电,缺少大脑的化学部分。神经网络是机器学习的核心,它们在复制大脑的电气部分方面有些成功:神经元和穿过它们的路径中交换的信号。尽管如此,对大脑中可能负责整体思维、情感和自上而下推理的化学部分的研究仍然很少:想想直觉。
最好的卫星导航系统甚至能驾驶你的车,但不能告诉你去哪里。
这是机器在结构上遗漏的大量功能。这正是人工智能与人类辩论的要点——机器做它们被编程做的事情,而人可以发挥创造力。
问正确的问题是人类的终极能力,只是遗憾的是,今天的学校正在教授如何回答问题,这正成为一种越来越不相关的技能。
这就是我们不必要地惊慌失措的原因吗?
优步、谷歌和特斯拉正在争论这个问题
目前,关于人工智能的辩论正在由自动驾驶汽车形成。随着优步、谷歌和特斯拉竞相推出市场上的第一辆无人驾驶汽车,人们认为这只是一个开端,并将很快导致机器运营一家公司,甚至是这个星球。
事情是这样的。
管理一家公司需要复杂的技能来驾驭模糊性和理解人类情感——这通常是“混乱的”和不可量化的。定义一个目标最终会改变市场,需要定义一个新的目标,一个叫做反身性的属性。
反身性指的是原因和结果之间的循环关系,尤其是在人类的信仰结构中。自反关系是双向的,在这种关系中,原因和结果都相互影响,但都不能被指定为原因或结果。
自动驾驶汽车只需要使用位置和速度等可测量的数据来读取物理事物——路况、其他汽车、行人。即使这样,也可能有程序员没有考虑到的“黑天鹅事件”,然而这些事件的数量是有限的,最终它们会被映射出来。
从结构上来说,一旦一辆车能开了,就完了;而管理行为将导致市场范式的转变,整个循环需要机器再次从头开始。
有趣的例子:认知失调
2012 年,在澳大利亚墨尔本,一辆运羊的卡车撞上了一座立交桥,导致数百只羊从下方的高速公路上倾泻而下。
虽然人类可以克服飞羊的认知失调,但你可以想象一个困惑的优步机器人说出那句古老的科幻栗子:不会计算!
这是一个意外事件的极端例子。笑一笑,解释一下为什么机器不会很快接管公司,可能会有所帮助。在管理的竞争游戏中,有许多绵羊在飞来飞去。
机器人企业:真相
当然,就像工业革命时期很多体力劳动岗位被机器取代一样,很多行政职能也可以转移到机器上。然而,更具创造性和高层次思维的角色将留在人类手中并得到加强。
使用的数据越多,就越需要领导力来指引方向。
这种人工智能/人类的相互作用一直是汽车制造商大众汽车公司近年来大量研究的主题。首席信息官马丁·霍夫曼(Martin Hoffman)解释了该公司如何将自动驾驶汽车的清单应用于“机器人企业”领域——在企业职能和流程中使用自适应算法。
一个例子
用一个实际的例子来总结:想象一下仓库重新订货过程的自动化,这是我个人非常熟悉的一个过程。今天,我们拥有可以让供应链自动运行的系统,除了策略仍然需要由人类来设定:
- 选择更多库存和更高成本的更好客户服务之间的权衡,还是选择投资更少但有缺货风险的更低库存?目标是未来几周的报道?
- 不存在最优水平,因为最佳答案是这取决于,决策的坐标要求将战略前景的变化转化为日常调整
- 机器决定了有效边界对于权衡来说,对于任何给定的目标覆盖周数,都只有一个最佳的仓储水平;人类必须选择周数。
大众汽车已经确定了 5 个人工智能控制级别,从人类做出所有商业决策的第 1 级(人工),到完全没有人类输入的第 5 级(全自动)。
一般来说,机器在大众汽车级别的 2 级(辅助)表现出色:机器提供建议,但人类做出最终决定。机器不会取代人类的判断,只会增强人类的判断,就像我们今天的手机每天都在增强我们的大脑一样。
快乐管理!
PS 我定期写关于 商业科学 。
测试你的数据,直到它受伤
理解大数据
数据测试故事
如果你从事分析工作,可以肯定你已经不止一次抱怨过数据质量问题。我们都有,痛苦是真实的!
作为一名数据工程师,数据及其质量是我最关心的。我敏锐地意识到良好的数据质量是多么重要——最近这个话题引起了一些热议,例如# 数据操作。有很多关于这个主题的文章:只需进入 DataKitchen 的 DataOps Medium 页面,或者如果你更喜欢 MLOps 这个术语,也有很多内容,比如来自 great expectations 博客的这篇关于 MLOps 中数据测试的博文。
还有更多——但是从我的经验来看,在实践中缺乏对系统数据测试和质量监控的采用。实际上,即使有数据测试,它也经常以一些断言被破坏到数据管道中而告终,污染了数据管道代码,并且没有创建任何数据质量问题的可见性。在这篇文章中,我想给我们的(正在进行的)数据测试之旅一些见解,以及为什么它会带来伤害!
数据质量
我看到的数据质量的第一个问题是,它是一个非常模糊的术语。如何定义数据质量或者哪些数据质量问题很重要的实际含义取决于您的用例以及您的数据类型。
一个常见的疑点是缺少数据/观察值,要么是因为记录不完整,要么是因为您管道中未被注意到的复制错误。企业数据存储中的上游作业发生了变化,数据中的行/观察值突然变少了。然后是错误的输入,也就是说,一个人在某个地方的字段中输入了一个明显错误或格式错误的数字。这样的例子不胜枚举。
好的,如果进入你系统的数据有问题,你输出的数据怎么办?即使你设法解决了这些问题,你能确保你发布的数据质量一流吗?另一个数据质量问题。
总而言之,在如何处理数据质量问题上,有许多事情需要考虑,还夹杂着许多噪音和不确定性。
你应该关心
如果您仍然认为您没有数据质量问题,因为您的代码通过了所有的自动检查,并且您模拟了所有的数据,甚至对您的样本数据进行了单元测试,那么您就错了!或者说,你现在可能是正确的,但最终当你的数据出现问题时(它们会出现),你很可能会在不知情的情况下使用并发布一些糟糕的数据。
如果你不测试你就不知道,就这么简单。所以现在就开始测试吧!而且一旦开始测试,就要测试到疼为止。如果您只是收集显示管道运行 X 行的数据指标,这样您就可以为您的自动化技能有多棒而沾沾自喜,这不会为您产生任何价值。或者反过来,套用丹尼尔·莫尔纳尔的话:“虚荣指标是无用的”,意思是不要监控那些让你看起来不错的指标,而是监控那些让你痛苦地发现什么是错的以及你需要纠正什么的不好的事情。如果测试没有伤害你,如果它们没有让你看到错误的地方,它们就没有价值。
测试你的数据,直到它受伤,这样你就可以修复问题并不断改进!
让我们把这个话题转到好的方面——我们可以做些什么来开始测试?我们怎样才能感受到好的痛苦?😅
**最重要的是开始。**从简单的事情开始。在我看来,测试我们的数据时,最大的价值可以从两件事情中获得:
- 如果数据质量不好,中断自动化管道
- 观察数据质量和意外数据/失败的管道
第一点是显而易见的,我们不想使用或发布坏数据,所以如果数据是坏的,我们就失败了。第二个几乎同样有价值:当你开始测试数据质量时,你很可能甚至不知道好数据是什么样子,也就是说,好数据的界限是什么,或者好的数据分布是什么样子?周末和工作日的数据可能会有变化,或者是您在处理初始数据集时没有注意到的季节性趋势。因此,为了保持数据质量,你需要学习和迭代好的数据实际上是什么样子的。
这对我们有用
到目前为止,我一直对我们实际上如何测试含糊其辞——所以让我们来看看我们的团队如何持续测试数据的一些更具体的例子。
正如我在一篇关于数据工程实践的文章中所写的:保持简单!如果你和我一样,经常使用 python 和 pandas,那么 great-expectations 是你开始数据测试之旅的绝佳起点。
远大期望的工作原理是构建期望套件(基本上是测试套件),随后用于验证数据批次。这些套件被保存为.json
文件,与您的代码一起存在。为了建立期望,您可以使用软件包中的一些基本分析器(或者编写自己的分析器——这相当简单),从一些建议开始,或者从头开始。让我们看一个简单的例子:
上面的例子假设您已经安装并初始化了这个包(我创建了这个 repo 来让您快速入门)。该示例展示了如何快速地将数据源添加到 great_expectations,将期望添加到期望套件,然后根据期望套件测试数据。您可以选择快速检查数据文档呈现。
关键特征
如前所述,我们想要瞄准的第一件事是,如果数据是坏的,就打破管道,然后我们想要观察数据质量随时间的变化。使用数据验证特性可以让您轻松地完成前一个任务:只需将验证作为管道的一部分运行,如果需要的话可以中断。后一个也包括在内,因为验证结果会告诉您哪里出错了,即哪些值是您没有预料到的。所以你马上就能知道哪里出了问题,并采取行动。
其他关键特性包括期望套件与代码共存,这对于版本控制来说是完美的。此外,您可以轻松地向您的套件添加注释,并捕获数据质量问题(它们可以很好地呈现在自动化数据文档中)。
因为所有这些都存在于您的代码库中(当然,您使用 git ),所以可以直接在团队中协作。在笔记本中添加编辑期望(带有可定制的 jinja 模板)是我们经常使用的功能:只需运行great_expectations suite edit <suite_name>
!
测试您的数据和数据分布。 great-expectations 允许您轻松测试数据分布。简单的均值、中值、最小值、最大值、分位数或更高级的东西,如库尔巴克-莱布勒散度。您可以使用mostly
关键字来表示大多数期望,以容忍一定比例的异常值。简单的内在期望会让你走得很远!
当然,还有更多:您可以根据管道运行时测试数据新鲜度,并使用运行时生成的评估参数或构建您自己的预期。还有很多内容我没有介绍,比如自动化数据文档、数据分析报告,它们都带有自动的 HTML 呈现,使共享和发布变得容易。
最重要的是,你可以很容易地参与到对代码库的贡献中来——这些人非常乐于助人,非常感激!
我们如何使用它
我们测试每个管道运行的输入和输出数据,与管道代码无关。我们的管道作为 kubernetes 作业运行,因此我们创建了一个简单的包装器,它读取命令行参数,解析数据集名称,将它们与一个期望套件进行匹配,并验证数据。
数据验证(蓝色菱形)与实际的管道代码分离,控制管道的失败、警报和发布。
上图是一个简单的图表,显示了当我们的任何管道运行时会发生什么:输入得到验证,然后实际的作业才运行。作业运行后,输出数据得到验证,然后数据才会被发布。如果对输出数据的验证失败,我们发布到一个failed
目的地,这样我们就可以在需要时检查输出。
疼痛
我们一把它投入生产,痛苦就开始了。我们花了大量的时间来分析数据,在非生产环境中运行所有带有新数据验证检查的管道。我们很自信。尽管如此,对于我们的数据以及数据随时间的变化,我们还有很多事情不知道。
几个星期以来,由于数据验证的原因,我们有失败的管道。有些是我们预料到的,但在某些时候,我觉得让我的一个支持轮换的同事经历这些真的很可怕:不断失败的运行,多次更新预期套件,清洗和重复。在开始的时候,很难弄清楚什么时候改变阈值/期望值,什么时候我们在看一个实际的问题。
只有痛苦。
增益
第一次痛苦消退后,我们很快看到奇怪的数据问题。在一个例子中,这使我们实际上发现了一些数据转换管道中的错误,这些错误只是随着时间的推移才显现出来。我们搞定了->利润!
在另一个例子中,我们实际上阻止了发布坏的预测——结果是从企业数据存储中复制数据的一个上游作业有不完整的数据😱。之前,这个 bug 已经导致我们在一个已知的事件中给出了一些不好的预测,其中有一些真实的💰对业务的影响。因此,阻止我们这样做是一笔可观的利润!
结论
这是真的:一分耕耘一分收获!
我们都知道我们必须检查我们的数据质量。一旦你打开了那罐蠕虫,你将很快感受到处理你发现的所有数据质量问题的痛苦。但好消息是:这是值得的。简单的数据测试可以让你走得更远,并显著提高你的产品质量。
在团队中,我与数据科学家密切合作,他们现在喜欢数据测试。他们欣赏这个工具以及它为团队和我们的产品创造的价值。我们用它不断改进我们的数据集,我们在测试上合作,测试不会因为管道代码而出错。
因此,尽管这一旅程可能会有痛苦,但这是非常值得的。立即开始测试您的数据!💯
测试你的技能:26 个(更多)数据科学面试问题和答案
来源: Pixabay
你能全部回答吗?
下面再来 26 个数据科学面试问答(以下是前 26 个)。这些问题按照数学和统计学到算法到深度学习到 NLP 的一般流程进行组织,其中穿插了数据组织问题。我建议在继续验证你的答案之前,先看看问题,花点时间想想答案。
无论你是大学生还是有经验的专业人士,每个人都可以花一些时间来测试(或更新)他们的技能!
你能全部回答吗?
来源:吉菲
1 |您可能会在数据中遇到哪些形式的选择偏差?
抽样偏差是一种系统误差,由于人口的非随机抽样,导致人口中的一些成员比其他成员少,例如低收入家庭被排除在在线民意调查之外。
时间间隔偏倚是指试验可能在一个极值提前终止(通常出于伦理原因),但该极值很可能由方差最大的变量达到,即使所有变量都具有相似的均值。
数据偏差是指选择特定的数据子集来支持一个结论,或者根据任意的理由拒绝不良数据,而不是根据先前陈述的或普遍同意的标准。
最后,流失偏倚是选择偏倚的一种形式,由参与者的损失引起,不考虑没有完成的试验对象。
2 |定义:错误率、准确度、灵敏度/召回率、特异性、精确度和 F 值。
其中 T 为真,F 为假,P 为正,N 为负,分别表示混淆矩阵中满足以下条件的项目数:
来源。图像免费共享和商业使用。
- 错误率:(FP + FN) / (P + N)
- 准确度:(TP + TN) / (P + N)
- 敏感度/召回率:TP / P
- 特异性:总氮/氮
- 精度:TP / (TP + FP)
- F-Score:精确度和召回率的调和平均值。
3 |相关性和协方差有什么区别?
相关性被认为是衡量和估计两个变量之间数量关系的最佳技术,它衡量两个变量的相关程度。
协方差衡量两个随机变量在周期中变化的程度。换句话说,它解释了一对随机变量之间的系统关系,其中一个变量的变化与另一个变量的相应变化相反。
4 |为什么 A/B 测试有效?
A/B 测试是对两个变量 A 和 B 的随机实验的假设测试。它的目标是识别例如网页中的任何变化,其中 A 组的客户被问候为“下午好”,而 B 组的客户被问候为“欢迎”,以查看哪一个可以促进销售。A/B 测试是有效的,因为它最大限度地减少了有意识的偏见——A 组的人不知道他们在 A 组,甚至不知道有 B 组,反之亦然。这是获取真实变量数据的好方法。然而,除了互联网业务,A/B 测试很难在任何环境下进行。
来源。图像免费共享和商业使用。
5 |你如何用一个骰子产生一个介于 1 和 7 之间的随机数?
一种解决方法是滚动骰子两次。这意味着有 6 x 6 = 36 种可能的结果。排除一种组合(比如 6 和 6),就有 35 种可能的结果。这意味着,如果我们指定五种掷骰子的组合(顺序很重要!)到一个数,我们可以生成一个 1 到 7 之间的随机数。
例如,假设我们掷出一个(1,2)。因为我们已经(假设地)将掷骰组合(1,1)、(1,2)、(1,3)、(1,4)和(1,5)定义为数字 1,所以随机生成的数字将是 1。
6 |区分单变量、双变量和多变量分析。
单变量分析是只对一个变量进行的统计分析技术。这可能包括饼图、分布图和箱线图。
双变量分析试图理解两个变量之间的关系。这可以包括散点图或等高线图,以及时间序列预测。
多变量分析处理两个以上的变量,以了解这些变量对目标变量的影响。这可以包括为预测或 SHAP 值/排列重要性训练神经网络,以找到最重要的特征。它还可以包括具有第三特征(如颜色或大小)的散点图。
7 |什么是交叉验证?它试图解决什么问题?为什么有效?
交叉验证是一种评估模型如何推广到整个数据集的方法。在传统的训练-测试-分割方法中,随机选择一部分数据作为训练数据,另一部分数据作为测试数据,这可能意味着模型在某些随机选择的测试数据部分表现良好,而在其他随机选择的测试数据部分表现不佳。换句话说,性能并不完全代表模型的性能,因为它代表了测试数据的随机性。
来源。图像免费共享和商业使用。
交叉验证将数据分成 n 段。该模型在数据的 n- 1 段上被训练,并在数据的剩余段上被测试。然后,在不同的一组 n -1 段数据上刷新和训练模型。重复此操作,直到模型获得整个数据的预测值(对结果进行平均)。交叉验证很有帮助,因为它提供了模型在整个数据集上的性能的更完整视图。
8 | naive Bayes 中的 Naive 是什么意思?
朴素贝叶斯算法基于贝叶斯定理,贝叶斯定理描述了基于可能与通风口相关的条件的先验知识的事件概率。该算法被认为是“幼稚”的,因为它做出了各种可能正确也可能不正确的假设。这就是为什么正确使用时它会非常强大——它可以绕过其他模型必须找到的知识,因为它假设这些知识是真实的。
9 | SVM 有哪些不同的果仁?
SVM 有四种核仁:
- 线性核
- 多项式核
- 径向基核
- Sigmoid 内核
10 |决策树过拟合的解决方案是什么?
决策树通常有很高的倾向性,因为算法的本质涉及到在数据中寻找非常合适的模式,并创建一个特定的节点来解决这个问题。如果放任不管,决策树将创建如此多的节点,以至于它将在训练数据上完美地执行,但在测试数据上失败。一种解决决策树过度拟合的方法叫做修剪。
过度适应数据的决策树。来源。图像免费共享和商业使用。
修剪是一种减少决策树大小的方法,它通过删除树中几乎没有分类能力的部分来实现。这有助于一般化决策树,并迫使它只创建数据结构所必需的节点,而不仅仅是噪声。
解释并给出协同过滤、内容过滤和混合过滤的例子。
协同过滤是推荐系统的一种形式,它仅仅依靠用户评级来确定新用户下一步可能喜欢什么。所有产品属性要么通过用户交互学习,要么被丢弃。协同过滤的一个例子是矩阵分解。
内容过滤是另一种形式的推荐系统,它只依赖于产品和客户的内在属性,如产品价格、客户年龄等。,提出建议。实现内容过滤的一种方式是找到简档向量和项目向量之间的相似性,例如余弦相似性。
混合过滤取二者之长,将内容过滤推荐和协同过滤推荐结合起来,实现更好的推荐。然而,使用哪种过滤器取决于现实环境,混合过滤可能并不总是确定的答案。
12 |在合奏中,装袋和助推有什么区别?
Bagging 是一种集成方法,其中通过从主数据集中随机选择数据来准备几个数据集(在几个子数据集中会有重叠)。然后,在几个子数据集中的一个上训练几个模型,并且通过一些函数聚集它们的最终决策。
提升是一种迭代技术,它调整最后一个分类的观测值的权重。如果一个观察被正确地分类,它试图增加观察的权重,反之亦然。提升降低了偏差误差,并建立了强大的预测模型。
13 |合奏中的硬投票和软投票有什么区别?
硬投票是当每个模型的最终分类(例如,0 或 1)被聚集时,可能通过平均值或模式。
软投票是将每个模型的最终概率(例如,分类 1 的 85%把握)汇总,最有可能是通过平均值。
软投票在某些情况下可能是有利的,但可能导致过度拟合和缺乏普遍性。
来源:吉菲。
14 |您的机器有 5GB 内存,需要在 10 GB 数据集上训练您的模型。你如何解决这个问题?
对 SVM 来说,部分适合就可以了。数据集可以分成几个较小的数据集。因为 SVM 是一个低计算成本的算法,它可能是这种情况下最好的情况。
在数据不适合 SVM 的情况下,可以在压缩的 NumPy 阵列上训练具有足够小批量的神经网络。NumPy 有几个压缩大型数据集的工具,它们被集成到常见的神经网络包中,如 Keras/TensorFlow 和 PyTorch。
深度学习理论已经存在了很长一段时间,但直到最近才变得流行起来。为什么你认为深度学习在最近几年激增了这么多?
深度学习的发展正在加快步伐,因为直到最近它才成为必要。最近从物理体验到在线体验的转变意味着可以收集更多的数据。由于转向线上,深度学习有更多的机会来提高利润和增加客户保留率,这在实体杂货店中是不可能的。值得注意的是,Python 中两个最大的机器学习模型(TensorFlow & PyTorch)是由大型公司谷歌和脸书创建的。此外,GPU 的发展意味着可以更快地训练模型。
(尽管这个问题严格来说与理论无关,但能够回答这个问题意味着你也着眼于你的分析如何在企业层面得到应用。)
16 |你如何初始化神经网络中的权重?
最传统的初始化权重的方式是随机的,将它们初始化为接近 0。然后,一个正确选择的优化器可以把权重放在正确的方向上。如果误差空间太陡,优化器可能难以摆脱局部最小值。在这种情况下,初始化几个神经网络可能是一个好主意,每个神经网络位于误差空间的不同位置,从而增加找到全局最小值的机会。
17 |没有设定准确的学习率会有什么后果?
如果学习率太低,模型的训练将进展非常缓慢,因为权重的更新很少。然而,如果学习率设置得太高,这可能导致损失函数由于权重的剧烈更新而不稳定地跳跃。该模型也可能不能收敛到一个误差,或者在数据太混乱而不能训练网络的情况下甚至可能发散。
18 |解释一个时期、一批和一次迭代之间的区别。
- Epoch:表示对整个数据集的一次运行(所有内容都放入训练模型中)。
- 批处理:因为一次性将整个数据集传递到神经网络的计算开销很大,所以数据集被分成几批。
- 迭代:一个批次在每个时期运行的次数。如果我们有 50,000 个数据行,批量大小为 1,000,那么每个时期将运行 50 次迭代。
19 |什么是三个主要的卷积神经网络层?它们通常是如何组合在一起的?
在卷积神经网络中通常有四个不同的层:
- 卷积层:执行卷积操作的层,创建几个图片窗口,概括图像。
卷积层。来源: Giphy 。
- 激活层(通常是 ReLU):给网络带来非线性,将所有负像素转换为零。输出变成校正的特征图。
- 池层:降低特征图维度的下采样操作。
通常,卷积层由卷积层、激活层和池层的多次迭代组成。然后,可能会跟随一个或两个额外的密集或下降图层以进一步概化,并以完全连接的图层结束。
20 |什么是辍学层,它如何帮助神经网络?
脱落层通过防止训练数据中复杂的共适应来减少神经网络中的过拟合。脱落层作为一个掩膜,随机阻止与某些节点的连接。换句话说,在训练期间,脱落层中大约一半的神经元将被停用,迫使每个节点携带更多被停用的神经元遗漏的信息。在最大池层之后,有时会使用退出。
应用辍学之前/之后的神经网络。来源。图片免费使用,有信用。
21 |在简化和基本的尺度上,是什么使新开发的 BERT 模型优于传统的 NLP 模型?
传统的 NLP 模型,为了熟悉文本,被赋予预测句子中下一个单词的任务,例如:“It’s raining cats and”中的“dog”。其他模型可以另外训练它们的模型来预测句子中的前一个单词,给定该单词之后的上下文。BERT 随机屏蔽句子中的一个单词,并迫使模型预测该单词及其前后的上下文,例如:“It’s _____ cats and dogs”中的“raining”
这意味着伯特能够理解语言的更复杂的方面,而这些方面不能简单地通过以前的上下文来预测。BERT 还有许多其他的特性,比如各种层次的嵌入,但是从根本上来说,它的成功来自于它阅读文本的方式。
22 |什么是命名实体识别?
NER,也称为实体识别、实体分块或实体提取,是信息提取的一个子任务,它试图定位非结构化文本中提到的命名实体并将其分类为诸如名称、组织、位置、货币值、时间等类别。NER 试图分离拼写相同但意思不同的单词,并正确识别名称中可能有子实体的实体,如“美国银行”中的“美国”。
给你一大堆推文,你的任务是预测它们是积极的还是消极的情绪。解释如何预处理数据。
由于推文充满了可能有价值的信息的标签,第一步将是提取标签,并可能创建一个一次性编码的特征集,其中如果有标签,推文的值为“1 ”,如果没有标签,则为“0”。对@ characters 也可以这样做(无论 tweet 指向哪个帐户都可能很重要)。推文也是被压缩的文字(因为有字符限制),所以可能会有很多故意的拼写错误需要纠正。也许推文中拼写错误的数量也会有所帮助——也许愤怒的推文中有更多拼写错误的单词。
删除标点符号虽然在 NLP 预处理中是标准的,但在这种情况下可能会被跳过,因为感叹号、问号、句点等的使用。与其他数据结合使用时可能很有价值。可能有三列或更多列,其中每行的值是感叹号、问号等的数量。但是,在将数据输入模型时,应该去掉标点符号。
然后,数据将被词条化和标记化,不仅有原始文本要输入模型,还有关于标签、@s、拼写错误和标点符号的知识,所有这些都可能有助于提高准确性。
24 |你如何找到两段文字之间的相似之处?
第一步是将段落转换成数字形式,使用一些选择的矢量器,如单词袋或 TD-IDF。在这种情况下,单词包可能更好,因为语料库(文本集合)不是很大(2)。此外,它可能更符合文本,因为 TD-IDF 主要是针对型号的。然后,可以使用余弦相似度或欧几里德距离来计算两个向量之间的相似度。
25 |在 N 个文档的语料库中,一个随机选择的文档包含总共 T 个术语。术语“hello”在该文档中出现了 K 次。如果单词“hello”在全部文档中出现了大约三分之一,那么 TF(单词频率)和 IDF(逆文档频率)的乘积的正确值是多少?
术语频率的公式是 K/T,IDF 的公式是总文档数对包含该术语的文档数的对数,或者是 1/1/3 的对数,或者是 3 的对数。因此,’ hello '的 TF-IDF 值是 K * log(3)/T。
有没有一套通用的停用词?你什么时候会提高停用词的“严格性”,什么时候会对停用词更宽容?(对停用词宽容意味着减少从文本中删除的停用词的数量)。
Python 中的 NLTK 库中存储了普遍接受的停用词,但是在某些上下文中,它们应该被加长或缩短。例如,如果给定一个 tweet 数据集,停用词应该更宽松,因为每个 tweet 一开始就没有太多内容。因此,更多的信息将被压缩到简短的字符中,这意味着丢弃我们认为是无用的词可能是不负责任的。然而,如果给定,比如说,一千篇短篇小说,我们可能希望对停用词更严格一些,这样不仅可以节省计算时间,而且可以更容易地区分每篇小说,因为每篇小说都可能多次使用停用词。
感谢阅读!
来源: Giphy
你答对了几个?这些问题针对统计、算法、深度学习、NLP 以及数据组织和理解,这应该是衡量您对数据科学概念熟悉程度的一个很好的标准。
如果你还没有,请点击这里查看另外 26 个数据科学面试问题和答案。
用数据科学的魅力测试基于 Python 的 API 调用
尤利娅·卢卡希娜
使用 Python asyncio 和 concurrent.futures 包测试 ThreadPoolExecutor 函数中的线程数量(max_workers 参数)的实验。
软件测试一瞥
随着计算机应用程序趋向于被授予更多的人类决策权,软件工程行业已经认识到测试是开发过程的一个基本部分。
软件测试的方法多种多样。应用程序作为一个整体,或者作为集成系统,甚至是一个单元一个单元地被测试。我们有测试工程师、测试经理和测试人员。有提供外包手工测试的平台,也有自动化测试:从字面上看,应用程序操作其他应用程序,甚至经常模仿一个活生生的用户。
为什么要测试 API?
案例研究是关于测试 API 调用性能的。Python asyncio 和 concurrent.futures 包用于运行多个 API 调用。他们将循环运行分成池,并以并行方式通过几个池,从而同时执行多个调用。这减少了总的执行时间。
最佳线程数的问题出现在以下方面。让我们想象一下,有一个移动应用程序访问一个提供 API 的开源数据库。我需要编写一个 API 调用来成功检索数据,并将其集成到应用程序中。这种集成应该包括接收数据的第一次处理。
正如我将在下一节中展示的,在最初处理数据的过程中,我遇到了一些问题。数据只能以小块的形式下载,因此,迫使我提出多个请求。这可能会降低应用程序的性能,破坏用户体验。
这个事实让我更加关注 API 调用本身,尽管最初,我的主要任务是在应用程序内部构建一个数据管道。
因此,我开始尝试 API 调用。
这个实验的目的是找出一个最佳的线程数量,或者并行调用的最大数量。这个数字有其限制,取决于不同的因素。
在我经历了一些痛苦的错误之后,我设法坚持了一个特别的系统化的方法,我将会公开这个方法。这篇文章展示了完成测试代码的步骤,附在文章的最后。
对数据的第一次了解
我用一个电影数据库中的数据来说明本文,该数据库包含关于电影的信息,比如标题、发行日期、类型、演员和工作人员等等。API 调用应该获取特定电影类型的所有电影的数据。
我使用了一个通用的 Python 请求包来发出一个简单的请求,并检查这个请求是否有意义。我获取了一个 JSON 并将其打印到控制台。第一眼看上去不错。但后来似乎有一些人为强加的限制。我只能读到 500 页,收集 10,000 部电影。
发现页面限制
我查了一下电影的实际数量,结果是 20 部。
每页/API 请求的结果
我发出了第二个请求,表明我希望通过添加“&page=2”来提取第 2 页。结果是相似的,只是我得到了另外 20 部电影。
似乎我必须快速翻阅一大堆页面才能找到所有的电影。我添加了一个遍历 500 页的 for 循环。我抓取了 asyncio 和 concurrent.futures 包,通过使用多线程(我设置为 100)来加速 for 循环的执行。
这一过程在几秒钟内完成,并成功收集了 10,000 部电影。
import asyncioimport nest_asyncioimport concurrent.futuresimport requestsnest_asyncio.apply()movies = []async def main(url, m_workers):with concurrent.futures.ThreadPoolExecutor(max_workers=m_workers) as executor:loop = asyncio.get_event_loop()futures = [loop.run_in_executor(executor,requests.get,url + '&page=' + str(i),)for i in range(1, 501)]for response in await asyncio.gather(*futures):try:dict = response.json()for item in dict['results']:movies.append(item)except:passloop = asyncio.get_event_loop()loop.run_until_complete(main(my_url, 100))
但我必须记住,这个请求是为移动应用程序考虑的。到目前为止,我构建了请求代码,并使用运行在云中的 Google Colaboratory 检查了数据。
API 性能因素
正如一位 StackOverflow 开发者指出的那样,API 调用的速度取决于以下因素:
- 网络速度和延迟
- 服务器可用性和负载
- 数据有效负载的大小
- 客户端设备资源
- 客户代码
- 在所有这些因素中,我只能控制网络、设备和客户端代码。
网络
为了模拟移动网络速度,我将移动热点连接到笔记本电脑上。根据来自 Computerbild.de 的信息,我所在位置的 LTE 网络显示速度如下:
计算机网络服务器
我必须在测试中发现服务器的容量。我没有控制这个参数。
数据量
每个 API 调用发送同一个请求并下载相同数量的数据。这个实验不测试数据量的任何变化。
每个请求返回一个字典。它的结果部分—一个列表—包含多达 20 个条目。每个条目都是一个有 14 个键和值的字典。
使用另一个 JSON 解析器是可能的,但是我不认为标准解析器是个问题。
最终用户设备
由于数据将通过移动网络发送和接收,因此在实验中考虑了这一因素。
我在本地的一台 Mac 电脑上用一台 Jupyter 笔记本进行了 API 调用测试,这台电脑有两个内核,运行速度为 1.7 GHz。
网络连接,我用的是 iPhone 6。正如 Everymac.com 的所说:
它拥有双核,运行频率约为 1.4 GHz。
采用 A13 芯片的最新 iOS 设备拥有六个 CPU 核心,两个 Lightings 和四个 Thunders。第一批运行频率为 2.66 GHz。(信息来自一篇连线文章)。
在八核(2.3GHz 四核+ 1.6GHz 四核)或四核(2.15GHz + 1.6GHz 双核)处理器上运行,具体取决于国家或运营商。
在这方面,我的测试是一种最坏的情况。
客户代码
考虑到目前的限制,比如数据的规定结构,我只能在线程数量上做些调整。这基本上是客户端代码的主要变化。
在线程数上循环
所以,让我们回到主测试。
我从云转移到本地运行时,并做了一些网络和硬件降级。
在这个新环境中,我提出了几乎相同的要求。两次运行 100 个线程都抛出了类似的错误:
HTTPSConnectionPool(host=’api.host.org’, port=443): Max retries exceeded with url: apiurlwithapikey (Caused by NewConnectionError(‘<urllib3.connection.VerifiedHTTPSConnection object at 0x10e44f2d0>: Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known’))
这意味着我用尽了网络或服务器,或者两者都用尽了。我把它减速到 50 个线程,让它运行两次,但还是出现了同样的错误。仅用 10 个线程,我就安全下载了所有 10,000 部电影。
由于我仍然认为 10 个线程对于确保移动应用程序中令人满意的用户体验来说太少了,所以我引入了一个 for 循环,该循环多次运行 main()函数,以等于 10 的步长将最大活动线程数从 10 改为 100。
我添加了一个简单的跟踪方法,保存异步循环的持续时间、返回的电影数量、检查的页面数量和线程数量。持续时间是通过两个时间戳之间的差来测量的:一个在循环开始之前,一个在循环完成之后。
我把列表转换成字典,然后字典变成了熊猫的数据框。
为了防止服务器耗尽,我使用了时间包中的睡眠功能来安排通话中断。
import asyncioimport nest_asyncioimport concurrent.futuresimport requestsfrom datetime import datetimeimport timeimport pandasasync def main(url, m_workers):with concurrent.futures.ThreadPoolExecutor(max_workers=m_workers) as executor:try:loop = asyncio.get_event_loop()except:passtry:futures = [loop.run_in_executor(executor,requests.get,url + '&page=' + str(i),)for i in range(1, 501)]except requests.exceptions.ConnectionError:print("Connection refused")passfor response in await asyncio.gather(*futures):try:dict = response.json()for item in dict['results']:movies.append(item)except:passnummoviesList = []pagescheckedList = []itlastedList = []maxworkersList = []for threads in range(10,101,10):try:movies = []executorList = []n = datetime.now()loop = asyncio.get_event_loop()try:loop.run_until_complete(main(genre_18_url, threads))except:passnummoviesList.append(len(movies))pagescheckedList.append(len(movies) / 20)nn = datetime.now()diff = nn - nitlastedList.append(diff)maxworkersList.append(threads)except:print("interrupted at ", threads)time.sleep(10)resultsdict = {'threads': maxworkersList, 'movies': nummoviesList, 'pages': pagescheckedList, 'duration': itlastedList}testresults = pandas.DataFrame(resultsdict)
我确实得到了大部分空的响应,但是有几个返回了正常的结果:
测试结果运行 1
这种趋势并不十分明显:当线程数量增加时,API 调用会变得更快,在 10 到 30 个线程之间,速度会大大加快。但是持续时间(显示为完成一个请求的秒数)变得不稳定,并且又增加了 100 个线程。
所有红点表示没有获取任何数据的运行。乍一看,持续时间/速度、线程数量和检索到的数据之间没有联系。我再次运行包装循环,结果明显不同:
测试结果运行 2
趋势几乎是一样的:越匆忙——我使用的线程越多——得不到数据的可能性就越大。
另一件重要的事情,也是我继续测试的原因。从移动应用发出的每个 API 请求至少需要 8 分钟,这是一场灾难。没有用户会等这么久!
在下一个循环中包装代码
我本可以再按几次“运行”来重复循环,但是我决定添加另一个循环——我通常喜欢循环——并且我以代码结束:
import asyncioimport nest_asyncioimport concurrent.futuresimport requestsfrom datetime import datetimeimport timeimport pandasasync def main(url, max_workers):with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:try:loop = asyncio.get_event_loop()except:passtry:futures = [loop.run_in_executor(executor,requests.get,url + '&page=' + str(i),)for i in range(1, 501)]except:passfor response in await asyncio.gather(*futures):try:dict = response.json()for item in dict['results']:movies.append(item)except:passgrandresult = pandas.DataFrame(columns = ['threads', 'movies', 'pages', 'duration', 'run'])for x in range (1,11):nummoviesList = []pagescheckedList = []itlastedList = []maxworkersList = []for max_workers in range(10,101,10):movies = []try:executorList = []n = datetime.now()loop = asyncio.get_event_loop()try:loop.run_until_complete(main(my_url, max_workers))except:passnummoviesList.append(len(movies))pagescheckedList.append(len(movies) / 20)nn = datetime.now()diff = nn - nitlastedList.append(diff)maxworkersList.append(max_workers)except:print("interrupted at ", max_workers)time.sleep(10)resultsdict = {'threads': maxworkersList, 'movies': nummoviesList, 'pages': pagescheckedList, 'duration': itlastedList}testresults = pandas.DataFrame(resultsdict)testresults['run'] = xgrandresult = grandresult.append(testresults)print('end run ' + str(x))time.sleep(60)
正如你所看到的,有一个新的列:“运行。”它显示了运行的顺序。
我复制了一份,以防万一。然后我查看了每个线程数的平均性能。
我只跑了 9 次,所以电影栏变得有点混乱。如果平均值低于 450,则每次并未获取所有电影。但是我们仍然可以看到成功的运行是最慢的。最快的只是不完整。
让我们把它全部放在一张图表上。
API 调用持续时间与线程数量:按运行分组
对于这个可视化,我删除了三个或四个异常值。圆点的颜色表示外部 for 循环中的不同运行。没有任何颜色聚类表示单次运行在性能上没有区别。只有一些线程起作用。
然后,我根据是否获取了任何数据来给这些点着色(深紫色或 0 表示没有数据,黄色或 1 表示下载了所有电影)。
API 调用持续时间与线程数量:按成功或失败分组(0 =失败,1-成功)
最后一个可视化结果表明,坚持 10 到 30 个线程的范围是有意义的。但即使是这些也大多不可靠。
测试较窄的范围
在陷入沮丧之前,我想做最后一次尝试,开始另一个实验,在 1 到 30 的范围内测试线程数,并制作一个 1 的小缺口。
下一张图表显示,几乎没有避免空白回答的选项。然而,一个接一个地发送请求持续的时间太长了:175 秒。
API 调用持续时间与线程数量:按成功或失败分组(0 =失败,1-成功)
我可以选择过滤掉最长的持续时间,但是这些都是可靠的配置。最后我把 25 秒以上的都去掉了。在图表的网格布局上,可以看到这是一个大部分点所在的范围,还有很多黄色的点。
API 调用的持续时间与线程数量:按成功或失败分组(0 =失败,1-成功)。持续时间范围:从 1 到 25。
没有一个群集具有可接受的持续时间和可靠的结果。在从 9 到 14 个线程的范围内,所有的点都是黄色的,因此,这些线程数确实下载了电影数据。
在这里,最终的选择变得棘手。
9 到 13 个线程缩放
10 线程和 13 线程点簇的持续时间最短。13 线程点簇比其他簇有更多的低持续时间。9 线程集群似乎是最稳定的:所有的点都挤在一起。
是时候做一些描述性统计了。我计算了平均值、中间值、偏差等。并按从低到高的顺序排列,最低的得到最高的等级。
不太科学,但最终有可能确定最佳结果。
根据基于中值、平均值和标准偏差值的排名的最佳线程数量
这是给定条件下的最佳线程数。
尽管如此,移动应用程序会让用户再等 13 秒来完成基于 API 调用的操作。这是采取下一步性能优化措施的好理由,比如减少要检索的数据量,或者考虑其他来源。这也是重新思考移动应用背后的商业决策的一个很好的理由。
为什么都用 Python?
至少有三个原因可能会导致您更喜欢使用 Python 作为编写软件测试的语言:
- 你一般爱 Python!
- 你想要一个持续的检查,在你的服务器上永久运行。
- 您希望将结果传输到一个 AI 中,该 AI 会自动纠正被测试的主软件中的线程数量(或任何其他参数)。
一些要带走的东西
当然,我用一段清晰的代码说明了这篇文章,这段代码实际上是从一片混乱中诞生的。因此,关于如何不搞砸你的测试的一些学习。
- 了解你的数据。我进行了第一个实验,循环浏览 1000 页。然后我发现只有 500 个可用的键,当我最终想要访问返回的字典中的所有键时。
- 追踪你的测试。运行一次尝试后,不要在 Jupyter 或 Colab 的同一个单元格中编辑代码:而是复制粘贴!以前的版本反而可以变成更好的。
- 花时间构建有意义的数据可视化。在我构建了包含成功和失败运行的图表后,我可以缩小范围并消除第 10 个缺口。
- 检查隐藏的依赖性和系统模式:使用你的数据 vizzes。
- 一步一步地发展你的最终代码。更容易还原自己的逻辑来报告测试结果。
- 小步前进。匆忙最终会耗费更多的时间。
- 从一个描述性的和更一般的方法开始,定位你的挑战,然后缩小你的焦点。我从一个单一的 API 请求开始,并把它发展成一个由三个循环相互包裹的代码。
- 要系统!
特别是关于 API 测试,我也想分享一些技巧:
- 在代码中放入大量的“try-except”对,后跟“pass”语句。这有助于您在不中断循环的情况下进入下一次运行。运行可能会由于与测试无关的临时网络问题而终止。
- 放一个具体的例外,比如:
except requests.exceptions.ConnectionError:print(“Connection refused”)pass
它会给你一个提示,为什么会出现这个问题。您还可以获取本机错误消息,我在“循环遍历数字…”一节中展示了这一点
- 在多线程请求之间放置一个“睡眠”中断。不要让服务器生气!
- 当尝试不同数量的线程时:从一个间隙开始,跟踪一个成功的范围;消除间隙并测试增益。
- 尝试不同的网络容量和硬件。
- 模仿最终用户设置。
在这里,您可以找到本文的所有代码片段,包括最终的代码和数据可视化片段:
测试 API 调用中的线程数:asyncio 和 concurrent.futures 包(Python)colab.research.google.com](https://colab.research.google.com/drive/1TX98-OpRYkdGEA5Onu81EDfv5GOOKHH2)
测试愉快!
使用 pytest 在 Google Cloud Composer 上测试气流作业
无需重新发明轮子的可靠 CI/CD
马克·克林在 Unsplash 上的照片
Airflow 是一个开源的工作流管理平台,由 Airbnb 开发,现在由 Apache 维护。它基本上是类固醇上的 cron[1],具有无限扩展的理论能力,将这一特性的复杂性完全抽象给最终用户。你只需要写代码,决定它什么时候运行,剩下的就交给 Airflow 了。部署气流并不容易,需要深厚的运营知识和工具,如 Kubernetes 和芹菜。出于这个原因,许多云提供商提供托管气流部署,比如天文学家. io 或谷歌云合成器,这里仅举最著名的例子。设置一个运行 Airflow 的集群只需点击几下,从那时起,几乎所有的东西都可以使用 Airflow Web UI 进行配置。
在 HousingAnywhere 我们几乎在所有事情上都使用谷歌云平台,决定在 Cloud Composer 上部署 Airflow 是一个自然的结果。生成的环境开箱即用,带有 CeleryExecutor,dags 文件夹存储在 Google 云存储中。你需要在气流上运行的任何东西都必须首先被推到那个桶中,并且作业产生的任何东西都将被存储在同一个桶上的特定文件夹中。
Airflow 完全用 Python 编写,所有工作流程都是通过 Python 脚本创建的。实际上,这不是一个限制,因为任务本身(组成 DAG 的原子工作单元,一组相互依赖的任务)可以用任何语言编写,并通过 bash 或 Docker 运行。在 HousingAnywhere,我们将 Airflow 用于大量不同的用例,从移动数据到网络抓取,当然,我们在 Github 上发布所有内容。在试验的最初几天,我们手动将主分支上刚刚合并的所有新工作推到桶中:这是可行的,但在规模上是不可持续的,存在拥有不同真实来源的巨大风险,一个在 Github 上,一个在 GCS 上。
使用 Google Cloud Build,我们设计了一个自动化流程,由我们的气流存储库的主分支上的任何相关更改触发。无论 master 上发生什么,都会自动与 GCS bucket 同步,不再需要任何人手动处理这个过程。基本上是一张关于气流的 CD。
Google Cloud Build 上触发的作业的历史记录
CloudBuild 语法和与 Google Cloud Composer API 的集成允许我们做更多的事情,序列化 Github 上的绝大多数气流环境:不仅仅是 dags 文件夹,还有任务所依赖的其他重要参数,如变量。这里的主要思想是,如果发生了不好的事情,我们可以几乎完全重建我们的环境,只需在新的 Airflow 集群上运行相同的 CloudBuild 作业,而无需任何努力或返工。
谷歌云构建步骤克隆气流变量
然而,这样的自动化流程需要仔细检查主分支上合并的内容,防止开发人员触发可能破坏环境的自动化任务。在制作 CD 时,我们开始设计一个自动化的 CI,能够可靠地测试我们的分支,如果有问题,可能会亮起红灯。
诚然,有意义的气流部署是复杂的,但建立一个能够顺序运行任务的快速环境并不复杂。创建一个本地气流部署实际上是三个命令的事情,底层的 Python 代码库使它非常轻量和灵活。
Bash 脚本需要启动一个简单的气流环境
使用 pytest (在 HousingAnywhere,我们已经使用这个库在我们所有的配置项上测试 Python)很容易模拟出运行一个任务所需的所有对象,幸运的是,这项工作可以在我们希望测试的所有气流实例之间共享。每个开发人员只需负责导入那些资源,并负责自己的测试。使用 Airflow 的复杂性几乎完全消除了,针对代码特性编写有意义的测试实际上是几十年前的最佳实践。
感谢巴斯·哈伦斯拉克的灵感
我们已经为所有的操作符编写了测试,并对 dags 文件夹中的 DAGs 进行了一致性检查,以便不在那里合并一些中断的(或循环的)东西。
DAGs 文件夹上一致性检查的代码
总结一下,现在只需要为您最喜欢的 CI 工具定义测试管道(在 HousingAnywhere,我们使用 Jenkins,但是无论什么都可以),然后运行 pytest 命令。如果分支是绿色的,则合并是安全的。包含测试的文件夹不需要被推到 GCS 上的桶中,并且可以被保留在设计的 CD 之外。
CI/CD 的简化架构
一个例子,使用雪花测试 DAGs】
在这里展示一个例子,展示我们如何处理在我们的云数据仓库雪花上运行的测试气流任务,可能会很有趣。如果使用 pytest 很容易模拟出 Postgres 实例,那么雪花的唯一解决方案就是在云上创建一个测试环境,尽可能与生产环境相似,并对其运行所有测试,注意用有意义的数据和资源填充它。
为此,通过雪花查询引擎提供的 GET_DDL 函数非常有用,它输出重新创建作为参数传递的表所需的 SQL DDL 查询。在测试时创建测试环境实际上就是执行几个 sql 查询。从监控的角度来看,将测试数据库连接到一个单独的仓库是明智的,这样可以控制成本并避免与预测资源的冲突。
雪花是直接从詹金斯启动的吊舱进入的
必须将生产数据的子集转储并复制到测试环境中,可能会在测试会话结束时擦除它们。但是这主要是基于特定的需求和要测试的任务的功能。Python 的雪花连接器在这个方向上提供了很大的自由度,但是对于一些非常特殊的用例,我们也将 SQLAlchemy 与 Pandas 结合使用。
在 Airflow 方面,所有到数据库或外部资源的连接都应该通过钩子来处理。SnowflakeHook 可以从默认的 Airflow 安装中获得,使用它的工作量非常有限,只需通过 pip 导入正确的资源即可。
可以使用 pytest mocker 库向任务公开测试凭证。每次函数调用 get_connection 时,解释器都会返回这些凭证,而实际上不会向 Airflow 请求任何东西。
测试的实际内容是特定于任务的,在这个例子中,我们希望为在雪花表格中推送新广告的工作编写测试。我们想强调我们没有使用任何不包含在任务结果中的广告客户(可能由另一个广告客户生成,之前执行过)。
测试操作员时执行的一些检查
前置集和后置集是直接针对雪花表运行查询来填充的。
[1]这个惊人的定义不是我的。马克·纳格尔伯格的功劳
在 R 中测试有序数据和回归的另一种可视化
Dataviz
使用 brms 和 ggplot2 仅在一个图上显示您的交互
有序数据无处不在(好吧,也许不是无处不在,但仍然很常见)。例如,在心理学(我的科学领域)中,人们经常使用有序数据,例如在使用李克特量表时。然而,可视化有序数据和用于分析有序数据的回归并不容易。当然,你可以用经典的 t 检验分析你的数据,并绘制柱状图,但这并不推荐( Liddell & Kruschke,2018 )。谢天谢地,你可以通过神奇的 brms R 软件包学习如何更好地打点( Bürkner & Vuorre,2018 )。这篇文章不是关于如何分析有序数据,而是关于如何可视化它。如果你想学习分析,你可以阅读上面引用的文章或者看本章出自所罗门·库尔茨。
“困难”(?)
有几个选项可以显示有序回归的结果。brms R 包( Bürkner,2018 )提供了一种很好的方式,用 conditional_effects 命令从序数模型中提取条件效果。在之前的研究中,我们已经将此方法与 Amélie Beffara Bret 一起使用,您可以在下面找到一个(定制)输出示例:
使用 brms 的有序回归可视化示例
我们可以看到,我们有两个预测值,称为“RWA”(连续,在 x 轴上)和“Conditioning”(两个值显示在不同的图中)。在 y 轴上,我们有顺序结果(“评估”),图例显示了概率等级。当然,这不是绘制这种数据和回归的唯一方法。结果可能是图例和概率在 y 轴(例如,见马修·凯的这篇博文)。然而,在这两种情况下,重要的一点是每个响应的概率在图上占一个维度,或者在图例中,或者在 y 轴上。因此,这个维度不能用于预测。这非常重要,因为这意味着当你对交互感兴趣时,你需要几个图(或 3D 图)。这不一定是一个大问题,但我想测试一个新的(至少对我来说)可视化选项。
种“解”(?)
下面是我最近测试的一个例子:
那么我们这里有什么?我们有两个预测值,即“我必须吃的水果”和“我必须吃带… 的水果”。这是两个分类预测值,一个在 x 轴上,另一个在图例上。在 y 轴上,我们可以找到具有 4 个可能值的有序结果。抖动的点是所有参与者的真实反应。我发现绘制原始数据非常重要。但是如果我们只画这些点,我们就没有模型的估计。正如我上面提到的,为有序模型绘制条件效应通常需要为每个响应的概率使用一个维度。在这里,我选择在抖动点上方的另一个小轴上绘制这个概率(以及它的可信区间 CI)。这允许我们在一个图上显示相互作用,因为我们有另一个第二预测值的自由维度。虚线简单地连接了每种情况下的一种“总体”响应估计(根据 brms 模型计算)。尽管这种方法远非完美,但它允许我们(imho)绕过一些通常在顺序模型可视化中遇到的限制。那么,我们该怎么做呢?如果你已经熟悉 brms 和 ggplot2,这并不复杂。让我们来看看。
乱码
在这里你可以下载重现例子所需的一切。
首先,我们需要一个数据框。我使用了一个从我正在做的项目修改而来的数据框架(这让我想到了我在这里展示的 dataviz)。我们有两个独立变量:水果(黑莓对树莓)和我们如何吃它(勺子对叉子对刀子)。我们的因变量是 4 个有序水平的被试的反应:“我讨厌它”、“我不喜欢它”、“我喜欢它”、“我喜欢它”,分别编码为 1、2、3、4。在这个实验中,我们有几个参与者和几个实验者。都有一个随机 ID。
library(tidyverse)
library(brms)
library(extrafont)
library(hrbrthemes)##### Import df #####
fruit_df <- read_csv("fruit_df.csv")
然后我们运行我们的(当然是顺序的)模型。我们想要估计水果的恒定效果,我们如何吃水果,以及这两个变量之间对反应的相互作用(即参与者如何喜欢它)。我们也包括由参与者和由实验者改变截距。
##### Run model #####
fit_fruit <- brm (
formula = resp ~ fruit * cutlery + (1 | ppt) + (1 | exp),
data = fruit_df,
warmup = 1000,
iter = 2000,
chains = 4,
cores = parallel::detectCores(),
control = list(adapt_delta = 0.8, max_treedepth = 10),
family = cumulative (link = "probit", threshold = "flexible")
)summary(fit_fruit)
我们不会在这里谈论模型的质量(或者如何检查它),这超出了范围。我们就当模型还可以吧。现在我们需要从模型中获得估计值,因为我们希望能够绘制它。更准确地说,我们想知道两个预测值的每个组合中每个响应的概率(以及与每个估计值相关的可信区间)。
##### Get estimates from the model ###### set conditions for the "fruit" predictor
cond_Blackberries <- data.frame(fruit = "Blackberries",
cond__ = "Blackberries")cond_Raspberries <- data.frame(fruit = "Raspberries",
cond__ = "Raspberries")# get estimates of the probability of each response in each combination of the two predictorsconditional_Blackberries <- conditional_effects(
effects = "cutlery",
conditions = cond_Blackberries,
fit_fruit,
re_formula = NULL,
robust = TRUE,
categorical = TRUE,
probs = c(0.025, 0.975),
plot = FALSE
)[[1]]conditional_Raspberries <- conditional_effects(
effects = "cutlery",
conditions = cond_Raspberries,
fit_fruit,
re_formula = NULL,
robust = TRUE,
categorical = TRUE,
probs = c(0.025, 0.975),
plot = FALSE
)[[1]]conditional_merged <-
rbind(conditional_Blackberries, conditional_Raspberries)
为了画出虚线,我们还需要对两个预测因子的每个组合的反应进行“总体估计”。这一部分不是最相关的,但它可以(可能)帮助想象兴趣的影响。“总体估计”给出了根据每个响应水平的中值概率计算的每个条件下的中值响应的概念。
# Compute overall response estimates (for the dashed lines on the plot)overall_list <- conditional_merged %>%
mutate(overall_resp = as.numeric(effect2__) * estimate__)overall_sum <-
aggregate(data = overall_list, overall_resp ~ fruit * cutlery, sum)
现在我们可以开始策划了。首先,我们通过显示每个响应来绘制原始数据(一个响应=一个点)。
#### Starting plot ##### Get font
hrbrthemes::import_roboto_condensed()
loadfonts()# Order levels
level_order <- c('Spoon', 'Fork', 'Knife')#### Plot raw data ####
plot_fruit <-
ggplot(fruit_df, aes(
x = factor(cutlery, level = level_order),
y = resp,
fill = fruit
)) +
geom_point(
data = fruit_df,
aes(
x = factor(cutlery, level = level_order),
y = resp,
colour = fruit,
fill = fruit
),
position = position_jitterdodge(
jitter.width = .08,
jitter.height = 0.16,
dodge.width = .2
),
size = 2,
alpha = .2,
shape = 20,
inherit.aes = FALSE
)
然后,我们绘制“第二轴”。图中的灰色小竖线。我们将在这些“轴”上绘制我们的概率估计及其 CI。这是代码中最糟糕的部分,因为我没有比手动设置坐标更好的解决方案。 geom_segment 否则表现不佳。
#### Prepare secondary axes ####
plot_fruit <- plot_fruit + geom_segment(
data = conditional_merged,
aes(
x = cutlery,
xend = c(
1.95,
2.95,
0.95,
1.95,
2.95,
0.95,
1.95,
2.95,
0.95,
1.95,
2.95,
0.95,
2.05,
3.05,
1.05,
2.05,
3.05,
1.05,
2.05,
3.05,
1.05,
2.05,
3.05,
1.05
),
y = as.numeric(effect2__) + 0.2,
yend = as.numeric(effect2__) + 0.5,
linetype = "1"
),
color = "gray20",
size = 0.3,
position = position_dodge(width = .2),
lineend = "round",
show.legend = FALSE
)
现在我们应用同样的方法,但是这次是针对概率估计和它们的 CI。
#### Plot estimates and CI ####
plot_fruit <- plot_fruit + geom_segment(
data = conditional_merged,
aes(
x = cutlery,
xend = c(
1.95,
2.95,
0.95,
1.95,
2.95,
0.95,
1.95,
2.95,
0.95,
1.95,
2.95,
0.95,
2.05,
3.05,
1.05,
2.05,
3.05,
1.05,
2.05,
3.05,
1.05,
2.05,
3.05,
1.05
),
colour = fruit,
y = as.numeric(effect2__) + 0.2 + lower__ * 0.3,
yend = as.numeric(effect2__) + 0.2 + upper__ * 0.3,
linetype = "1"
),
size = 2,
position = position_dodge(width = .2),
lineend = "round",
show.legend = FALSE
) + geom_point(
data = conditional_merged,
aes(
x = cutlery,
y = as.numeric(effect2__) + 0.2 + estimate__ * 0.3,
colour = fruit,
),
size = 4,
position = position_dodge(width = .2),
show.legend = FALSE
)
我们画虚线。它们将我所说的“总体估计”联系起来。
#### Dashed lines ####
plot_fruit <- plot_fruit + geom_line(
data = overall_sum,
aes(
x = factor(cutlery, level = level_order),
y = overall_resp,
group = fruit,
colour = fruit
),
linetype = 3,
size = 0.5
)
我们添加文本来说明每个响应级别的含义。
#### Labels ####
plot_fruit <- plot_fruit + annotate(
"text",
x = 0.4,
y = 1.07,
hjust = 0,
color = "gray40",
label = "I hate it",
size = 7
) +
annotate(
"text",
x = 0.4,
y = 2.07,
hjust = 0,
color = "gray40",
label = "I don't like it",
size = 7
) +
annotate(
"text",
x = 0.4,
y = 3.07,
hjust = 0,
color = "gray40",
label = "I like it",
size = 7
) +
annotate(
"text",
x = 0.4,
y = 4.07,
hjust = 0,
color = "gray40",
label = "I love it",
size = 7
)
最终定制,我们可以绘图!
#### Custom ####
plot_fruit <- plot_fruit +
scale_colour_brewer(palette = "Dark2",
name = "The fruits \nI have to eat") +
scale_fill_brewer(palette = "Dark2",
name = "The fruits \nI have to eat") +
theme_minimal() +
scale_x_discrete(name = "I have to eat the fruits with a") +
scale_y_continuous(name = "Responses",) +
theme_ipsum_rc(
base_size = 25,
subtitle_size = 25,
axis_title_size = 30
) +
guides(alpha = FALSE,
colour = guide_legend(override.aes = list(shape = 15, size = 7))) +
scale_alpha_continuous(range = c(0.2, 1)) +
theme(text = element_text(size = 30))plot_fruit
不滚动了,这里又是剧情。
就是这样。没什么特别的,但这是(可能是?)一个选项。当然,如果在论文中使用,这种情节需要有充分的解释。但那是后话了。如果您对可能的改进有任何意见或建议,请告诉我。感谢阅读!
感谢
非常感谢拉迪斯拉斯·纳尔博奇克、伊索尔特·赫贾-布里沙德、贝特朗·贝法拉和艾米里·贝法拉·布雷特对本文早期版本的评论和帮助。
脚注
你可以在这里找到(凌乱++的)代码,在这里找到预印本*,在这里找到论文(法文)里面的情节*。**
你可以在这里 找到(凌乱++的)代码 ,在这里 找到预印本 。
在冠状病毒文章上测试基于 BERT 的问答
COVID19 图像
简介
目前世界大部分地区都受到了 T2 新冠肺炎疫情 T3 的影响。对我们许多人来说,这意味着在家隔离,社会距离,工作环境的破坏。我非常热衷于使用数据科学和机器学习来解决问题。如果你是一家医疗服务公司,正在寻找数据科学帮助来应对这场危机,请通过这里的联系我。
世界各地的媒体不断报道疫情——最新的统计数据、政府的指导方针、保护自己安全的提示等等。整理所有的信息会很快让人不知所措。
在这篇博客中,我想分享你如何使用基于 BERT 的问答来从关于病毒的新闻文章中提取信息。我提供了关于如何自己设置它的代码提示,并分享了这种方法在哪里有效以及何时会失败。我的代码也上传到了 Github 。请注意,我不是健康专家,本文的观点不应被解释为专业建议。
什么是问答?
问题回答是自然语言处理中计算机科学的一个领域,它包括建立能够从给定的文本中回答问题的系统。在过去的 2-3 年里,这是一个非常活跃的研究领域。最初的问题回答系统主要是基于规则的,并且只限于特定的领域,但是现在,随着更好的计算资源和深度学习架构的可用性,我们正在获得具有通用问题回答能力的模型。
现在大多数表现最好的问答模型都是基于变形金刚架构的。为了更多地了解变形金刚,我推荐了这个 youtube 视频。转换器是基于编码器-解码器的架构,其将问答问题视为文本生成问题;它将上下文和问题作为触发器,并试图从段落中生成答案。BERT、ALBERT、XLNET、Roberta 都是常用的问答模型。
小队— v1 和 v2 数据集
斯坦福问答数据集(SQuAD )是用于训练和评估问答任务的数据集。小队现在发布了两个版本——v1和 v2 。这两个数据集之间的主要区别在于,SQuAD v2 还考虑了问题在给定段落中没有答案的样本。当一个模型在小队 v1 上训练时,即使没有答案,模型也会返回一个答案。在某种程度上,你可以使用答案的概率来过滤掉不太可能的答案,但这并不总是有效。另一方面,在 SQuAD v2 数据集上进行训练是一项具有挑战性的任务,需要仔细监控精度和超参数调整。
构建和测试班伯特模型
随着这种病毒在世界范围内的爆发,有大量的新闻文章提供了关于这种病毒的事实、事件和其他消息。我们在模型从未见过的文章上测试问答如何工作。
为了展示这种能力,我们从 CNN 选择了一些信息丰富的文章:
来自 huggingface 的 transformers 是一个令人惊叹的 github repo,其中他们编译了多个基于 transformer 的训练和推理管道。对于这个问答任务,我们将从 https://huggingface.co/models下载一个预先训练好的小队模型。本文中我们将使用的模型是Bert-large-uncased-whole-word-masking-fine tuned-squad。从模型名称可以明显看出,该模型是在大型 bert 模型上训练的,该模型具有不区分大小写的词汇并屏蔽了整个单词。使用该模型我们需要三个主要文件:
- Bert-large-un cased-whole-word-masking-fine tuned-squad-config . JSON:这个文件是一个配置文件,其中包含代码将用来进行推理的参数。
- Bert-large-un cased-whole-word-masking-fine tuned-squad-py torch _ model . bin:这个文件是实际的模型文件,它包含了模型的所有权重。
- Bert-large-un cased-whole-word-masking-fine tuned-squad-TF _ model . H5:该文件具有用于训练该文件的词汇模型。
我们可以使用以下命令加载我们已经下载的模型:
tokenizer = AutoTokenizer.from_pretrained(‘bert-large-uncased-whole-word-masking-finetuned-squad’, do_lower_case=True)model = AutoModelForQuestionAnswering.from_pretrained(“bert-large-uncased-whole-word-masking-finetuned-squad”)
总的来说,我们将代码组织在两个文件中。请在我的 Github 上找到以下内容:
- 问题 _ 回答 _ 推理. py
- 问题 _ 回答 _ 主页. py
question _ answering _ inference . py 文件是一个包装文件,它具有处理输入和输出的支持函数。在这个文件中,我们从文件路径中加载文本,清理文本(将所有单词转换为小写后删除停用单词),将文本转换为段落,然后将其传递给 question_answering_main.py 中的 answer_prediction 函数。answer_prediction 函数返回答案及其概率。然后,我们根据概率阈值过滤答案,然后显示答案及其概率。
question_answering_main.py 文件是一个主文件,它具有使用预训练模型和标记器来预测给定段落和问题的答案所需的所有功能。
此文件中的主要驱动程序函数是 answer_prediction 函数,它加载模型和记号化器文件,调用函数将段落转换为文本,将文本分段,将特征转换为相关对象,将对象转换为批次,然后用概率预测答案。
为了运行脚本,请运行以下命令:
python question_answering_inference.py — ques ‘How many confirmed cases are in Mexico?’ — source ‘sample2.txt’
该程序采用以下参数:
- ques:问题参数,要求用单引号(或双引号)将问题括起来。
- source:该参数具有包含文本/文章的文本文件的源路径
模型输出
我们在冠状病毒的几篇文章上测试了这个模型。:
冠状病毒的爆发提醒我们,我们触摸自己的脸次数太多了。减少这种意愿…
edition.cnn.com](https://edition.cnn.com/2020/03/08/health/coronavirus-touching-your-face-trnd/index.html) [## 美国冠状病毒病例超过 20 万。更多的州说呆在家里
越来越多的数据显示,没有症状的人正在加剧冠状病毒的传播,这让高层官员重新思考是否…
edition.cnn.com](https://edition.cnn.com/2020/04/01/health/us-coronavirus-updates-wednesday/index.html)
在下面的例子中,我们有传递给模型的文本和问题,以及返回的答案及其概率。
问答示例 1
以上回答正确。该模型能够以很高的置信度选择正确的答案。
问答示例 2
这是一个更棘手的问题,因为文章中有几个共享的统计数据。冰岛的一项研究显示,大约 50%的携带者没有症状,而疾病控制中心估计有 25%。看到这个模型能够选择并返回正确的答案真是令人惊讶。
同一篇文章后来谈到了干预的效果以及它可以避免多少死亡。相关文本复制如下。然而,当运行代码时,我们传递的是整篇文章,而不是下面的子集。由于 SQUAD 模型对可以处理多少文本有限制,所以我们在多个循环中传递完整的文本。如下所示,这意味着模型会返回几个答案。这里概率最高的第一个答案是正确的。
问答示例 3 —返回多个答案
下面分享了另一个发生这种情况的例子。正确答案是迈克·瑞安是世卫组织突发卫生事件项目的负责人。该模型能够以 96%的概率发现这一点。然而,它返回福奇博士作为一个低概率的答案。在这里,我们也可以使用概率分数来得到正确的答案。
问答示例 4 —多个答案
上面的例子显示了从很长的新闻文本中获取答案的能力有多强。另一个惊人的发现是在小队训练的模型有多强大。他们能够很好地概括以前从未见过的文本。
所有人都说,这种方法在所有情况下都完美地工作仍然有一些挑战。
挑战
使用第一小队回答问题的几个挑战是:
1)很多时候,即使答案不存在于文本中,模型也会提供足够高概率的答案,导致误报。
2)虽然在许多情况下,答案可以通过概率正确排序,但这并不总是防弹的。我们观察过错误答案与正确答案的概率相似或更高的情况。
3)该模型似乎对输入文本中的标点符号敏感。在向模型输入内容时,文本必须是干净的(没有垃圾单词、符号等),否则可能会导致错误的结果。
使用 v2 小队模型代替 v1 小队可以在一定程度上解决前两个挑战。SQuAD v2 数据集在训练集中有样本,其中没有所提问题的答案。这允许模型更好地判断何时不应该返回答案。我们有使用 v2 小队模型的经验。如果您有兴趣将此应用到您的用例中,请通过我的网站联系我。
结论
在本文中,我们看到了如何轻松实现问题回答来构建能够从长篇新闻文章中查找信息的系统。我鼓励你自己尝试一下,在隔离期间学习一些新的东西。
总的来说,我对 NLP、变形金刚和深度学习非常感兴趣。我有自己的深度学习咨询公司,喜欢研究有趣的问题。我已经帮助许多初创公司部署了基于人工智能的创新解决方案。请到 http://deeplearninganalytics.org/.的来看看我们吧
参考
- 变压器模型纸:【https://arxiv.org/abs/1706.03762
- BERT 模型解释:https://towards data science . com/BERT-Explained-state-of-art-language-Model-for-NLP-F8 b 21 a9b 6270
- 抱紧脸
测试是不确定性的疫苗
为什么测试和实验是成功商业成果的关键
商业实验是避免代价高昂的错误和做出有利可图的决策的关键。从数据库时钟修改的图像。
生命中只有三件事是确定的——死亡、税收和不确定性。
现实生活是不确定的。这是概率性的。如果你是执行决策者,你可能已经知道了。举个例子,让我们来比较一下重塑了美国和世界零售业的两个最具代表性的零售商:亚马逊和 JCPenney。当亚马逊每个季度都达到不可思议的高度时,JCPenney 却在破产的边缘苦苦挣扎。怎么会变成这样?早在 1994 年,JCPenney 不就是走在时代前列,成为第一批上线的零售商之一吗?然而,一旦灾难降临,他们就再也没有恢复过来。
这场“灾难”始于 2010 年至 2013 年间的一系列失误,当时 JCPenney 发起了一场大规模的品牌重塑活动,同时改变了营销和折扣策略。为赢得更多消费者而付出的努力最终却疏远了他们。你可以把责任归咎于很多决策,但在 10,000 英尺高空的情况更清楚:JCPenney 实施了巨大的变革,而且是一次实施很多变革,没有在消费者身上进行测试。
在没有任何测试或实验的情况下实施变革,就像拿你的企业玩俄罗斯轮盘赌。
像 JCPenney 这样的伟大王朝不是因为决策失误而灭亡的:他们是因为直到为时已晚才知道自己错了。在花大价钱彻底改变你的商业策略之前,为什么不验证一下你提议的改变在小范围内是否有效呢?给自己一个失败的机会。亚马逊的巨大成功不是因为他们从来没有错,而是因为他们建立了一种文化,这种文化促进了创新,并为失败提供了安全的空间。他们是怎么做到的?
关键在于测试和实验,这是世界上最成功的公司,如脸书、谷歌、亚马逊和微软已经根植于他们的文化中的东西。他们向一小部分用户展示他们的最新想法。这就是“测试”组。与此同时,他们保留了一组“控制”或“安慰剂”用户,他们还没有经历任何变化。这组人可能不会改变他们的行为,但如果他们这样做了,你可以肯定这不是因为测试。它们提供了一个“基线”,根据这个基线可以衡量“测试”组中任何行为变化的增量效果。
一次又一次,这些公司成功了,因为他们很快失败了,并转向了新的东西。如果你的“测试”组对任何变化都没有反应,并且继续表现出与“控制”组一致的行为,那么你失败的程度要小得多。然而,你可能在一个无论如何都不会起作用的改变上节省了数百万美元。
“有对失败的恐惧,就会有失败。”乔治·S·巴顿将军
测试和实验一点都不新鲜。我们已经做了很多年了。一个很好的例子是进行临床试验,测试一种新药是否有效。直到最近,FAANG 公司才把这变成了一种商业哲学。为什么不呢?我们都知道他们是多么的成功。所以,我们不都应该开始做实验吗?什么会出错?
一个设计糟糕的测试会像不测试一样有效地毁掉你的生意。这是因为设计不良的测试会给出有偏见和不可靠的结果,提供误导性的信息,让你误以为是有用的见解。那我们如何拯救我们自己呢?正如任何批判性思考者会说的——提出问题!
- ****为什么你要进行这个测试?变革的预期效果是什么?
- ****什么样的指标能正确衡量变革的效果?
- 谁应该是你测试的一部分?
- 您的测试应该运行多长时间?
为什么?
变革的预期效果是什么?你想获得更高的广告收入吗?或者,你只是想维持用户参与度?这不是一个数据科学或分析问题:这是商业战略。与您的首席执行官和关键决策者谈论他们关心的指标是什么,以及测试有一个目标。
“如果你不知道要去哪里,你必须非常小心,因为你可能到不了那里。”—约吉·贝拉
你的“为什么”不需要总是关于未来。有时,您需要衡量刚刚发生的变化的效果。新冠肺炎一夜之间彻底改变了人们的消费习惯。从连锁杂货店、餐馆老板到服装零售商,每个人都只能眼睁睁地看着自己的企业要么被压垮,要么被摧毁。你无法挽回已经发生的事。然而,在新的现实中两个月后,你仍然可以从过去的事件中形成假设,用你所拥有的数据来测试它们,并利用你的发现来为未来做出明智的决定。
什么?
什么应该是可测量的效果:一个你想要跟踪的度量**。您可以收集许多参与度指标,但并非所有指标都与您的变更相关。如果你想测量用户保持率,那么你需要测量你的日活跃、周活跃或月活跃指标。如果你想从广告中赚更多的钱,你最好测量一下你应用程序上广告印象的点击率。**
有一个清晰定义的“什么”也将帮助你磨练测试中重要的部分,并使它在决策中分析和使用更清晰。你没有做广告测试来发现你的客户是否在不同的时间登录你的网站。但是,不要过犹不及,目光短浅。您可能希望在进一步开展计划之前,看到测试对您的一些 KPI 的影响。
谁啊。
最终,你对谁进行测试将对测试是否有用有很大的影响。需要记住业务和技术两方面的考虑,它们分为三类:
- 你的测试目标是什么类型的客户?
- 需要多大的样本量?
- 我应该如何划分测试和控制?
当你在考虑你的消费者时,你的目标应该是决定测试的范围,这样你可以得到更清晰和更有力的见解。您可以根据静态或行为属性对您的消费者进行细分。一个更小的有针对性的测试将证明比全面测试更可靠,即使是在你从未打算推出产品的领域。
心中有一个目标不仅对细分消费者很重要,对理解预期效果大小也很重要。一个更大的测试会给你更多的统计能力,让你可靠地测量一个更小的效果大小。请记住,您的测试越大,执行它的成本就越高。因此,您的样本大小应该由最小影响大小来决定,这个最小影响大小刚好足以让您可靠地测量变更的增量影响。
在某一点之后,真正重要的不是测试样本有多大,而是它对你的目标人群有多大的代表性。测试的黄金标准一直是随机化,但也有更微妙的策略可用。
多久了?
我们都喜欢快速反馈。你的实验设计也应该如此。当您考虑您的测试应该运行多长时间时,您的目标应该是尽可能快地获得洞察力。你的实验进行得越久,代价就越大,要么是在一次糟糕的测试中推出更多的客户,要么是更快推出一个好主意的机会成本。幸运的是,我们有统计技术来帮助优化实验的长度。例如,您可以使用一种带有反馈循环的多臂强盗方法,该方法经常呈现有效的测试版本,并避免那些无效的版本。一旦你开始得到非常令人信服的结果,表明测试正在工作,你可以应用有效停止测试。
最后,我们学到了什么?
“一个白痴讲的故事,充满了喧嚣和愤怒,却毫无意义!”——威廉·莎士比亚
用不朽的莎士比亚的话来说,有效的测试和实验都是关于“明天、明天、明天”的思考。你需要为你的公司想要做的事情建立一个长期的愿景,从而计划你的测试来开辟这条道路。为你的长期测试策略做计划,不仅包括基本的想法,还包括度量标准、样本大小和防止测试重叠。太多的公司要么不理解测试的价值,根本不做测试,要么他们疯狂地进行设计糟糕的测试,最终只是声音和愤怒,没有任何意义。确保你的测试意味着什么,并告诉你一个可操作的故事,你可以用它来指导业务。
使用 Pytest、Cython 和 spaCy 测试、分析和优化 NLP 模型
单元测试你的机器学习模型,剖析你的代码,充分利用 c 的自然语言处理速度。
目录:
- 为什么您应该关注分析 NLP 模型
- 为什么 spaCy 比 NLTK 快
- 当你调用 nlp(doc)时,到底发生了什么?
- 设置模型测试
- 判决结果:哪一方因速度而胜
- 编写文本处理管道的最佳实践
- NLP 优化的建议工作流程
- 资源和代码库
我读了一篇博文声称已经为自然语言数据预处理分析了 spaCy 和 NLTK,并且发现 NLTK 要快得多。
嗯(通过 giphy ,@ TheLateShow)
什么?
NLTK 是自然语言处理工具包中的吉普大切诺基:它很大,已经存在很长时间了,它有很大的动力,但它很慢,很费油。
SpaCy 是兰博基尼 Aventador。它可能不是一个有着所有花里胡哨的坦克,但它很光滑,只剩下裸露的金属。它做什么,它就做快。它的高马力也带来了风险(和乐趣),即在蜿蜒的道路上加速转弯时转弯过猛,偏离道路。
这个,但是用向量(via giphy ,@ thegrandtour)
所以,这个说法让我觉得很奇怪:
Spacy 比 NLTK 慢多了。NLTK 只用了 2 秒钟就标记了 7 MB 的文本样本,而 Spacy 用了 3 分钟!
如果您正确地编写了管道,并且您的硬件有足够的内存,这是不可能发生的。
我为什么要关心?
我主要从事研究工程——我的工作是制作模型,而不是构建软件架构。那么,如果你只想构建聊天机器人和搜索引擎,为什么要关心你的代码性能呢?
如果你对构建数据的最佳模型感兴趣,你不能脱离代码质量来考虑机器学习模型。
- 大规模的 NLP 语料库意味着,除非你尝试在空间和时间上优化你的代码,否则你将在算法和工具上受到限制。
- 不写测试意味着你不知道什么变化导致了什么错误——或者更糟,在你的实体模型中可能有你甚至没有意识到的问题,并且永远不会发现。(你是否曾经编写了一个 ML 函数或类,却发现它从未被调用过?)
- 理解您正在使用的库不仅对代码性能至关重要,而且对深入理解您正在构建的模型的实质也很重要。你将加速你的知识从简单的导入 scikit-learn 和装配一个估计器到真正的搜索支持 NLP 的算法。
- 良好的测试和深思熟虑的代码对于可重复的研究至关重要。
- 如果你是为了生产而写代码,而不仅仅是为了学术目的,你绝对需要考虑它在现实世界中如何运行。
为什么 spaCy 这么快?
SpaCy 的喷漆工作是 Python,但引擎是 Cython。 Cython 就像一种克里奥尔语言——一部分是 Python,一部分是 c。它是 Python 的超集(所有有效的 Python 都是有效的 Cython),但它包含了来自 c 的更快、更复杂的特性
对于某些用例,Cython 是一个很好的速度提升工具——例如,计算大量数字结果,其结果取决于一系列 if 语句。通常你会使用 numpy 来加速计算,但是 numpy 擅长于矢量化代码——对每个元素做同样的事情。当我们想要对每个元素做不同的事情时,Cython 允许我们使用相同的 c 优化,但是增加了逻辑复杂性。
SpaCy 广泛使用了开箱即用的 cythonization,与许多其他 Python 库相比,它是一个非常快速的 NLP 框架。
不理解你的算法的陷阱
让我们回到那个认为 spaCy 比 NLTK 慢的博客。
当我使用 line_profiler 在相同的文档上运行我的 NLTK 和 spaCy 文本清理器版本时,采用了苹果对苹果的比较, NLTK 花了 spaCy 5.5 倍的时间来做基本上相似的工作。
TL;DR: NLTK 在相同数据上的可比 NLP 管道中使用时比 spaCy 慢 5.5 倍。
我的代码有什么不同?首先,我从里到外研究了这些系统的架构,包括:
- 他们在做什么工作,什么时候做
- 他们期望并返回什么数据类型
- 功能的控制流
为了进行有意义的比较,您需要知道 spaCy 在被引用的代码中比 NLTK 做了更多的 lot 。默认情况下,spaCy 管道包括标记化、词汇化、词性标注、依存解析和命名实体识别。每次您调用nlp(doc)
时,它都会完成所有这些(甚至更多)。
spaCy 的词性标注和依存解析功能示例
相比之下,NLTK(在引用的代码中)只是标记和小写的语料库。
将这两条管道进行对比是荒谬的。
我们需要一个更好的框架:
- 我暂时禁用了 spaCy 管道中的依赖解析和命名实体识别,因为 NLTK 不做这些事情。
- 我让 NLTK 做了词性标注和词汇化,让它更接近 spaCy 的性能。
这仍然不是完美的一对一比较,但已经非常接近了。
两个麻雀的故事
我写了两个版本的 spaCy pipeline,来反映我是如何看到人们在野外使用nlp.pipe
的。第一个是list(nlp.pipe(docs))
。第二种更有效的方法是使用nlp.pipe(docs)
作为生成器对象。
用于相互比较管道的脚本。
github.com](https://github.com/lorarjohns/nlp_profiling/blob/master/scripts/profiling_spacy.py)
这种区别很重要,因为与 Python 列表不同,生成器对象不会同时在内存中保存整个语料库。这意味着您可以迭代地修改、提取或写入数据库的内容。在 NLP 中,这种情况经常出现,因为语料库通常非常大——大到无法一次保存在内存中。
结论是什么?
cProfile(戏剧化)(通过 giphy ,@ f1)
在同一个 Reddit 语料库(n=15000)上测试我的三个管道(使用 NLTK、spaCy-as-list 和 spaCy-as-generator),下面是 line_profiler 的结果:
- 列表空间:总时间= 64.260 秒
- 发电机空间:总时间= 60.356 秒
- NLTK:总时间= 334.677 秒
分析的结果可以在这里以*_reddit_2.txt 的形式找到](https://github.com/lorarjohns/nlp_profiling/tree/master/profiling)
使用 spaCy,甚至不用编写自己的 Cython,就可以将代码速度提高 5 倍以上。
这是有道理的——NLTK 没有用 Cython 进行优化,当它标记和 lemmatizes 令牌时,它使用了比 spaCy 更耗时的操作。
编写文本预处理管道的最好方法是什么?
与任何代码一样,如果你不理解 spaCy 的数据结构以及如何负责任地使用它们,spaCy将会变得很慢。**
阅读源代码。 SpaCy 依靠两个主要的东西来快速运行:Cython 的 c 内核和 Python 生成器。因此,它使用复杂的类和数据管道,这意味着它的对象的类型和方法并不总是显而易见的。
例如,当您在文本上调用nlp
来获取一个 Doc 对象时,spaCy 会生成 c 代码来处理您的数据。虽然您可以使用括号符号等普通命令进行索引以与结果文档进行交互,但它们的工作方式与基本 Python 不同。更确切地说,Doc 类重载了 Python 操作符,让您可以像与 Python 对象一样与结构进行交互。
Doc 类中的一个 c 函数
真正了解这一点的唯一方法是阅读源代码。文档不会为你解释清楚。除了通过 Spacy 教程学习 高级 NLP 之外,没有其他方法可以真正掌握诀窍。
轻松阅读源代码将极大地提高您的编程素养和数据管道。
有计划。在开始编写之前,确保你已经用涂鸦和伪代码概述了管道的步骤。有一个深思熟虑的计划将帮助你思考如何最好地将不同的功能联系在一起。您将看到数据的效率,将函数和变量组合在一起以加快速度的方法,以及如何转换数据以方便流动。
自然语言处理优化的工作流程
- 解决问题不考虑最优性。让它工作起来。
- 在你开始改变你的代码之前,准备好工作测试。拥有测试意味着你可以改变架构的重要部分,而不用担心引入新的神秘错误。测试并不是很多数据科学家预先考虑的事情,而且考虑如何为 NLP 机器学习模型编写测试并不总是容易的。但是至少在数据预处理方面,它们可以帮助您避免预处理不好的文本的“垃圾输入,垃圾输出”现象。一些例子包括:
- 为你的正则表达式(例如,你用来标记句子的表达式)编写单元测试,确保它们只匹配你想要的
- 检查你的函数是否返回正确的数据类型。返回值应该是数字数组、字典、字符串、列表还是列表列表?测试一下。
- *检查你所有的类和函数是否真的按照你想要的方式被调用。*发现重要的嵌入模型或特征工程组件得到了错误的输入(或者更糟,根本没有被调用)一点都不好玩。
但是,在开始 cythonizing 之前,请确保您已经剖析了代码并清理了 Python。甚至像 gensim 这样的纯 Python 库也可以非常快,而且内存效率高,因为它们严格地收紧了数据结构和管道。
- 持续地、可重复地测量代码的速度和性能。你需要一个基线来知道你是否在改善(或者让事情变得更糟)。行分析器、 cProfile 和 py-spy 都会生成记录脚本性能的文件,您可以阅读、引用和比较这些文件。
- 确保你使用了正确的数据结构和函数调用。在你确定你的 Python 已经尽可能快之前,不要为 Cython 费心。有时候,Cython 并不是合适的工具,对 Python 代码的微小修改会比 cythonization 产生更大的改进。正如我们所见,用列表替换生成器是一个简单的瓶颈修复方法。
- **检查你的函数的控制流。**逐行分析器在这里真的很有帮助。在编写比较时,我注意到 line_profiler 说我的 spaCy 函数在文本清理函数的 NLTK 部分花费了时间。我已经编写了代码,以便在我检查
spacy=True
参数是真还是假之前定义只与 NLTK 相关的内部函数。将该代码移动到 if-else 语句的 NLTK 部分中,可以阻止我的 spacy 模型每次都运行该(不相关的)代码块。 - 编写好的测试。考虑你的函数需要产生什么样的输出来通过你的测试,几乎会迫使你自动去做 1-3。
使用 pytest 对管道进行的一些测试
github.com](https://github.com/lorarjohns/nlp_profiling/blob/master/scripts/test_profiling_spacy.py)
更好的代码,更好的科学
以这种方式思考需要对您的模型进行更多的架构设计,但是为了避免等待半个小时来处理您的文档,这是值得的。花时间仔细考虑模型的逻辑结构,编写测试,并思考分析器的输出,以避免以即时满足的名义进行草率的科学研究。任何人都可以制造一袋单词;NLP 的精妙之处在于细节工作。
资源:
- 我对这篇博文的完整回购,附带理解 spaCy 内部结构和编写自己的 Cython 的额外代码
github.com](https://github.com/lorarjohns/nlp_profiling)
使用 SeleniumBase 测试简化应用
在我为 Streamlit 工作的这段时间里,我见过数百款令人印象深刻的数据应用,从计算机视觉应用到公共卫生新冠肺炎的追踪,甚至是简单的儿童游戏。我相信 Streamlit 越来越受欢迎的原因是通过 Streamlit“魔法”功能和保存 Python 脚本时自动重新加载前端的快速迭代工作流。编写一些代码,在编辑器中点击“保存”,然后直观地检查每个代码更改的正确性。随着用于简化部署 Streamlit 应用程序的 Streamlit sharing 的推出,您可以在几分钟内从构思到编码再到部署您的应用程序!
一旦您创建了一个 Streamlit 应用程序,您就可以使用自动化测试来保证它不会出现倒退。在这篇文章中,我将展示如何使用 Python 包 SeleniumBase 以编程方式验证 Streamlit 应用程序在视觉上没有改变。
案例研究:细流叶
streamlit-flour 测试应用程序的基准图像(作者提供的图像/截图)
为了演示如何创建自动化的可视化测试,我将使用streamlit-leave GitHub repo,这是我为 leave . js 的leave Python 库创建的 Streamlit 组件。视觉回归测试有助于检测应用的布局或内容何时发生变化,而不需要开发人员在其 Python 库中每次代码行发生变化时手动视觉检查输出。视觉回归测试还有助于提高您的 Streamlit 应用程序的跨浏览器兼容性,并提供有关影响应用程序显示方式的新浏览器版本的高级警告。
设置测试工具
streamlit-follow 测试工具有三个文件:
[tests/requirements.txt](https://github.com/randyzwitch/streamlit-folium/blob/master/tests/requirements.txt)
:测试只需要 Python 包[tests/app_to_test.py](https://github.com/randyzwitch/streamlit-folium/blob/master/tests/app_to_test.py)
:参考要测试的 Streamlit 应用[tests/test_package.py](https://github.com/randyzwitch/streamlit-folium/blob/master/tests/test_package.py)
:演示包按预期工作的测试
第一步是使用要测试的包创建一个 Streamlit 应用程序,并使用它来设置基线。然后,我们可以使用 SeleniumBase 来验证应用程序的结构和视觉外观相对于基线保持不变。
这篇文章的重点是描述test_package.py
,因为它是涵盖如何使用 SeleniumBase 和 OpenCV 进行 Streamlit 测试的文件。
定义测试成功
从测试的角度来看,有几种方法可以思考什么构成了看起来相同的。我选择了以下三个原则来测试我的 streamlit-leav 包:
- 页面的文档对象模型(DOM)结构(但不一定是值)应该保持不变
- 对于标题等值,测试这些值是否完全相等
- 视觉上,应用程序应该看起来一样
我决定采用这些不太严格的“未更改”定义来测试 streamlit-follow,因为 follow 包本身的内部似乎是不确定的。这意味着,相同的 Python 代码将创建相同的外观的图像,但是生成的 HTML 将会不同。
使用硒基测试
SeleniumBase 是用 Python 编写的一体化框架,它包装了用于浏览器自动化的 Selenium WebDriver 项目。SeleniumBase 有两个函数可以用于上面列出的第一个和第二个测试原则: check_window ,它测试 DOM 结构和 assert_text ,以确保页面上显示特定的一段文本。
为了检查 DOM 结构,我们首先需要一个基线,我们可以使用check_window
函数生成这个基线。根据所需的name
参数,check_window
有两种行为:
- 如果在
visual_baseline/<Python file>.<test function name>
路径中不存在文件夹<名称> 的话,这个文件夹将由所有的基线文件创建 - 如果文件夹确实存在,那么 SeleniumBase 将按照指定的精度级别将当前页面与基线进行比较
您可以在 streamlit-leav repo 中看到一个调用 check_window 和结果基线文件的示例。为了在两次运行之间保持基线不变,我将这些文件提交给了 repo 如果我要对我正在测试的应用程序(app_to_test.py
)进行任何实质性的更改,我需要记住设置新的基线,否则测试将会失败。
基线文件夹现在已经存在,运行 check_window 将运行比较测试。我选择在级别 2 运行测试,级别定义如下:
- 级别 1(最不严格) : HTML 标签与 tags_level1.txt 进行比较
- 级别 2 : HTML 标签和属性名与标签 _ 级别 2.txt 进行比较
- 第三级(最严格) : HTML 标签、属性名和属性值与 tags_level3.txt 进行比较
正如在“定义测试成功”一节中提到的,我在第 2 级运行了check_window
函数,因为 follow 库向 HTML 中的属性值添加了一个类似 GUID 的 ID 值,所以测试永远不会在第 3 级通过,因为属性值在运行之间总是不同的。
对于第二个测试原则(“检查某些值是否相等”),使用assert_text
方法非常容易:
self.assert_text("streamlit-folium")
该函数检查应用程序中是否存在准确的文本“streamlit-follow ”,测试通过,因为在本例中这是 H1 标题的值。
使用 OpenCV 进行测试
虽然检查 DOM 结构和一段文本的存在提供了一些有用的信息,但我真正的接受标准是应用程序的视觉外观不会从基线改变。为了测试应用的视觉效果是否与像素相同,我们可以使用 SeleniumBase 的save_screenshot
方法来捕捉应用的当前视觉状态,并使用 OpenCV 包与基线进行比较:
使用 OpenCV,第一步是读入基线图像和当前快照,然后比较图片的大小是否相同(shape
比较检查像素的 NumPy ndarrays 是否具有相同的尺寸)。假设图片大小相同,我们可以使用 OpenCV 中的subtract
函数来计算每个通道(蓝色、绿色和红色)像素之间的差异。如果所有三个通道没有差异,那么我们知道 Streamlit 应用程序的视觉表示在运行之间是相同的。
使用 GitHub 动作自动化测试
随着我们的 SeleniumBase 和 OpenCV 代码的设置,我们现在可以自由地对我们的 Streamlit 组件(或其他 Streamlit 应用程序)进行更改,而不用担心意外中断。在我的单贡献者项目中,很容易在本地强制运行测试,但是有了开源项目免费提供的工具,如GitHub Actions,建立一个持续集成管道保证了每次提交都运行测试。
streamlit-leav 定义了一个工作流程[run_tests_each_PR.yml](https://github.com/randyzwitch/streamlit-folium/blob/master/.github/workflows/run_tests_each_PR.yml)
,执行以下操作:
- 为 Python 3.6、3.7、3.8 建立一个测试矩阵
- 安装包依赖关系和测试依赖关系
- 将代码用薄片 8 标记
- 用硒鼓安装铬合金
- 运行 Streamlit app 进行后台测试
- 在 Python 中运行 SeleniumBase 和 OpenCV 测试
通过在 repo 中定义这个工作流,并在 GitHub 上启用所需的状态检查,现在每个 pull 请求都会在底部附加以下状态检查,让您知道您的更改的状态:
合并前 GitHub 运行的检查(图片/作者截图)
从长远来看,编写测试可以节省工作
在代码库中进行测试有很多好处。如上所述,自动化视觉回归测试允许你维护一个应用程序,而不需要一个人在循环中寻找变化。编写测试对潜在用户来说也是一个很好的信号,表明你关心项目的稳定性和长期可维护性。为 Streamlit 应用程序编写测试并让它们在每次 GitHub 提交时自动运行不仅容易,而且从长远来看,向 Streamlit 项目添加测试的额外工作将节省您的时间。
对本文或 Streamlit 有任何疑问吗?驻足于 Streamlit 社区论坛 ,展开讨论,结识其他 Streamlit 爱好者,在 Streamlit 组件跟踪器 或 中找到合作者,分享你的 Streamlit 项目 !有很多方法可以加入 Streamlit 社区,我们期待着您的到来🎈
原载于 2020 年 11 月 13 日https://blog . streamlit . io。
测试您的数据库
数据库过程测试的检查点概要
格伦·卡斯滕斯-彼得斯在 Unsplash 上拍摄的照片
无论在哪个行业,数据库测试都是任何数据系统实现的重要组成部分。实现一个供各种角色的员工日常交互的数据库,要求所有存储和检索的数据(无论是通过 SQL 查询还是某种 UI)都是准确的,否则数据库本身就毫无价值。创建数据库后,对其进行功能测试以确保应用程序的健壮性是至关重要的。测试将确保模式、表、触发器和数据完整性本身都是一致的,并且每个操作都是有效的。
主要有三种类型的数据库测试:
- 结构测试
- 功能测试
- 非功能测试
结构测试
验证数据存储库中主要不是供最终用户使用的所有元素。这一步涉及数据库组件,如服务器和其他数据存储组件,如列测试、模式测试、存储过程/视图测试和触发器测试。
模式测试(映射测试)
模式本质上是我们数据库的映射,它为实际的查询过程提供了重要的指导,使我们能够获取准确的数据。模式测试将允许我们确保应用程序的后端和前端的模式映射是相似的。
当进行模式测试时,我们必须确保:
- 模式已经过验证—表的映射格式必须与最终用户界面的映射格式兼容。
- 如果一个环境包含多个数据库,这些数据库需要与应用程序的整体映射保持一致
- SQL Server 允许测试人员通过简单和独立的查询来查询数据库的模式。
**示例:**如果我们有一个包含一组表的模式,那么对单个表的结构所做的更改应该有效地适应所有依赖于该更改后的表的结果查询。
数据库/列测试
在这个测试步骤中,我们必须验证数据库及其特性列的结构是一致的。
- 字段长度和命名约定必须在应用程序的所有级别(后端和用户界面)上匹配
- 必须考虑任何未使用或未映射的表和列,并验证它们的存在
- 应用程序后端的数据类型和数据长度必须能够为最终用户提供高效、正确的摘要视图
- 必须适应用户的输入文档——换句话说,应用程序必须能够支持用户的业务规范
- 必须根据域要求定义主键和外键,并且必须包含在各自的表中(此外,必须考虑到键的任何唯一或非空特征)
触发测试
当你想到“触发”时,想想连锁反应。触发测试确保数据库代码的过程流正常工作,没有错误。
- 遵循标准编程编码标准
- 执行的触发器匹配所需的条件
- 触发器应该正确地更新数据(更新、插入、删除等)。)
数据库服务器检查
这些测试都围绕着主机服务器管理它将收到的请求的能力。
- 每个业务域的预期事务数量将由服务器提供
- 必须根据业务需求维护用户授权标准
存储过程和视图
这个步骤本质上验证了当用户执行查询或界面请求时,将为用户检索并显示正确的结果。
- 异常/错误得到正确处理,不会破坏系统
- 遵循传统的编码标准
- 接受任何条件或循环(输入数据通过并被接受)
- 任何未使用的过程都被考虑在内
- 验证存储过程模块是否正常工作,并在数据库中流动
功能测试
这个测试点要求最终用户将要执行的任何和所有交易或操作与业务的任何要求一致,并且它们都可以被有效和准确地执行。
卢卡·布拉沃在 Unsplash 上的照片
- 字段必须声明为强制的,也可以不声明,并且可以处理潜在的空值
- 每个字段的长度必须是适当的大小
- 所有表中的字段标题必须相同,以避免查询时混淆
黑箱测试
这种类型的测试需要验证数据库集成以检查功能。这些测试将验证来自用户的数据以及该功能产生的任何数据的完整性。一些黑盒测试的例子:
- 因果图
- 等价划分
- 边界值分析
白盒测试
这些测试集中于用户看不到的数据库内部结构。数据库中的模块与触发器、视图和一些查询一起被强调。数据库中的表、模式和模型将使用默认表值进行验证,以验证整个数据库的一致性。在这个过程中,代码中的 bug 和其他错误通常会被发现和协调。白盒测试的一些例子:
- 条件覆盖
- 决策覆盖
- 报表覆盖范围
非功能测试
非功能测试本质上是我们数据库的性能测试。完成这些测试是为了符合业务需求,这将有助于了解实际结果是否与预期结果一致。在这一步中,要考虑压力条件下的反应时间等因素。
阿洛拉·格里菲斯在 Unsplash 上拍摄的照片
负载测试
这种类型的测试将检查是否有任何正在运行的事务对数据库的整体性能有影响。
- 多个最终用户一次执行一个事务的响应时间应该同样一致
- 系统中最重要的功能应该进行最多的测试
- 应包含可编辑的事务,以区别于不可编辑的事务
- 应注意最佳响应时间
负载测试的示例:
- 一遍又一遍地运行一个非常常见的查询事务,以确保一致性
- 从外部来源添加大量数据
- 在同一台计算机或服务器上同时运行多个应用程序,以确保应用程序不受影响
压力测试
在压力测试中,我们试图让应用程序的工作负载过载,以确定故障点(断点**)**。然后,可以针对这些要点进行改进,或者向最终用户突出显示。通常,会使用第三方压力测试工具。
例如,如果建议一个 ERP 应用程序在任何给定时间最多接受 20,000 个用户,压力测试人员将逐渐增加工作负载,使其超过最大值,以确定应用程序在哪个点开始出现故障。在为最终用户组织文档时,可以考虑这些基准。
包扎
执行数据库测试的方法有很多,通常公司会让员工单独负责测试数据。理解和使用这些过程将允许任何数据用户创建和使用健壮的数据库应用程序,满足业务和最终用户的所有功能需求。
用 GitHub 动作测试您的 Python 项目
几天前,我第一次在我的一个项目中使用 GitHub Actions。总的来说,结果是非常积极的,但也有一些工作要做。希望这篇文章能帮助你以更低的成本做到这一点!
激活 GitHub 动作
在项目的根目录下创建一个.github/workflows
目录:
mkdir -p .github/workflows
在该目录中,用您选择名称创建一个或多个 YAML 文件。
在我的例子中,我创建了两个文件:
[continuous-integration-pip.yml](https://github.com/mwouts/jupytext/blob/master/.github/workflows/continuous-integration-pip.yml)
,以及[continuous-integration-conda.yml](https://github.com/mwouts/jupytext/blob/master/.github/workflows/continuous-integration-conda.yml)
。
命名您的行动
在 YAML 文件的顶部,我们有这个字段:name: CI (pip)
。虽然 YAML 文件的名称似乎没有任何影响,但文件顶部的name
字段是出现在您的操作选项卡中的字段,也是您将在工卡上看到的名称:
使用on
字段,您可以选择哪些事件应该触发一个动作。我最初尝试了on: [push, pull_request]
,但是我很快就感觉触发了太多的构建。现在我使用on: [push]
,这似乎就足够了。这样,当贡献者的一个提交破坏了配置项时,他们会收到一封电子邮件,因此他们可以在打开拉请求之前修复问题。使用on: [push]
,您已经在 pull 请求中获得了状态更新:
几分钟后:
测试 Python 的多个变体
Python 代码是可移植的,但实际上,我更喜欢在各种平台上测试我的代码。
在我的项目中,我想测试
- Python 环境使用
pip
和conda
构建 - Python 版本 2.7、3.5、3.6、3.7 和 3.8
- Linux、Mac OS 或 Windows 上的 Python。
注意,我不需要测试完整的矩阵(30 个作业)。如果我在所有可能的操作系统(11 个作业)上测试了 pip 和 Linux 的所有 Python 版本,以及 conda 的 Python 2.7 和 3.7,那么我已经可以确信我的程序将在几乎所有地方工作。
先说pip
,超级容易设置。这里是我的[continuous-integration-pip.yml](https://github.com/mwouts/jupytext/blob/master/.github/workflows/continuous-integration-pip.yml)
文件的摘录,显示:
- 如何使用
actions/checkout@v2
查看 GitHub 库 - 如何在
python-version: ${{ matrix.python-version }}
参数化的版本中用actions/setup-python@v1
安装 Python - 如何从项目的
requirements.txt
和requirements-dev.txt
文件安装包 - 如何安装可选依赖项
name: CI (pip)
on: [push]
jobs:
build:
strategy:
matrix:
python-version: [2.7, 3.5, 3.6, 3.7, 3.8]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt
# install black if available (Python 3.6 and above)
pip install black || true
现在我们前往conda
。我的[continuous-integration-conda.yml](https://github.com/mwouts/jupytext/blob/master/.github/workflows/continuous-integration-conda.yml)
文件摘录显示:
- 如何用
actions/checkout@v2
检查你的 GitHub 库 - 如何在 Ubuntu (Linux)、Mac OS、Windows 中选择操作系统
- 如何用
goanpeca/setup-miniconda@v1
安装 Miniconda,用python-version: ${{ matrix.python-version }}
参数化的 Python 版本 - 如何从
[environment.yml](https://github.com/mwouts/jupytext/blob/master/environment.yml)
文件创建 conda 环境 - 以及如何激活相应的环境
name: CI (conda)
on: [push]
jobs:
build:
strategy:
matrix:
os: ['ubuntu-latest', 'macos-latest', 'windows-latest']
python-version: [2.7, 3.7]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup Miniconda
uses: goanpeca/setup-miniconda@v1
with:
auto-update-conda: true
auto-activate-base: false
miniconda-version: 'latest'
python-version: ${{ matrix.python-version }}
environment-file: environment.yml
activate-environment: jupytext-dev
代码质量
在运行任何测试之前,确保所有代码都是有效的是一个好主意,我用flake8
做到了这一点。
我的[continuous-integration-pip.yml](https://github.com/mwouts/jupytext/blob/master/.github/workflows/continuous-integration-pip.yml)
文件中对应的步骤是
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# all Python files should follow PEP8 (except some notebooks, see setup.cfg)
flake8 jupytext tests
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --statistics
在[continuous-integration-conda.yml](https://github.com/mwouts/jupytext/blob/master/.github/workflows/continuous-integration-conda.yml)
中,需要一个额外的shell
参数。我第一次尝试shell: pwsh
(PowerShell),效果不错,所以我现在在用
- name: Lint with flake8
shell: pwsh
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# all Python files should follow PEP8 (except some notebooks, see setup.cfg)
flake8 jupytext tests
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --statistics
了解 CI 错误
我最初对flake8
步骤有疑问。错误是:
Lint with flake8
4s
##[error]Process completed with exit code 2.
Run # stop the build if there are Python syntax errors or undefined names
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
all Python files should follow PEP8 (except some notebooks, see setup.cfg)
flake8 jupytext tests
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --statistics
shell: /bin/bash -e {0}
env:
pythonLocation: /opt/hostedtoolcache/Python/3.6.10/x64
0
/home/runner/work/_temp/98d1db20-f0af-4eba-af95-cb39421c77b0.sh: line 3: syntax error near unexpected token `('
##[error]Process completed with exit code 2.
我的理解是,/home/runner/work/_temp/98d1db20-f0af-4eba-af95-cb39421c77b0.sh
是一个临时脚本,包含该步骤的命令。所以当我们被告知脚本抛出这个错误:第 3 行:意外标记(*)附近的语法错误时,我们应该看看那个步骤的
run`属性的第三行。在我的命令中,那是所有的 Python 文件都应该遵循 PEP8(除了一些笔记本,见 setup.cfg)* ,而且确实是少了一个注释 char!
运行 Pytest
一旦我们确信代码在语法上是正确的,我们就想知道是否所有的单元测试都通过了。相应的步骤是:
- name: Test with pytest
run: coverage run --source=. -m py.test
注意,我使用coverage run --source=. -m py.test
而不仅仅是pytest
,因为我也想知道代码覆盖率。还有,对于 conda 文件,我们需要添加一个shell: pwsh
属性,否则找不到coverage
或者pytest
命令。
上传覆盖范围
在配置项中计算覆盖率是很好的,但是在拉请求中更新覆盖率,并在自述文件中显示覆盖率标记就更好了。为此,我使用 codecov 。我更喜欢只上传 conda CI 的覆盖率,因为它让我可以测试更多的可选功能。覆盖率上传步骤是[continuous-integration-conda.yml](https://github.com/mwouts/jupytext/blob/master/.github/workflows/continuous-integration-conda.yml)
中的最后一步:
- name: Upload coverage
shell: pwsh
run: coverage report -m
有了这个,我就有了保险徽章
我可以添加到我的自述文件中,详细的覆盖率统计数据和图表在 codecov.io 中,以及拉请求中的覆盖率报告:
自动化作业取消
一开始让我感到惊讶,但很有意义的一个特性是自动作业取消。当 CI 中的一个作业失败时,所有其他仍在运行或挂起的作业都会被取消。
下面是我的项目中的一个例子——Windows 版本出现了一个问题,导致剩余的 Windows 和 Mac OS 作业被取消:
与 Travis-CI 的差异
在发现 GitHub 动作之前,我使用的是 Travis-CI 。我喜欢它!我在许多项目中使用过 Travis-CI,包括这个奇特的项目,在那里我们测试…自述文件本身!
现在,我将以两者之间的简单比较来结束我的发言。
- 特拉维斯. CI 在那里的时间要长得多。我可能担心 GitHub 操作的文档会更难找到,但事实并非如此。有用的参考有:使用 Python 和 GitHub 动作和设置 Miniconda 。
- 就像 Travis-CI 一样,Github Actions 可以免费用于公共项目。
- GitHub 集成对于 Travis-CI 和 GitHub 操作来说都非常出色,尽管这些操作在项目页面上有一个专用的选项卡,这使得访问 CI 更加容易。
- 用 Github 动作配置 conda 比用 Travis-CI 更简单,为此我使用了这个 hack 。
- 我发现这个矩阵(比如 Python 版本乘以 OS,比如这里的)在 Github 动作上使用起来更简单。
- 我没有注意到工作持续时间的显著差异。在我的示例 PR 中,Travis-CI 上的六个作业(pip 和 conda,仅 Linux)在 8m 33s 中运行,而在 GitHub Actions 上,第一系列的五个 pip 作业(仅 Linux)在 4m 57s 中运行,而其他系列的六个 conda 作业(Linux、Mac OS、Windows)在 12m 48s 中并行运行——因此,在该示例中,GitHub Actions 花费了 50%的时间,但也覆盖了更多的数量
感谢你阅读这篇文章!如果你想了解更多,可以看看我在 Medium 上的其他帖子,在 GitHub 上我的开源项目,或者在 Twitter 上关注我。此外,如果您有在其他环境中使用 GitHub 操作的经验,例如,如果您知道如何在线发布文档,请在此处发表评论让我们知道,或者随时就此回购提出问题或请求!
德州扑克模拟器
德州扑克是当今最流行的扑克游戏。随着社交距离协议调整了生活方式,许多人开始与朋友玩休闲游戏。失败一点也不好玩,有时这个游戏看起来像是对你不利。在本文中,我将讨论与玩不同牌局相关的概率,以及一个交互式应用程序,您可以使用它来模拟数千手扑克,以确定概率并提高您的技能。如果您对 Dash 应用感兴趣,请点击此处。
随着社交距离协议的继续,德州扑克的在线人数大幅增加。下图显示了随着冠状病毒开始影响美国,德州扑克应用程序 Poker Face 的增长情况。
我发现德州扑克中的一些数字知道起来很有用,也很容易计算。假设你坐在牌桌上,拿着一张红桃 j 和一张红桃 4,翻牌圈又出现了两张红桃。你现在在等一个有九张听牌的同花听牌。
在一副牌中,十三张有红心的牌,其中四张放在桌子上。剩下的 47 张牌中有 9 张可以提供最后一张红心给你同花。在还剩两张牌的情况下,凑成同花的概率约为 35%。
这是了解你的风险和决定你愿意赌多少来看下一张牌的有用信息,但它留下了许多未知数。在上面的场景中,玩家有一张高同花,尤其是因为牌桌上有红心王。别人有红桃皇后或 a 和另一张红桃牌的概率是多少?或者,他们只能有红心皇后或 a,并希望有两个以上的心显示。这取决于手中剩下的玩家数量,从而变得更加复杂。如果你要单挑,你可以相当有信心拿到高同花顺听牌,但如果你和其他几个玩家在一张牌桌上,你就没那么有信心了。也就是说,你仍有 65%的机会没有拿到同花。如果你打了一个 q,a,或者 q,9 或者 7,9(所有这些都可以按任意顺序打)。这里打顺子的概率是 4.4%。
计算特定场景的概率并不太难,但是对每一种可能的纸牌组合进行计算就变得非常复杂了。
这就是可以实现编程能力的地方。使用 python,您可以模拟数百万手牌,记录任何牌和牌桌组合的每次同花、顺子等等。这使得用户能够完全控制卡片,而不必进行任何计算。下面是之前讨论的 100 万手模拟牌的输出。
代码创建手牌,然后洗牌。首先,它将牌分发给一些选定的玩家。然后,它将剩余的 X 张牌放在桌上,并记录每手牌是否被击中。然后将该手牌与其他玩家的手牌进行比较,以确定该手牌是否是获胜的手牌,并记录该信息。这个过程重复 n 次模拟。随着模拟牌局数量的增加,所列概率的准确性也会增加。如前所述,我创建了一个 Dash 应用程序,你可以在这里亲自尝试一下。下面是应用程序的截图。
有了模拟手的能力,我们可以很容易地分析许多不同的情况。下图显示了每对口袋对子的获胜概率。有些差异是必需的,因为数十亿手牌的组合是可能的,而模拟只有数百万次。然而,你可以看到一个明显的趋势,毫不奇怪地表明,口袋二的远不如口袋火箭。
1.口袋 a 有多好?
2.7 2 异花到底有多烂?
3.你拿到同花 8-9 的顺子、同花或同花的可能性有多大?
与这个项目相关的所有代码都可以在我的 Github 上找到。如果你对这个项目有任何疑问,请随时联系我们。感谢您的阅读,希望您喜欢!
德州重新开放了。他们的新冠肺炎数据是怎么回事?
让我们快速看一下数据
恩里克·马西亚斯在 Unsplash 上的照片
自从德克萨斯州州长格雷格·阿博特宣布德克萨斯州的一些企业现在可以以 25%的能力开业以来,不到两周就过去了,包括零售店、图书馆、餐馆、商场、电影院和博物馆。上周一(18 日),他宣布进一步减少限制。健身房、儿童护理中心、办公楼、青年俱乐部、非必需制造业、按摩护理中心和工作办公室被允许立即重新开放。5 月 22 日,餐馆将被允许从 25%的容量增加到 50%的容量。同时,酒吧、品酒室和手工酿酒厂将被允许以 25%的容量开放。
在听取了所有这些限制后,重要的是要考虑重新开放的前一阶段已经产生了什么影响。
得克萨斯州卫生部周六报告称,该州共有超过 47000 例新冠肺炎确诊病例,仅周六一天就有超过 1800 例新增病例(见下图)。
每日新病例
得克萨斯州每日确诊新新冠肺炎病例(来源: Knowi 冠状病毒数据中心
在这张图表中,您可以看到每天新增病例的数量在稳步增加。随着大约两周前重新开放,这种增长可能会更快,这被认为是新新冠肺炎病例的潜伏期。
然而,漫长的潜伏期使得现有的上升趋势很难归因于重新开放本身。
5 月 16 日的大峰值是州长归因于增加测试的峰值。
测试增加
(来源: Knowi COVID 测试仪表板)
州长阿博特表示,得克萨斯州正在增加新冠肺炎检测的数量,特别是在疗养院、监狱和肉类加工厂等高风险设施中。这是最近报告的确诊病例增加的原因。
按日期在德克萨斯州进行的测试数量(来源: Knowi COVID 测试仪表板
尽管医学专家一再强调进行更多测试的重要性,但这确实使数据更难解读。数字上升是因为重新开放还是因为测试增加了?
德克萨斯州阳性检测的百分比(来源)
正如州长所指出的,该州阳性检测结果的百分比似乎呈下降趋势。而在 4 月初,阳性病例约为 10%,现在显示约为 5%。
然而,这可能并不像许多人似乎暗示的那样,实际上是感染人数减少的指标。以前在大多数州,接受测试的人是表现出最严重症状的人。随着各州对普通人群进行越来越多的检测,预计感染者的比例将会下降,因为接受检测的人不仅仅是那些表现出最明显新冠肺炎症状的人。
德克萨斯州的热点在哪里?
得克萨斯州各县新冠肺炎病例热图(来源:已知冠状病毒数据中心
正如你在上面的热图中看到的,得克萨斯州新冠肺炎病例最多的是两个最大的县:达拉斯县和哈里斯县。考虑到哈里斯县包括休斯顿市,这并不奇怪。得克萨斯州有 2100 多个病例发生在波特县,兰德尔县有 600 多个已知的新冠肺炎病例。少数病例分散在整个州。
埃尔帕索的官员甚至要求将他们排除在下一阶段重新开放之外。
前景尚不明朗
在这里,我简要介绍了与得克萨斯州新冠肺炎病例相关的数据。我不认为有足够的信息对将要发生的事情,甚至对现在正在发生的事情做出任何明确的预测。但我确实认为,阳性病例百分比下降表明危险减少的论点在逻辑上是有缺陷的,可能会误导人们,可能包括州长艾伯特。