TowardsDataScience-博客中文翻译-2021-三十一-
TowardsDataScience 博客中文翻译 2021(三十一)
通过构建 Python 模拟器来揭开抵押贷款的神秘面纱
一步一步的指南,建立一个有用的 Python 模拟器,帮助你更好地了解你的房屋净值及其潜在的未来增长。

托德·肯特在 Unsplash 上的照片
抵押贷款不仅仅是在规定的支付期限内根据商定的金额每月还款。如果没有很好地了解其还款机制和潜在风险,抵押贷款很容易危及我们的财务。
在这里,我们将通过一步一步的实践指南来开发一个可以模拟长期抵押贷款偿还的 Python 模拟器。该模拟器还将使我们能够可视化贷款摊销和我们的房屋净值的未来增长。你可能会惊讶地发现,看似略高的贷款利率会严重影响房屋净值。
必备 Python 库
在开始开发过程之前,我们需要确保以下库在我们的机器中可用:
GitHub 回购
如果您希望使用我的代码来跟踪这篇文章,您可以在我的 Github Repo 获得完整的源代码。
你也可以运行我从 GitHub repo(mortgage simulator . py)获得的代码来预览这个应用。确保您已在机器中正确设置了 Streamlit。您可以参考 Streamlit 网站了解更多信息。
抵押贷款模拟器的开发
1.导入库
首先,我们在程序中导入所有需要的库。
2.设置页面标题
在这里,我们将开始使用 Streamlit 来构建我们的模拟器。 Streamlit 是一个开发数据 app 的开源 Python 框架。
首先,让我们为浏览器选项卡和主页设置页面标题。
第 1 行:使用 Streamlitset _ page _ config中的 page_title 为我们的浏览器标签页定义一个标题。
第 2 行:创建我们模拟器的主标题。
此时,我们可以尝试运行 Streamlit 应用程序来可视化输出。为此,我们在终端/命令提示符下键入以下命令。
streamlit run YourPythonFileName.py
(注意: 在运行应用程序之前,请确保您已经导航到保存脚本文件的目录。)
我们应该会看到如下输出:

作者准备的图像
3.为抵押详细信息创建输入字段
为了模拟按揭付款,我们需要四条信息,它们是房屋价值、首付比例、贷款利率和付款期限 。
在本节中,我们将使用 Streamlit 构建四个数字输入字段,以获取用户对上述四条信息的输入。
第 1 行:创建标题。
第 2 行:定义两列来放置我们的输入字段。
第 4–9 行:在第一列中,创建相关的副标题,并使用 Streamlit number_input 方法创建房屋价值和利率的数字输入字段。我们将最小值设置为零,并将输入格式设置为十进制数。
第 11–16 行:在第二列中,重复上述类似过程,为首期付款百分比和付款期(年)创建相关副标题和数字输入字段。

作者准备的图像
4.每月分期付款计算
有了这四条信息,我们现在可以开始计算每月分期付款。这将会给我们一个粗略的概念,我们每月的抵押贷款还款承诺。
第 1–4 行:从房屋价值中扣除首付款,计算贷款金额。将付款年数乘以 12,得到付款月总数。将利率转换成小数。
第 5–6 行:根据输入的利率,我们使用以下公式计算定期利率

作者准备的图像
定期利率是在较短时间内(如 1 个月)表示的年利率。由于抵押贷款是按月偿还的,这里我们的目标是获得每月定期利息,因此 N=12。最后,使用 Numpy pmt 方法,根据周期利率、还款总月数和贷款金额计算每月的还款金额。 Numpy pmt 方法将封装计算逻辑并自动得出每月分期付款金额。
第 8–10 行:向我们的模拟器显示首期付款、贷款金额和每月分期付款。
让我们尝试在抵押详细信息的数字输入字段中输入一组示例值:
房屋价值— 500000
首付比例— 10
贷款利率— 4.5
目标付款年限— 30 年

作者准备的图像
模拟器处理我们的样本输入,结果是每月分期付款 2256.02 美元。
5.抵押贷款分期偿还
在这个阶段,我们的模拟器能够根据我们提供的抵押贷款详细信息的输入值来估计每月分期付款金额。然而,每月分期付款金额本身并不能让我们知道我们的付款分别对贷款本金和贷款利息产生了多大的影响。虽然每月的分期付款总额是相同的,但包含贷款本金和贷款利息的金额部分会随着时间的推移而有所不同。

由 Alexander Mils 在 Unsplash 上拍摄
在本节中,我们将为抵押贷款生成一个 分期偿还计划 。摊销时间表是一个表,显示了贷款本金和贷款利息的金额,包括每个月的分期付款,直到贷款全部还清。此外,我们还将绘制一个图表,以显示构成我们每月分期付款的贷款本金和贷款利息的每月变化。
第 4–6 行:创建三个 Numpy 系列来保存每月剩余本金、已付本金和已付利息的值。用零初始化每个 Numpy 系列。
第 8–23 行:创建一个循环来迭代计算构成当月分期付款的本金和利息。当前的利息支付是基于定期利率与先前剩余本金的乘积计算的(第 15 行)。从每月分期付款中减去由此产生的利息付款将得到该特定月份的本金付款(第 16 行)。将当前的利息支付、本金支付和剩余本金存储到前面创建的三个 Numpy 系列中(第 21–23 行)。
第 31–37 行:使用 Python Plotlymake _ subplots方法创建一个包含表格和图表的合成图形。
第 39–49 行:使用 Plotly go。Table 对象创建一个显示每月本金支付、利息支付和剩余本金的表。将之前创建的 Numpy 系列插入到单元格的值中(第 44–46 行)。使用 add_trace 方法将表格添加到复合图形对象中。
第 51–58 行:使用 Plotly go。散点图对象为几个月内的本金支付创建一个折线图。将本金支付的 Numpy 系列设置为 y 轴值。再次使用 add_trace 方法将绘图添加到复合图形对象。
第 60–67 行:以类似的方式,使用 Plotly go。散点图对象为几个月的利息支付创建一个折线图。此时,我们使用 append_trace 方法添加线图,这样它将与同一图表中本金支付的线图重叠。
第 69–81 行:通过设置相关的标题、尺寸和图例来配置组合图的布局。
第 83 行:使用 Streamlit plotly_chart 方法渲染合成图。

作者准备的图像
从上面的分期偿还表和线图中,我们可以观察到我们每月分期付款的大部分用于支付我们付款计划早期阶段的贷款利息。在最初几年里,我们分期付款中只有一小部分用于支付本金。
然而,随着时间的推移,这种趋势正在改变。由于利息支付是根据之前剩余本金的定期利率计算的,因此持续还款将导致利息支付从一个月到另一个月稳步减少。在分期偿还计划的后期,我们会发现每月分期付款的大部分用于支付我们的贷款本金。
6.房屋净值(市场价值不变)
持续偿还抵押贷款不仅可以减少我们不时支付的利息,还可以不断增加我们的房屋净值。基本上,房产净值是我们在任何给定时间实际拥有的房产现值的一部分。

罗尼·乔治在 Unsplash 上的照片
假设我们以 50 万美元的市场价购买了一处房产,我们的首付是 10%。这意味着我们最初的房屋净值相当于我们的首付 50,000 美元。当我们开始偿还抵押贷款时,无论何时分期付款,我们的房屋净值都会累积。例如,如果我们支付了三个月的分期付款,累计本金支付总额为 2700 美元,我们最新的房屋净值为 50,000 美元+2700 美元= 52700 美元。
假设房子的市场价值在我们的还款期内保持不变,我们的房屋净值将相当于我们抵押贷款期限结束时 500,000 美元的市场价格。
让我们给我们的模拟器添加一个情节,以显示一个更清晰的画面。
第 4–5 行:使用 Numpy cumsum 方法获得本金支付和利息支付系列的累计和。本金支付的累计金额相当于累计房屋净值(假设房产的市场价值保持不变)。
第 7 行:创建一个 plottlyFig对象来显示线条图。
第 8–14 行:使用 Plotly go。散点图对象创建一个折线图来显示几个月内的累计房屋净值。使用 add_trace 方法将线图添加到 fig 对象中。
第 16–22 行:以类似的方式,使用 Plotly go。散点图对象创建另一个折线图来显示几个月来支付的累计利息,并将其添加到图对象中。
第 24–36 行:通过设置图表图形的标题名称、x 轴& y 轴标题、尺寸和图例来配置布局。

作者准备的图像
从上面的线图中,我们可以看到我们的累计房屋净值逐月增加,直到在还款期结束时达到顶峰。此外,我们还可以观察到,我们的累计房屋净值大约在第 314 个月后(接近还款期结束时)才会超过累计利息支付。
假设我们在模拟器中调整贷款年利率,从 4.5 降到 4。一旦一个值被改变,我们的图将自动更新如下。

作者准备的图像
年利率降低 0.5%,我们可以观察到最终支付的累计利息明显减少。大约在 278 个月后,我们的累计房屋净值将超过累计利息。这就是为什么我们总是寻找一个金融机构,可以为我们提供最好的抵押贷款利率。
现在,如果我们把我们的付款期从 30 年调整到 25 年呢?让我们看看它将如何影响我们的累计房屋净值随着时间的推移。

作者准备的图像
随着贷款偿还期限的缩短,累计支付的利息大幅减少。我们的累积房屋净值将会高于大约在我们的抵押贷款期中期后支付的累积利息。这表明,虽然我们可以支付较低的每月分期付款和较长的任期,但从长远来看,我们承担了巨大的利息成本。在控制我们当前的财务承诺和长期利润之间应该有一个平衡。
7.房屋净值增长预测
最后,让我们为我们的抵押贷款模拟器添加一个增长预测特性。在上一节中,我们的房屋净值的演变完全基于我们在整个贷款期限内的本金支付,没有考虑房屋市场价值的增长。

沃洛季米尔·赫里先科在 Unsplash 上的照片
如果我们房屋的市场价值每年都在变化(这种情况经常发生),我们的房屋净值会发生什么变化。值得注意的是,增长不一定是正的。也可能出现负增长。
在这里,我们添加了另一个输入字段,让用户输入我们模拟器中的预测增长率,并创建一个折线图来显示一段时间内的预测房屋价值和预测房屋净值。
第 4–5 行:创建一个相关的副标题和一个新的数字输入字段,用于表示国内市场价值的年增长率。
第 7–8 行:将年度预测增长率转换为月度增长率。使用 Numpy full 方法创建一个增长数组,并用月增长率填充它。
第 9–10 行:使用 Numpy cumprod 方法计算各月增长率的累计乘积。将由此产生的累积增长乘以原始房屋价值。这将产生一个预测家庭价值系列。
第 11–12 行:计算几个月内房屋所有权的累计百分比。将该累计百分比乘以预测房屋价值系列,这将得到预测房屋净值系列。
第 14–51 行:重复上一节介绍的类似步骤,创建线形图,以显示几个月内的预测房屋价值、几个月内的预测房屋净值和几个月内的剩余本金。使用 Plotly add_trace 方法将三个线图添加到同一个图表中。通过设置相关标题、x 轴& y 轴标题、尺寸和图例来配置图表图形布局。
第 53 行:渲染图表图形。

作者准备的图像
通过设定每年 3%的增长率,我们将看到我们的国内市场价值在 300 个月后(25 年)将翻一番。当我们还在用同样的月供还房贷时,202 个月后,我们的房屋净值已经超过了原始房屋价值(500,000 美元)。在我们的还款期结束时,我们的房屋净值相当于预测房屋价值,是原始房屋价值的 200%。这种房屋净值的增加可以为我们提供一个申请房屋净值贷款的机会,可以将我们的股权转换为现金。
现在,让我们尝试用负值-5 再次调整增长率,看看它如何影响我们的房屋净值。

作者准备的图像
从上面的线图中,我们可以观察到房屋价值在 300 个月(25 年)后严重贬值到原始市场价值的 30%左右。这也意味着我们的房屋净值也将在抵押贷款期限结束时贬值。我们因财产贬值遭受了巨大损失。
此外,有相当长的一段时间(大约第-57 个月到第-169 个月),我们的房屋价值属于剩余本金金额。这样的情况被称为 水下抵押 。在此期间,我们将没有任何股本可用于信贷,甚至可能阻止我们出售房屋,除非我们有足够的现金支付损失。水下抵押贷款是 2008 年金融危机期间的一个普遍问题。

来自 Pexels 的 Andrea Piacquadio 的照片
结论
家庭投资可以是非常有益的,但这是一个长期的过程,充满了风险。在我们自己的财务规划中,它需要仔细的市场分析和良好的自制力。希望这里展示的 Python 模拟器能给你一些关于抵押贷款的生动想法。任何投资都不会是一种随意的猜测活动,而是需要对未来情景进行一些可靠的预测,这将有助于我们做出更明智的决定。
我希望你喜欢阅读这篇文章。
参考
- https://www.investopedia.com/terms/h/home_equity.asp
- https://www.investopedia.com/terms/h/homeequityloan.asp
- 【https://www.cnbc.com/id/100543831
- https://www . investopedia . com/terms/u/under water-mortgage . ASP
- https://www . investopedia . com/terms/a/摊销 _ 时间表. asp
揭秘多伦多自行车盗窃案:哪些街区应该得到更多关注?
根据历史数据,发现多伦多警察局应该关注哪些街区的潜在自行车盗窃事件。
总结
这项研究旨在根据多伦多警察局公布的 2014 年至 2020 年报告的自行车盗窃案件清单,找出多伦多哪些街区在自行车盗窃方面应该引起注意。这项研究表明,多伦多警察局应该关注 6 年内占自行车盗窃案件总数约 47%的 10 个街区,此外还有其他 3 个街区的公寓,它们对 2020 年自行车盗窃案件的增长趋势有重要贡献。
简介
自行车是一种历史悠久的交通方式,给人类社会带来显著的好处。自行车不仅有利于运送人或货物,而且对保持身体健康非常有益,有助于增进精神健康。
由于在新冠肺炎疫情期间骑自行车成为一种流行的生活方式和自行车供应可能赶不上需求的增长,毫无疑问自行车价格可能会继续上涨。因此,丢失你可爱的自行车可能是最大的遗憾之一,如果发生的话。
这篇文章探讨了 2014 年至 2020 年发生在多伦多的自行车盗窃案件。用于执行分析的数据集由多伦多警察局提供,可在此处访问。
这篇文章回答了以下问题:
- 在过去的 6 年里,多伦多哪些社区的自行车盗窃案最多?
- 有没有一些有助于发现潜在盗窃案件的常规行为?
- 2020 年,有没有哪个街区的自行车盗窃案数量会大幅增加?
使用 r 执行分析。执行分析的详细步骤请参考此处的。
数据特征
以下是本次研究考虑的特征。
- 邻域(总邻域数= 140)
- 报告日期
- 被盗自行车的类型(如山地车、普通自行车等。)
- 自行车最后一次停放的场所(称为“场所类型”)
调查结果
在过去 6 年里,多伦多哪些社区的自行车失窃案最多?
帕累托分析用于根据社区在过去 6 年多伦多自行车盗窃案件总数中的重要性对社区进行排序。这些社区被分为三组:
- 十大社区
- 不在前 10 个街区,但仍占自行车盗窃案总数的 80%
- 其余街区

图 1—2014–2020 年多伦多街区自行车盗窃案贡献的帕累托图(图片由作者提供)
据了解,10 个街区贡献了大约 47%的盗窃案件。与此同时其他 32 个小区加起来的数字达到 80% 。其余 20%的盗窃案件分散在其他 98 个社区。
从现在开始,假设邻域可以被分成 3 组:
- “前 10 名” : 10 个社区贡献了大约 47%的案例
- “下一个 32 强” : 32 个社区贡献了大约 33%的案例
- “其余社区” : 98 个社区,约占案件的 20%
哪些街区被归为“前 10 名”?
以下是 2014 年至 2020 年落入“前 10 名”群体的社区列表,以及它们各自的自行车盗窃案件数量。

图 2—2014–2020 年自行车盗窃案件数量排名前十的社区(图片由作者提供)
是什么让“十佳”邻里团脱颖而出?
深入到楼宇类型,注意到一般情况下,上次停放在楼宇外的自行车容易被盗。一个相似的模式也显示在的“前 10”邻居组中。
然而,除了“前 10 名”之外,发生在户外和住宅区(即公寓和房屋)的案件中值数量几乎相似。

图 3—2014-2020 年多伦多自行车盗窃案件数量(按房屋类型划分)(图片由作者提供)
房屋类型的不同模式可能是使“前 10 名”在其他邻里群体中脱颖而出的模式。为了证明这一论点, K-means 聚类被用于跨邻域可视化群体分割。
‘剪影法’和‘肘法’用于确定最佳聚类数( k ) 。建议最佳的k-值为 2,因为这是平均距离突然下降的点(根据肘法)和剪影分数达到其峰值的点(根据剪影法)。

图 4 —肘部和剪影方法(图片由作者提供)
根据下面包含两个聚类的聚类图,“前 10 名”社区被归类到与其他社区不同的聚类中。这显示了“前 10 名”的重要性,在过去 6 年中,多伦多所有自行车盗窃案件中,这一邻里群体的贡献最大,这些案件主要发生在建筑物外。

图 5 —丛状地块(图片由作者提供)
有没有一些有助于发现潜在自行车盗窃案件的常规行为?
从下图可以了解到,多伦多的自行车盗窃案大多发生在工作日。

图 6—2014–2020 年按报告日统计的多伦多自行车盗窃案件数量 ( 图片作者 )
从逐月趋势来看,病例数在春季开始堆积,在夏季达到高峰,然后趋势显示从秋季到冬季持续下降。

图 7—2014–2020 年报告月份的自行车盗窃案件数量(图片由作者提供)
山地车和普通自行车是 2014 年至 2020 年期间报告失窃的两种最常见的自行车类型。

图 8—2014–2020 年多伦多自行车失窃案件数量(按自行车类型划分)(图片由作者提供)
2020 年,有哪些街区的自行车盗窃案数量出现大幅跃升?
虽然“前 10 名”邻里小组对案件数量的贡献最大,但其他邻里的重要性也不容忽视。
从同比趋势来看,据了解,2020 年多伦多的自行车盗窃案件数量有所增加,尽管新冠肺炎实施了限制。此外,与其他组相比,“下一个前 32 名”邻近组中的病例中值数显示出显著增加。

图 9—2014–2020 年报告年度多伦多自行车失窃案件数量(作者图片)
还值得注意的是,2019 年至 2020 年,“下一个 32 强”组的病例数量增加了 20%左右。另一方面,“前 10 名”下降了 14%左右。
此外,在对 2020 年病例的增量趋势数量贡献最大的 10 个街区中,其中 6 个属于“下一个前 32 名”。同时,只有一个地区(河谷镇)代表“前 10 名”。这表明“下一个前 32 名”群体中的社区对自行车盗窃案件数量的重要性。

图 10—2020 年各街道组对同比总病例数的贡献以及对增量病例数贡献前 10 名(作者图片)
公寓自行车盗窃案件的数量对 2020 年案件数量的增长起到了重要作用。此外,这一数字也是芒特普莱森特西(49 例)、柳谷东(28 例)和湾景村(22 例)病例增加的主要原因。这些街区的公寓案件数量与其他街区增加的案件总数相似,甚至更多,如 Englemount-Lawrence、Yonge-Eglinton 等。

图 11 —房屋类型对同比案件总数的贡献以及前 10 名贡献者中每个贡献者的案件增量(图片由作者提供)
这表明芒特普莱森特西、柳谷东和湾景村的公寓,不属于“前 10 名”邻里群体,在 2020 年自行车盗窃案件的增量趋势数字中发挥了重要作用。
结论
这项研究建议多伦多警察局应该更加注意在以下地方防止自行车被盗,希望能够减少多伦多的自行车被盗案件。
- 在过去的 6 年中,10 个街区的自行车盗窃案占了 47%,尤其是停在大楼外面的自行车。
- 芒特普莱森特维尤、柳谷东区和湾景村的公寓;因为这些对 2020 年自行车盗窃案件数量的增加做出了重要贡献。
此外,建议在春夏季节到来时,特别是在工作日,要警惕潜在的自行车盗窃犯罪。
如果您对本文有任何反馈,请通过LinkedIn联系我们。还有,可以随意查看我的 GitHub 资源库 来探索我的项目。
揭开 boto3 的神秘面纱:如何在 Python 中使用任何 AWS 服务
深入探究 boto3 以及 AWS 如何构建它

AWS 将 boto3 定义为一个 Python 软件开发工具包,用于创建、配置和管理 AWS 服务。在本文中,我们将了解 boto3 如何工作,以及它如何帮助我们与各种 AWS 服务进行交互。
目录:
1。Boto3 引擎盖下
2。客户端与资源
∘ 为什么资源通常比客户端容易使用
∘ 为什么你仍然会在大部分工作中使用客户端
3 .等待者
∘ 等到特定的 S3 对象到达 S3
4。收藏
5。会话:如何将 IAM 凭证传递给你的 boto3 代码?
∘ 如何更改默认的 boto3 会话?
结论
1.引擎盖下的 Boto3
AWS CLI 和 boto3 都建立在 botocore 之上——一个低级 Python 库,负责向 AWS 发送 API 请求和接收响应所需的一切。肉毒杆菌:
- 处理会话,凭证和配置,
- 为所有操作提供细粒度的访问。ListObjects,DeleteObject )在特定服务( ex)内。S3 ),
- 负责将输入参数、签名请求,以及将响应数据反序列化到 Python 字典中,
- 提供低级客户端和高级资源抽象,以与 Python 中的 AWS 服务进行交互。
你可以把 botocore 看作是一个包,它允许我们忘记底层的 JSON 规范,在与 AWS APIs 交互时使用 Python (boto3)。
2.客户端与资源
在大多数情况下,我们应该使用 boto3 而不是 botocore。使用 boto3,我们可以选择与较低级的客户端或者较高级的面向对象的资源抽象交互。下图显示了这些抽象之间的关系。

boto3、aws-cli 和 botocore 中的抽象级别,以 S3 为例—图片由作者提供
为了理解这些组件之间的区别,让我们看一个简单的例子,它将展示 S3 客户端和 S3 资源之间的区别。我们想要列出来自images目录的所有对象,即所有带有前缀images/的对象。

Boto3:客户端 vs 资源——作者图片
通过这个简单的例子,您可能已经发现了不同之处:
- 使用客户端,您可以从反序列化的 API 响应中直接与响应字典进行交互,
- 相比之下,使用资源,你可以与标准的 Python 类和对象交互,而不是原始的响应字典。
您可以使用help()和dir()来调查资源对象的功能:

Boto3:探索资源对象—作者图片
总的来说,资源抽象产生了可读性更好的代码(与 Python 对象交互,而不是解析响应字典)。它还处理许多底层细节,如分页。资源方法通常会返回一个生成器,这样你就可以轻松地遍历大量返回的对象,而不用担心分页或者内存不足。
有趣的花絮: 无论是客户端还是资源代码,都是基于描述各种 AWS APIs 的 JSON 模型动态生成的。对于客户端,AWS 使用 JSON 服务描述 ,对于资源 a 资源描述 , 作为自动生成代码的基础。这有助于更快的更新,并为您与 AWS 交互的所有方式提供一致的界面( CLI、boto3、管理控制台)。JSON 服务描述和最终的 boto3 代码之间唯一真正的区别是,
*PascalCase*操作被转换为更 Pythonic 化的*snake_case*符号。
为什么资源通常比客户端更容易使用
假设您需要列出 S3 存储桶中的数千个对象。我们可以尝试在初始代码示例中使用的相同方法。唯一的问题是s3_client.list_objects_v2()方法只允许我们列出一个最多一千个对象。为了解决这个问题,我们可以利用分页:

boto 3:S3 客户端分页——图片由作者提供
虽然分页器代码非常简单,但是资源抽象只用两行代码就完成了工作:

Boto3: S3 资源—作者图片
为什么您仍然会在大部分工作中使用客户端
尽管有资源抽象的好处,客户机提供了更多的功能,因为它们与 AWS 服务 API 几乎是 1:1 的映射。因此,根据特定的用例,您很可能最终会同时使用客户端和资源。
除了功能上的不同,资源不是线程安全的,所以如果你计划使用多线程或多重处理来加速 AWS 操作,比如文件上传,你应该使用客户端而不是资源。更多关于那个这里。
注意:有一种方法可以直接从资源对象访问客户端方法:
s3_resource.meta.client.some_client_method()。
3.服务员
等待者正在轮询特定资源的状态,直到它达到您感兴趣的状态。例如,当您使用 boto3 创建 EC2 实例时,您可能希望等到它达到“运行”状态,直到您可以对这个 EC2 实例做一些事情。以下是展示这个特定示例的示例代码:

Boto3:使用 waiter 轮询新 EC2 实例的运行状态——图片由作者提供
请注意,上例中的ImageId对于每个 AWS 区域是不同的。您可以按照 AWS 控制台中的“启动实例”向导找到 AMI 的 ID:

寻找阿美族——作者图片
等到一个特定的 S3 对象到达 S3
实话实说吧。您多长时间发布一次新实例?可能不经常。所以让我们建立一个更真实的服务员例子。
假设您的 ETL 过程一直在等待,直到一个特定的文件到达 S3 桶。在下面的例子中,我们一直等到市场部的人上传一个包含当前活动成本的文件。虽然您可以使用带有 S3 事件触发器的 AWS Lambda 实现相同的功能,但是下面的逻辑并不依赖于 Lambda,可以在任何地方运行。

使用 S3 资源中的服务员—图片由作者提供
或者同样使用更可配置的客户端方法:

在 S3 客户端使用服务员—作者图片
从上面的代码片段可以看出,使用客户端的服务员抽象,我们可以指定:
- MaxAttempts :我们应该检查多少次特定对象是否到达——这将防止僵尸进程,如果对象在预期时间内没有到达,将会失败,
- 延迟:每次尝试之间等待的秒数。
文件一到达 S3,进程就停止等待,这允许您对新到达的数据做一些事情。
4.收集
集合表示一组资源,如桶中的一组 S3 对象或一组 SQS 队列。它们允许我们在单个 API 调用中对一组 AWS 资源执行各种操作。收藏可用于:
- 获取带有特定对象前缀的所有 S3 对象:

Boto3 系列—作者图片
- 获取具有特定内容类型的所有 S3 对象,例如,查找所有 CSV 文件:

Boto3 系列—作者图片
- 获取所有 S3 对象版本:

Boto3 系列—作者图片
- 指定要迭代的对象的块大小,例如,当 1000 个对象的默认页面大小对于您的应用程序来说太大时:

Boto3 系列—作者图片
- 在一个 API 调用中删除所有对象(小心点!):

Boto3 集合:删除所有对象—作者图片
更常见的操作是删除带有特定前缀的所有对象:

Boto3 集合:删除带有特定前缀的所有对象—图片由作者提供
5.会话:如何将 IAM 凭证传递给你的 boto3 代码?
在与 boto3 交互时,有许多方法可以传递访问键。以下是 boto3 尝试查找凭据的位置顺序:
1 显式传递给boto3.client()、boto3.resource()或boto3.Session():


Boto3:访问键—作者图片
2 设置为环境变量:

将访问键作为环境变量—图片由作者提供
3 在~/.aws/credentials文件中设置为凭证(该文件由 AWS CLI 中的 *aws configure* 自动生成):

AWS 凭据—图片由作者提供
4 如果您将具有适当权限的 IAM 角色附加到您的 AWS 资源,您根本不需要传递凭证,而是分配一个具有所需权限范围的策略。这是它在 AWS Lambda 中的样子:


我在 AWS Lambda 中的角色—图片由作者提供
这意味着通过将 IAM roles 附加到 Lambda 函数等资源上,您不需要手动传递或配置任何长期访问键。相反,IAM 角色动态地生成临时访问密钥,使得这个过程更加安全。
如果你想利用 AWS Lambda 与 Python 和 boto3 的特定用例,请看下面的链接:
- 如何构建事件驱动的 ETL 和事件驱动的数据测试,
- 如何使用 Amazon Rekognition 从图像中提取文本,
- 如何使用社交网络、SQS 和 Kinesis 构建解耦服务,
- 如何使用 NoSQL DynamoDB 读写数据,
- 如何使用机密管理器管理凭证,
- 如何使用 S3 选择来提高从 S3 检索数据的性能。
AWS Lambda 的一个有用特性是 boto3 已经预装在所有 Python 运行时环境中。这样,您可以直接在 Lambda 函数中运行本文中的任何示例。只需确保添加与您想要在 Lambda 的 IAM 角色中使用的服务相对应的适当策略(例如,,S3 只读策略):

在 AWS Lambda 中创建函数-作者图片

测试来自 AWS Lambda 的 boto3 图片由作者提供
如果你计划在生产中运行一些 Lambda 函数,你可以探索一下dash bird——一个可观察性平台,它将帮助你监控和调试你的无服务器工作负载。它对于构建故障自动警报、基于项目或域对相关资源进行分组、提供所有无服务器资源的概览、交互式浏览日志以及可视化操作瓶颈尤其有价值。多亏了 CloudFormation 模板,整个设置只需要 2 分钟。

Dashbird 提供的所有无服务器资源概述—图片由 Dashbird.io 提供
如何更改默认的 boto3 会话?
Boto3 使更改默认会话变得很容易。例如,如果您有几个概要文件(,比如一个用于 *dev* ,一个用于 *prod* AWS 环境,您可以使用一行代码在它们之间切换:

Boto3: session —作者图片
或者,您可以将凭据直接附加到默认会话,这样您就不必为每个新客户端或资源单独定义凭据。

Boto3: session —作者图片
结论
在本文中,我们研究了如何使用 boto3 以及它是如何在内部构建的。我们研究了客户端和资源之间的差异,并调查了它们各自如何处理分页。我们探索了等待者如何在继续我们代码的其他部分之前帮助我们轮询 AWS 资源的特定状态。我们还研究了集合如何允许我们在多个 AWS 对象上执行操作。最后,我们探索了向 boto3 提供凭证的不同方法,以及如何使用 IAM 角色和 IAM 用户访问键来处理这些凭证。
感谢您的阅读!
参考文献:
[1]AWS re:Invent 2014 |(dev 307)针对 Python (Boto)的 AWS SDK 第 3 版简介
[2] Boto3 文档
揭开去认同的神秘面纱
了解数据保护法规遵从性的关键技术

来源:https://unsplash.com/photos/B2SRwbYWLuI
数据匿名化、去标识化、编辑、假名化和标记化是满足数据保护法规(如 GDPR 和即将出台的 CPRA)的关键技术。但是区分匿名化、去标识化、编辑、假名化和标记化比看起来更复杂:存在足够多的混淆和错误信息,甚至可以迷惑最有经验的数据科学家。
匿名化 vs 去标识化 vs 编辑 vs 假名化 vs 标记化
获得正确的定义是做出正确决策以最有效地保护和使用数据的关键一步。我们将看看每一个的定义,并给出一个运行的实际例子来直观地展示每一个的样子。
在围绕这些术语的讨论中,重新识别的风险经常交织在一起。再识别是指对数据集中有直接识别信息(如全名、社会安全号)或准识别信息(如年龄、大概地址)的个体进行身份确定的行为。当组合在一起时,准识别符会导致重新识别的指数风险。在某些情况下,去识别机构需要重新识别的能力,在这种情况下,另一层风险在于恶意方访问将直接和准标识符与它们被替换的数据相链接的数据的可能性。
匿名化
匿名化是指删除个人可识别信息和准可识别信息(即当与其他信息结合时,可导致重新识别的数据;例如年龄、大概地址等。)以使得个体变得永久不可识别。参见匿名化和 GDPR 合规;概述了解它如何融入 GDPR。
匿名化通常是使结构化医疗数据集安全共享的首选方法。非结构化数据呢?可以匿名吗?虽然这样做比较棘手,但答案是肯定的。这是一封经过适当匿名处理的电子邮件样本:
“你好[姓名],
抱歉,它已经在我的垃圾邮件中结束了!
我明天[时间]有预约,但是[时间]可以。届时,我将发送更新的邀请。如果这对你不起作用,请告诉我。
谢谢你,
[姓名]"
取消识别
去识别也需要删除个人和准识别符,但通过一个过程,使原始数据重新连接到去识别结果。参见数据去识别或匿名化指南。
实际上,取消身份通常用于描述删除直接标识符(全名、地址、SSN 等)的过程。)和有时的准标识符(年龄、性别等)。)但与匿名化相比,它对数据不能追溯到个人的保证更少,尽管它有时也被用作包含匿名化和假名化的术语。
你可能会想,如果你不能保证数据是匿名的,那么解密数据又有什么意义呢?这取决于用例。
将上面的匿名电子邮件改为:
“你好[姓名 1],
抱歉,它已经在我的垃圾邮件中结束了!
我明天在[TIME_1]有预约,但是[TIME_2]也可以。届时,我将发送更新的邀请。如果这对你不起作用,请告诉我。
谢谢你,
[姓名 2]"
现在,假设一家公司决定加密与 NAME_1、NAME_2、TIME_1 和 TIME_2 相关联的直接和潜在标识符,并单独存储它们,以防它们需要重新识别电子邮件(可能用于法庭)。那封电子邮件将不再被视为匿名邮件,因为标识符可以链接回它。
但这并不意味着隐私受到了损害。例如,如果分析和机器学习团队使用去身份化的电子邮件(而不是明文原件),他们实际上为他们的用户和他们的公司提供了很好的服务。有可能获得洞察力,同时降低用户隐私风险,并最大限度地降低将个人数据发送到组织的另一部分的安全风险,在那里个人数据可能变得无法跟踪。
修订版
为了增加匿名化和取消身份识别之间的混淆,术语“编辑”也经常被错误地使用。根据国际隐私专业人员协会的术语表,编辑是“识别和删除或阻止正在生成的文档中的信息的做法[…]”。
编辑在去标识化方面扮演了一个有趣的角色。修订不一定涉及完全删除个人数据,而是有选择地删除特别敏感的信息。一个例子是从客户服务对话中删除信用卡号码。如果电子邮件、电话记录或聊天记录泄露了关于如何使用吸尘器的问题,那可能不会造成很大的损害。但是如果那些聊天记录里有信用卡号并且没有被删除呢?大买卖。
假名化
现在有一个术语经常被误解。即假名化。假名化是指替换某些数据(如姓名、地址等)。)带有假数据,这些假数据通常被表示为与原始数据相链接。这为一个术语留下了一个相当大的漏洞,这个术语意味着用与原始数据无关的虚假数据替换信息。我们将杜撰一个短语 无链接的自然假名化 来定义这一点。
如上所述,与去识别相比,无关联的自然假名化有许多优点。首先,数据对于机器学习训练和推理变得更加友好。在下面的示例中,PII 已被替换为斜体的假数据:
“嗨凯特,
抱歉,它已经在我的垃圾邮件中结束了!
我预约了明天下午 5 点,但是上午 9 点也可以。届时,我将发送更新的邀请。如果这对你不起作用,请告诉我。
谢谢你,
琳达
此外,意外留下的任何个人或准可识别信息都变得像大海捞针一样难以与虚假数据区分开来(或者更像大海捞针);例如,假设在取消识别上述电子邮件时,意外遗漏了“Linda ”:
“你好[姓名 1],
抱歉,它已经在我的垃圾邮件中结束了!
我明天在[TIME_1]有预约,但是[TIME_2]也可以。届时,我将发送更新的邀请。如果这对你不起作用,请告诉我。
谢谢你,
琳达"
在 Private AI,我们已经花了大量的时间来找出如何正确地进行自动假名化。这里有一个提示:字典查找不起作用。我们必须创建自己的 transformer 模型架构(一种为自然语言处理而构建的机器学习模型),以便以上下文化、非确定性的方式生成真实的单词和数字。仔细选择训练数据对于产生真实的替代物是至关重要的,这也是其他的交易技巧之一。
标记化也经常被称为一种假名化。
标记化
最后一个术语是标记化,它通常用于具体描述替换某些数据的标记类型。也就是说,用随机令牌替换个人数据。通常,在原始数据和令牌之间保持链接(例如,用于网站上的支付处理)。例如,令牌可以由单向函数(例如加盐散列)生成,或者可以是完全随机数。例如,如果某些类型的令牌化依赖于加密,那么它们甚至是可逆的,在这种情况下,只需要存储解密密钥,而不需要存储每条个人数据与其替代数据之间的链接。
让我们在运行的电子邮件示例中标记直接和准可识别的信息:
“Hi 748331d 230 BF 99d 9 a 39 ed 0 e 6 c 6668 cdd,
抱歉,它已经在我的垃圾邮件中结束了!
我明天订了 3388 e 06178d 0634 fc 03 ffbdecce 677 f 8,不过 f6f 7755d 5141d 5 b 7308 df 2516 aa 9 a 82 c 也行。届时,我将发送更新的邀请。如果这对你不起作用,请告诉我。
谢谢你,
ce5a 40345609 b 81 a5e 7c 973 C1 F3 d 93 EB "
虽然标记化对支付处理特别有用,但它不太可能成为非结构化数据保护的赢家,因为与没有链接的自然假名化相比,它相对缺乏相关的上下文信息。
把所有的放在一起
尽管直接和准标识符通过匿名化、去标识化、编辑、假名化和标记化中的每一种方式被删除,但它们在维护原始数据的上下文信息方面都非常有效。请继续关注我们下一篇关于匿名化是如何被误解的文章。
同时,这里有一个方便的表格来指导你的决策:

致谢
感谢 John Stocks 和 Pieter Luitjens 对本文早期草稿的反馈。
揭秘高斯混合模型和期望最大化
以简化的方式解释高斯混合模型及其期望最大化的基本算法

在您学习了如何使用最简单的聚类算法 k-means 对未标记数据点的样本进行聚类之后,我们开始看到 k-means 在将该技术应用于真实数据集时的一些缺点。ML 工程师将采取的下一步是应用更复杂的算法来理解他/她的数据样本中的各种分组(集群),并且该算法很可能是高斯混合建模(GMM)。由于开源软件和多种 ML 框架的存在,比如 Scikit-learn ,使用这种算法只需要几行代码。然而,对许多人来说,理解这一过程中使用的数学基础是很难的。在本文中,我们将更直观地研究这个算法的内部工作原理。
GMM 相对于 k-means 的优势
让我们开始构建高斯混合模型的概念,直接研究 k-means 的缺点。
- 聚类大小不成比例: k-means 的工作原理是将数据样本分配到最近的假设聚类中心,从而在超平面中形成 Voronoi 图。因此,如果一个聚类的分布距离其正确的聚类中心太远,几个数据样本将会被错误分类。使用 GMM,数据点在集群中的分布不需要从集群中心开始保持一致。

Voronoi 分割重叠的 GMM 不同分布的集群(图片由作者提供)
- 不同形状的聚类:看待上述问题的另一种方式是 k-means 可能扰乱聚类的形状,尽管数据样本被紧密地打包在聚类内。随着聚类方向的改变,k-means 的结果可能会显著改变。

在 GMM 形成的集群,集群中心和相应的 Voronoi 分区重叠(图片由作者提供)
- 重叠聚类:有时,属于不同聚类的数据点可以非常紧密地打包,k-means 算法会毫不犹豫地在样本分配到其聚类之间进行推测。k-means 将在聚类之间绘制硬边界,即使样本可能无限接近该边界。对于 GMM,你用一个假设来阐述你的模型,即集群中不存在硬边界,这将我们引向 GMM 的下一个主要优势。

GMM 的重叠集群(图片由作者提供)
- 软分配:利用 k-means 的标准算法,你以 100%的概率将一个数据点分配给一个聚类。但是,在 GMM 中,您可以为数据集中的每个数据样本分配一组可能性,以确定该数据样本属于系统中每个聚类的概率。例如,在下面由 4 个聚类组成的分布中,如果要求 GMM 对数据样本进行聚类,则为出现在中心的数据样本分配相等的概率(各 25%)。

GMM 将做软作业(图片由作者提供)
正态分布
那么,从数学上来说,我们如何表示这些大小、形状、方向可能不同,并且可能相互重叠的集群的功能呢?正如这项技术的名称所暗示的,我们利用高斯分布来分别表示系统中的每个集群。在我们研究它是如何成为可能之前,让我们简单回顾一下 1D 的高斯分布。

各种高斯分布的 PDF(图片来源:维基百科)
这里我们展示了一些高斯分布的概率密度函数(PDF)。该单峰函数的峰代表平均值,并且也出现在该分布的中心。这种分布在平均值周围的分布由标准差来确定。标准差的平方项被称为该分布的方差。
但是由于我们的数据集将处于更高维度(比如 n),我们将不得不利用 n 维高斯分布函数来表示我们的聚类。由于存在多个特征(由图像中的轴表示)对高斯的影响,我们将从简单的方差上升到协方差矩阵,这将有助于我们捕获关于分布(通过方差)和方向(通过相关性)的信息。
使用高斯函数创建集群
接下来让我们用高斯分布函数创建不同位置、大小、形状和方向的集群。让我们考虑我们有一个 2 维特征集,它将产生一个 2×2 维协方差矩阵。为了创建一个简单的圆形集群,这里是我们的协方差矩阵。

方差相等的协方差矩阵(图片由作者提供)
对角线项表示轴的每个方向上高斯分布的方差,它们应该相等以得到圆形。现在,如果我们改变方差的尺寸,圆形将被转换成如图所示的椭圆。

协方差矩阵中方差不相等的椭圆聚类(图片由作者提供)
上面的星团是在一个基于笛卡尔坐标的 X-Y 坐标系中排列的轴。为了改变规则轴对齐的方向,我们在非对角线位置添加相关项。

带方向的椭圆群集(图片由作者提供)
我们如何改变这些集群的位置?我们利用 n 维平均向量(用μ表示)来实现这一点。例如,下面是数据样本的四个高斯模型聚类的集合,每个聚类都有其均值向量和协方差矩阵。

四个独立的高斯分布

四个分布上的四个独立集群(图片由作者提供)
我们如何组合这些高斯模型的集群?
虽然我们已经描述了上面的四个集群,但是我们是如何将它们组合在一起的呢?难道不应该有一种关系来捕捉每个集群相对于其他集群的重要性吗?这就引出了另一个由π表示的参数,它量化了系统中每个簇的权重的相对比例。由于这是一个相对标度,我们将确保系统中所有π的总和等于 1。

比例权重参数
因此,为了表示我们的聚类(或混合)分量,我们将不得不使用总共三个参数(均值μ、协方差∑和比例权重π),它们统称为聚类参数。
我们如何跟踪软分配?
我们将不得不增加一个术语。我们需要表达将每个数据样本分配给系统中所有现有聚类的概率。我们将通过由 rᵢₖ表示的责任向量来捕获该软分配,该责任向量超越了集群 k 将为数据样本 I 承担的责任量。由于这些是概率,与单个数据点相关联的责任的总和将等于 1。所以,我们有,

软分配参数
模型的表述
既然我们已经有了表示集群的高斯分布,让我们从模型中提取一些有用的信息。我们将尝试回答的第一个问题是,如果你随机选择一个数据样本(比如样本 I),它以什么概率属于这些聚类中的每一个(比如总共 k 个聚类)?答案很简单,就是我们对每个集群的权重比例分量π,因为它转化为每个集群在系统中的重要性/优势。数学上,

换句话说,这个等式对应于将数据样本分配给聚类 k 的先验概率
现在让我们向前迈出一步。假设我们知道之前看到的 iᵗʰ样本(由 zᵢ表示)属于聚类 k,那么让我们尝试计算数据样本 zᵢ中存在的输入向量(由 xᵢ表示)的特定配置属于聚类 k 的概率是多少?如果你想象一下,这个问题的答案等于聚类 k 的高斯分布函数,因为该分布函数换句话说是存在于其中的样本的个体集合。这里的样本是由输入向量组成的。所以数学上,我们有,

假定 zᵢ属于群集 k,这个等式对应于 xᵢ出现的可能性
现在,我们已经定义了由聚类参数和软分配组成的模型,我们需要设计一种算法来建立各种聚类参数之间的关系,并最终将软分配分配给所有单个数据点。让我们分两步利用假设的数学能力来解决这个问题。
步骤 1:假设,集群参数是已知的
尽管我们实际上并不知道,但让我们暂时假设,我们知道所有簇的簇参数{μ,∑和π}的值,因此高斯函数的分布是已知的。我们现在必须计算软分配概率。聚类 k 中的特定数据样本 zᵢ的责任向量内的个体概率值转化为观察到聚类 k 中的数据样本 zᵢ的可能性,该可能性被该聚类 k 的加权因子(先验概率)放大。因此,在数学上,这被表示为:

因为这是一个概率值,我们必须在责任向量的每个元素的所有可能的集群分配上标准化这个等式。

步骤 2:假设,软分配是已知的
以前,我们假设集群参数是已知的,然后,我们找到了一种计算软分配的方法。现在让我们以相反的方式完成这一步。让我们通过假设软分配是已知的来找到计算集群参数的方法。
为了简化计算过程,我们将暂时考虑每个数据样本到一个聚类的分配是绝对的(硬的),类似于 k-means。现在,我们需要分别使用属于每个聚类的数据样本来计算所有聚类的{μ,∑和π}。这是最大似然估计的直接应用,我们试图找到目标函数中参数的最佳值,然后用最佳值拟合函数。
然而,我们将采取一种捷径,因为我们已经知道高斯分布中的平均向量和协方差矩阵的值,并且我们将不使用带有优化器的 MLE 的标准过程来导出这些值。因此,均值和协方差的估计值为:

使用硬分配估计聚类参数
Nₖ表示聚类 k 中样本的数量,n 对应于数据集中样本的总数。π的估计聚类比例参数是属于聚类 k 的数据样本出现的直接概率值。因此,

使用硬分配的估计比例权重
现在估计的簇参数方程准备好了,让我们假设簇分配是软的而不是硬的或绝对的来解决原始问题。为此,我们可以使用硬赋值在已经导出的方程的基础上构建。在硬任务中,我们对 xᵢ在群集 k 中的全部观察进行了处理,但现在我们只需缩减其相对责任份额(0.0 到 1.0)的绝对(100%或 0%)贡献。具有软分配的更新的集群参数估计将是:

使用软分配估计集群参数
出于好奇,您可以通过将责任向量更改为 absolute (1.0 或 0.0),将这些等式逆向工程为硬分配的等式。
期望值最大化算法
我们已经观察到,如果我们将我们的集群参数固定为某些值,我们可以在该时间步长瞬间计算软分配。类似地,当我们固定软分配时,我们可以在该时间步获得集群参数值。这形成了两个基本步骤,我们可以迭代运行有限次来创建期望最大化算法。在这一点上唯一的挫折是我们应该从什么值开始时间步长 0。就像在 k-means 聚类过程的开始,我们可以随机分配一些聚类参数,然后开始 EM 算法。
让我们正式定义我们看到的两个步骤。
电子步骤:这在我们解释的步骤 1 中有描述。在这一步中,我们估计在该时间步中给定聚类参数估计的聚类责任向量。
M 步:这在我们解释的第 2 步中有描述。在这一步中,我们最大化该时间步中给定责任向量的聚类参数的可能性。
最后,我们反复不断地重复上述步骤,直到聚类参数和软分配的似然值收敛到局部模式。更简单地说,这意味着当分别在 E-step 和 M-step 之间迭代时,软分配和集群参数值的振荡低于阈值水平。
在这篇文章中,我们探讨了无监督学习方法的聚类与高斯混合建模及其潜在的算法的期望最大化。请分享你对这篇文章内容的看法。
揭开 Git 引用的神秘面纱
支持核心 Git 操作的真正主力

图片由作者提供,使用图制作。
作为一名数据科学家或数据工程师,当他/她知道所有的核心元素都被像 git-clone 或 git-push 这样的 Git 操作所利用时,与 Git 一起工作总是轻而易举的。尽管核心 Git 操作已经得到了爱好者们的充分关注,但这里特别关注的是一个名为 Git 引用的核心实体,它支持几个这样的核心 Git 操作。
为了理解 Git 引用及其重要性,让我们考虑下面的复杂结构的远程仓库

展示了一个包含五个分支(包括主分支)的远程存储库结构。图片由作者提供,使用图制作。
并如下克隆上面所示的远程存储库
$ git clone https://github.com/<git_username>/my-repo.git
正如预期的那样,克隆操作会产生一个本地存储库,其中有一个默认的本地主分支链接到远程主分支上,还有一个远程连接源分支和所有远程分支,如下所示

说明了包含五个分支(包括主分支)的远程存储库的克隆操作。图片由作者提供,使用图表制作。
然而,在您的本地机器上仔细观察,本地目录 my_repo 恰好包含您的远程 main 分支中存在的文件的副本。尽管像 branch_1 和 branch_2 这样的远程分支的内容被克隆并存在于您的本地存储库中,但是它们的文件内容在您的本地机器上似乎还不可见。因此,引出了一个问题
如何访问远程分支的内容?
好啦好啦,别担心,这就是 Git 引用发挥作用的地方。为了能够访问除远程主分支之外的其他远程分支的内容, git-clone 不仅仅是创建远程主分支和远程连接源的本地副本。根据亚特兰蒂斯人的 git-clone 文档,
为了方便起见,克隆会自动创建一个名为“origin”的远程连接,指向原始存储库。这使得与中央存储库交互变得非常容易。这种自动连接是通过在
refs/remotes/origin下创建到远程分支负责人的 Git refs 并初始化remote.origin.url和remote.origin.fetch配置变量来建立的。
换句话说,除了简单地创建一个远程连接源,见上图, git-clone 操作还创建 Git 引用又名 refs 到远程分支 branch_1 、 branch_2 等。这些参考位于您本地的 my_repo 目录下文件夹 refs/remotes/origin 下。进一步简化,默认情况下, git-clone 操作创建一个本地分支 main ,其文件内容位于您的本地目录 my_repo 中。对于其余的远程分支,它获取其内容,存储在本地。git 目录,并创建 Git 引用,而不是创建多个本地分支及其自己的特定于分支的本地 my_repo 目录。所有 Git 引用到这些远程( origin )分支可以列出如下
my_repo $ cd .git/refs/remotes/origin
origin $ lsHEAD branch_1 branch_2 branch_3 branch_4
注意。git 在 refs 目录前面。一般来说,所有的 Git 元数据都存储在下。git 目录在你本地的 my_repo 目录下,除了之外。gitignore 文件,这是用户特定的。使用 ls -a 列出隐藏文件。
列出上述远程 Git 引用 ( refs )的另一种方式是利用 git 分支命令以及标志 -a 或 - remote 。我们使用- -remote 标志,它列出了所有的 refs 上面的 git-clone 操作,这些操作是为远程存储库中的所有远程分支创建的,如下所示
my_repo $ git branch --remote remotes/origin/HEAD -> origin/main
remotes/origin/branch_1
remotes/origin/branch_2
remotes/origin/branch_3
remotes/origin/branch_4
remotes/origin/main
Git 引用 remotes/origin/HEAD ,默认指向 remote ( origin) main 分支。注意 origin/main 只是引用Gitreferenceremotes/origin/main的另一种方式。或者, -a 标志列出了本地和远程 Git 引用,见下文
my_repo $ git branch -a* main
remotes/origin/HEAD -> origin/main
remotes/origin/branch_1
remotes/origin/branch_2
remotes/origin/branch_3
remotes/origin/branch_4
remotes/origin/main
请注意,默认情况下,本地 Git 引用 main 是在 git-clone 操作期间创建的,并且在 refs/heads 文件夹下可用,与位于 refs/remotes/origin 文件夹中的远程 Git 引用相反。
鉴于所有的远程参考都已设置,我们将我们之前的问题重新表述为
我们如何使用远程 Git 引用来访问远程分支的内容,比如本地机器上的 branch_1 ?
假设我们想要访问本地机器上的远程 branch_1 的内容,即在我们的本地存储库中,我们需要做的就是利用 refs/remotes/origin 中为 branch_1 设置的远程 Git 引用,并执行以下操作
my_repo $ git checkout branch_1
上面的命令在幕后做了很多事情。首先在 refs/remotes/origin 文件夹中寻找 Git 引用 branch_1 。如果没有找到,它抛出一个错误。其次,它在您的本地存储库中创建了一个名为 branch_1 的本地分支,它是基于远程 branch_1 的。本地分支 _1 也链接到远程分支 _1 ,即用于执行拉或推操作。第三,在文件夹 refs/heads 下创建一个本地Gitreferencebranch _ 1。最后,它将本地目录 my_repo 中的文件内容替换为远程 branch_1 中的文件内容,即本地目录 my_repo 中的文件不再是远程 main 分支中文件的副本。因此,我们现在有两个本地分支,即 main 和 branch_1 ,链接到相应的远程分支,但仍然只有一个本地 my_repo 目录,如下所示
my_repo $ git branch -a* branch_1
main
remotes/origin/HEAD -> origin/main
remotes/origin/branch_1
remotes/origin/branch_2
remotes/origin/branch_3
remotes/origin/branch_4
remotes/origin/main
本地Gitreferencebranch _ 1前面的星号“”表示本地存储库中当前活动的分支。类似地,我们也可以检出*(访问)其他远程分支的内容,比如本地存储库中的 branch_2 和 branch_3 。用这种方式做的一件很酷的事情是,您只在需要的时候基于远程分支创建一个本地分支。因此,避免了本地存储库中不必要的本地分支混乱。
要从本地分支 _1 切换回本地主分支,您需要做的就是
my_repo $ git checkout main
这将在本地主分支旁边放置星号“”。为了确保本地主分支中的文件内容与远程主*分支中的文件内容相同,执行 git-pull 。
这就是我们的结局。希望以上见解有所加强🏋️♀️你对 Git 引用及其好处的理解。享受 Gitting!🙏
还是那些好奇的人。为了查看本地 Git 引用如 main 或 branch_1 如何链接到其对应的远程分支,我们列出了本地存储库的配置变量
my_repo $ git config --list... skipped other variables ...
remote.origin.url=https://github.com/<git_username>/my_repo.git
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
**branch.main.remote=origin**
branch.main.merge=refs/heads/main
**branch.branch_1.remote=origin**
branch.branch_1.merge=refs/heads/branch_1
如你所见,以粗体显示的本地配置变量 branch.main.remote 和 branch.branch_1.remote 是用远程连接 origin 初始化的。意味着本地分支主和分支 _1 链接到远程分支主和分支 _1 。请注意,每当在本地计算机上签出新的远程分支时,相应的配置变量将被添加到本地存储库的配置文件中。
揭秘链表
开始使用这种数据结构而不是数组!
选择正确的方式存储数据是一项艰巨的任务。有许多数据结构,但没有一种数据结构适合所有问题。你能做的最好的事情就是识别每一种数据结构的用法,并确定哪一种对于特定的情况是最有效的。
链表一直是我和我的同行在学习数据结构时的噩梦。有时我会感到困惑,既然我们已经有了简单的“数组”,为什么还要有这样的数据结构。如果你和我想的一样,那么你还没有从根本上理解它。所以,我们将直接进入并回答这个百万美元的问题:到底什么是链表?

什么是链表?
链表被归类为线性数据结构。线性数据结构具有顺序排列的数据元素,并且每个成员元素都与其前一个和下一个元素相连接。我们可能没有意识到,但众所周知的“数组”或“列表”也被归类为线性数据结构。线性数据结构最适合用于存储顺序数据(有序数据)。
动态规划
但是简单的“数组”有什么问题呢?在编译之前需要数组声明,因为编译器需要知道需要为每个变量留出多少内存空间。因此,当我们在开始声明数组大小时,我们不能在代码运行时改变数组大小。天真的解决方案是选择一个大的数组大小,但这将是低效的,浪费内存。
这就是动态内存分配的用武之地!首先,我们需要了解内存分配有两种类型,静态和动态。静态内存中的元素被分配到堆栈中,这样声明的变量以各自的顺序连续存储。另一方面,动态内存中的元素在堆中分配。与堆栈不同,在堆中,你不知道内存被分配到了哪里,对于你的每个请求,一个随机选择的内存块将被分配来存储这个值。
幸运的是,在 C 中,它们为动态内存分配提供了最有用的函数, malloc()。下面是这个函数的语法。
void *malloc (size_t size)
该函数为所请求的变量/结构保留所需字节的大小,并返回堆中分配的地址。如果请求的内存大小不可用,该函数将返回 NULL。还有其他一些支持动态内存分配的函数,即**【calloc()】和【realloc()】,但我们不会深入讨论这些函数。
链表的结构
链表是一种基于动态内存分配的数据结构。基本上,链表是由节点和链接组成的。我们可以创建一个简单的结构,由一个存储值的容器和指向下一个节点的指针组成。
在 ListNode 结构中, int item 被声明为存储节点中的值,而 struct _listnode next 被声明为存储下一个节点的地址。如果是最后一个节点,那么下一个的将指向空。*

不错!现在,我们可以通过第一个节点跟踪第二个节点,也可以通过第二个节点跟踪第三个节点。但是我们如何跟踪第一个节点呢?没有第一个节点的地址,第二个和第三个节点将无法访问。因此,我们将引入头指针。头指针不是节点,而是存储第一个绿色块的地址的指针,该绿色块是第一个节点。

链接列表示例
我们最终定义了链表的结构以及它是如何工作的。现在,让我们开始编码部分。我将通过一个简单的代码来指导你。
下面是执行代码后链表的结果。

从代码中可以看出,链表很大程度上依赖于 malloc() 函数来为新节点动态分配一些内存。我们需要使用临时变量的原因是,我们不想改变头指针中存储的地址。随后,在这段代码执行之后,头指针将仍然指向第一个节点,而临时指针将指向最后一个节点。
Python 中的链表
另外:链表也可以用其他编程语言创建,比如 Python、Java 等等。虽然 Python 没有指针或结构,但类可以帮助 Python 程序员制作链表。
我们可以创建两个类。第一个是 ListNode 类,用于存储值和下一个指针。第二个是 LinkedList 类,它的用法类似于 c 中的头指针。
最后的话
链表是计算机科学中最重要的数据结构之一。它是创建堆栈和队列等其他数据结构的基础。链表的结构也不限于简单链表(我们在本文中讨论的那个)。还有更复杂的链表类型,包括双向链表和循环链表,以适应相应的需要。
开始学习不同的数据结构,帮助你选择正确的数据结构(甚至是它们的组合!)来解决一个特定的问题。
问候,
胡安·塞缪尔·潘嗣敬
揭秘合并排序
排序算法指南
升级你的排序游戏!
以前,我写过关于快速排序的文章。如果你没有读过,你可以先浏览一下。合并排序是另一种有效的排序算法技术。

由 Unsplash 上的 Max Panamá 拍摄的图片
到目前为止,我们已经介绍了 4 种排序算法,在您阅读本文之后,总数将达到 5!那么,你还在等什么?敬请期待,继续看完这篇文章。
什么是合并排序?
合并排序是计算机科学中分而治之策略的经典例子。Merge Sort 得名于在这种排序技术中执行的合并操作。
基本上,合并排序操作中发生的事情是多次将原始数组分成两半,直到所有子数组都由一个元素组成。之后,将元素重新组合成一个排序后的数组。在合并排序的实现中,我们还将应用递归函数。
它是如何工作的?
下面列出了实现合并排序的步骤:
- 递归地执行步骤 2、3 和 4。
- 取原始数组,将数组分成 2 个长度相等的子数组。
- 对两个子数组进行排序
- 通过将排序后的数组合并成一个排序后的数组,将元素组合回数组中。
合并排序示例
像往常一样,我将从为您提供伪代码开始。
合并排序伪代码
现在,我们将转向 Python、C 和 JavaScript 的实现。
Python 中的合并排序代码
C #中的合并排序代码
JavaScript 中的合并排序代码
归并排序的时间复杂度
在合并排序中,最好的情况/最坏的情况/平均的情况总是均衡的。每个分区大小相等,每个分区有 n/2 个元素。然后,每个大小为 n/2 的子问题递归地排序两个大小为 n/4 的子阵列。如此继续下去,直到每个子阵列只有一个元素。这种情况导致时间复杂度为 O(n log n)。
最后的话
合并排序是最强大的排序算法之一。除此之外,归并排序也被广泛使用。此外,对于广泛使用的分而治之技术,合并排序是一个很好的案例研究。合并排序将帮助您拾起基础知识,并帮助您彻底了解计算机科学基础。合并排序的缺点是它不像其他排序算法那样节省空间。归并排序的空间复杂度为 O(n + log n),n 代表辅助数组,log n 代表堆栈空间。
学习排序算法将帮助你理解计算机科学的重要基础。
"永远不要把学习当作一种责任,而是当作令人羡慕的学习机会."——阿尔伯特·爱因斯坦
今天就开始学习吧!
问候,
弧度克里斯诺
揭开 ML 的神秘面纱—第 1 部分:基本术语和线性回归

作者图片
机器学习是人工智能(AI)的一种应用,它为系统提供了自动学习和根据经验进行改进的能力,而无需显式编程。
基于上面提到的定义来定义机器学习很容易,但它提出了进一步的问题,如“它是如何完成的?”、‘ML 的各个子域是什么?’、‘各种算法是什么?’,‘我需要懂数学吗?’、‘各种工业应用是什么?’等。此外,在过去几年的行业工作中,我已经意识到,作为应用科学家,我们主要关注 ML 的现有概念和应用级知识,以及其他技能,如解决问题、项目管理、软件工程等,以使其成为现实。因此,对我们许多人来说,核心 ML 概念仍然是一个黑箱。
就我个人而言,通过在计算机视觉、NLP 和结构化数据等领域使用不同算法的各种实验,我已经培养了强大的直觉和信心来实现 ML 的具体目标,但我并不总是能够理解核心概念,因为我不像核心研究人员那样积极解决算法进步。
为了解决我的这个问题,我开始了这个博客系列,以与核心学习保持一致,并分享一页纸的各种 ML/ DL 算法的流程图,如下图所示的线性回归。希望这也能对面临和我类似问题的专业人士有所帮助:)
我相信,从应用的角度来看,将这些算法作为流程图和一页视图中的各种直觉来研究(每次我们在项目中应用这些概念时都可以查看)会更有影响力。

图片作者| 线性回归的单页视图示例
在我开始分享这些核心知识之前,理解将在各种算法中使用的基本概念和术语很重要—
- 变量:一个训练样本的单个观察单位或数据点称为变量。表格数据可能包含分类/数量/顺序变量。对于单个训练图像,变量可以是对应于图像矩阵中特定位置的像素值。它可以是在一个时间序列的特定时间范围内记录的观察结果。
- 目标变量:您希望加深理解的数据集的变量或特征。它可以是针对多个概念的训练样本的注释,如“具有猫和狗的图像的标签”或“表示对象价格的表格中的行的标签”等。
- 方程:每个方程代表数据集中变量和目标变量之间的映射。右侧代表独立输入变量,左侧代表目标变量。机器学习只不过是为这些精确代表整个数据集的方程识别系数。简单线性回归使用传统的斜率截距形式,如下所示,其中“m”和“b”是我们的算法将尝试“学习”的变量,以产生最准确的预测。‘x’代表我们的输入数据,‘y’代表我们的预测。
y = mx + b (Simple regression)
f(x,y,z) = w1x1 + w2x2 + ... + wNxN (Multivariable regression)
- 正向传递:模型训练过程中处理为每个训练样本计算‘y’(或预测输出)的步骤称为正向传递。如果是第一次迭代,则选择随机(或 0)系数,否则使用最后一次迭代的系数。这些系数随着每次迭代而优化,以实现更接近目标变量的“y”。
- 损失/成本函数:它只是帮助我们了解每次迭代的预测值&和实际值之间的 差异。用于在训练阶段以单个实数的形式量化这种损失的函数被称为“损失函数”,它帮助我们达到方程的最优解。损失函数指的是单个训练样本的误差,而成本函数指的是整个训练数据集中损失函数的平均值。
- 反向传播:从技术上讲,反向传播计算每个系数的损失函数的梯度,这有助于更新每个系数,以便在下一次迭代中,这些更接近于最优解,从而进一步减少损失。
- 梯度下降:梯度下降是优化算法,用于更新方程的系数(或参数)。它用于通过沿梯度负值定义的最陡下降方向迭代移动来最小化成本/损失函数。我们迭代地继续这个过程,直到我们到达全局最小值。

- 学习率:在每次迭代中向损失函数的最小值移动时,每步的大小。在高学习率或大步长的情况下,存在错过损失函数的最小值的风险,而在非常低的学习率下,存在陷入局部最小值的风险,并且模型训练也可能是耗时的。
- 训练迭代:将正向传递- >损失计算- >反向传播(更新权重)的每一步称为一次训练迭代。为了建立一个基于训练数据进行归纳的模型,我们应该避免大量的训练迭代,并在模型开始过度拟合时使用早期停止等技术来停止模型。
- 权重和模型:权重是在所有训练迭代之后计算的等式的所有系数的。就深度学习而言,它是为神经网络的每一层计算的模型的所有参数(或权重矩阵)。完整的算法方程被称为模型,其系数是在基于训练数据集最小化损失的同时计算的。
下一个系列—第 2 部分:M 中的线性分类器(即将推出…)
我希望这有助于应用 ML 知识的读者理清一些核心概念。感谢 Anit Bhandari 通过对 ML 概念的核心理解为 upskill 提供了方向性的意见。
参考资料:
https://ml-cheatsheet.readthedocs.io/en/latest/linear_regression.html https://medium.com/analytics-vidhya/the-pitfalls-of-linear-regression-and-how-to-avoid-them-b93626e1a020 https://github.com/leventbass/linear_regression/blob/master/Linear_Regression.ipynb
揭开神经网络的神秘面纱
用 Python 和 NumPy 从头开始实现

杰斯温·托马斯在 Unsplash 上的照片
就像生活中的许多事情一样,学习的最好方法是自己动手。我自学了神经网络,我认为对理解它们的内部工作最有帮助的是从头开始构建一个。事实上,可以手动导出所有公式,并用基本的 Python 库实现它们。
让我们看看逻辑回归是如何工作的,这是神经网络的一个非常简单的例子。我将把数学保持在最低限度——我认为有时看代码更容易——但是你仍然需要熟悉矩阵代数和导数。
所有机器学习模型都学习如何将输入映射到输出。在深度学习中,“学习”是通过一系列变换或层来完成的,每个变换都由该层的权重来定义。下图说明了简单网络的工作原理。
最初,随机实现权重,并通过网络的隐藏层( 【正向传播】 )传播到最终层、输出层或预测。然而,此时的转换是没有意义的,结果可能还很遥远。该网络实现了一个损失函数,该函数测量输出与地面实况的距离,并将该值反馈给各层以调整权重值,从而减少损失。在每一次迭代中,模型学习更多,更接近最优值。这个过程称为 反向传播 ,由优化器实现。

神经网络图
当然,上图非常简单,现实世界的应用程序可能会非常复杂。尽管如此,它们的构造块都是一样的。
从零开始的逻辑回归
逻辑回归是一个浅层神经网络。它只有一个输入层和一个输出层,没有隐藏层。然而,这是开始理解神经网络内部工作的一个非常好的地方,并且从头实现起来相当容易。
首先,让我们为二元分类器创建一些人工数据。
X 的形状为(100,2)y的形状为(100,1)。数据如下图所示。

现在让我们来实现网络的构建模块:前向传播和反向传播。
正向传播
让我们随机初始化用于正向传播的权重矩阵 W。在本例中,输出层需要具有与y(100,1)相同的尺寸。由于没有隐藏层,所以输出层只是 X 和 W 的点积。根据矩阵积的规则,权重矩阵 W 需要具有维度(1,2),使得(100,2) x (2,1) = (100,1)。然而,为了便于计算,我们用 shape (1,2)定义 W,并进行转置。
分类器的输出需要限制在 0 和 1 之间,因此我们还需要一个 激活函数 应用于输出层。对于逻辑回归,激活函数就是简单的逻辑(或 sigmoid )函数。输出激活是我们的预测。
让我们想象一下决策边界。背景颜色指的是未训练分类器的分类决策。由于权重仍然是随机的,我们还没有优化它们,我们预计分类器在这一点上相当糟糕。事实上,它不能正确区分积极的阶级和消极的阶级。

我们现在需要优化权重。在我们进入反向传播之前,让我们先谈谈我们将使用的优化器,梯度下降。
梯度下降
GD 基于一个 梯度 的概念,可以看作是导数对多维输入的概括。如果一个函数是可微的,即它的导数存在,那么就有可能找到它的最小值,也就是导数等于零的点。
函数的导数给出了它在任意给定点的斜率。如果当权重向某个方向移动(增加或减少)时损失减少,导数将返回负值。梯度下降算法在负梯度方向(沿着损失函数向下)更新参数。然后重复这个过程一定次数的迭代或直到收敛。
在数学术语中,这意味着求解 N 个参数的多项式方程(其中 N 是网络中权重的总数),以找到使损失最小化的参数组合。
请注意,在真实情况下,N 很容易以百万计,而求解这样的方程是不可能的。这就是为什么我们通常实现批量梯度下降,即随机抽取一批训练数据,并只计算这一批的梯度。
幸运的是,我们不必在简单的逻辑回归中这样做,因此,为了简单起见,我们将实现常规梯度下降,而不是批量下降。
反向传播
我们将在反向传播中实现的主要步骤如下:
1.计算激活层(预测)和地面真实之间的损失
2.计算梯度
3.更新权重。
为了计算损失,我们首先需要定义它。在二进制分类问题中,通常使用二进制交叉熵(或对数损失),所以我们将使用它。
梯度 是损失函数相对于每个权重的导数(偏导数)。可以证明交叉熵函数 w.r.t. W 的导数为(y _ hat y)X,其中 y_hat=sigmoid(z)。我们不打算在本文中演示它,但是这里有一个很好的解释。
一旦我们有了梯度,我们就可以更新权重。对于这一步,我们需要定义步或学习率。它决定了模型学习的速度,并调整 GD 的步长。
我们还需要为算法收敛定义一定的迭代次数。在我们的例子中,15 次迭代足以使算法收敛。随着我们越来越接近最佳值,损耗将减少,梯度的步长变得更小。
拼凑一切
我们现在可以把所有的部分放在一起,运行模型。
我们可以想象梯度下降在每次迭代中的表现。从下图中,我们可以看到模型如何在接近最小损失时采取越来越小的步骤。

我们再来看看决策边界。现在权重已经过优化,分类器的性能也有了很大提高。仍然有一些错误分类的点,但总的来说,分类器在分离这两个类别方面做得很好。

训练分类器的决策边界
完整的代码可在这里获得。
在下一篇文章中,我们将通过给模型添加一个隐藏层来增加复杂性。请在评论中告诉我你的想法!
揭开神经网络的神秘面纱第二部分
用 Python 和 NumPy 实现 NN 中的隐藏层

哈桑·阿尔马西在 Unsplash 上的照片
在以前的一篇文章中,我们从零开始构建了一个逻辑回归作为浅层神经网络的例子。现在让我们增加一点复杂性,增加一个隐藏层。即使数学变得稍微复杂一些(我希望你喜欢导数!),我们仍然可以只用 Python 和 NumPy 来编码整个网络。
逻辑回归在数据是线性可分的情况下工作得很好,但我们可以看到,当它不再是线性可分时,它就不好用了。作为一个例子,让我们再次使用 scikit-learn 来生成一些数据。

作者图片
显然,没有一条直线会完全符合上述数据,我们预计逻辑回归在这种情况下表现不佳。让我们将前一篇文章中编写的逻辑模型应用到这些数据中。
正如我们从决策边界看到的,相当多的点被模型错误分类。很明显,我们需要一个能够提出非线性决策边界的模型。

作者图片
1-隐层神经网络
让我们添加一个隐藏层到我们的网络。
我们现在有一个输入层,一个隐藏层和一个输出层。我们将使用 sigmoid 作为输出和隐藏层的激活函数,交叉熵作为损失,就像我们对逻辑回归所做的一样。然后,我们可以重新使用上面为 sigmoid 和交叉熵定义的函数。
正如我们对 LR 所做的那样,让我们实现神经网络的构建模块:前向传播和反向传播。
正向传播
这一步与逻辑回归示例非常相似,除了我们有两个权重矩阵——一个用于隐藏层,一个用于输出层。对于这个特殊的例子,我在每一层的重量旁边添加了预期的尺寸。我认为这有助于确定它们应该是什么样的。
反向传播
我们可以重用上一节的代码,但是在梯度计算上有一些显著的不同。损失(交叉熵)相对于权重的偏导数根据层具有不同的函数形式,因此我们需要两个不同的梯度函数。
输出层的梯度与我们为逻辑回归定义的梯度相同(完整的推导见。
交叉熵相对于 Wₕ的梯度可以使用 δ规则获得。如果 l 为输出层,δₗ=σ(z)y。可以证明(此处见推导)δₗ₋₁=δₕ=((wₗ₋₁)ᵗδₗ)σ’(zₗ₋₁),其中为元素间乘积。然后梯度是点积δᵗ ₗ ₋₁⋅ x 。注意,σ′(zₗ₋₁)=σ(zₗ₋₁)(1−σ(zₗ₋₁))但是,根据定义,σ( zₗ ₋₁)是隐藏层激活á͂。因此σ′(zₗ₋₁)=aₗ₋₁(1−aₗ₋₁).
我们现在可以像往常一样实现梯度。唯一的区别是我们必须更新输出和隐藏层的权重。
请注意, δ规则即使在我们添加多个层时也能很好地工作,并且可以很容易地用一个循环进行编码:在每一层 n ,我们只需要给定层的激活和权重——我们已经有了——为层 n+1 和 n+1 激活计算的δ。
让我们看看它是如何工作的。通用层的导数l-n,其中n∈【1,..,N],就是σ’(zₗ₋ₙ)=aₗ₋ₙ**(1aₗ₋ₙ),其中 aₗ₋ₙ 是该层的激活。δ ₗ₋ₙ 是上面的导数和(wₗ₋ₙ)ᵗδₗ₋ₙ₊₁.)的元素乘积 wₗ ₋ₙ是层l—n*的权重,而δ ₗ ₋ₙ₊₁是在前一轮计算的 δ (记住,在反向传播中,顺序相反,层 n+1 在层 n 之前)。最后,我们使用来自 n+1 层的激活,而不是仅用于输出层的 X。
把一切拼凑在一起
让我们把所有的东西放在一起。
让我们比较一下这两种型号的损耗。1 隐层神经网络实现了比 LR 更小的损失。
Logistic Regression Min Loss: 0.28
1-Hidden Layer NN Min Loss: 0.18
想象结果
我们需要为我们的模型定义一个预测函数,以便以后使用它。
我们再来看看决策边界。我们的 1-隐层分类器的性能比逻辑回归好得多。非线性判定边界能够正确地分类所有红点。仍然有一些错误分类的蓝点,但总的来说,分类器在分离这两个类别方面做得很好。

作者图片
完整的代码可在这里获得。请在评论中告诉我你的想法!
揭开 Python 多重处理和多线程的神秘面纱
…和全局解释器锁

TLDR :如果你的程序是网络绑定的,你应该使用线程或者多处理如果是 CPU 绑定的。
就我个人而言,这些年来我多次试图理解多重处理和多线程,但总是无法完全理解这些概念。为此,我们需要理解几个重要的术语以及 Python 编程语言特有的东西——全局解释器锁(GIL)。
如果您已经知道这些术语,请随意跳到下一节。
术语
核心:CPU 的处理器。这个术语指的是 CPU 的硬件组件。核心可以处理单个任务;多核处理器可以同时执行多项任务。
线程:管理任务的虚拟组件。如果您的 CPU 启用了多线程/超线程,每个 CPU 内核最多可以有两个线程。您可以搜索自己的 CPU 处理器来了解更多信息。对于 Mac 用户,可以从了解关于>系统报告。这意味着我的 6 核 i7 处理器有 6 个内核,最多可以有 12 个线程。

作者图片
我们可以使用htop(见下图 GIF)来重新确认我的机器拥有的线程数量,从 0 到 11。

进程:由一个或多个线程执行的计算机程序的实例。根据操作系统的不同,一个进程可能由多个执行线程组成,这些线程同时执行指令[1][2]。
多线程:中央处理器(CPU)(或多核处理器中的单核)提供多个线程并发执行的能力,由操作系统支持[3]。
多重处理:在一个计算机系统中使用两个或多个 CPU[4][5]。该术语也指系统支持一个以上处理器的能力或在它们之间分配任务的能力。
什么是全局解释器锁(GIL)?
如果我们用谷歌搜索“什么是 Python 中的全局解释器锁”,我们得到的答案是这样的:
Python 全局解释器锁(GIL)是一种进程锁,每当 python 处理进程时都会使用它。一般来说,Python 只使用一个线程来执行这组写好的语句。这意味着在 python 中一次只能执行一个线程。
通过在每次运行一个 Python 进程时只允许使用一个线程,这确保了一次只有一个线程可以访问一个特定的资源,并且还防止了同时使用对象和字节码。
多线程操作
GIL 和多线程有什么关系?没什么,但它有助于我们理解何时使用多线程。让我们看一个例子。
作者 Github 要点
如果我们看一下上面的函数,变量final在range(100_000_000)上被求和。在我的机器上执行这个需要大约 7.88 秒——现在,你认为多线程会加速这个操作吗?
作者 Github 要点
如果你猜的是“不”,那你就对了!使用 8 个线程的ThreadPoolExecutor,我们注意到这并没有加速进程!为什么会这样,引擎盖下发生了什么?
即使我们指定使用 8 个线程,也没有加速这个过程。以下是事情经过的详细分析:
- python 解释器创建一个新的进程并产生线程
- 线程 1 开始运行,获取 GIL
- 线程 2 到 8 想要协助线程 1,但是必须等待线程 1 释放 GIL,然后其他线程才能处理它
- 由于没有 I/O 操作,线程 1 将继续处理整个
sum_square(100_000_000)操作
为什么需要 GIL?
在上面的例子中,我们在每次迭代中不断更新final变量。如果多个线程能够同时访问该代码的执行,则由每个线程检索和修改的i的值可以在其他线程访问它时发生变化。那么,i和final在任一时间点的真实值是什么呢?这是一个程序不希望的状态,称为竞争条件。
那么,什么时候应该使用多线程呢?
正如我们在前面的sum_square中看到的,一个 100%计算密集型任务无法利用多线程,因为一次只能使用一个线程(由于 GIL)。如果我们执行一个很大程度上受 I/O 限制的任务,我们就可以利用多线程。这里有一个我们试图从网上下载图片的例子:
作者 Github 要点

单线程性能—作者 GIF
使用一个仅由 80 个图片 URL 组成的demo_urls.txt,这个过程总共花费了 6.71 秒。此外,请注意,其他核心/线程没有启动(保持 0%的利用率)。让我们用多线程做同样的事情。
作者 Github 要点

多线程性能—作者 GIF
同样是 80 个图片网址,使用多线程在 1.38 秒内完成了整个过程。请注意,所有 12 个线程(从 0 到 11)都被利用了(非零)。
多重处理
如果我们使用ProcessPoolExecutor(即多进程)运行上述相同的进程,您认为速度会大于还是小于 1.38 秒?
作者 Github 要点
如果你猜大于 1.38 秒,你就对了!由于download_image功能主要由 I/O 操作组成,我们在等待这些操作完成时,大大节省了时间。

多进程性能—作者 GIF
尽管如此,多重处理仍然允许我们在 3.34 秒内相当快地下载 80 张图片,尽管这更加占用内存。这是因为 Python 多处理在进程间传递对象时使用 pickle 来序列化对象,要求每个进程创建自己的数据副本,这增加了大量的内存使用,更不用说昂贵的反序列化了。
关键要点
- Python 不是单线程语言。
- 由于 GIL,Python 进程通常使用单线程。
- 尽管有 GIL,但执行计算繁重任务的库,如 numpy、scipy 和 pytorch 利用基于 C 的实现,允许使用多个内核。
- 根据经验,大部分 I/O 受限的进程受益于多线程,而计算量大的任务受益于多处理。
最后的想法
感谢您的阅读,如果您发现任何错误,一定要让我知道!
支持我! —如果你喜欢我的内容并且没有订阅 Medium,请考虑支持我并通过我在这里的推荐链接订阅 ( 注意:你的一部分会员费将作为推荐费分摊给我)。
参考
[1] 亚伯拉罕·西尔伯沙茨;格雷格·卡涅;高尔文,彼得·贝尔(2004)。“第四章。流程”。操作系统概念与 Java* (第六版。).约翰·威利&儿子们。国际标准书号 0–471–48905–0*
[2]瓦哈里亚,乌雷什(1996 年)。“第二章。过程和内核”。 UNIX 内部:新前沿 。普伦蒂斯-霍尔公司国际标准书号0–13–101908–2。
[3] 多线程(计算机体系结构)
[4]拉杰·拉贾戈帕尔(1999 年)。 微软 Windows NT 集群服务器简介:编程与管理 。CRC 出版社。第 4 页。国际标准书号978–1–4200–7548–9
[5]迈克·埃伯斯;约翰·凯特纳;韦恩·奥布莱恩;比尔·奥格登(2012)。 新主机介绍:z/OS 基础知识 。IBM。第 96 页。国际标准书号978–0–7384–3534–3
[6] Youtube: Python 不是单线程的(以及如何绕过 GIL)
揭秘快速排序
排序算法指南
升级你的排序游戏!
在前 3 篇文章中,我们讨论了冒泡排序、选择排序和插入排序。在一般情况下,所有这些算法的时间复杂度都是 O(n)。剧透警报!这是第一个在一般情况下运行得比 O(n)更好的排序算法。

我们走吧!当我们开始深入研究更高级的算法时,我激动不已。这些概念一开始可能不会被理解,即使如此,继续尝试,我保证你会在几次尝试后理解它。
什么是快速排序
快速排序,也称为分区交换排序,是现有的最快的排序算法之一,也是大多数排序库中常用的方法。这种排序方法在其他方法中表现最好,因此被命名为快速排序。该算法基于分治策略。
在快速排序中,从称为轴心的数组中选择一个元素。下一步是将阵列分成两个子阵列。这样做是为了使小于轴心的所有元素位于数组的左侧,而较大的元素位于右侧。在这个循环之后,pivot 元素位于数组中的固定(最终)位置。之后,我们对每个子数组递归地执行这个过程。为了简单起见,我们将每个子数组的第一个元素作为支点。
它是如何工作的?
- 选择第一个元素作为轴心。
- 对数组进行分区,使所有较小的元素位于数组的左边,较大的元素位于右边。
- 递归地执行步骤 1 和 2,直到数组排序完毕。
有许多分区操作可用,最流行的两个是 Hoare 分区方案和 Lomuto 分区方案。Hoare 划分方案比 Lomuto 划分方案更有效。这就是为什么我们将在快速排序算法中应用霍尔划分方案。
快速排序示例
像往常一样,我们将首先从伪代码开始。
快速排序伪代码
现在我们将看看 Python、C 和 JavaScript 中的算法代码。
Python 中的快速排序代码
C 语言中的快速排序代码
JavaScript 中的快速排序代码
快速排序的时间复杂度
快速排序最佳情况时间复杂度发生在分区均匀平衡时(主元固定位置在子数组的中间)。在这种情况下,最佳时间复杂度为 O(n log n)。最坏的情况是,当数组已经排序,或者轴心总是最小或最大的元素时,就会发生这种情况。快速排序将以 O(n)时间复杂度运行,与我们之前学习的其他排序算法相当。好消息是快速排序的平均时间复杂度也是 O(n log n)。一般情况下,枢轴位于数组中的 1/4 或 3/4 位置。
临别赠言
在我们的实现中,选择最左边的元素作为枢纽,当数组已经排序时,时间复杂度为 O(n)。幸运的是,这个问题可以很容易地通过选择一个随机索引作为轴心或者选择中间索引作为轴心来克服。那么最坏的情况下时间复杂度会变成 O(n log n)。
记住,在编程中,总有你可以改进的地方。你应该从批判性地思考我们如何做出必要的改进开始,这值得我们花时间吗?对于快速排序的情况,这确实是值得的,我们只需要采取中间位置而不是第一个位置,这可以显著提高我们算法的效率。
“你总能改善你的处境。但你要面对它,而不是逃避。”—布拉德·华纳
让我们一起提高编程的技巧吧!
问候,
弧度克里斯诺
每个镇议会的登革热病例
2020 年 7 月和 12 月新加坡的登革热病例

Unsplash 上 Elliott Stallion 的照片| Unsplash 上егоркамелев的照片
背景
新加坡的民选议员有责任通过主持由其选区组成的市议会来管理市政事务(1988 年《市议会法》)。为了居民的利益,新加坡市议会对住宅和商业物业的共同财产负责,并确保这些物业处于最佳状态(国家发展部,2020 年)。这包括维护小区卫生。
新加坡最近一次大选是在 2020 年 7 月 10 日。在 30 天内,必须成立一个镇议会(1988 年镇议会法)。因此,截至 2020 年 7 月 30 日,以下 17 个镇议会根据其各自的选区组成(镇议会(宣布)令,2020 年),这些选区包括团体代表选区和单一成员选区:
- 阿琼尼-后港:阿琼尼 GRC 和后港 SMC
- Ang Mo Kio: Ang Mo Kio GRC、Kebun 巴鲁 SMC 和 Yio Chu Kang SMC
- 璧山-大巴窑:璧山-大巴窑 GRC 和玛丽蒙特 SMC
- 蔡珠康:蔡珠康 GRC,和洪家北 SMC
- 东海岸:东海岸 GRC
- Holland-Bukit Panjang:Holland-Bukit Timah GRC 和 Bukit Panjang SMC
- 贝萨尔街:贝萨尔街 GRC 和 Potong Pasir SMC
- 裕廊-克莱门蒂:裕廊 GRC、武吉巴托克 SMC 和裕华 SMC
- 海上游行:海上游行 GRC,麦克弗森 SMC,蒙巴顿 SMC
- 马息林红豆杉球座:马息林红豆杉球座 GRC
- 需要很快:需要很快
- Pasir Ris-pung gol:Pasir Ris-pung gol GRC 和 Punggol West SMC
- 三巴旺
- 僧康:僧康 GRC
- 坦帕因斯:坦帕因斯 GRC
- 丹戎巴葛:丹戎巴葛 GRC 和 Radin Mas SMC
- 西海岸:西海岸 GRC 和先锋 SMC
巧合的是,2020 年 7 月有一个高峰,有 1792 例登革热病例(亚洲新闻频道,2020)。

截至流行病学第 51 周,2017 年至 2020 年的登革热病例数(国家环境署,2021 年)
从那时起,在过去的 6 个月里,登革热病例数量急剧线性下降,到 2020 年 12 月接近 200 例。
在这次活动中,我有兴趣了解自 2020 年新加坡大选以来新成立的哪些镇议会在 2020 年的最后六个月成功战胜了登革热病例。
使用的数据
- 来自 Data.gov.sg的两个登革热集群数据集:分别更新于 2020 年 7 月 23 日的和 2020 年 12 月 30 日的
- 大选 2020 选举地图来自谷歌我的地图****
整理和转换
QGIS 用于进行预处理,这包括根据 Google My Map 的选举地图创建显示市议会分区的地图。

2020 新加坡大选行政区划选举地图(来源:谷歌我的地图)

使用 QGIS 创建新加坡市议会地图,图片由作者提供
此外,还根据 2020 年 7 月和 2020 年 12 月每个镇议会的每个登革热集群汇编了登革热病例数。

前 19 行分别显示了 2020 年 7 月和 2020 年 12 月每个镇议会的登革热病例数(基于每个登革热集群),图片由作者提供
形象化
通过使用 Tableau ,构建了以下三个图表:
- 显示登革热病例在市议会各部门分布的 Choropleth 地图。
- 条形图分别显示了 2020 年 7 月和 2020 年 12 月每个镇议会的登革热病例数,可以进行过滤。
- 与生成的条形图类似,创建了另一个条形图来比较每个镇议会两个月的登革热病例数。这是为了让用户看一看哪个镇议会为战胜登革热病例付出了努力。

Choropleth 地图和条形图的仪表板显示了 2020 年 7 月镇议会的登革热病例数,图片由作者提供
从 choropleth 地图来看,与 2020 年 7 月的其他地区相比,登革热病例的高发区集中在新加坡的东南部地区(即海洋游行镇委员会和贝萨尔镇委员会)。
从柱状图来看,登革热病例数量最多的前 3 个镇议会是:
- 海军游行镇议会
- 贝萨尔镇议会路
- 阿尔朱尼德-后港镇议会
丹戎巴葛镇议会和昂莫乔镇议会的登革热病例数量相似。

Choropleth 地图和条形图的仪表板显示了 2020 年 12 月镇议会的登革热病例数,图片由作者提供
从 choropleth 地图来看,整个新加坡的登革热病例不太集中,2020 年 12 月,新加坡的北部地区(即 Nee Soon 镇议会、 Pasir Ris-Punggol 和森巴旺镇议会)的登革热病例为零。
然而,即使在 2020 年 12 月,前面提到的三个镇议会仍然是登革热病例高发的前三个镇议会。****

2020 年 7 月和 2020 年 12 月各镇议会登革热病例数对比柱状图,图片作者
从对比柱状图中可以推断出海上游行镇议会确实在抗击登革热方面投入了巨大的努力,将的数量从 2020 年 7 月的 3294 只减少到 2020 年 12 月的 145 只** (~ 95.6% )。**
让我们检查一下贝萨尔镇议会和阿尔朱尼德-后港镇议会。在 Jalan Besar 镇委员会的登革热病例数量已经从 2020 年 7 月的1906 例下降到 2020 年 12 月的 127 例(~93.3%),而在阿茹尼达-后港镇委员会的登革热病例数量已经从 2020 年 7 月的1430 例下降到 2020 年 12 月的(~在两个亚军之间,贝萨尔镇议会在战胜登革热方面的表现优于阿尔朱尼德-后港镇议会。
让我们比较一下 Ang Mo Kio 镇议会和 Tanjong Pagar 镇议会,这两个地方在 2020 年 7 月和 12 月的登革热病例数相似。昂莫乔镇委员会的登革热病例数从 2020 年 7 月的 812 例下降到 2020 年 12 月的 27 例,丹戎巴葛镇委员会的登革热病例数从 2020 年 7 月的 854 例下降到 2020 年 12 月的 22 例这表明丹戎巴葛镇议会在战胜登革热方面比昂莫桥镇议会做得更好,因为两个月的登革热病例数量相似。
最后,西海岸市议会的病例数似乎没有相对变化,2020 年 7 月有 70 例登革热病例,2020 年 12 月有 65 例登革热病例。镇议会可能需要加强努力,了解登革热的严重性,以防止未来登革热在该地区的传播。
推荐
由于 Marine Parade 镇议会、Jalan Besar 镇议会和 Aljunied-Hougang 镇议会有大量登革热热点,这些镇议会可以与国家环境局(NEA)合作向其居民宣传登革热的严重性以对抗登革热传播。这包括社交媒体广告,如 Instagram 广告,通过利用地理围栏瞄准镇议会周围的人。
此外,这些镇议会可以增加熏蒸的使用来消灭蚊子。
最后,NEA 可以启动沃尔巴克氏体项目,将这些镇议会作为减少登革热蚊子数量的首要任务(国家环境署,2020 年),然后是其他镇议会。
限制
来自 Data.gov.sg 的登革热群集数据集经常更新。因此,一旦用户获得了数据集,他/她就拥有了登革热聚类的最新数据集,而无法访问同一数据集的历史数据。这是因为数据集是基于最新的流行病学周。因此,如果我有更多的历史登革热集群数据集,以便在不同时期和不同镇议会之间进行更多的比较,那就太好了。
坦率地说,我已经在那个月下载了 2020 年 7 月的登革热集群数据集,因为我打算开始这项练习。然而,在此期间,由于选举刚刚结束,一些市议会尚未正式成立。因此,它当时不会带来价值。
未来的工作
尽管新加坡是世界上犯罪率较低的最安全的国家之一(经济发展委员会,2020 年),但这项工作可以用于确定每个镇议会发现的犯罪数量。此后,各自的市议会可以找到打击这种特定类型犯罪的方法。这包括与新加坡警方合作,向居民宣传打击犯罪的方法。
关于这项工作,分析这些地区的人口统计数据,如人口的年龄组以及人口密度,将有助于理解为什么这些地区会出现登革热热点。此外,该地区的房屋类型或设施也是分析中需要考虑的因素。
闭幕词
总而言之,预防胜于治疗。因此,在新的一年里,让我们团结起来,继续抗击登革热和另一个威胁——新冠肺炎!坚强点,新加坡!
参考
亚洲新闻频道。(2020).每周登革热病例降至“历史爆发年”最低水平,NEA 敦促继续保持警惕。十二月十八日。检索自https://www . channel news Asia . com/news/Singapore/dengue-cases-Singapore-lowest-weekly-count-2020-nea-13799726
经济发展委员会。(2020).居住的好地方。十二月十六。检索自https://www . EDB . gov . SG/en/why-Singapore/a-great-place-to-live . html。
国家发展部。(2020).关于市议会。7 月 30 日。检索自https://www . MND . gov . SG/our-work/regulating-town-councils/about-town-councils
国家环境署。(2021).登革热病例。1 月 6 日。从 https://www.nea.gov.sg/dengue-zika/dengue/dengue-cases取回
国家环境署。(2020).沃尔巴克氏体-伊蚊灭蚊策略。十二月十六日。检索自https://www . nea . gov . SG/corporate-functions/resources/research/Wolbachia-Aedes-mosquito-suppression-strategy
1988 年镇议会法案。(c.329A)。新加坡:新加坡总检察长办公室立法处。从 https://sso.agc.gov.sg/Act/TCA1988取回
第 2020 号城镇议会(宣布)令。新加坡:新加坡总检察长办公室立法处。从 https://sso.agc.gov.sg/SL/TCA1988-S641-2020?取回 DocDate=20200730#Sc1-
反规范化和烹饪:度量是使数据有用的方法
如果数据团队是组织中信息的“顶级厨师”,那么度量就是他们获得有价值的数据洞察力的“配方”。

摄影由 塞巴斯蒂安·科曼摄影 上 下
组织、建模和提供数据的最终目标是让数据对利益相关者有用。反规范化是使数据变得有用的关键,然而这个概念没有得到广泛的讨论,并且缺乏为构建干净和结构化的核心数据集而开发的深思熟虑的方法。
数据建模在过去十年中有了很大的改进——无论是在工具方面还是在方法的思想方面——我们都受益匪浅,但下一代数据工具将彻底改变反规范化的过程,那些了解这些趋势的人将是第一批受益者。
为了理解反规格化,我们首先需要定义规格化:
- 规范化是指组织数据,使其在所有记录和字段中看起来相似。规范化旨在减少冗余并确保数据仓库中的一致性。
标准化做得好的话,可以实现更广泛、更容易的数据消费。为了使用这些数据,数据使用者必须能够组合各种数据集并应用聚合。这个过程叫做反规范化。
- 反规范化是组合和综合来自各种来源的经过清理和组织的数据集的过程,这有助于使数据对分析有用。
规范化类似于组织准备烹饪的配料,而非规范化则是获取这些配料并准备一顿饭的过程。保持一个干净整洁的储藏室和冰箱可以让准备你最喜欢的食物的过程更加顺利和愉快。整理你的厨房是不够的。为了利用各种成分,你需要知道如何将它们组合起来。
数据分析师是厨师,通常能够即兴发挥他们的原料,而业务用户通常寻求一致可靠的结果,并希望遵循食谱。

规范化类似于组织食材准备烹饪,而非规范化则是获取这些食材并准备一顿饭的过程。照片由 凯蒂·史密斯 上 下
反规范化和规范化都很关键,在某种形式上,每个数据团队都这样做。虽然标准化在分析工程界定义明确并经常讨论,但在现代数据堆栈中几乎没有做什么来改进我们用来服务非标准化数据集的方法。结果是数据堆栈中的逻辑蔓延。
分析师大部分时间都在进行反规范化,公司的大部分业务逻辑都是在这个过程中定义的。大多数数据分析师都知道这些概念,尽管他们可能会使用核心数据集或数据集市这样的词来表示规范化数据集,使用汇总表或度量表来表示非规范化数据集。
规范化与反规范化:区别是什么?

作者图片
数据的价值并非来自整洁有序的存储。这是成功的必要条件,但是仅仅规范化并不能使数据变得有用。它通过反规范化变得有用,反规范化是将信息提取到数据集的过程,数据集将压缩的信息表示为可用于获得洞察力的数据点或指标。
同样,食物的价值不在于配料或我们组合这些配料的过程,而在于最终产品,即菜肴。反规格化是组合成分的过程,而连接、聚合和过滤器的排序和表达是实现期望的最终产品所需的配方。

反规范化是组合配料(烹饪)的过程,而连接、聚合和过滤是实现所需最终产品所需的配方……就像这道精美的餐厅菜肴。照片由 周杰伦https://unsplash.com/s/photos/plating-food?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText
在我们能够在实践层面上完全理解反规格化之前,我们需要深入一些关于规格化的细节。规范化数据被定义为在确保数据完整性的同时限制数据冗余的数据模型。举几个例子:
- 数据冗余(例): 当用户的地址同时存储在用户表和事务表中时。在规范化的数据集中,工程师将只在 users 表中存储用户的地址,并将 users 表连接到 transactions 表。
- 数据完整性(例): 当同一个字段以多种形式出现时——例如 US、USA、United States。在标准化的数据集中,工程师已经将所有这些不同的值更改为相同的值。
对于数据和分析工程师来说,深思熟虑的规范化过去是、现在仍然是一项非常重要的工作。每个应用程序背后都有一个数据库,甚至许多数据库,这些数据库必须组织在一个分析数据仓库中,以便为数据消费者提供最佳服务。
规范化有时被称为规范形式,与主数据管理的历史概念密切相关。这个概念在不同程度上来自于 1970 年作为第一范式(1NF)提出的简单定义,到今天相当常见的第三范式(3NF),以及更远,一直到不切实际的复杂的第六范式(6NF)。正常化是很好的管家。出于这个原因,在过去五十年中提出的一系列数据建模技术对数据团队近年来取得的进步起到了重要作用。
反规格化和冗余
数据堆栈中的几乎每个工具都会发生反规范化。在我们的 EL 任务中,在数据仓库中计划的批量转换作业中,通过编排工具,以及作为下游商业智能(BI)和分析工具中的查询。几乎每个使用数据的接口都要经历反规范化的过程。
在实践中,应用连接、聚合和过滤器的行为相对简单,但它们会对逻辑治理和可重用性产生显著的二级影响,或者说,实际上,会降低数据集的可重用性。挑战变成了再现性、一致性和数据发现。
这里是 我们在考虑组织应该如何应用反规范化的策略时应该考虑的几个重要因素:
- ****非规范化数据比规范化数据更容易查询:规范化数据查询起来既费钱又费时。由于数据从不重复,我们必须首先连接数据集来做任何有趣的事情。出于这个原因,我们在数据仓库和各种下游工具中创建、消费和管理大量非规范化数据集。
- ****反规格化无处不在:反规格化无处不在。向最终用户发布最常见的度量和维度对的简明摘要表是很常见的。这些非规范化数据集反映了最常见的问题,但是,为了更深入地挖掘,我们在分析或 BI 工具中聚合、过滤和连接数据集。许多问题最终需要返回到规范化的表,将新的原始数据集与这些汇总表合并,或者任何其他组合。任何使用数据的工具都会发生这种情况。
- ****非规范化数据集在大规模管理时可能会面临挑战:由于各种原因,管理从规范化数据集派生的数据是一件痛苦的事情。具有讽刺意味的是,其中一个最突出的原因是冗余——与规范化的预期好处相反。如果你曾经想知道为什么像 Airbnb 这样的组织在他们的数据仓库中有超过 10 万个表,那是因为有许多数据应用程序,每个应用程序都需要不同的连接、切片和骰子或公司核心规范化数据集的表示。在实践中,他们必须追求这些不同的派生数据集,以从数据中获得价值,并且他们必须付出管理冗余的代价。
- ****对非规范化数据的治理并非无足轻重:对于分析来说,可能有许多令人感兴趣的数据组合,但我们只能预计算这么多可能的组合。尽管需要纪律和资源来确保准确性,但其中一些查询值得持续维护和更新。不幸的是,随着时间的推移,这些衍生数据集被遗忘并成为一种负担,其中的指标定义逐渐偏离了当前的时代精神。如果没有适当的上下文,并且没有意识到这些数据集的质量问题,分析人员以后会使用这些数据集,而结果将是可疑的。这导致了对数据的普遍不信任。
- ****非规范化数据很难或不可能重新调整用途:聚合是信息压缩,过滤器只是数据移除。因此,从非规范化的数据集回到它们更有用的规范化形式或许多其他相关的数据集几乎是不可行的。就其本身而言,这不成问题。如果非规范化数据集正在创造价值,那很好。挑战来自于非规范化数据集的数量,这些数据集需要支持一系列旨在获取数据并将其转化为见解的问题和答案。
度量和反规范化:它们是如何联系的?
指标的核心是将这些规范化的数据集组合成一组有意义且易于理解的值或时间序列的公式。在我们的食品类比中,指标是获取各种成分并创造有价值的东西的配方。虽然你可以用部分重叠的配料做意大利调味饭或西班牙肉菜饭,但如果他们点了一个却收到了另一个,没有人会高兴。我们混合配料的方式很重要。
****与反规格化相关的定义的度量:度量是反规格化数据的方法,被合成为通用的、可理解的数据语言。

指标的核心是将这些标准化的数据集组合成一组有意义且易于理解的值或时间序列的公式。度量是获取各种成分并创造有价值的东西的方法。照片由 丹金 上 下 下。
数据团队的任务是提供一个清晰的界面来解决最常见的问题,因此他们创建汇总表、数据集市和视图。大多数公司都有大量难以管理的潜在指标和维度组合,这使得它们无法提前具体化每个有用的数据集。相反,构建指标的逻辑渗透到公司工具堆栈中构建或使用数据的每一个工具中。从性能和易用性的角度来看,预计算总是更可取的,但对于不习惯添加新数据模型的最终用户来说,它也是一种限制——而且它缺乏提出任何问题的灵活性。
随着数据接口的改进,消费者能够提出更多的问题。他们最终会从核心数据集构建衍生数据集,以找到问题的答案。除了复制数据来构建这些非规范化的数据集和指标,我们还经常复制应该在多个系统中保持一致的逻辑。结果是各种工具之间重复逻辑的扩散,更糟糕的是,许多人在彼此的逻辑基础上构建,使得最终结果对最终消费者来说几乎是一个黑盒。
根据过去两年与数百名数据分析师的交谈,我认为这是数据堆栈中为数不多的几个点之一,在这些点上几乎没有既定的最佳实践,更不用说实现它们的工具了。这个问题限制了数据消费的广度和消费者愿意为其决策提供信息的深度。手动管理这些数据集的解决方案给数据和分析工程师带来了维护负担,使他们无法完成更有意义的工作。
虽然这篇文章旨在为讨论反规范化及其与指标的关系提供一个知识基础,但论点是在现代数据栈中缺乏支持反规范化的更好的工具和过程。当我们谈论现代数据堆栈的缺失层时,我们实际上是在指出管理非规范化数据集所面临的挑战。
为数据科学部署 beast 虚拟机
理解大数据
使用 Jupyter Hub 在 Azure 中构建定制数据科学虚拟机的指南,在一个命令中即可运行。

(图片来自 pixilart.com来源:https://www.pixilart.com/art/little-laptop-1b5bef298dcee31)
你梦想有一天拥有超越你笨重的笔记本电脑 J-Hub 或 Google Colab 会话的能力吗?幻想您的 M/L 实验使用 64+内核和 500+GB RAM 的专用硬件?直接访问英伟达特斯拉 T4,M60,V100 和 AMD 镭龙 MI25 GPU 设备,或 1800+MBit/秒的互联网速度来下载数据进行处理怎么样?(底线:如果这些让你的瞳孔放大,像我一样,你可能需要多出去走走。)
今天我要把那个书呆子梦变成现实。我将向您展示如何在 Azure 中部署任何针对数据科学预配置的虚拟机,以及运行 Jupyter Hub 服务器,只需一个命令。
如果你一直想进入专用云硬件的神秘世界,现在是时候了。有一种新的语言叫做 Bicep ,来自微软(2020 年 8 月推出)。它提供了一种简单而优雅的方式来描述 Azure 云组件,您可以在命令行轻松部署这些组件。
我在 GitHub 上专门为数据科学家构建了一个二头肌模板集。手动选择您的虚拟机规格,包括型号(内核和 ram 选项),选择操作系统磁盘大小(高达 4TB),使用一个命令部署脚本,您的虚拟机在 90 秒内即可启动。它带有一个定制的 Linux Ubuntu 18.04 操作系统映像,专门为数据科学设置,预装了 150GB 的好东西,包括对 Python、R、Julia、SQL、C#、Java、Node.js、F#的原生支持。
如果你不了解 Linux,不要担心。开箱即用,该机器运行 Jupyter Hub 服务器,让您可以通过 HTTPS(使用自签名 TLS 证书)即时(安全)访问该机器。一旦机器启动,你就可以通过 JHub 访问它。零设置。零麻烦。零笑话。
对于 Python JHub 的粉丝来说,我敢肯定,你们中的许多人都对从本地机器上运行的硬件限制感到沮丧,或者实际上是来自像 Google Colab Premium 这样的云笔记本服务的限制。
非常清楚:这个 VM 是你自己的私有 JHub 服务器,拥有你愿意支付的所有能力和存储。
需要 500GB Ram、4TB 存储和 64 个 CPU 内核运行 6 小时?在几秒钟内部署您需要的确切虚拟机,并像专业人员一样完成工作。也许你和一些朋友需要一个 128GB 内存的中等规格钻机和一个英伟达特斯拉 T4 一个月;分担成本并获得协作。或者试试 Azure 30 天免费试用版(200 美元信用),体验一下基本的 4 核机器、32GB 内存和 1TB 存储。选择权在你。
你的虚拟机将会为你运行,毫不妥协,不受限制。听,并理解。这台机器就在外面。这是不能讨价还价的。这是无法讲道理的。它不会感到怜悯、悔恨或恐惧。而且它绝对不会停止,直到你的[信用卡]死亡。(抱歉,终结者。忍不住。)
在以下部分,我将尝试总结和对比现代数据科学家的硬件选项和局限性。我将提供云基础设施的快速速成课程(基于我不完善的理解),我还将通过数据科学的视角描述 Azure 的整个 VM 目录。我的目标是揭开云基础设施的神秘面纱(至少对 Azure 来说是这样),并描绘出有哪些选择,何时你可能想使用它们,以及你预计会支付多少钱。

要是云技术像这样就好了。(图片来自 pixilart.com)。来源:https://www.pixilart.com/art/rainbow-cloud-c07afa838edaa20
问题:云很可怕
我认为现实是有大量的数据科学家对本地硬件或免费云服务的局限性感到沮丧,渴望尝试专用的虚拟硬件,但不知道如何轻松开始。(即智力进入成本太高)
谁不会被所有可笑的供应商专用术语和难以比较的定价吓跑呢?此外,还有与“云”远程机器相关的其他可怕的东西,如 linux、git、ssh-keygen 公共/私有加密、网络协议、TLS 证书和 VPN 安全考虑。这是一个字面上的噩梦,这就是为什么整个行业都在努力摆脱所有这些痛苦,提供笔记本电脑即服务类型的产品。
有趣的是,“云”技术就像它的名字来源于大气云一样不透明。
令人悲伤的事实是,如果你召集一个顶级工程师团队,把他们关在一个房间里两周,并让他们设计他们能想象到的最复杂、最不连贯、最难以理解的云生态系统,你就会得到我们今天所拥有的。
供应商们不再以功能来命名事物,而是被激励去创造像“EFA fabric adapter”或“infiniband”这样的公司流行语(顺便说一下,这些都是真实的)来锁定客户。从短期来看,这可能会保护市场和客户份额,但从长期来看,我认为缺乏术语的功能标准化对行业来说确实是有害的。当硬件基本上在做同样的事情时,事情不应该这么复杂。在汽车行业,世界上每一个机械师都称“燃油泵”为“燃油泵”。它泵送燃料,因此根据它的功能准确地命名。当然有不同品牌的燃油泵,有些泵的压力比其他泵高,但它们基本上做的是一样的。可悲的是,这并没有发生在云世界,我认为现实的混淆是非常可悲的。这是一个很难想象云虚拟硬件原理上如何工作的抽象概念,更不用说在不同“制造商”对每个组件都有不同命名的情况下理解它了。
第二个问题是:硬件不是免费的。现代数据科学家几乎总是会遇到硬件限制。无论是在本地机器上,还是在 Kaggle Kernals 或 Google Colab 中令人沮丧的会话超时,以及 ram 和存储的持续压力。你升级你的本地机器吗?选择托管服务(如 Google Colab Premium 或 Google AI platform )还是勇往直前进入专用虚拟硬件的最终领域?成本和限制如何比较,学习曲线会有多陡?
如果你需要更好的规格,你需要做好支付的准备。句号。但我认为,如果做得明智,云是一个比升级本地机器更具成本效益的选择,而且就您卧室的本地硬件而言,您可以远远超出即使是最好的钱也能买到的规模。
我希望这篇文章能让你对这些问题有一个大致的了解,并提供一个简单的选项,用最少的设置让 Azure data science vm 超快地运行起来。
带回家的消息
- 为数据科学建立一个专用的虚拟机不再像过去那样可怕,打开了访问你一直梦想的庞大硬件规格的大门。
- 微软发布了一种叫做 Bicep 的新语言,它可以帮助你优雅地描述和构建他们的基础设施。他们还发布了一个定制的数据科学操作系统映像。(很爽)。
- Bicep 和 data science 操作系统映像的结合意味着您可以在 90 秒内按下按钮构建一个 data science 虚拟机,并通过 JHub 连接到它。我已经构建了模板来帮助您做到这一点:像老板一样手动选择您的虚拟机规格并部署基础架构代码。
- 虽然专用硬件通常必须付费,但你可以使用 200 美元的信用进行 30 天的免费试用,但有一些重要的警告。
快速入门
如果你知道如何使用 ARM 模板(和 Bicep)部署 Azure 资源,那么克隆我的 GitHub repo ,打开适当的 Bicep 模板文件,设置你的 VM 规格,创建一个资源组,然后用一个命令在 Azure CLI 中部署。
使用单一命令部署
az deployment group create -f vmtemplate.bicep --resource-group <RESOURCE GROUP NAME> --parameters adminUsername="USERNAME" adminPassword="PASSWORD"
这将使用针对免费帐户优化的默认模板虚拟机规格(E 系列、4 核、32GB 内存、64GB 临时固态硬盘、1TB 固态硬盘操作系统磁盘):
或者使用最多六个参数指定虚拟机规格:
az deployment group create -f vmtemplate.bicep --resource-group <RESOURCE GROUP NAME> --parameters adminUsername="USERNAME" adminPassword="PASSWORD" vmModel="Standard_E4s_v3" osDiskSize=1000 osDiskType="Premium_LRS" projectName="myproject"
通过 JHub 访问虚拟机
部署完成后,获取新虚拟机的公共 IP 地址(从门户或 CLI)并通过[https://xxx.xxx.xxx.xxx:8000](https://xxx.xxx.xxx.xxx:8000)在浏览器中访问 Jupyter Hub 服务器
通过安全外壳(SSH)访问虚拟机
通过终端直接访问:ssh USERNAME@xxx.xxx.xxx.xxx
注意事项:
- 二头肌模板部署就像手臂。json 模板(你只需要先安装 Bicep)
- 用户名和密码应该用“引号”括起来,否则特殊字符将无法正确检测
- 密码需要很强(1 个大写字母、1 个数字、1 个特殊字符)
- 对于 JHub 和其他暴露在互联网上的服务,vm 为 HTTPS 创建一个自签名证书(TLS/SSL)。当你试图连接时,现代浏览器仍然会大发脾气。只需点击通过安全警告,你可以连接确定,并相信你是通过加密协议访问服务。
- 如果你不需要 JHUB,并且希望使用密钥对你的虚拟机进行更安全的 SSH 访问,我有一个专门针对 T4 的模板。
- 对于高级用户,我也有一个模板,用于将您的虚拟机放在高级 VPN 网关后面
vmtemplate_vpn.bicep。请参阅文档或 GitHub 自述文件中的详细说明。 - 请注意,具有公共 IP 和暴露端口的虚拟机确实会引入易受攻击的漏洞。这对于短期任务来说可能是可以的,但是最佳实践是将虚拟机私有地放在 VPN 后面。我已经在我的 repo 中为此提供了一个模板,尽管注意它是为高级用户提供的,因为它需要手动步骤来创建根/客户端证书。我认为对于短期工作来说,攻击的风险是相当低的,使用默认设置应该没问题,但要知道这是有风险的。
初学者指南
如果你是云基础设施的新手,并假装在这一点上不害怕,不要担心。遵循本指南和下面的逐步说明,您将很快拥有一个完全专用的虚拟机。
下面是你要做的:在一条命令中,你将把 Bicep 文件(描述云基础设施的高级语言)编译成 Azure Resource Manager (ARM)模板(JSON 格式的基础设施的低级抽象),然后在 Azure 中构建所需的资源。部署大约需要 2 分钟,您就可以启动并运行了。如果你是微软云的新手,我建议你获得一个免费的微软 Azure 账户,这样你就可以在试用的限制内免费玩了。
真正需要强调的是,我们在此次部署中使用的操作系统映像完全是(由微软)为数据科学而设置的。这意味着几乎不需要任何设置(或 Linux 技能)。它提供了对所有通用语言的支持,并且它本机运行 Jupyter Hub 服务器和 R Studio lab 服务器作为开箱即用的服务!这意味着一旦虚拟机启动,您就可以通过 HTTPS 安全地立即连接到虚拟机。
现代数据科学家的硬件选择
在选择硬件时,我认为实际上有三个主要选项:
- 本地机器
- 托管服务(例如笔记本电脑即服务产品)
- 专用远程硬件(即虚拟机)
每一种都有其优势和局限性,还有许多其他因素,如协作和共享工作的能力,这些因素更适合一些选项。下面我提供了众所周知的笔记本工具与专用云硬件的快速对比。很难从 Kaggle 和 Colab 那里知道确切的数字,因为许多限制都没有确切地说明或公布,所以我从其他人那里了解了一些情况。

Kaggle、Colab 和云虚拟机(在本例中为 Azure)的快速比较。
为什么选择虚拟机?
- 可扩展性和选择:访问数百个内核、数千 GB 内存和海量存储。
- 按需付费(按秒计费)
- 完全控制(完全控制您的硬件)
- 疯狂的网速(我用一个典型的 4 核虚拟机达到了 1854 MBit/秒的下载速度)
专用虚拟机的替代方案
- 您的本地硬件
- Google Colab
- Kaggle kernels
- 天蓝色笔记本(虽然我认为这已经不存在了)
- 深度笔记
- 曲线板
- 等。
Google Colab(以及类似服务)是如何免费的??
事实是,他们不是真的。硬件不是免费的。但是硬件可能没有得到充分利用,我怀疑,这正是这些服务可以零成本提供给你的原因。你在 Kaggle Kernals 和 Google Colab 上获得的将是现货市场闲置的产能;啤酒杯底的渣滓。您无法锁定超过 6-12 小时的硬件的原因可能是因为在企业客户早上醒来并以全价按需启动硬件之前,组件通常不会被使用。当这种情况发生时,你将被踢出你的硬件,以支持付费用户。我不确定,但这是我最好的猜测。我在这里想说明的一点是,当你想要适当地访问硬件时,你需要付费,要么通过一个很棒的本地平台,一个托管服务,要么通过云中的专用虚拟机。免费服务很棒,但是有充分的理由严格限制。
我可以在我的虚拟机上安全地访问 Jupyter Hub 吗?
是的……嗯合理地安全地。事实上,这可能是这个特殊设置中最重要的事情。微软已经完成了构建特殊数据科学 linux 操作系统映像的所有工作,该映像可以自动运行 Jupyter Hub 服务器。不需要设置。他们还处理自签名 TLS 证书,这意味着您可以使用 HTTPS 连接到您的虚拟机的 JHub 服务器。在大多数浏览器中,您需要点击通过安全警告,但这只是因为您在虚拟机和您的 pc 之间使用自签名证书。这意味着您可以立即启动 JHub 并以强劲的马力运行,如果您愿意,还可以在您的新硬件上与其他人实时协作。我要再次强调,让一台机器的端口对公共互联网开放是有风险的。最好的选择是将机器放在 VPN 后面的私有网络上,但这要复杂得多,而且更难让 JHub 工作(我在 GitHub repo 中为高级用户准备了一个专用模板)。对于初学者,我认为你可以使用默认的虚拟机设置和公共 IP。只是要意识到风险。
什么是基础设施即代码?
这个例子演示了如何将云基础设施构建为代码,这是一种将您需要的组件描述为“代码”的方式。真的就是这样。许多(或所有)大公司都有某种 API,用于解释要部署的基础设施。无论你是从浏览器还是直接从代码构建一台机器,它都被转换成一种特定于领域的格式,供供应商吸收,就像一个蓝图,以便构建组件并将它们连接起来。微软 Azure 使用被称为 ARM 模板的东西。您想要构建的所有基础设施的 json 表示。AWS 使用. json 和。yaml 喜欢的界面。我不确定谷歌和其他公司。微软发布了一种新的开源语言,名为Bicep(2020 年 8 月),它极大地简化了你描述他们基础设施的方式。它真的很棒,我们要用它了!
当我部署虚拟机时,实际构建的是什么??
重要的是要明白,当您调配虚拟机时,还需要其他云资源;它不仅仅是一个孤立配置的神奇虚拟机。例如,要部署一个具有一些暴露于互联网的端口的虚拟机,您在 Azure 中实际做的是构建一个虚拟网络、网络内的子网、虚拟网络接口卡、网络安全组(控制打开/关闭哪些端口之类的事情)、具有持久磁盘的存储帐户(预加载了操作系统)、虚拟机本身(实际上是计算 cpu-ram 组件)和一个面向公众的 IP 地址,以绑定到网络接口卡,以便您可以通过互联网访问虚拟机。在你把自己从最近的阳台上扔下去之前,我保证一旦你掌握了基本知识,它不会太糟糕。所有这些神奇的事情都发生在一个干净的步骤中,因此您不需要担心复杂性,可以专注于您最擅长的事情:数据的科学【T1:)
这里是网络拓扑,只是给你一个你将在 Azure 中构建的最终产品的图片。

这些是您将构建的组件,只需一个命令,即可创建您的数据科学虚拟机。
在 Azure 中理解虚拟机类型
我认为大多数重量级数据科学应用程序需要高内存处理,以及 CPU 或 GPU 的并行处理。如果你是像我一样的黑客数据科学家,你会知道生活中的所有问题都可以用更多的 RAM 来解决。因此,我认为最令人感兴趣的虚拟机类型是来自 Azure 的 D/E/M/N 系列。
下表列出了我对 Azure 机器类型以及数据科学应用程序需要关注的快速而粗略的描述。有许多子变型,所以这只是一个味道,让你对规格和成本范围的想法。

关于数据科学的 Azure VM 类的快速浏览
需要注意的一件重要事情是:RAM 数量是基于 CPU 内核进行扩展的。所以你不能只有一个 256GB 内存的 4 核机器,以防你想知道。不同的类有不同的核心:内存比率,这是值得理解的。E 系列拥有最高的内存:内核比率。
更多信息在这里。有用的网站 azurepricenet 可以让你快速找到你需要的 VM 家族和具体型号,以及定价。
对于数据工程和 M/L 中的非 GPU 应用,我认为 D/E 系列为您提供了一个可靠的全能设置,单个实例中最多可有 96 个内核和 672GiB RAM,外加许多选项来适应特定项目。例如,一个“E16as_v4”将为您提供 16 个 2.35Ghz 内核、128GiB RAM 和 256GB 临时 SSD 存储,每小时约 1 美元。
如果您正在做一些疯狂的事情,M 系列是直截了当的猛兽,单个实例可以时钟输出到 416 个核心和 11,400Gb RAM。我的意思是,我不知道你会在数据科学中使用这些。公平地说,这些更适合核心企业应用程序。但是他们在那里。
对于快速发展的深度学习人群,新的 N 系列适合你。内有许多变体和类,但本质上,您可以自定义虚拟机以获得对 GPU 的部分访问(例如,每个节点 0.25 个 GPU 核心到 4 个专用 GPU 核心)。您可以直接访问 Nvidia Tesla T4 和 M60、Volta V100、AMD Radion MI25,这些虚拟机采用最新一代 cpu 内核库,包含 4 至 64 个 CPU 内核。我应该强调这些在免费试用中不可用,你必须加入付费计划。这些都是严肃的,我想你们中的许多人可能想尝试。
这里还值得一提的是,微软并不是 GPU 云产品领域的巨头。公平地说,这是谷歌和其他公司。底线是他们中的大多数都提供 GPU 选项,如果这对你的工作至关重要,那么就值得研究选项。无论如何,我认为 Azure 是尝试专用云硬件的一个很好的选择,因为现在使用新的 Bicep 语言很容易部署。
另一件值得注意的重要事情是,在标准 PAYG 帐户上,您将无法提供开箱即用的资源。所有 Azure 帐户都有软和硬 vcpu(核心)配额,因此如果您想要超过 4 个核心,您需要向服务台提出配额增加请求,这可能需要 48 小时来处理。您可以在 Az CLI 中根据给定区域检查所有虚拟机类型的当前限制,更多信息请点击。
我的虚拟机在哪里?
微软在世界各地都有数据中心,你可以在这张地图上看到。根据您将创建的“资源组”的位置,您的虚拟机将驻留在您选择的数据中心。Azure 资源组只是一个方便的桶,可以放入所有的资源,就像桌面电脑上的文件夹一样。您可以在“文件夹”级别控制访问,并通过一次删除来删除其所有内容。地区之间存在边际价格差异,但是对于这个用例,最重要的因素是为您的资源组选择离您当前位置最近的位置。这将最小化你和机器之间的延迟。例如“美国中部”或“英国南部”。
我可以在浏览器中使用 Azure 门户构建一个数据科学虚拟机吗?
是的。事实上,我建议你使用 Azure 门户,选择数据科学操作系统映像,构建你的第一个虚拟机。这与我在这个构建模板中使用的操作系统映像完全相同。使用门户有一些限制,所以你不能指定太多的选项,但是你肯定可以在 JHub 等上启动并访问你的虚拟机。我希望这篇指南向您展示将基础设施作为代码部署是多么容易,无论如何,当您从 Azure 门户进行部署时,这是在幕后实际发生的事情。
我的虚拟机如何计费?
你按秒付费。是的,让虚拟机开着会比周五晚上喝龙舌兰酒更快地积累你的信用卡(你在免费账户上受到保护,别担心)。
大多数其他基础设施基本上是免费的(虚拟网络、子网、公共 IP 等)。关键成本是计算(虚拟机)和存储(连接到虚拟机的持久磁盘)。
请注意,小时费率是 PAYG,如果您对虚拟机有持续需求,通常可以在 3 年预订期内将按需价格降低 60–70%(您可以随时取消预订)。许多虚拟机还可以现货价格购买,这非常有吸引力。不要上当。我认为这对于数据科学应用来说不是一个好主意,因为你通常需要长的不间断的处理管道。在现货市场上,你的 VM 可以在没有任何警告的情况下被拉出来,毁掉你所有的工作。PAYG 是在使用资源时获得有保证的独占性的唯一途径。
黄金法则是:永远记住关闭虚拟机(取消配置)或拆除所有资源(删除所有内容)您可以暂时取消配置,保留操作系统磁盘,就像关闭 PC 一样,或者您可以在完成后删除整个资源组。
免费试用版中最好的虚拟机是什么?
30 天的免费试用可以获得 200 美元的积分,这很好,但请注意以下一些重要限制:
- 最大核心数=每个区域 4 个(意味着免费帐户上没有大灰狼虚拟机)
- 无法访问 GPU 虚拟机系列(升级到 PAYG 帐户以访问 N 系列 GPU 优化的虚拟机,起价约为 1 美元/小时)
最残忍的免费帐户设置:
- e 系列“标准 E4s_v3”(我的模板中的默认值)
- 4 个内核(英特尔至强白金 8272CL 基本内核时钟 2.5GHz,可提升至 3.4Ghz 所有内核)
- 32GB 内存
- 1tb 高级固态硬盘(最快的操作系统磁盘类型)
- 疯狂的网速(通常 1000 多兆比特/秒)
这个包将燃烧约 10 美元的信用/天,你可以运行它 24-7 全速,不间断,没有 cpu 的限制,为 20 天,直到你的免费信用耗尽。您可以将操作系统磁盘大小设置为高达 4,095 GB(4tb)的任何值,但 1tb 最大限度地提高了 30 天试用期的存储容量。
存储如何与虚拟机协同工作?
所有虚拟机都需要一个用于操作系统映像的托管永久磁盘。您可以附加额外的磁盘(通常是几个)并把它们挂载到文件系统上,但是请注意,如果您不熟悉 linux 的话,这是非常麻烦的。到目前为止,最快、最简单的选择是将操作系统磁盘大小(高达 4TiB SSD)增加到您手头任务所需的大小,因为这是自动安装的。
许多 VM 类提供临时高速存储也没有什么价值。这通常在地理位置上靠近数据中心的计算硬件(cpu 核心),基本上是您可以获得的最快的存储。我认为这有时被称为“暂存”存储。请注意,它是短暂的,仅持续几天,因此对于数据处理阶段非常有用。如果您的 VM 类提供临时存储,它会自动安装在您的 VM 上的位置/mnt。
如何在虚拟机之间来回传输数据?
这是一台合适的远程 Linux 机器,所以它不像将文档复制粘贴到你的笔记本电脑上运行 JHub 的 windows 文件系统那样简单。但是,美妙之处在于,你可以通过浏览器直接通过 Jupyter Hub 服务器进行大部分上传/下载,这应该可以满足大多数人的需求。别忘了,你可以从虚拟机上以闪电般的速度从互联网上下载数据。因为你的虚拟机位于数据中心,它的数据传输速度通常比你的家庭互联网或 Colab 快十倍(1800+ Mbit/s)。
将数据放入虚拟机:
- 从您的 pc:从 linux 终端使用浏览器或类似于
rsync的工具中的 JHub 上传功能(要求您在 windows 中有 WSL) - 来自互联网:wget/curl/github(就像你在云笔记本工具中一样)
从您的虚拟机中获取数据:
这比你想象的要复杂一些,因为机器运行的是 Linux,而你可能运行的是 Windows,但是我没有什么标准的建议。它还取决于你计划在哪里存储数据,以及你有多少数据。
- 小(<30GB): use the JHub file download feature in browser (the simplest)
- medium: (<1TB): use a linux data transfer application like 【 (requires linux on your local machine, native for MacOS but Windows you will need WSL
- 大型:(+1TB):直接传输到云数据存储服务,如 Azure Blob 或网络文件系统(NFS)。这将允许您快速从虚拟机中获取数据并将其关闭(以节省成本),然后您可以直接连接到云存储服务以下载或更长期地存储数据。
说明
既然速成课程已经完成,我们可以从一步一步的指导开始,以代码的形式部署您的虚拟机基础架构。注意这都在 myGitHub repo中有详细说明
先决条件
- 微软 Azure 账户(例如免费试用或现收现付)
1.安装 VS 代码和二头肌/手臂延伸(可选)
这是为我们打开和编辑项目文件做准备,主要是vmtemplate.bicep文件或类似的模板。Microsoft Visual Studio 代码非常适合这个项目,因为它是开源的,并且有可下载的 bicep 和 ARM 模板扩展,这意味着它很好地着色了代码,使其更具可读性。下载并安装 VS 代码以及手臂工具和二头肌延伸。注意,一旦 VS 代码运行,就可以很容易地从代码中安装这些扩展。当然这是可选的。您可以使用任何编辑器(例如 Notepad++和 VIM 等)。)并且您根本不需要编辑文件,因为您可以在 build 命令中将 vm 规范作为参数传递。
2.安装 Azure CLI
什么是 Azure CLI?这是一个专门的程序,它提供了一个命令行界面(即 CLI)来直接与 Azure 资源进行交互。这意味着您可以像老板一样在命令行上构建和拆除基础设施,而不是从 web 浏览器门户进行。最直接的方法是安装 Azure CLI ,它可以在 Windows、MacOS 和 Linux 上运行。
我真的需要使用 Azure CLI 吗?对于这个完整的例子,是的。因为门户界面有一些限制。一般情况下:不需要。如果您只想使用用户名/密码和 data science 操作系统映像构建虚拟机,您可以根据需要从门户一次性完成所有操作。
3.安装二头肌
Bicep 是一种很酷的新的领域特定语言,用于以比使用 ARM 模板更简单的方式部署 Azure 资源,ARM 模板是 JSON 格式的,阅读起来很痛苦。Bicep 文件编译成 Azure 资源管理器(ARM)模板,然后 Azure 可以直接接收这些模板来构建基础设施。因此,Bicep 脚本是 ARM 模板之上的高级抽象,它简化了您想要构建的基础设施的描述。安装二头肌只需要几分钟。此处遵循安装指南。
在 Azure CLI 最新版本中,它基本上是:
az bicep install
az bicep upgrade
4.克隆此回购
将这个项目 repo 复制到你的本地机器上,或者直接从 Github 浏览器下载,或者通过git clone等。如果你不熟悉 GitHub 和 git,实际上,你只需要把vmtemplate.bicep文件放到你的本地机器上,你就可以在 Azure CLI 中访问它。
5.配置虚拟机规格(有趣的部分)
在 visual studio 代码中打开vmtemplate.bicep文件。
在文件的开头,我总结了所有你可能想要调整虚拟机设置的旋钮和转盘。默认情况下,我选择了我能在免费帐户的限制内找到的最艰难的设置(这是一个 E4s_v3,带有 32GB RAM,64GB 临时 SSD 存储和 1TB 高级 SSD 操作系统驱动器)。当然,你可以在免费账户上混合搭配几乎任何多达 4 个内核的虚拟机,并尝试不同大小和类型的硬盘。
您可以在。bicep 文件本身,或者通过在 build 命令中将所需的值作为参数传递来覆盖默认值。完全由你决定。进一步提供的例子。
关键决策点:
- 虚拟机型号—这一点至关重要,因为它决定了内核、RAM、临时存储的数量以及与 I/O 相关的其他限制。实际上有数百个选项。在 Azure docs 或 azurenet 上查找您想要的内容。你只需要文本字符串,比如“Standard_E4s_v3”。
- 操作系统磁盘大小—默认为 1TB 高级 SSD,但您可以选择高达 4tb(4095 GB)的任何容量作为单个磁盘。
- 操作系统磁盘类型请特别注意,有 3 种不同的存储类别,即固态硬盘“高级 _LRS”,“标准固态硬盘 _LRS”,即受限制的固态硬盘介质,然后是传统的硬盘驱动器“标准 _LRS”。标准 ssd 是高级 ssd 价格的一半,标准 HDD 是高级 SSD 价格的 1/4。在此参考文件。在所有的数据科学应用程序中,为了获得最佳性能,我只会使用“高级 LRS”。
6.登录 Azure
从 azure CLI:
az login --use-device-code
这将打开浏览器,让您输入 CLI 中显示的代码
检查可用帐户
az account list --output table
设置订阅(如果默认帐户不正确)
az account set --subscription <name>
列出资源组(查看订阅中的任何现有资源组)
az group list --output table
可选:将 Azure CLI 输出格式永久设置为 table,该格式比 JSON 更易于阅读,这是默认设置。我强烈建议这样做。
az configure(并按照提示操作。确保选择输出为表格格式)
7.创建 Azure 资源组
在地理位置靠近您当前位置的区域创建一个新的资源组。
要查看可用区域:
az account list-locations
在本例中,我在“美国中部”地区创建了一个名为“beast”的资源组。通常需要几秒钟。
az group create --name beast --location "Central US"
检查资源组是否已创建
az group list --output table(如果您已经更改了 Az CLI 配置,则不需要每次都附加- output 表)
几秒钟后,它应该会出现。您可以通过搜索“资源组”或在 CLI 中键入az group list来直接在 portal.azure.com 进行检查。
8.设置访问
我们几乎准备好构建资源了。我们需要做的最后一件事是设置如何访问机器。有两种主要方法可以做到这一点:用户名/密码凭证或 SSH 公共/私有密钥加密。我有一个单独的二头肌文件为每个选项。我现在推荐 user/pass default,因为这是 JHub 兼容的选项。
选择用户名和密码
- 注意密码必须至少包含 1 个大写字母、1 个数字和 1 个特殊字符。
- 我建议你用类似 keepass 的东西生成一个强密码。
- 对于我们将使用的默认模板,您必须创建用户名和密码。这是因为 Jupyter Hub 需要用户/通行证,不支持 SSH 密钥。因为我假设大多数人希望在他们的虚拟机上运行笔记本,所以我设置了允许用户名/密码的模板,这并不是连接到 Linux 主机的最安全的方式。
可选:创建 SSH 密钥对
仅适用于您不打算使用 JHub 并且想要最安全的方式来访问您的 VM 的情况。如果您在 Windows 或 MacOS 中运行 linux、WSL,并且您基本上有一个 linux 终端,那么您可以为虚拟机的安全 shell 访问(SSH)创建公钥/私钥加密文件。这是最安全的访问方式,尽管 Jupyter Hub 不支持它。所以不管怎样,如果你打算主要使用 JHub,你就需要使用推荐的vmtemplate.bicep模板。从 JHUB 你可以访问一个完整的根终端来做你需要的任何事情。因此,这实际上只适用于那些希望能够用加密密钥直接 SSH 到虚拟机的铁杆用户。如果您确实需要这个选项,那么创建 SSH 密钥对时要准备好公钥以供复制。
9.伟大的建筑
这是你们一直在等待的时刻:我们已经准备好建设基础设施。从 Azure CLI 中,确保导航到当前工作目录,即vmdeploy.bicep文件所在的目录。您还必须通过 Az CLI 登录您的 Azure 帐户(步骤 6)。通过运行下面适当的命令,传入用户名/密码或公钥的参数来构建虚拟机。
让我们假设您决定使用用户名:jamesbond /密码:G0|den3y3,并且已经创建了一个名为“beast”的资源组。
使用用户名/密码部署
使用中的默认虚拟机规范进行构建。二头肌锉:
az deployment group create -f vmtemplate.bicep --resource-group beast --parameters adminUsername="jamesbond" adminPassword="G0|den3y3"
构建将自定义虚拟机规格作为参数传递:
az deployment group create -f vmtemplate.bicep --resource-group beast --parameters adminUsername="jamesbond" adminPassword="G0|den3y3" vmModel="Standard_D2s_v3" osDiskSize=180 osDiskType="Premium_LRS" projectName="myproject"
使用 SSH 公钥部署
az deployment group create -f vmtemplate_ssh.bicep --resource-group beast --parameters adminUsername="jamesbond" adminPublicKey="INSERT FULL ASCII PUBLIC KEY HERE"
笔记
- 对于 SSH,您调用的是另一个名为
vmtemplate_ssh.bicep的 bicep 模板文件。 - 始终用引号将用户名和密码(以及公钥)括起来,以确保正确解析特殊字符。有时没有它们你会得到一个错误。
如果它工作了,你应该看到类似这样的东西

如果你在耐心等待 2 分钟后在 Azure CLI 中看到类似这样的东西,那么你看起来不错。
登录 Azure 门户网站,看看你的新基础设施!

导航到门户中的资源组,您可以看到所有新创建的组件(在右边)
获取虚拟机的公共 IP 地址

单击虚拟机本身,查看其公共和私有 IP 地址(右上角)
10.通过 Jupyter Hub 通过浏览器连接到机器!
您的新虚拟机预配置了一系列服务。部署后,它立即运行一系列容器化服务(通过 Docker ),包括在端口 8000 上公开的 Jupyter Hub 服务。Jupyter Hub(在某种程度上)是一个网络服务器,所以你可以从互联网上的任何浏览器直接连接到它。
首先获取新虚拟机的 IP 地址:
- 从 Azure 门户:搜索资源组,导航到正确的组,点击虚拟机(你可以在右上角看到公共 IP)
- 来自 Azure CLI:
az vm show -d -g <RESOURCE GROUP NAME> -n <VM NAME> --query publicIps -o tsv
打开浏览器并访问 Jupyter Hub webserver(它运行在通过端口 8000 暴露的虚拟机上),其中 IP 地址替换了 x。:
[https://xxx.xxx.xxx.xxx:8000](https://xxx.xxx.xxx.xxx:8000)
浏览浏览器安全警告。您的虚拟机已经生成了自己的自签名 SSL 证书,以允许加密的浏览器流量(HTTPS)。但是,由于这不是一个公共证书,当您第一次连接时,浏览器通常会发出警告。不要担心,你通常可以点击“接受风险”,然后“转到网站”。

你仍然可以通过 HTTPS 安全地传输数据,只不过你使用的是一个来自 Linux 虚拟机的自签名证书,它不能被浏览器公开识别。
完成后,您应该会看到一个 Jupyter hub 登录屏幕:

如果你看到这个屏幕。开始庆祝吧。
使用您在部署时为虚拟机提供的用户名和密码登录 Jupyter Hub
如果成功了,您将看到如下所示的 Jhub 会话。

Jupyter Hub 会话由运行在本地机器浏览器中的远程虚拟机托管!
你被录取了。在这一点上,你可以开始玩笔记本电脑或与朋友合作,以数据科学了!
我真诚地希望这对某人有用;这对一年前的我肯定是有用的。请注意,在我的 Github repo 中,我在READEME.md的结尾提供了额外的细节,比如如何将你的虚拟机放在 VPN 后面(如果安全是最重要的),以及如何测试你的虚拟机的一些基本规格,如互联网速度,如果你不熟悉 Linux,检查处理器和 RAM 的利用率等。
最后要说明的是,我不是云方面的权威,我只是碰巧花了六个月的时间与各种 Azure 虚拟机一起工作,觉得是时候分享一些我一路走来所学到的东西了。
我欢迎更正和澄清,我也希望看到了解 AWS 和谷歌云的人写类似的文章。
享受❤
在谷歌人工智能平台上部署机器学习模型

谷歌 ML 教程
如何轻松创建一个云服务来查询你训练好的 ML 模型
在上一篇文章中,我们为我们的机器学习模型找到了最佳超参数,然后对其进行训练。
下一步是部署它:我们必须创建一个服务,我们可以用新数据查询该服务,以从我们的模型中获得预测。
我们将使用 Google AI 平台预测服务来存储我们的模型,对其进行版本化,并创建服务来获得预测。
对于本教程,您需要:
- 一个活跃的谷歌云平台账户(你可以通过访问主页建立一个新账户)和一个 GCP 项目。
- gcloud 和 gsutil 安装在您的工作站上。
- 您想要部署的经过训练的模型。你可以在这个系列的其他教程之后创建一个,或者你可以下载这个作为例子。
到目前为止,您只能部署一个 scikit-learn、XGBoost 或 Tensorflow 模型。
我将使用银行营销 scikit-learn 管道,但是所有框架的过程都是一样的。
第一步:将训练好的模型存储在谷歌云存储中
您必须将实际的模型对象存储在云中的某个地方:存储桶是正确的方式!
如果您还没有存储您的模型,您可以直接从浏览器上传或使用gsutil:
gsutil cp local-path/to/model.joblib gs://bank-marketing-model/
请记住,模型对象必须具有以下名称之一:
model.joblib如果是用joblib库创建的model.pkl如果用pickle库创建
步骤 2:在本地测试预测
至于训练模型,我们可以在实际部署之前在本地测试我们的预测服务。
为此,我们需要一个 json 文件,其中包含用于查询模型的输入数据。该文件的格式非常特殊,它是这样的:
[56, “housemaid”, “married”, “basic.4y”, “no”, “no”, “no”, “telephone”, “may”, “mon”, 261, 1, 999, 0, “nonexistent”, 1.1, 93.994, -36.4, 4.857, 5191, “no”]
[57, “services”, “married”, “high.school”, “unknown”, “no”, “no”, “telephone”, “may”, “mon”, 149, 1, 999, 0, “nonexistent”, 1.1, 93.994, -36.4, 4.857, 5191, “no”]
所以我们对每条记录都有一行要预测;每一行都是由模型输入要素的值组成的列表,按原始数据集排序。
现在您可以使用这个命令运行本地测试:
gcloud ai-platform local predict \
— model-dir gs://your-bucket/path-to/model-directory \
— json-instances ./your-input-file.json \
— framework scikit-learn
model-dir必须是包含model.joblib对象的 GCS 目录的路径(不是模型本身的路径)framework是用于训练模型的实际框架。它可以是 scikit-learn、TensorFlow 或 xgboost。
请记住,现在我们使用我们自己的笔记本电脑来运行这个预测作业,所以这个作业依赖于您当前的 Python 环境。为了避免依赖性或版本问题,最好使用与用于训练模型的运行时版本具有相同库的conda或virtualenv创建一个环境。
步骤 3:在人工智能平台上部署模型
如果最后一步成功,我们现在可以在 AI 平台上创建一个新的模型!
你可以看看平台上的具体板块,不过如果是第一次,应该是空的……

作者图片
要部署我们的管道,我们必须遵循两个步骤:
- 首先,我们创建一个模型实例
- 然后,一个版本的型号出现了
一个模型实例就像一个模型版本的容器。其思想是:用例(如信用卡欺诈检测、交叉销售推荐或收入预测)是模型;用特定数据子集和特定算法(随机森林而不是逻辑回归)训练的实际joblib是版本。通过这种方式,您可以保持同一个用例的多个在线版本,甚至可以从不同的用例中获得预测。
第一步非常简单:要创建一个新的模型实例,只需运行
gcloud ai-platform models create your_model_name \
— region your-region
- 型号名称只能包含字母、数字和下划线(没有连字符!)
- 和往常一样,要选择地区,一个好的经验法则是选择离你当前位置最近的。
您可以使用检查模型是否开启
gcloud ai-platform models list —-region your-region
现在第二步:创建我们模型的第一个版本。
gcloud ai-platform versions create your_version_name \
— model your_model_name \
— origin gs://your-bucket/path-to/model-directory \
— region your_region \
— framework scikit-learn \
— python-version 3.7 \
— runtime-version 2.2 \
— machine-type n1-standard-4
- 至于型号名称,版本名称应该只包含字母、数字和下划线
origin参数与本地测试中使用的 GCS 路径相同- 使用为您的云培训工作指定的相同的
python-version和runtime-version。如果您没有使用培训作业来创建您的模型,请选择与您所使用的包版本相同的运行时版本。 - 提供的
machine-type的列表提供了广泛的选择。
要做出正确的调用,你得了解你是否需要 GPU,你的模型神器有多大,你预计你的模型会收到多少预测请求。我选择了一个最简单的机器类型,有 4 个节点。
这可能需要一段时间,所以如果您必须等待几分钟,请不要担心…
与之前一样,您可以检查您的版本是否与在线
gcloud ai-platform versions list \
— model your_model_name \
— region your_region
第四步:实际使用模型!
现在,我们终于可以用新数据查询我们的模型,并获得我们应得的预测。用gcloud命令,超级简单!快跑吧
gcloud ai-platform predict \
— model your_model_name \
— version your_version_name \
— region your_region \
— json-instances ./your-input-file.json
json 输入文件应该与用于本地培训的文件具有相同的结构。例如,使用上面的 2 条记录,我得到
[0, 0]
步骤 5:清除模型
如果您的模型必须保持在线,您就不应该遵循这个步骤,但是出于学习和测试的目的,您应该删除模型和版本,以免产生不必要的成本(从经验上讲…)
运行两者
gcloud ai-platform versions delete your_version_name \
— model your_model_name \
— region your_regiongcloud ai-platform models delete your_model_name \
— region your_region
就是这样!现在你可以在谷歌上管理整个模型的创建,从调优到培训再到部署。
享受,并感谢阅读这篇文章!
重点放在将一个简单的 Flask 应用程序部署到 Heroku 中,与 PostgreSQL 交互和故障排除
专注于后端,没有前端和认证
Flask 是可以用来创建 API 服务器的工具。它是一个微框架,这意味着它的核心功能保持简单,但有许多扩展,允许开发人员添加其他功能(如身份验证和数据库支持)。
Heroku 是一个云平台,开发者可以在这里用多种语言托管应用程序、数据库和其他服务。开发者可以使用 Heroku 来部署、管理和扩展应用。Heroku 也是免费的,只需付费的专业会员资格,而且大多数服务,比如数据库,都提供免费层。
备注:
这个故事将集中在没有前端和认证的应用程序部署和数据库交互上。将提供一个经过测试的示例应用程序,因此您不需要在本地测试它。
我们开始吧。
首先,依赖:基于我的本地设置如下:
- python 3.8(或高于 python 3)
- PostgreSQL 客户端和服务器安装在 Windows 中
- Ubuntu (Windows 子系统):Ubuntu 20.04.2 LTS
- PostgreSQL 客户端和服务器安装在 Ubuntu 中
- Heroku CLI
准备好的烧瓶应用样品
您可以使用下面的示例进行部署。
在我们开始之前,在 PostgreSQL 中创建一个数据库,给出名称,不需要进一步的操作。
create databse local_db_name;
创建应用程序所需的 6 个以下文件
- models.py 定义 PostgreSQL 数据库、表和配置
import os
from sqlalchemy import Column, String, Integer, create_engine
from flask_sqlalchemy import SQLAlchemydb = SQLAlchemy()
'''
setup_db(app):
binds a flask application and a SQLAlchemy service
'''
def setup_db(app): database_name ='local_db_name'
default_database_path= "postgres://{}:{}@{}/{}".format('postgres', 'password', 'localhost:5432', database_name)
database_path = os.getenv('DATABASE_URL', default_database_path)
app.config["SQLALCHEMY_DATABASE_URI"] = database_path
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db.app = app
db.init_app(app)'''
drops the database tables and starts fresh
can be used to initialize a clean database
'''def db_drop_and_create_all():
db.drop_all()
db.create_all()class Movie(db.Model):
__tablename__ = 'movies'
id = Column(Integer, primary_key=True)
title = Column(String(80), unique=True)
release_date = Column(db.DateTime) def __init__(self, title, release_date):
self.title = title
self.release_date = release_date def details(self):
return {
'id': self.id,
'title': self.title,
'release_date': self.release_date,
} def insert(self):
db.session.add(self)
db.session.commit() def delete(self):
db.session.delete(self)
db.session.commit() def update(self):
db.session.commit()
models.py 中有两个数据库路径:
- default_data_path 是本地测试的本地 PostgreSQL 路径
- DATABASE_URL 是 Heroku 数据库 URL,它将由 Heroku 命令生成并保存在 setup.sh 文件中
- 使用 os.getenv(),如果 DATABASE_URL 为空,将直接获取 default_data_path
- app.py: 主应用
import os
from flask import Flask, request, abort, jsonify
from flask_cors import CORS
from models import setup_db, Movie, db_drop_and_create_alldef create_app(test_config=None):
# create and configure the app
app = Flask(__name__)
setup_db(app)
CORS(app) """ uncomment at the first time running the app """
db_drop_and_create_all() @app.route('/', methods=['GET'])
def home():
return jsonify({'message': 'Hello,hello, World!'}) @app.route("/movies")
def get_movies():
try:
movies = Movie.query.order_by(Movie.release_date).all()
movie=[]
movie=[mov.release_date for mov in movies]
return jsonify(
{
"success": True,
"movie name": movie
}
), 200
except:
abort(500) @app.errorhandler(500)
def server_error(error):
return jsonify({
"success": False,
"error": 500,
"message": "server error"
}), 500 return appapp = create_app()if __name__ == '__main__':
port = int(os.environ.get("PORT",5000))
app.run(host='127.0.0.1',port=port,debug=True)
- manage.py :它可以管理数据库模式以及您对它所做的更改。有了这个,Heroku 就可以运行到托管在平台上的数据库的迁移。
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommandfrom app import app
from models import dbmigrate = Migrate(app, db)
manager = Manager(app)manager.add_command('db', MigrateCommand)if __name__ == '__main__':
manager.run()
- Procfile file:指定应用程序启动时执行的命令。
web: gunicorn app:app
- requirements.txt 文件来包含所有的依赖项。
angles==2.0
certifi==2020.4.5.1
chardet==3.0.4
Flask==1.1.2
Flask-Cors==3.0.8
Flask-Migrate==2.5.3
Flask-Script==2.0.6
Flask-SQLAlchemy==2.4.1
Jinja2==2.11.2
jose==1.0.0
Mako==1.1.2
MarkupSafe==1.1.1
psycopg2-binary==2.8.5
pyasn1==0.4.8
python-dateutil==2.8.1
python-editor==1.0.4
python-jose==3.1.0
requests==2.23.0
rsa==4.0
six==1.14.0
SQLAlchemy==1.3.16
urllib3==1.25.9
Werkzeug==1.0.1
xacro==1.13.3
gunicorn==20.0.4
boto==2.49.0
botocore==1.16.5
如果依赖项尚未安装,请使用下面的进行本地安装。这是本地运行。对于在 Heroku 部署,Heroku 将远程搜索,而不是从您的本地端。
pip install -r requirements.txt
6.并且我们还需要创建 setup.sh 文件来保存环境变量(DATABASE_URL),目前添加一行并让其为空。
export DATABASE_URL = ''
现在,文件应该如下所示:

运行本地迁移
对于迁移,运行以下命令:
python3 manage.py db init
python3 manage.py db migrate
python3 manage.py db upgrade
我们可以使用我们的文件运行我们的本地迁移,以反映当我们部署我们的应用程序时 Heroku 将如何在幕后为我们运行。在本地开发环境中,如果数据库有任何变化,我希望同时使用 migrate 和 upgrade 命令,但是在生产环境中,在 Heroku 中,应该在您的本地端使用 migrate,然后在 Heroku 中升级。
现在,文件应该如下所示:

文件夹 migrations 和 pycache 是自动生成的。
现在检查下面的文件夹:
迁移->版本
如果它是空的,创建一个名为'的空文件。保持'(或另一个带点的名称)如下:

如果版本为空,运行 git push 命令时将会出错
manage.run()
......FileNotFoundError: [Errno 2] No such file or directory: '/app/migrations/versions'
部署到 Heroku
假设已经安装了 Heroku CLI。以下命令在 Ubuntu 中运行。
- 开始运行 Heroku 命令
heroku login
它会提示 Heroku 登录页面,点击登录(假设你之前已经注册过),Ubuntu 应该会自动让你登录并提示另一个命令行
2.创建名为 casting-agency-xw 的 Heroku 应用程序
heroku create casting-agency-xw
3.在 Heroku 中创建一个 PostgreSQL 数据库:您需要给出的唯一参数是应用程序名。这个命令将自动生成数据库。
heroku addons:create heroku-postgresql:hobby-dev --app casting-agency-xw
4.检查配置
heroku config --app casting-agency-xw
您将找到如下所示的数据库 URL:
=== casting-agency-xw Config Vars DATABASE_URL: postgres://boozofewcboexi:fXXXXXX
修复 Heroku 上的配置
回到应用程序 setup.sh 文件,将上一步中的 DATABASE_URL 复制到 setup.sh 文件中,如下所示
export DATABASE_URL='postgres://boozofewcboexi:fXXXXXX'
现在部署
你可以在 Heroku-deploy 中使用 Heroku Git 进入下面的页面,如下所示,这与网站上的过程有些不同。
git init
heroku git:clone -a casting-agency-xw
git add .
git commit -am "add new files"
git push heroku master

如果一切正常,应用程序部署如下:

但是如果你去资源,点击 Heroku 数据库,它将显示 0 个表。接下来,我们需要迁移数据库。
迁移数据库
在以下命令下运行:
heroku run python3 manage.py db upgrade --app casting-agency-xw
您将看到表 movies 被添加到数据库中,但是它是空的。接下来,我们给它添加一条记录。
通过 Heroku psql 与数据库交互
确保不仅安装了客户端,还安装了服务器。
如果尝试:psql 版本,结果如下:
psql (PostgreSQL) 12.6 (Ubuntu 12.6-0ubuntu0.20.04.1)
但是运行 psql 返回如下错误,可能是服务器没有安装。
psql: error: could not connect to server: No such file or directory
Is the server running locally and accepting
connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?
stack overflow中的这个链接可能会帮你安装。
正确安装服务器后,它应该如下所示:
Password:
Welcome to Ubuntu 20.04.2 LTS (GNU/Linux 4.4.0-18362-Microsoft x86_64)
postgres=#
现在使用下面的命令连接到 Heroku 数据库:
heroku pg:psql postgresql-clear-05212 --app casting-agency-xw
postgresql-clear-05212 是 Heroku 数据库的名称
现在插入两条记录:

让我们检查一下端点:
开放端点:

获取电影端点:/movies,它看起来像:

现在删除一条 id =1 的记录:

端点将如下所示:

结果和我们预料的一样。
小费:
- 首先,在 deployment 中,取消对 db_drop_and_create_all()的注释以生成表,但是如果您已经进行了更改,并且希望 git 推送这些更改,请注释此命令,因为它将与 Heroku 中的现有表冲突。
""" uncomment at the first time running the app """
db_drop_and_create_all()
2.如果部署正常,数据库也可以工作,但是错误代码 503,一种可能是它可能有以前的流量冲突。使用下面的比例动态
heroku ps:scale web=0
等待一会儿(可能 30 秒),然后尝试以下操作:
heroku ps:scale web=1
2.如果需要更新该表,请在本地运行 db migrate 并在 Heroku 上升级。
3.了解表格生成过程:
init:创建 alembic _versoin 表,供 alembic 内部使用
migrate:检查 models.py,并将其与数据库中的实际内容进行比较。
根据本地设置,部署可能会有所不同。
感谢您的阅读。
参考:
- Udacity 全栈 web 开发人员课程
用 App Engine 在 10 分钟内部署一个 Node.js 应用!
在 Google 云平台的应用程序引擎上部署简单 node.js 应用程序的演练。

埃米尔·佩龙在 Unsplash 上的照片
谷歌云的应用引擎允许你在一个完全由谷歌管理的平台上部署可扩展的网络应用。这些应用的范围可以从后端服务和 API 层到运行在 Angular 和 React 框架上的前端应用。谷歌免费提供每天 28 小时的运行时间,这样你就可以免费托管了!
在本文中,我将带您在这个 App Engine 平台上部署一个简单的 Node.js 应用程序。
先决条件
要跟进,您应该具备以下条件:
- 对 Node.js 工作原理的基本理解
- 安装在本地机器上的节点
- 一个谷歌云平台账户和一个项目
让我们构建并部署我们的应用程序吧!
创建项目
在本地机器上初始化一个新的 Node.js 项目。
mkdir helloworld
cd helloworld
npm init
在helloworld文件夹中创建一个包含以下内容的简单执行文件index.js:
*const* express = require('express');
*const* app = express();app.get('/', (*req*, *res*) *=>* {
*res*.send('GCP App Engine!');
});*const* PORT = process.env.PORT || 8080;app.listen(PORT, () *=>* {
console.log(`Server listening on port ${PORT}...`);
});
我们的应用程序不会做太多事情,只是在被调用时返回一个'GCP App Engine!'字符串。
将以下启动脚本和 express 依赖关系添加到创建的package.json文件中:
{
...
*"scripts"*: {
*"start"*: "node index.js"
},
*"dependencies"*: {
*"express"*: "^4.16.3"
}
}
Express 不是必需的,我使用它来简化部署。应用程序引擎将使用启动脚本来启动您的应用程序。请注意,index.js与我上面创建的主执行文件的名称相匹配。
安装依赖项(快速)并确保您的应用在本地运行:
npm install
node index.js
导航到 http://localhost:8080 ,您应该会看到:

作者图表
应用程序已经准备就绪,但我们需要向应用程序引擎提供一些信息,以便它知道如何部署我们的代码。我们使用一个 YAML 文件来完成这项工作。这个文件中的配置会变得非常复杂,有很多选项需要配置,但是在我们的例子中,我会保持简单。在helloworld文件夹中创建一个名为app.yaml的文件,并添加以下内容:
runtime: nodejs14
env: standard
instance_class: F1
automatic_scaling:
min_idle_instances: automatic
max_idle_instances: automatic
min_pending_latency: automatic
max_pending_latency: automatic
我的 Node.js 运行时版本是 14.16.0,如果您的版本不同,请随意更改运行时。我们将使用一个标准环境和一个 F1 实例,因为这些都包含在 GCP 的免费配额中。
在这一点上,你应该有下面的文件结构,我们准备开始迁移我们的代码到 GCP。
├── helloworld
│ ├── index.js
│ ├── package.json
│ ├── app.yaml
迁移您的代码
在部署应用程序之前,您需要将代码提供给 GCP。您可以通过在本地机器上利用 Cloud SDK 或使用 Cloud Shell 来实现这一点,正如我将在本演练中所做的那样。
在将代码推送到应用引擎之前,我将使用一个云存储桶来存放我的代码。创建一个新的存储桶来存放您的源代码(如果需要,您可以重用现有的存储桶)。对于区域,您应该设置 Regional,其他设置可以保留默认值。在我的例子中,我正在创建一个名为sample-code-repo的桶,并将整个 helloworld 文件夹上传到根目录。

作者图表
接下来,我们需要将代码上传到云壳虚拟机,你可以通过从任何 GCP 控制台页面打开云壳终端或点击此处来完成。

作者图表
要在云 Shell 虚拟机上创建所需的文件夹结构,并同步 bucket 中的代码,请运行以下命令,将sample-code-repo/helloworld替换为<source-code-bucket-name>/<app-folder-name>:
mkdir helloworld
cd helloworld
gsutil rsync -r gs://sample-code-repo/helloworld .
您将被要求授权存储桶访问(弹出窗口),一旦完成,运行ls命令将确认数据复制:

作者图表
如果您有其他将代码迁移到云 Shell 的首选方法(例如 git),请随意使用。至此,我们的项目已经可以部署了。
部署应用程序
要在 App Engine 上部署应用程序,我们需要返回到我们的云外壳虚拟机并运行以下程序:
cd helloworld
gcloud app deploy
对于您的第一个应用引擎部署,您将需要指定一个区域——我使用了us-central作为我的区域。代码将需要一分钟的时间来编译,一旦完成运行gcloud app browse将输出一个链接,您可以使用它来访问您现在部署的应用程序!

作者图表
结论
谷歌的应用引擎是一个免费快速在线部署应用程序的伟大平台。在本文中,我向您介绍了如何将这个平台用于 Node.js 应用程序,但是使用 Java、Python、PHP 和 Go 也可以获得相同的结果。我希望你能从这篇文章中学到一些东西。
祝好运,编码快乐!
原载于 2021 年 4 月 11 日 https://theappliedarchitect.comhttps://theappliedarchitect.com/deploy-a-node-js-application-with-app-engine-in-10-minutes/。
部署生产就绪的本地 Kubernetes 集群
走向现代软件架构
你需要考虑的几件事
去年在疫情期间,我有机会自己部署了一个本地 Kubernetes。在本文中,我想标记一些事情来提醒我,并告诉您在部署本地 Kubernetes 时应该知道的所有事情。

库贝斯普雷
Kubespray 使用 Ansible 行动手册作为库存和供应工具,帮助我们部署通用的 Kubernetes 集群。它还处理我们的配置管理任务。它自动化了你部署 Kubernetes 的所有困难。你所需要的只是修改 Kubespray 提供的 YAML 文件配置。以下指南是从 Kubespray 的文档中复制的,您可以在这里查看:
https://github.com/kubernetes-sigs/kubespray
首先,您需要 git 克隆存储库并使用 pip 安装 Python 需求。
git clone [https://github.com/kubernetes-sigs/kubespray.git](https://github.com/kubernetes-sigs/kubespray.git)
# Install dependencies from ``requirements.txt``
sudo pip3 install -r requirements.txt
如果您无法安装 Ansible,请查看以下链接:
https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html
清单文件夹中有一个样本清单。您需要复制并命名您的整个集群(例如 mycluster)。存储库已经为您提供了库存构建器来更新 Ansible 库存文件。
# Copy ``inventory/sample`` as ``inventory/mycluster``cp -rfp inventory/sample inventory/mycluster# Update Ansible inventory file with inventory builderdeclare -a IPS=(10.10.1.3 10.10.1.4 10.10.1.5)CONFIG_FILE=inventory/mycluster/hosts.yaml python3 contrib/inventory_builder/inventory.py ${IPS[@]}
接下来,你要修改inventory/mycluster/hosts.yml。下面是一个示例,它将三个节点设置为主节点,将另外三个节点设置为工作节点。etcd 与主设备位于相同的节点中。
all:
hosts:
node1:
ansible_host: 192.168.0.2
ip: 192.168.0.2
access_ip: 192.168.0.2
node2:
ansible_host: 192.168.0.3
ip: 192.168.0.3
access_ip: 192.168.0.3
node3:
ansible_host: 192.168.0.4
ip: 192.168.0.4
access_ip: 192.168.0.4
node4:
ansible_host: 192.168.0.5
ip: 192.168.0.5
access_ip: 192.168.0.5
node5:
ansible_host: 192.168.0.6
ip: 192.168.0.6
access_ip: 192.168.0.6
node6:
ansible_host: 192.168.0.7
ip: 192.168.0.7
access_ip: 192.168.0.7
children:
kube-master:
hosts:
node1:
node2:
node3:
kube-node:
hosts:
node4:
node5:
node6:
etcd:
hosts:
node1:
node2:
node3:
k8s-cluster:
children:
kube-master:
kube-node:
calico-rr:
hosts: {}
因为 Ansible 将与您的主机建立 SSH 连接,所以必须将 Ansible 主机的 SSH 密钥复制到清单中的所有服务器或主机。您需要做的是:
- 用
ssh-keygen生成一个 SSH 密钥 - 使用
ssh-copy-id -i ~/.ssh/mykey user@host将密钥复制到服务器
现在,您需要检查并更改集群的参数。有些方面你应该考虑。
# Review and change parameters under ``inventory/mycluster/group_vars``cat inventory/mycluster/group_vars/all/all.ymlcat inventory/mycluster/group_vars/k8s-cluster/k8s-cluster.yml
主节点 HA API 服务器负载平衡器
第一个是为 API 服务器的高可用性设置一个负载平衡器。负载平衡器用于在我们的一个主节点不工作时防止服务失败。通常我们会设置至少三个主服务器。您可以在文档的 K8s 的 HA 端点部分找到更多详细信息。
https://github.com/kubernetes-sigs/kubespray/blob/master/docs/ha-mode.md
对于生产就绪的 Kubernetes 集群,我们需要使用外部负载平衡器(LB)而不是内部 LB。外部 LB 为外部客户机提供访问,而内部 LB 只接受到本地主机的客户机连接。
我使用ha proxy+keepalive来配置一个高可用的负载平衡器。设置了两个虚拟机来执行负载平衡器功能。我提到的参考资料来自这个网站:
文章虽然有点老,但是概念是一样的,程序也挺像的。
给定前端的
VIP地址和后端的IP1, IP2地址,下面是作为外部 LB 的 HAProxy 服务的配置示例:
#/etc/haproxy/haproxy.cfglisten kubernetes-apiserver-httpsbind <VIP>:8383mode tcpoption log-health-checkstimeout client 3htimeout server 3hserver master1 <IP1>:6443 check check-ssl verify none inter 10000server master2 <IP2>:6443 check check-ssl verify none inter 10000balance roundrobin
然后,您需要更改外部负载平衡器配置。同样,配置是从文档中 K8s 部分的 HA 端点复制的。
#kubespray/inventory/mycluster/group_vars/all/all.yml## External LB example config## apiserver_loadbalancer_domain_name: "elb.some.domain"# loadbalancer_apiserver:# address: <VIP># port: 8383
代理人
如果您的集群不能直接访问互联网,并且在像我这样的公司代理后面,您将在部署过程中经历痛苦…确保您在kubespray/inventory/mycluster/group_vars/all/all.yml中添加您的代理设置
将您的代理添加到http_proxy ,并在additional_no_proxy 部分添加您不希望您的集群通过代理访问的域/IP。(重要!)
从外部访问 kubectl
如果您的主虚拟机有两个网络接口,并且您需要从 Kubernetes 使用的接口之外的另一个接口访问 Kubernetes,您需要在配置文件中添加补充地址:
## Supplementary addresses that can be added in kubernetes ssl keys.## That can be useful for example to setup a keepalived virtual IPsupplementary_addresses_in_ssl_keys: [10.0.0.1, 10.0.0.2, 10.0.0.3]
负载平衡器
为了让您的用户访问部署在 Kubernetes 中的服务,您需要公开您的服务。从集群外部访问有三种方式:入口、负载平衡器和节点端口。为了在内部实施负载平衡器类型的服务,我们选择了 MetalLB 来为我们处理网络负载平衡功能。 MetalLB 是裸机 Kubernetes 集群的负载平衡器实现,使用标准路由协议。
使用 Kubespray 安装 MetalLB 非常容易。你只需要修改插件 YAML 文件和 k8s 集群 YAML 文件。请注意,您分配给 MetalLB 的 IP 范围必须由您自己预先准备。
# kubespray/inventory/mycluster/group_vars/k8s-cluster/addons.ymlmetallb_enabled: truemetallb_ip_range: - “10.5.0.50–10.5.0.99”
请记住将参数 kube_proxy_strict_arp 设置为 true。
# kubespray/inventory/mycluster/group_vars/k8s-cluster/k8s-cluster.yml# must be set to true for MetalLB to workkube_proxy_strict_arp: true
部署
最后,您可以使用 Ansible 行动手册部署 Kubespray!根据您的群集大小和网络吞吐量,群集大约需要 15–30 分钟才能准备好。之后,您就可以使用您的 Kubernetes 集群了!
# Deploy Kubespray with Ansible Playbook - run the playbook as root# The option `--become` is required, as for example writing SSL keys in /etc/,# installing packages and interacting with various systemd daemons.# Without --become the playbook will fail to run!ansible-playbook -i inventory/mycluster/hosts.yaml --become --become-user=root cluster.yml

Guille Álvarez 在 Unsplash 上拍摄的照片
在将应用程序部署到 Kubernetes 集群之前,我们还有很长的路要走。
舵
Helm 是 Kubernetes 的包装经理。在赫尔姆的官方网站上,它写道
Helm 是查找、共享和使用为 Kubernetes 构建的软件的最佳方式。Helm 帮助您管理 Kubernetes 应用程序— Helm Charts 帮助您定义、安装和升级最复杂的 Kubernetes 应用程序。
要安装 Helm,最简单的方法是通过脚本安装:
$ curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3$ chmod 700 get_helm.sh$ ./get_helm.sh
您可以获取该脚本,然后在本地执行它。它有很好的文档记录,因此您可以通读它,并在运行它之前了解它在做什么。
https://helm.sh/docs/intro/install/
进入
为了让您的用户访问部署在 Kubernetes 的服务,您需要公开您的服务。有三种从集群外部访问的方式:入口、负载平衡器和节点端口。在生产中,不建议使用节点端口,因为它缺乏可用性。对于负载平衡器,我们已经使用 MetalLB 实现了。现在,我们将实现入口。请查看本网站入口的详情:
https://kubernetes.io/docs/concepts/services-networking/ingress/
根据官方 Kubernetes 文档的描述,入口公开了从集群外部到集群内服务的 HTTP 和 HTTPS 路由。流量路由由入口资源上定义的规则控制。入口控制器控制入口资源。我使用的那个叫做 NGINX 入口控制器。您可以使用 Helm 轻松安装。
https://docs.nginx.com/nginx-ingress-controller/installation/installation-with-helm/
helm repo add nginx-stable https://helm.nginx.com/stablehelm repo updatehelm install my-release nginx-stable/nginx-ingress
储存;储备
pod 中的数据是短暂的,如果您希望数据持久化,您可以将数据存储在持久性卷中。根据 Kubernetes 官方文档的描述,持久卷 (PV)是集群中的一块存储,由管理员提供或使用存储类动态提供。
https://kubernetes.io/docs/concepts/storage/persistent-volumes/
每个存储类都有一个处理卷分配的置备程序。我选的是长角牛。根据 Longhorn 官方文档的描述,它指出
Longhorn 是一个轻量级的、可靠的、功能强大的分布式块存储系统。Longhorn 使用容器和微服务实现分布式块存储。它为每个块设备卷创建一个专用的存储控制器,并跨存储在多个节点上的多个副本同步复制该卷。存储控制器和副本本身是使用 Kubernetes 编排的。
这使得我们的存储没有单点故障。它还有一个直观的 GUI 控制面板,您可以在其中查看卷的所有详细信息。
以下安装指南复制自 Longhorn 官方文档:
安装长角牛
1.添加长角牛头盔存储库:
helm repo add longhorn https://charts.longhorn.io
2.从存储库中获取最新图表:
helm repo update
3.在 longhorn-system 命名空间中安装 Longhorn。
kubectl create namespace longhorn-systemhelm install longhorn longhorn/longhorn --namespace longhorn-system
4.要确认部署成功,请运行:
kubectl -n longhorn-system get pod
如果准备就绪,您应该会看到所有 pod 都在运行。
登记处
您需要一个注册表来存储您开发的 docker 图像。其中一个开源选择是 Harbor。
同样,你可以很容易地安装舵图港。我用的那个是 bitnami 维护的:
https://github.com/bitnami/charts/tree/master/bitnami/harbor/#installing-the-chart
结论
最后,我将带您了解一个本地 Kubernetes 集群的整个安装过程。让我们做一个简单的清单:
- 库贝斯普雷
- 可变配置
- 主节点 HA API 服务器负载平衡器(HAProxy + keepalived)
- 代理设置
- 从集群外部配置 kubectl 访问
- 服务公开:负载平衡器和入口
- 包管理:掌舵
- 存储:长角牛
- 内部图像存储库:注册表
还没有…
它仍然只涵盖了生产就绪的 Kubernetes 集群的一部分,我仍在探索中。其他重要的方面,如监控(如普罗米修斯& Grafana),安全(RBAC/用户管理),CICD(阿尔戈)等,在这篇文章中仍然没有
欢迎来到库伯内特的世界!
如果您想知道如何准备认证 Kubernetes 应用程序开发人员(CKAD)考试,请查看这篇文章:
你可能也想检查下面的附属链接。
免费部署一个公共的 Streamlit Web 应用程序—方法如下
Google Sheets 作为其后端,由 Streamlit Sharing 托管

随着 Python 越来越受欢迎,成为许多数据科学家的首选,传播他们的发现已经成为一种迫切的需要。Web 应用程序代表了一种跨平台的解决方案,它提供了足够的交互性。然而,传统的开发需要 Python 用户充分熟悉相对复杂的 web 框架,如 Flask 和 Django。尽管对于任何有经验的 Python 用户来说,学习这些框架并不是最难的事情,但对于数据科学家来说,展示他们的数据科学项目可能有点过头了。
幸运的是,我们数据科学家现在有了一个更好的选择——Streamlit 框架。它只需在几分钟内将简单的 Python 脚本转换成实用的、交互式的、可共享的 web 应用程序。因为它是为展示数据科学产品而设计的,所以它本身支持主要数据科学库的数据模型和图形,如 pandas 和 matplotlib。因此,如果您已经非常了解 Python,那么它不需要什么学习曲线。如果您还没有尝试过,这里有一些我以前发表的文章,可以帮助您开始使用 streamlit。
</8-simple-and-useful-streamlit-tricks-you-should-know-ad16c6691b84>
在本文中,我想进一步向大家展示如何发布 web 应用程序,以便其他人可以公开访问您的数据科学项目。更重要的是,我将向您展示如何将 Google Sheets 集成为我们项目的免费数据库主机。请注意,Google Sheets 不是一个行业级的数据库,但它足以容纳一个小型数据集。更重要的是,它是免费的。
事不宜迟,让我们开始吧。
第一步。在本地构建 Web 应用程序
首先,我想确保你已经在电脑上安装了 streamlit,并且能够在本地启动 web 应用程序。
1.1.安装 Streamlit
您可以使用 pip 工具安装 streamlit 框架:pip install streamlit。
只需查看版本:streamlit --version即可检查是否安装。这个命令应该告诉您所安装的 streamlit 包的版本。在我写这篇教程的时候,显示的版本信息是Streamlit, version 0.89.0。
1.2.创建应用程序的脚本
创建一个 Python 脚本文件,我们姑且称之为streamlit_sharing.py。因为本教程的目标是向您展示如何发布 web 应用程序,所以我们将尽量减少应用程序中的内容。假设该脚本包含以下代码行。
简化共享—基本设置
1.3.在本地启动应用程序
要在本地启动应用程序,在终端中,您可以运行以下命令:streamlit run streamlit_sharing.py。请确保您需要导航到保存 Python 脚本的目录。否则,您必须指定文件的完整路径。

本地 Streamlit Web 应用程序
上面的屏幕截图显示了在本地主机上运行的 web 应用程序。太好了!您已经启动了您的第一个 Streamlit web 应用程序。
第二步。连接到 Google 工作表
我们应该理解,Streamlit 支持到许多不同类型的数据库的连接,但是在线数据库主机通常不是免费的。为了向您提供概念证明,我们将使用一个公开的 Google 工作表作为我们 web 应用程序的数据源。假设我们的工作表有以下数据。
2.1.创建一个 Google 表单
谷歌表单中的数据
2.2.分享工作表
创建 Google 工作表后,请打开公开共享,以便我们的 web 应用程序可以直接访问它。

启用公共共享
重要提示:为了保持应用程序的简单,我们将只考虑使用公共谷歌表单的设置。如果你想使用一个私人的谷歌表单,它需要启用谷歌 API,感兴趣的读者可以参考 Streamlit 的网站获取更多说明。
2.3.使用 gsheetsdb 连接板材
为了以编程方式访问 Google sheet,我们需要通过运行pip install gsheetsdb来安装包[gsheetsdb](https://github.com/betodealmeida/gsheets-db-api)。安装完成后,我们可以将脚本更新到以下版本:
整合谷歌表单
上述代码涉及以下更改:
- 我们使用
gsheetsdb来连接到谷歌表单。 - 为了使用该表,我们使用类似 SQL 的语法来检索数据。值得注意的是,我们需要指定工作表的 URL,而不是指定工作表的名称。不要忘记工作表 URL 的双引号。
- 我们从检索到的行中创建一个
DataFrame对象。
有了所有这些变化,我们的 web 应用程序现在看起来如下。如您所见,我们确实能够从创建的 Google sheet 中检索数据。

更新的 Web 应用程序
第三步。公开部署应用程序
3.1.创建 Streamlit 共享帐户
有不同的选项来托管一个 Streamlit 应用程序,比如 Heroku(你可以在一篇中型文章中找到教程)。在这里,我想向您展示如何使用 Streamlit Share——Streamlit 提供的免费 Streamlit web 应用程序共享服务。你可以在它的官方博客找到更多信息。以下是一般步骤。
- 由于 Streamlit 团队仍在开发该平台,您需要请求邀请才能在 Streamlit Share 上部署该应用程序。您可以在这里提交请求:【https://streamlit.io/cloud
- 一旦你提交了你的请求,他们很快就会批准你的请求。就我而言,不到一天就收到了邀请。
- 您现在可以使用您的 GitHub 身份验证登录 Streamlit 共享(https://share.streamlit.io/)。
3.2.更新您的脚本文件
接下来你会看到,我们将在一个公共的 GitHub 存储库中共享我们的应用,因此我们不想暴露 Google sheet 的 URL,这可能是一个潜在的安全问题。当然,使用私有的谷歌表单或其他数据库进行认证更加安全。
您可以将 URL 存储在共享应用程序的设置中,而不是直接在脚本中指定 URL,这样您就可以使用设置的名称进行访问。
# Original
gsheet_url = "the_link"# Updated, when the URL is saved in the settings
gsheet_url = st.secrets["public_gsheets_url"]
3.3.创建一个公共 GitHub 库
一旦你更新了你的脚本,就终于到了公开你的应用程序的时候了(在某种程度上)。您要做的是创建一个公共的 GitHub 存储库。在这里,我不打算详述您如何做到这一点。我使用 PyCharm,我只需要使用内置的 Git 工具就可以轻松地创建一个存储库。
3.4.分享 Web 应用程序!
转到 Streamlit Share 网站,你可以通过点击“新建应用”来创建一个新的 web 应用,它会弹出如下图所示的窗口(左图)。


如果你已经链接了你的 GitHub 账户,Streamlit 足够智能,可以拉出存储库列表,你可以简单地选择一个并指定文件路径。
重要的是,您单击“高级设置”并在那里指定链接,因为如前所述,这是我们的 streamlit 脚本文件访问机密信息的方式。需要时,您需要为您的项目选择合适的 Python 版本,因为默认情况下,它被设置为 3.7。
之后,单击“部署!”按钮,等待几分钟,您应该能够看到您的应用程序启动并运行!

公共 Web 应用程序
因为它是由 Streamlit Share 作为公共网站托管的,所以你可以将链接分享给你的队友或客户,他们可以从他们想要的任何地方访问它。
最后的话
Streamlit 使数据科学家开发 web 应用程序变得容易,因为它负责 web 元素的布局,而我们数据科学家只负责我们应用程序的核心部分——数据。
如果您从未尝试过 Streamlit,我强烈建议您尝试一下,我敢打赌您会爱上它。
感谢阅读这篇文章。通过注册我的简讯保持联系。还不是中等会员?用我的会员链接支持我的写作。
将 Python 可视化面板应用程序部署到谷歌云应用程序引擎
谷歌云应用引擎和 Github 操作

由pix poeties在 Unsplash 拍摄的照片
相关文章: Python 可视化面板 App to Google Cloud Run:Google Cloud Run、Google Cloud Build、Terraform
在不了解 Docker 或 Kubernetes 以及不使用 Docker 文件的情况下,有可能将 Python 应用程序或仪表板部署到云上吗?是的,这是可能的,而且使用谷歌云应用引擎非常简单!本文将向您展示如何使用三个简短的脚本将 Panel 应用程序部署到 Google Cloud,并展示如何使用 Github 操作自动化您的工作流程。
这是我的非常简单的示例应用程序的样子。这里托管(我会保持 3 个月的直播)。关于面板应用的更多例子和灵感,请查看awesome-panel.org、panel.holoviz.org,以及我之前关于 HoloViz 工具的博文。

这篇文章中提到的所有代码都可以在这个回购:https://github.com/sophiamyang/panel_gcp。
1。设置
设置您的 Google Cloud 帐户以启用应用程序引擎:
应用引擎文档(https://cloud . Google . com/App Engine/docs/standard/python 3/quick start)描述了运行项目所需的四个步骤:
- 选择或创建一个 Google Cloud 项目(我们假设项目名称和 ID 都是“您的项目”)
- 启用应用引擎 API
- 启用云构建 API
- 启用计费
在本地机器上安装并初始化 Google Cloud SDK:
- 安装 Google Cloud SDK :操作系统不同,说明也会有所不同,或者您可以简单地
conda install -c conda-forge google-cloud-sdk
- 初始化 gcloud:
gcloud init - 将项目设置为“您的项目”(或您用于您的项目的任何名称/ID):
gcloud config set project your-project
2.创建面板应用
创建一个新目录,或者在这个目录中创建以下三个文件,或者从我的 repo 中获取:https://github.com/sophiamyang/panel_gcp
app.py
这是创建 Panel 应用程序的 Python 文件。要在本地运行这个应用程序,你可以简单地做conda install panel hvplot并运行panel serve app.py
requirements.txt
该文件列出了我们的 Panel 应用程序的所有包依赖项。
app.yml
这是应用程序引擎配置文件。面板应用是散景应用的一种,散景应用需要指定env:flex和entrypoint: panel serve app.py --adddress 0.0.0.0 --port 8080 --allow-websocket-origin="*",因为应用引擎灵活环境支持 WebSockets。其他类型的应用可能不需要 flex 环境和入口点。
3。将 Panel 应用部署到谷歌云应用引擎
- 初始化您的应用引擎应用:
gcloud app create - 部署您的应用:
gcloud app deploy
在 gcloud 努力设置好你的项目几分钟后,你应该可以在your-project.ue.r.appspot.com上看到你的仪表盘直播了。
就是这样!现在,你可以与任何想使用你的应用的人共享该网址。
如果您的部署有任何问题,检查日志和调试可能会有所帮助:https://console.cloud.google.com/debug
查看整体信息:https://console.cloud.google.com/appengine
查看版本:https://console.cloud.google.com/appengine/versions
4.为自动化设置 Github 动作
在实践中,当您开发和改进 Panel 应用程序时,您通常会希望随着时间的推移重新部署它的不同版本,同时保留文件的每个版本的记录。为了简化这个过程,您可能会发现 Github 动作非常有用。有了 Github Actions,我们可以建立一个工作流,每当我们推送变更、标记发布或获得 PR 时,一些构建、测试或部署流程就会运行。
- 首先,我们需要按照这些文档到中的步骤创建一个服务帐户,向您的服务帐户添加一个密钥,并将密钥下载到一个 JSON 文件中。
- 启用应用引擎管理 API
- 现在,如果您还没有这样做,创建一个新的 Github repo,并将第 3 节中的所有三个文件添加到这个 repo 中,并将其推送到 Github。
- 进入你的 Github repo-Settings-Secrets,添加两个秘密
GCP 凭据:从您刚刚下载的 JSON 文件中复制并粘贴密钥
GCP 项目:你的项目的名字,在上面的例子中是“你的项目”。

- 增加一个。您目录中的 github / 工作流 /python-app.yml 文件
这是一个 Github 操作配置文件。在这个例子中,每当有主分支的推送时,我们将应用部署到 Google Cloud 应用引擎。
现在您的 Github 操作应该已经准备好了。您可以在“操作”选项卡上查看跑步信息。在这里,我尝试添加另一个应用程序,工作流程自动开始运行。

现在,您可以看到我们有两个应用程序正在运行

总的来说,本文使用三个简单的脚本将可视化面板应用程序部署到 Google Cloud App Engine,并使用另一个配置文件来设置 Github 操作。你可能会想,为什么我不用 Google Cloud Run 或者 AWS?我写了另一篇关于 Google Cloud Run 的文章。来看看: Python 可视化面板应用到 Google Cloud Run: Google Cloud Run,Google Cloud Build,和 Terraform 。就 AWS 而言,我在 Anaconda 的朋友们正在研究一些非常酷的东西,以帮助简化 AWS 的部署过程,预计将在 2022 年的某个时候推出。敬请期待!
对于那些对视频教程感兴趣的人,这里是本文的视频版本:
参考文献:
- https://cloud . Google . com/app engine/docs/standard/python 3/runtime # application _ startup
- https://cloud . Google . com/app engine/docs/flexible/python/quick start
鸣谢:感谢 Jim Bednar 和 Philipp Rudiger 的支持和指导。
作者索菲亚·杨 2021 年 12 月 18 日
将 Python 可视化面板应用程序部署到 Google Cloud Run
Google 云运行、Google 云构建和 Terraform

小塔德乌在 Unsplash 上的照片
相关文章:部署一个 Python 可视化面板 App 到 Google Cloud App Engine:Google Cloud App Engine 和 Github Actions 。
在我上一篇博客文章中,我写了如何将 Python 可视化面板应用部署到谷歌云应用引擎。App Engine 运行良好,但它可能很贵,因为无论是否有人使用它,应用程序都会持续运行。幸运的是,有一个更便宜的选项叫做 Cloud Run,它只在收到请求时运行。
在本文中,我将带您了解如何使用三个简单的脚本将 Python 应用程序或仪表板部署到 Google Cloud Run,以及如何通过 Cloud Build 和 Terraform 自动化您的 Google Cloud 设置。
这是我的非常简单的示例应用程序的样子。它被托管在这里,在这篇文章发表后,它将在这里生存 3 个月。关于面板应用的更多例子和灵感,请查看awesome-panel.org、panel.holoviz.org,以及我之前关于 HoloViz 工具的博文。

1.设置
设置您的 Google Cloud 帐户:
云运行文档描述了运行项目所需的以下步骤:
- 选择或创建一个谷歌云项目(我们假设项目名称和 ID 都是“你的项目”)
- 启用计费
在本地机器上安装并初始化 Google Cloud SDK:
- 安装谷歌云 SDK :操作系统不同,说明也会有所不同,或者你可以简单地
conda install -c conda-forge google-cloud-sdk
- 初始化 gcloud:
gcloud init
- 将项目设置为“您的项目”(或您用于您的项目的任何名称/ID):
gcloud config set project your-project
2.创建面板应用程序
创建一个新目录,或者在这个目录中创建以下三个文件,或者从我的 repo 中获取:https://github.com/sophiamyang/panel_cloud_run。
app.py
这是创建 Panel 应用程序的 Python 文件。要在本地运行这个应用程序,您可以简单地执行conda install panel hvplot并运行panel serve app.py。
requirements.txt
该文件列出了我们的 Panel 应用程序的所有包依赖项。
Dockerfile
Dockerfile 安装 Python 和这个项目的依赖项,然后运行命令panel serve来运行我们的面板应用程序。
3.将应用程序部署到 Google Cloud Run
部署您的应用程序(选择服务文件夹):
gcloud run deploy
在 gcloud 努力设置您的项目几分钟后,您应该能够在命令行中看到的服务 URL 上看到您的仪表板,该 URL 将类似于“service-xxx-uc.a.run.app”。
4.通过云构建和 Terraform 将应用程序部署到 Google Cloud Run
这一步对于我们这个简单的 app 来说是没有必要的。但是当你的应用变得复杂,并且有很多应用需要管理时,使用 Terraform 通常是一个好的做法。Terraform 是一个“作为编码软件工具的开源基础设施”。
在步骤 3 中,当我们通过gcloud run deploy部署应用程序时,我们在命令行中做了很多决定。例如,我们设置了项目的区域,启用了一些需要的 API,并允许未经身份验证的调用来服务。Terraform 允许我们在代码中捕捉所有这些决策,这样我们就有一个地方来查看基础设施是如何设置的。
要将 Terraform 与 Google Cloud Run 结合使用,需要两个部分:
第 1 部分是使用 cloudbuild.yaml 文件构建一个容器映像来执行您的应用程序(即“构建映像”步骤),并将您的容器映像推送到工件注册表(即“推映像”步骤)。
cloudbuild.yaml
运行以下命令:
- 你可能需要认证
gcloud auth application-default login gcloud builds submit
使用 Google Cloud Build 提交构建。完成这一步后,您应该会在 https://console . cloud . Google . com/gcr/images/your-project/global/docker 看到您的容器映像,因为-project 是您的项目 ID,docker 是我们在 cloudbuild.yaml 文件中定义的服务名。
第 2 部分是使用 terraform 从我们刚刚创建的容器映像创建一个 Google Run 服务。
main.tf
这个 terraform 配置文件为我们创建了一个“project”变量,以便在命令行上定义项目,启用云运行服务,指定云运行服务来运行我们刚刚在第 2 部分中创建的容器映像,设置服务公共,并返回一个服务 URL。
运行以下命令:
- 如果在本地运行:
conda install -c conda-forge terraform - 初始化地形:
terraform init - 创建一个执行计划,给我们一个回顾的机会:
terraform plan -var project=your-project - 执行地形计划:
terraform apply -var project=your-project
几分钟后,您应该会在命令行中看到您的应用程序 URL:demo-XXX-UC . a . run . app。
然后如果您想要移除云运行服务,terraform destroy -var project=your-project或者删除整个项目。
此外,正如这篇 Google Cloud 博文中提到的,对于持续部署的开发,请查看“使用 Terraform、Cloud Build 和 GitOps 将基础设施作为代码进行管理”。
总的来说,本文使用三个简单的脚本将一个可视化面板应用程序部署到 Google Cloud Run,并使用另外两个文件来设置 Google Cloud Build 和 Terraform。
对于那些对视频教程感兴趣的人,这里是本文的视频版本:
参考文献:
- https://cloud . Google . com/run/docs/quick starts/build-and-deploy/python
- https://cloud . Google . com/blog/topics/developers-从业者/可预测-无服务器-部署-地形
- https://github . com/Google cloud platform/server less-expeditions/tree/main/terraform-server less
- https://cloud . Google . com/solutions/managing-infra structure-as-code
鸣谢:感谢吉姆·贝德纳的指导和支持!
索菲娅·杨 2021 年 12 月 24 日
部署 NLP 管道。烧瓶+Heroku+Bert。
逐步指南
部署 NLP 项目的简单、快速的解决方案,以及您在部署过程中可能面临的挑战。

皮查拜在Pexels.com拍摄的照片
介绍。
通常,作为一名数据科学家,您可能会面临一项包括完整管道的任务:从数据收集到在服务器上部署应用程序。我在找工作的面试过程中撞见了这样一份奇奇怪怪的工作。重点不是开发最准确或最复杂的模型,而是展示对机器学习和 NLP 概念的良好理解。
在本文中,我将向您展示如何部署 Bert 模型和预处理管道。为了部署应用程序,我使用了 Heroku 服务器和 Flask Python 框架。
任务和问题描述。
这个任务的基础是一篇名为识别假新闻和讽刺的细微差别:使用语义和语言线索的论文。本文介绍了两种将文本内容分类为“讽刺”或“假新闻”的模型——一种基于 Google 的 BERT 模型,另一种基于 coherence metrics 模型。
这项任务的目标是:
- 发展一个新的模式来分类“讽刺”或“假新闻”;
- 构建一个演示 web 应用程序来服务于模型预测;
- 将其部署到云服务 Heroku
您可以选择任何型号,该型号将具有以下特点:
1.BERT 嵌入(向量)——使用代表每个文本的句子转换器库。
2.每个文本的情感和形态—使用模式库。
这个项目的简单结构是:
/web-app
|
|--data/
| |--model_for_prediction.pkl
|--static/
| |--style.css
|--templates/
| |--home.html
| |--result.html
|--.gitignore
|--app.py
|--nltk.txt
|--requirements.txt
|--runtime.txt
|--Procfile
假设您已经有了一个带标签的数据集,每个单元格中都有一篇文章/文章段落。标签“1”代表讽刺,“0”代表假新闻。
句子转换文档推荐了几个预先训练好的模型和我们可以应用它们的各种任务。即使您是第一次看到这个库,带有清晰示例的文档也会大大节省您的时间。所以让我们开始吧!
第 1 部分——开发新模型。
伯特嵌入。我从拥抱脸/句子变形金刚库里拿了一个小伯特模型。大小对我们的任务至关重要。Heroku 有时间和大小限制——应用程序的大小应该小于 500Mb,每个操作最多 30 秒;因此,我们不想让我们的 web 应用崩溃。我选择了一个 light 57.4Mb 的型号,CPU(不是 GPU)选择了 PyTorch 版本。
当我试图安装 sentence-transformers 库并部署应用程序时,我的 web 应用程序崩溃了,出现了错误 H12 (请求超时)。我决定以句柄的方式实现这一部分,以降低运行时的复杂性。CPU 的 PyTorch 版本也显著减小了应用程序的大小。不用安装整个库就可以使用句子嵌入模型。这样的一招节省了我的时间,web 应用也没有再崩溃。
各文本的情绪 。任何文本我们都可以大致分为两类:事实和观点。观点承载着人们对世界的情感、评价和感受。pattern.en 模块捆绑了一个形容词词库(例如,好的、坏的、惊人的、气人的等)。)经常出现在文章/评论中,注释有情绪得分polarity(正面-负面)和subjectivity(客观↔主观)。极性是-1.0和+1.0之间的一个值,主观性是0.0和1.0之间的一个值。让我们提取这些值:
基于情感极性和主观性得分的特征工程。
各文本的 情态 。模式库中的modality()函数返回一个介于-1.0和+1.0之间的值,其中值> +0.5代表事实。
基于确定度的特征工程。
特征工程的最后一步——串联成一个数据集:
通用特征矩阵的创建。
模特培训。如上所述,我们可以选择任何型号。我从 sklearn 拿了一个 Logistic 回归。你可以自由选择你喜欢的。首先,我们创建一个模型。然后以 pickle 格式保存到/data文件夹中以备后用;
重要通知。在这个 POC 中,我使用 Pandas Python 库只是为了方便。Pandas 并不总是运行生产代码的最佳库。它有利于分析和数据探索,但速度很慢,因为它在后台做了一堆事情。
第 2 部分——为模型服务的演示 web 应用程序。
是时候创建一个 web 应用程序了。我们放在/templates文件夹中的home.html文件。看起来是这样的:
home.html—来自/templates 文件夹的主页文件。
页面显示我在一个单独的result.html文件中制作的预测结果,并放入同一个/templates文件夹:
result.html-显示模型预测的文件(也在/templates 文件夹中)。
UI 设计简单,在/static/style.css:
web 应用程序的 style.css。
重要 :将文件夹/data 和/static标记为资源。在 PyCharm for Linux 中,可以在文件- >设置- >项目结构中完成。将/templates文件夹标记为模板。很高兴从 Heroku 上传中排除一些文件夹,并减少应用程序的大小(虚拟环境文件夹)。不要忘记在您的项目中添加一个.gitignore文件:

图 1 文件→设置→项目结构。
由于我们使用 Flask 进行部署,我们需要指定一种模板语言:

图 2 文件→设置→语言和框架→模板语言
最后,在项目的目录中,我们可以创建我们的 app.py 文件。首先,我们放入所有需要的导入和预处理管道函数。然后,我们创建一个 Flask 应用程序实例(第 50 行),并添加主页和结果页面的功能。在 predict()函数中,我们打开一个保存的 before 模型并预测输入文本。
app.py:一个文件中的所有 NLP 管道和 Flask 功能。
在 main 中运行应用程序。恭喜你!现在你可以在本地主机 http://127.0.0.1:5000/ 上查看你的 app 作品。
第 3 部分—云服务部署。
首先,让我们创建一个 requirements.txt 文件。有两种方便的方法可以做到:
- 通过 Pycharm IDE。右键单击项目名称→新建→文件→将文件命名为 requirements.txt。当您打开一个空的刚刚创建的 requirements.txt 文件时,PyCharm IDE 会让您自动记下所有导入。很方便的方式:)
- 通过命令行和项目目录中的
'pip freeze > requirements.txt’。
别忘了给 CPU 换个 PyTorch 版本:
torch @ [https://download.pytorch.org/whl/cpu/torch-1.6.0%2Bcpu-cp36-cp36m-linux_x86_64.whl](https://download.pytorch.org/whl/cpu/torch-1.6.0%2Bcpu-cp36-cp36m-linux_x86_64.whl)
在当前项目中,我得到了一个很长的库列表:63 个。对于第一次面对这样一个任务的人,我要注意到:requirements.txt中的最后一行应该是空的。
关于 Heroku 和 NLTK 库的一个 重要提示 :如果你的应用程序使用 NLTK 库,你应该创建一个额外的 nltk.txt 文件,其中包含内部导入。在我们的例子中,pattern.text.en 使用 NLTK 和nltk.txt应该包含两行:
wordnet
pros_cons
我们需要指出在服务器上使用哪个 Python 版本。您可以像创建 requirements.txt 文件一样创建它:通过 IDE 或命令行。它应该包含一行:
python-3.6.13
Procfile。这个文件告诉 Heroku 当应用程序被部署时要做什么,并且包含一行代码:
web: gunicorn app:app
确保你有一个 Heroku CLI (和 Git CLI)。因为现在只有命令行操作:
heroku login
heroku create your_application_name
以下步骤与 Git CLI 几乎相同:
git init
git add .
git commit -m 'initial commit'
git push heroku master
就这些了,伙计们!你在 Heroku 服务器上部署了一个 WEB 应用。访问链接看起来像https://your _ application _ name . heroku app . com/
结论。
在本教程中,您学习了如何创建 NLP 管道,包括基于 Bert 的和附加的功能工程。您还将熟悉如何使用 Flask 创建一个演示 WEB 应用程序,以及如何在 Heroku 服务器上部署它。
资源。
Github 回购。文章中的代码。
我的 WEB 应用 URL 部署在 Heroku 上。
文章为灵感。
特别鸣谢莫迪凯作品。
在 AWS Panorama 的边缘部署对象检测器模型
理解大数据,AWS PANORAMA 模型部署分步指南
了解如何在 AWS Panorama 上部署最先进的计算机视觉模型,这是一种功能强大的边缘设备,可实现在线和经济高效的对象检测。

近年来,计算机视觉已经成为深度学习最令人兴奋的应用领域之一:经过训练的卷积神经网络(CNN)模型可以达到类似人类的精度水平,在图像或视频流中检测对象。这些令人难以置信的进步开辟了广泛的应用领域,从零售客户行为分析到安全和工业质量保证。
在这个场景中,出现了几个不同的深度学习模型来解决计算机视觉的一个常见用例:对象检测。这本身就是一个理想的结果,也是诸如目标跟踪、姿态估计和环境监控等广泛应用的普遍基础。
此外,当摄像机产生输入图像时,现代计算机视觉能力提高了应用于安全和监控的对象检测深度学习模型的可实现性。然而,由于实时应用的短响应时间要求,这样的场景是非常具有挑战性的。警报应该在检测到危险的几秒钟内发出;否则就没用,甚至有害。
延迟在定义对可用计算类型的限制方面起着重要作用。由于有限的带宽和不可靠的网络,将大量视频流传输到云,通过在云实例上运行的快速准确的深度学习模型来处理视频通常不可行或成本过高。视频分析经常需要高配置计算能力,这种需求削弱了按需或类似无服务器的自动扩展基础设施的优势。此外,带宽从来都不划算,这使得这种解决方案在大多数使用情况下都是负担不起的。
边缘计算成为实现更好延迟和降低总系统成本的理想解决方案,打开了一个全新的市场。不幸的是,对于大多数数据科学家来说,用 GPU 构建可靠且不昂贵的硬件来运行计算机视觉模型并不是一件容易的事情。考虑到一些用例管理的视频流可能包含人们视频镜头的敏感信息,安全要求使得这项任务更加困难。
进入 AWS 全景
在亚马逊 re:Invent 的 2020 虚拟版中,亚马逊网络服务的前首席执行官 Andy Jassy 展示了一款名为 AWS Panorama 的新设备,完全是为边缘计算而设计的。Nvidia Jetson Xavier 图形处理单元采用紧凑设计和 IP5 外壳的小型封装,可以分析多达 16 个并发视频流。该设备的外观和设置在 AWS 机器学习英雄迈克·钱伯斯的惊人视频中有更详细的介绍。
简单的初始配置和配置体验使 Panorama 适合非技术用户安装。
发展理念
在引擎盖下,AWS Panorama 不仅部署了深度学习模型,还要求开发人员定义一个 Panorama 应用。一个 Panorama 应用是打包的深度学习模型、业务逻辑代码和清单结构(应用图)的集合,清单结构定义了这些组件之间的数据管道。
应用程序组件被称为节点。设备上的每个资源都由一个节点表示:深度学习模型、业务逻辑代码、摄像头流,甚至显示输出和参数。每个节点有一个或多个接口,定义其输入和输出。在部署之前,模型和代码类型的节点资源被归档到二进制资产中。资产连同清单文件 ( package.json)被称为包。包的清单文件包含了关于其资产的所有信息,并定义了在应用程序图中使用的接口。可以在包描述符中提供额外的特定于节点的细节,例如,深度学习模型的输入张量的维度或应用可执行入口点。包被上传到由 AWS Panorama 服务管理的 S3 接入点,并向该服务注册。
当开发人员使用 AWS Panorama 服务部署应用程序时,应提供一个应用程序清单文件(graph.json),将应用程序定义为由节点和边构建的图形。在部署时,Panorama 服务在清单文件中找到按名称引用的已注册包,并将它们下载到 Panorama 设备。
总而言之:
- 一个全景应用是连接的节点的集合。连接由应用清单(或应用图)描述。
- 节点可以有以下类型:深度学习模型、应用源代码、摄像头输入、显示输出、部署时参数。
- 节点也定义了它们的接口。一个接口是输入和输出端口的列表。端口是命名和键入的数据字段。支持数字、布尔、字符串和“媒体”类型。
- 应用代码和 ML 模型被归档到资产中。资产、及其清单文件被称为包。Panorama 服务会上传和注册包。
- 在部署时,用户应该指定应用程序图。Panorama 服务在图中查找与单个节点相关联的包,并将所需的包下载到设备。
有关更多信息,请参考 AWS Panorama 开发人员指南。
为目标检测选择最先进的计算机视觉模型
你只看一次(YOLO)用于实时物体检测的深度学习模型在 CVPR 2016 上亮相。从那时起,它就成了这类任务的标准基准。它提供了实时推理性能、通用对象表示理解(提高了以前从未见过的图像的准确性)以及沿模型大小/准确性轴的缩放。与早期基于区域的卷积神经网络(R-CNN)相比,YOLO 模型只需一步就能处理图像。在接下来的几年中,这些模型有了显著的改进,引入了广泛的增强功能,从 YoloV2、YoloV3、YoloV4 到 YoloV5。
YOLO 模型可以检测对象并识别它们在图像中的位置,绘制包围它们的边界框。在早期的实现中,模型使用一系列预定义的边界框,称为锚点,并预测它们在图像中的偏移。这种方法需要指定在给定图像区域内要检测的锚的数量,这在一些使用情况下是有限制的。
2021 年,随着 YOLOX 的崛起,该模型得到了进一步改进,采用了无锚方法。YOLOX 在 PyTorch 中实现,COCO 数据集上的预训练模型在 GitHub 上发布。 COCO 数据集包含 80 个不同的对象类别,包括人、车辆、一些动物、运动设备和日常物品,因此预先训练的模型已经准备好检测这些开箱即用的对象。
创建 Panorama 应用程序
先决条件
要遵循此分步指南,需要一个 AWS 帐户和一个 AWS Panorama 设备。应将 Panorama 设备调配到帐户中(请参考上面 Mike 的教程了解这些步骤)。
测试解决方案还需要 RTSP 流,Panorama 设备应该能够从其连接的网络访问它。该流可以由大多数 IP 摄像机或运行 RTSP 服务器的计算机提供。
部署步骤将使用 AWS 命令行界面(CLI)和 Panorama (CLI)执行,从 AWS Panorama 开发人员指南中提供的示例应用程序开始。确保工作站上安装并配置了 AWS CLI、Panorama CLI 和 Docker。

全景示例应用程序。图来自 AWS 全景开发者指南 (CC BY-SA 4.0)。
本教程还附带了一个 GitHub 库,在这里你可以一个提交一个提交地跟踪项目的进展,如果你遇到困难,可以把它作为参考。我们将在每个步骤后提供一个带有书签图标的相关提交的链接:🔖。
Panorama 应用程序的包
首先,使用 AWS Panorama CLI 的init-project命令初始化一个项目:
$ panorama-cli init-project --name yolox-panorama
该命令将生成一个空的项目模板。它只是一个脚手架,上面有名为assets和packages的空文件夹,以及graphs/yolox-panorama/graph.json中的一个 JSON 文件。 GitHub 检查点:🔖
要部署 Panorama 应用程序,必须至少定义以下节点:
- 摄像机输入,
- 模型(将包裹 YOLOX),
- 应用程序代码(业务逻辑),以及
- 显示输出(HDMI,用于调试)。
AWS Panorama 定义了一个特殊的概念,即“抽象节点”,因为在应用程序开发期间,确切的 RTSP URI 是未知的,因为它取决于源摄像机流。
这种抽象允许相同的应用程序被发布到不同的设备,处理不同的流(使用不同的 RTSP URIs)。Panorama SDK 提供了一个“抽象摄像机”,这是一个摄像机的占位符节点,其连接 URI 将在部署时定义。
抽象摄像机节点是使用
add-panorama-package --type camera
Panorama CLI 的命令。为相机定义抽象节点不是强制性的:可以使用命令添加特定的 RTPS 相机流
create-package --type camera
然后在生成的文件packages/${AWS_ACCOUNT_ID}-[camera_name]-1.0/package.json的“接口”字段中提供摄像机 RTSP·URI、用户名和密码。
AWS Panorama 还提供了另一种类型的抽象节点来映射 HDMI 显示输出。使用该媒体接收器,可以在连接到 Panorama 设备的 HDMI 监视器上显示带注释的视频。需要考虑的一点是,该显示用于调试目的,一次只有一个应用程序可以使用它,即使用这种资源部署的第一个应用程序。
将到目前为止的所有命令包装在一起,通过以下方式实现配置:
向 Panorama 应用程序添加包。 GitHub 检查点🔖
关于 AWS 帐户 id 的说明
每个 Panorama 项目都在许多项目工件中使用所有者的 AWS 帐户 ID。它用于文件夹名称以及多个 JSON 配置文件中。帐户 ID 通常被认为是一条不希望公开的敏感信息。在本教程中,在命令行示例中,帐户 ID 被替换为${AWS_ACCOUNT_ID}。这个表达式引用了一个变量,这个变量可以用真正的 AWS 帐户 ID 初始化,这样 shell 就会自动替换它。在 JSON 代码片段中,我们将使用虚拟帐户 ID 123456789012,应该总是用实际的 AWS 帐户 ID 手动替换。
定义应用程序的节点
AWS Panorama CLI 不会在应用程序图中为业务逻辑和深度学习模型创建节点,因此开发人员必须手动添加它们。
这可以通过打开graphs/yolox-panorama/graph.json并在nodeGraph.nodes数组中添加以下对象来完成:
代码和模型节点。 GitHub 检查点:🔖
参数可以添加到 Panorama 应用程序中,它们的值将在部署时指定。应用程序逻辑可以在运行时访问这些参数的值。参数有一系列用途:定义与模型相关的参数(例如,检测阈值)或应用程序设置(例如,S3 存储桶名称)。AWS Panorama 支持以下参数类型:int32、float32、boolean和string。
在该部署中,单个float32参数代表物体检测器的置信度阈值。低于该阈值的检测置信水平使得相关对象被丢弃。参数需要手动添加到应用图中作为参数型节点。可以指定默认值和覆盖配置,以及在部署时向用户显示的可读文本。将以下对象添加到nodes数组中:
参数类型节点。 GitHub 检查点:🔖
关于此处参数的更多信息可在 Panorama 开发者指南的相关章节中找到。
建立计算机视觉管道
每个节点在应用中扮演一个特定的角色:一些节点发出信息(camera_node、detection_threshold,另一些节点消费数据(display_node,还有一些节点发出并消费数据,如code_node和model_node。
边缘引导流经应用程序的信息,将一个节点的输出端口连接到下一个节点的输入端口。输入和输出端口有特定的类型,只有兼容的类型才能连接。

正在开发的应用程序的组件图。来源:作者本人作品。
检测阈值参数和摄像机节点链接到代码节点。然后,代码节点的输出被链接到显示节点。模型节点没有连接到图中的其他节点,因为应用程序逻辑处理去往/来自模型的信息流。我们将在后面看到如何在预处理后将输入数据发送到模型,并从模型中读出推理结果进行后处理。
节点通过graphs/yolox-panorama/graph.json中的边连接:
应用程序图的边。 GitHub 检查点:🔖
添加机器学习模型神器
YOLOX 模型必须转换为 TorchScript,这是 AWS Panorama 支持的格式之一。完整的工作流程在yolox-torch scriptJupyter 笔记本中有概述。
一个重要的方面是记住导出模型的预期输入形状,这在稍后编写推理代码时是需要的。对于图像处理模型,输入形状的格式为[batch_size, channel_size, width, height]。这里的batch_size是1,channel_size等于3(红、绿、蓝),型号规格定义width和height。对于 yolox-s 型号,输入形状为[1, 3, 640, 640]。
在 Jupyter 笔记本的最后几个步骤中,TorchScript 模型被保存为一个.tar.gz包。这个档案将用于创建模型节点的包。
Panorama CLI 将归档添加为项目资产,采用--model-local-path参数中.tar.gz文件的路径。在发出任何这些命令之前,重要的是导出本地 AWS 帐户 ID,以具有可重复和可移植的步骤。
向 Panorama 应用程序添加模型。 GitHub 检查点:🔖
结果是一个新的节点在graph.json中,命名为yolox_s_asset,它应该被合并到已经创建的model_node中。编辑nodes列表,使得只有一个节点保留该内容:
合并的模型节点
interface字段是指yolox_s 包中的interface属性。Panorama CLI 创建的接口名称可以更改为更合适的名称,只需将name属性编辑为packages/${AWS_ACCOUNT_ID}-yolox_s-1.0/package.json内nodePackage.interfaces数组中的“interface”。
修正了模型界面。 GitHub 检查点:🔖
packages/${AWS_ACCOUNT_ID}-yolox_s-1.0/descriptor.json处的模型描述符应该包含关于您的模型的额外的必需元数据。编辑这个文件并添加框架名PYTORCH和输入名称和形状。模型描述符的最终版本应该如下所示:
模型描述符。 GitHub 检查点:🔖
实现计算机视觉管道
部署在 AWS Panorama 上的计算机视觉应用程序应至少实现以下功能:
- 连续查询视频流中的最后一帧,
- 预处理该帧并将其转换成与深度学习模型的输入具有相同形状的 NumPy 数组,
- 将预处理后的帧传递给模型(它已经被模型节点初始化了),
- 读取推理结果并最终对其进行后处理,
- 用推理结果边界框注释该帧,
- 将带注释的帧发送到下游显示节点。
除了这些基本的视频管道处理步骤,一个模型通常实现一些业务逻辑,例如:
- 计算人数并测量他们之间的距离,
- 如果某些条件得到验证,例如,这些人不遵守社交距离规则,
- 使用消息协议(例如 MQTT 或 AWS SNS)将这些警报发送给相关方,
- 生成业务指标并持久化它们(例如,在 CloudWatch 中或通过 Amazon Kinesis Data Firehose 在 S3 桶中),以便以后用于分析目的。
- 通常,与下游业务应用程序集成,或者
- 拍摄一个有趣的帧的“截图”,并将其上传到数据存储服务。
在本教程中,我们只实现媒体管道,不特别强调业务逻辑。主要重点是在 HDMI 监视器上显示视频流,然后集成 YOLOX 对象检测器模型。
使用开放容器图像格式构建全景应用程序
AWS Panorama 使用开放容器图像(OCI)格式,为在设备上运行的应用程序提供上下文。一个最小的 docker 文件,与 OpenCV 和 NumPy 捆绑在一起,分别处理 Python 中的图像和数组,可以从 Panorama CLI 在packages/${AWS_ACCOUNT_ID}-application_logic-1.0/Dockerfile中创建的存根文件中创建。
生成的文件应该类似于:
应用程序节点的 Dockerfile。 GitHub 检查点:🔖
上面的 Dockerfile 文件执行以下步骤:
- 建立在
panorama-application基础图像之上(这是所有 Panorama 应用程序必须具备的)。这个基础映像包含 Panorama SDK,它是与其他节点通信的基础设施。 - 更新 pip 并安装 OpenCV 和 NumPy。
- 将主机的
src文件夹中的内容复制到容器的/panorama文件夹中。
其他所需的依赖项也可以安装在同一个 Other 文件中。
定义应用程序节点的接口
在编写用于推理的应用程序代码之前,要做的第一步是定义代码节点 : 的接口一个构造,它列出了输入和输出端口,提供了与其他节点通信的方法。接口在packages/${AWS_ACCOUNT_ID}-application_logic-1.0/package.json中定义。将这些对象添加到nodePackage.interfaces数组中:
应用程序节点的接口。 GitHub 检查点:🔖
这定义了媒体流的video_in输入,作为float32参数的threshold输入,以及下游媒体消费者的video_out输出。关于这些输入和输出如何与其他节点连接,请参考graph.json的边缘部分。
日志记录设置
由于无法直接在 Panorama 设备上调试应用程序逻辑,因此需要使用诊断日志消息来实现应用程序的可观察性。对 Panorama 上运行的容器的标准输出的访问被禁用,这意味着将消息打印到 stdout 或使用 Python logger 的简单配置将不起作用。日志需要与 Panorama SDK 的日志基础设施集成。
Panorama 守护进程监视设备上运行的容器的/opt/aws/panorama/logs文件夹:写入该文件夹的任何文本文件都将被增量发送到 AWS CloudWatch 日志。这意味着向该文件夹中的文件添加日志条目会将新行直接推送到云中。
通过以下方式实现此目的的标准 Python 记录器配置:
配置记录器
创建应用程序存根
可以在一个名为
packages/${AWS_ACCOUNT_ID}-application_logic-1.0/src/application.py的新文件中创建一个应用程序的存根,其内容如下:
Panorama 应用程序存根
Application类的初始化器将记录器保存为实例属性,并初始化threshold属性,稍后将使用节点参数值填充该属性。实际上,没有办法从模型节点本身检索模型的名称和预期的输入大小。由于这个原因,在这个例子中它们被硬编码。
然后,init函数读取节点参数值。代码节点的输入在节点接口中定义,可通过self.inputs属性访问。输入的名称来自代码节点接口定义。这里,threshold 参数的值被读取并保存为实例属性。
每当有一个以上的摄像机连接到应用程序时,process_streams方法就会遍历所有的输入流,并为每一个输入流调用process_media。最后,它将修改后的(带注释的)媒体流发送到video_out输出,由下游节点处理,这里是 HDMI 显示。
process_media方法计算每个流的每一帧。它将帧传递给preprocessor方法,用预处理后的帧调用模型节点,最后对推理结果进行后处理。
preprocess和postprocess核心函数在这里就不赘述了。
最后,应该启动主应用程序循环,实现应用程序的入口点。在application.py的末尾增加以下内容:
主视频处理循环
关于应用程序执行的最后一件事是在应用程序的包描述符中指定处理容器的入口点脚本。打开packages/${AWS_ACCOUNT_ID}-application_logic-1.0/descriptor.json并修改如下:
应用程序描述符。 GitHub 检查点:🔖
构建应用程序框架
使用 Panorama CLI 工具可以轻松构建 docker 容器:
构建应用程序容器。 GitHub 检查点:🔖
运行此命令后,编辑graphs/yolox-panorama/graph.json的节点部分,删除除以下之外的所有code_node,并将接口名称更改为interface:
在应用程序图中只留下一个有效的代码节点
有时,Panorama CI 会在packages/${AWS_ACCOUNT_ID}-application_logic-1.0/package.json中添加第二个界面。应该只有一个,所以在删除多余的一个后,按如下方式更新另一个:
修复应用程序节点的接口。 GitHub 检查站:🔖
打包应用程序
AWS Panorama 设备从由 S3 接入点实施并由 AWS 维护的中央包存储库中下载应用包。必须使用以下命令将编译后的包上传到这个中央存储库:
panorama-cli package-application
Panorama CLI 使用罩下的 AWS CLI 来部署应用程序的资产,这意味着它将使用默认配置的 AWS 区域。确保默认区域与配置 Panorama 设备的区域相同。
部署基本管道
如 Panorama 开发人员指南中所述,可将应用程序部署到 Panorama 设备。因为应用程序不使用任何 AWS 服务,所以不需要为应用程序提供 IAM 角色。在部署阶段之后,应用控制 HDMI 显示器(只要它是部署到设备的唯一应用)。来自摄像机的 RTSP 视频流随即显示在屏幕上。对于这么多的工作来说,这显然不是一个很大的成就,但是它为进一步的开发设置了基线,并结束了部署的循环。
将 YOLOX 物体探测器模型部署到 AWS 全景图
YOLOX 模型要求输入帧以特定格式发送,并输出原始预测。这意味着必须对图像进行预处理和后处理。预处理包括将输入帧调整到正确的尺寸。后处理是对象检测的基本步骤,因为它将预测数组投影到边界框和检测到的对象类。这些预处理和后处理可以直接从 YOLOX 库中选取,仔细检查 Docker 映像中的所有依赖项。
最初的 yolox-s pytorch 模型有一个动态计算图,允许使用动态大小的输入,但这有一些推理时间性能缺点。AWS Panorama 要求模型采用优化的 TorchScript 格式,使用静态图形。
预处理就是将输入帧的大小调整为 640 x 640 像素的输入大小。调整大小是使用“适合+填充”策略实现的,该策略不会裁剪图像的任何部分,而是以图像的长边适合 640 x 640 正方形的方式来调整图像的大小。最后剩下的空白空间用灰色填充。该逻辑在 YOLOX 存储库中的[yolox/data/data_augment.py](https://github.com/Megvii-BaseDetection/YOLOX/blob/dd5700c24693e1852b55ce0cb170342c19943d8b/yolox/data/data_augment.py)脚本的[preproc](https://github.com/Megvii-BaseDetection/YOLOX/blob/dd5700c24693e1852b55ce0cb170342c19943d8b/yolox/data/data_augment.py#L144)函数中实现,应该添加到packages/${AWS_ACCOUNT_ID}-application_logic-1.0/src/application.py中:
为 YOLOX 检测器预处理帧
该模型输出 8400 个被检测对象的边界框候选,并且单个检测可以具有多个候选。在后处理方法中使用非最大抑制(NMS)算法,可以找到最大概率包含实际物体的候选。YOLOX 存储库包含这个函数和一些其他的助手,可以添加到一个新创建的packages/${AWS_ACCOUNT_ID}-application_logic-1.0/src/yolox_postprocess.py文件中。将 YOLOX 库中的[yolox/utils/demo_utils.py](https://github.com/Megvii-BaseDetection/YOLOX/blob/2c2dd1397ab090b553c6e6ecfca8184fe83800e1/yolox/utils/demo_utils.py)中的以下函数添加到yolox_postprocess.py 文件中:
demo_postprocesnmsmulticlass_nmsmulticlass_nms_class_awaremulticlass_nms_class_agnostic
在导入 NMS 函数并将它们连接到process_results方法后,生成的application.py文件应该包含:
后处理功能
process_results 方法迭代模型的输出,并调用后处理器方法来提取检测的边界框。如 Panorama SDK 的stream类所预期的,这些框被缩放到[0; 1]间隔。然后为输出流的每个检测添加一个矩形。后处理方法(取自 YOLOX 库中的[demo/ONNXRuntime/onnx_inference.py](https://github.com/Megvii-BaseDetection/YOLOX/blob/2c2dd1397ab090b553c6e6ecfca8184fe83800e1/demo/ONNXRuntime/onnx_inference.py#L73))将模型输出转换为非最大值抑制算法的预期格式。
将process_media方法改为调用process_results而不是preprocess:
最终的 process_media 方法。 GitHub 检查站:🔖
现在,可以按照前面章节中描述的步骤构建应用程序并将其部署到 Panorama 设备。AWS Panorama 使用上述配置向 CloudWatch 控制台发送应用程序日志。可以发现过滤带有/aws/panorama/devices/日志前缀的日志。
何去何从?
这篇文章只是触及了计算机视觉在 edge 上所能实现的表面,AWS Panorama 提供了一个很好的生产环境来实现这一点。本分步指南是关于如何部署最先进的对象检测模型的第一个示例,允许识别 COCO 数据集的 80 个不同对象类,并使用边界框定位它们,在 HDMI 显示器上显示带注释的视频流。
从这里,可以使用自定义图像数据集训练自定义 YOLOX 模型,然后将其部署到 Panorama 应用程序以实现非常具体的分类。
上述结果是为 Neosperience Cloud Services(以前的 Mikamai)和 Cogen 的联合项目开发的,旨在改进视频监控的 PeopleAnalytics 技术。这些结果可以进一步提高边缘设备的应用门槛。
在“开发者端”,可以添加许多业务逻辑来围绕模型构建完整的服务,因为有了适当的 IAM 角色,Panorama 设备中运行的应用程序可以直接访问 AWS 资源,如 S3 桶、MQTT 主题、SNS 通知或 CloudWatch 指标。
关于作者
Janos Tolgyesi 是 Neosperience 的 AWS 社区构建者和机器学习解决方案架构师。他在 ML technologies 工作了五年,在 AWS infrastructure 工作了八年。他喜欢构建东西,让它成为边缘的视频分析应用或基于点击流事件的用户分析器。你可以在 Twitter 、 Medium 和 LinkedIn 上找到我。
卢卡·比安奇博士是 AWS 的英雄,也是 Neosperience 的首席技术官。他热爱无服务器和机器学习,负责 Neosperience 的研发。对技术、ML、计算机视觉有热情,可在 Twitter 、 Medium 、 LinkedIn 联系。
Neosperience 通过软件解决方案释放同理心的力量,这些解决方案利用人工智能使品牌能够理解、参与和发展他们的客户群。在www.neosperience.com伸出手。
使用 Flask 和 WhyLabs 部署和监控您的 ML 应用程序
提高你的人工智能系统的可观察性

作者图片
在每个人工智能构建者的旅程中,最好的里程碑之一是模型准备好从培训中毕业并投入生产的那一天。根据 Algorithmia 最近做的一项调查,大多数组织已经有超过 25 个模型投入生产。这强调了企业是如何越来越多地依赖 ML 来提高实验室之外的性能的。然而,部署后阶段对于您的 ML 模型来说可能是一个困难的阶段。数据科学家可能认为一旦模型部署完毕,困难的部分就结束了,但事实是问题才刚刚开始。数据错误、管道破裂和模型性能下降总有一天会出现,当这一天到来时,我们必须准备好有效地调试和解决这些问题。为了拥有一个可靠和健壮的 ML 系统,可观测性是绝对必须的。
在本文中,我想分享一种方法,通过有效地记录和监控您的模型来提高您的 ML 应用程序的可观察性。为了演示,我们将部署一个 Flask 应用程序,用于基于众所周知的虹膜数据集的模式识别。在监控部分,我们将探索免费的入门版why labsObservability Platform,以便建立我们自己的模型监控仪表板。从仪表板上,我们可以访问从 ML 管道的每个部分收集的所有统计数据、指标和性能数据。为了与平台交互,我们将使用由 WhyLabs 开发的开源数据日志库 whylogs 。
监控仪表板的一个关键用例是当我们的数据质量和/或一致性发生意外变化时。因此,我们模拟了最常见的模型失败场景之一,即特征漂移,这意味着我们的输入分布发生了变化。然后,我们使用一个监控仪表板来查看如何检测和调试这类问题。虽然特征漂移可能会也可能不会影响模型的性能,但观察生产中的这种变化应该始终是进一步检查和模型再训练的理由。
总之,我们将一步一步地介绍:
- 部署集成了 WhyLabs 的 Flask API
- 测试应用程序
- 注入特征漂移并浏览模型操控板
如果这是一个让你产生共鸣的问题,我们已经将本教程的完整代码放在这里供你重用。您需要将它复制到您的机器上,以便遵循这个示例。您还需要一个 Docker,最好还需要一个 Python 环境管理工具,比如 Conda 或 pipenv。对于那些对细节感兴趣的人,我们已经包括了一个非常详细的描述和一个 Jupyter 笔记本作为指南。
1.概观
让我们看看系统的不同组件是如何相互作用的。

作者图片
我们将在本地部署一个 Flask 应用程序,它负责通过 REST 端点向用户提供所请求的预测。我们的应用程序还将使用 whylogs 库来创建生产过程中应用程序的输入和输出特性的统计概要。这些统计特性将在固定的时间间隔内以微批次的形式发送到 WhyLabs。WhyLabs 会自动合并它们,每天创建统计数据。
有多种方法可以将您记录的指标上传到平台。在本例中,我们定期在微批次中上传它们,如图所示。另一种选择是在每个日志步骤上传它们。
2.设置您的 WhyLabs 帐户
为了监控我们的应用程序,让我们首先设置一个 WhyLabs 帐户。具体来说,我们需要两条信息:
- API 令牌
- 组织 ID
前往 https://whylabs.ai/free 的获取一个免费账户。如果您愿意,您可以跟随示例,但是如果您只对跟随本演示感兴趣,您可以跳过快速入门说明。
之后,系统会提示您创建一个 API 令牌,您将使用它与您的仪表板进行交互。创建令牌后,复制它并将其存储在安全的地方。这里的第二个重要信息是您的组织 ID。把它也记下来。WhyLabs 为您提供了如何创建会话并将数据发送到仪表板的示例代码。你也可以测试它,检查数据是否通过。否则,在你获得 API 令牌和 Org ID 后,你可以去 https://hub.whylabsapp.com/models 的看看你闪亮的新模型的仪表板。为了进行到这一步,我们使用了 WhyLabs API 文档,它也提供了关于令牌创建的附加信息以及如何使用它的基本示例。
3.部署 Flask 应用程序
一旦仪表板启动并运行,我们就可以开始部署应用程序本身了。我们将使用 Gunicorn 提供一个 Flask 应用程序,打包到 Docker 容器中以方便部署。
WhyLabs 配置
第一步是配置与 WhyLabs 的连接。在这个例子中,我们通过.whylogs_flask.yaml文件来完成。可以将写入器设置为在本地输出数据或输出到不同的位置,例如 S3、MLFlow path 或直接输出到 WhyLabs。在这个文件中,我们还将设置项目的名称和其他附加信息。
环境变量
应用程序假设存在一组变量,所以我们将在一个.env文件中定义它们。这些稍后使用 dotenv 库加载。复制以下内容,并将WHYLABS_API_KEY和WHYLABS_DEFAULT_ORG_ID值替换为创建 WhyLabs 帐户时获得的值。您可以保持其他变量不变。
让我们谈谈其他一些现有的变量。
- why labs _ DEFAULT _ DATASET _ ID—数据集的 ID。模型-1 是默认值,在您创建帐户后自动创建。如果您尚未向 WhyLabs 发送任何内容,请保持不变。但是如果它已经被填充,您可以将其更改为 model-2。记得在 https://hub.whylabsapp.com/models 设置新模型。一个新的模型 id 将被分配给新创建的模型,您可以在您的。环境文件。
- ROTATION_TIME —用于向 WhyLabs 发送数据的周期。在实际的应用程序中,我们可能不需要如此频繁的更新,但是对于这个例子,我们将它设置为一个较低的值,这样我们就不必等待那么长时间来确保它正常工作。
创造环境
该应用程序将从 Docker 容器内部运行,但是我们还将运行一些前脚本(下载数据和训练模型)和后脚本(发送请求),所以让我们为本教程创建一个环境。如果您正在使用 Conda,您可以从environment.yml配置文件中创建它:
conda env create -f environment.yml
如果没有达到预期效果,您还可以从头开始创建一个环境:
conda create -n whylogs-flask python=3.7.11conda activate whylogs-flask
然后从需求中直接安装:
python -m pip install -r requirements.txt
训练模型
如果你仔细观察,我们的一个环境变量叫做MODEL_PATH。我们还没有模型,所以让我们创建它。我们将使用 sklearn 从虹膜数据集中训练一个简单的 SVC 分类模型,并将其保存为model.joblib。从我们示例的文件夹的根,我们可以简单地调用训练例程:
python train.py
建立码头工人形象
现在我们已经具备了实际运行应用程序的一切。为了构建映像,我们定义了下面的 Dockerfile 文件:
然后构建图像并运行我们的容器:
docker build --build-arg PYTHON_VERSION=3.7 -t whylabs-flask:latest .docker run --rm -p 5000:5000 -v $(pwd):/app whylabs-flask
这将在本地端口 5000 上启动我们的应用程序。在这个例子中,我们使用 Gunicorn 将 Flask 应用程序作为 WSGI HTTP 服务器运行。通过设置reload变量,我们能够更有效地调试,当代码发生变化时,自动重新加载工人。
您应该会看到来自 gunicorn 的启动服务器的消息:
[2021-10-12 17:53:01 +0000] [1] [INFO] Starting gunicorn 20.1.0
[2021-10-12 17:53:01 +0000] [1] [INFO] Listening at: http://0.0.0.0:5000 (1)
[2021-10-12 17:53:01 +0000] [1] [INFO] Using worker: sync
[2021-10-12 17:53:01 +0000] [8] [INFO] Booting worker with pid: 8
[2021-10-12 17:53:01 +0000] [20] [INFO] Booting worker with pid: 20
4.测试 API
一旦 Docker 容器运行,我们应该检查 API 是否正常工作。该应用程序有两个端点:
- /api/v1/health :如果 api 启动并运行,则返回 200 状态响应。
- /api/v1/predict :给定输入特征向量,返回预测类。
Swagger 对该 API 进行了适当的文档化,因此您可以前往http:127 . 0 . 0 . 1:5000/API docs浏览文档:

作者图片
从 /apidocs 中,您将能够看到尝试两个端点的请求示例,以及 curl 片段,如:
curl -X GET "http://127.0.0.1:5000/api/v1/health" -H "accept: application/json"curl -X POST "http://127.0.0.1:5000/api/v1/predict" -H "accept: application/json" -H "Content-Type: application/json" -d "{ \"petal_length_cm\": 0, \"petal_width_cm\": 0, \"sepal_length_cm\": 0, \"sepal_width_cm\": 0}"
您应该从第一个命令中获得“健康”的响应。同样,来自预测请求的响应应该是:
{
"data": {
"class": "Iris-virginica"
},
"message": "Success"
}
好了,我们的应用程序正恰当地服务于我们的请求。现在,我们可以检查数据是否安全可靠地到达我们的仪表板。
重要的是要记住,数据不会随着每个请求的完成而立即发送。根据在.env文件中定义的ROTATION_TIME环境变量,它被定期发送。在本例中,它被设置为 5 分钟,这意味着在信息被发送到我们的仪表板之前,我们必须等待 5 分钟。然后,我们应该会从 whylogs 中看到一条消息,表明上传已经完成。
上传完成后,收到的信息将在几分钟内显示在您的模型的仪表板上。从您的型号的仪表板中,您可以检查是否记录了任何配置文件,并访问您的摘要仪表板:

作者图片
到目前为止,我们已经记录了 1 个配置文件和 5 个特征,这意味着数据正在通过。现在,让我们通过一个用例更深入地探索这个平台:我们将向我们的数据分布中添加一些异常值,并看看这是如何反映在我们的仪表板中的。
5.检测特征漂移
当事情出错时,任何可观察性平台的真正价值就会显现出来。事情可能以许多不同的方式出错,但是对于这个演示,让我们选择一个特定的方式:特性漂移。
机器学习环境中的漂移现象可能是一个冗长的主题,因此在这种情况下,我们将限制自己对特征漂移的基本定义:当模型输入的分布发生变化时。
我们将使用 Iris 数据集中的 150 个未改变的样本来表示每日批次的正态分布。然后,为了表示异常批次,我们将采用相同的样本集,除了我们将这些样本中的 30 个样本替换为一个随机输入要素的随机异常值。我们将继续请求具有如下输入要素的预测:
- 第 1 天 —正常数据
- 第 2 天 —修改数据(改变分布)
- 第三天 —正常数据
下面的代码片段将在不改变输入特性的情况下发出 150 个请求。第二天,我们简单地修改代码以传递data_mod作为有效载荷,而不是data(第 35 行),然后重复这个过程。在这个演示中,离群值被添加到了sepal_width特征中。
让我们简要地看一下我们控制面板中的一些部分。从输入页面,有许多有用的信息,如每批记录的数量、空分数和推断的特征类型。

作者 Gif
一条特别有用的信息是分布距离。这是一个时间序列,它显示了在所选日期范围内该特征与前一批数据的平均统计距离,使用 Hellinger 距离来估计分布之间的距离。通过在sepal_width特征中添加异常值,我们不仅看到了sepal_width特征本身的分布距离的变化,还看到了预测结果的变化。
注意:对于剩余的特征,距离似乎在最后一天增加。这实际上是我的一个错误,因为我多发送了 1 条记录,总共 151 条记录。由于图中各要素之间的比例不同,因此这种变化的影响似乎很大,但是当检查值本身时,附加记录产生的分布距离为 0.02。
我们可以通过单击来进一步检查各个功能。从分布图中,我们可以看到漂移对class和sepal_width特征的影响。
在配置文件部分,我们可以选择多达 3 个数据集配置文件进行比较,这是一个非常酷的功能。在下面的图片中,我选择了一些特征进行比较。如前所述,添加异常值引起的变化也非常明显。

作者图片
虽然我们不可能在这里讨论所有可用的特性,但我最喜欢的一些特性是:
- 每个功能监视器的手动阈值配置
- 电子邮件/松弛时间的通知计划
- 上传训练集作为基线参考集
- 分析期间分段数据
请自行探索它们吧!
6.结论
ML 应用程序的部署后阶段给我们带来了无数的挑战,这些应用程序的故障排除过程仍然是非常手动和繁琐的。在这篇文章中,我们介绍了一个例子,说明如何通过 WhyLabs 提高系统的可观测性来减轻这一负担。
我们讲述了一个简单的例子,基于众所周知的 Iris 数据集部署 Flask 应用程序进行分类,并使用 whylogs 数据记录库将其与 WhyLabs 平台集成。我们还通过在输入中注入异常值来模拟一个特性漂移场景,以便查看它是如何反映在我们的监控仪表板中的。尽管这是一个非常简单的用例,但是这个例子可以很容易地被修改以涵盖更多定制的场景。
感谢您的阅读,如果您有任何问题/建议,请随时联系我们!如果你试用后有问题,我发现 Slack 上的 WhyLabs 社区非常有帮助,反应也很快。
使用 Streamlit 部署代码
为什么要简化 it 以及关于从 Python 部署数据仪表板应用程序的一些提示。

马克·克鲁兹在 Unsplash 上的照片
我最近在 Mac 上使用 Python 构建并部署了一个数据应用程序,没有编写一行 HTML、CSS 或 JavaScript 代码——所有这些都是通过一个叫做 Streamlit 的漂亮包实现的。
本文包含一些注释,说明在使用 Streamlit 部署代码时哪些有效,哪些无效。
我最近用 Steamlit 部署了一个数据仪表板的早期 alpha 版本。虽然这款应用还处于起步阶段,但我很高兴它能处于某种生产状态,我很高兴能继续对它进行改进。根据我的经验,这篇文章包含了一些最大的陷阱和技巧,可以帮助您突破在部署 Streamlit 时可能会遇到的一些最终问题。这篇文章不是一个完整的指南,为此,只需查看一下 Streamlit 网站,它在一步一步的过程中做得很好。
死亡之谷
很长一段时间以来,我一直想知道部署我的数据分析的最佳方式。例如,我们做了所有这些工作,并埋头于代码,但似乎总是有差距。就好像有一个山谷,项目在我们分享它们之前就死去了。
在我们分享项目之前,有些项目会夭折。
可能的解决方案包括 Jupyter notebooks 和 Deepnote ,它们非常适合共享代码和分析。另一个是 ObservableHQ,它非常擅长将 D3 视觉效果推出门外。还有许多其他方法可以完成这项工作。然而,尽管有这些选项,我从来没有能够连接到一个具有合适特性的部署方法。幸运的是,我的导师给了我一些建议,让我尝试 Plotly 和 Streamlit 的结合。
虽然我知道 Plotly ,但我之前从未听说过 Streamlit。Streamlit 号称是“构建和共享数据应用程序的最快方式”,它承诺在几分钟内将您的代码转化为 web 应用程序,而无需任何前端工作。我认为这好得难以置信,但事实证明,Streamlit 确实有效。
为什么选择 Streamlit?
- 自由的
- 可通过 pip 安装获得
- 良好的文档
- GitHub 回购集成
- 处理前端
- 仅需要 Python
如果这一切听起来很有趣,请查看 Streamlit 页面。文档和说明非常清楚;但是,我认为在您的代码中有几个重要的设计特性值得考虑。请继续阅读了解更多信息。
部署压缩的大数据
有时你有一吨数据,50 万或 100 万行数据——如何最好地部署指向如此大数据集的数据应用程序?尽管有很多答案,包括首先避免拥有一个庞大的表,让我们继续解决这个特定的问题。现在怎么办?
大文件的问题
处理单个大型数据表有三个主要问题。首先,在磁盘上,这种大小的文件可能有数百兆字节。其次,如果使用 Streamlit 部署,您必须使用 GitHub,这意味着大约 50 MBs 的硬限制。第三也是最后一点,加载大型数据集可能会导致应用程序崩溃。因此,考虑将数据帧压缩为压缩的 BZ2 pickle 文件,而不是 CSV 文件。

项目通常从某种 csv 数据表开始。在最初摄取后,考虑继续压缩 BZ2 泡菜文件,以节省时间和内存。来自作者 Justin Chae。
大数据,大问题:245 MB。csv 文件还是 20 MB .bz2 文件?
插入于 2020 年 1 月 13 日 — 尽管这种压缩方法作为一种生产手段适用于大量数据,但作为下一步,您当然应该采取额外的步骤来尽可能减小每个文件的大小。在下面链接的后续文章中会有更多关于优化的内容。
大型数据帧的解决方案
为了处理大型数据帧,在读取初始 csv 文件后,设计您的工作流,使用 BZ2 压缩来读写经过酸洗的数据。BZ2 泡菜组合在两个方面对你有好处。首先,pickled 格式保留了所有列的状态,并且比 CSV 文件占用更少的磁盘空间。第二,BZ2 高效地将数据压缩成微小的字节,并在后端进行了非常好的解压缩。
幸运的是,熊猫让这个任务变得简单。您所需要的只是将“. bz2”作为文件扩展名。
import pandas as pd**# given a dataframe of 600,000 records..**path = 'data/product_sales.bz2'df.to_pickle(path)***# pandas writes compressed pickle .bz2 based on filename
# to_pickle() has parameter of compression=infer*****# read back in to dataframe** df = pd.read_pickle(path)
Pickle 协议 5 值错误
像大多数项目一样,工作流从 CSV 格式的数据开始;然而,在应用程序内部,我设计的程序可以读写 pickle 格式的数据帧。使用 pickled DataFrames 的一个主要原因是序列化文件保留了各种元数据——如果您将 dtypes 设置为字符串、整数或类别,那么每当您读入数据时,这些 dtypes 都会被保留。另一方面,对于 CSV 文件,您必须将数据重新处理回合适的数据帧。

以 csv 文件开始的简单工作流。不要总是从后续的 csv 文件中写入和读取,而是尝试从 pickle 文件中 pickle 和读取,以保留数据状态。来自作者贾斯汀蔡。
尽管 pickle 文件非常可爱,但在使用 Streamlit 进行部署的最后几步,我遇到了 pickle 协议错误的阻碍。

不支持的 pickle 协议错误。通过将协议从 5 改为 2 解决。
有这个误差吗?
显然,Pandasto _ pickle()方法默认为版本 5 的协议,该协议并未得到普遍支持。因此,尽管一个标准的 Pandas paged data frame 可以在本地机器上进行测试,但是部署到服务器上就另当别论了。
**ValueError: unsupported pickle protocol: 5
Traceback:**File "/usr/local/lib/python3.7/site-packages/streamlit/script_runner.py", line 332, in _run_script
exec(code, module.__dict__)File "/app/app_courts/main.py", line 56, in <module>
run_app()File "/app/app_courts/main.py", line 52, in run_app
, classify=FalseFile "/app/app_courts/do_data/getter.py", line 124, in to_df
df = pd.read_pickle(path)File "/home/appuser/.local/lib/python3.7/site-packages/pandas/io/pickle.py", line 182, in read_pickle
return pickle.load(f)
Pickle 协议 5 错误的解决方案
当面对一个错误时,我有时会选择另一种解决方案,也就是说,某种东西也能产生同样的结果。然而,由于各种限制,我对数据文件没有什么选择。在寻找答案的过程中,我发现解决方案相当简单——将 Pandas to_pickle()协议从默认的改为版本 2。当熊猫泡菜与 BZ2 压缩相结合,结果是一个超级小,超级方便,非常兼容的数据文件。
**# to avoid pickle protocol error
# change params from 5 to 2**path = 'data/product_sales.bz2'df.to_pickle(path, protocol=2)
当熊猫泡菜与 BZ2 压缩相结合,结果是一个超级小,超级方便,非常兼容的数据文件。
不支持的区域设置错误
除了可视化之外,该应用程序还向用户展示了数据集高级数字的叙述。例如,有几个句子以书面形式解释了计数和频率。为了让读者跟上叙述的节奏,我想将数字格式化为带有千位分隔符的字符串,而不是纯整数。将数字格式化为文本的一种方法是使用区域库。

用格式化字符串形式的数字(左)和数字形式的数字(右)生成关于数据的叙述。来自作者 Justin Chae。
**# one way to format numbers as strings**import locale
locale.setlocale(locale.LC_ALL, 'en_US')case_id = 8456981formatted = locale.format_string("%d", case_id, grouping=*True*)*# formatted -> '8,456,981'*
不幸的是,虽然这种方法在我的本地机器上工作得很好,但是部署却因为一个 不支持的区域设置错误 而夭折了。

格式化字符串时出现不受支持的区域设置错误。通过使用 F 字符串来解决。
有这个误差吗?
不管出于什么原因,locale 给部署带来了巨大的困难。虽然可能有一些其他选项来解决区域设置,但我意识到可能有更好的替代方法。
**Error: unsupported locale setting
Traceback**:File "/usr/local/lib/python3.7/site-packages/streamlit/script_runner.py", line 332, in _run_script
exec(code, module.__dict__)File "/app/app_courts/main.py", line 8, in <module>
from app.app import AppFile "/app/app_courts/app/app.py", line 6, in <module>
from analyze_data.charts import ChartsFile "/app/app_courts/analyze_data/charts.py", line 25, in <module>
locale.setlocale(locale.LC_ALL, 'en_US')File "/usr/local/lib/python3.7/locale.py", line 608, in setlocale
return _setlocale(category, locale)
解决方法总是 f 弦,这是一个奇妙而漂亮的发明,它会在你最需要帮助的时候帮助你。
Python 不支持区域设置的解决方案
f 弦是一个奇妙的发明。虽然语法可能看起来吓人(需要一些时间来适应),但它是有效的。要返回带有千位分隔符的整数格式,请尝试以下语法。
case_id = 8456981formatted = f"{case_id:,d}"*# formatted -> '8,456,981'*
操作系统和 PWD 出现键盘错误
管理文件路径和目录是一件痛苦的事情。例如,语法可能会根据您是 Mac、PC、虚拟环境还是其他任意组合而变化。为了处理这种不确定性,像许多其他人一样,我养成了用 OS 库编写文件路径分隔符的习惯,以确保跨不同环境的兼容性。
**# an example of creating a cross-platform file path**import osfolder = 'data'
self.path = os.environ['PWD'] + os.sep + *folder*""" a go-to approach given a root and some sub-folders
-root/
app.py
----analysis/
----data/
----figures/
"""
不管出于什么原因,尽管该应用程序在我的本地机器上工作,但当我试图访问“PWD”或打印工作目录时,在线 Streamlit 部署会返回一个 KeyError 。

使用“PWD”作为文件路径的操作系统密钥时出现密钥错误。通过使用相对路径来解决。
有这个误差吗?
虽然我不确定为什么OS . environ[' PWD ']无法工作,但我最终改变了方法,依靠相对路径。
**KeyError:'PWD'
Traceback:**File "/usr/local/lib/python3.7/site-packages/streamlit/script_runner.py", line 332, in _run_script
exec(code, module.__dict__)File "/app/app_courts/main.py", line 12, in <module>
reader = Reader()File "/app/app_courts/do_data/getter.py", line 17, in __init__
self.path = os.environ['PWD'] + os.sep + folder + os.sepFile "/usr/local/lib/python3.7/os.py", line 681, in __getitem__
raise KeyError(key) from None
Streamlit 中 Python KeyError 的解决方案
如果 Streamlit 从项目根目录运行,即 main.py 或 app.py,那么可以考虑简单地引用带有相对路径的子文件夹。考虑下面的设置,streamlit 在其中运行 app.py(从根目录)。
**# from terminal, run app.py**
>>> streamlit run app.py""" project structure
-root/
**app.py**
----analysis/
----data/'product_sales.csv'
----figures/
"""
在这种情况下,如果应用程序需要从数据子文件夹中读取文件,请使用OS . sep . join()并记住相对位置。在测试这个解决方案时,我注意到它在我的本地机器和部署中都工作得很好。
**# an alternative to using OS with PWD**
path = os.sep.join([self.root, *filename*])*# path -> data/product_sales.csv*
结论
使用 Streamlit,可以将基于 Python 的项目部署为 web 应用程序,只需很少甚至不需要前端工作。尽管这一过程需要的时间不仅仅是几分钟,但在几个小时或一天的工作中是可行的。我分享这篇文章是为了传递关于 Streamlit 的信息,并分享一些解决一些问题的技巧。
至于问题,我希望我从一开始就设计好了这些路障。尽管每个问题都相当小,但每个问题都会妨碍应用程序的部署,并且需要大量的时间来研究和重构。希望这些关于我的错误的笔记能对你的下一个项目有所帮助。
感谢阅读。如果您正在考虑使用 Streamlit 进行部署或者正在进行故障排除,我希望这篇文章能够帮助。
资源
部署带有 CI/CD 的容器化 Plotly Dash 应用程序(P1: Heroku)

在 Unsplash 上由 Bernd Dittrich 拍摄的照片
假设您在本地开发了一个很酷的应用程序,并希望与全世界分享。此外,一旦您的应用上线,您希望轻松地做出直接反映在网上的更改。这可能是一项艰巨的任务,涉及选择云提供商、将您的应用程序容器化以及自动化部署流程。如果这似乎是一项艰巨的任务,那么请继续阅读,因为本文提供了每个组件的分解。
编辑:我已经将部署管道更改为 Google Cloud Run ,关于通过 CI/CD 部署到 Google Cloud Run 的完整概述,请查看 P2。
更具体地说,本文是如何使用 Github actions for CI/CD 在 Heroku 上构建和部署容器化 Plotly Dash 应用程序的分步指南。请注意,Dash 和 Heroku 部分可以由其他应用框架和其他云平台交换,而整体结构保持不变。在本指南结束时,您只需对 repo 的主要分支进行更改,并观察 Dash 应用程序如何部署到 Heroku!
我的回购示例可以在 Github 的这里找到。这些步骤大部分是我从这门 testdriven.io 课程中学到的。我假设你知道什么是 Plotly Dash 并且你知道 Github 是如何工作的。
该应用程序的一个工作示例可以在谷歌云上找到。我们正在构建的内容概述:

使用 Github Actions CI/CD 管道部署在 Heroku 上的示例应用,图片由作者提供
步骤:
- 文件结构
- 创建 Plotly Dash 应用程序
- 创建一个 Dockerfile 文件,在本地运行
- 用 Github 动作构建 Docker 图像
- 创建 Heroku 帐户和应用程序
- 通过 Github 操作部署到 Heroku
初始化
创建一个 Github 存储库,最好带有一个自述文件,并在您的本地机器上设置它( git-guide )。
1.文件结构
我们将在父文件夹中构建以下文件结构(在我的例子中为 docker-dash-example ):
├── .github
│ └── workflows
│ └── main.yml
│
├── project
│ ├── app
│ │ ├── __init__.py
│ │ ├── app.py
│ │ ├── functions.py
│ │ └── assets
│ ├── Dockerfile
│ ├── Dockerfile.prod
│ └── requirements.txt
│
├── release.sh
├── setup.cfg
├── .pre-commit-config.yaml
├── .gitignore
│
└── README.md
该结构可分为 4 个部分,稍后将详细解释:
- 的。github 文件夹包含我们的工作流 main.yml 文件,该文件用于 CI/CD 管道的 Github 操作(步骤 4 和 6)。
- 项目文件夹包含一个带有 Plotly Dash 应用程序的文件夹,其资产()。css 文件)、包含必要包的 requirements.txt 文件、用于本地部署的 Dockerfile 和用于在 Heroku 上部署的 Dockerfile.prod (步骤 2 和 3)。
- release.s h 用于最后一步(步骤 6)在 Heroku 上发布 app。
- (可选)。pre-commit-config.yaml 和 setup.cfg 文件用于代码样式和林挺,但还可以用于更多用途(步骤 2 的一部分)。
2.创建 Plotly Dash 应用程序
在这里,我将在项目文件夹的 app 文件夹中共享 app.py 文件。在创建自己的应用程序时,不要让这个示例应用程序限制了您的创造力!
这里需要注意两件重要的事情:
- 我们将 app.server 放入一个 server 变量中。
- 没有什么比 app.run_server 更能运行 app.py 文件了,就像你在开发过程中在本地所做的那样(参见下面的代码块)。这段代码被排除在外,因为我们将使用来自 Dockerfile 的命令来运行该应用程序,以便使用 Gunicorn WGSI 服务器来运行它。
- 我们从functions . py导入 plot_regression 函数。
if __name__ == "__main__":
app.run_server(host="0.0.0.0", port=8050, debug=True)
请注意,这个应用程序组件可以与许多 Python 或非 Python web 框架互换。
预提交挂钩(可选)
在将代码提交到存储库之前,预提交挂钩可以执行多项检查并识别简单的问题。安装很简单,而且很多钩子都很容易找到。这个库中使用的预提交钩子可以在这里找到,它由薄片 8 、黑色和 isort 组成。我使用这些钩子来保持代码格式良好(black 和 isort),并确保没有多余的代码或简单的错误(flake8)。
3.创建 Dockerfile 文件
Docker 是一种封装应用程序的好方法,使它们独立于本地机器的配置,并且容易部署到各种平台上。在继续之前,确保您的本地机器上安装了 Docker(下载&安装 Docker )。
为了在容器中运行 Plotly Dash 应用程序,我们在项目文件夹中创建了一个 Dockerfile 。这个 Dockerfile 看起来如下:
这些命令具有以下功能:
- 来自:拉标签为 3.8.6-slim-buster 的 Python 镜像,这是 Python 3.8.6 的精简版,包含运行 Python 所需的最少的包,这里简单解释一下。
- 标签:可选。维护者的姓名和电子邮件。
- 工作目录:设置容器内的工作目录。
- 复制 requirements.txt: 将 requirements.txt 文件复制到容器中。
- 运行 pip 安装—升级:升级 pip 以确保您运行的是最新版本。
- 运行 pip install -r:安装 requirements.txt 文件中的所有包。
- 复制 /app:将/app 文件夹复制到容器的工作目录中。
- 运行 useradd:添加一个用户来代替 root 使用(遵循 Heroku 指南)。
- 用户:切换到新创建的用户。
- CMD :使用 Gunicorn WSGI 服务器运行 Plotly Dash 应用程序,从 app.py 文件中调用服务器变量。Gunicorn 处理 web 服务器和我们的 Dash 应用程序之间的一切。请注意,这个 Dockerfile 现在可以用于本地部署。
本地运行
要使用上面的 Dockerfile 在您的本地机器上运行您的 Plotly Dash 应用程序(或我的示例之一),您必须构建映像并运行容器,将之前指定的端口分配给它。

运行 Docker 容器的步骤,从这个Docker 文件分解
在您的终端中,转到项目的父文件夹,运行以下命令,使用您的 Dockerfile 构建映像。
docker build -t docker-dash project/.
t 标志用于用正确的名称标记容器,在本例中是“docker-dash ”。标记完容器后,我们指定包含您的 Dockerfile 和您的应用程序所需的其他文件的上下文(路径)。
现在,使用以下命令运行包含您的应用程序的映像:
docker run -p 8050:8050 docker-dash
这里-p 标志代表 publish ,它指示将主机的哪个端口绑定到容器的端口。请记住,容器使用您的本地机器作为资源,但是独立运行。要与 Plotly Dash 应用程序的 Gunicorn 服务器进行交互,您需要指定服务器正在使用的端口:8050(如我们的docker 文件中所示)。打开一个浏览器窗口,进入 https://localhost:8050 查看你的应用程序在容器内运行的情况。
现在应用程序已经在本地运行了,我们将关注使用 Github Actions 中的 CI/CD 管道将应用程序容器部署到 Heroku。该管道将在 git 推送到主分支时触发,如下所示:

Github 动作管道,图片作者
4.用 Github 动作构建 Docker 图像
Github Actions 是一种自动化工作流程的好方法,开启了一个充满可能性的世界。我们将利用 Github 包来存储我们的 Docker 映像,并在稍后的 Heroku 部署步骤中使用它。
个人访问令牌
首先创建一个个人访问令牌并选择这些范围:
- 写:包
- 删除:包
- 工作流程

在 Github 上选择秘密范围,图片作者
这个令牌可以通过调用 GITHUB_TOKEN 在工作流中使用,如这里的所述。有了这个令牌,我们可以安全地使用我们的 Github 包。
工作流:构建
对于 CI/CD 管道的第一步,我们将在。github/workflows 文件夹,这个结构显示 github 这个文件是 Github 动作的工作流。一个 。yml 文件常用于写配置文件。我们的 main.yml 文件如下所示。
“name:”和“on: push: branches:”应该是不言自明的。env:'为工作流设置全局环境变量,在本例中是我们的 Docker 图像在 Github 包中的(未来)位置。
在作业下,我们指定一个作业:“构建:”,该作业包含以下步骤:
- name:'和' runs-on:'分别指定作业和运行环境的名称。
- '签出主节点':使用 checkout@2.3.4 动作允许我们签出主节点分支并获取最新的提交。
- “登录到 Github 包”:使用之前创建的令牌,我们登录到 Github 包,确保 GITHUB_TOKEN 作为本地环境变量可用,如果创建了它,它将在我们的 Github Secrets 中可用。
- ' Pull image ':如果图像已经存在于全局' env '中,我们将提取该图像。“图像”位置。
- “构建映像”:我们使用缓存从提取的映像中构建映像,以加快构建过程。注意,这里我使用'- -file '标志指向我们的 Dockerfile 。在编写部署作业时,我们将把它改为指向一个 Dockerfile.prod ,这将在本指南的最后一部分解释。
- ' Push image ':最后,更新后的映像被推送到 Github 包,以覆盖(或创建)app 包。
当您将此文件推送到 repo 的主分支时,此管道将运行。请注意,第一次镜像不存在于您的 Github 包(容器注册表)中,因此它将从头开始创建并被推送到注册表中。工作完成后,您可以在 Github repo/packages 中看到新创建的映像,它应该是这样的:

Github 包中使用 main.yml 管道创建的图片示例,图片作者
5.创建 Heroku 帐户和应用程序
Heroku 是一个云平台即服务,它为任何人托管低流量、低计算能力的应用程序提供了一个巨大的免费层。有了合适的基础架构,它还可以轻松扩展。您的应用程序将在他们的一个免费的 Dynos 上运行。
进入 Heroku ,创建账户,安装 Heroku 命令行界面。现在我们将在正确的区域创建一个命名的应用程序,使用:
heroku create YOUR_APP_NAME --region YOUR_REGION
现在你可以在 Heroku 仪表盘这里看到(空的)应用。为了让您的 Github 工作流能够访问您的 Heroku 帐户,您需要使用以下方法检索您的 Heroku 授权令牌:
heroku auth:token
现在我们希望能够像之前在构建步骤中从我们的秘密中获取的 GITHUB_TOKEN 一样安全地使用这个令牌。转到 Github repo 的设置,找到“机密”标签,点击“新建存储库机密”。添加您的 Heroku 令牌并将其命名为 HEROKU_AUTH_TOKEN,以便我们能够在部署步骤中使用它。

让您的 Heroku 授权令牌在回购的秘密中可用,图片由作者提供
6.通过 Github 操作部署到 Heroku
在这最后一步,我们将完成 main.yml 文件,并确保使用我们的管道将应用程序部署到 Heroku。
Dockerfile.prod
在将部署步骤作为作业添加到我们的工作流之前,我们需要确保 Plotly Dash 应用程序可以使用 Heroku 上的可用端口。我们将利用他们环境中可用的 Heroku 的端口变量。制作一份 Dockerfile 的副本,并将其重命名为 Dockerfile.prod ,这样我们就知道哪个文件将用于生产。现在,将我们将 gunicorn 服务器绑定到的最后一行改为:
CMD gunicorn --bind 0.0.0.0:$PORT app:server
容器将使用 Heroku 的端口变量,因此可以通过 Heroku url 访问它。确保也将 main.yml 构建作业中的引用从 Dockerfile 更改为 Dockerfile.prod. ( 示例docker file . prod)
# In main.yml build job
- name: Build Image
run: |
docker build \
--cache-from ${{ env.IMAGE }}:latest \
--tag ${{ env.IMAGE }}:latest \
--file ./project/Dockerfile.prod \
“./project”
部署工作流程
让我们将部署作业添加到构建作业下面的工作流 main.yml 中。
请注意,' needs: [build]'命令告诉部署步骤等待构建步骤完成。在部署作业的环境中,我们存储我们的 Heroku 应用程序名称,并使用它来指定 Heroku 容器注册表中的映像位置(类似于在 Github 上的构建阶段指定映像位置)。
- 前三个步骤与构建工作相同,我们签出 master,登录到 Github 包(Github docker 注册表)并提取映像。接下来的步骤是将容器部署到 Heroku:
- ' Build Image ':我们构建容器,注意我们使用的不同标签,即引用源图像。
- “登录到 HEROKU 容器注册表”:使用您添加到 Github 机密中的 HEROKU_AUTH_TOKEN,工作流可以登录到 Heroku 容器注册表。
- ' Push to the registry ':将图像从 Github 推送到 Heroku 的注册表。
- 设置环境变量':设置环境变量,以便在 releash.sh 文件中访问它们。
- ' release ':使用 Heroku 指定的释放步骤释放容器(chmod +x 将 release.sh 文件更改为可执行)。
注意,我对 Heroku 建议的示例 release.sh 结构做了一些小的修改。为 curl 请求的非零状态添加“set -e”和“Authorization:……”立即退出,并将请求授权给 HEROKU_AUTH_TOKEN 的持有者以确保安全。这里我们可以使用 HEROKU_REGISTRY_IMAGE 和 HEROKU_AUTH_TOKEN,因为它们是在“设置环境变量”中设置的。
推后坐
将代码中的更改推送到 repo 中,并导航到 Github 上的 Actions 选项卡,查看您的工作流程!您应该会看到在您的 main.yml 文件中定义的两个步骤:

两步工作流程,按作者排列图像
最初,工作流可能需要一些时间来安装软件包,因为它没有任何缓存来加速构建步骤。
查看您的应用程序!
前往https://YOUR _ APP _ name . Heroku APP . com查看您的应用程序运行情况,在您的 Heroku 仪表盘中,您也可以看到应用程序正在运行。
结论
最后,我们有 Github Actions,Dash,Docker 和 Heroku 共同合作,免费(不再免费)在线部署您的应用程序!Github Actions 和 Docker 使部署应用成为可能,而不管应用框架或云提供商。如果你想部署到不同的云平台,请确保查看这些关于 Azure 、 AWS 或 GCP 的介绍。
希望这篇文章能丰富您对整个管道及其各个部分的理解。
感谢阅读
希望对你有帮助!我从找出细节并尽可能地把它安排得有条理、紧凑和详细中学到了很多。请不要犹豫提出问题或给予反馈。
第二部分阐述如何部署到 Google 云平台!
开心连线 LinkedIn !
一些我的其他项目。
需要改进的地方:
- 在 CI/CD 管道的构建和部署步骤之间可以(也应该)有一个测试步骤。
- 使用多步骤构建可以加快部署。
- 通过适当的调整,docker 映像可以变得更小,这意味着更快的构建和部署。
其他可以尝试的事情:
- 部署到其他云平台(也有免费层/时段),如: Azure 、 AWS 或 GCP 。
- 使用另一个选择的应用框架,比如 Streamlit 、 Flask ,或者甚至不使用 Python。
- 部署一个没有容器化的 Dash app,本文还包含了更多关于 Gunicorn、Github 和 Heroku 的背景信息。
- Testdriven.io FastApi Docker 课程,很棒的课程,从中我学到了本指南中描述的大部分流程。
- 在 Flask app 内使用 Dash,解释 Dash 如何也能成为更大 Flask app 结构的一部分。
在 Amazon Sagemaker 上部署基于定制深度学习的算法 Docker 容器
在本文中,我将介绍如何在 Amazon Sagemaker 上部署定制的深度学习容器算法。Sagemaker 提供了两个选项,其中第一个选项是使用 Sagemaker 提供的内置算法,包括 KNN、Xgboost、线性学习器等。而另一种选择是使用来自 ECR(弹性容器注册中心)的自定义 docker 容器。在本文中,我们将看到如何部署我们的定制 docker 容器并将其托管在 Sagemaker 上。出于数据目的,我使用了著名的 Kaggle 的泰坦尼克号数据集。您可以参考我的 Github 存储库来查找部署和托管容器所需的所有文件。
先决条件:
Docker :
Docker 提供了一种简单的方法将任意代码打包成一个完全独立的映像。一旦有了映像,就可以使用 Docker 运行基于该映像的容器。运行容器就像在机器上运行程序一样,只是容器为程序的运行创建了一个完全独立的环境。容器是相互隔离的,也与宿主环境隔离,所以不管在哪里运行,你设置程序的方式就是它运行的方式。
在某些方面,Docker 容器就像一个虚拟机,但是它的重量要轻得多。例如,在一个容器中运行的程序可以在不到一秒的时间内启动,并且许多容器可以在同一个物理机或虚拟机实例上运行。
Docker 使用一个名为 Dockerfile 的简单文件来指定如何组装图像。你可以基于你自己或者其他人构建的 Docker 映像来构建你的 Docker 映像,这可以简化很多事情。
容器结构:

容器的文件结构。(decision_trees 是算法的名称,我们可以用我们的算法/用例名称来替换它)(图片来自 AWS github 资源库)
让我们逐一查看所有文件:
Dockerfile:
这个文件描述了如何构建你的 Docker 容器映像。它是一个文本文档,包含用户可以在命令行调用的所有命令,以组装映像,还包含安装各种软件包、设置活动工作目录、复制目录等命令。

上图显示了我们的泰坦尼克号用例的 docker 文件(图片由作者提供)
上图是我们泰坦尼克号用例
的 docker 文件在 docker 文件中,我已经安装了 Tensorflow、Scikit-learn、Keras 等库。这将用于处理、训练训练数据上的模型,并用于对测试数据进行推断。我已经用 Ubuntu 18.04 做基础图了。
Build_and_push.sh 是一个脚本,它使用 docker 文件构建您的容器映像,然后将其推送到 ECR。

上图显示了容器中列出的文件(图片由作者提供)
- nginx.conf 是 nginx 前端的配置文件。一般来说,我们照原样接受这个文件。
- predictor.py 是实际实现 Flask web 服务器和这个应用程序的巨大预测的程序。我们将对其进行定制,以对测试数据执行预处理并执行推断。
- serve 是容器启动托管时启动的程序。它只是启动 gunicorn 服务器,运行 predictor.py 中定义的 Flask 应用程序的多个实例。
- train.py 是运行容器进行训练时调用的程序。在这个文件中,我们定义了预处理步骤、模型训练以及最终将模型保存到模型目录中。
- wsgi.py 是一个用于调用 Flask 应用的小包装器。我们不需要修改这个文件。
dockerfile 文件中设置的工作目录将是 opt/ml/。以下是该目录的文件夹层次结构。

上图显示了 opt/ml 目录中的文件夹结构(图片来自 AWS github 资源库)
让我们从需要在各种文件中完成的更改开始:
Step1 : 克隆仓库
你可以从 github 克隆我的 repo 或者克隆官方 AWS 仓库
步骤 2 : 编辑 docker 文件
其次,我们需要对 docker 文件进行修改,我们需要在其中指定整个训练和推理过程所需的所有库。为了部署深度学习模型,您可能需要 Tensorflow、Keras 等库..
注意- 检查受支持的 Keras 和 Tensorflow 的正确版本。我们没有在 docker 文件中指定容器的入口点,所以 docker 将在训练时运行 train.py,在服务时运行 serve.py。
我们还需要将容器文件夹复制到 opt/ml 目录,并将其设置为容器的活动工作目录。参考下图:

图中显示 Titanic 文件夹设置为活动工作目录(图片由作者提供)
第三步:编辑 train.py 文件
现在我们的 docker 文件已经准备好了,我们需要开始编辑训练和处理代码。对于当前的数据集来说,预处理并不多,因此我将它合并到了 train.py 文件本身中。我们需要做一些修改,尤其是在 train()函数中。请参考下图:

在将训练数据提供给模型进行训练之前,需要对训练数据进行预处理(图片由作者提供)
以下是我在 titanic 数据集上实现的预处理的一部分:
1 .将标题从名称中分离出来,并将其添加到不同的类别中,如稀有、错过等。
2。创建一个新功能“Family_members ”,增加了 SibSp 和 Parch。
3。通过对标题分组并取平均值来处理年龄列中的缺失值。
4。通过对 Pclass 分组并取平均值来处理 Fare 列中缺失的值。
5。通过用“S”(模式)
6 替换来处理 apollowed 中缺失的值。通过创建新列 Pclass_Band 来反转 Pclass 的值,以创建与票价的正相关。
7。一个热点编码的栏目“性别”,“已上市”和“标题”。
现在我们必须定义我们的模式架构。
对于 Titanic 数据集,我定义了两个隐藏层,分别具有 8 个和 4 个神经元,每个层中具有 Relu 激活函数,以及一个输出层,具有 1 个具有 Sigmoid 激活函数的神经元。
为了编译模型,我使用了 Adam optimizer、binary_crossentropy loss 和 accuracy 作为验证指标。
现在,我们使用 model.fit 函数对这个模型进行大约 200 个时期的训练,批次大小为 8。我没有为这个模型执行任何超参数调整,因此可以更改这些值以获得更好的精度。

该图显示了用于训练模型的 Keras 连续层(图片由作者提供)
最后,我们将模型 pickle 文件保存在模型目录中。

该图显示了在定义的模型路径中保存训练好的模型(图片由作者提供)
步骤 4:编辑 predict.py 文件 由于测试文件将类似于训练集,我们必须执行相同的预处理步骤,然后才能从训练好的模型中进行推断。我们必须在预测函数中添加所有这些步骤。

上面的截图显示了 predict 函数中的预处理步骤(图片由作者提供)
一旦我们定义了所有的预处理步骤,就该加载训练好的模型文件了。为此,我们需要定义 model_path 来定位文件。这里的路径是 opt/ml/model/keras.h5。为了加载模型,我使用了 keras .models 中的 load_model 命令。我们还需要初始化 Tensorflow 默认图,该图将用于从我们训练好的神经网络中获取预测。

上图显示了训练好的模型的加载(图片由作者提供)
一旦加载了模型,处理了测试数据,就该进行预测了。预测代码也在预测函数中定义。

上面的快照显示了从训练好的模型中获取预测的命令(图片由作者提供)
容器的本地测试:
当我们第一次用 Amazon SageMaker 打包一个算法时,我们想自己测试它,以确保它工作正常。在目录 container/local_test 中,有一个框架可以做到这一点。它包括运行和使用容器的三个 shell 脚本和一个目录结构:
这些脚本是:
1。train_local.sh:
用图像的名字运行这个,它将在本地树上运行训练。我们还需要修改目录 test_dir/input/data/…以便为算法设置正确的通道和数据。因此,在这个目录中,我们将放置泰坦尼克号列车的数据。

以上截图为 train_local.sh 脚本(图片由作者提供)
2. serve_local.sh :
一旦我们训练了模型,我们需要用图像的名称运行这个文件,它应该为模型服务。这个文件反过来运行容器中的 serve.py 文件。这基本上启动了一个监听端口 8080 的 python 应用程序,并启动了 ngnix 和 gunicorn。
Nginx 是来自互联网的请求首先到达的地方。它可以非常快速地处理它们,并且通常被配置为只让那些真正需要到达 web 应用程序的请求通过。
Gunicorn 将从 Nginx 获得的请求转换成您的 web 应用程序可以处理的格式,并确保您的代码在需要时执行。
3.预测. sh:
这个脚本以一个有效负载文件的名称和(可选的)我们想要的 HTTP 内容类型运行。内容类型将默认为文本/csv。例如,我们可以运行$。/predict.sh payload.csv 文本/csv。这里,我们需要粘贴 Titanic 测试文件,并将其重命名为 payload.csv。在本地测试模型时,我们会将该文件作为输入进行传递。

上面的快照描述了预测脚本(图片由作者提供)
本地测试的步骤:
第一步:构建 docker 映像:
为了构建 docker 映像,我们需要移动到容器目录并运行以下命令:
sudo docker build。-t 泰坦尼克 _ 图片

上面的截图显示了泰坦尼克号的成功建造
第二步:训练模型: 在这一步我们需要训练模型,并将它的 pickle 文件保存在 model 目录下。为此,我们需要使用下面的命令运行 train_local.sh 脚本。
CD local _ testsudo bash train _ local . sh 泰坦尼克-image


上面的快照显示了我们的神经网络在泰坦尼克号上的成功训练
步骤 3:运行 serve 脚本 下一步是运行 flask 应用程序,为此我们需要使用以下命令运行 serve_local.sh 脚本: sudo bash serve _ local . sh titanic-image

上图显示了有 8 个工作人员的运行服务器(图片由作者提供)
步骤 4:运行预测脚本 我们必须让服务器脚本在一个选项卡中运行,而在另一个选项卡上,我们可以运行预测脚本来获得模型推断。Payload.csv 文件(Titaninc 测试数据集)将作为参数传递给模型,我们将使用 bash 命令传递该文件以运行 predict.sh 脚本。通过运行它,我们用有效负载文件在端口 8080 上攻击服务器,然后服务器返回预测值作为响应。这形成了一个请求响应范例。 sudo bash predict . sh payload . CSV


上面的快照显示了模型的输出预测值(图片由作者提供)
现在终于到了将我们的容器图像推送到 Amazon ECR 的时候了!!
构建和推动
现在是时候建立和推动我们的码头形象 ECR。最后一步可以使用 Sagemaker Notebook 实例来完成。确保实例具有 sagemaker 完全访问权限、输入文件和模型文件所在的 S3 存储桶访问权限、ECR 等。
首先,我们需要将 titanic 文件夹上传到笔记本实例中的 Sagemaker Jupyter 实验室。接下来,我们需要在笔记本内部构建 docker,并将图像本地推送至 ECR。
下面的代码可以在 build_and_push.sh 文件或者 Bring _ Your _ Own-Creating _ Algorithm _ and _ Model _ Package 笔记本里面找到。

下面的代码将 docker 图像推送到带有标签“latest”的 ECR(按作者排序的图像)
一旦我们有我们的形象推到 ECR,我们可以训练模型。为此,第一步是将我们的训练和批量推理数据上传到 S3。然后,我们需要创建一个估计器并拟合模型。最后,我们可以运行批处理推理作业来测试模型输出。我们可以进一步将模型部署为 Sagemaker 端点。您可以在存储库内的 jupyter 笔记本中找到这些附加步骤。
这就是我们如何在 Amazon Sagemaker 上部署我们的模型容器。
使用 Github 操作在 Azure 上部署 FastAPI
使用 Github 动作自动化您的部署工作流程
Github 操作
Github Actions 是一个新的工作流自动化工具,用于直接从 Github 构建、测试和部署您的代码。
如果您已经在使用 Github 作为代码库,那么就没有必要集成第三方工具来自动化常见的开发人员工作流。
只需在存储库中放置一个 Github Actions .yml文件,该文件设计为响应特定事件而运行。(推送、拉取请求等)
工作流程图
今天,我们将通过一个示例工作流,使用 Python 构建一个准系统 API,选择 FastAPI 作为框架。

Github 动作工作流程图。图片由作者提供。
我们将构建一个容器映像并将其推送到 Azure Container Registry,并将该映像拉入 Azure Web 应用程序进行部署。
请注意,本文假设您事先了解下面列出的技术。
给出的 shell 命令示例是在 macOS 上。但是如果您在 Windows 上开发,您应该能够找到等效的命令。
我们将利用的产品包和技术的完整列表包括:
- VS 代码 —作为首选的 IDE。
- pipenv——处理包依赖关系、创建虚拟环境和加载环境变量。
- FastAPI— Python API 开发框架。
- uvicon—FastAPI 应用程序的 ASGI 服务器。
- Docker 桌面 —在我们的本地机器上构建并运行 Docker 容器映像。
- Azure Container Registry——用于在 Azure cloud 中存储我们的容器映像的存储库。
- Azure 应用服务——托管 FastAPI 应用服务器的 PaaS 服务。
- Github Actions —自动化 FastAPI 应用程序的持续部署工作流程。
继续从上面的链接下载 VS Code 和 Docker Desktop,因为我们在整个指南中都需要这两个程序。
本地计算机上的项目设置
创建您的项目文件夹
在终端中,导航到要创建项目的文件夹,并运行以下命令。
mkdir fastapi-cd
cd fastapi-cdcode .

创建项目文件夹。Gif by 作者。
VS 代码应该从您创建的项目文件夹开始。
安装管道
pipenv 是一个多功能包,它消除了 Python 应用程序中常见的对requirements.txt文件的需求。
点击Ctrl + ~打开 VS 代码终端,输入命令:
sudo -H pip install -U pipenv
pipenv install fastapi uvicorn

pipenv 安装包。Gif 作者作者。
pipenv 将继续在虚拟环境中安装库,并在Pipfile中为您管理依赖关系。

Pipfile 包管理。图片由作者提供。
因为 pipenv 为您的项目创建了一个虚拟环境,所以您也不需要使用常规的venv / virtualenv命令。
只需使用pipenv shell激活虚拟环境。
pipenv shell
uvicorn --versionexit
uvicorn --version
使用exit命令退出虚拟环境。
请注意,在环境之外无法再访问 uvicorn。它仅安装在使用pipenv shell可访问的虚拟环境中。

用 pipenv shell 激活虚拟环境。Gif 作者作者。
创建项目文件
在项目目录中创建以下文件。
touch main.py .env .gitignore .dockerignore Dockerfile
在.gitignore和.dockerignore文件中,将.env列为项目文件夹中要忽略的文件。
开源代码库
创建一个没有任何文件的裸 Github repo 并复制 repo URL。
开始跟踪本地回购的变化。在 VS 代码终端中,运行:
git init
git add .
git commit -m "first commit"git remote add origin <github repo url>
git push -u origin main
码头工人
前往 Docker 桌面安装程序。
这允许您在本地机器上运行 Docker 命令。
https://www.docker.com/products/docker-desktop
密码
我们终于完成了设置。该编码了。回到 VS 代码。在.env中,设置PORT=8000。
在main.py中,输入以下代码:
main.py 文件。Github gist 作者作者。
默认地址路由现在将向您返回一条成功消息。
在 VS 代码终端运行pipenv run python main.py启动 uvicorn 服务器:
然后转到[http://localhost:8000/docs](http://localhost:8000/docs)查看 FastAPI 是否在运行。

FastAPI swagger 文档。图片由作者提供。
注意,在运行main.py之前,pipenv 会为您加载环境变量PORT=8000。
构建并运行容器映像
不要将我们的应用程序部署为一个包,让我们将我们的应用程序构建为一个 Docker 映像,这样构建过程将在Dockerfile中概述。
Dockerfile使构建过程无缝且可重复。
在Dockerfile中,写下以下内容:
Dockerfile。Github gist 作者作者。
构建您的容器,并检查图像是否是用docker images命令创建的。
docker build . -t fastapi-cd:1.0
docker images
在端口 8000 上使用您之前指定的图像标签运行您的容器。
docker run -p 8000:8000 -t fastapi-cd:1.0
前往[http://localhost:8000/docs](http://localhost:8000/docs)查看您的集装箱化申请。
您应该看到同一个 FastAPI 应用程序正在运行。
恭喜你!您刚刚构建了一个简单的 FastAPI 应用程序,并在本地机器上使用 Docker 容器对其进行了容器化。
基础设施设置
Azure 容器注册表
是时候在 Azure 中部署我们的应用了。首先,创建一个 Azure 容器注册表。

创建 Azure 容器注册表。图片由作者提供。
在访问键窗格中启用管理员用户选项。

启用管理员用户。图片由作者提供。
回到你的 VS 代码终端,用你的账号登录 Azure。
az login
az acr login --name fastapicd
构建 Docker 映像并将其推送到注册服务器。
docker build . -t fastapicd.azurecr.io/fastapi-cd:1.0docker images
docker push fastapicd.azurecr.io/fastapi-cd:1.0

将容器映像推送到 Azure 容器注册服务器。Gif 作者作者。
检查您的 Docker 映像是否已成功推送到注册表中的 repo。

验证 Azure 容器注册表报告中的容器映像。图片由作者提供。
Azure 应用服务
接下来,创建一个 App 服务资源。

创建应用服务。图片由作者提供。
对于应用服务计划,在生产工作负载选项卡下,将大小更改为标准 S1 SKU。

标准 S1 应用服务计划。图片由作者提供。
在 Docker configuration 选项卡上,确保您之前推送的容器映像被选中。

将应用程序服务配置为使用容器映像。图片由作者提供。
资源部署完成后,请转至[https://<your-webapp-name>.azurewebsites.net/docs](https://<your-webapp-name>.azurewebsites.net/docs),检查您的 web 应用程序是否正在运行。
您应该会看到 FastAPI swagger 文档页面呈现。
Github 操作
现在我们已经准备好创建我们的 Github 动作了。yml 文件,它将自动部署我们的 FastAPI 应用程序。
在 VS 代码中,创建一个.github/workflows 目录和一个prod.workflow.yml文件。
mkdir .github
cd .githubmkdir workflows
cd ..touch .github/workflows/prod.workflow.yml
建立你的prod.workflow.yml文件,如下所示:
prod.workflow.yml 文件。Github gist 作者。
现在,每当我们对主分支进行 git 推送时,Github Actions 将运行一个部署作业,该作业由上面的 5 个步骤组成,每个步骤都有自己的名称。
使用 git 命令将这个新文件推送到 Github:
git add .
git commit -m "github actions deployment workflow"
git push
服务主体
为了用 Github 操作自动化我们的部署工作流,我们需要给操作运行者一个服务主体来认证 Azure,并执行应用部署。
在 VS 代码终端中,运行:
az ad sp create-for-rbac --name "github-actions" --role contributor --scopes /subscriptions/<GUID>/resourceGroups/fastapi-cd --sdk-auth
您可以从用于创建资源组的订阅中获取订阅 GUID。
您将得到如下响应:
创建服务主体 JSON 响应。Github gist 作者作者。
复制响应并保存。你再也看不到它了。
前往 Github 设置,创建 3 个 Github 秘密:
- AZURE 凭证:上面的完整 JSON 响应。
- 来自 JSON 响应的 clientId 值。
- 来自 JSON 响应的 clientSecret 值。

创建 Github 秘密。图片由作者提供。
将应用服务配置为使用 Github 操作进行持续部署
在 App Service 的部署中心窗格中,链接您的 Github repo 主分支,并配置部署以使用 Github 操作。

将应用程序配置为使用 Github 操作持续部署。图片由作者提供。
创建临时部署插槽
当前应用程序正在生产插槽中运行。为了保证更高质量的部署,我们将创建一个暂存槽。

创建临时部署插槽。图片由作者提供。
插槽非常有用,原因有很多:
- 可以将变更发布给登台槽中更少%的用户,以便在将登台槽与生产交换之前验证新的版本。
- 暂存槽应用程序实例在交换到生产环境之前会预热,以确保应用程序能够响应请求。
- 如果新版本出现问题,可以再次执行交换来回滚更改。
转到[https://<your-webapp-name>-staging.azurewebsites.net/docs](https://<your-webapp-name>-staging.azurewebsites.net/docs),检查暂存应用是否像生产应用一样运行。
为临时插槽配置与生产插槽相同的部署中心设置。
将新版本推送到暂存槽。
在您的 main.py 文件中,对返回消息进行修改。
return {"data": "Application ran successfully - FastAPI release v2.0"}
对主分支进行 git 推送,以触发 Github 操作工作流。
git add .
git commit -m "FastAPI v2.0 release"
git push
Github Actions 将自动构建并部署新版本的应用程序到 staging slot。

Github 操作部署作业。图片由作者提供。
前往[https://<your-webapp-name>-staging.azurewebsites.net/docs](https://<your-webapp-name>-staging.azurewebsites.net/docs)查看应用程序的新版本。
向默认路由发送请求以检查响应。您应该在返回消息中看到 2.0 版。

验证新应用程序发布到暂存槽。图片由作者提供。
当您准备好将暂存应用程序切换到生产时,只需在应用程序服务的部署插槽窗格中单击 Swap。

将暂存应用程序换成生产应用程序。图片作者作者。
通过转到生产 URL [https://<your-webapp-name>.azurewebsites.net/docs](https://<your-webapp-name>.azurewebsites.net/docs),对新应用版本进行与上面相同的验证。
结论
开发软件应用程序时,速度很重要。
作为开发人员,有很多事情我们必须跟上——供应基础设施、构建新环境、应用程序测试等。
如果我们将无聊的事情自动化,我们可以将时间集中在最关键的任务上——构建新功能。
在本文中,我们用 Github 动作自动化了 DevOps 生命周期的发布和部署阶段。这让我们有信心经常发布到产品中,而不会出现部署失败。

DevOps 生命周期。
资源
本文中的所有代码都可以在 Github repo:
https://github.com/natworkeffects/fastapi-cd
我想对所有帮助完成这篇文章的大量文档和 YouTube 视频大声欢呼:
- 使用 Github 操作将自定义容器部署到应用服务
- Github 动作报告—部署到 App 服务
- 在应用服务中设置暂存槽
- 通过 7 个简单步骤学习 Docker 完全初学者教程
- 用 Docker 封装 FastAPI 应用
- 将 Docker 图像推送到 Azure 容器注册中心
- pipenv 教程视频
- 如何在 Docker 容器中运行 pipenv
免费 PostgreSQL 数据库的逐步部署和数据接收
实践教程
在 Heroku 中免费部署 PostgreSQL 数据库,并使用 Pandas 和 SQLAlchemy 接收数据

在这篇文章中,你将学会如何…
- 在 Heroku 部署免费的 PostgreSQL 数据库
- 生成一个 Heroku API 令牌(以两种方式)
- 动态检索 Heroku 数据库 URL(有助于克服免费计划的缺点)
- 使用 Pandas 和 SQLAlchemy 将数据摄取到数据库中的一个表中
- 使用 SQLAlchemy 数据类型指定表格中列的数据类型
相关技术的一行摘要
PostgreSQL :一个免费的开源对象关系数据库管理系统,强调可扩展性和 SQL 兼容性。
Heroku :平台即服务(PaaS)适合快速部署,只需极少的开发运维经验。
SQLAlchemy:Python SQL 库和对象关系映射器(ORM),用于与数据库交互。
Pandas :一个用于数据分析和操作的开源 Python 库。
先决条件
您将需要以下 Python 库
此外
- Heroku CLI (通过在终端输入
heroku --version来验证您的安装)
Heroku 注册和部署
Heroku 是一个平台即服务(PaaS ),使开发人员能够完全在云中构建和运行应用程序。Heroku 提供了一个随时可用的环境,使得在几乎没有开发经验的情况下尽快部署代码变得非常简单。这对于初学者和中小型公司来说是一个极好的选择,不像 AWS 通常需要有经验的开发人员,并且有复杂的部署过程。
1.注册 Heroku 并部署您的第一个 PostgreSQL 数据库
你可以免费注册 Heroku。注册并登录到您的帐户后,您将被引导到 Heroku 仪表板。然后,您可以按照以下剪辑中的说明创建一个新的应用程序并添加一个 PostgreSQL 数据库。
部署新的 Heroku 应用程序并添加 PostgreSQL 驱动程序
免费计划允许您拥有最多 20,000 行数据和最多 20 个到数据库的连接。这个计划对于一个小型的个人项目来说通常是足够的。
注意:在免费计划中,数据库凭证偶尔会改变,因为 Heroku 会定期轮换凭证,有时会执行维护。
为了解决数据库凭证偶尔更改的问题,我们可以使用 Heroku CLI 动态检索数据库 URL。但是首先,让我们回顾一下通过 Heroku CLI 登录您的帐户的步骤。
2.使用令牌访问您的 Heroku 帐户
👉本节所涵盖的内容通常适用于通过Heroku CLI使用任何 Heroku 应用程序。
2.1.生成 Heroku API 令牌
您可以通过以下两种方式生成令牌:
2.1.1。Heroku 账户(浏览器)
进入账户设置→应用。在授权部分,点击创建授权。您必须在打开的窗口中给出描述,并设置到期时间,或者只设置令牌没有到期时间(通过将该框留空)。

从 Heroku 仪表板创建 Heroku API 令牌
2.1.2。Heroku CLI(终端)
安装 Heroku CLI 后,首次尝试使用需要访问您的帐户的命令时,系统会提示您在浏览器上登录 Heroku 帐户。一旦登录,你可以通过 Heroku API 做几乎任何事情。例如,我们可以通过运行以下命令来创建令牌:
*$heroku authorization:create*
以上命令将为您生成一个长期令牌。第一次运行上述命令时,会在浏览器中提示您登录您的帐户。一旦您成功登录到您的帐户,您就可以返回到终端并查看生成的令牌,如下所示。

通过 Heroku CLI 生成 Heroku API 令牌
2.2.在您的环境中存储您的 Heroku 令牌
现在您已经有了 Heroku API 令牌,您需要在您的终端/环境中将它设置为HEROKU_API_KEY。您可以通过在终端中运行以下命令来实现这一点:
*$export HEROKU_API_KEY=<your_token>*
关于 shell 终端变量作用域的提示:在 shell 终端中设置的变量将只在您运行的终端中可用,并且在关闭它后会死去。相反,你可以把上面的命令放在你的~/.bash或~/.bashrc文件中,这样这个变量就可以在你打开的任何新终端中使用。这样就不需要再担心设置这个变量了!
一旦您在终端中设置了HEROKU_API_KEY变量,您就不再需要使用基于 web 的身份验证或用户名和密码来登录。如果您想将 Heroku CLI 用作自动化流程或 CI/CD 的一部分,这一点尤为重要。这样,您不需要每次登录并在任何不同的终端中使用令牌。
2.3 检索 Heroku PostgreSQL 数据库 URL
您可以通过运行以下命令来获取数据库 URL:
*$heroku config:get DATABASE_URL --app <your-app-name>*
这将以如下格式输出数据库 URL
postgres://<db_user>:<db_password>@<db_host>/<db_name>
我们可以使用 Python 的标准库子进程来运行上述命令并检索数据库凭证。这样我们就可以用 Python 编写所有的代码。
使用子进程库从 Python 中检索 Heroku 应用程序的数据库 URL
注意:您的 Python (iPython)终端/环境应该设置了HEROKU_API_KEY。您可以通过运行os.environ["HEROKU_API_KEY"]并验证输出中的令牌来验证这一点。
将数据摄取到表中
创建 SQLAlchemy 引擎
在我们使用 Pandas 将数据接收到已部署的 PostgreSQL 数据库的表中之前,我们必须创建一个 SQLAlchemy 引擎,它将被传递给 Pandas 方法。可以使用以下代码片段创建 SQLAlchemy 引擎/连接:
检索数据库 URL 并创建 SQLAlchemy 引擎
正如您在上面可能注意到的,在创建 SQLAlchemy 引擎之前,需要进行一些字符串操作。
使用 Pandas & SQLAlchemy 摄取数据
我们可以通过简单地使用 pandas to_sql()函数并将 SQLAlchemy 引擎/连接对象传递给它,将数据摄取到一个表中。
使用 Pandas to_sql() 函数填充 PostgreSQL 表
在上面的示例中,指定了几列的数据类型。您可以通过传递一个字典来确定列的 dtype,字典中的键应该是列名,值应该是 SQLAlchemy 类型。对于所有可用的 dtypes,您可以查看 SQLAlchemy 文档以了解它支持的数据类型。
其他提示
使用 pandas [read_sql_table()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_sql_table.html)将数据读入 Pandas 数据帧。
*df = pd.read_sql_table(
"covid19", # table name
con=engine
)*
您可以使用 SQLAlchemy 的[.execute(“SQL Query”)](https://docs.sqlalchemy.org/en/14/core/engines.html#sqlalchemy.create_engine)函数运行原始 SQL 查询。例如,如果您想通过运行 SQL 查询删除上面的表,可以通过执行以下操作来实现:
*engine.execute("DROP TABLE covid19")*
上面将创建一个 SQLAlchemy 游标。
结论
在这篇文章中,我们使用 Heroku free plan 部署了一个免费的 PostgreSQL 数据库。我们还通过 Heroku CLI 动态检索数据库凭证,解决了 Heroku 在自由计划中更改数据库凭证的问题。使用 Pandas 的to_sql()函数,我们快速创建了一个表,甚至通过 SQLAlchemy 数据类型指定了列的数据类型。
感谢阅读🙏
加入我的邮件列表接收类似帖子 。也可以关注我上 中LinkedIn,Twitter。
有用的链接
*https://devcenter.heroku.com/articles/authentication *
10 分钟内在亚马逊 SageMaker 上部署 HuggingFace 模型
使用 HuggingFace Hub 大规模部署 NLP 模型

图片来自 Unsplash
我通常讨厌点击诱饵标题,所以我将保证这不是一个开始这篇文章。hugging face Hub包含数千种不同的自然语言处理模型,适用于从摘要到文本生成的各种自然语言处理任务。今年早些时候,亚马逊 SageMaker 与 HuggingFace 合作发布了 AWS 管理的 HuggingFace 容器,使得将 HF 模型和脚本带到云上比以往任何时候都更容易。在本文中,我们将探索一个简单的例子,用几行简单的代码从 AWS SageMaker 上的 HF Hub 部署 bert-base-uncased 预训练模型。在继续这篇文章之前,AWS 的一些先验知识和 SageMaker 是如何操作的,有望完全理解所有的内容。
目录
- 设置
- SageMaker 上的高频部署
- 结论/额外资源
设置
对于这个例子,我们将使用传统的 SageMaker 笔记本实例。首先转到 AWS 控制台上的 SageMaker,然后点击笔记本实例。在笔记本实例中,您可以选择创建笔记本实例。在这里,您可以选择一个具有适当计算能力的实例,这个例子并不太密集,所以我们可以使用更便宜的 ml.t2.medium。

作者截图
接下来,您将被要求创建一个角色,该角色将在必要时授予您的实例使用其他服务的权限。对于这个用例,保留默认的执行角色和 SageMaker 完全访问权限,因为我们不会使用任何其他 AWS 服务。接下来创建 Notebook 实例,您应该可以选择访问 Jupyter 实验室环境,您可以在其中工作。在这里你可以创建一个合适内核的笔记本。Python3 内核对于这个例子来说已经足够了。现在我们有了一台笔记本电脑,可以在上面部署我们的 HF 模型。

作者截图
SageMaker 上的高频部署
要访问我们正在使用的模型,请转到下面的 HF Hub link 。这个模型是预先训练好的,可以完成各种任务,我们将专门用它来进行文本分类。使用来自 Hub 的预训练模型的令人惊叹之处在于,当它们集成在一起时,它们已经为我们提供了在 SageMaker 上部署的指导。一旦进入高频集线器链接,在右上角的中你会注意到展开。如果你点击选项,你会看到亚马逊 SageMaker。

作者截图
点击 SageMaker 后,您可以选择任务类型(文本分类)并为配置选择 AWS 。这将提供样板代码,您可以在您的笔记本实例中利用它来部署这个特定的模型。
导入和集线器配置
HF 模型 ID 和任务是 HuggingFace 容器如何理解我们正在处理的模型和它试图解决的问题。我们现在可以通过 SageMaker 定义内置的 HuggingFace 模型。
创建 HF SageMaker 模型
创建 HuggingFace 模型后,最后一步也是最简单的一步是使用 SageMaker 实时端点部署它以进行推理。
将 HuggingFace 模型部署到实时端点
在端点成功部署后,我们可以快速测试一些示例推断。
SageMaker 推理
这样,我们应该可以看到文本分类结果与多数类一起显示。

作者截图
如果当前不使用端点,请确保将其删除,以免产生任何额外费用。
删除端点
结论
HuggingFace 拥有大量的 NLP 资源,SageMaker 有助于将这些模型扩展到令人难以置信的规模。从 HuggingFace Hub 部署只是 SageMaker 的一种部署方法。您还可以从 S3 的模型数据中部署 HuggingFace 模型。您还可以训练 HuggingFace 估计器,然后部署一个定制推理脚本,让您管理输入和输出。为了进一步探索,我在附加资源类别中附加了一些例子和文章。
我希望这篇文章对使用 Amazon SageMaker 和 HuggingFace 的人有用。如果你对 ML & AWS 感兴趣,欢迎在评论中留下任何反馈或在 LinkedIn 上与我联系。如果对我的更多作品感兴趣,请务必关注我的媒体。感谢您的阅读。
额外资源
使用 Nginx 和 Gunicorn 部署多个 Flask 应用程序

来自 Pexels 的 panumas nikhomkhai 的照片
这篇博文是关于如何使用 Nginx 和 Gunicorn 在 Linux 服务器上部署多个 Flask 应用程序的分步教程。
在本教程中,我假设您已经有了一个可以使用 IP 地址 ssh 到的服务器。我还假设你对创建 Flask 应用程序有基本的了解,因为我不会详细讨论。
我在本教程中使用的 VPS 运行在 Ubuntu 上。其实,如果你想知道如何购买和配置一个 VPS,你可以查看这个视频。此外,如果您不熟悉创建 Flask 应用程序,您可以查看此文档。
我们开始吧!
本地机器:
在我的本地机器上,我有一个 Flask 应用程序,我想把它部署在我的远程 VPS 上,(实际上我有两个应用程序,但是现在让我们只关注一个应用程序)。

图片来自 memegenerator.net
我的应用程序位于一个名为“chatbot”的目录下,其中包含了主 Flask app 文件 (app.py) ,我的虚拟环境 (chatvenv) ,以及一些帮助文件。因此,在我的本地机器上,我使用scp命令将我项目的所有文件复制到远程服务器上。
$ scp -r Desktop/chatbot ubuntu@IP_ADDRESS:~/
⚠️请记住,根据您的服务器配置,可能会要求您提供密码。此外,请确保您更改了本地路径,以及远程服务器的用户名和 IP 地址!
虚拟专用服务器
让我们现在连接到我们的副总裁,以便做肮脏的工作
$ ssh ubuntu@IP_ADDRESS
现在我们已经在服务器上了,让我们安装 python 和虚拟环境包。然后,在我们的项目文件夹中创建一个虚拟环境。
~$ sudo apt install python3-pip
~$ sudo apt install python3-venv
$ python3 -m venv chatvenv
下面是我们目录树结构的概述:

现在,我们将使用以下命令激活虚拟环境:
$ source chatvenv/bin/activate
如果您已经有了一个 requirements.txt 文件,那么您可以简单地使用下面这个不言自明的命令来安装您项目的需求。相反,您必须手动安装您的应用程序所依赖的包。
(chatvenv)$ pip install -r requirements.txt
之后,尝试执行以下两个命令来运行您的应用程序。
(chatvenv)$ export FLASK_APP=app.py
(chatvenv)$ flask run --host=0.0.0.0
最后,您可以通过浏览器访问您的应用程序来检查一切是否正常:[http://IP_ADDRESS:5000/](http://IP_ADDRESS:5000/)
Nginx 和 Gunicorn
虽然到目前为止你对你的工作很满意,但是我们的方法有两个问题。首先,正如您在终端中看到的,Flask 运行在开发模式下。第二,应用程序在前台运行,如果我们点击^C来取回我们的终端,应用程序将不再可达。
为了解决这个问题,我们将使用一个 web 服务器( Nginx )、一个 Web 服务器网关接口( Gunicorn ),并将我们的执行妖魔化,以便应用程序将在后台运行。
让我们首先在我们的虚拟环境中安装 Nginx 和 Gunicorn
(chatvenv)$ sudo apt install nginx
(chatvenv)$ pip install gunicorn
现在,您可以使用这个命令将http://IP_ADDRESS:5000和您的 Python 逻辑绑定在一起
(chatvenv)$ cd ~/chatbot
(chatvenv)$ gunicorn --bind 0.0.0.0:5000 app:app
然后在[http://IP_ADDRESS:5000](http://ip_address:5000)查看你的应用
⚠️注意,在最后一个命令中,第一个 app 指的是 flask app 文件的名称,而第二个 app 指的是您在该文件中用来创建应用程序的名称:app = Flask(__name__)
现在是时候让 Ubuntu 的 init 系统在服务器启动时自动启动 Gunicorn 并为 Flask 应用提供服务了。
首先,让我们退出虚拟环境。
(chatvenv)$ deactivate
然后,用下面的代码创建一个项目名为“chatbot”的服务文件。别忘了更改用户名( ubuntu )、项目名( chatbot )和虚拟环境名( chatvenv )。
$ sudo nano /etc/systemd/system/chatbot.service
[Unit]
Description=Gunicorn instance to serve **chatbot**
[Service]
User=**ubuntu**
Group=www-data
WorkingDirectory=/home/**ubuntu**/**chatbot**
Environment="PATH=/home/**ubuntu**/**chatbot**/**chatvenv**/bin"
ExecStart=/home/**ubuntu**/**chatbot**/**chatvenv**/bin/gunicorn --workers 3 --bind unix:**chatbot**.sock -m 007 **app:app**
[Install]
WantedBy=multi-user.target
然后启动、启用并测试 Gunicorn 服务:
$ sudo systemctl start chatbot
$ sudo systemctl enable chatbot
$ sudo systemctl status chatbot
你可能已经注意到了,我不会在这里解释每一行代码。然而,如果你有兴趣了解更多,查看这篇博客文章了解更多细节。
将 Nginx 配置为代理请求
在这一节中,我们将通过修改配置文件来配置 Nginx 传递 web 请求。首先,我们在站点可用目录中创建聊天机器人文件,然后将它链接到启用了站点的目录。
当你复制/粘贴这段代码时,再次仔细检查名字;否则你会遇到一些麻烦,很明显!
$ sudo nano /etc/nginx/sites-available/chatbot
server {
listen 80;
server_name **IP_ADDRESS**;
location / {
include proxy_params;
proxy_pass http://unix:/home/**ubuntu**/**chatbot**/**chatbot**.sock;
}
}
$ sudo ln -s /etc/nginx/sites-available/chatbot /etc/nginx/sites-enabled
运行以下命令检查语法错误
$ sudo nginx -t
如果一切顺利,重启 Nginx 服务器;然后配置防火墙,允许完全访问 Nginx 服务器:
$ sudo systemctl restart nginx
$ sudo ufw allow 'Nginx Full'
最后,你可以在[http://IP_ADDRESS](http://ip_address:5000)查看你的应用。恭喜你!现在可以自豪地说,你知道如何使用 Nginx 和 Gunicorn 部署 Flask 应用程序😅。
添加另一个烧瓶应用程序
即使我们退出 VPS 环境并关闭本地机器,我们的 Flask 应用程序现在也在上述地址启动并运行。在本节中,我们将做一些更改,以便能够在同一台服务器上同时运行多个应用程序。
首先,让我们将第二个 Flask 应用程序移动到 VPS。然后,正如我们之前所做的,我们开始创建一个虚拟环境( betavenv )并安装您的项目的任何需求。因此,文件夹树的新结构现在看起来像这样:

其次,我们用新项目的名称“beta PP”创建另一个服务文件,代码如下。再来一次:别忘了更改用户名( ubuntu )、项目名( betapp )、虚拟环境名( betavenv )!
$ sudo nano /etc/systemd/system/betapp.service
[Unit]
Description = guni corn instance to servebeta PP
After = network . target
【服务】
User =Ubuntu
Group = www-data
working directory =/home/Ubuntu/beta PP
Environment = " PATH =/home/Ubuntu/beta PP/beta venv/bin】
ExecStart =/home/ubsock-m 007beta run:app****
[安装]
wanted by = multi-user . target
然后启动并启用 Gunicorn 服务:
$ sudo systemctl start betapp
$ sudo systemctl enable betapp
就像第一个项目一样,我们将配置 Nginx 来传递 web 请求,首先,在站点可用目录中创建 app2 文件,然后将它链接到启用了站点的目录。但是,为了让我们的新应用程序正常工作,我们应该选择 80 以外的另一个端口(这里是 5000)。
$ sudo nano /etc/nginx/sites-available/app2
服务器{
监听5000;
服务器名称 IP 地址;
location / {
包含 proxy _ params
proxy _ passhttp://UNIX:/home/Ubuntu/beta PP/beta PP。袜子;
}
$ sudo ln -s /etc/nginx/sites-available/app2 /etc/nginx/sites-enabled
检查语法错误:
$ sudo nginx -t
重启 Nginx 服务器,在 [http://IP_ADDRESS](http://ip_address:5000/)和[http://IP_ADDRESS:5000](http://ip_address:5000/)访问你的两个应用
$ sudo systemctl restart nginx
结论
Flask APIs 是将你训练过的机器学习模型投入生产【2】的优秀工具。在本教程中,我们介绍了如何使用 Nginx 和 Gunicorn 部署 Flask 应用程序的过程。
原载于 2021 年 7 月 3 日 https://aienthusiasts.comhttps://aienthusiasts.com/deploy-multiple-flask-applications/。
将多个 TensorFlow 模型部署到一个端点
使用 Amazon SageMaker 的多型号终端

图片来自 Unsplash
假设您正在处理多个模型,并希望根据应用程序的用例选择一个来调用。引入 SageMaker 多模型端点作为您的可扩展、经济高效的解决方案。使用 SageMaker 多模型端点(MME),您可以将数千个模型集中到一个端点,并指定您希望根据您的用例调用哪个模型。这个推断选项的主要约束是模型所有都需要在相同框架中成为,因此所有 TensorFlow 或所有 PyTorch 都不是两者的混合。如果想要一个众多框架的组合,你会想要查看 SageMaker 多容器端点。在本文中,为了简单起见,我们将介绍一个例子,其中我们使用了两个定制的 TensorFlow 模型。我们将遍历端到端示例,看看如何通过简单的 Boto3 API 调用来调用或定义每个不同的模型。在开始之前,请确保阅读先决条件/设置部分,因为有足够的 AWS & ML 知识来完全理解本演示。如果你想获取代码,请查看下面的链接。
目录
- 先决条件/设置
- 多模型端点概述
- 示例演练
- 整个代码和结论
先决条件/设置
本文将假设您对 AWS 服务有中等程度的了解,特别是那些与 SageMaker 功能高度集成的 S3 和 ECR 的服务。了解 SageMaker containers 的一般运作方式以及幕后发生的事情也很重要。幸运的是,SageMaker 已经提供了它管理的 TensorFlow 容器,因此我们可以通过一个更简单的功能来训练我们的模型,这个功能被称为脚本模式。使用脚本模式,我们可以在训练脚本中传递自定义模型,我们将该脚本提供给SageMaker tensor flow estimator,它在幕后有一个托管容器。要使用自定义模型跟踪 TensorFlow 脚本模式的端到端示例,请查看这篇文章。在本例中,我们将使用脚本模式和两个不同的 TensorFlow 模型进行多模型端点设置。
关于设置和实例类型,请确保为 S3 和 ECR 创建具有适当权限的 IAM 角色。对于实例类型,一个自由层 ml.t3.medium 实例应该足够了,但对于更复杂或计算密集型的模型,请查看 SageMaker 提供的不同的计算实例。
我们将使用的数据集是基于表格和回归的。第一个是波士顿房产,第二个是来自 Kaggle 的汽油消耗数据集。
多模型端点概述
对于多模型端点,仍然只有一个容器/实例。你用脚本模式训练你的模型,然后把训练好的模型工件推到一个普通 S3 桶位置。注意,模型数据必须是 SageMaker 的tar.gz 格式。然后,您可以用这些不同的模型填充您的端点,并在您的端点调用中指定您正在使用的模型。
示例演练
S3 设置和导入
在开始任何训练或推理代码之前,我们需要确保所有必要的导入和设置我们将在这个例子中使用的 S3 桶。
导入+ S3/IAM 设置
注意,我们的 S3 时段设置是必不可少的,因为我们的多模型端点期望所有的模型工件都在同一个 S3 位置。我们将使用这个带有不同前缀的桶来指定输入数据、输出数据、MME 位置等等。
波士顿住房培训和模型创建
下一步涉及到我们将在波士顿住宅区使用的第一个数据集。使用 Sklearn,我们可以下载数据集,并在准备好用于训练的数据时将其推送到 S3。
波士顿数据集准备
现在,我们已经在 S3 准备好了我们的波士顿数据集,我们可以构建我们的训练脚本,并将其输入到 TensorFlow 估计器中。训练脚本将包含我们建立的 TensorFlow ANN 模型,以及我们正在通过 TensorFlow 估计器传递的其他超参数。
波士顿住房培训脚本
我们现在可以将这个脚本传递给 TensorFlow 估计器,它将适合我们准备开始训练的输入数据。
TF 估计器波士顿培训
训练将需要几分钟来完成,但是一旦成功完成,我们需要通过一个简单的调用从这些训练工件中创建一个模型。然而,在我们这样做之前,我们需要准备一个推理脚本。这个脚本让我们指定要传递给端点的数据类型(JSON、JSONline、CSV 等)。推理文件将使我们的端点清楚我们接受和输出什么类型的数据,我们可以将这个推理文件用于我们将要创建的两个模型。
帮助输入/输出数据格式的推理脚本
现在我们可以创建我们的模型,并传入这个推理脚本。
创建波士顿模型
汽油消耗培训和模型创建
现在,我们可以用汽油消耗量数据集重复同样的过程。我将跳过数据上传过程,因为这是完全相同的程序,但请确保将数据正确上传到 S3 或遵循代码库获取指导。
我们将再次构建一个训练脚本 t,这次是为汽油数据集定制的,并将它传递给我们的估计器,然后创建一个模型。
石油模型培训和模型创建
多模型端点创建
太棒了,我们已经准备好将两个模型添加到我们的端点。现在,为了创建端点,我们需要指定我们两个模型数据所在的 S3 位置,并确保它采用适当的 tar.gz 格式以及相同的存储桶。
多模型端点创建
使用多数据模型估计器,我们可以输入包含两个模型的模型工件的模型数据前缀。如果您为模型信息传入 model_1 或 model_2 并不重要,因为两者都在相同的容器中操作。我们可以通过下面的 Boto3 调用来确保我们的两个模型都存在。

MME 模型(作者截图)
然后,我们可以像部署单模型端点一样部署我们的端点。

多模型端点调用
现在我们可以用相同的端点测试我们的两个模型。
波士顿住房测验

波士顿房屋祈求(作者截图)
现在,让我们对汽油房屋数据集做同样的操作,看看两个模型的工作情况。
汽油消耗试验

汽油调用(作者截图)
通过初始参数,我们可以传入我们想要调用的模型,我们可以看到多模型端点的惊人功能。
整个代码和结论
要访问该示例的完整代码,请查看上面的链接。库还包含我构建和编译的各种其他 SageMaker 推理示例,你可以参考使用。多模型端点非常强大且经济高效,因为您可以将多个模型加载到一个端点中,而不是将一个端点与每个模型相关联。如果你有这些框架的用例,还有更多关于 SKLearn 和 PyTorch 的例子。
我希望这篇文章对使用 Amazon SageMaker 的人有用。如果你对 ML AWS 感兴趣,欢迎在评论中留下你的反馈或者在 LinkedIn 上联系我。如果对我的更多作品感兴趣,请务必关注我的 Medium 。感谢您的阅读。
使用 ONNX 运行时在边缘设备上部署 PyCaret 模型
关于如何将使用 PyCaret 训练的 ML 模型转换为 ONNX 以实现高性能评分(CPU 或 GPU)的分步教程

在 Unsplash 上由 Austin Distel 拍摄的照片
介绍
在本教程中,我将向您展示如何使用py caret(Python 中的开源低代码机器学习库)训练机器学习模型,并将它们转换为 ONNX 格式,以便部署在边缘设备或任何其他非 Python 环境中。例如,您可以在 Python 中使用 PyCaret 训练机器学习模型,并在 R、Java 或 c 中部署它们。本教程的学习目标是:
👉PyCaret 是什么,如何入门?
👉有哪些不同类型的模型格式(pickle,onnx,pmml 等。)
👉ONNX ( 读作 ONEX )是什么,有什么好处?
👉使用 PyCaret 训练机器学习模型,并在 ONNX 中转换,以便在 edge 上部署。
PyCaret
PyCaret 是一个开源、低代码的机器学习库和端到端的模型管理工具,内置于 Python 中,用于自动化机器学习工作流。PyCaret 以其易用性、简单性以及快速高效地构建和部署端到端机器学习管道的能力而闻名。要了解更多关于 PyCaret 的信息,请查看他们的 GitHub。
功能:

py caret——Python 中的开源、低代码机器学习库
skl2onnx
skl2onnx 是一个将 scikit-learn 模型转换为 onnx 的开源项目。一旦采用 ONNX 格式,您就可以使用 ONNX Runtime 之类的工具进行高性能评分。这个项目是由微软的工程师和数据科学家在 2017 年启动的。要了解这个项目的更多信息,请查看他们的 GitHub。
安装
对于本教程,您需要安装以下库。安装只需几分钟。
**# install pycaret** pip install pycaret**# install skl2onnx** pip install skl2onnx**# install onnxruntime** pip install onnxruntime
不同的模型格式
在我介绍 ONNX 及其优点之前,让我们看看目前有哪些不同的模型格式可用于部署。
👉泡菜
对于包括 PyCaret 在内的许多 Python 库来说,这是将模型对象保存到文件中最常见的格式和默认方式。 Pickle 将一个 Python 对象转换成一个比特流,并允许它存储到磁盘上,以后再重新加载。它提供了一种存储机器学习模型的良好格式,前提是推理应用程序也是内置的 python。
👉PMML
预测模型标记语言(PMML)是机器学习模型的另一种格式,相对来说没有 Pickle 那么常见。PMML 自 1997 年就已经存在,因此有大量应用程序利用这种格式。SAP 和 PEGA CRM 等应用能够利用 PMML 的某些版本。有一些开源库可以将 scikit-learn 模型(PyCaret)转换成 PMML。PMML 格式的最大缺点是它不支持所有的机器学习模型。
👉ONNX
ONNX ,开放神经网络交换格式是一种开放格式,支持机器学习模型跨库、跨语言的存储和移植。这意味着你可以使用任何语言的任何框架来训练你的机器学习模型,然后将其转换为 ONNX,可以用于在任何环境中生成推理(无论是 Java,C,.Net,Android 等。).与其他格式相比,ONNX 的这种与语言无关的能力使它非常强大(例如,除了 Python 之外,您不能使用任何其他语言保存为 Pickle 文件的模型)。
ONNX 是什么?
ONNX 是一种开放的格式,可以表示深度学习和传统模型。有了 ONNX,AI 开发人员可以更容易地在最先进的工具之间移动模型,并选择最适合他们的组合。ONNX 由微软、脸书和 AWS 等合作伙伴社区开发和支持。
ONNX 得到了广泛的支持,可以在许多框架、工具和硬件中找到。实现不同框架之间的互操作性,简化从研究到生产的路径,有助于提高人工智能社区的创新速度。ONNX 有助于解决与人工智能模型相关的硬件依赖性挑战,并支持将相同的人工智能模型部署到多个硬件加速目标。
来源:微软

https://microsoft.github.io/ai-at-edge/docs/onnx/
各种语言有很多优秀的机器学习库——py torch、TensorFlow、scikit-learn、PyCaret 等。其思想是,您可以使用任何工具、语言或框架来训练模型,然后使用另一种语言或应用程序来部署它,以进行推理和预测。例如,假设您有一个用。Net、Android 应用程序,甚至是边缘设备,并且您希望将您的机器学习模型预测集成到那些下游系统中。你可以通过将你的模型转换成 ONNX 格式来实现。Pickle 或 PMML 格式无法做到这一点。
主要优势:
👉互用性
在您喜欢的框架中开发,而不用担心下游推理的影响。ONNX 使您能够将您喜欢的框架与您选择的推理引擎一起使用。
👉硬件访问
ONNX 使得访问硬件优化更加容易。使用 ONNX 兼容的运行时和库来最大限度地提高硬件性能。这意味着,如果延迟是您关心的事情,您甚至可以在 GPU 上使用 ONNX 模型进行推断。

兼容性与互操作性
👉我们开始吧
资料组
对于本教程,我使用 PyCaret 的存储库中的一个名为 insurance 的回归数据集。你可以从这里下载数据。

样本数据集
**# loading dataset** from pycaret.datasets import get_data
data = get_data('insurance')**# initialize setup / data preparation** from pycaret.regression import *
s = setup(data, target = 'charges')

设置功能的输出(为显示目的而压缩)
👉模型训练和选择
既然数据已经为建模做好了准备,让我们使用compare_models函数开始训练过程。它将训练模型库中所有可用的算法,并使用 k-fold 交叉验证评估多个性能指标。
**# compare all models**
best = compare_models()

compare_models 的输出
基于交叉验证指标,最佳模型是 梯度推进回归器。 您可以使用save_model功能将模型保存为 Pickle 文件。
**# save model to drive** save_model(best, 'c:/users/models/insurance')
这将会以 Pickle 格式保存模型。
👉使用 Pickle 格式生成预测
您可以使用load_model函数将保存的模型加载回 Python 环境,并使用predict_model函数生成推理。
**# load the model** from pycaret.regression import load_model
loaded_model = load_model('c:/users/models/insurance')**# generate predictions / inference** from pycaret.regression import predict_model
pred = predict_model(loaded_model, data=data) # new data

在测试集上生成的预测
👉ONNX 转换
到目前为止,我们看到的是以 Pickle 格式(PyCaret 的默认格式)保存和加载训练好的模型。但是,使用 skl2onnx 库,我们可以在 onnx 中转换模型:
**# convert best model to onnx**
from skl2onnx import to_onnx
X_sample = get_config('X_train')[:1]
model_onnx = to_onnx(best, X_sample.to_numpy())
我们还可以将model_onnx保存到本地驱动器:
**# save the model to drive**
with open("c:/users/models/insurance.onnx", "wb") as f:
f.write(model_onnx.SerializeToString())
现在,为了从insurance.onnx生成推理,我们将使用 Python 中的onnxruntime库(只是为了演示这一点)。本质上,你现在可以在任何其他平台或环境中使用这个insurance.onnx。
**# generate inference on onnx**
from onnxruntime import InferenceSession
sess = InferenceSession(model_onnx.SerializeToString())
X_test = get_config('X_test').to_numpy()
predictions_onnx = sess.run(None, {'X': X_test})[0]**# print predictions_onnx** print(predictions_onnx)

预测 _onnx
请注意,当我们使用 PyCaret 中的predict_model函数时,predictions_onnx的输出是一个 numpy 数组,但如果您匹配这些值,数字都是相同的(使用 ONNX 时,有时您会发现小数点后第四位有微小的差异——很少使用)。
任务完成!
即将推出!
下周我将深入探讨 ONNX 转换,并讨论如何将整个机器学习管道(包括估算器和转换器)转换为 ONNX。如果你想自动收到通知,你可以在 Medium 、 LinkedIn 和 Twitter 上关注我。

PyCaret —作者图片

PyCaret —作者图片
使用 Python 中的这个轻量级工作流自动化库,您可以实现的目标是无限的。如果你觉得这很有用,请不要忘记给我们 GitHub 库上的⭐️。
想了解更多关于 PyCaret 的信息,请关注我们的 LinkedIn 和 Youtube。
加入我们的休闲频道。邀请链接此处。
重要链接
文档
博客
GitHub
stack overflow
安装 PyCaret 笔记本教程 贡献于 PyCaret
更多 PyCaret 相关教程:
[## 使用 PyCaret 编写和训练您自己的自定义机器学习模型
towardsdatascience.com](/write-and-train-your-own-custom-machine-learning-models-using-pycaret-8fa76237374e)
使用 Linux 将 Python APIs 部署到 Web
使用 FastAPI、Gunicorn、Nginx 和 CentOS 的完整 API 演练

菲利普·卡岑伯格在 Unsplash 拍摄的照片
web 运行在 Linux 上,我们现在生活在 API 时代。这两个事实加上 Python 是世界上最流行的编程语言,使得知道如何通过 Linux 部署 Python API 成为一项无价的技能。
Python 中的 API 开发通常被规范为 Django、Flask 或 FastAPI,以及其他一些框架。API 开发中最快的是名副其实的 FastAPI 库。
在本文中,我们将使用 FastAPI 生成一个简单的 API,并学习如何使用 Uvicorn、Gunicorn、systemd 和(可选的)NGINX 在 Linux webserver (CentOS)上部署它。我们将涵盖:
**> Prerequsites**
1\. EPEL
2\. Python
3\. NGINX**> Creating a Python Environment****> Python Setup**
- pip install
- API Code**> Systemd**
- The Gunicorn Service
- Common Errors**> NGINX Setup (Bonus)
** - Before We Start
- NGINX**> Other Useful Articles**
先决条件
在设置和部署我们的 API 之前,我们需要在 Linux 机器上安装一些东西。这些是:
- EPEL
- 计算机编程语言
- NGINX
EPEL
EPEL 安装了:
sudo yum install epel-release
EPEL 代表用于企业 Linux 的额外软件包。它是一个管理和维护一组用于 Fedora(及其衍生工具,如 CentOS)的 Linux 包的组织。
我们想要 EPEL 的原因是因为它允许我们通过yum安装大量开源软件包。
计算机编程语言
现在我们已经安装了 EPEL,我们可以继续快速安装 Python,只需:
sudo yum install python36
我们可以通过键入python3 -V来确认 Python 已经正确安装:

Nginx
要安装 nginx,我们只需要:
sudo yum install nginx

NGINX 层充当了我们的“原点”(我们的服务器)和互联网之间的中间人。
我们使用 NGINX 作为服务器的“反向代理”。这意味着 NGINX 创建了一个屏障,作为互联网和我们的服务器之间的网关。
我们的应用程序可以在没有 NGINX 的情况下工作,但是使用 NGINX 有几个好处,即:
- 我们可以隐藏“原始”服务器的特征。
- 更好地抵御 DoS/DDoS 和恶意软件。
https://www.nginx.com/resources/glossary/nginx/
https://en.wikipedia.org/wiki/Reverse_proxy
创建 Python 环境
理想情况下,我们希望将用于 API 的 Python 安装与服务器上的其他 Python 版本分开。我们通过在虚拟环境(venv)中使用单独版本的 Python 来实现这一点。
我们需要先安装virtualenv,它可能已经安装了——但是我们通过尝试安装来检查:
python3 -m pip install virtualenv
一旦virtualenv安装完毕,我们就可以创建目录来存放我们的 venv(和代码):
mkdir ~/project-dir
cd ~/project-dir
现在,我们安装一个 venv(以及它自己的 Python 版本),带有:
virtualenv <env-name>

每当我们想要切换到这个虚拟env——我们输入source apienv/bin/activate。我们需要为 Python 包的安装激活环境。

我们可以看到 apienv 环境是活动的,在控制台输入之前有 (apienv) 。
Python 设置
pip 安装
一旦我们有了我们的 venv 并且用source <env-name>/bin/activate激活了它,我们就可以pip install运行我们的 API 所需的包:
pip install fastapi gunicorn uvicorn uvloop httptools
API 代码
现在我们可以为我们的 API 编写代码了。当然,如果您有自己的 API 脚本,就使用它。我们将通过打开 Vim 在本地文件api.py中输入代码:
vim api.py
接着按i开始编辑文件。我们希望它看起来像这样:
一旦完成,我们通过键入ESC然后键入:wq和ENTER来保存并退出。这样,我们的 API 就建立起来了,并将使用 Uvicorn 运行。
我们还需要 Gunicorn 来处理我们的 Uvicorn workers 的多个实例,这将允许我们的 API 的多个实例并行运行。回到终端,我们可以初始化 Gunicorn 处理我们的 Uvicorn 工人:
gunicorn api:app -w 2 -k uvicorn.workers.UvicornWorker -b "0.0.0.0:5000"
这里,我们用我们在api中的代码和 API 实例app初始化 Gunicorn。
-w 2指定了两个工人。要使用的工人类型由 Uvicorn 提供,我们用-k uvicorn.workers.UvicornWorker指定。
最后,我们用-b “0.0.0.0:5000”将 Gunicorn 实例绑定到我们的外向端口5000。

前往您的服务器地址example.com:5000应该会在您的浏览器中显示 API 响应。在这一点上,你可以叫它一天,离开它。
虽然我很抱歉地说,我们还没有完全达到。
继续使用您的 API——之后,我们还有一些事情要做:
- 设置 Gunicorn 实例在后台运行并在引导时初始化。
- 为 Gunicorn 和 NGINX 创建一个套接字(类似于另一个内部信息网关)来进行通信。
- 正在设置 NGINX!
系统 d
我们使用 systemd 将 Gunicorn 实例设置为在后台运行。一旦服务器启动,我们的 API 就会启动并运行。
名称systemd指的是 Linux 中使用的一个软件套件,它作为一个统一的系统和服务管理器。我们将使用它来运行我们的 API,它将在我们的服务器后台发出嗡嗡声。可以在以下位置找到 systemd 服务目录:
/etc/systemd/system
Gunicorn 服务
在这里,我们创建一个新文件来运行 Gunicorn 实例。键入sudo vim <service-name>.service开始编辑新服务。

在这里,我们想写这样的东西:
这里发生了很多事情,让我们来分析一下。
我们保存并再次退出ESC,然后是:wq和ENTER。接下来,我们使用以下命令初始化并检查服务的状态:
sudo systemctl start api
systemctl status api
常见错误
如果您遇到这样的错误:

失败的服务状态将是这样的——希望您永远不会看到它。
有几个常见问题。最有可能的是:
- 服务文件语法不正确。
- 指定的路径是错误的(您的路径是
/home/user/<user>还是仅仅是/home/<user>?). - Gunicorn 文件权限错误。
要解决后者,您可能需要返回到~/api/apienv/bin并使用以下命令更改gunicorn文件的所有者:
sudo chown <user> gunicorn
运行后,您应该会看到以下内容:

活动服务状态。
此时,我们的代码将会运行。您应该能够前往example.com:5000并看到来自您的 API 的响应!
本文的其余部分是一个额外的收获,我们将设置 NGINX,我们可以认为它本质上是一个网络连接管理器——它非常有用,但可能会根据您当前的设置而变得复杂。选择权在你。
NGINX 设置
NGINX 充当我们面向外部的网关——NGINX 反向代理。这个设置看起来很吓人,但是相信我,它真的不太难。
开始之前
首先,我们需要对 API 使用的端口进行一些修改,以便它们可以与 NGINX 通信。
首先,我们需要创建一个内部套接字,NGINX 将使用它与 Gunicorn 通信。它本质上充当 NGINX 和 Gunicorn 之间的内部网关。
我们需要做的就是修改api.service中的 Gunicorn 命令来创建它。我们添加-m 007,并绑定到unix:api.sock而不是"0.0.0.0:5000"。这将在工作目录/home/user/api中创建 websocket:
ExecStart=/home/user/api/apienv/bin/gunicorn -w 3 **-b unix:api.sock -m 007** -k uvicorn.workers.UvicornWorker api:app
编辑我们的服务文件后,我们需要重新加载并重新启动它:
sudo systemctl daemon-reload
sudo systemctl restart speculate_api
NGINX
我们 API 的外向入口由/etc/nginx/conf.d/<domain>.conf中的server: server_name给出,如下所示:
一旦准备好,保存并退出(ESC、:wq、ENTER)。我们现在设置 NGINX 权限,允许nginx用户访问我们的用户目录:
sudo usermod -a -G <user> nginx
chmod 710 /home/<user>
然后,我们测试我们的新 NGINX 配置是否适用于:
sudo nginx -t
希望你会看到这个:

成功的信息
同样值得检查的是,这个新的配置文件包含在主nginx.conf文件中。在/etc/nginx/nginx.conf内,检查包含在/conf.d目录内的所有.conf文件:
include /etc/nginx/conf.d/*.conf;
在http {...}部分内:

如果一切正常,我们可以使用以下命令重启 NGINX:
sudo systemctl daemon-reload
sudo systemctl restart nginx
您现在应该能够在example.com:5000再次访问 API 了!

关于用 Python 将 API 部署到 web 的这篇文章到此结束!我们涵盖了很多内容,包括:
- API 中 EPEL、Python 和 NGINX 的基本知识
- Python 环境
- API 包和代码
- Gunicorn 和 Uvicorn
- Linux 系统 d
- NGINX 配置
所有这些都是很多的,不是一次就能完成的(对大多数人来说)。
当你阅读这篇文章的时候,我肯定会推荐你阅读我在下面列出的其他几篇文章。这些内容涵盖了我们在这里讨论的大部分内容,但是或者更深入,或者针对不同的设置/场景。
我希望你喜欢这篇文章!如果您有任何问题,请通过 Twitter 或在下面的评论中告诉我。如果你想要更多这样的内容,我也会在 YouTube 上发布。
感谢阅读!
其他有用的文章
使用 Uvicorn 和 Nginx 部署 Django > 3.1(异步)
如何在 CentOS 7 上使用 Gunicorn 和 Nginx 服务烧瓶应用
如何在 Ubuntu 15.10 上安装 NGINX 作为 Apache 的反向代理
使用 Azure 函数部署您的机器学习 Python 代码

Azure 函数是代码触发的事件,由于它们的无服务器功能,伸缩性很好。触发机制多种多样——基于时间的(CRON 函数)、http、存储触发器(blob、队列)等。函数也是独一无二的,因为它们可以用多种语言编写,如 C#、Python、Javascript 等。在本文中,我将演示一个简单的 ML python 脚本,它是使用 VS 代码通过 Azure 函数触发的。你可以在这里查看我的 git 回购。
要求:
- 加载 Azure 扩展的 VS 代码
- Azure 订阅(提供免费点数)
- Azure 函数 CLI 已安装。请关注https://docs . Microsoft . com/en-us/azure/azure-functions/functions-run-local?tabs = windows % 2c csharp % 2c bash
- 一个腌 ML 模型。在这里,我选择了一个简单的模型,它使用回归算法来预测一块房地产的价格,基于的因素包括建筑的年龄、离城市的距离、周围商店的数量、纬度和经度。关注的焦点是模型在 Azure 函数中的实现,而不是模型本身的准确性。
将 python 代码和 pkl 文件放在单独的文件夹中。建议使用虚拟环境来安装必要的文件。冻结同一文件夹中的需求文件。
启动 VS 代码。从扩展中启动功能应用程序,选择 http trigger 作为触发器,选择 Anonymous 作为触发器类型。启动存储 python 代码和 pkl 文件的工作空间和文件夹——自动创建需求文件。进一步添加了运行代码所需的必要文件,包括运行 pkl 文件所需的包。启动该函数会自动创建一个 init.py 和一个 function.json 文件,其他助手除外。
让我们更深入地了解一下 init.py 文件实际上在做什么——在这个基本代码中,init.py 文件是包含函数 app 的主要代码的脚本,它触发 http 并具有 post 和 get 请求。在对模型进行预测之后,json 转储的结果作为 numpy 数组返回。function.json 文件只是一个指向 init.py 文件的绑定器(会根据使用的触发器而改变)。请注意使用的匿名认证级别。
根据您的要求,您可以更改这些设置。例如,如果您基于 blob 的文件更改进行访问,请确保您已经准备好了安全的 SAS 密钥。
差不多就是这样,真的。现在是时候测试自己的功能 app 了。在命令提示符下,使用以下命令初始化该函数:
func init
func host start
您应该能够看到一些 ascii 字符。您将被定向到本地的一个链接。顺其自然吧。这说明功能 app 其实一直到现在都在无瑕疵的工作。
打开 git bash 并运行以下命令:
curl -w '\n' '[http://localhost:7071/api/real_estate?Age=25&Dist=251&Num_stores=5&Lat=24.9756&Long=121.5521](http://localhost:7071/api/real_estate?Age=25&Dist=251&Num_stores=5&Lat=24.9756&Long=121.5521)'
您当然可以更改年龄、距离等的值。在运行这个 bash 命令时,python 终端中应该显示成功,以及 bash 终端中的预测值。
通过 vscode 将其部署到 Azure 是最简单的方法。这非常简单——按照 Functions 扩展的提示使用部署命令。你的应用应该准备好了。使用部署的 weblink,并将相同的部分添加到 http link(?age = 25 & Dist = 251 & Num _ stores = 5 & Lat = 24.9756 & Long = 121.5521)。
你应该在你的网页链接中看到同样的回复。
好了,差不多了!!!—现在,这是一个使用 vscode 和 azure 函数触发 python 脚本的端到端管道。Azure 函数非常通用,可以与 datafactory 放在一个管道中,用于更复杂的工作。
在 SageMaker 实时端点上部署数千个模型,并提供自动再培训管道
艾米莉·韦伯和埃里克·托宾的联合文章
本帖也是 SageMaker 月的一部分!查看我们的日历,了解 SageMaker 的所有入门知识——以前所未有的速度构建、培训和部署模型。利用实践研讨会、专用工具和资源来提高团队的工作效率。

在 SageMaker Studio 中创建自动再培训管道
你正在开发一个应用程序,向全美各城市推荐下一个最好的食品配送。在过去的两年中,您已经研究出了一个基于 XGBoost 的大型多分类模型,它推荐城市级别的餐馆。芝加哥、纽约、旧金山、西雅图,所有这些都由专门的 SageMaker 终端托管。它们从你的应用程序接收请求,处理数据,并在一位数毫秒内返回建议的餐馆。突然,一个实习生进来演示了在你的数据集中为每个客户训练一个模型的可能性。您的准确性突飞猛进,但从成本角度来看,您担心这种做法的可行性。在你的数据库中,有成千上万个不同的买家,你怎么可能为每个人提供一个模型呢?你如何让这些模型跟上最新的购买趋势?
在亚马逊 SageMaker 上输入[多型号端点。
说到底,从 SageMaker 的角度来看,一个模型是两件事。它是坐落在 S3 的训练有素的模型人工制品,它是你包装在图像中的推理脚本。无论您是使用云中的 spot 实例廉价地训练该模型,从您的笔记本电脑加载它,从您办公桌下的 NVIDIA 设备编译它,还是从 H20 或 DataRobot 移植它,只要您可以定义该模型的计算要求,您就可以在 SageMaker 上托管它。
现在,让这笔交易更加划算的是您可以从一个 SageMaker 端点托管任意多的模型。你实际上有两个选择。如果您正在考虑一个场景,其中您有一个建模框架,比如 XGBoost,并且您想要在该框架内将它扩展到成千上万个模型,您将想要选择“多模型端点”或者,如果您有几个不同的建模容器想要在单个端点上托管,您会看到我们刚刚推出的多容器方法](https://github.com/aws/amazon-sagemaker-examples/blob/master/advanced_functionality/multi_model_xgboost_home_value/xgboost_multi_model_endpoint_home_value.ipynb)。
在这篇文章中,我们将关注“多模型端点”我们还将讨论如何通过自动再培训渠道保持这些信息的更新。
你问 SageMaker 到底是怎么处理托管上万个模型的?很简单。我们用 S3。

您要做的第一件事是选择将托管您的模型的容器。
在大多数情况下,最简单的方法是使用我们称之为“脚本模式”或托管容器。
脚本模式让你从 SageMaker Python SDK 和导入估算器,绕过 Docker 构建步骤。您可以使用我们的深度学习容器作为基础并扩展它们,直接引入您的代码,指定框架版本,并定义您需要的任何自定义需求。SageMaker 从一个计算 和一个容器视角管理后端,两者都在云中为您构建一个专用实例,并帮助运行您的代码。
您完全可以在 SageMaker 的脚本模式下运行完整的培训任务。您还可以用您的工件和推理脚本托管一个预训练的模型。首先在 SageMaker SDK 中定义您的模型,就像这样。

注意,您正在使用您自己的训练图像,并且指向您自己的存储在 S3 的模型工件。这意味着在 SageMaker 上部署模型之前,你可以在任何地方训练你的模型!
接下来,我们将使用相同的 SageMaker SDK 来创建多模型端点。

通过 SageMaker 上的多模型端点服务数千个模型
创建多模型端点的最大区别在于,模型工件在调用后只出现在端点 ***上。SageMaker 完全管理哪些工件在磁盘上,哪些工件在你的桶中。我们根据请求将这些数据从 S3 拷贝到端点,并将它们放入 RAM 以响应您的端点请求。
多模型端点非常适合您训练和部署数千个模型的情况,在您的客户群中每个单元可能有一个模型。而这几千个模型需要在同一个软件框架里,所以所有 TensorFlow 模型,或者所有 XGBoost,所有 SKLearn 模型等等。另一方面,多容器端点是当你总共有 5-6 个模型时,但是这些模型在不同的软件框架中,并且有不同的推理脚本。例如,如果您为一个 TensorFlow、一个 XGBoost 和一个 PyTorch 模型提供服务,那么多容器端点是一个不错的选择。这里我们将关注多模型端点。
现在,您仍然需要考虑针对该端点的流量。如果你真的在为数以万计的客户服务,实际上最好的办法就是直接联系我们。作为亚马逊人和机器学习专家解决方案架构师,我们工作的很大一部分是直接与客户迭代他们的最终架构计划,以确保它符合最佳实践。你不必单干!我们可以帮忙。
所以我们已经旋转了我们的端点。我们如何与它互动?***

注意,我们可以在这个推理请求中传递模型工件的名称。这意味着我们可以动态地确定我们想要使用哪个模型进行推理*。
最常见的生产方式是将推理代码包装在 Lambda 函数中。然后你可以从你的应用程序逻辑中调用你的 Lambda 函数,不管它在哪里。*
自动再训练管道
我们已经了解了在 SageMaker 多模型端点上托管数千个模型,但是我们如何建立一个自动再培训管道呢?就像托管一样,你的再培训管道的核心其实是位于 S3 的对象,以及打包在 SageMaker 中的图像。有了再培训管道,在高层次上你想完成几个关键步骤。
- 指向您的新数据集
- 重新培训您的模型
- 评估这个,如果好,部署!
*就编排所有这些组件而言,您有多种选择。如果你刚刚开始,一般我们推荐 SageMaker-native 接手这个, 管道 。Pipelines 是一种直接从 SageMaker Studio 构建第一个 MLOps 工作流的简单方法,它使用了 SageMaker 用户体验中的所有相同结构。您可以在 ide 中构建一个非常好的 DAG。
如果你已经熟悉编排工作流,你可能会选择一些与现有企业编排策略很好地配合的东西,如 Apache Airflow、Jenkins、Code Pipeline 或 KubeFlow。SageMaker 可以很好地处理所有这些问题,并且为气流和库伯流都提供了本地插件。
我们将在下面的管道中一步一步地这样做:*
- 为住房数据定义数据预处理脚本、培训和模型评估脚本
- 将脚本导入 SageMaker pipelines API,创建一个有向无环图
- 实现一个 Lambda 函数来启动管道执行
- 测试解决方案,执行新的管道,将模型加载到模型注册中心,并将它们部署到我们的多模型端点上。
首先,我们来看看火车步。注意,虽然这个例子使用了一个内置算法,但是您可以很容易地指向您自己的图像和/或脚本。我们构建了一个估计量,并使用它来定义我们的超参数。

有了估计器,我们将把对象传递到管道 API* 。这发生在我们定义*训练步骤时。**

接下来,我们将清洗并重复管道中的所有剩余步骤。这意味着我们正在创建预处理、训练、评估和有条件加载到模型注册中心的步骤。

现在我们有了一条管道!您可以在 Studio 中查看这个管道并启动执行。

我们选择为每个型号创建独特的渠道。这意味着有一条通往芝加哥、圣地亚哥、洛杉机、休斯顿等地的管道。虽然从 MLOps 的角度来看,这听起来像是很大的开销,但是它确实给了您分别训练和处理每个模型的灵活性。因此,如果突然一个 KNN 模型开始在一个地区更好地工作,而一个深度学习模型在另一个地区更好,你可以在你认为合适的时候将这些组件添加到每个管道中。您还可以分别管理这些数据的处理,以适应独特的数据流、见解和利益相关者。

一旦这些管道执行,它们将模型放入模型注册中心。这是 Studio 中的一个附加层,它让您可以看到您已经创建的模型,以及这些模型的版本,因此您可以更容易地部署它们。

这是我们所有管道的截图,可以在 Studio 中看到。
这里有一个我们模型包组的截图,加载在模型注册表中。
这是单个模型包组的视图——尤其是所有版本都很容易看到!

对于每个版本,您可以查看这是否被批准。

就这样结束了!您可能会想,哎呀,这比我预期的要多得多,但事实是,这实际上比一些客户开发的要简单得多。特别是当您大规模地投入复杂的数据操作时,除了最先进的模型之外,这些项目可以很容易地扩大范围。
这就是为什么把你的平台开发卸载到 AWS 上是如此重要。这是使用托管服务的核心—通过将您的基础架构管理和开发卸载到云上的专用服务,您的团队可以专注于真正使您的业务脱颖而出的功能。所有的功能请求、平台增强、错误修复和低级软件开发都可以推给 Amazon 团队,优先考虑您最关心的数据科学结果。
所有图片均由作者制作
使用 Docker 和 Docker Compose 在任何其他机器上部署您的 AI 引擎

数据科学家入门包——第 3 部分(如果它能在我的笔记本电脑上运行,那它肯定也能在你的笔记本电脑上运行!)
当从事人工智能项目时,我们倾向于在笔记本电脑上进行所有的初始开发,然后与客户沟通。可能会发生这样的情况,客户端不共享相同的操作系统,这意味着代码可能不会在客户端运行。这就是 Docker 发挥作用的地方!
在本文中,我们将探讨 Docker 背后的主要动机,以及它如何允许构建支持更快开发和部署的与操作系统无关的产品。
目录
摘要如下:
**1-什么是 Docker?
2-安装** 3-从人工智能项目到 Docker 映像
4- Docker 撰写
5-最佳实践
什么是 Docker
Docker 是一个进程隔离器工具,允许在受限环境中运行应用程序。它经常与虚拟机混淆,虚拟机“虚拟化”物理资源,而 Docker 虚拟化执行环境,因此启动和运行起来更轻、更快。

作者图片
Docker 的发明主要是为了使程序与操作系统无关,以便于开发和部署。例如,一个数据科学家可以在 macOS 上编写他的程序,并在客户端的 it 基础设施上使用 Docker 运行它,而不管它的操作系统是什么(macOS、linux、Windows 等等)。

作者图片
Docker 引入了不同的概念:
【Dockerfile】:以书面顺序缓存执行的一组动作
【Docker image:文件和安装系统(来自 Docker file)您将需要在没有任何附加进程的情况下运行您的程序
【Docker container:是一个映像实例,它托管所有文件和所需程序的副本,并通过终端
附加一个交互进程。dockerignore: 一个文件,它包含了您不想在 docker 映像上包含的所有元素的路径
entry point . sh:一个 cmd 文件,它决定了运行容器时要启动的命令
Docker 还提供了 Dockerhub ,云服务,可以托管共享的 Docker 图片,可以由团队进行推送和拉取。它还托管官方语言图像,如 Python 的图像。
装置
你可以通过选择你机器上安装的操作系统,使用 Docker 的官方网站来安装 Docker。
安装完成后,启动 Docker 并运行以下命令行来检查是否一切正常:
docker run hello-world

作者图片
从人工智能项目到 Docker 图像
设置
一旦开发稳定下来,你的人工智能项目的“dockerization”就开始了,我们假设它是用 python 语言编写的。
文件 Dockerfile,。dockerignore 和 entrypoint.sh 被放在资源库的根目录下,如下所示(查看我以前的文章了解项目组织):

作者图片
+我们将入口点. sh 定义如下:
#!/bin/bash
set -xe
case $1 in
test)
python -m pytest -v --tb=line tests/unit_testing.py action_1)
python app.py fonction_1;;
action_2)
python app.py fonction_2;;esac
+创建 Dockerfile 🐳:
- 从 Dockerhub 选择 python 版本,说python:3.7-slim-buster带 debian OS:
*FROM python:3.7-slim-buster*
- 使用 apt-get 安装必要的模块(例如 liblept5):
*RUN apt-get update -y\
&& apt-get install -y liblept5*
- 创建文件夹 data/ 作为工作目录:
*RUN mkdir /data
WORKDIR /data*
- 我们将本地存储库的所有文件和文件夹复制到 Docker 镜像的文件夹 /data 中,除了中提到的那些。dockerignore* 😗
*ADD . /data*
- 我们安装 Virtualenv ,创建 project_vir_env,激活它,然后在其中安装所有的 python 需求:
*RUN pip install virtualenv
RUN virtualenv project_vir_env
RUN . project_vir_env/bin/activate
RUN pip install -r packages.txt*
- 我们向入口点文件添加执行权限,并将其设置为:
*RUN chmod +x /data/entrypoint.sh
ENTRYPOINT ["data/entrypoint.sh"]*
文件如下:
*FROM python:3.7-slim-buster
RUN apt-get update -y \
&& apt-get install -y liblept5 \
RUN mkdir /data
WORKDIR /data
ADD . /data
RUN pip install virtualenv
RUN virtualenv project_vir_env
RUN . project_vir_env/bin/activate
RUN pip install -r packages.txt
RUN chmod +x /data/entrypoint.sh
ENTRYPOINT [ "/data/entrypoint.sh"]*
+我们也定义。dockerignore :
*project_vir_env/
notebooks/
.vscode/
**/__pycache__/
.DS_Store*
发动
为了构建docker 映像,首先启动docker 引擎然后运行以下命令行:
*docker build -t nameofdockerimage .*
- -t:用于命名图像
- 。:是 Dockerfile(当前文件夹)的位置
您可以使用以下命令行运行容器:
*docker run -v $PWD:/data/ nameofdockerimage entrypointfunction*
- -v:用于定义卷并将您的当前目录(项目存储库)与您的容器的数据/* 文件夹链接起来*
- **文件名称:与构建阶段使用的名称相同
- **entrypointfunction:entry point . sh(test,action_1 或 action_2)中定义的函数之一
你可以检查这个 cheat shee t 中可能的 docker 命令。
Docker 撰写
当处理一个复杂的项目时,最终产品可能由不同的服务组成,比如一个前端,一个 DS AP I,和一个数据库。Docker-compose 是一个 docker orchestrator,它帮助你“dockerize”并以多容器格式组织你的所有服务。
为了便于说明,我们将考虑一个带有Streamlit前端的 python 应用程序,它调用一个FlaskAPI来计算两个数之和。其结构如下:

作者图片
该项目的结构如下:

作者图片
每个服务都有自己的 Dockerfile 文件:
- 数据科学 API 的 Dockerfile:
*FROM python:3.7-slim-buster
RUN mkdir /ds_api
WORKDIR /ds_api
ADD . /ds_api
RUN pip install virtualenv
RUN virtualenv api_vir_env
RUN . api_vir_env/bin/activate
RUN pip install -r requirements.txt
EXPOSE 8080
ENTRYPOINT ["python"]
CMD ["app.py"]*
- 前端的 Dockerfile:
*FROM python:3.7-slim-buster
RUN mkdir /frontend_dir
WORKDIR /frontend_dir
ADD . /frontend_dir
RUN pip install virtualenv
RUN virtualenv front_vir_env
RUN . front_vir_env/bin/activate
RUN pip install -r requirements.txt
EXPOSE 8501
ENTRYPOINT ["streamlit", "run"]
CMD ["app.py"]*
DS API 暴露在端口 8080 上,而前端暴露在端口 8501 上
为了同时管理这两个服务,我们需要创建一个 docker-compose.yml 🐳:
- 我们首先设置 docker-compose 版本
- 然后,我们定义将在不同容器中启动的应用程序的服务。在每个服务器中,我们定义:
+容器名
+主机名
+构建(服务 Dockerfile 的文件夹和名称)
+端口(exposition): 机器 _ 端口:容器 _ 端口
+重启(方法)
*version: '3'
services:
datascience_api:
container_name: datascience_api
hostname: datascience_api
build:
context: ./datascience_api
dockerfile: Dockerfile
ports:
- 8080:8080
restart: unless-stopped front:
container_name: frontend
hostname: frontend
build:
context: ./frontend
dockerfile: Dockerfile
ports:
- 8501:8501
restart: unless-stopped
depends_on:
- datascience_api*
NB1 :前端服务依赖于data science API,首先需要运行。
NB2 :前端通过 http 协议使用其容器名调用 DS API:
*requests.post(“http://datascience_api:8080/add", params=query).json()*
docker-compose 文件完成后,我们在项目的根目录下运行以下命令行:
*docker-compose build*

作者图片
*docker-compose up*

作者图片
可以使用以下命令行来可视化正在运行的容器:
*docker-compose ps*

作者图片
因为容器和本地机器使用相同的端口,所以我们可以在我们机器的浏览器上打开前端:

作者图片
你可以在 github 库中找到所有的脚本。
最佳实践
- 冻结所有提取图像的版本(python、java),使用最新版本会使生产环境不稳定
- 启动带有测试入口点的第一个容器,以检查所有的安装都正确执行了
- 将 docker 容器与卷进行映射,以便进行实时开发,而无需在每次更改时进行重建
- 将每个服务单独归档,以便于开发和调试
结论
我希望您喜欢阅读这篇文章,并获得 docker 的第一手经验。它将使您能够更快、更有效地部署您的产品,无论开发是在哪里进行的。
请随时查看我以前的 DS Starter pack 文章:
- 数据科学项目中的必备工具
- 关于 Git,GitHub & GitLab 你需要知道的一切
轻松部署您的 Jupyter 笔记本电脑— Python 版
使用活页夹 Repos 部署笔记本电脑
通过 7 个简单的步骤,让您的 Jupyter 笔记本在其他人的机器上运行

在 Unsplash 上由 Lidya Nada 拍摄的照片
介绍
在这篇文章中,我要帮助你永远不要说—
“但是……它在我的笔记本电脑上运行正常😥“再也不会了。
我将向您展示如何通过 7 个简单的步骤部署您的笔记本电脑😄。
想象一下。你已经花时间在 Jupyter 笔记本上构建了一个很棒的机器学习管道。它在你的电脑上首尾相连地运行,现在你想把它分享给你的老板或 LinkedIn 网络,以显示你有多棒。
“这是容易的部分”,你天真地对自己说。
“我会把它附在一封邮件里,或者发布一个指向 GitHub 知识库的链接。瞧。
如果你曾经遇到过这种情况,你就会知道试图分享工作的挫败感。
您可能面临的复杂情况如下:
😡笔记本中的代码因库依赖而出错。
😡用户不能与笔记本进行交互。
😡笔记本中使用的数据存储在您的本地机器上。
好消息是,实际上有一种非常简单(而且免费)的方法来部署您的 Jupyter 笔记本电脑,并避免所有这些常见问题。而且,你也不必是一个软件工程专家。
👍我们可以使用活页夹存储库部署我们的笔记本电脑。
在进入细节之前,让我们简单地谈论一下绑定器存储库。
什么是活页夹存储库?
绑定器是一个代码库,至少包含两个元素:
☑️Code 或者你希望人们能够运行的内容。出于我们的目的,这将是一个 Jupyter 笔记本
环境的☑️配置文件。绑定器使用这些来构建代码运行所需的环境。
最棒的是,有在线、开源、活页夹回购服务,可以让你轻松部署 Jupyter 笔记本。
在本教程中,我们将使用我的活页夹。由 binder 社区维护的一个易于使用的服务,既作为 Binder 服务,也作为 BinderHub 技术的演示。
我们开始吧!
先决条件
本教程的重点是部署基于 python 的 Jupyter 笔记本。因此,我假设读者已经熟悉 Jupyter 笔记本。
你需要一个 GitHub 账户来存储你的项目,包括任何使用的 CSV/数据。如果您没有 GitHub 帐户,您应该在继续之前创建一个。
部署您的笔记本电脑
我已经创建了一个小的 Jupyter 笔记本,为我们的部署教程绘制了一些数据。我会把这个放到 GitHub 上。
步骤 1——创建一个 GitHub 存储库来保存项目,您可以随意命名您的 GitHub repo。
我把我的名字叫做“部署 _ 笔记本 _ 示例”(…非常有创意,我知道)。
步骤 2 —使用以下代码创建一个 Jupyter 笔记本:
从 GitHub 读取 CSV
绘图条形图
第一段代码是从 GitHub 存储库中读取 CSV 文件的函数。您需要将 url 更改为存储库中数据文件的位置。
步骤 3——创建一个需求文本文件并上传到 GitHub。
该文件包含 Jupyter 笔记本的所有库依赖项。这就是活页夹如何知道安装什么库来重新创建您的笔记本在其他人的机器上顺利运行所需的环境。
最简单的方法是在你的 Jupyter 笔记本上运行“ pip freeze ”。这将显示您环境中安装的所有库。只需将您在笔记本中使用过的库复制粘贴到记事本中,并另存为“需求”。
注意,库也包含版本是很重要的。
如果操作正确,您的需求文件应该如下所示:

作者图片:需求文件
⭐You 应该只复制你已经导入到笔记本的库!
步骤 4——将您的 Jupyter 笔记本、csv 文件和需求文本文件上传到 GitHub repo。
你的 GitHub repo 应该是这样的。

图片作者:GitHub repo:
第 5 步——找到我的活页夹
将包含项目的资源库的 GitHub URL 粘贴到窗口中。
这里写着 Git ref type inmain。
其中在笔记本文件名中显示笔记本类型的路径。您可以通过点击 GitHub 存储库中的笔记本并复制文件路径来获得笔记本文件名。
一旦完成,只需点击 启动 按钮。我的活页夹将在几分钟内构建您的活页夹回购。
一旦完成,你就可以和任何你想在他们的机器上运行你的项目的人分享这个链接。
🚀点击活页夹按钮获取您的链接!

作者图片:活页夹示例
第 6 步——获取您的活页夹链接,与世界分享!
庆祝
看,这很容易,希望你再也不用说“但是……它在我的笔记本上工作了”。
🌈如果您觉得这很有帮助,请留下一些反馈或与想要展示其 Jupyter 笔记本的朋友分享。
谢谢
https://www.linkedin.com/in/john-adeojo/ https://github.com/john-adeojo/deploy_notebook_example
使用 AWS Fargate 部署您的 Python 应用程序—教程

*AI 创作了作者的艺术。在 opensea 上看到的 as NFT:https://opensea . io/assets/0x 495 f 947276749 ce 646 f 68 AC 8 c 248420045 cb7b5e/88390065957809873863678979246400438929541864483832853795295379539539537953795395379537953795379953953953953795379 受到雅各布·欧文斯的启发【https://unsplash.com/photos/1HFzTWbWA-A 的
目录
- 关于本文
- 我应该使用哪种 AWS 基础设施类型
- AWS 账户
- 设置 AWS 凭证
- 使用 IAM 中的用户和角色设置凭证
- 在弹性容器注册表(ECR)中创建一个存储库
- 配置一个集群
- 创建任务以在 AWS 中运行 Docker 容器
- 执行任务
- 在网页中暴露定义的端口
- 在线观看您的应用程序
- 奖励:调查错误
- 免责声明
- 关于
关于这篇文章
在本文中,我将介绍在 AWS 中启动一个示例 web 应用程序的步骤。在我的上一篇文章中,我谈到了用 python 创建自己的 web 应用程序,以及如何用 AWS Lambda 部署它:
现在我想测试另一种基础设施类型。本文假设您熟悉构建和容器化 web 应用程序。在 python 设置中,我总是使用 Flask 和 Docker(参见以前的文章)。然而,本文主要关注部署这样一个应用程序的“devops”视角。我将在下面的文章中介绍更多的方面,比如设置一个合适的域名和使用额外的服务,比如负载平衡。
我使用 AWS 是因为我已经在我的上一个项目中使用了它,并发现它有很好的文档记录,操作起来很直观,即使有如此多的选项可供选择。
从目录中可以看出,本文的主要部分包括:
- 使用 AWS 凭证设置和连接本地开发
- 在弹性容器注册表(AWS ECR)中创建一个存储库
- 创建集群和任务,以便在云中运行 docker 容器
我应该使用什么类型的 AWS 基础设施
这里有一篇很棒的文章我想推荐:https://medium . com/thundra/getting-it-right-between-ec2-fargate-and-lambda-bb 42220 b 8 c 79
他在我看来总结得很完美。因此,我想要的是部署我的容器,但不想更深入地了解基础设施。这就是我选择 AWS Fargate 的原因。
AWS 帐户
首先,您需要创建一个 AWS 帐户。他们会指导你完成整个过程,不会有任何困难。
设置 AWS 凭据
如果您在证书部分遇到问题,请查看本文以供参考。
AWS 凭据
首先,你需要得到一个 AWS access key id和access key
使用 IAM 中的用户和角色设置凭据
我尽可能简单地分解它:
- 在 IAM 仪表板上,单击“添加用户”按钮。
- 为用户提供一个名称,并选择编程访问的访问类型。
- 在“设置权限”屏幕中,选择 amazone C2 containerregistryreadonly、amazone C2 containerregistryfull access、amazone C2 containerregistrypower user 的权限。
- 标签是可选的。
- 查看用户详细信息。
- 复制用户密钥并将其保存在安全的位置,因为在以后的阶段会用到它们。

添加权限;作者截图
在项目中添加凭据
在你的根目录下创建一个.aws/credentials文件夹
mkdir ~/.aws
code ~/.aws/credentials
并从 AWS 粘贴您的凭据
[dev]
aws_access_key_id = YOUR_KEY
aws_secret_access_key = YOUR_KEY
与config相同
code ~/.aws/config[default]
region = YOUR_REGION (eg. eu-central-1)
注意,code是用我选择的编辑器 vscode 打开一个文件夹。
将分配给用户的 AWS 访问密钥 id 和秘密访问密钥保存在文件~/中。AWS/凭据。请注意。aws/ directory 需要在您的主目录中,并且凭据文件没有文件扩展名。
在弹性容器注册中心(ECR)中创建一个存储库
搜索 ECR,然后您将进入可以创建新存储库的页面。

创建存储库;作者截图
之后,您可以看到新的回购协议:

存储库概述;作者截图
接下来,我们要获取推送命令:

推送命令;作者截图
只需按照这些说明为 AWS 连接设置本地 repo。要意识到你是项目的根本,这样一切都会顺利进行。
确保您已经安装了 AWS CLI,或者按照官方文档进行安装。
如果你在这里有问题,只需谷歌错误信息。通常,策略和您的用户会有问题。这个 SO 问题帮了我:https://stack overflow . com/questions/38587325/AWS-ECR-getauthorizationtoken
执行推送命令后,您将拥有在线映像:

知识库中的 Docker 图像;作者截图
配置集群
接下来,转到“集群”(在亚马逊 ECS 下,不是 EKS!)在菜单里。
- 选择“仅网络”模板
- 添加姓名
- 创造

创建一个集群;作者截图

启动集群;作者截图
在这一部分,我有时会得到错误消息。如果您遇到这种情况,您可以简单地重新创建集群。如果一切都设置正确,它应该工作。
创建一个任务以在 AWS 中运行 Docker 容器

定义任务;作者截图
转到“任务定义”并创建一个与 Fargate 兼容的新任务。

选择 Fargate 任务;作者截图
然后
- 添加姓名
- 指定任务大小(我使用最小的选项)
- 添加容器

配置任务;作者截图
- 添加容器的名称
- 将从 CLI 命令获得的映像地址复制到映像被推送的位置
- 添加暴露的端口(在您的 docker 文件中指定)

设置容器;作者截图
然后创建任务

已完成的任务;作者截图
现在,您应该已经在 Fargate 中定义了一个任务,并连接了您的容器。
执行任务
现在,您可以运行您定义的任务:

运行任务;作者截图
选择 Fargate 作为午餐类型,并在表单中添加提供的下拉选项(集群 VPC 和子网)

运行任务;作者截图
之后,您可以运行该任务,它应该是这样工作的:

成功的任务;作者截图
在网页中显示定义的端口
由于我们定义了一个特定的端口,现在我们需要通过 security 选项卡公开它。
- 单击您定义的任务
- 点击 ENI Id 进入网络界面
- 点击您的网络 ID
- 转到“安全组”
- 将您的端口作为自定义 tcp 添加到入站规则中

任务概述;作者截图

ENI 身份证概述;作者截图

编辑入站规则;作者截图
在线观看您的应用
在任务选项卡中,您将看到您的公共 IP 显示。只需导航到相应端口的页面,您就会看到您的网站

静态网站
截图中显示的 IP 地址不再工作,以避免 AWS 成本。然而,这篇文章是一个更大项目的一部分,我将在www.shouldibuycryptoart.com下发布这个项目。该应用程序正在开发中。如果你想关注它的发展,请随时联系我或关注我的社交媒体账户。
奖励:调查错误
由于一些特定的标志,我在本地容器开发上运行时,我的应用程序中的特定函数出现了一些错误。
在容器下的任务概述中,您可以检查 cloudwatch 中的日志。点击链接,它会显示你的应用崩溃的原因:

链接到 Cloudwatch 的任务概述;作者截图

调查 Cloudwatch 日志;作者截图
现在你可以调试你的程序了。
编码快乐!
放弃
我与本文中使用的任何服务都没有关联。
我不认为自己是专家。除了做其他事情,我只是记录事情。因此,内容并不代表我的任何专业工作的质量,也不完全反映我对事物的看法。如果你觉得我错过了重要的步骤或者忽略了什么,可以考虑在评论区指出来或者联系我。
这写于 2021 年 3 月 6 日。我无法监控我的所有文章。当你阅读这篇文章时,提示很可能已经过时,过程已经改变。
我总是乐于听取建设性的意见以及如何改进。
关于
丹尼尔是一名艺术家、企业家、软件开发人员和商业法毕业生。他的知识和兴趣目前围绕着编程机器学习应用程序及其所有相关方面。从本质上说,他认为自己是复杂环境的问题解决者,这在他的各种项目中都有所体现。

连接到:
直接:
艺术相关:
- 中等/最先进的
- Instagram/art_and_ai
- 稀有的
- 公海
- 已知产地
- 魔鬼艺术
分三步在 Heroku 上部署您的 Python 机器学习模型
在 Flask Web 应用程序上部署 ML 模型以供公共使用的说明性教程。
先决条件:
- Heroku 账号(如果你还没有的话,在【https://www.heroku.com/】的注册)
- GIT 安装在本地 PC 上(免费在https://git-scm.com/downloads安装 GIT)
- 一个用 python 开发的经过训练的 ML 模型(本教程中将其命名为 model.pkl )。
本教程的目的
因此,在您的本地开发环境中,您有一个工作的 ML 模型,并且您停留在“模型部署”阶段,如下面的 ML 生命周期所示:

作者图片|展示 ML 生命周期
那你来对地方了!本文的其余部分将关注于模型部署步骤。完整的源代码可以在我位于 https://GitHub.com/incubated-geek-cc/your-custom-app-name 的 github 获得,你可以随意把它作为你自己的☺使用
注:本教程中使用的样本 ML 模型用于预测一个人基于几个特征(逻辑回归模型)选择寻求精神保健治疗的可能性。根据您的 ML 模型的用例,在下面的演示文件中相应地调整参数。
第一步。在 Heroku 上创建一个新的应用程序

图片作者| 第一步:登录 Heroku 账户后,在选择“创建新应用”。第二步:输入你想要的 web app 名称。第三步。选择“创建应用程序”。
第二步。启动本地电脑上的项目文件夹
作者的代码片段|将 ML 模型( model.pkl )和以 JSON 格式( X_test.json) 存储的模型输入的列参数放在“models”文件夹中。
每个文件内的内容(requirements.txt,runtime.txt,Procfile,app.py,X_test.json,index.html,run_app.bat):
解释和注意事项:
- requirements.txt —包含设置 Flask web 应用程序和加载 ML 模型的所有 python 依赖项。建议:为了避免本地 PC 上的 python 库版本冲突,建议在 python 虚拟环境中进行开发工作。
创建一个 python 虚拟环境—(将其命名为)。env【本教程中的 ,打开命令提示符并运行以下命令:
作者代码片段|请注意,上述命令适用于 Windows 操作系统。对于 MacBook/Unix 用户,运行**source env/bin/activate** in your shell terminal instead to activate your python virtual environment.
重要: requirements.txt 中的 Python 包依赖应该包括用于开发你的 ML 模型的包以及用于 web app 部署的Flask+guni corn。
要自动提取 python 依赖项,运行命令:pip freeze>requirements . txt**
- runtime . txt-指定用于开发模型的 Python 版本。
例如对于 python 3 . 7 . 9 版本,文件内容应该是: python-3.7.9
对于 python 3 . 7 . 2 版本,文件内容应为: python-3.7.2
重要提示:请注意,本文件区分大小写和精确。关键是“python-3.7.x”要用小写字母输入,不能有空格。如果另外指定,Heroku 版本将失败,例如“ P ython-3.7.9”(大写字母“P”)或“python 3.7.9”(无 hypen“-”)。
- X_test.json —您的 ML 模型的输入参数名称的 json 数组。
- index.html—为用户选择输入和检索模型输出结果而设置的极简用户界面。
重要提示:务必注意在index.html*中找到的表单输入名称与 X_test.json 中陈述的特征相对应*
要在 localhost 上测试 web 应用程序,请继续运行 run_web.bat 文件,并打开浏览器导航到 http://localhost:5000/ 。您应该能够查看以下用户界面:

作者图片|通过 run_app.bat 文件从本地主机运行 Flask app 时index.html文件的预览
通过选择以下表格输入,输出 ML 模型的结果:

图片作者|注意,在左边,预测的答案是“是”,而在右边,预测的结果是“否”,这取决于用户的选择。
第三步。在项目文件夹中启动 GIT
确保 web 应用程序在本地 PC 上顺利运行后,右键单击并打开项目文件夹中的 Git Bash 终端。运行以下命令:

作者图片|网络浏览器应自动打开,并选择如上所示的“登录”。在您的 Git Bash 终端上,应该会出现heroku:Waiting to log in…,log in…done。
最后,打开另一个 Git Bash 终端(在项目根文件夹中)并运行以下命令:
作者代码片段|根据您的 heroku web 应用程序的名称,相应地更改参数。
Heroku 应根据 requirements.txt 文件中规定的 python 依赖关系,使用 runtime.txt 中规定的特定 python 版本,继续构建应用程序。
最后,所有的源代码都构建好了,部署也完成了!恭喜你!
(忽略) 你现在有你的机器学习模型可供公众访问了:https://your-custom-app-name.herokuapp.com/
注意:由于 Heroku 托管平台的变化,web 应用程序没有迁移到 https://your-custom-app-name.onrender.com/。请忽略上面的 Heroku 应用程序(配置可以保持不变)
本教程中的所有源代码都可以在我的 GitHub 上找到:https://github.com/incubated-geek-cc/your-custom-app-name
请随意派生它,并相应地调整它以适合您的用例。玩得开心!☺
*https://geek-cc.medium.com/membership *
只需点击一下按钮,即可在 Heroku 上部署您的 Tensorflow 模型
自动化您的 tensorflow 模型服务

在建立了这个卓越的模型之后,接下来呢?你如何向你的朋友炫耀它?你如何添加额外的一层神奇之处,帮助你超越 Github 中的一堆 jupyter 笔记本,让其他人也能与之互动?服务于您的模型使您离构建产品更近了一步,而不仅仅是拥有代码。
对于希望快速完成概念验证的爱好者和数据科学家来说,如果有一种方法可以以最少的工作量自动化您的模型部署,那么可以节省大量时间。在本文中,我将向您介绍一个工具,它可以让您轻松地将 Tensorflow 模型作为 rest apis 使用!
先决条件
为了跟进,你需要一个 Heroku 账户和一个在 AWS 上的公开的 s3 bucket。
让我们和克鲁斯一起建造吧!
欢迎来到克鲁斯!Cruise 是一个简单的设置,它消除了在 Heroku 平台上部署和服务模型时需要了解 TensorFlow 服务和 docker 的顾虑。它让你只需点击一个按钮就能完成所有这些。
在本文中,我们将使用著名的 MNIST 数据集构建一个图像分类器模型,然后使用 Cruise 部署该模型。
步骤 1:使用 SavedModel 格式构建并保存您的模型
Tensorflow SavedModel 使打包模型变得非常容易,以便使用 TFLite 和 TensorFlow Serving 等工具进行共享或部署。它存储运行模型所必需的参数,而不需要训练代码,从而可以方便地重用模型。
在第 58 行,我们指定了保存模型的路径。我们还使用时间戳作为模型的名称,以确保每次运行时,我们都会保存模型的新版本。
步骤 2:创建 Tensorflow 服务器使用的配置文件。
选择具有 TensorFlow 服务的模型的一种方法是通过配置文件。配置文件允许您方便地为服务器提供多个模型,还可以控制应该提供哪个(些)版本的模型。在 tf-models 文件夹中,创建 models.conf 文件:
在配置文件中,我们已经指定了模型的名称,这个名称将在我们访问 Heroku 上的模型的最终 url 中使用。基本路径告诉 Tensorflow 服务在哪里可以找到我们模型的所有可能版本。模型版本策略有助于我们控制对可以提供哪些模型的访问。更多相关信息可在这里找到。
第三步:压缩 tar.gz 格式的模型文件,并保存在一个公共 S3 桶
为了使用 cruise,我们必须首先将我们保存的模型作为一个压缩文件放在一个公开可用的 s3 bucket 上。下面是一个简单的代码,可以用来压缩模型文件:
第四步:和克鲁斯一起上菜!
访问 Cruise Repo ,点击 deploy 按钮,会将您重定向到 Heroku,您需要输入一些值:

巡航部署示例。(图片由作者提供)
应用程序名称是您的 heroku 应用程序的名称,必须是唯一的,否则 Heroku 会标记错误。您可以选择列表中离您最近的任何地区。 MODEL_BASE_PATH 指的是保存模型和配置文件的基本文件夹。在我们的例子中,我们将这个文件夹命名为 tf-models ,并将我们的压缩文件命名为tf-models.tar.gz。
MODEL_CONFIG_FILE 指的是我们给配置文件起的名字。在我们的例子中,我们称之为 models.conf 。
最后, TENSORFLOW_MODEL_URL 引用 s3 提供的 s3 bucket 对象 URL。请注意,我们必须使用 https url,因为 cruise 在内部使用 curl 来下载文件,如果协议不是 HTTP,就会标记一个错误。点击部署按钮,heroku 设置您的应用程序,最终完成后,您可以查看应用程序:

成功部署巡航导弹(图片由作者提供)
点击“查看”按钮可进入已部署应用程序的根页面,该页面返回“未找到”,因为 Tensorflow 服务器未使用该路径。要查看您部署的模型的健康状况,您可以导航到 https:https://YOUR-APP.herokuapp.com/v1/models/img_classifier
将 YOUR-APP 替换为 Heroku app 的名称,将 image_classifier 替换为您在 models.conf 文件中为模型指定的任何名称,在我们的示例中,url 将是:【https://cruise-mnist.herokuapp.com/v1/models/img_classifier】T2

模型健康终点(图片由作者提供)
要对我们的模型进行预测,我们只需发出如下请求:
注意第 20 行的 url。我们已经将' :predict '添加到我们之前的 url 中,指定我们想要在模型上执行的操作。现在你知道了!您可以在其他应用程序中轻松使用互联网上的实时模型!
结论
我构建 Cruise 的动机是找到一种将 Tensorflow 模型作为 API 自动部署的方法。如果您在一个必须向不同的人或团队提供模型的环境中工作,例如,软件工程师或您在一个团队中工作,并且需要一个工具来在实验时快速共享您的模型,那么使用 Cruise 进行部署是一个值得考虑的好方法!如果你有任何问题或者想要联系,这是我的 LinkedIn。谢谢大家!
部署基本的 Streamlit 应用程序
本文演示了一个基本的 Streamlit 应用程序(预测鸢尾的种类)的部署,以简化共享。

琼·加梅尔在 Unsplash 上的照片
Streamlit 是一个应用框架,用于部署使用 Python 构建的机器学习应用。这是一个开源框架,类似于 r 中的 Shiny 包。本文假设读者具备 Conda 环境、Git 和 Python 机器学习的基础知识。
模型开发
型号 1
我们将对 Scikit-Learn 软件包中的 Iris 数据集拟合一个逻辑回归模型。下面的代码将数据集分为训练集和测试集,以便在测试集上部署后评估模型。我们将使用互信息度量通过“选择最佳”方法进行特征选择。“SelectKBest”的超参数调整和逻辑回归的正则化参数是使用 GridSearchCV 的 3 倍来完成的。

作者图片
从上面的“GridSearchCV”结果来看,只有 3 个输入特征是重要的。我们使用从“GridSearchCV”中找到的最佳超参数重新调整了管道数据,发现“萼片宽度(cm)”并不重要。
模型 2
我们将通过消除管道中的“特征选择”步骤来构建另一个模型。此外,从训练数据中删除了“萼片宽度(cm)”列。

作者图片
上述“GridSearchCV”结果为模型 1 和 2 返回了相同的交叉验证分数。然而,为了简单起见,我们将部署“模型 1”。使用“joblib”将“模型 1”保存到名为“iris_model.pkl”的文件中。
应用部署可简化 it 共享
一旦模型被开发、评估和保存,我们需要导入“streamlit”包来开发我们的应用程序。使用我们用于模型开发的(上面的)代码是行不通的。我们需要为模型部署创建一个新的 Python 脚本(不是 Jupyter 笔记本)。我们将创建一个部署/项目文件夹,其中包含
- 名为' iris_streamlit_demo.py '的部署 Python 脚本(按照惯例,文件名应该是' streamlit_app.py ',但不是强制的)。
- 保存的模型(' iris_model.pkl ')。
- requirements.txt '文件,该文件指定要安装的软件包。必须指定软件包的版本,以避免“它在我的机器上工作”的问题。软件包的版本必须与我们 Conda 环境中的版本相匹配。我们将使用的“requirements.txt”文件和部署/项目文件夹结构如下所示。
streamlit==0.79.0
numpy==1.19.2
joblib==0.17.0
scikit-learn==0.23.2

部署文件夹结构(作者图片)
iris_streamlit_demo.py '如下所示。我们使用 Streamlit 的“numeric_input”方法添加了 4 个数字输入文本框。我们添加了一个“预测”按钮,当任何输入小于或等于 0 时,它会返回一个错误“输入必须大于 0”。如果所有输入都大于 0,那么结果将是一个预测。
我们将使用下面的命令从终端运行应用程序来测试它。在本地机器上运行的应用程序的屏幕截图如下所示。

作者图片

在本地机器上运行的应用程序(图片由作者提供)
要部署该应用程序来简化共享,我们需要创建一个 Streamlit 帐户。一旦创建了帐户,我们需要将部署文件夹(本地 repo)推送到‘Github’(远程 repo)中,剩下的就交给 Streamlit 了。下面是 streamlit.io 上部署页面的截图。

https://share.streamlit.io/deploy
下面是部署的应用的截图,以简化分享。

为简化共享而部署的应用程序的屏幕截图(图片由作者提供)
用于评估部署模型的测试集如下所示。发现看不见的数据的分数是 1(偶然的)。

评估已部署模型的不可见数据
这是部署基本应用程序以简化 it 共享的演示。需要注意的重要一点是,为简化 it 共享而部署的应用程序不是私有的。Streamlit 已经成为部署机器学习应用程序的 Flask 的替代方案。使用 Streamlit 构建的应用也可以部署在流行的云平台上(不仅仅是 Streamlit 共享)。
将基本的 Streamlit 应用程序部署到 Heroku
本文展示了在 Heroku 上部署一个基本的 Streamlit 应用程序(模拟中心极限定理)

作者图片
Streamlit 是一个应用框架,用于部署使用 Python 构建的机器学习应用。它是一个开源框架,类似于 R. Heroku 中的 Shiny 包。Heroku 是一个平台即服务(PaaS ),支持在云中部署和管理用多种编程语言构建的应用程序。
根据中心极限定理,随着样本容量的增加,样本均值将越来越接近总体均值。如果从总体中抽取足够数量的样本,随着样本量的增加,样本均值的分布(也称为样本均值的抽样分布)看起来更接近高斯分布,而不考虑潜在的总体分布。样本均值的标准偏差(又称标准误差)将等于(总体标准偏差/样本大小的平方根)。
关于应用程序
这个 Streamlit 应用程序模拟了样本和总体特征变化时的中心极限定理。这个应用程序使用户能够玩人口范围,人口规模,样本大小和样本数量。改变总体和样本的这些特征会对总体参数、样本统计、总体分布和样本均值的分布产生影响。这个应用程序可视化了样本均值和人口分布的这些变化。
文件夹结构
下面是用于将应用程序部署到 Heroku 的部署文件夹结构。

作者图片
central_limit_theorem.py
这个 Python 脚本(。py 文件,不是笔记本)包含了 Streamlit app 的代码。
requirements.txt
“requirements.txt”文件指定了要安装的包。必须指定软件包的版本,以避免“它在我的机器上工作”的问题。软件包的版本必须与我们 Conda 环境中的版本相匹配。我们将使用的“requirements.txt”文件如下所示。
matplotlib==3.4.1
numpy==1.20.2
pandas==1.2.3
streamlit==0.79.0
setup.sh
“setup.sh”指定在运行应用程序之前配置环境要执行的命令。在我们的' setup.sh '中,我们首先创建一个'。streamlit '目录来存储凭据和配置文件。然后,我们指定向 streamlit.io 注册的电子邮件,并将其写入“credentials.toml”文件。然后,我们将配置细节添加到“config.toml”文件中。这两个文件都位于。“简化”目录。
mkdir -p ~/.streamlit/
echo "\
[general]\n\
email = \"email@domain\"\n\
" > ~/.streamlit/credentials.toml
echo "\
[server]\n\
headless = true\n\
enableCORS=false\n\
port = $PORT\n\
" > ~/.streamlit/config.toml
Procfile
“Procfile”列出了启动应用程序时要执行的命令。在我们的“Procfile”中,我们将首先运行创建所需配置文件的“setup.sh ”,然后使用“streamlit run”命令运行应用程序。
web: sh setup.sh && streamlit run iris_streamlit_demo.py
将应用程序部署到 Heroku
- 登录你的 Heroku 账户,从右上角的“新建”菜单中选择“创建新应用”。

作者图片
2.输入您的应用程序的名称(基于可用性的任何名称),然后单击“创建应用程序”。

作者图片
3.选择部署方法。因为我已经使用 GitHub 托管代码文件(远程回购),所以我将选择那个选项。如果您是第一次进行连接,可能需要验证您的 GitHub 凭据。

作者图片
4.输入您要部署的 GitHub repo 的名称,单击“搜索”并单击“连接”

作者图片
5.然后选择要部署的分支,并单击“部署分支”。我不打算在未来修改应用程序,所以我没有启用自动部署。

作者图片
6.成功部署应用程序后,您将看到消息,并单击“查看”查看应用程序。

作者图片

已部署应用的屏幕截图(图片由作者提供)
部署到 Heroku 的 app 可以在 这里找到 。由于该应用程序仅用于演示目的,我使用免费的 dynos,这可能会导致应用程序性能不佳。有时,应用程序启动可能需要更长的时间,因为 dyno 可能会在较长时间不活动时进入睡眠模式。此外,这个应用程序通过滑块(不使用提交按钮)接受输入,并与大型 Numpy 数组一起工作,这可能会使应用程序崩溃,使其无法访问。然而,我使用了“@st.cache”装饰器,据说它可以在执行高资源要求的计算时提高应用程序的性能。您也可以从 Streamlit 共享T5 这里 访问应用程序。
使用 AWS Copilot 部署容器化的 Web 应用程序
使用 AWS Copilot 简化 AWS ECS 和 AWS Fargate 的部署

约翰·麦克阿瑟在 Unsplash 的照片
本文将向您展示如何使用 AWS Copilot 将容器化的 web 应用程序部署到 AWS。Copilot 极大地简化了 AWS 的部署,并提供了一个统一的框架来提供架构、构建映像和部署容器作为公共或私有服务。此外,Copilot 允许我们根据自己的需求创建负载平衡服务或请求驱动服务,而无需用户更改应用程序、配置或架构。
将逐步创建一个身份访问管理帐户,在 AWS 上通常称为 IAM。创建此帐户后,我们将连接到本地机器上的 AWS 和 Copilot CLI。
注意:您需要 docker 运行才能成功完成这项工作。
登录或注册 AWS

要在 AWS 上创建 IAM 帐户,您必须先注册一个 AWS 帐户。如果您尚未执行此操作,请在此处执行操作。
在 AWS 上创建 IAM 帐户
创建帐户后,以 Root 用户身份导航到 AWS 管理控制台。
将会有一个标有“所有服务”的下拉列表点击这个,它会打开一个 AWS 提供的所有不同服务的大列表。IAM 将位于右上方的“安全、身份和合规性”部分。

当您到达 IAM 控制面板时,会有大量的内容可供您点击。
您首先需要创建一个具有管理员访问权限的“用户组”。
为此,请点击“用户组”
如果您过去已经创建了一个用户组,它们将在这里列出。我们将假设您没有创建任何,然后一起创建一个。
首先单击“创建组”按钮。

然后会要求您为新用户组命名。您将称之为“管理员”
现在,您可以跳过向该组添加用户,因为您将在创建该组后执行此操作。
再向下滚动一点,您将看到“附加权限策略”部分。在文本框中,键入“admin ”,然后按回车键。这将进一步过滤结果,并允许我们更快地找到“AdministratorAccess”策略名称。继续并选中该策略旁边的框。

最后,单击“创建组”
现在,您已经成功创建了“管理员”用户组。
现在我们已经创建了管理员组,我们需要创建一个新用户并将他们添加到该组中。
返回 IAM 主页,单击 IAM 资源下的“用户”链接。

当页面加载时,您将单击“添加用户”按钮。

对于用户名,我们将称之为“copilot ”,因为这是我们将这个 IAM 帐户连接到的。
然后,我们希望选中“编程访问”旁边的框,因为我们将要求该用户使用 AWS CLI。

设置完成后,单击权限继续下一页。

您可以在这个页面上把我们的新用户添加到我们新创建的“管理员”用户组中。为此,请选中“管理员”用户组旁边的复选框。

选中该框后,您可以点击进入下一页,标签。标签只是您可以添加给用户的一些附加信息,以便快速查找或收集信息。我们目前不关心添加任何标签,但是如果你愿意,你可以这样做。
如果您对添加(或未添加)的标签感到满意,请进入下一页查看新用户信息。如果一切正常,单击“创建用户”完成新用户的创建。

您应该会收到一条绿色消息,说明用户已成功创建,以及我们稍后将需要的关于用户的一些信息,特别是访问密钥 ID 和秘密访问密钥。要么留在此页面,要么保存此信息以备后用。
将 AWS CLI 安装到您的计算机上
成功创建用户后,我们现在可以安装 AWS CLI 并连接刚刚创建的 IAM 帐户。
要安装 AWS CLI,打开 Terminal(对于 Unix 机器)或 git-bash(任何其他命令行工具)for Windows。
从那里,根据您的操作系统运行以下命令之一:
马科斯
curl “https://awscli.amazonaws.com/AWSCLIV2.pkg" -o “AWSCLIV2.pkg”sudo installer -pkg AWSCLIV2.pkg -target /
Linux 操作系统
curl “https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o “awscliv2.zip”unzip awscliv2.zipsudo ./aws/install
Windows 操作系统
msiexec.exe /i [https://awscli.amazonaws.com/AWSCLIV2.msi](https://awscli.amazonaws.com/AWSCLIV2.msi)
然后它会询问你的电脑密码并安装它。
完成后,您就成功地将 AWS CLI 安装到了本地计算机上。
下载示例存储库
现在您已经在我们的机器上安装了 AWS CLI,您现在可以使用 Copilot 推送一个示例 web 应用程序。
为了让我们开始,我创建了一个存储库,其中包含一个已经编码好的容器化 web 应用程序。你可以在这里下载库。
一旦克隆到您的机器上,继续在 terminal/git-bash 中打开这个目录。
使用 Copilot 部署应用程序
在终端的垃圾邮件检测器存储库中。然后,您就可以使用 Copilot 为部署准备这个 web 应用程序了。
这是通过简单的命令完成的
copilot init
运行时,系统会提示您回答一些关于项目的问题:
- 您是否希望使用现有的应用程序之一—否(如果您以前从未使用过 Copilot,您可能看不到此提示)
- 您希望如何命名您的应用程序—垃圾邮件检测器应用程序(您可以随意命名)
- 哪种工作负载类型最能代表您的架构?—负载平衡 Web 服务或请求驱动 Web 服务(如果您希望它面向公众)。
- 您希望将此负载平衡的 web 应用命名为什么?—垃圾邮件检测器应用程序(或任何您喜欢的应用程序)
- 你想将哪个 docker 文件用于垃圾邮件检测器应用程序?— ./Dockerfile.copilot
回答完所有这些问题后,它将开始部署您的应用程序!
一旦部署了这个实例,您将得到一个提示,询问您是否想要部署一个测试环境。
测试环境是应用程序的另一个实例,使用更少的资源。如果您将在完全部署项目之前进行大量测试和更改,这将非常有用。
这将开始构建我们的环境,然后是 docker 容器。一旦成功创建了这些,Copilot 就会将 docker 容器推送到 ECR,用 ECS 引导应用程序,并给我们一个 URL 来测试应用程序。
测试应用程序是否工作
测试 GET 请求
既然构建已经完成并部署好了,我们可以前往终端中返回的 URL。您可以将该 URL 复制/粘贴到您的浏览器中,或者按住 cmd 键单击该 URL 以自动打开它。
应用程序应该加载,并在窗口上有一些文字说:
“应用程序已启动”
测试 POST 请求
为了测试 POST 请求能否正常工作,我们将使用免费应用程序 Postman。
如果你没有安装 Postman,你可以在这里下载它。
打开 Postman,您将获得我们收到的 URL,并将其粘贴到“输入请求 URL”文本框中。然后,您将在 URL 的末尾添加“/predict ”,因为这是我们为处理 POST 请求而创建的路由。您还需要确保请求的类型设置为 POST。

正确设置 URL 并选择 POST 后,单击“body”选项卡。
“body”选项卡将包含我们想要发送到 POST 端点的数据。
我们想要发送的数据类型是 JSON。所以从给定的选项中选择“raw ”,然后使用下拉菜单将类型从“Text”更改为“JSON”。

然后,您可以填充下面的 JSON。我们将简单地发送一个键/值对。

最后,您可以单击 send 并等待来自我们端点的响应。

如果您按照正确的步骤操作,您应该会收到返回的结果“ham ”,从而确认我们的 POST 端点正在按预期工作。
关闭应用程序
Copilot 也使关闭您的部署相对容易。您可以通过 AWS CLI 一次关闭所有服务,而不是进入 AWS 并单独关闭每个服务。
因此,回到您的终端的同一个应用程序目录中,输入以下命令来关闭我们的部署:
copilot app delete
系统会提示您确认是否要删除该应用程序,只需键入“y”然后回车确认即可。
几分钟后,您的应用将成功关闭!
结论
正如你所看到的,AWS 的 Copilot 允许部署和关闭一个容器化的 web 应用程序,就像在终端上键入几个命令一样简单。
如果你想看这一过程的视频版本,请查看我的 YouTube 频道。
部署跨平台深度学习应用
使用 Python 在 iOS、Android、MacOS、Windows 和 Linux 上运行 Tensorflow Lite 推理

作者图片
TL;速度三角形定位法(dead reckoning)
向下滚动 Python 代码,使用 Tensorflow Lite 运行推理,它可以在 Android、iOS、Windows、MacOS 和 Linux 上运行。
为什么坚持用 Python?
Python 是一个奇妙的生态系统。有这么多高质量的开源库可以帮助你快速构建非常复杂的项目。这无疑有助于 Python 作为深度学习框架的流行。至关重要的是,pip(或 pipenv)为您处理依赖关系,这样您可以避免陷入版本地狱。这使得 Python 非常适合于原型开发,但是要得到一个易于使用的完美产品,有时可能比所有其他产品加在一起还要费力。正如笑话所说,答案可能是“我不会从这里开始”。
Web app 还是手机 app?
通常,最好的选择是在 web 上部署应用程序,这样浏览器就能有效地处理平台细节。然后,您的 Python 代码可以作为服务运行,并集成到运行在云上的可扩展架构中。但是如果需要来回发送的数据量太大或者太敏感怎么办?鉴于我们大多数人口袋里都装着相当于 80 年代超级电脑的东西,利用手机的力量是有意义的。
作为一个例子,我使用深度学习开发了一个基于原始音频数据的音乐推荐算法。给定一组 MP3,它会自动创建音乐播放列表,这些音乐可以很好地放在一起,或者从一首歌平稳地过渡到另一首歌。我希望能够在我的手机、平板电脑或电脑上运行它,而不必将我的所有曲目上传到云端进行分析。我认为 Tensorflow Lite 可以在几乎所有可以想象到的平台上使用,不需要重写大量代码就可以实现。
Qt 对 Kivy
现在有很多跨平台的开发工具,但是很少能在桌面和移动设备上工作,并且很容易集成 Python 代码。我研究了两个声称能做到这一点的工具:Qt 和 Kivy。
Qt 以 PyQt5 和 pyqtdeploy 的形式出现。特定于平台的东西,比如播放音频,被 Qt 抽象掉了,所以理论上,你只需要写一次代码。这种通用方法的缺点是,您可能无法充分利用目标设备的功能。我的经验是,在 Android 上使用 Numpy 非常困难,我甚至没有在 iOS 上尝试过。这真的感觉就像试图把一个圆钉塞进一个方孔。
另一方面,Kivy 是用 Python 编写的,可以与像 buildozer (用于在 iOS 和 Android 上构建)、 PyInstaller (用于打包桌面应用)、 p4a (Python 用于 Android)和 kivy-ios 这样的库一起工作。我使用 Numpy 获得了一个基本应用程序,运行非常快,能够使用 KivyMD (材质设计)让它看起来很智能,同时使用 pyobjus (用于在 iOS 上从 Python 调用 Objective C)pyjnius(用于在 Android 上从 Python 调用 Java)和 plyer 完全控制平台特定的功能。由于 pyjnius 开发人员之一 Tito 在 Android 上运行 Tensorflow Lite 的示例,我领先了一步。
我花了很长时间才让 iOS 版本工作,主要是因为我没有 Mac,所以我不得不使用模拟器,但也因为 Objective C 很糟糕,不容易从 Python 中调用。(我也尝到了版本地狱的滋味,kivy-ios 和 Cocoapod 都有音频库中的重复符号。)另一种方法是从 Swift 调用 Tensorflow Lite 和 Python,但这将意味着完全重写我的应用程序。
下面的代码片段扩展了 Kivy,允许您以独立于平台的方式在 Tensorflow Lite 上运行推理。它假设您的模型只有一个输入和输出张量——这是通常的情况——但是推广到多个输入和输出是非常简单的。
为了方便开始,我创建了一个可以在 Android、iOS、MacOS、Windows 和 Linux 上运行的“Hello World”tensor flow Lite 应用。对您来说,根据自己的需要对其进行调整应该是相当简单的。现在,没有什么可以阻止您开发一个利用您设备的传感器和功能的深度学习应用程序!
https://github.com/teticio/kivy-tensorflow-helloworld/tree/main
总之,我想说 Kivy 非常有前途,开发者们一直在忙于改进它。在我看来,它非常接近于能够生产出高质量的应用程序。
使用 TensorFlow 和 React 在移动设备上部署深度学习模型
我们将介绍如何使用 React Native 和 TensorFlowJS React Native adaptor 构建一个跨平台的移动应用程序(适用于 iOS 和 Android)

安娜·佩尔泽在 Unsplash 上的照片
随着移动电话变得越来越普及,移动电话的使用也在增加。用户越来越频繁地在桌面上使用移动设备,移动应用需求旺盛。这些连接互联网的设备提供了一个让推理模型更接近用户的机会。
概述
- 关于数据:食物-101
- 第 1 部分:使用 TensorFlow 训练图像分类器
- 第 2 部分:转换模型
- 第 3 部分:推理的考虑事项:在服务器上运行还是在客户机上运行
- 第 4 部分:部署 Web 应用程序
- 第 5 部分:部署移动应用程序
关于数据:食物-101
本项目使用 Food-101 数据,包括 101 个食品类别,共 101,000 张图像。因此,每个类有 1000 幅图像,其中 250 幅是人工检查的测试图像,750 幅是训练图像。ETHZ Food-101 的分类是来自食物图片分享网站 foodspotting.com 的 101 个最受欢迎的分类。

数据引用
Bossard,Lukas 和 Guillaumin,Matthieu 和 Van Gool,Luc,用随机森林挖掘 101 种食品歧视成分,欧洲计算机视觉会议,2014 年。
第 1 部分:使用 TensorFlow 训练图像分类器
使用 TensorFlow 2.3.4 训练图像分类器。代码可在 GitHub 上的本笔记本中查阅。TensorFlow 2 / Keras 中有许多预训练的模型。我们使用了 ResNet50 和 MobileNetV2 架构。MobileNet 模型系列是移动友好的,它将用于移动应用程序。
表 1:比较模型架构
我们在下面的表格中比较了模型的准确性、参数数量和模型大小。
MobileNetV2 是一个移动友好的架构,具有较少的参数。移动应用程序部署中使用的最终模型是 MobileNetV2 微调模型,精确度约为 66%。

作者图片
第 2 部分:转换模型(量化和优化)
我们将model.h5和classes.json(这是食品类别名称的列表)文件下载到本地计算机上一个名为model_tf的文件夹中,并在虚拟环境中进行模型转换。
我们创建的模型model.h5,格式为“TensorFlow Keras”。我们需要将其转换为“TensorFlow.js”格式,因为客户端推理需要这种格式。我们转换默认 tensorflow.js 模型有几个原因:
- 模型碎片:我们的模型文件很大,默认的 tensorflow.js 将模型分解成 5 MB 的碎片。为了部署移动应用程序,我们需要一个文件,所以我们指定 50,000,000 字节的
weight_shard_size_bytes来获取该文件。 - 推理-速度优化使用
[**GraphModel**](https://livebook.manning.com/book/deep-learning-with-javascript/chapter-12/1#search)转换
GraphModel转换如何提升 TensorFlow.js 模型的推理速度?这是通过利用 TensorFlow (Python)对模型的计算图进行精细粒度的提前分析来实现的。计算图分析之后是对图的修改,这些修改减少了计算量,同时保持了图的输出结果的数字正确性。
- 使用量化的推理速度优化:量化是一种减少模型大小的后训练技术。这里,我们使用量化将默认的 32 位精度降低到 16 位精度,这将使模型文件大小减半。
我们将所有 3 个转换步骤合并为:
我们保存了转换后的模型文件,并将其上传到移动 repo 的 GitHub releases 区域:deploying-mobile-app/release
这些模型和类文件将在创建 web 应用程序时用作输入。
表 MobileNetV2 的型号大小
请注意,量化的模型大小减少了 50%,从 14MB 减少到 6.9MB。两种模型大小的推断时间相似。在大多数情况下,文献表明 16 位量化不会显著影响精度。
Web App: Compare Model Size Before & After Optimization and Quantization╔═════════════╦════════════════════╗
║ Model ║ Model Size ║
║ ║ ║
╠═════════════╬════════════════════╣
║ MobileNetV2 ║ 14MB ║
║ ║ ║
╠═════════════╬════════════════════╣
║ MobileNetV2 ║ 6.9MB ║
║ (16-bit ║ ║
║ quantized)║ ║
╚═════════════╩════════════════════╝
第 3 部分:推理的考虑事项:在服务器上运行还是在客户机上运行
用户的延迟/网络连接
在服务器端推理中,一旦接收到图片/文本,推理时间是一致的。但是,总时间是由用户的网络上传速度决定的。在客户端推理中,推理时间取决于用户运行的硬件。
隐私
对于敏感数据,用户可能不愿意将数据发送到服务器。客户端推理允许用户安全地运行他们的工作负载。
模型的未来更新
服务器端推理的一个好处是能够部署新的、最先进的模型并持续更新它们。在客户端推理中,新模型的部署受到用户表示的更新频率的限制。
最先进的模型与移动优化
由于客户端硬件和存储的限制,小型且针对推理优化的模型是理想的。web 上的大多数网站都是不到 2 MB 的 JavaScript 代码和 CSS。我们创建的最简单的模型大约为 20 MB,这对于在 web 上提供服务来说仍然不理想。因此,目前大多数模型都是在服务器上提供的。
第 4 部分:部署 Web 应用程序
我们使用这个模板库来部署 web。模板库是一个 web 应用程序,它同时执行服务器端和基于浏览器的推理:
deploying-web-app
我们将模型复制到我们的分叉回购中。
这是来自 Colab 的原始文件:model.h5
这是转换后的 TensorFlow.js 文件:model_tfjs
包含模型文件的存储库的结构如下。我们将原始的和转换后的模型放在目录backend/assets中。
├── backend
│ ├── app.py
│ ├── assets
│ │ ├── classes.json
│ │ ├── model_tf
| | |──├──model.h5
│ │ └── model_tfjs
│ │ ├── group1-shard1of1.bin
│ │ └── model.json
在本地提供 Web 应用
在 Python 中提供 web 应用程序有多种选择,包括 Flask、Django 和 FastAPI。
我们使用 FastAPI 提供浏览器应用程序,并使用 React 作为前端框架。
首先,我们使用 Docker 在本地运行该应用程序。
repo 提供了一个 Docker 文件来运行应用程序。运行这些命令来启动应用程序。第一次使用 Docker 运行时,可能需要 10 分钟。这个命令需要在您的 repo 的基础层运行,这里有Dockerfile文件。
运行以上两个命令会启动一个在本地机器上运行的 web 服务器。
可以在 http://localhost:8000 本地访问服务器。
瞧啊。我们有一个本地运行的 web 应用程序!它看起来像下面的演示。
Web 应用程序演示
这款应用在manning-deploy-imagenet.herokuapp.com生产

作者图片
向云平台提供 Web 应用(Heroku)
Heroku 是一个很好的免费应用部署选项。
一旦安装了 Heroku 命令行工具,就可以使用下面的命令运行它。
用独特的东西代替APP_NAME。根据您的互联网上传速度,以下步骤可能需要一些时间(5 到 10 分钟)。对于我们的项目,我们设置APP_NAME="manning-deploy-imagenet"。
这款应用可以在这里试用:manning-deploy-imagenet.herokuapp.com
推理次数
我们测量了几个样本图像的延迟。我们实验了不同大小的图片,并在桌面和手机上访问了该网站。
表 Web 应用程序的推理时间
Web App: Compare Inference Times╔═════════════╦════════════════════╦═══════════════════╦════════╗
║ Inference ║ Desktop Browser ║ Mobile Browser ║ Model ║
║ Source ║ duration ║ duration ║ Size ║
║ ║ (Inference in ms) ║ (Inference in ms) ║ ║
╠═════════════╬════════════════════╬═══════════════════╣════════╣
║ Server ║ 559 ║ 594 ║ 29MB ║
║ (Heroku) ║ (202) ║ (180) ║ ║
╠═════════════╬════════════════════╬═══════════════════╣════════╣
║ Browser ║ 50 ║ 177 ║ 6.9MB ║
║ ║ ║ ║ ║
╚═════════════╩════════════════════╩═══════════════════╩════════╝**NOTES** The above results show the latency cost associated with sending an image to the server for inference.* For the Server (Heroku) model, it is the h5 file, the keras model.
* For the Browser model, it is the post-training quantized and optimized model. (converted using TensorFlow.js)
第 5 部分:部署移动应用程序
让推理在移动应用上本地运行的好处是,它可以在没有互联网连接的情况下运行。因为模型运行在用户的设备上,所以延迟较低。在设备上本地运行的推理也保护了用户的隐私。
我们使用 React Native 和 TensorFlowJS React Native adaptor,因为它允许我们构建跨平台的移动应用程序。
我们使用这个模板库来部署移动网络;它适用于 iOS 和 Android: 部署移动应用
我们将tfjs转换后的模型文件上传到发布部分。
推理发生在文件[ModelService.tsx](https://github.com/reshamas/deploying-mobile-app/blob/main/components/ModelService.tsx#L110)中。为了初始化 TensorFlow.js 模型,ModelService.tsx在create方法中调用下面的代码。
下面是用于从classifyImage中使用的图像获得预测的核心代码。
Expo 是一个围绕 React Native 构建的免费开源工具链,帮助使用 JavaScript 和 React 构建跨平台的原生 iOS 和 Android 项目。通常用于构建应用程序的 JavaScript 环境是节点。为了运行这个应用,我们使用了 yarn ,用于安装 Expo 之类的 JavaScript 包。安装yarn后,我们做了:
yarn run start
下一步是打开 Expo 应用程序,登录后,您应该会看到应用程序列表。

作者图片
移动应用程序演示
此移动应用程序在以下位置生产:

作者图片
表 4:比较移动应用程序的推理时间
注意:我们预计移动应用程序的推理时间会更快。这里有点慢。这可能是由于 React 本地适配器不成熟。
Mobile App: Compare Inference Times
╔═════════════╦════════════════════╦═══════════════════╗
║ Inference ║ Mobile Browser ║ Mobile App ║
║ Source ║ duration ║ duration ║
║ ║ (Inference in ms) ║ (Inference in ms) ║
╠═════════════╬════════════════════╬═══════════════════╣
║ Pixel 1 ║ 310 ║ 411 ║
║ (2016) ║ ║ ║
╠═════════════╬════════════════════╬═══════════════════╣
║ iPhone XS ║ 220 ║ 327 ║
║ (2019 ║ ║ ║
╚═════════════╩════════════════════╩═══════════════════╝**NOTES** Both the mobile browser and app allow you to run inference in less than 1 second. This performance is acceptable for a mobile app.
摘要
本文概述了如何使用 TensorFlow 运行深度学习分类器,以及如何在 web 和移动设备上服务该模型。如需更多分步说明,请查看我们的 Manning liveProject: 在 Web 和移动应用上部署深度学习模型 (使用 TensorFlow 和 React)。这个项目的第一个里程碑,主要是训练模型,是公开的。

liveProject: 部署深度学习模型
我们将重点放在使用 TensorFlow-serving 的演示上,因为用于部署移动应用程序的 TensorFlow 生态系统比 PyTorch 更加成熟。PyTorch Mobile 大约在 2019 年 10 月发布,TensorFlow Lite 在 2017 年 5 月发布。
录像
我们在 PyData Global 2021 上介绍了这个主题。有一个 30 分钟的视频,结尾有问答讨论。
参考
- 在网络和移动应用上部署深度学习模型 (TensorFlow,React)【Manning live project】
- GitHub repo:deploying-we b-app(tensor flow,React)
- GitHub repo: 部署-手机-app (TensorFlow,React Native)
- 在 Web 和移动上部署深度学习模型 (fastai,PyTorch,React)
- 深度学习与 JavaScript:tensor flow . js 中的神经网络作者蔡、Stanley Bileschi、Eric D. Nielsenn 和 Francois Chollet 第十二章。测试、优化和部署模型
使用 ECS 和 Fargate 部署 Docker 容器。
包括必要权限的指南。

本周,我需要在 ECS 上部署一个 Docker 映像,作为数据接收管道的一部分。我发现将 Docker 映像部署到 ECS 的过程相当简单,但是从安全团队那里获得正确的权限却是一件难事。
在本文中,我们将深入探讨将一个简单的应用程序部署到 ECS 并在 Fargate 集群上运行的步骤,这样您就不必担心配置或维护 EC2 实例。更重要的是,我们将了解必要的 IAM 用户和 IAM 角色权限,如何设置它们,以及如果您在工作中需要这样做,需要向您的网络安全团队提出什么要求。
让我们深入研究一下,从术语开始。
ECS,ECR,Fargate
我们将在这里使用的三种 AWS 技术是弹性容器服务(ECS)、弹性容器注册(ECR)和 Fargate。
精英公司
ECS 是我们工作的核心。在 ECS 中,我们将创建一个任务并运行该任务,以将我们的 Docker 映像部署到一个容器中。ECS 还处理需要运行多个实例的应用程序的扩展。ECS 管理我们应用程序的部署。了解更多。
electroniccashregister 电子现金出纳机
ECR 是 AWS 上 Docker 图像的版本化存储。部署时,ECS 从 ECR 提取映像。了解更多。
法盖特
Fargate 供应和管理计算实例集群。这很神奇,因为:
- 您不必供应或管理应用程序运行的 EC2 实例。
- 您只需为应用运行的时间付费。对于运行定期任务并退出的应用程序来说,这可以节省很多钱。
策略、组、IAM 用户和 IAM 角色
如果您是 AWS 生态系统的新手,并且没有以 root 用户的身份学习本教程,那么您需要对 AWS 上的安全管理有所了解。
政策
策略是指定服务的权限集合。例如,您可以制定一个策略,仅允许某些用户查看 ECS 任务,但允许其他用户运行这些任务。
策略可以附加到组,也可以直接附加到单个 IAM 用户。
组
组顾名思义就是共享访问策略的用户组。当您将策略添加到组中时,该组的所有成员都将获得策略中的权限。
IAM 用户
IAM 代表身份和访问管理,但实际上它只是一个借口来调用一个识别用户的服务“我是”(聪明吧?).如果您不是 root 用户,您将作为 IAM 用户登录 AWS 管理控制台。
IAM 角色
角色有点令人困惑。角色是 AWS 服务的一组权限。当一个服务需要访问另一个服务的权限时,使用它们。该角色是为它将附加到的特定类型的服务创建的,并且它附加到该服务的实例。(角色还有其他应用程序,但它们超出了本文的范围。)
设置权限
正如我提到的,这是过程中最痛苦的部分。亚马逊试图让这变得简单,但访问管理很难。
我们将从 root 帐户开始逐步设置适当的策略。然后,我们会将其转化为对您的安全团队的要求,以便您可以在 ECS 上启动并运行 Docker 容器。
创建 IAM 用户并分配权限
这是一个很好的练习,只是为了了解幕后发生的事情。它将帮助您协商您需要从您的组织获得的访问权限,以完成您的工作。
- 以 root 用户身份登录您的 AWS 帐户。如果您没有帐户,您可以在此注册一个帐户。
- 搜索 IAM

作者图片
- 从 IAM 仪表板的左侧菜单中选择
Users。 - 从页面顶部选择
Add user。

作者图片
- 在添加用户屏幕上选择一个用户名,
- 检查
Programatic access和AWS Management Console access。其余的我们可以离开他们。

作者图片
附加 ECS 访问策略
为了简化我们的工作,我们将访问策略直接附加到这个新的 IAM 用户。除了明确属于 ECS 的权限之外,ECS 还需要许多服务的权限,例如列出角色和创建集群。向我们的新 IAM 用户添加所有这些权限的最佳方式是使用 Amazon 托管策略向新用户授予访问权限。
- 选择
Set permissions下的Attach existing policies directly。 - 搜索
AmazonECS_FullAccess。(前面带有 cube 标志的策略是 Amazon 管理的策略)。 - 选择策略旁边的复选框。

作者图片
创建 ECR 策略
我们还需要访问 ECR 来存储我们的图像。除了没有 Amazon 托管策略选项之外,这个过程是类似的。我们必须创建一个新策略来附加到我们的 IAM 用户。
- 再次选择
Create policy。 - 在维修下选择
Elastic Container Registry。 - 在动作下选择
All Elastic Container Registry actions (ecr:*) - 在资源下选择
specific和Add ARN。在这里,我们将选择地区,留下我们的帐号,并选择Any作为存储库名称。

作者图片
- 点击
Add。 - 点击
Next: Review跳过标签。 - 填写适当的策略名称。我们将使用
ECR_FullAccess - 选择
Create policy
将新策略附加到 IAM 用户
- 创建策略后,返回到我们创建 IAM 用户的浏览器选项卡。
- 通过单击策略表右上角的刷新符号来刷新策略。
- 搜索
ECR_FullAccess ECS_FullAccess并选择我们创建的每个策略左侧的单选按钮,将其附加到我们的 IAM 用户。

作者图片
- 选择
Next:Tags。 - 将标签留空。
- 选择
Next:Review - 最后,回顾我们的工作并创建用户。

作者图片
当您提交此页面时,您将看到一个确认屏幕。将所有信息保存在安全的地方当我们部署我们的容器时,我们将需要所有这些信息。
在现实世界中,您不太可能需要为自己创建这些权限。更有可能的情况是,您需要向组织中的某个人(也许是安全团队)请求它们。现在你已经知道了一些相关的事情,你可以更好地提出要求。
您的请求应包含
- 对你需要完成的事情的一个非常简短的解释。
- 请求的权限列表。
第二种可能是不必要的,但它将节省每个人的时间和许多来回电子邮件的痛苦,因为他们试图找出你到底需要哪些权限。
他们可能会授予您所请求的权限,或者授予您其中的一部分。他们是网络安全专家,所以如果你得到的比你要求的少,真诚地进行。如果你碰壁了,把错误发给他们,这样他们就可以授予你继续前进的必要权限。
您的请求可能如下所示:
Hi Joe,I need to deploy a Docker container on ECS. I will also need access to ECR for this.Please add the following to my IAM user privileges:
- AmazonECS_FullAcces managed policy
- The following policy for ECR access:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "ecr:*",
"Resource": "*"
}
]
}Thanks! You are the best!
好了,接下来是主要事件
将 Docker 容器部署到 ECS
这里的步骤是:
- 创建 Docker 图像
- 创建 ECR 注册表
- 给图像加标签
- 授予 Docker CLI 访问您的 Amazon 帐户的权限
- 将您的 docker 图像上传到 ECR
- 为 ECS 创建一个 Fargate 集群,用于部署您的容器。
- 创建一个 ECS 任务。
- 运行 ECS 任务!
创建 Docker 图像
出于演示的目的,我将使用一个简单的 flask 应用程序来显示 GitHub 库中猫的 gif。该应用程序是 docker-curriculum.com 的一部分,如果你刚刚开始,这是一个很好的 Docker 入门。
我们开始吧
- 将 GitHub 和 cd 中的源文件克隆到
flask-app目录中。
$ git clone [https://github.com/prakhar1989/docker-curriculum.git](https://github.com/prakhar1989/docker-curriculum.git)$ cd docker-curriculum/flask-app
- 创建 Docker 图像:
docker build -t myapp .
测试应用程序以确保一切正常。我们下载的 flask 应用程序监听端口 5000,因此我们将使用同一个端口进行测试。
docker run --publish 5000:5000 myapp
现在你应该可以去localhost:5000看到一个随机的猫 gif

作者图片
耶!
创建 ECR 注册表。
在这一步中,我们将在 ECR 中创建存储库来存储我们的图像。我们将需要这个存储库的 ARN(Amazon Resource Name——所有 AWS 资源的唯一标识符)来正确标记和上传我们的图像。
使用我们之前创建的 test_user 凭据首次登录 AWS 控制台。Amazon 会询问您的帐户 id、用户名和密码。

作者图片
- 一旦你进入,搜索
Elastic Container Registry并选择它。

作者图片
- 从这里开始,将存储库的名称填写为
myapp,其他的都保持默认。

作者图片
- 选择页面左下角的
Create Repository,您的存储库就创建好了。您将在存储库列表中看到您的存储库,最重要的是 ARN(这里称为 URI),我们将需要它来提升我们的形象。为下一步复制 URI。

作者图片
如果您愿意,也可以从命令行执行上述步骤,如下所示:
$ aws ecr create-repository \
--repository-name myapp \
--region us-east-1
给图像加标签
为了让 ECR 知道我们将图像推送到哪个存储库,我们必须用那个 URI 标记图像。
$ docker tag myapp [use your uri here]
我的 ECR 注册表的完整命令如下所示:
docker tag myapp 828253152264.dkr.ecr.us-east-1.amazonaws.com/myapp
授予 Docker CLI 访问您的 Amazon 帐户的权限
我承认这一步有点复杂。我们需要登录 aws 来获得一个密钥,我们将它传递给 docker,这样它就可以将我们的图像上传到 ECR。您将需要 aws cli 来完成我们余下的工作。
- 首先,我们将登录到我们的 aws 帐户。
# aws configure
AWS 将要求我们提供您在创建 AIM 用户时保存的凭据(对吗?).使用这些凭据进行身份验证。
- 接下来,我们需要为 docker 生成一个 ECR 登录令牌。这一步最好与下一步结合起来,但是更深入地看看发生了什么也是好的。当您运行以下命令时,它会抛出一个难看的令牌。Docker 需要这个令牌来推送到您的存储库。
# aws ecr get-login-password --region us-east-1
- 我们可以像这样将令牌直接传送到 Docker。确保用您的账号替换
**[your account number]**。末尾的 ARN 与我们之前使用的相同,只是末尾没有存储库的名称。
# aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin **[your account number]**.dkr.ecr.us-east-1.amazonaws.com
如果一切顺利,响应将是 Login Succeeded。
将您的 docker 图像上传到 ECR
我们现在已经完成了最困难的部分。从这里开始应该会一帆风顺。
- 使用 docker 将图像推送到 ECR 存储库。
docker push 828253152264.dkr.ecr.us-east-1.amazonaws.com/myapp
创建一个 Fargate 集群。
对于这一步,让我们返回到 AWS 管理控制台。
- 搜索
Elastic Container Service,选择Elastic Container Service。 - 从左侧菜单中选择
Clusters - 选择
Create cluster

作者图片
- 在
Select cluster template下,我们将只选择网络。我们在集群中不需要 ec2 实例,因为 Fargate 会在我们开始任务时负责加速计算资源,在我们停止任务时负责停止计算资源。

作者图片
- 我将把集群命名为
fargate-cluster,其余的我们可以保持原样。

- 选择
Create
创建 ECS 任务
ECS 任务是获取我们的映像并将其部署到容器中的操作。要创建 ECS 任务,让我们返回到 ECS 页面并执行以下操作:
- 从左侧菜单中选择
Task Definitions。然后选择Create new Task Definition

作者图片
- 选择
Fargate - 选择
Next Step

作者图片
- 输入任务的名称。我要用
myapp。 - 将
Task Role和Network Mode设置为默认值。

作者图片
- 保持
Task Execution Role设置为默认值。 - 对于任务内存和任务 CPU,选择最小值。这项测试我们只需要最少的资源。

作者图片
- 在容器定义下选择
Add Container. - 输入容器名称。我会再次使用
myapp。 - 在图像框中输入我们图像的 ARN。如果您还没有这样做,您将需要从 ECR 仪表板中复制并粘贴它。
- 我们可以将内存限制保持在 128Mb
- 在端口映射中,您会注意到我们实际上不能映射任何东西。我们在这里输入的任何端口都将在实例上打开,并映射到容器上的同一个端口。我们将使用 5000,因为这是我们的 flask 应用程序侦听的位置。

作者图片
- 将其他所有内容设置为默认值,并单击对话框左下角的
Add。 - 将 Configure task and container definitions 页面中的其他内容保持不变,并选择页面左下角的
Create。 - 回到 ECS 页面,选择
Task Definitions,我们应该会看到我们的新任务处于活动状态。

作者图片
运行 ECS 任务!
这是我们期待已久的时刻。
- 在任务定义列表中选择任务
- 点击
Actions,选择Run Task

作者图片
- 对于
Launch type:选择Fargate - 确保
Cluseter:设置为我们之前创建的fargate-cluster。

作者图片
- 集群 vpc 从列表中选择一个 VPC。如果您正在构建自定义应用程序,这应该是分配给任何其他 AWS 服务的 vpc,您将需要从您的实例访问这些服务。对于我们的应用程序,任何都可以。
- 至少添加一个子网。
Auto-assign public IP应设置为ENBABLED

作者图片
- 编辑安全组。
因为我们的应用程序监听端口 5000,并且我们在容器上打开了端口 5000,所以我们还需要在安全组中打开端口 5000。默认情况下,运行任务创建的安全组只允许端口 80 上的传入连接。单击安全组名称旁边的Edit,添加一个打开端口 5000 的自定义 TCP 规则。

作者图片
最后,点击页面左下角的Run Task运行任务。
查看我们的应用程序是否正在运行
运行任务后,您将被转到fargate-cluster页面。当您的集群的最后状态变为RUNNING时,您的应用程序启动并运行。在状态为RUNNING之前,您可能需要刷新几次表格。这可能需要几分钟时间。

作者图片
- 单击任务列中的链接。
- 在任务页面的网络部分找到公共 IP 地址。

作者图片
- 在浏览器中输入公共 IP 地址,然后输入:5000 ,查看您的应用程序运行情况。

作者图片
关闭 app
当你看完猫的 gif 后,你会想关闭你的应用程序以避免收费。
- 从 ECS 页面的左侧菜单中选择集群,并从集群列表中选择
fargate-cluster。

作者图片
- 从页面底部的表格中选择任务。
- 选中正在运行的任务旁边的框
- 从表格顶部的下拉菜单中选择停止

作者图片
结论
既然您已经知道如何将 Docker 映像部署到 ECS,那么世界就是您的了。您可以部署一个刮擦应用程序,它会一直运行到完成,然后关闭,这样您只需为它运行的时间付费。您可以扩展 web 服务。你可以用多个 cat gif 服务器在互联网上传播 cat gif。一切都取决于你。
资源
-
如果您的权限不允许您的任务创建 ECS 任务执行 IAM 角色,您可以按照以下说明创建一个。
-
如果你是 Docker 新手,docker-curriculum.com 是一个不错的起点。
https://docker-curriculum.com/
- 将 Docker 映像部署到 ECS 的 Amazon 教程。
现在去做好事吧。
使用 Google Cloud Run 和 Flask 部署假新闻检测器 Web 应用程序
同时考虑到技术债务

在 Unsplash 上由 Teslariu Mihai 拍摄的照片
你的 ML 模型已经毕业了。现在它需要一份工作。
在你恰当地训练和验证了你的 ML 模型之后,是时候让它去做它应该做的事情了:服务。一种常见的方法是将其部署为 REST API。在这篇文章中,我想分享我是如何在我的个人项目中为假新闻检测构建一个简单的 web 应用程序的。
同时,我想借此机会讨论一个非常重要的问题:技术债务。
如今,部署 ML 系统相对较快,但是很容易忽略随着时间的推移维护这些系统是多么困难和昂贵。我不是这方面的专家,所以我不想讨论它的每个方面,而是想谈两个问题:
- 模型陈旧:ML 系统可能会遇到变化的、不稳定的数据。在这些情况下,如果模型没有被足够频繁地训练以产生最新的模型,则该模型被认为是陈旧的。
- 训练/服务偏斜:特征可能由系统的不同部分中的不同代码路径来计算。当这些代码路径生成不同的值时,这被称为训练/服务偏差。
根据应用程序的性质和复杂性,了解这两个问题的影响以及如何检测和避免(或减轻)它们是非常重要的。
因此,在向您展示我是如何部署我的应用程序的同时,我还想讨论这些问题是如何出现在这个特定项目中的,以及我们如何在设计中考虑这些问题。
应用程序
最后,我想要的是一个假新闻检测的 web 应用程序:一个用户可以输入一篇新闻文章的 URL 的页面,系统会告诉它预测的结果:是假的还是真的。举例来说,这是最终结果:

作者 Gif
应用程序的完整代码可以在项目的 Github 中找到。
注意:本文建立在我的上一篇的基础上,在这篇文章中,我训练了一个文本分类 SVM 模型(并跟踪了它的性能)。为了训练这个模型,我使用了来自 Kaggle 数据集的数据,你可以在这里找到。
需要注意什么
将模型投入生产时,我们应该考虑一些事情(以及其他事情)。
例如,用于训练模型的数据集包含 2015 年至 2018 年间的新闻文章。因此,作为一个例子,如果一篇关于新冠肺炎的文章被提交给模型进行推理,它的预测会是什么?新闻本质上是不断变化的。很明显,模型陈旧是这里的一个重要考虑因素。
另一个问题是没有显示在原始数据集中提取文本的方法。这很可能不是我在生产中用来提取内容的方法。因此,这里存在一些不可避免的训练/服务偏差。但是,当用生产中收集的数据重新训练模型时,我们必须有办法评估它,并从长远来看减轻它。
最后,我们还应该考虑训练和服务期间的文本预处理之间的差异。如果我在培训期间删除停用词,我必须确保在生产中也删除它们。如果在生产中引入了额外的预处理步骤,那么我应该重新训练模型。训练/发球偏斜的另一个例子。
概观
建立一个 web 应用程序可以有很多不同的方式。对于这个项目,这是我选择的方式:

作者图片
主应用程序是使用 Flask 构建的。Cloud Run 是 Google 提供的一个完全托管的解决方案,用于部署一个容器化的 web 应用程序。因此,为了在 Cloud Run 上部署我的应用程序,首先必须将它打包到 docker 容器中。
嗯,模型文件需要存储在某个地方。在我的上一篇文章中,我使用的是 AWS,但是因为我要使用 Cloud Run,所以让我们通过使用 Google 云存储将所有东西都放在同一个云环境中。当实例被创建时,所需的文件从我的存储桶中下载。
为了解决前面讨论的问题,我决定将所有预测结果存储在一个表中。在这种情况下,谷歌云 BigQuery。通过这种方式,我可以在未来使用在线预测的数据来重新训练模型。此外,如果我存储每个推断的预测概率值,我可以检查我的模型是否随着时间变得不确定。通过存储新闻内容,我还可以检查文本是如何处理的,并验证单词分布情况。我还可以记录产生结果的模型的名称,这样我就可以在不同版本和不同类型的模型之间进行各种测试。
初步步骤
为了设置我的环境,我必须执行一些步骤。
创建项目
第一个是创建一个 GCP 帐户,然后通过选择“创建项目”这里的来创建一个项目。
创建服务帐户
为了使用 Python APIs 访问存储和 BigQuery,我需要 JSON 格式的 GCP 凭证。我按照谷歌文档中“创建服务账户”的指示下载了我的证书。
创建存储桶
我还必须按照这里的指示在云存储中创建一个 bucket。我的桶被命名为“ models”,,在其中,我根据模型的名称存储了我需要的模型文件。这些名称和文件是根据我的上一篇文章创建的,在这篇文章中我讨论了跟踪 ML 实验(文章在这里和 Github 在这里)。

作者截图
创建表
最后一步是在 BigQuery 上创建表来存储我的预测。这可以用不同的方法来完成。我是这样做的:通过控制台在 BigQuery 上创建一个数据集,然后通过 Python 中的[google-cloud-bigquery](https://pypi.org/project/google-cloud-bigquery/)创建表本身:
pip install -upgrade google-cloud-bigquery
然后通过这个脚本:
注意,我们使用在上一步中下载的凭证作为环境变量。table_id是基于要创建的项目、数据集和表的名称构建的。
创建表后,您可以设置它的模式。对于这个项目,我决定存储以下重要字段:
- 标题:新闻的标题
- 内容:新闻的文本内容
- 模型:生成预测的模型的名称
- 预测:预测结果:真假
- 置信度:预测的概率,表示模型对其预测的置信度
- url: 原始新闻文章的 url
- 预测日期:进行预测的日期和时间
前端
既然是很简单的接口,这里就不多说了。主页 URL 只是呈现一个标题和一个文本框作为用户输入:
烧瓶应用程序
这是主要的应用程序代码。当表单发送 POST 请求时,会调用classify_news函数。它主要执行以下步骤:
- 从 URL 读取内容
- 预处理、矢量化文本内容并将其转换为 tf-idf 表示
- 预测它是假新闻还是真新闻
- 将预测结果插入到 BigQuery
- 向用户显示信息
你可以看到到classify_news有两条路线。一个是当它从主 URL 被调用时,在这种情况下text是从一个表单中获取的,这个函数应该返回一个 HTML 格式的字符串。
您还可以将它作为 API 端点直接调用,以便更容易从任何类型的应用程序中调用。然后,返回结果将等于用于将结果插入 BQ 表的字典。下面是我在 Postman 上本地测试应用程序时的一个例子:

作者截图
得到我们需要的
为了进行预测,我们首先需要获得模型文件。这包括 pickle 文件,它是用于 CountVectorizer 映射的词汇表,以及 joblib 文件,它是 sklearn 模型本身。
为了下载文件,我使用了[google-cloud-storage](https://pypi.org/project/google-cloud-storage/)包。我们可以使用前面创建的表所用的相同凭证。
阅读内容
然后,我们需要一种方法来实际提取文本,给定一个 URL。为此,我使用了一个名为[boilerpy3](https://pypi.org/project/boilerpy3/)的包。
预处理
一旦我们有了文本,我们需要将它转换成模型可以理解的格式。在训练期间,我们有一个简单的文本预处理阶段,随后是计数矢量化,然后将其转换为 tf-idf 表示。我不会详细讨论 NLP 方法,但你可以在这篇 sklearn 教程中了解更多。
您会发现了解生成模型的代码路径非常重要,这样您就可以在服务时尽可能好地重新创建它。还有,储存你以后可能需要的所有物品。
预言;预测;预告
现在我们有了正确的输入,我们可以通过加载我们训练好的模型并调用它的预测方法来进行预测。在这种情况下,prediction_proba返回两个类的概率(Real=1,Fake=0)。哪个更高就是预测类。
我们需要预测的概率值来监控模型的性能。但是要访问它,必须在训练阶段之前设置正确的参数。事先意识到这一点,而不仅仅是在生产过程中,肯定会使事情变得容易得多。
存储结果
我们最终可以将所有信息收集到一个字典to_insert中,然后将结果发送给 BigQuery:
打包和部署
一旦 Flask 应用程序在本地得到正确测试,我们现在就可以创建 Docker 映像并将其部署到云上。为此,我在这里遵循了这个很棒的教程:用 Python 和 Docker 部署 APIs】。
我不会解释这个过程中的每一个细节,因为上面的教程已经解释得很清楚了。但是,总而言之,我需要:
- 创建 Dockerfile 文件:
FROM python:3.7WORKDIR /appCOPY . .RUN pip install -r requirements.txtCMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 app:app
docker build -t fakenewsdeploy:<model_name> .- 安装谷歌 SDK
gcloud auth logingcloud auth configure-dockergcloud builds submit -t gcr.io/<your_project_id>/fakenewsdeploy:<model_name>
到目前为止,我们已经创建了图像,并将其上传到了 Google 容器注册表。现在,我们必须从我们的映像部署一个云运行应用程序。我们可以通过在控制台的云运行中单击“创建服务”来实现,最终结果应该是这样的:

作者截图
在前面的步骤中,我们在图像中插入了带有型号名称的标签,在这里,我们还可以为每个版本插入版本 URL。这不仅是一个标签,也是一个专门访问该版本的 URL。这样,我们可以访问和比较每个模型的性能,或者版本之间可能存在的任何其他差异。
另一个很酷的功能是你可以设置每个版本的流量。假设您刚刚训练了一个新的花式变压器模型,并希望将其与您的经典模型进行比较。这样,您可以逐渐增加最新型号的流量,以降低风险。因为您记录了结果,所以如果有问题,您可以很容易地恢复流量。
结果呢
不幸的是,由于我在 GCP 的试用期即将结束,我不会继续在线提供这项服务了。但是如果你很快就读到了这篇文章,你可以在https://fakenewsdeploy-2 hqadru 3 za-UC . a . run . app查看
最终的结果已经在本文的开头展示了。剩下要显示的是我们在 BigQuery 的表:

作者截图
我们现在可以直观地检查结果或进行一些 SQL 操作来计算一些有用的度量,如模型置信度、内容的单词分布和类分布。
结论
在本文中,我向您展示了我如何部署我的简单 web 应用程序来检测假新闻,同时试图为未来的自己减少债务。为了避免将来的一些大麻烦,你现在可以采取一些不痛不痒的行动。我相信在这件事上还有很多事情要做,但是,嘿,让我们一次学一件事。
既然涨了,剩下的就是维持了。您应该持续监控您的应用程序,并在需要时进行重新培训/重新部署。
为了重新训练你的模型,你最终将不得不标注你存储的在线预测。我读过一些关于人们选择置信度高于某个阈值的预测,并把它作为基本事实的报道。我不知道这是否真的值得推荐,但也许值得一试。
如果我继续这个个人项目,我想下一步应该是建立一个监控仪表板。为了让所有东西都在同一个地方,这可以在 Google Data Studio 中完成,例如,通过将我们的表设置为数据源。这样,我可以建立一些整洁的时间序列图、图表和图形。
暂时就这样吧!如果有什么建议,随时联系!
感谢您的阅读!
参考资料:
使用 Flask 在 Windows 上部署 fastai 模型

图片:作者
对深度学习模型进行基本的 web 部署是一种很好的方式,可以原型化如何使用您的模型,并验证您在培训过程中所做的假设。在与 Keras 一起工作时,我做了几个模型的简单部署,并发表了一些文章,描述我用 Facebook Messenger 和 T2 Flask 部署 Keras 模型的经历。
由于我在去年花了大量时间使用另一个主要的高级深度学习框架 fastai ,我希望获得 fastai 模型简单部署的实践经验。我决定用 Flask 来修改我在 Keras 模型的 web 部署中使用的方法。在本文中,我将描述创建 fastai 模型的简单 web 部署时必须克服的一些障碍,以及与 Keras 相比 fastai 为部署提供的一些意想不到的好处。
目标
我之前使用 fastai 管理的表格数据集 ADULT_SAMPLE 训练了一个 fastai 模型。该数据集的特征描述了个人(他们的年龄、工作类别、教育背景等),如下所示:

成人样本数据集的片段
我在 ADULT_SAMPLE 上训练的模型预测具有一组给定特征值的个人的收入是高于还是低于 5 万美元。出于部署的目的,我将这些特征值称为评分参数。
对于本文中描述的部署,我希望创建一个简单的 web 应用程序,用户可以在其中选择个人的特征值/评分参数,并从训练好的模型中获得关于此人的收入是否会超过 50 k 美元阈值的预测。
部署方法
我想尽可能多地重用我为 Keras 模型所做的 web 部署中的代码。我改编了 Keras web 部署中的 HTML 文件和 Flask 模块,并采用了下图中描述的方法:

Web 部署方法
- home.html—用户选择评分参数(年龄、工作类别、教育背景等值)的网页,他们希望获得个人的收入预测。
- Flask 模块 —服务网页并加载训练好的 fastai 模型。Flask 模块包含用于组成部署的两个网页(home.html 和 show-prediction.html)的视图函数。当一个网页被加载时,该网页的视图函数被执行,这使我们有机会从熟悉的 Python 设置中采取行动,比如调用模型进行预测。
- 经过训练的 fastai 模型-这是我使用成人样本数据集训练的模型,它根据个人的评分参数预测个人的收入是否超过 5 万美元。当启动 Flask 模块时加载该模型,并使用从 home.html 传来的评分参数在 show-prediction.html 的查看功能中调用该模型。
- show-prediction.html-显示模型对个人预测的网页,评分参数设置在 home.html。
在更新 HTML 文件以反映成人样本数据集的细节之后,我可以重用来自 Keras 部署的 HTML 文件。我不需要对这些文件做任何针对 fastai 的更改。
我必须做一些工作来从 Keras 部署中获取 Flask 模块,以便正确地加载和应用 fastai 模型。在下一节中,我将描述实现这一点的挑战和一些惊喜。
将所有这些放在一起:三个陷阱和一个惊喜
整个解决方案中最困难的部分是将 fastai 模型正确无误地加载到 Flask 模块中。根据我在 fastai 论坛上读到的内容,如果我一直使用 Linux 而不是 Windows 作为开发环境,我会更容易一些。然而,Windows 应该是 fastai 支持的平台,我的这个部署示例的观众需要能够使用 Windows,所以放弃这个平台不是一个选项。
要使部署工作正常进行,我必须克服三个关键问题。
-
当我试图加载 fastai 模型时,我一直得到 PosixPath 错误。我可以通过向 Flask 模块添加以下导入来解决这个问题(在这个堆栈溢出线程的帮助下):
-
由于形状不匹配错误,加载模型一直失败。在我包含了上述代码片段中显示的导入之后,我能够加载模型(在与 Flask 模块相同的目录中),但是我需要(a)将我的本地系统上的 Pandas 更新到最新级别(b)确保我使用了 Python 的平台不可知路径功能以避免反斜杠/正斜杠混淆,以及(c)使用模型的完全限定文件名作为 load_learner 的参数,如下所示:
-
我用来训练模型的成人样本数据集中的分类值都以空格开头。我忽略了在训练时进行转换来修剪这些空格,所以模型是用每个以空格开头的分类值来训练的。但是,我在 home.html 编码的分类特性的值(指定用户可以选择的有效值)不是以空格开头的。我没有注意到训练集和用户可以选择发送到部署模型的内容之间的不匹配。当我测试 web 部署时,该模型看到了所有分类特性的前所未有的值。结果是,在 web 部署中,模型总是预测“少于 50 k 美元”,即使在 Jupyter 笔记本中一次性调用时,模型预测得分参数集“大于 50 k 美元”。一旦我发现了训练集中的异常,我就更新 home.html 中的分类特征值,以一个空格开始。更新之后,web 部署预测与一次性预测相匹配。
最后,来自 fastai 的一个惊喜是:我能够部署模型,而不必显式地定义评分参数的管道。fastai 在推理时自动调用与训练时相同的分类值转换。这比我在 Keras 部署中所做的修改有更大的优势,例如,如果在训练模型时“星期一”被映射到 0,那么当调用部署的模型来获得预测时,它也被映射到 0。
结论
在 Windows 上完成一个 fastai 模型的简单的、基于 Flask 的 web 部署需要一些反复试验。为了能够成功地加载一个经过训练的 fastai 模型,我需要确保我有模型的精确正确的路径定义,这需要进行一些调查。我用来训练模型的数据集有一个异常,如果我在训练时修剪前导空格,就可以避免这个异常。然而,最终我能够使用适用于 Keras 模型的相同方法来部署 fastai 模型,fastai 使我不必担心在训练时和推理时如何同步分类值的编码。
背景
- Git repo 使用本文描述的 web 部署代码:https://github.com/ryanmark1867/fastai_deployment
- 本文视频版:【https://youtu.be/lLCeOPc82DI
- fastai 和 Keras 对比视频:https://youtu.be/3d6rGGyPR5c,https://youtu.be/wCMuQD2QBMk
在 Red Hat OpenShift 容器平台上部署机器学习模型作为 API
使用 Flask、Scikit-Learn 和 Docker 从 GitHub 库中的源代码

Annamária Borsos 摄影
机器和深度学习应用程序变得比以往任何时候都更受欢迎。正如我们之前所看到的,企业 Kubernetes 平台(Red Hat open shift Container Platform)通过引入额外的安全控制并使环境更易于管理,帮助数据科学家和开发人员使用他们喜欢的工具真正专注于价值。它能够在企业级和高度可用的集群中部署、服务、保护和优化机器学习模型,使数据科学家能够专注于数据的价值。我们可以使用托管服务(IBM Cloud 上的 Red Hat OpenShift、AWS 上的 Red Hat OpenShift 服务、Azure Red Hat OpenShift)在云中安装 Red Hat OpenShift 集群,或者我们可以通过从另一个云提供商(AWS、Azure、Google Cloud、平台无关的)安装来自行运行它们。我们还可以在受支持的基础设施(裸机、IBM Z、Power、Red Hat OpenStack、Red Hat 虚拟化、vSphere、Platform agonistic)上创建集群,或者在我们的笔记本电脑上创建对本地开发和测试有用的最小集群(MacOS、Linux、Windows)。这里很自由。
在本文中,我们将展示如何在云上的 OpenShift 集群上部署一个用 Python 开发的简单机器学习模型。出于本文的目的,我们将在 IBM Cloud 上创建一个 OpenShift 集群,并展示如何从 GitHub 存储库中部署我们的机器学习应用程序,并公开应用程序以访问它(有和没有 docker 文件)。
我们可以用很少很简单的步骤做到这一切。
创建一个 OpenShift 集群实例
我们连接到我们的 IBM Cloud 帐户,点击导航菜单,OpenShift,Clusters:

点击创建集群:

我们可以选择几个选项,如位置、运行集群或工作池的计算环境(vCPUs 数量、内存、加密本地磁盘……),然后单击“create”。一个有趣的选择是,我们可以选择卫星,它允许在我们自己的数据中心运行我们的集群。出于本文的目的,我们选择了 Classic。

搞定了。

您还可以使用 CLI 创建集群:https://cloud.ibm.com/docs/openshift?topic=openshift-clusters
从 GitHub 存储库中的源代码部署应用程序
我们可以从源代码、图像或模板创建新的 OpenShift 企业应用程序,并且可以通过 OpenShift web 控制台或 CLI 来完成。用所有的源代码和 Docker 文件创建了一个 GitHub 存储库,以便组装 Docker 映像,并在以后将其部署到 OpenShift 集群:https://github.com/xaviervasques/OpenShift-ML-Online.git
首先,让我们看看并测试我们的应用程序。我们克隆我们的存储库:
git clone [https://github.com/xaviervasques/OpenShift-ML-Online.git](https://github.com/xaviervasques/OpenShift-ML-Online.git)
在文件夹中,我们应该会找到以下文件:
Dockerfile
train.py
api.py
requirements.txt
OpenShift 将自动检测是否使用了 Docker 或源代码构建策略。在我们的存储库中,有一个 Dockerfile。 OpenShift Enterprise 将生成 Docker 构建策略。 train.py 是一个 python 脚本,它加载并分割 iris 数据集,这是一个经典且非常简单的多类分类数据集,由 3 种不同类型的 iris(Setosa、Versicolour 和 Virginica)花瓣和萼片长度组成,存储在 150 x4 numpy . NDA array 中。我们使用 scikit-learn 创建数据集和模型(支持向量机分类器)。requirements . txt(flask,flask-restful,joblib)用于 Python 依赖关系,而 api.py 是将被调用来使用 REST API 执行推理的脚本。API 将返回 svm 模型对测试数据的分类分数。
train.py 文件如下:
api.py 文件如下:
Dockerfile 文件:
最后是 requirements.txt 文件:
为了测试一切是否正常,让我们在本地机器上构建并运行 docker 映像:
cd OpenShift-ML-Online
docker build -t my-ml-api:latest .
docker run my-ml-api
输出如下所示:

您可以使用带有 curl 的 API:
curl [http://172.17.0.2:8080/](http://172.17.0.2:8080/)
我们应该得到以下输出:

我们现在准备部署。
要创建一个新项目,我们可以同时使用 CLI(使用 IBM Shell 或我们自己的终端)或 OpenShift web 控制台。在控制台中,为了创建一个新项目,我们从 OpenShift 集群控制台中选择我们的集群(mycluster-par01-b3c.4x16 ),然后单击 OpenShift web 控制台。


从透视图切换器中,我们选择 Developer 来切换到 Developer 透视图。我们可以看到菜单提供了+Add、Builds 和 Topology 等项目。

我们点击+Add 并创建项目:

在本章中,我们将在本地机器上使用 CLI。由于我们在 IBM Cloud 上安装了 OpenShift 集群,如果还没有安装,那么有必要安装:
-open shift Origin CLI(https://docs . open shift . com/container-platform/4.2/CLI _ reference/open shift _ CLI/getting-started-CLI . html)
然后,我们需要登录 OpenShift 并创建一个新项目。为了做到这一点,我们需要复制登录命令:

我们登录我们的帐户:
ibmcloud login
我们复制/粘贴登录命令:
oc login — token=sha256~IWefYlUvt1St8K9QAXXXXXX0frXXX2–5LAXXXXNq-S9E — server=https://c101-e.eu-de.containers.cloud.ibm.com:30785
new-app 命令允许使用本地或远程 Git 存储库中的源代码创建应用程序。为了使用 Git 存储库创建应用程序,我们可以在终端中键入以下命令:
oc new-app [https://github.com/xaviervasques/OpenShift-ML-Online.git](https://github.com/xaviervasques/OpenShift-ML-Online.git)
这个命令有几个选项,比如通过指定— context-dir 标志来使用我们的源代码库的子目录,指定 Git 分支或者设置— strategy 标志来指定构建策略。在我们的例子中,我们有一个 Socker 文件,它将自动生成一个 Socker 构建策略。

应用程序已部署!应用程序需要向外界公开。正如前面的输出所指定的,我们可以通过执行以下命令来实现这一点:
oc expose service/openshift-ml-online

我们可以检查状态:
oc status

我们可以在输出中找到 API 的路径:
curl [http://openshift-ml-online-default.mycluster-par01-b-948990-d8688dbc29e56a145f8196fa85f1481a-0000.par01.containers.appdomain.cloud](http://openshift-ml-online-default.mycluster-par01-b-948990-d8688dbc29e56a145f8196fa85f1481a-0000.par01.containers.appdomain.cloud/)
它提供了预期的输出(svm 模型对测试数据的分类得分)

oc get pods --watch

我们还可以在 OpenShift web 控制台中找到关于我们服务的所有信息:




在透视图切换器中,如果我们选择 Developer 切换到 Developer 透视图并单击 Topology,我们可以看到下面的屏幕:

在屏幕的右下角,面板显示了可以访问应用程序的公共 URL。你可以在路线下看到它。如果我们单击链接,我们也可以从应用程序中获得预期的结果。

我们可以使用 web 控制台或 CLI 创建不安全和安全的路由。不安全路由最容易设置,也是默认配置。然而,如果我们想为保持私有的连接提供安全性,我们可以使用 create route 命令并提供证书和密钥。
如果我们想从 OpenShift 中删除应用程序,我们可以使用 oc delete all 命令:
oc delete all — selector app=myapp
在没有 Docker 文件的情况下,OpenShift Source to Image (S2I)工具包将创建一个 Docker 映像。源代码语言是自动检测的。我们可以遵循相同的步骤。OpenShift S2I 使用构建器映像及其源来创建部署到集群的新 Docker 映像。
结论
使用 Docker、Python、Flask 和 OpenShift 封装和部署机器/深度学习应用变得很简单。当我们开始将工作负载迁移到 OpenShift 时,应用程序被封装到一个容器映像中,该映像将被部署到测试和生产环境中,从而减少了我们在现实生活中部署应用程序时会看到的遗漏依赖项和错误配置问题的数量。
真正的生活就是这样。MLOps 需要数据科学家、开发人员和 IT 运营人员之间的交叉协作,这在协调方面非常耗时。在 Kubernetes 混合云平台(如 OpenShift)上构建、测试和培训 ML/DL 模型,可以实现一致、可扩展的应用部署,并有助于根据需要在我们的生产环境中频繁部署/更新/重新部署。Red Hat OpenShift 中集成的 DevOps CI/CD 功能允许我们将模型自动集成到开发过程中。
来源
https://developer . IBM . com/technologies/containers/tutorials/scalable-python-app-with-kubernetes/
https://cloud . Google . com/community/tutorials/kubernetes-ml-ops
https://docs . open shift . com/enterprise/3.1/dev _ guide/new _ app . html
https://github . com/jjasghar/cloud-native-python-example-app/blob/master/docker file
https://docs . open shift . com/container-platform/3.10/dev _ guide/routes . html
https://docs . okd . io/3.11/minishift/open shift/exposure-services . html
https://www . open shift . com/blog/serving-machine-learning-models-on-open shift-part-1
https://sci kit-learn . org/stable/modules/generated/sk learn . datasets . load _ iris . html
部署 REST API 来服务人脸轮廓模型
经过相当长时间的搜索,我们已经确定了几个产品,可以用来缓解将深度学习模型部署到生产中所需的提升。由于我们的最终应用程序并不明确(尽管我们有几个想法),生产化该模型的最佳方法是将其部署为 REST 服务,该服务可以独立于生成每个模型的数据科学生命周期过程进行维护,并且对于每个数据科学家来说都足够简单。轻松部署 REST 端点的能力是模型随时间快速迭代的关键促成因素。Ubiops 是一个为深度学习服务提供托管服务的产品,运行在 Kubernetes 上,大大简化了创建和维护 REST 服务的过程。

来自托管面部轮廓模型的 REST 端点的输出。(图片由作者提供,原文:Schniter,Eric,& Shields,Timothy。(2020).参与者面临重复的囚徒困境[数据集]。芝诺多。http://doi.org/10.5281/zenodo.4321821
介绍
在本文中,我们使用 IPython Jupyter 笔记本来部署一个带有 Ubiops 的 REST 端点。本演示中使用的模型是我们在2020–10–12博客中开发的面部轮廓。该模型是一个面部轮廓,旨在作为一种工具来控制表型属性的影响,这些表型属性可以从肖像风格的图像(有脸的图片)中观察到。REST 端点将支持底层模型的持续开发,独立于基于它构建的应用程序。发送的大部分字节将是来自经过训练的 Unet 分段模型的权重,大小为 165MB,经过 pickle 压缩。演示的最后一步展示了开发客户如何使用终端来获取面部特征。
通常使用的 UbiOps 的一些替代方案是 AWS Lambda 或其他类似的无服务器产品,自托管的“有状态”Flask 应用程序,以及在 MLOps 旗帜下销售的其他有前途的解决方案,如 Streamlit,Seldon,FastAPI,特别是提供“无服务器 GPU”产品的 Algorithmia。模型服务的关键问题是:它需要低成本,因为我们正在引导一个产品。它需要提供一个编程 API 和围绕模型发布和消费的常识性行为。最后,它需要使用 Jupyter 笔记本作为源
本教程的代码可以在这里找到: Github Repo
部署现有模型
自述文件对用于部署此端点的不同工件有更全面的描述。这些步骤可以在 Ubiops 文档和 Ubiops 食谱中找到。这个例子略有不同,因为一个需求是将笔记本作为代码的记录系统。在 cookbook 教程中,笔记本代码由 python 模块填充,而在本教程中,python 模块是使用Fastai-nb dev项目从笔记本构建的。基本模式是:

从带有 Ubiops 的 Jupyter 笔记本电脑部署。(图片作者)
高级功能
实施包括几个步骤。首先,我们创建了Deployment类。Deployment类的实现结构是由 Ubiops 定义的,最好的地方是在指南中。Deployment类成为端点的入口点,它的所有依赖项都可以在deployment_package中得到考虑。我们压缩deployment_package,然后使用 Ubiops API 注册部署请求的输入和输出。最后,我们将使用 API 将您的deployment_package zip 存档推送到 Ubiops。下面点击了高点,但是完整的代码在Github Repo中找到。
部署类
import sys; import os
from pathlib import Path
import io
import jsonimport skimage
from skimage import color
import matplotlib.pyplot as plt
import numpy as npfrom prcvd.img.core import (
TrainedSegmentationModel, MaskedImg
)
from prcvd.img.face import (
FacialProfile
)
from prcvd.core import json_to_dictclass Deployment:
def __init__(self, base_directory:str, context):
"""
Initialisation method for the deployment. It can for
example be used for loading modules that have to be kept in
memory or setting up connections. Load your external model
files (such as pickles or .h5 files) here.
:param str base_directory: absolute path to the directory
where the deployment.py file is located
:param dict context: a dictionary containing details of the
deployment that might be useful in your code.
It contains the following keys:
- deployment (str): name of the deployment
- version (str): name of the version
- input_type (str): deployment input type, either
'structured' or 'plain'
- output_type (str): deployment output type, either
'structured' or 'plain'
- language (str): programming language the deployment
is running
- environment_variables (str): the custom environment
variables configured for the deployment.
You can also access those as normal environment variables via os.environ
"""
print("Loading face segmentation model.")
self.basedir = Path(base_directory)
self.mod_fp = self.basedir/'model1.pkl'
self.output_classes = [
'Background/undefined', 'Lips', 'Eyes', 'Nose', 'Hair',
'Ears', 'Eyebrows', 'Teeth', 'General face', 'Facial hair',
'Specs/sunglasses'
]
with open(Path(self.basedir)/'ubiops_output_spec.json') as f:
self.output_spec = json.load(f)self.output_mapping = {
obj['name']: obj['id']
for obj
in self.output_spec
}
self.size = 224
self.model = TrainedSegmentationModel(
mod_fp=self.mod_fp,
input_size=self.size,
output_classes=self.output_classes
)
上面,我们将模型加载到内存中。Ubiops 警告说,这一步发生在端点空闲一段时间之后,所谓的冷启动可能需要一些时间。base_directory是deployment_package的根级别,您可以看到,当Deployment被实例化时,我们加载了该文件夹中的几个文件。下一部分是定义调用model.predict的Deployment.request。
def request(self, data, attempt=1):
"""
Method for deployment requests, called separately for each individual request.
:param dict/str data: request input data. In case of deployments with structured data, a Python dictionary
with as keys the input fields as defined upon deployment creation via the platform. In case of a deployment
with plain input, it is a string.
- img: str, file path
- sampling_strategy: str, 'use_all' | ...
- align_face: bool, yes/no apply face alignment
- num_attempts: int, max attempts before failure (sometimes face alignment fails)
:return dict/str: request output. In case of deployments with structured output data, a Python dictionary
with as keys the output fields as defined upon deployment creation via the platform. In case of a deployment
with plain output, it is a string. In this example, a dictionary with the key: output.
"""
img = MaskedImg()
img.load_from_file(data['img'])
try:
profile = FacialProfile(
model=self.model,
img=img,
sampling_strategy=data['sampling_strategy'],
align_face=data['align_face']
)
except:
if not attempt > data['num_attempts']:
return self.request(
data=data,
attempt=attempt+1,
)
else:
return None, None## .. make/save the plot .. (see github for full code)
row = profile.get_profile()
row['model_id'] = str(self.mod_fp) # for ubiops output type str
row = {**row, **{'img': str(outfp)}}
return {self.output_mapping[k]: v for k,v in row.items()}
model.predict使用用户提供的输入来计算面部轮廓,并将其与原始图像一起可视化(见报告)。可以将文件保存到当前工作目录,Ubiops 会负责清理它们。另一方面,如果您需要保存作为输入提交的图像,您需要将该代码添加到请求中。
创建部署包
发送到 Ubiops 的是一个包含Deployment类和依赖项的压缩文件。如果您有任何私有依赖项,例如私有回购中不在 PiPy 上的包,您可以手动将它们添加到deployment_package中。下面的部分是在笔记本中完成的,但也可以从命令行完成。
打包部署类
下一部分可以从笔记本或命令行运行。它将笔记本代码(mod)生成的模块转换为 Ubiops 私有依赖。必要的部分是setup.py和mod文件夹,其中包含特定于该部署的 python 模块。我们删除了.git目录和笔记本,因为我们想最小化deployment_package的大小。
cp -r .. ../../prod-mod-face-profile-cp
rm -rf ../../prod-mod-face-profile-cp/deployment_package/
rm -rf ../../prod-mod-face-profile-cp/*.zip
rm -rf ../deployment_package/libraries
mkdir ../deployment_package/libraries
mv ../../prod-mod-face-profile-cp ../deployment_package/libraries/prod-mod-face-profile
rm -rf ../deployment_package/libraries/prod-mod-face-profile/.git/
获取任何其他私有依赖关系
我们需要获取任何其他私有库来打包这个部署。这个库包含了所有操纵经过训练的深度学习模型的代码,以及计算人脸轮廓的代码。
rm -rf ../deployment_package/libraries/prcvd
cd ../deployment_package/libraries && git clone [@github](/{user}:{pw}<a href=).com/prcvd/prcvd.git">https://{user}:{pw}[@github](http://twitter.com/github).com/prcvd/prcvd.git
cd ../deployment_package/libraries/prcvd && git checkout {branch}
rm -rf ../deployment_package/libraries/prcvd/.git/
提示:删除模块不需要的文件。
警告:为了在 git repo 中不提交保存的冗余文件的情况下工作,我们不提交
deployment_package和其他大型工件,如*pkl、*pth和*zip。更多详情见.gitignore底部
部署
您可以使用 Ubiops API 部署deployment_package.zip。第一部分是定义一个“部署”,如下面的代码所示。其主要部分是定义名称和数据类型输入以及来自Deployment.request的输出。我选择在单独的文件中管理它们,因为除了在这里定义部署之外,它们还会在几个地方使用。这是允许的 Ubiops 数据类型列表。我选择将输出中的每一项都作为单独的输出对象。在连接到 Ubiops Python API 之前,创建一个登录和项目是很重要的。
配置 Ubiops API 连接
这一步需要您用 Ubiops UI 手动获取一个 api ke y,并创建一个新项目。一旦您将 api 密匙存储在安全的地方,您就可以连接了。
client = ubiops.ApiClient(
ubiops.Configuration(
api_key={'Authorization': os.getenv('API_TOKEN')},
host='[https://api.ubiops.com/v2.1'](https://api.ubiops.com/v2.1'))
)
api = ubiops.CoreApi(client)deployment_template = ubiops.DeploymentCreate(
name='my_deployment',
description='description',
input_type='structured',
output_type='structured',
input_fields=[
ubiops.DeploymentInputFieldCreate(
name=str(obj['name']),
data_type=obj['data_type']['value'])
for obj in input_spec
],
output_fields=[
ubiops.DeploymentOutputFieldCreate(
name=str(obj['id']),
data_type=obj['data_type']['value'])
for obj in output_spec
],
labels={'demo': 'mod'}
)
一旦部署存在,就会创建一个部署Version,在这里定义集群细节(例如,最大实例数、内存、空闲时间等..),如下:
version_template = ubiops.VersionCreate(
version='v1',
language='python3.6',
memory_allocation=3000,
minimum_instances=0,
maximum_instances=1,
maximum_idle_time=1800 # = 30 minutes
)
最后,我们可以用下面的代码将deployment_package.zip推送到 UbiOps:
file_upload_result = api.revisions_file_upload(
project_name='face-profile',
deployment_name='my_deployment',
version='v1',
file=zipfp
)
值得查看 Github 中的笔记本,其中包含完整的部署代码。在那里,它展示了如何利用 Ubiops API 生成的一些异常来做一些基本的,但自动升级的事情。
提示:
deployment_name和version标识符可以通过笔记本中的代码来控制。
检查部署
可以使用 API 来检查部署的状态,这需要反复询问状态。或者,用户可以在 Ubiops UI 中监控状态和日志。部署的日志如下所示:

Ubiops 登录用户界面(作者图片)
Python 请求客户端
一旦模型被部署,它简化了使用,因为现在不需要在本地加载模型,我们只需要调用一个 REST 端点。这就避免了安装依赖的问题,在我的经验中,安装依赖是阻止我的模型被他们的目标用户使用的最令人沮丧的问题。呼叫可以在一行中完成,如下所示:
client = UbiOpsClient(
project_name='face-profile',
deployment_name='my_deployment',
deployment_version='v1',
input_spec='./ubiops_input_spec.json',
output_spec='./ubiops_output_spec.json',
api_key=os.getenv('API_TOKEN'),
api_host=os.getenv('HOST')
)# >> out
{'0000': (52, 47, 49),
'0001': (133, 86, 112),
'0002': (179, 144, 159),
'0003': (33, 28, 34),
'0004': (106, 10, 34),
'0005': (118, 102, 117),
'0006': None,
'0007': (144, 122, 132),
'0008': None,
'0009': None,
'0010': (97, 87, 107),
'0011': (76, 72, 92),
'0012': (196, 163, 176),
'0013': (145, 122, 133),
'0014': (188, 157, 166),
'0015': 3.4990597042834075,
'0016': 6,
'0017': -0.0,
'0018': 1.596774193548387,
'0019': 99.0,
'0020': 62.0,
'0021': 18828,
'0022': 0.018748672190354792,
'0023': 0.04110898661567878,
'0024': 0.30359039728064585,
'0025': 0.0014871468026343743,
'0026': 0.013702995538559592,
'0027': 0.0,
'0028': 0.2953579774803484,
'0029': 0.0,
'0030': 0.0,
'0031': 0.006107924367962609,
'0032': 0.0053112385808370514,
'0033': 0.06161036753770979,
'0034': 0.09693010410027618,
'0035': 0.15604418950499258,
'0036': '/home/fortville/code/prod-mod-face-profile/deployment_package/model1.pkl',
'0037': '/home/fortville/code/prod-mod-face-profile/deployment_package/tmp.jpeg'}
查看模型的输入/输出

在右边,看到输入图像。在左边,可以看到输出。可以将手动编码器绘制的线条(黑色实线和黑色虚线)与 PRCVD 绘制的线条进行比较。AI 算法(实心红和实心绿)(作者图片)
提示:在过去,使用不同的技术,我将“请求客户端”代码保存在它自己的模块中。请求者通常是拥有不同权限的数据科学家,而不是创建部署的工程师。
结论
总的来说,UbiOps 实现了简化 REST API 服务部署的承诺,并且提供了一个相当慷慨的免费层。UbiOps 接受单个部署类,并提供一个简单的目录结构来支持其库依赖关系。在本教程中,我们将讨论 jupyter 笔记本电脑和 UbiOps 云之间持续集成的概念验证。用户可以在 jupyter 笔记本中以半自动方式进行更改,包括更改模型重量、测试这些更改和部署。通常编写部署类的文件通过从笔记本创建的模块导入而成为标准文件。如果没有这个特性,用户将需要在笔记本中维护代码的一个版本(例如“原型”),并在生产中在 python 模块中维护另一个版本(或者只是一个 python 文件)。就像我用过的其他生产技术,比如 AWS Lambda,有一个学习曲线,我必须对工具进行部分逆向工程,这需要我稍微重新思考我的原型设计的几个方面。
未来的工作包括集成更多的 Github 动作,这样,deployment_package.zip的创建和测试可以由新的 PR commit 或合并到主分支来触发。事实上,Ubiops 最近有一篇文章描述了如何与 github actions 集成:这里
本教程中的所有代码都可以在这里找到
使用 AWS 部署可扩展的端到端客户流失预测解决方案
用于生产就绪的端到端客户流失预测管道的部署包
失去客户要花钱。发现可能会离开的客户,然后阻止他们流失,这样可以省钱。如果你能留住客户更长时间,最大化他们一生的收入,这不是很好吗?如果这可以通过机器学习大规模实现,那不是更好吗?
猜猜看,现在你可以了!

来源:金次郎www.brandonlepine.art/,承蒙 吉菲
在这篇博文中,您将使用 AWS 服务部署一个端到端的客户流失预测解决方案。您将使用 Amazon SageMaker 和 AWS 步骤函数构建自动训练和推理管道,用于机器学习流失检测。除了识别最有可能流失的客户之外,随需应变的能力,作为 ETL 过程运行,支持预处理,并具有可解释性。AWS 上的客户流失渠道是以基础设施为模板的代码,使其能够扩展和重新应用。该解决方案作为参考实施,使各种规模的组织更容易实施端到端的训练和推理管道。
该解决方案通过使用 Amazon Lambda 调用来触发管道运行,从而支持数据摄取、培训/再培训和推理。它利用亚马逊 S3 与亚马逊 SageMaker 和 AWS Step 功能直接集成,由亚马逊胶水和亚马逊雅典娜支持。这使得能够自动运行、快速试验、快速部署,并轻松纳入 TB 级的扩展数据大小。
解决方案概述🏗️
以下架构图说明了该解决方案的工作流程:

作者图片
该工作流程包括以下步骤:
- 一个用来存放数据、云形成模板和模型人工制品的 S3 桶
- Amazon Glue Crawler 扫描来自 S3 的数据,并将其加载到 Athena 数据库
- 指向 S3 的训练和推理数据的 Amazon Athena 数据库
- 一个训练管道步骤功能工作流(状态空间机器),由 Amazon Lambda 触发器组成,这些触发器运行 Amazon SageMaker 预处理和 Amazon SageMaker 训练作业
- 推理管道步骤功能工作流(状态空间机器),由运行 Amazon SageMaker 预处理和 Amazon SageMaker 推理作业的 Amazon Lambda 触发器组成
在开始之前,您首先需要一个配置了凭证的 AWS 帐户设置,如本文档中所述。此外,确保已经安装了 AWS 命令行界面 AWS CLI。本教程假设您有一个具备必要的身份访问管理 IAM 权限的环境。
请记住,运行本教程将在您的 AWS 帐户中产生费用!!!
对数据的快速浏览📊
在本例中,您将使用一个虚构的电信公司的合成流失数据集,其结果Churn?被标记为True(流失)或False(未流失)。功能包括客户详细信息,如计划和使用信息。客户流失数据集是公开可用的,并在 Daniel T. Larose 的书发现数据中的知识中提到。作者将其归功于加州大学欧文分校的机器学习数据集仓库。

作者图片
请记住,这个数据集可以用您自己的数据替换,只要代码库被更新以适应它。换句话说,如果你的目标是将它重新应用到你的数据中,这篇文章是你实现目标的第一步!继续读下去,你就会明白怎么做了。
启动解决方案🚀
首先将 Github repo 克隆到本地文件夹中。
git clone [https://github.com/awslabs/aws-customer-churn-pipeline.git](https://github.com/awslabs/aws-customer-churn-pipeline.git)
在克隆的目录中应该有一个名为standup.sh的文件。接下来,我们将使用这个脚本来构建必要的基础设施,以运行训练和推理管道。该脚本只接受三个命令:您希望为堆栈及其相关资源指定的名称、堆栈的区域以及存放所有工件和数据的 AWS Bucket 名称。您可以像下面这样运行该命令:
bash standup.sh {STACK_NAME} {S3_BUCKET_NAME} {REGION}
bash standup.sh churn-pipeline churn-pipeline-artifacts ap-southeast-2
这将开始使用调用 AWS CLI 和部署 Amazon CloudFormation 模板在您的默认 AWS 帐户中建立必要的资源。
具体来说,该脚本将创建:
- Amazon Athena 数据库,包含基于堆栈名称的主要工作组名称
- 一个 Amazon Glue 爬虫,以及爬虫的 IAM 角色,扫描数据并从指定的 S3 存储桶将其加载到数据库中
- 将训练、推理和预处理 python 脚本上传到您的 S3 桶中
- 将 AWS 步骤功能
pipeline.yaml上传到您的 S3 桶中 - 为训练和推理部署 AWS 步骤函数管道。这是基于上述 S3 的位置,并创造了多个亚马逊 Lambda 和亚马逊 SageMaker 工作。
- 将堆栈名称和区域写入
delete_resources.sh,以便稍后可以使用该脚本来拆除 AWS 基础设施
一旦直立完成,你的云形成控制台应该看起来如下,所有堆栈显示绿色。

作者图片
同样,如果您转到 Athena 控制台,您现在会看到用于训练和推理的表格。
注意,数据库的名称将基于您在standup.sh中分配的 S3 存储桶名称。
最后,如果您转到 Step Functions 菜单,您将看到两个状态机(或工作流),一个用于训练,另一个用于推理。

作者图片
这两个管道都被设计为按需或按计划运行,能够自动部署打包的代码,因此在部署中几乎没有工作和风险。本节和下一节将解释每个管道是如何工作的,让您更接近完全自动化的机器学习流失管道。
自动化培训渠道🤖
培训管道使用亚马逊 Lambdas 和亚马逊 SageMaker,通过七个步骤向亚马逊 S3 输出经过全面培训、验证和优化的客户流失模型。

作者图片
让我们首先通过调用 Amazon Lambda 来启动培训管道:
aws lambda --region ${REGION} invoke --function-name invokeTrainingStepFunction --payload "{ '': ''}" out
您应该会得到 200 代码,表明 Lambda 触发了
{"StatusCode": 200, "ExecutedVersion": "$LATEST"}
步骤 1: SageMaker 培训步骤预处理🎛️
现在,工作开始了!让我们回顾一下它正在采取的步骤。
Amazon SageMaker 的预处理作业是在使用 SageMaker 的 Scikit Learn 容器直接从 Amazon Athena 表中查询的数据上运行的。
使用scripts/preporcessing.py按以下顺序运行该步骤:
- 使用 awswrangler 从 Athena 表中读取数据
- 通过随机拆分将数据分为训练数据集和验证数据集
- 缺失值被估算,分类值被热编码
- 然后,经过分割和预处理的数据集将作为 csv 文件写回 S3
- 预处理器被保存以在推理管道中使用
预处理脚本和云形成模板pipeline.yaml的阶跃函数参数是可更新的。例如,容器的入口点参数在 CloudFormation 中设置为:
"ContainerArguments": [
"--database",
"${AthenaDatabaseName}",
"--region",
"${AWS::Region}",
"--table",
"train",
"--train-test-split-ratio",
"0.2"]
数据库名{AthendaDatabaseName}作为栈名传入,并附上-db。从您传递给standup.sh的变量中设置区域。表名默认为训练数据名,在本例中为“train”。最后,训练和测试之间的随机分割在这里被设置为默认值,25%的数据用于测试。
对于这篇博文,您将保留pipeline.yaml的设置。请记住,可以根据您的数据更改所有这些配置。
步骤 2 : SageMaker 超参数调整步骤📈
超参数调整步骤为您的模型找到超参数的最佳组合。在本例中,您使用 XGBoost 将流失建模为二元结果(将流失/不会流失)。具体来说,您将尝试通过最大化曲线下的区域,在重复的并行运行中找到最佳的正则化项、深度和树分裂组合(默认为总共 2 个)来实现最高的精度。在给定可用数据的情况下,这将产生最准确的模型。
值得注意的是,这里没有脚本。使用 SageMaker 的 XGBoost 容器,所有配置都作为 JSON 直接传递给pipeline.yaml中的 SageMaker。和以前一样,默认值是硬编码的。然而,像管道的所有部分一样,它们可以根据需要进行更新。要更深入地了解使用 Amazon SageMaker 进行超参数调整以及可能的输入类型,请参见这里的。
步骤 3: SageMaker 步骤获得最佳超参数⭐️
此步骤调用 Lambda 函数来记录最佳执行模型(和超参数配置),然后将其传递到步骤函数工作流中的下一步。
步骤 4: SageMaker 培训步骤👾
现在确定了最佳模型,您将再次重新训练,以获得完全训练的模型和输出模型可解释性度量。
同样,这个步骤使用来自pipeline.yaml的 SageMaker 配置来运行 SageMaker 的 XGBoost 容器映像。这一次,培训从优化的超参数和 SageMaker 调试器设置开始。使用调试器运行训练作业,除了完整训练的模型之外,还允许将可解释性度量输出到 S3。
可解释性度量显示了每个特性如何影响客户流失。结合像 SHAP 这样的技术,能够从整体上解释模型,更重要的是,能够了解如何在单个客户基础上确定分数。
步骤 5: SageMaker 步骤保存模型💾
这一步调用一个 Lambda 函数将训练好的模型作为 Amazon SageMaker 模型工件保存到 S3。
步骤 6: SageMaker 获取模型 Url🔦
这一步从 S3 检索模型 URI,用于下一步的模型评估。
步骤 7: SageMaker 步骤模型评估🧪
最后一步是对训练和测试数据进行全面评估,并向 S3 输出结果报告。模型评估步骤在这里作为一个模块,因为它允许为不同的客户流失用例定制指标、图表和挂钩。
首先,训练好的模型直接从其存储的 S3 URI 加载。然后,它生成测试数据的分类报告,并将结果作为evaluation.json输出回 S3。最后,输出 SHAP 值和要素重要性图,并保存回 S3。请注意,与步骤 4 SageMaker 训练步骤中的 SageMaker 调试器步骤不同,这些输出直接发送到您命名的 S3 桶,而不是其他地方的 SageMaker 默认桶。

作者图片
自动推理管道🤖
推理管道使用从训练管道生成的 Amazon SageMaker 人工制品对看不见的数据进行推理,然后分两步将其放回 S3。

作者图片
SageMaker 推理步骤预处理🎛️
在这一步中,您将加载保存的预处理程序并转换数据,使其格式适合运行流失推断。
与培训管道相同,这是通过调用 Amazon Lambda 触发的。
lambda --region ${REGION} invoke --function-name invokeInferStepFunction --payload "{ '': ''}" out
和以前一样,200 代码表示作业启动成功,推理管道开始运行。
{"StatusCode": 200, "ExecutedVersion": "$LATEST"}
在pipeline.yaml 中查看显示,推断数据被假定在表名infer下。
"ContainerArguments": [
"--database",
"${AthenaDatabaseName}",
"--region",
"${AWS::Region}",
"--table",
"infer"]
和以前一样,数据库名{AthendaDatabaseName}作为栈名传入,并附上-db。区域设置为传递到standup.sh的区域。同样,SageMaker 的配置几乎完全相同,容器映像仍然使用 SageMaker 的 Scikit Learn 的容器。
这里的例外是您将使用scripts/inferpreprocessing.py而不是scripts/preprocessing.py 。该脚本从训练管道步骤 1 加载保存的训练预处理器,用于新数据。然后,转换后的要素以前缀data/intermediate的形式输出回 S3,进入您指定的 S3 存储桶。
批量转换输入数据集(推理)⚡️
既然推理数据集的格式正确,您就可以获得流失预测。下一步利用 Amazon SageMaker 的批处理转换特性,以批处理作业的形式直接运行推理,然后将数据结果写到前缀/data/inference_result中的 S3。
您的最终结果应该包括每个客户的流失概率得分:

作者图片
清理🗑
要清理资源以防止进一步收费,请运行以下文件:
bash delete_resources.sh
这将拆除 Churn 管道的云形成堆栈。要确认所有东西都被删除了,去你的 CloudFormation 控制台。控制台现在应该没有所有相关的堆栈。

作者图片
请注意,由于该进程没有生成 S3 存储桶,因此运行管道得到的所有文件仍将在那里。如果您不想保留这些文件,您需要清空存储桶并单独删除它们。
结论🙏
这个博客非常适合开始使用自动化的客户流失预测解决方案。也就是说,还可以做更多的事情来支撑管道。例如,数据完整性检查,像 PyDeequ 或亚马逊 SageMaker 模型监视器可以添加到管道中,以进一步提高模型完整性。通过改变容器图像和数据库部分,可以将工作负载换成其他形式的数据,如文本。此外,可以通过使用 AWS 代码管道或类似的服务来完全自动化,这些服务将构建所有的基础设施并运行由单个提交触发的两个工作流。
使用 Amazon SageMaker 管道部署无服务器推理服务
实践教程
SageMaker 无服务器模型部署分步指南
将您的一些 ML 模型部署到无服务器架构中,允许您创建可伸缩的推理服务,消除操作开销,并更快地进入生产。我已经在这里和这里和发布了例子,展示了如何在你的项目中采用这样的架构。

照片由 SpaceX 在 Unsplash 上拍摄
在本文中,我们将更进一步,使用Amazon SageMaker Pipelines自动部署这种无服务器推理服务。
使用 SageMaker Pipelines,您可以加速端到端 ML 项目的交付。它将 ML 工作流编排、模型注册和 CI/CD 结合到一把伞中,因此您可以快速地将您的模型投入生产。
我们将基于 SageMaker 提供的 MLOps 模板创建一个项目,用于模型构建、培训和部署。该项目在鲍鱼数据集上训练一个示例 XGBoost 模型,并将其部署到 SageMaker 端点中。我们将保留项目的模型构建和培训部分,并更新模型部署,以便它可以是无服务器的。
演练概述
我们将分三步部署推理服务:
- 我们将首先在 SageMaker 中启动一个 MLOps 项目,并定义我们的推理服务。
- 然后,我们将更新 ModelDeploy repo 以反映我们的无服务器部署。
- 最后,我将展示如何使用 ModelDeploy 管道将推理服务部署到您的帐户中。
以下是该项目的架构概述:

我们将使用这个 MLOps 模板并将模型部署到一个无服务器堆栈中,而不是 SageMaker 端点中。
先决条件
要浏览此示例,请确保您具备以下条件:
- 对于无服务器推理服务,我们将重用我以前的文章中展示的代码和概念。开始前,确保您熟悉这个例子和这个例子。
- 访问使用 Amazon SageMaker 管道构建、自动化、管理和扩展 ML 工作流和介绍 Amazon SageMaker 管道可能是一个好的开始,如果这个 SageMaker 特性对您来说听起来很新的话。
- 访问亚马逊 SageMaker 工作室环境并熟悉工作室用户界面。
- Docker 构建 Lambda 容器映像并将其推送到 ECR,如果您是在自己的环境中完成的话。 SageMaker Studio 映像构建 CLI ,如果您从 Studio 推送容器映像。
- 这个 GitHub 库克隆到您的工作室环境中
步骤 1:在 SageMaker 中启动 MLOps 项目并定义推理服务
启动您的 MLOps 项目
首先,我们需要启动一个基于 MLOps 模板的 SageMaker 项目,用于模型构建、培训和部署。
你可以按照朱利安·西蒙的视频来做:
项目模板将为 ModelBuild 和 ModelDeploy 创建 2 个 CodeCommit repos,为 CI 和 CD 创建 2 个 CodePipeline 管道,为打包和测试工件创建 CodeBuild 项目,以及运行项目的其他资源。
ModelBuild 管道将自动触发 ML 工作流,并将 XGBoost 模型注册到模型注册中心。我们将保持项目的这一部分不变,并修改 ModelDeploy repo,以便我们可以将模型部署到无服务器服务中。

模型部署流程的视图
定义您的无服务器推理服务
Amazon API Gateway 将成为我们服务的门户,AWS Lambda 将处理推理。堆栈将由 CDK 定义。你可以在我以前的帖子这里和这里中找到类似的模式。

无服务器推理服务的一个视图
为 Lambda 创建推理处理程序
下面的 predict.py 文件包含 XGBoost 模型的推理处理程序:
当一个新的 XGBoost 模型被创建时,SageMaker 将二进制文件保存在 S3 的一个model.tar.gz文件中。我们将把这个 S3 位置作为环境变量传递给 Lambda 函数,这样该函数就可以下载并提取它到 /tmp 文件夹中。我已经创建了 utils.py 来处理这件事。
你可以在容器文件夹中找到 Lambda 函数的 Dockerfile。
将 Lambda 图像推送到 ECR
ModelDeploy 管道中的第一步运行名为 ModelDeployBuildProject 的 CodeBuild 项目。默认使用非特权模式下的AWS/codebuild/amazonlinux 2-x86 _ 64-standard:3.0来封装我们的栈基础架构模板。
因此,CDK 将无法从 CodeBuild 本身构建容器映像并将其推送到 ECR。如果您从 Studio 中完成,您可以使用 SageMaker Studio 映像构建 CLI 将容器映像推送到 ECR。在我的例子中,我使用 build_and_push.sh 从我的笔记本电脑推送它:
sh build_and_push.sh lambda-inference
注意:要直接从 CodeBuild 构建容器映像,您可以让 CodeBuild 项目在特权模式下运行,或者甚至创建您的定制项目模板。但是超出了本文的范围。
为推理服务创建一个 CDK 堆栈
您可以在堆栈文件夹中找到推理服务的 CDK 堆栈,并将您的 ECR 映像位置添加到其中。

确保 stack.py 文件中有正确的容器图像位置
我们将在步骤 2 中更新 buildspec.yml 文件,以便 CodeBuild 可以从中生成 CloudFormation 模板。
步骤 2:更新 ModelDeploy 存储库以反映无服务器部署
在将 ModelDeploy 存储库克隆到您的环境中之后,您可以使用来自这个存储库的代码来更新代码。


您的回购在更新之前(左)和之后(右)应该是什么样子
你可以在下面找到 buildspec.yml 文件。它从 CDK 堆栈生成 CloudFormation 模板,并将其输出到 CodePipeline 进行部署:
build.py 脚本使用 boto3 从您的模型注册表中获取最新批准的模型二进制文件,并将其放入登台和生产配置文件中。
我们还更新了 test.py 以便在准备阶段对推理服务进行基本测试。它向 API 发送一个示例有效负载,并检查响应状态是否正常。
步骤 3:部署和使用您的推理服务
部署前
ModelDeploy 管道为堆栈中的资源提供了 IAM 角色 ARN 以供使用。您将需要更新此角色,以便它可以使用 API 网关、AWS Lambda 和从 ECR 提取图像。
该角色名为AmazonSageMakerServiceCatalogProductsUseRole,您可以像我下面所做的那样更新其权限:

我在这个例子中使用了托管策略。确保在您的环境中加强权限。
触发部署
现在我们已经做好了启动无服务器推理服务的一切准备。您可以将代码推送到 modeldeploy repo 的主分支。
您还可以进入您的模型注册中心,批准您的模型投入生产。

这将触发 ModelDeploy 管道。一旦测试成功,您就可以导航到 CodePipeline 控制台,并手动批准您的推理服务进入 prod。
使用您的服务
当您的服务成功部署到产品中时,您可以导航到 API 网关服务控制台并复制您的 API URL。

我们在这里使用 $default 阶段只是为了说明的目的。参见发布 REST APIs 供客户调用以获得发布 API 的指导。
以下是您可以添加到请求正文的测试数据点:
你可以使用像 Postman 这样的工具从你的电脑上测试推理 API:

结论
Amazon SageMaker Pipelines 将 ML 工作流编排、模型注册和 CI/CD 整合在一起,减少了运行端到端 MLOps 项目的工作量。在这篇文章中,我们用一个现成的模板创建了一个 SageMaker MLOps 项目,并使用它来部署一个无服务器推理服务。
更进一步,你还可以学习如何使用 Amazon SageMaker 优化无服务器推理服务的性价比。
使用 Flask 部署 Spotify 推荐模型
机器学习模型的真正价值在于可用性。如果模型没有被恰当地部署、使用,并且没有通过客户反馈的循环不断地更新,它注定会停留在 GitHub 的仓库中,永远不会达到它的实际潜力。在本文中,我们将学习如何通过几个简单的步骤在 Flask 中部署 Spotify 推荐模型。
我们将部署的应用程序存储在 recommendation_app 文件夹中。其结构如下所示:
wsgi.py
requirements.txt
data/
application/
model.py
features.py
templates/
home.html
results.html
about.html
static/
style.css
routes.py
在根目录中,我们有 wsgi.py 文件,当我们在终端中运行' $ flask run app '时将调用该文件,它调用 create_app()函数在本地主机上创建我们的服务器。Requirements.txt 包含我们的项目在另一个需求中运行所需的依赖项。数据文件夹包含模型推荐歌曲所需的数据。
应用程序文件夹包含我们的 flask 应用程序的主要组件。显然,我们需要的第一个组件是模型本身。这里,我们将使用一个 Spotify 推荐模型,在给定一个 Spotify 播放列表的情况下,根据从 Spotify 库中检索到的音频特征推荐一些适合该播放列表的歌曲。如果您对如何检索此类模型的相关数据、基于音频特征执行聚类并开发推荐模型感兴趣,请随时查看本系列的以下文章:
此外,我们需要一个函数,将 Spotify 播放列表链接转换为包含相关功能的 pandas 数据帧,推荐将基于该数据帧进行——在我们的示例中,它存储在 features.py 文件中。简而言之,该函数获取一个可以从桌面 Spotify 应用程序获取的链接,并连续分割它以获得构成播放列表 ID 的字母和数字的组合。最后,通过使用 spotipy 库中的“user_playlist”函数和一系列字典操作,该函数创建了最终的数据帧。
最后,是时候创建一个简单的 flask 应用程序了!
flask 应用程序的最简单形式由两个文件夹组成——templates 和 static,以及一个包含应用程序路线的 python 文件。前一个文件夹包含用户输入数据时将呈现的 HTML 模板,后一个文件夹包含带有简单样式的 CSS 文件。路线文件将包含三条路线:
@app.route("/")
def home():
return render_template('home.html')@app.route("/about")
def about():
return render_template('about.html')@app.route('/recommend', methods=['POST'])
def recommend():
URL = request.form['URL']
df = extract(URL)
edm_top40 = recommend_from_playlist(songDF, complete_feature_set, df)
number_of_recs = int(request.form['number-of-recs'])
my_songs = [] for i in range(number_of_recs):
my_songs.append([str(edm_top40.iloc[i,1]) + ' - '+ '"'+str(edm_top40.iloc[i,4])+'"', "https://open.spotify.com/track/"+ str(edm_top40.iloc[i,-6]).split("/")[-1]]) return render_template('results.html',songs= my_songs)
- 用户打开应用程序时将到达的家庭路线('/');
- 推荐路径('/recommend)将处理来自表单的输入,并将推荐歌曲的列表发送回用户;
- 包含项目基本信息的信息路线('/about ');
recommend()函数到底是做什么的?
- 首先,它通过 POST 请求从 HTML 表单中获取用户输入的 URL
- 它调用 extract()函数,该函数将 URL 转换为音频特征的数据帧;
- 它调用 recommend_from_playlist()函数根据用户的播放列表创建推荐歌曲的数据帧;
- 它根据通过 POST 请求在下拉菜单中选择的值,请求用户想要的推荐数量;
- 它创建一个空列表,用 x 首推荐歌曲填充,其中 x 是选择的推荐数;
- 最后,它呈现以 my_songs 列表作为输入的 results.html 模板,并为用户输出歌曲推荐;
为了让应用程序看起来更好看,我们将使用 bootstrap,它包含各种可以重用的元素,如按钮、标题、表单等。在我的例子中,我把引导程序用于标题、“关于”和“主页”按钮。此外,为了使推荐逐渐出现,我在 CSS 中使用了提供一些动画功能的关键帧标签。
@keyframes fastSlide {
0% { transform: translate(120%) skewX(0deg) ; }
70% { transform: translate(0%) skewX(1deg) ; }
80% { transform: translate(0%) skewX(0deg) ; }
95% { transform: translate(0%) skewX(0deg) ; }
100% { transform: translate(0%) skewX(0deg) ; }
}
例如,这允许我从屏幕右侧逐渐显示推荐。
要在本地运行我们的推荐应用程序,我们可以在根目录中运行“$ python wsgi . py”——这将确保服务器处于开发模式,我们可以在进行任何更改时调试和刷新它。

图片作者。

图片作者。
正如我们所见,该应用程序运行正常,并根据播放列表链接和用户选择的推荐数量返回一组推荐。然而,我们还没有完成!如果我们希望有人使用我们的应用程序,而不必在本地安装所有的文件夹,该怎么办?
这就是云部署的用武之地!有各种各样的服务可以帮助人们部署他们的应用程序,但在本文中,我们将使用 Pythonanywhere.com,它有免费试用和负担得起的大型应用程序选项。我们所需要做的就是创建一个初学者帐户,创建一个适当的文件夹结构,并将我们所有的文件上传到那里。在我的例子中,我遵循了 Sohan Dillikar 关于如何在 PythonAnywhere 上免费托管你的 Flask 应用的教程——然而在我的例子中,我没有使用 requirements.txt 文件,而是使用下面的教程创建了一个虚拟环境并安装了软件包。
瞧,我们有了一个功能正常的网站,上面有我们的应用程序,可以随时使用并向潜在雇主展示:
网站演示文稿
很简单,对吧?
使用 Heroku、Google Cloud 和 GitHub 部署 Web 应用程序
允许用户从 Google Cloud 交互式查询数据,而不暴露您的凭据。
我最近玩了一下应用程序部署,做了一个关于芝加哥地区犯罪的应用程序。点击这里查看!
顾名思义,我希望将源代码保留在 GitHub 上,使用 Heroku 进行部署,因为它是免费的,并允许用户从芝加哥警察局实时查询数据,以减少存储成本和维护。安全地做到这一点比我预期的要复杂得多,所以我认为这篇文章可能对其他人有所帮助。

为什么是这些工具?
GitHub :我想把我的代码都放在 GitHub 上。出于几个原因,我不想在多个位置存储不同的项目。第一,很乱。我不想为了维护我的项目而在平台之间切换。第二,我记性很差。如果我没有东西放在一个地方,很可能我会忘记一些曾经存在过的东西。
Google Cloud: 那是我获得数据的地方。要构建一个几乎不需要维护并保持最新的应用程序,我知道我需要一些东西,允许我在需要时从那里查询数据。还有,数据是海量的!光是加载就够给熊猫添麻烦了,所以把数据存储在 GitHub 上不太实际。
Heroku:我想我本可以继续使用谷歌云,使用他们的应用引擎。也许吧。我还没有深入调查过,所以不能确定。它要求我放下一张信用卡,所以我停下来。我还没有富到让公司拿我的信用卡做人质的地步。此外,我有使用 GitHub & Heroku 部署应用程序的经验。老实说,对我来说,Heroku 的界面比谷歌云服务更友好。
那么挑战是什么?
安全问题:要使用 BigQuery(数据在 Google Cloud 上),我必须在每次想要查询数据时向应用程序提供我的凭证。有一个简单明了的计划,就是把所有东西都发布到 GitHub 上,然后让 Heroku 接手。
试验 1: 上传凭证到 GitHub 上的私有库,在主项目的库中创建子模块,引用私有库。听起来可行,对吧?没有!Heroku 不加载 GitHub 的子模块。我希望我在尝试之前能看到这个…
试炼 2 : GitHub 秘笈!我认为将我的凭证复制粘贴为存储库秘密是可行的。然后,当 Heroku 从 GitHub 部署时,我可以使用 GitHub Actions 将秘密作为一个变量进行广播,我可以使用os从 Python 脚本中获得这个变量。老实说,我仍然不知道这是否可行。我写了一个‘动作’剧本(你是这么说的吗?)似乎通过了 GitHub 的 sniff 测试。但是在我的 Python 脚本中,我根本无法访问这个变量。如果你知道,请告诉我。
试验三:然后我想到也许我可以在 Heroku 这边做一些类似的事情?也许我可以直接告诉 Heroku 我的资历。而我找到了我的解决方案!
第三次是一种魅力
因此,步骤是这样的(我不会经历完全复制我的项目的所有步骤,只是那些我认为对于实现使用来自 Google Cloud 的数据从 GitHub 部署 Heroku 应用程序的类似目标是必要的):
- 创建一个 Heroku 帐户,然后在您的控制面板中,单击“新建”创建一个新应用程序。我选择了 Python。
- 按照这些步骤来集成 GitHub 和 Heroku。我不建议允许自动部署,除非你确定一切正常。当 Heroku 给你的收件箱发邮件说‘这没用!’时,你会感到焦虑。!!'当它每 5 分钟尝试部署你的应用时。
- 在 GitHub repo 中创建一个 Procfile、setup.sh(由 GitHub复制并粘贴)和 requirements.txt(包含一个 python 包的列表以使您的应用程序工作)文件。
- 按照这些步骤为 Google BigQuery 设置一个 Python 客户端。不过,你不需要使用虚拟环境。我用康达。我认为 google-cloud-bigquery 确实与一些 python 包冲突,所以我必须为这个项目创建一个新的 conda 环境。最后,您应该得到一个包含您的凭证的. json 文件。还有,第一个 1TB 是每月免费的,所以我没有设置计费账户。
- 按照这些步骤让 Heroku 知道你的证书。
streamlit——网络的上帝——开发无能
我唯一真正懂的语言是 Python。过去,我曾尝试过 MATLAB、Java 和 R,主要是为了协作项目或课程。当然,如果情况需要,我可以学习新的语言。但如果是为了个人项目,我会尽量把自己对 Python 的理解推得更远。我只是在走阻力最小的路。
想象一下,当我发现我不必学习 Javascript 或 CSS 之类的东西时,我有多轻松。按照以下步骤安装 streamlit 。我会用conda install -c conda-forge streamlit来代替。点击此链接查看他们的小工具选项。我没有足够的经验来判断这些选项是否足以满足你的所有需求,但它们肯定足以满足我的需求。
我如何构建应用程序的精简演练
首先,我给这个应用起了一个时髦的名字,吸引眼球,比如
import streamlit as st
st.title("Chicago Crime")
那里!然后,我将所有东西包装在一个if语句中,以确保代码只在我拥有 Google Cloud 凭证的情况下运行。
然后,我想要一个侧边栏,让用户指定他们的偏好。
当你打开我的网络应用程序时,我想这些功能显而易见。然后,根据question变量返回的内容,执行一条if语句。
我认为 streamlit 的可爱之处在于,我不必担心将所有东西都包装在一个不断获取用户输入的循环中。例如,如果用户首先选择“普遍犯罪”,则相应的 if 语句被激活。一个普通的 Python 程序会在一次输入后结束。但是有了 streamlit,用户可以随心所欲地多次输入他们的选项,脚本就可以“重新运行”,而无需我为这个过程显式编码。
为了可视化数据,我使用了 plotly。这个过程就像一个人通常会做的那样,但是为了形象化,像这样传递它来简化它
st.plotly_chart(fig1)
总结
本文讨论了构建一个从 Google Cloud 查询数据的 web 应用程序并使用 Heroku & GitHub 部署它的必要步骤。在 Heroku 上部署应用程序肯定有更快更简单的方法。事实上,我想要 GitHub 上的所有东西,这让整个过程变得复杂。
由此产生的应用程序也存在延迟问题,因为它是从大型数据集实时查询的。我还注意到应用程序启动需要一点时间,这让我想知道是否有比 Heroku 更好的平台。
保持联系
我喜欢写关于数据科学和科学的文章。如果你喜欢这篇文章,请在 Medium 上关注我,加入我的电子邮件列表,或者成为 Medium 会员(如果你使用这个链接,我将收取你大约 50%的会员费),如果你还没有的话。下一篇帖子再见!😄
通过 Azure 模板部署带有所有自定义配置的 Azure 服务
如何通过点击一个按钮或一行命令来部署一切

动机:
我们都面临过这种情况。当我们测试一个新的服务或者一个新的库时,我们需要制造一个全新的虚拟机来消耗我们每天宝贵的时间。有没有什么东西可以自动做到这一点?嗯,不用担心, Azure Templates 就是来解决这个问题的。在这篇博客中,我将写如何为你的资源创建模板,这样你就可以在将来通过点击来部署它们。
先决条件:
- 一个带有 Azure 虚拟机服务的 Azure 账号。
- Azure SSH 密钥服务
- (可选) Azure CLI
Azure 模板创建:
有不同的方法来创建模板,但我们将通过简单和首选的方式。所以,让我们以最传统的方式,通过 Azure 门户创建一个 VM。但是在此之前,我们需要创建一个 SSH 密钥。搜索“SSH 密钥”服务,然后创建它。

苏拉布什雷斯塔。通过 Azure 模板 1 部署带有所有自定义配置的 Azure 服务。2021.JPEG 文件。
现在搜索虚拟机,然后点击它。不要忘记选择您刚刚在虚拟机中创建的密钥。

苏拉布什雷斯塔。通过 Azure 模板 2 部署带有所有自定义配置的 Azure 服务。2021.JPEG 文件。
让我们也为这个虚拟机添加自动关闭功能。

苏拉布什雷斯塔。通过 Azure 模板 3 部署带有所有自定义配置的 Azure 服务。2021.JPEG 文件。
现在,让我们为该虚拟机添加最重要的功能,即自定义数据。这是我们为机器添加脚本以便在启动时运行的地方。我已经添加了一些脚本来将 nvidia docker 镜像安装到机器中。

苏拉布什雷斯塔。通过 Azure Templates 4 部署带有所有自定义配置的 Azure 服务。2021.JPEG 文件。
让我们也添加一些标签。

苏拉布什雷斯塔。通过 Azure Templates 5 部署带有所有自定义配置的 Azure 服务。2021.JPEG 文件。
这里,我们不点击“创建”,而是点击“创建”按钮旁边的“下载自动化模板”。

苏拉布什雷斯塔。通过 Azure Templates 6 部署带有所有自定义配置的 Azure 服务。2021.JPEG 文件。
它会提示你进入新的一页。单击“下载”下载您的模板。

苏拉布什雷斯塔。通过 Azure Templates 7 部署带有所有自定义配置的 Azure 服务。2021.JPEG 文件。
您将获得一个名为“template.zip”的 zip 文件,然后在该 zip 文件中,您将获得两个名为“template.json”和“parameters.json”的文件。模板是您的模式,参数包含您选择的所有值。现在打开 paramters.json 并检查它。您会发现缺少一些东西,adminPublicKey 和自定义数据。这是故意的,因为微软不希望你的敏感信息包含在 JSON 中,这对微软来说是一件非常好的事情。现在,您必须手动将其添加到 JSON 中。
让我们从 adminPublicKey 开始。还记得我们制作的 SSH 密钥吗?现在,让我们再次访问该服务,您将在服务的前端提示中看到公钥,以“ssh-RSA”开始,以“= generated-by-azure”结束。复制所有内容,然后粘贴到 JSON 的“adminPublicKey”上。
现在是“customData”字段的时间了。这里我们不能像上面那样简单的复制粘贴,我们需要用 base64 严格编码。这里有一个 python 代码来编码它。
苏拉布什雷斯塔。通过 Azure 模板 8 部署带有所有自定义配置的 Azure 服务。2021.JPEG 文件。
运行此代码,您将获得一个编码字符串,将其粘贴到“customData”字段。保存 JSON。现在是有趣的部分。
Azure 模板部署:
再次转到门户并搜索“部署自定义模板”。

苏拉布什雷斯塔。通过 Azure Templates 9 部署带有所有自定义配置的 Azure 服务。2021.JPEG 文件。
点击后,您将被重定向到另一个页面。点击“在编辑器中构建您自己的模板”。

苏拉布什雷斯塔。通过 Azure Templates 10 部署带有所有自定义配置的 Azure 服务。2021.JPEG 文件。
点击“加载文件”并选择“template.json”。选择后,点击“保存”。

苏拉布什雷斯塔。通过 Azure Templates 11 部署带有所有自定义配置的 Azure 服务。2021.JPEG 文件。
我们的模式已经加载,现在是上传参数的时候了。点击“编辑参数”,然后上传“parameters.json”并点击“保存”。

苏拉布什雷斯塔。通过 Azure 模板 12 部署带有所有自定义配置的 Azure 服务。2021.JPEG 文件。
如您所见,我们选择的所有参数都已选中,出于安全考虑,敏感参数放在密码字段中。点击“查看并创建”。

苏拉布什雷斯塔。通过 Azure 模板 13 部署带有所有自定义配置的 Azure 服务。2021.JPEG 文件。
正在部署您的虚拟机。等待一段时间。

苏拉布什雷斯塔。通过 Azure 模板 14 部署带有所有自定义配置的 Azure 服务。2021.JPEG 文件。
部署完成。现在让我们看看虚拟机本身,并尝试通过 SSH 密钥进入虚拟机内部。

苏拉布什雷斯塔。通过 Azure Templates 15 部署带有所有自定义配置的 Azure 服务。2021.JPEG 文件。
成功了。现在让我们看看在创建虚拟机时初始化的关闭功能。

苏拉布什雷斯塔。通过 Azure 模板 16 部署带有所有自定义配置的 Azure 服务。2021.JPEG 文件。
现在是我们加载到虚拟机中的脚本。我的脚本是下载 Nvidia docker 映像,然后安装它,所以我应该在 monitoring 选项卡中看到峰值。让我们检查一下。

苏拉布什雷斯塔。通过 Azure Templates 17 部署带有所有自定义配置的 Azure 服务。2021.JPEG 文件。
如您所见,所有四个主要指标都出现峰值,这证明后端脚本正在虚拟机内部运行。一切正常。
结论:
它像预期的那样工作。我们为虚拟机创建了一个灵活的模板,可以随时随地进行部署。我们还可以将这个模板存储在我们的 GitHub repo 中,以便与我们的 DevOps 操作集成。我使用 VM 作为例子,因为与其他服务相比,它具有独特的特性。我也选择在 Azure Portal 中这样做,因为这是一种简单直接的方式。创建模板后,我们也可以使用 Azure CLI 进行部署。
az deployment group create --resource-group medium-test-rg --name rollout01 --template-file template.json --parameters parameters.json
只需这一个命令,一切都将为您部署,但要做到这一点,您需要从主机上使用 Azure 帐户登录。

苏拉布什雷斯塔。通过 Azure 模板 18 部署带有所有自定义配置的 Azure 服务。2021.JPEG 文件。
成功了。我们还可以从 PowerShell、REST API、Github 和 CloudShell 进行部署。您应该根据自己的需求决定从哪里开始部署。然而,选择是无穷无尽的,你想做什么取决于你自己。如果你遇到任何问题或难以遵循这些步骤,请在下面评论这篇文章或在 tsulabh4@gmail.com 给我发消息。你也可以在 Linkedin 和 GitHub 上和我联系。
资源:
[1] Azure 模板和 Azure CLI:https://docs . Microsoft . com/en-us/Azure/Azure-resource-manager/Templates/deploy-CLI
[2] ARM 模板文档:https://docs . Microsoft . com/en-us/azure/azure-resource-manager/templates/
通过几次点击部署端到端深度学习项目:第 2 部分
初学者的数据科学
从 Jupyter 笔记本到 Flask 应用程序采用模型,使用 Postman 和 Heroku 部署测试 API 端点
注意:这是从零开始实现深度学习项目的两部分系列的第二部分。 第一部分 涵盖了问题陈述的设置、数据预处理、迁移学习背后的直觉、特征提取、微调、模型评估。第 2 部分介绍了 Flask 应用程序的实现及其在 Heroku 上的后续部署。为了保持连续性,请遵循教程。 上的代码 Github 。

你可以在这里玩烧瓶应用程序。
https://github.com/V-Sher/house-interior-prediction
快速抬头
我倾向于为部署脚本创建新的工作环境。
但是为什么呢?
对于云部署,我们需要使用 *pip freeze* 命令创建一个 *requirements.txt* 文件,所以最好只保留那些在活动环境中运行 *app.py* 脚本所需的包。正如你可能在 第 1 部分 中看到的,在模型训练期间,我们最终会进行大量的 pip 安装,而这些包中的许多可能并不需要进行部署,并且会不必要地增加你的应用程序大小。
为什么是 Heroku,为什么不是 Docker?
简单的回答:这又快又简单,而且不需要写文档(这需要一些技巧)。
注意:我打算在 Heroku 仪表板上点击几下就部署代码。话虽如此,没有理由不使用 Heroku CLI 直接从命令行管理他们的应用程序。
Flask 应用后端
现在我们已经有了一个名为fine_tuned_house.h5(来自第 1 部分)的训练有素的模型,现在是时候创建一个快速部署的 Flask 应用程序了。我已经写了一篇关于如何为初学者创建 Flask app 的详细文章。
在创建前端(即index.html)之前,最好使用 Postman API 创建并测试后端脚本(您可能希望先创建一个账户)。我总是在一个名为api_test.py的文件中保存一些样板代码以备测试。目前,它所实现的只是一个名为intro()的GET方法,该方法返回字典{“Hello”: “World”}。
***# api_test.py***from flask import Flask, jsonify, request# define this is a flask app
app = Flask(__name__)# some dummy results
res = {"Hello": "World"}@app.route('/', *methods*=["GET"])
*def* intro():
return jsonify(*result*=res)if __name__=="__main__":
app.run(*debug*=True)
要在 Postman 中测试api_test脚本,首先在 VSCode 中本地运行它,然后转到 Postman 桌面应用程序,提供本地主机 URL(通常是127.0.0.1:5000),将方法设置为GET,并单击蓝色的 Send 按钮。您将看到它返回预期的结果。

现在,是时候创建将返回模型预测结果的POST方法了。为此,让我们创建predict()方法:
*# api_test.py*from flask import Flask, jsonify, request# define this is a flask app
app = Flask(__name__)# some dummy results
res = {"Hello": "World"}@app.route('/', *methods*=["GET"])
*def* intro():
return jsonify(*result*=res)**@app.route('/predict-interior', *methods*=['POST'])
*def* predict():
.
.
.**if __name__=="__main__":
app.run(*debug*=True)
route装饰器的第一个参数指定了 URL 端点,在这种情况下,URL 看起来类似于127.0.0.1:5000/predict-interior。
在这个函数中,我们首先将使用request.files读取一个图像文件img (我们将从前端接收该文件),现在,让我们只返回它的形状。
@app.route('/predict-interior', *methods*=['POST'])
*def* predict():
**f = request.files['img']
file = Image.open(f)
file_shape = np.asarray(file).shape****return jsonify(*file_shape*=file_shape)**
在我们在 Postman 上测试POST方法之前,我们需要在 Postman 中进行一些设置:
- 将请求类型从获取更改为发布。
- 在 Headers 下,添加一个新的键值对:
Content-Type : application/json。

- 要上传图像,进入主体→表单-数据,将关键字设置为字符串
img(记住该字符串应该与您使用request.files请求的文件名相同)。选择文件,点击蓝色的发送按钮。


最终输出将是一个字典,其值与输入图像的形状完全匹配。

让我们更新predict(),现在包括预测功能:
**IMG_SHAPE = (224,224)
CLASSES = ["Modern", "Old"]**@app.route('/predict-interior', *methods*=['POST'])
*def* predict():
f = request.files['img']
file = Image.open(f)
file_shape = np.asarray(file).shape*# predictions* **preds = model.predict(np.expand_dims(file, *axis*=0))[0]
i = np.argmax(preds)
label = CLASSES[i]
prob = preds[i]
predictions={"label": label, "prob": str(prob)}**return jsonify(***predictions*=predictions**)
以下是输出结果:

既然测试已经完成,让我们创建最终的app.py脚本。
进口
import base64
import numpy as np
from PIL import Image
from flask import Flask, render_template, request
from tensorflow.keras.models import load_model
加载微调模型和变量
IMG_SHAPE = (224,224)
CLASSES = ["Modern", "Old"]model = load_model('fine_tuned_house.h5')
定义烧瓶应用
*# define this is a flask app* app = Flask(__name__)
指定获取方法
# basic first page@app.route('/')
*def* sayhello():
return render_template('index.html')
顾名思义,[render_template()](https://flask.palletsprojects.com/en/2.0.x/api/#flask.render_template)方法将呈现提供给它的html文件(我们将很快创建index.html)。
指定发布方法
@app.route('/predict-interior', *methods*=['POST'])
*def* predict():
f = request.files['img']
**fpath = getfpath(f)**
file = Image.open(f)
file_shape = np.asarray(file).shape***# resize image to (224,224) if needed*
if file.size != IMG_SHAPE:
file = file.resize(IMG_SHAPE)
file_shape = np.asarray(file).shape***# predictions* preds = model.predict(np.expand_dims(file, *axis*=0))[0]
i = np.argmax(preds)
label = CLASSES[i]
prob = preds[i]
pred_output={
'img_size': file_shape,
'label': label,
'probability': np.round(prob*100,2)
}return render_template('index.html',
*img_shape*=file_shape,
***user_image*=fpath**,
*pred_output*=pred_output
)
我们做了一些小改动:
- 如果需要,检查并调整输入图像的大小(因为我们的模型是在
224x224图像上训练的)。 - 渲染
index.html,但这次我们传递了额外的参数,如img_shape、user_image和pred_output。我们将看到这些将如何在前端index.html中使用。 - 创建一个名为
getfpath()的方法,将输入图像编码为 base 64,并在前端显示。
(另外,该方法的输出将被输入到*index.html*中的*<img src=”{{ user_image }}” height=”350" width=”350">*)。)
*def* getfpath(*img*) -> str:*# convert to bases64*
data = *img*.read() # get data from file (BytesIO)
data = base64.b64encode(data) # convert to base64 as bytes
data = data.decode() # convert bytes to string
*# convert to <img> with embed image*
fpath = "data:image/png;base64,{}".format(data)
return fpath
注意:确保在 *Image.open* 之前调用 *getfpath()* 。这是因为 *Image.open(f)* 的工作方式是,它会先做 *f.seek(0)* 即把指针设置回文件 *f* 的起始位置,然后是 *f.read()* ,然后返回一个非空字符串。切换顺序将导致调用 *f.read()* 两次,而没有将指针设置回文件的开头(和/或关闭它),因此将产生一个非空但无意义的字符串(这将不会在 *index.html* 中呈现 apt 图像)。
前端
这里有一个比较简单的前端index.html。
需要考虑的事情很少:
- 与
render_template()一起传递的img_shape、pred_output和user_image现在用于打印图像形状(第 21-23 行)、模型预测(第 25-27 行)和显示调整到350x350分辨率的原始图像(第 29-31 行)。 - 在第 13 行,在
url_for中指定的字符串应该与app.py中的 POST 方法名称相匹配。 - 在第 15 行,为
name参数指定的值应该与在app.py的request.files中指定的文件名相匹配。
前端和后端都准备好了,本地运行应用程序,看看一切正常。一旦你满意了,就是 Heroku 部署的时候了。
Heroku 部署
第一步:创建 requirements.txt
对于 Heroku 部署,您需要在使用pip freeze > requirements.txt冻结需求之前执行pip install guincorn。
注意:只将应用程序运行所需的那些包放在 requirements.txt 中。因此,在单独的环境中运行您的笔记本电脑,以将内存块大小保持在 500MB 以下(这是 Heroku 的 最大允许大小)。
第二步:创建过程文件
在项目根文件夹中创建一个名为 Procfile 的新文件,文件类型为:
web: gunicorn app:app
第三步:上传项目目录到 Github repo
注意:如果我们在 第一部分 中使用一些更大的模型,比如 Resnet-50(而不是 EfficientNet),我们将需要 使用 Git LFS 上传更大的文件 到 Github。这样做将生成一个 *.gitattributes* 文件,将其作为回购的一部分上传是很重要的。
第四步:头转向 Heroku 仪表盘
首先,让我们创建一个新的应用。接下来,转到 Deploy 选项卡,选择 Github 选项。您还需要提供回购名称。

回购连接后,可以选择要部署的分支,点击部署分支。

第一次构建应用程序会花费更长的时间,但后续的部署会涉及一些缓存,因此会更快。
完成后,任何人都可以在https://*<app-name>*.herokuapp.com/访问您的应用。例如,我的应用程序可以在https://house-interior-prediction.herokuapp.com/访问。
构建可能失败的原因有两个:
- 废料浆尺寸太大
有许多方法可以有效地管理 Heroku 部署的 slug 大小,但其中一种方法是在您的需求中用 tensorflow-cpu 替换 tensorflow 。【演职员表: StackOverflow 】。这很有效,因为推理在 CPU 上运行良好,而 Heroku 不支持 GPU。
- Git LFS 用于在回购中上传更大的模型。
Heroku 没有对 Git LFS 的内置支持,因此构建并不简单。
解决方案是使用构建包(我使用这个在其他项目中部署 Resnet-50 模型期间处理 Git LFS 资产)。
设置很简单:
-在 Heroku 仪表板的设置选项卡下,前往 Buildpacks 部分并点击添加 buildpack 。当提示输入构建包 URL 时,输入https://github.com/raxod502/heroku-buildpack-git-lfs。


-在相同的设置选项卡下,转到配置变量部分,输入 KEY 作为 HEROKU_BUILDPACK_GIT_LFS_REPO,输入 VALUE 作为要下载 Git LFS 资产的库的克隆 URL。例如,如果我的当前回购中有一个大型模型,我会将该值设置为 https://

直到下次:)
使用 FastAPI 部署 ML 模型——简明指南
如何使用 NLP 模型作为 API——智能的、生产就绪的方式。

FastAPI 是一种更新、更好的方法,可以将您的机器学习模型部署为 REST API,用于 web 应用程序。在他们的官方文档中,他们声称这是启动并运行生产的最快方法,自然,这激起了我的兴趣。
准备好探索这个新的库,我继续前进,用 spacy 做了一个简单的 NLP 模型,并试图围绕它构建一个 API。老实说,它相当简单,非常方便,有无数有用的函数,我在不到一个小时的时间里就准备好了 API——还有测试,也没有 Postman 或 CURL。
炒作够了吧?下面我描述一下你可以用你自己的 ML 模型做同样的事情的步骤。
👇我们走吧!
设置您的环境
设置虚拟环境的两个简单步骤:
- 激活新的 pipenv env:
pipenv shell
2.在其中安装库:
pipenv install spacy spacytextblob pydantic fastapi uvicorn
构建模型
在尝试任何新的库时,我总是更专注于探索库提供的确切功能,而不是背景细节。
出于这个原因,我只用最少的设置用 spacy 构建了一个简单的情绪分析模型,以便快速获得一个模型来进行预测。
这是模型的完整代码,在一个名为 model.py. 的模块中定义
import spacy
from spacytextblob import SpacyTextBlob
from pydantic import BaseModelclass SentimentQueryModel(BaseModel):
text : strclass SentimentModel:
def get_sentiment(self, text):
nlp = spacy.load('en_core_web_sm')
spacy_text_blob = SpacyTextBlob()
nlp.add_pipe(spacy_text_blob)doc = nlp(text)polarity = doc._.sentiment.polarity
subjectivity = doc._.sentiment.subjectivityreturn polarity, subjectivity
是的,真的是这个。如果你像我一样从 FastAPI 开始,我建议你先用这个简单的模型探索这个 API 及其特性,然后再去开发更复杂、更大的模型。
我简单解释一下代码:
- 我们首先导入项目所需的库
- SentimentQueryModel 只是一个模型,包含我们对这个模型的唯一查询——我们将预测其情感的文本。 Pydantic 库有助于确保我们可以快速拥有一个包含模型所需数据的字段,这将是 文本 变量。FastAPI 文档还描述了许多使用这个库声明数据字段的方法。
- sensition model是加载 spacy tokeniser 和 spacytextblob 库并对文本执行情感预测的类
情感分析得分的两个主要组成部分是:
极性 —它是一个位于[-1,1]范围内的浮点数,其中 1 表示完全肯定的陈述,而-1 表示完全否定的陈述。
主观性—主观句一般指个人观点、情感或判断,而客观则指事实信息。主观性分量是一个位于[0,1]范围内的浮点数。
现在,我们已经从模型中返回了两个分数,让我们转到实际构建 API 的部分。
制作 API
首先,我们导入我们的库和模块:
import uvicornfrom fastapi
import FastAPIfrom model
import SentimentModel, SentimentQueryModel
然后,我们实例化 FastAPI 对象和预测类:
app = FastAPI()
model = SentimentModel()
最后,我们创建了一个新函数,通过一个 POST 请求来获取预测:
@app.post('/predict')
def predict(data: SentimentQueryModel):
data = data.dict()
polarity, subjectivity = model.get_sentiment(data['text'])
return { 'polarity': polarity,
'subjectivity': subjectivity
}
确保我们可以从 POST 函数中访问作为 JSON 对象的文本字符串对象。
得到分数后,我们简单地将它们作为另一个 dictionary 对象返回。
现在我们完成了,我们继续运行应用程序,代码如下:
if __name__ == '__main__':
uvicorn.run(app, host='127.0.0.1', port=8000)
我们完事了。这是完整的代码,你的 API 已经可以测试了。
总结→测试您的 API
这是学习使用 FastAPI 最令人兴奋的部分之一。显然,通过它与 SwaggerUI 的集成,你可以直接测试 API,而不需要任何外部工具,如 Postman 或终端命令 CURL 。
导航到地址http://127.0.0.1:8000/docs 以查看您的 API 的运行情况。按下试一试按钮。
它应该是这样的:

继续在字段中输入您的文本。
最后,按下执行。

现在你知道了!这些预测,以及浏览器本身返回的响应代码。是不是很神奇?
请放心,我将来也会广泛地探索这个库!
整个代码也可以在这个要点获得。
然而,如果您已经遵循了这一点,那么您应该已经有了可以开始构建自己的 API 的代码!
感谢阅读!😃
单独学习数据科学可能会很难。跟我来,让我们一起变得有趣。😁
在 Twitter 上与我联系。
这里是我所有数据科学故事的代码库。快乐学习!⭐️
另外,看看我的另一篇文章,你可能会感兴趣:
使用无服务器框架部署 AWS Lamba 功能和层
关于在 AWS Lambda 层上安装依赖项并从通过无服务器框架开发和部署的 AWS Lambda 功能扩展它们的教程。

图一。AWS Lambda、API 网关、无服务器框架|作者图片
无服务器环境已经成为在云实例中部署应用程序的一种破坏性替代方案,无需配置、管理、操作和维护传统服务器。
在本教程中,我们将看到一个关于如何开发、配置、集成和部署 Lambda 函数[ 1 ]的示例,该函数通过无服务器框架[ 3 ]扩展 Lambda 层[ 2 ]的功能。
本博客将分为以下几个部分:
- AWS Lambda 功能&层
- 无服务器框架
- 我们要做什么
- 安装无服务器框架
- 部署 AWS Lambda 层
- 部署 AWS Lambda 功能
如果您已经熟悉 AWS Lambda 和无服务器框架,可以跳过接下来的两节,直接看例子。
让我们喝杯咖啡,享受☕️吧!
AWS Lambda 函数和层
AWS Lambda 是一种计算服务,允许您在不需要配置和管理服务器的情况下运行代码。要使用 AWS Lambda,您只需要打包您的代码以及您将需要的依赖项(作为一个.zip文件或一个docker image)并将它们组织在一个 Lambda 函数中。
在图 2 中,我们看到了 Lambda 函数中元素组织的典型描述。

图二。Lambda 函数|作者图片
如上图所示,每个 Lambda 函数都是一个独立的环境,也就是说,本质上它们不能直接与另一个 Lambda 函数共享或扩展功能。而这也是 Lambda Layer 出现的原因之一。
Lambda Layer 是一个 AWS Lambda 扩展,可以直接使用 Lambda 函数。Lambda 层的目标是包含应用程序、需求、依赖项,甚至可以从 Lambda 函数扩展的自定义运行时组件。
在图 3 中,我们看到了一个 Lambda 层与一对 Lambda 函数集成的描述。

图 3。Lambda 图层和功能|作者图片
正如我们从上图中看到的,Lambda 层的实现有利于通过 Lambda 函数共享和扩展的组件的组织。此外,Lambda 层的使用有助于减少 Lambda 函数的大小,因为不必多次打包依赖项(如图 2 所示)。
然而,在实践中,定义和配置一个或多个 Lambda 功能,以及与一个或多个 Lambda 层集成,可能是一个费力而乏味的过程,因为 AWS Lambda 通常与不同的服务集成,如亚马逊 API Gateway、亚马逊 S3、亚马逊 SQS、亚马逊 SNS 等等。这就是Serverless Framework占据中心舞台的地方。
无服务器框架
无服务器框架是一个工具,它简化了 AWS Lambda 的定义和配置,以及与其他 AWS 服务的集成。简而言之,无服务器框架简化了 AWS Lambda 的开发、集成和部署过程。
Serverless 是一个与云无关的框架,也就是说,它允许通过定义一个YAML文件和使用 CLI 来为不同的云提供商(如 AWS、Azure、Google Cloud、Knative 等)开发和部署服务。
一旦我们明确了 AWS Lambda Function & Layer 之间的关系以及无服务器框架在云服务开发和部署中的相关性,让我们直接进入教程。
别忘了倒满你的咖啡,☕️!
我们要做什么
我们将创建一个 Lambda 函数和一个 Lambda 层。Lambda 层将只包含 numpy 库。lambda 函数将从 Lambda 层扩展 numpy 库,并在其 main 方法中实现它。整个开发和部署过程将通过无服务器框架。
一旦定义了上下文,我们就开始吧!
安装无服务器框架
要安装无服务器,我们首先需要有node.js。要在 macOS 上安装node.js:
$ brew install node
用于在 Ubuntu 上安装node.js:
$ sudo apt install nodejs
$ sudo apt install npm
或者如果你愿意,可以直接去官方节点站点下载。一旦安装了node.js并且启用了npm管理器,我们就开始安装无服务器:
$ npm install -g serverless
如果您对通过npm管理器进行的安装有任何问题,您可以遵循官方的无服务器安装指南来安装独立的二进制文件。
由于我们将在本例中开发并部署到 AWS,您需要添加 AWS 帐户的凭证,如下所示:
$ serverless config credentials --provider aws \
--key <access_key> \
--secret <secret_key>
一旦安装了无服务器并配置了凭证,我们就可以开始有趣的部分了,让我们开始吧!
部署 AWS Lambda 层
首先,让我们用serverless CLI 为我们的 Lambda 层创建一个模板,我们称之为lambda-layer。
(venv) $ serverless create --template aws-python3 \
--name layer-numpy \
--path layer-numpy
上面的命令将生成一个名为lambda-layer的目录,其中包含handler.py和serverless.yml文件。
(venv) $ tree
.
└── layer-numpy
├── handler.py
└── serverless.yml
本质上,handler.py文件包含了将在 AWS Lambda 上运行的代码。serverless.yml文件包含 Lambda 函数或层的定义,以及部署服务所需的所有配置。
神经衰弱,因为在这种情况下我们想要部署一个只包含一个库的 Lambda 层,所以handler.py文件是不必要的。相反,我们需要的文件是requirements.txt,它将包含 Lambda 层将托管的库。
因此,删除handler.py文件并添加requirements.txt文件,我们的目录如下所示:
(venv) $ tree
.
└── layer-numpy
├── requirements.txt
└── serverless.yml
其中requirements.txt文件仅包含对numpy库的引用:
(venv) $ cat requirements.txt
numpy==1.21.0
为了通过serverless部署requirements.txt文件的内容,我们将需要serverless-python-requirements插件,该插件允许serverless访问requirements.txt文件的内容并为部署做准备。
要安装serverless-python-requirements插件,我们键入:
(venv) $ sls plugin install -n serverless-python-requirements
安装插件时,通过添加已安装插件的定义来更新serverless.yml文件。我们的serverless.yml的默认内容如下面的代码片段所示。
代码片段 1。serverless.yml |默认版本
正如我们所看到的,在第 10 行中,我们有一个默认创建的 Lambda 函数的定义,但是对于 Lambda 层部署,我们不需要它。另一方面,在第 14 行中,我们引用了上一步中安装的插件。
我们的serverless.yml文件,在为我们的 Lambda 层的部署做了修改之后,如下所示:
代码片段 2。serverless.yml |准备部署
正如我们所看到的,从第 13 行开始我们的 Lambda 层的定义,它是类型pythonRequirements,其内容将是dockerized。我们的 Lambda 层被称为python-numpy,与python 3.8运行时兼容。
值得一提的是,因为我们启用了需求的dockerization,所以有必要将docker安装在我们的本地机器上,从这里我们将执行部署。
很好,一旦我们有了requirements.txt文件,定制了serverless.yml文件并安装了plugin,我们就可以开始部署了。对于部署,我们仅键入:
(venv) $ sls deploy
就是这样!我们的 Lambda 层应该可以从 AWS 控制台看到,如下图所示:

图二。AWS 控制台中的 Lambda 层“python-numpy”|作者图片
一旦我们的 Lambda 层被部署,就有必要识别相关的ARN,因为它需要引用我们的 Lambda 函数的定义。
太好了,我们已经部署了我们的 Lambda 层。现在让我们看看如何部署扩展 Lambda 层依赖关系的 Lambda 函数。
让我们去吧!
部署 AWS Lambda 函数
首先,我们将为我们的 Lambda 函数生成一个aws-python3模板,我们将其命名为test-function。
(venv) $ serverless create --template aws-python3 \
--name test-function \
--path test-function
上述命令将生成一个名为test-function的目录,其中包含两个文件handler.py和serverless.yml。handler.py文件将包含 AWS Lambda 将运行的代码。serverless.yml文件将包含部署的定义。
(venv) $ tree
.
└── test-function
├── handler.py
└── serverless.yml
首先,让我们修改一下handler.py文件。因为我们假设我们将从上一节创建的 Lambda 层扩展numpy库,所以我们在这里要做的就是导入numpy并声明一些基本功能。最后,我们的handler.py文件应该是这样的:
代码片段 3。handler.py |从 Lambda 层扩展 numpy 库
现在我们将更新serverless.yml文件。基本上,我们将定义 3 个主要的东西:Lambda 函数、Lambda 层扩展和一个 API 网关方法(我们将用它来请求我们的 Lambda 函数)。最后,serverless.yml文件看起来像这样:
代码片段 4。从 Lamba 层扩展 numpy 的 Lambda 函数的定义
在第 12 行我们定义了函数的名称(hello),在第 13 行我们定义了将从handler.py文件中执行的方法。在第 15 行我们定义了 Lambda 层的扩展(这是我们使用前一节中创建的 Lambda 层的ARN的地方),最后在第 19 行我们定义了一个GET方法来请求我们的 Lambda 函数。
就这样,我们准备好部署了!
(venv) $ sls deploy
一旦我们的 Lambda 函数被部署,我们就可以在 AWS 控制台中看到它了。在下图中,我们看到了从控制台部署的 AWS Lambda 函数的特征。

图 3。AWS 控制台中的 Lambda 函数“测试函数”
正如我们所看到的,我们的 Lambda 函数有一个 Lambda 层,它有一个 API 网关作为触发器。
最后,为了测试我们的 Lambda 函数,我们使用如下的serverless CLI:
(venv) $ sls invoke -f hello
{
"statusCode": 200,
"body": "\"Random number: 17\. Numpy version: 1.21.0\""
}
就是这样!我们的 AWS Lambda 函数从 Lambda 层扩展了numpy库,整个开发和部署过程都是通过无服务器框架完成的。
参考
[1] AWS Lambda 功能
[2]AWSλ层
[3] 无服务器框架
使用 Docker、GCP 云运行和 Flask-RESTful 部署容器
提供一个 API 来访问来自 Google BigQuery 的数据

如今,数据科学从业者发现他们越来越依赖云平台,无论是数据存储、云计算还是两者的混合。本文将展示如何利用 GCP 的 Cloud Run 来访问存储在 Google BigQuery 上的数据集,应用快速转换,并通过 Flask-RESTful API 将结果返回给用户。
简介— GCP 云运行、容器与虚拟机
Cloud Run 是一项服务,它允许你构建和部署可以通过 HTTP 请求访问的容器。云运行是可扩展的,并且抽象化了基础架构管理,因此您可以快速启动和运行。
你问的容器是什么?考虑容器的一个简单方法是,它们类似于虚拟机(VM ),但是在规模和范围上要小得多。
有了虚拟机,你通常会有一个虚拟版本的整个操作系统在运行(比如 Windows PC 通过类似 VirtualBox 的东西运行 Linux 虚拟机)。)这种 Linux 虚拟机通常有一个图形用户界面、一个网络浏览器、文字处理软件、ide 和与之配套的一整套软件。
然而,有了容器,你可以拥有执行你想要的任务所需的最少数量的软件,使它们紧凑高效,易于创建、销毁和动态部署。例如,本文中的容器只安装了 Python 3.8,没有其他内容。
云运行非常适合部署无状态容器。为了更好地理解有状态容器和无状态容器,请看一下本文。
入门指南
我们将在 BigQuery 上查看的公共数据集是 big query-public-data . USA _ names . USA _ 1910 _ 2013 数据集:

查询以获得名字的总数。
开始之前,您需要创建:
- 一个关于 GCP 的项目,
- 一个服务账户和一个服务账户密钥。
关于如何快速做到这一点的指南,请查看 BigQuery API 文档。一旦创建了服务帐户,就可以创建并下载一个. json 服务帐户密钥,该密钥用于在尝试通过 BQ API 访问 BigQuery 数据时对您进行身份验证。
第一步:谷歌云外壳
进入谷歌云外壳,点击‘打开编辑器’。您应该会看到类似这样的内容:

云壳编辑器——注意左下角的“云代码”。
接下来点击左下角的“云代码”:

这将弹出一个选项菜单。选择“新应用程序”:

然后从以下选项中选择'云运行应用 ' → ' Python (Flask):云运行'。这为您提供了用于云运行的基于 Flask 的示例“Hello World”应用程序,我们将在该应用程序上构建以访问我们的 BigQuery 数据集。您现在应该有这样的东西:

Hello World 示例应用程序
接下来的步骤将是更改提供的 app.py 和 Dockerfile,以及添加一些我们自己的代码来访问 BigQuery。
步骤 2:用 Docker 构建容器
第一步是稍微编辑现有的 docker 文件,以指定如何创建我们的容器。将现有的 Dockerfile 代码替换为:
# Python image to use.FROM python:3.8 # Set the working directory to /appWORKDIR /app# copy the requirements file used for dependenciesCOPY requirements.txt .# Install any needed packages specified in requirements.txtRUN pip install --trusted-host pypi.python.org -r requirements.txt**RUN pip install flask-restful****RUN pip install --upgrade google-cloud-bigquery****RUN pip install --upgrade gcloud****RUN pip install pandas**# Copy the rest of the working directory contents into the container at /appCOPY . .# Run app.py when the container launchesENTRYPOINT ["python", "app.py"]
该 Dockerfile 文件将:
- 从官方 Python 3.8 映像构建一个容器
- 设置容器的工作目录
- 在现有的 requirements.txt 文件中安装软件包
- 安装必要的额外软件包(如果愿意,这些软件包可以添加到现有的 requirements.txt 文件中)
- 将工作目录中的其他现有文件复制到容器的工作目录中(包括我们的服务帐户密钥)
- 容器启动时运行 app.py
步骤 3:用 app.py 启动 Flask 应用程序
将现有 app.py 中的代码替换为:
import os
import requests
import bqfrom flask import Flask
from flask_restful import Resource, Apiapp = Flask(__name__)
api = Api(app)class QueryData(Resource):
def get(self):
return bq.run_()api.add_resource(QueryData, '/')if __name__ == '__main__':
server_port = os.environ.get('PORT', '8080')
app.run(debug=True, port=server_port, host='0.0.0.0')
Flask-RESTful 使用 Resource 对象来轻松定义 HTTP 方法(更多信息参见文档)。上面我们定义了一个资源来获取 bq.py Python 脚本的结果,该脚本查询、排序并返回数据。(可以创建许多资源,并使用。add_resource()方法。)
步骤 4: BigQuery API Python 代码
以下是将访问 big query-data . USA _ names . USA _ 1910 _ 2013 数据集的代码文件:
bq.py
def run_():
import os
import pandas as pd from google.cloud import bigquery
from google.oauth2 import service_account key_path = "./your_key.json" credentials = service_account.Credentials.from_service_account_file(
key_path, scopes=["[https://www.googleapis.com/auth/cloud-platform](https://www.googleapis.com/auth/cloud-platform)"],
) client = bigquery.Client(credentials=credentials) query = """
SELECT name, SUM(number) as total_people
FROM `bigquery-public-data.usa_names.usa_1910_2013`
WHERE state = 'TX'
GROUP BY name, state
ORDER BY total_people DESC
LIMIT 20
"""
query_job = client.query(query)
counts = []
names = []
for row in query_job:
names.append(row["name"])
counts.append(row["total_people"])
# put names and name counts in a dataframe and sort #alphabetically, to simulate operating on data with a model
results = {'Names': names, 'Name Counts': counts}
df = pd.DataFrame.from_dict(results) # convert to DataFrame
df = df.sort_values(by=['Names']) # sort alphabetically
df = df.to_dict(orient='list') # convert to dictionary format
return df
将此代码添加到与 app.py 和 Dockerfile 位于同一目录的新文件名 bq.py 中:

bq.py
bq . py 分解:
这一部分将允许我们验证和访问 BigQuery 来获取我们的数据:
from google.cloud import bigquery
from google.oauth2 import service_account**key_path = "./your_key.json"**credentials = service_account.Credentials.from_service_account_file(
key_path, scopes=["[https://www.googleapis.com/auth/cloud-platform](https://www.googleapis.com/auth/cloud-platform)"],
)client = bigquery.Client(credentials=credentials)
注意 key_path = "。/your_key.json "必须更改为您先前下载的 json 服务帐户密钥的名称。要将下载的密钥从计算机的下载文件夹导入到云外壳编辑器,只需将文件拖放到浏览器窗口中:

云壳项目中的服务帐户密钥。
下一部分包含对我们所需数据的查询:
query = """
SELECT name, SUM(number) as total_people
FROM `bigquery-public-data.usa_names.usa_1910_2013`
WHERE state = 'TX'
GROUP BY name, state
ORDER BY total_people DESC
LIMIT 20
"""
query_job = client.query(query)
剩下的代码只是对两个数据列进行排序,根据“Name”列的字母顺序对列进行排序:
counts = []
names = []
for row in query_job:
names.append(row["name"])
counts.append(row["total_people"])
# put names and name counts in a dataframe and sort #alphabetically, to simulate operating on data with a model
results = {'Names': names, 'Name Counts': counts}
df = pd.DataFrame.from_dict(results) # convert to DataFrame
df = df.sort_values(by=['Names']) # sort alphabetically
df = df.to_dict(orient='list') # convert to dictionary format
return df
数据必须以 json 兼容的格式返回,以便用于 Flask-RESTful,这就是我们以字典格式返回数据的原因。
最后一步—使用云运行部署容器!
最后,我们可以将服务部署到 web 上。使用 Cloud Run 进行部署将生成一个链接,允许访问我们的数据转换结果。
再次选择云壳编辑器左下角的“云代码”。这次单击“部署到云运行”:

按照步骤创建一个服务,选择一个区域,允许未经身份验证的调用,以及一个构建环境(本地或云构建)。准备就绪后,单击部署!您可以单击“显示详细日志”来查看正在进行的构建和部署步骤。
容器构建完成后,单击提供的链接:

这个链接为我们的最终结果打开了一个新的选项卡——应用了排序的查询 BQ 数据!

这两个数据列已经按照“名称”列的字母顺序进行了排序!虽然这是一个简单的操作,但是存在更复杂的工作流的可能性。您可以应用经过训练的机器学习模型进行预测,并通过 API 返回结果,而不是对数据进行排序。给页面添加一个更好的设计也会有助于可读性。
顺便提一下,将服务帐户密钥存放在存储中并不被认为是最佳做法,还有其他可供 GCP 使用的身份验证方法。此外,关注 GCP 产品的计费,公共 BQ 数据集可以免费查询 1TB,但如果您不长期使用它们,则值得停用项目。
我希望这篇文章对你有用。如果你喜欢这个故事,请考虑在媒体上关注我。你可以在 https://mark-garvey.com/的上找到更多
在 LinkedIn 上找到我:https://www.linkedin.com/in/mark-garvey/
在 AWS 弹性豆茎上部署 Docker 集装箱 ML 模型
在 AWS 上为您的模型提供服务的银碟指南

基拉·奥德·海德在 Unsplash 拍摄的照片
介绍
iPhone 照片库、亚马逊购物篮和网飞主页有什么共同点?
以这样或那样的方式,这些应用程序中的每一个都与机器学习模型进行交互,以改善用户体验,并更好地服务于最终用户。
毫无疑问,机器学习已经从根本上改变了我们今天与技术的互动方式,并将在未来几年继续如此。
我进入数据科学世界的旅程告诉我,训练一个 ML 模型实际上只是任何 ML 解决方案的一部分。大多数数据爱好者都有能力训练一个模型,但部署该模型以使其有用则是一个完全不同的挑战。
在本指南结束时,我将帮助你回答我无数次问自己的问题:
我如何部署我的机器学习模型?
我如何为我的模特服务?
我将向您展示如何在 Docker 容器内在 AWS 上部署 ML 模型,从而帮助您迈出进入不断增长的机器学习工程领域的第一步。以下是我们将在 AWS Elastic Beanstalk 上部署模型的关键步骤。
- 训练随机森林分类器。
- 用 API 端点构建一个简单的 Flask 应用程序。
- 使用 Docker 封装我们的应用程序。
- 在 AWS elastic beanstalk 上部署容器化的应用程序。
- 将我们的模型作为 API。
为什么是 AWS 弹性豆茎?
AWS Elastic Beanstalk 是您可以部署模型的许多方式之一,了解没有一种尺寸适合所有解决方案是很重要的。
尽管如此,在云中部署模型时,AWS Elastic Beanstalk 提供了几个优势。
首先,Elastic Beanstalk 通过消除与管理 web 服务底层基础设施相关的复杂性,使开发人员能够快速、轻松地在 web 中部署应用程序。在 Elastic Beanstalk 中,AWS 服务(如 EC2 实例、弹性负载平衡和系统健康监控)的配置和供应是自动化的。这让开发者可以专心开发。其次,Elastic Beanstalk 广泛支持许多语言,如 Java。NET、PHP、Node.js、Python、Ruby、Go 以及最重要的 Docker 容器。
和任何技术一样,总有缺点。需要记住的一点是,您的应用程序将全天候运行。根据项目要求,应用程序的 24/7 实施可能是一项优势,也可能是一项巨大的成本负担。与 AWS Lambdas 不同,在 Elastic Beanstalk 上没有“按需”实现应用程序的选项。此外,Elastic Beanstalk 上缺少日志文件会使失败的部署难以调试,因此,开发会更加困难。
还在吗?那我们开始吧。
内容
- 先决条件
- 模特培训
- 构建烧瓶 API
- 码头集装箱化
- 测试烧瓶应用程序
- 设置 AWS CLI 凭据
- 在 AWS 弹性豆茎上展开
- 将我们的模型作为 API
- AWS 资源终止
- 结束语
先决条件
在继续前进之前,您需要满足一些关键的先决条件。我们将使用相当多的工具,所以请花一些时间安装先决条件。
- 你需要一个 AWS 账户。您可以注册免费层,该层将在注册时自动应用。
- 导航命令行的一些技术知识。
- AWS 弹性豆茎 CLI
- 码头工人
- Python 3.9.7
- VS 代码或任何您喜欢的 Python IDE。
- 诗歌——Python 包管理工具(阅读我的上一篇关于诗歌入门的文章)
- Python 库:scikit-learn、numpy、requests、pandas、flask、joblib 和 json。您可以使用 poem 安装我当前的 python 版本,或者将
requirements.txt文件包含在 Git 存储库中。 - 这个项目使用的所有代码都可以在 GitHub 链接这里找到。
AWS_ElasticBeanstalk_deploy
├── Dockerfile
├── README.md
├── documentation.ipynb
├── models
│ └── rf_clf.joblib
├── poetry.lock
├── pyproject.toml
├── requirements.txt
└── scripts
├── eb_predict.py
├── flask_api.py
├── predict.py
└── train_iris_rf.py
太好了!注册 AWS 并安装所有先决条件后,您可以继续本指南的设置部分。
构建一个简单的 Flask API
现在我们都设置好了,让我们开始编码。总的来说,下面是我们将在 AWS 上部署模型的步骤。
- 训练随机森林分类器。
- 用暴露的 API 端点构建一个简单的 Flask 应用程序。
- 使用 Docker 容器封装我们的应用程序。
- 在 AWS Elastic Beanstalk 上部署容器化的应用程序。
- 将我们的模型作为 API。
1。模特培训
让我们用 Iris 数据集训练一个非常简单的 RandomForest 分类器,并用 Flask API 为它服务。
我们将使用 sklearn python 库来加载 Iris 数据集并训练我们的模型。
模型将用joblib序列化并保存在模型文件夹中,该文件夹可在 Flask 应用程序中调用。
2.构建一个 Flask API
接下来,让我们构建一个带有/predict端点的 Flask API 应用程序。
如下面的主代码块所示,/predict端点将执行predict_endpoint()函数,该函数调用随机森林模型并返回预测作为响应。更详细地说,predict_endpoint()函数将一个json对象解析成一个numpy数组,进行预测,并将响应作为json返回。
@app.route('/predict', methods=['POST'])
def predict_endpoint():
test_data = request.get_json()
test_data = np.array(test_data)
predictions = model.predict(test_data)
response = json.dumps(predictions.tolist())
return Response(response,
status=200,
mimetype="application/json")
在 Flask app 初始化之前,执行if __name__ == ‘__main__':块中的代码。因此,加载序列化模型的代码将从这里的model = joblib.load('rf_clf.joblib')开始。
if __name__ == '__main__':
model = joblib.load('rf_clf.joblib')
app.run(host='0.0.0.0', port=8080)
3.码头集装箱化
我们将使用 Docker 封装 Flask 应用程序。使用 Docker 有很多好处。一个是跨机器维护构建环境的一致性。
这种一致性允许您在本地机器上测试您的 containerised 化应用程序,并在 Docker 运行的任何系统上部署它,因为您知道它将完全像在本地测试时那样执行。
我还将在 Docker 中使用诗歌来锁定包的依赖关系,以确保相同的构建在机器间得到镜像。我不会对 Docker 中的命令进行过多的详细描述,但一般来说,这些都是Dockerfile中列出的步骤。
- 从官方 Docker 映像库加载 Python:3.9。
- 安装诗歌(1.1.11)。
- 设置工作目录。
- 安装
poetry.lock和pyproject.toml中定义的必要依赖项。 - 将必要的 Python 文件复制到 Docker 映像中。
- 暴露端口 8080。
- 设置 Docker 映像初始化时要执行的入口点或文件。
注意: 要在 Docker 中实现一个工作缓存层,应该在安装完诗歌之后,添加任何其他文件之前插入 *COPY poetry.lock pyproject.toml /deploy/* 。这确保了只有在两次构建之间发生更改时才重新安装依赖项。
4.测试烧瓶应用程序
让我们构建应用程序的 docker 映像,并在部署之前在本地测试它。请注意此处链接的当前项目的文件夹结构。Dockerfile需要位于构建过程的根文件夹中。
AWS_ElasticBeanstalk_deploy
├── Dockerfile
├── README.md
├── documentation.ipynb
├── models
│ └── rf_clf.joblib
├── poetry.lock
├── pyproject.toml
├── requirements.txt
└── scripts
├── eb_predict.py
├── flask_api.py
├── predict.py
└── train_iris_rf.py
在“终端”中,导航到您的文件夹并使用描述性标签构建 docker 图像:
docker build -t flask-api:latest .
然后在分离模式-d下运行 docker 镜像,用-p option暴露端口8080。
docker run -d -p 8080:8080 flask_api:latest
Docker 容器现在将在http://localhost:8080/predict上运行,我们可以通过运行predict.py脚本在本地调用 API 来测试。

predict.py 脚本的执行调用 localhost:8080/predict API 端点
要查看正在运行的容器列表:
docker ps
要停止容器:
docker stop <NAME_OF_CONTAINER>
5.在 AWS ElasticBeanstalk 上部署
一旦应用程序经过 Docker 测试,在 AWS 上部署就相对简单了,我们知道它运行起来没有错误。
首先,我们必须在 AWS 上创建一个新用户,并在从我们的机器部署到 AWS 之前分配正确的权限。让我们一步一步来。
a) 登录 AWS 控制台。

AWS 登录控制台
b) 在你的控制台中,选择所有服务然后是安全,身份&合规然后是 IAM。
c) 在左侧选项卡上,选择用户。如果您没有看到左侧选项卡,请单击左上角 AWS 徽标正下方的三个后栏。
d) 选择添加用户并给用户一个用户名。确保选择访问键—编程访问复选框,然后点击下一步

e) 让我们给这个用户 AWS Elastic Beanstalk 资源的管理员权限。将策略AdministratorAccess-AWSElasticBeanstalk附加到权限列表。

f) 跳过添加标签部分,在查看部分创建用户

g) 创建成功后,将访问密钥 ID 和秘密访问密钥复制到记事本上或下载.csv进行安全保存。我们需要这些键来完成 AWS Elastic Beanstalk CLI 的设置。
在终端中,导航到项目目录,并使用以下命令初始化 Elastic Beanstalk CLI:
eb init
根据提示输入您的访问密钥 id 和秘密访问密钥。这些是我在具体项目中使用的设置。根据您的位置和延迟,地区会有所不同。
- 默认区域:16
- 选择要使用的应用程序:3[创建新应用程序]
- 应用名称:flask-api
- 码头工人:Y
- 选择平台分支:1 (Docker 运行在 64 位 Amazon Linux 2 上)
- 代码提交:n
- 宋承宪:n
注意 :您会注意到 AWS Elastic Beanstalk CLI 已经创建了一个 *.elasticbeanstalk* 文件夹,其中包含一个详细描述部署配置的 *config.yml* 。
初始化后,使用以下命令在 AWS Elastic Beanstalk 上创建一个应用程序:
eb create
按照屏幕上出现的提示操作。对于这个项目,所有选项的默认值就足够了。
Elastic Beanstalk 将自动处理帮助您部署项目所需的所有基础设施部署,因此您可以专注于开发代码库。它将自动创建所有必要的资源,例如启动 EC2 实例、设置负载平衡器、自动扩展组和路由以服务于您的应用程序。

成功部署后,Elastic Beanstalk 将返回一个应用程序可用的地址。在本例中,该应用程序可在http://flask-api-dev.eu-west-2.elasticbeanstalk.com获得。
6.将我们的模型作为 API
现在我们的应用程序部署在云中,我们可以像以前在本地测试应用程序时一样访问它。这次唯一的主要区别是我们将访问 API 的地址。
由于该应用程序是在 Docker 容器中测试的,我们可以预期我们之前的代码会在一些小的调整后工作。用您的应用程序的网址替换网址[http://localhost:8080/predict](http://localhost:8080/predict)。在这种情况下,我将用[http://flask-api-dev.eu-west-2.elasticbeanstalk.com](http://flask-api-dev.eu-west-2.elasticbeanstalk.com)代替它。

EB _ preview . py 脚本的执行调用预测 API 端点
如果一切正常,你应该会得到一个回复,上面有一个预测列表和一个准确率分数。
恭喜🎉🎉🎉您已经成功地在云中部署了一个机器学习模型,您可以使用 API 在任何机器上访问该模型。
AWS 资源终止
在项目结束时终止资源是很重要的。查看所有当前运行资源的最简单方法之一是登录您的 AWS 控制台。
在服务下选择弹力豆茎然后选择环境。您可以在这里找到目前部署在 AWS 弹性 Benstalk 上的所有活动环境。

要终止,请选择您的环境,并在操作选项卡下选择 终止环境。您需要通过键入环境名称进行确认。

删除应用程序的过程与您希望删除应用程序的过程相似。
结束语
您如何部署您的应用程序将对开发构建周期和与维护它相关的成本有许多影响。为了最好地服务于您的模型,理解您的项目和最终用户的需求总是很重要的。AWS 弹性豆茎是众多为模型提供服务的方式之一,理解没有一种适合所有尺寸的解决方案很重要。
它是关于为正确的工作使用正确的工具。
我们在本指南中完成了一些工作。我们首先用 Iris 数据训练了一个 RandomForest 分类器,我们把它打包在一个 flashboard 应用程序中作为一个 API。接下来,我们将 flashboard 应用程序包含在 Docker 容器中,并在部署前对其进行本地测试。最后,我们在 AWS 弹性豆茎上部署了容器化的应用程序,作为一个可以通过 URL 访问的 API。
需要注意的是,这里所采取的在弹性豆茎上部署的步骤适用于任何 Docker 容器 web 应用程序。
如果你已经读完了这篇指南,我希望你已经学到了一些新的东西。更多数据科学相关内容,请务必在 Medium 和 Twitter ( @iLloydHamilton )上关注我。
注意这个空间。
使用 Argo CD 部署 Kubeflow 1.3 RC
使用 GitOps 简化和自动化 Kubeflow 的部署
Kubeflow 是一个流行的开源机器学习平台,运行在 Kubernetes 上。Kubeflow 简化了许多有价值的 ML 工作流,即它允许用户轻松部署开发环境、使用 Kubeflow 管道的可扩展 ML 工作流、使用 Katib 的自动化超参数调整和神经架构搜索、团队内的轻松协作等等。如此多的功能也带来了复杂性。完整的 Kubeflow 部署包含许多服务和依赖项,这使得用户很难使用传统的 kfctl CLI 工具和 KfDef YAML 文件来定制、管理和安装 Kubeflow。出于这个原因,即将发布的 Kubeflow 1.3 版本已经停止使用 kfctl ,取而代之的是使用标准 Kustomize ,使得使用 GitOps 工具如 Argo CD 部署 Kubeflow 变得更加容易。
Argo CD 是“一个用于 Kubernetes 的声明式 GitOps 连续交付工具”。 Argo 项目已经与 Kubeflow 密切相关,因为 Kubeflow 管道在幕后使用 Argo 工作流,使得 Argo CD 成为部署 Kubeflow 的自然选择。GitOps 的一个简单描述是使用 Git 存储库作为部署所需状态的真实来源。然后,一个持续的交付工具,如 Argo CD 监控 Git 存储库的变更和更新部署,如果需要的话。
遵循该指南所需的代码和清单可以在 https://github.com/argoflow/argoflow 找到。部署应该与本地和云中的任何 Kubernetes 集群兼容。注意——虽然包含了一些额外的清单以使内部部署更加容易,例如metalllb和 Rook Ceph ,但这些清单在默认情况下是禁用的。
准备
第一步是派生出 ArgoFlow 存储库并在本地克隆它。接下来,您需要安装 yq version 4 来使用允许您轻松设置 fork 的脚本和 Kustomize v4.0.5 来安装 Argo CD 和提供的清单。当然,访问 Kubernetes 集群也是一个要求。这可以通过虚拟机或云中的工具在本地完成,如 minikube 、 kind 或 MicroK8s 。但是,设置 Kubernetes 集群超出了本文的范围。
安装 Argo CD
为了简单起见,Argo CD 将与 Kubeflow 安装在同一个集群上。高可用性模式下的 Argo CD 2.0 的候选版本是因为我喜欢与软件保持同步。对 Argo CD 配置做了一些优化,包括 Kustomize 的 v4.0.5,这是撰写本文时的最新版本。
在本地克隆了 ArgoFlow 的分支后,您可以在 ArgoFlow 文件夹中执行以下命令来安装 Argo CD:
kustomize build argocd/ | kubectl apply -f -
接下来在本地安装 Argo CD CLI 工具。要访问 Argo CD UI,您可以使用负载平衡器公开其服务,使用kubectl和端口转发进入或连接到它。Argo CD 入门页面有更多关于如何操作的说明。
接下来,通过执行以下命令来获取用户admin的默认密码:
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath=”{.data.password}” | base64 -d
现在,您可以使用 Argo CD CLI 工具登录,并按如下方式更改默认密码:
argocd login <ARGOCD_SERVER> # e.g. localhost:8080 or argocd.example.com
argocd account update-password
你现在应该可以用你的新密码登录 Argo CD 用户界面了。

阿尔戈光盘网络界面
定制 Kubeflow 部署
清单已经设置了一些默认值来帮助新用户入门,但是大多数人都应该更改。例如,用户应该更改默认用户的密码,并在 cert-manager 中设置一个颁发者,以便为 Istio 入口网关创建正确的证书。许多人可能需要更改的另一件事是入口网关服务,默认情况下它设置为使用负载平衡器。为了保持这篇文章的清晰和中肯,我不会在这里详细讨论如何更改这些设置,因为这会涉及到很多文件链接。 ArgoFlow 存储库中的自述文件提供了更改部署的这些方面的说明。
准备部署 Kubeflow
除了不同 Kubeflow 组件的 Kustomize 清单, ArgoFlow 库还包含每个 Kubeflow 组件的 Argo CD 应用程序规范。为了使人们更容易选择和部署他们想要的组件,位于根存储库中的一个kustomization.yaml文件用于定义应该部署哪些 Argo CD 应用程序。反过来,存储库根目录中的kubeflow.yaml文件是前面提到的kustomization.yaml文件的 Argo CD 应用程序。简单来说就是一个 Argo CD 应用,部署其他 Argo CD 应用。
接下来,需要编辑 Argo CD 应用程序规范,以便它们指向您的 ArgoFlow 存储库的分支。包含一个脚本来简化这一过程。在存储库的根目录中,只需运行下面的命令来更新所有的应用程序规范,使其指向存储库的分支:
./setup_repo.sh <your_repo_fork_url>
奖励:用文件浏览器扩展 Volumes Web 应用
对于许多人来说,一个大问题是如何容易地将数据上传到安装为笔记本服务器的工作区卷的 PVC,或者从安装为笔记本服务器的工作区卷的 PVC 下载数据。为了使这更容易,创建了一个简单的 PVCViewer 控制器(tensorboard-controller 的稍微修改版本)。PVC 查看器将与 ReadWriteOnce PVCs 一起工作,即使它们安装在活动的笔记本服务器上。这个特性在 1.3 版本中还没有准备好,因此我在这里只是把它作为一个实验性的特性来记录,因为我相信很多人都想拥有这个功能。它(还)不是上游库伯流的一部分,将来可能会改变。

运行中的 PVC 查看器演示
如果您想要部署这个特性,您需要注释掉根kustomization.yaml文件中的argocd-applications/volumes-web-app.yaml条目,并取消注释以下两行:
- argocd-applications/experimental-pvcviewer-controller.yaml- argocd-applications/experimental-volumes-web-app.yaml
一旦您完成了对部署的定制,只需将您的更改提交并推送到您的 ArgoFlow 存储库的分支中。
部署 Kubeflow
在提交和推送您的更改后,您可以通过执行以下命令来安装 Kubeflow:
kubectl apply -f kubeflow.yaml
也可以手动安装组件。例如:
kubectl apply -f argocd-applications/kubeflow-roles-namespaces.yaml
您现在应该开始看到应用程序出现在 Argo CD UI 中,如果一切顺利,它们应该是“健康的”和“同步的”。由于 Kubeflow 部署中的大量资源以及一些先有鸡还是先有蛋的场景,一些应用程序可能会保持“不同步”一段时间。

Kubeflow 组件在 Argo CD 中的应用
通过点击一个应用程序,Argo CD 将向您展示由该应用程序创建的所有资源的概述。

Argo CD 中 Jupyter Web 应用程序资源概述
通过点击任何资源,Argo CD 将向您显示有用的信息,例如当前部署的 YAML 与 Git 库或 pod 日志中声明的内容之间的差异。
更新您的部署
要更新或更改您的部署,只需将您的更改提交并推送到您的存储库,Argo CD 将自动检测并更改您的 Kubernetes 集群中的部署。
结论
由于即将发布的 Kubeflow 1.3 使用标准 Kustomize,这使得使用 Argo CD 等工具来管理其部署变得更加容易。此外,由于 Kubeflow 的大小和复杂性,使用 GitOps 和 Argo CD 的声明性方法应该使用户更容易定制和部署适合他们需求的 Kubeflow。
从头开始将 Kubeflow 部署到裸机 GPU 集群
我在具有多个 GPU 的物理服务器上部署 Google 的 Kubernetes ML 工具包的经验

攻击库伯弗洛。图片来自 Anastasia Markovtseva,CC-BY-SA 4.0。
五金器具
我有 3 个标准的超微塔式服务器,每个都有 256GB 内存、一个固态硬盘、5 个硬盘和 4 个 GPU。以太网将它们连接到可以访问互联网的“控制器”戴尔服务器,并应该控制 SSH 到群集的连接。我用团队成员的家乡城市来命名这些塔;我发现这个方案比分配随机的形容词(“食蚁兽”、“无畏者”)、前缀索引(“数据科学 1”、“数据科学 2”)或希腊字母(“阿尔法”、“贝塔”)更有趣,我在以前工作的地方已经见过太多次了。当有人问你在哪个服务器上训练网络时,你可以回答,“我在马德里”或“我在莫斯科”。

集群网络方案。图片作者。
安装 Linux
我在每台机器上都安装了 Ubuntu 20.04。这一步已经存在一定的困难:没有配置 PXE(通过网络引导),安装操作系统的唯一文明方式是从闪存盘引导,而戴尔服务器不支持它。我的意思是,有 USB 端口,当然,但他们的 UEFI 没有看到一个可引导的设备。我不得不在 2020 年刻录一张 DVD,我仍然无法相信。在超微型电脑上安装 Ubuntu 也不是一件容易的事。由于 UEFI 出了问题,GRUB 无法安装,所以我不得不在安装过程中进入内核外壳并即时修复。
如果我知道计算实例运行在有白名单用户的可信网络中,我总是禁用计算实例上的内核安全补丁。附带的性能损失比强加的风险要昂贵得多。所以我在 GPU 塔上编辑了/etc/default/grub如下:
GRUB_CMDLINE_LINUX_DEFAULT="pti=off spectre_v2=off l1tf=off nospec_store_bypass_disable no_stf_barrier"
GRUB 是一个开源的 bootloader,可以将 Linux 内核作为常规的 ELF 应用来执行。
/etc/default/grub中的命令行标志是真实的argv。
正如我在以前的一篇博客文章中提到的,如果您计划点对点 GPU 通信,例如 Tensorflow 或 PyTorch 中的多 GPU 模型训练,禁用 IOMMU 至关重要。这不是什么秘密,经常出现在他们的 GitHub 问题中。
GRUB_CMDLINE_LINUX_DEFAULT="intel_iommu=off rcutree.rcu_idle_gp_delay=1"
IOMMU 代表输入输出内存管理单元。在我们的上下文中,IOMMU 与虚拟化直接内存访问 (DMA)相关。英特尔 CPU 以名为英特尔 VT-d 的“面向定向 I/O 的虚拟化技术”来实现它。
我使用 udhcpd 在控制器中设置了内部网的静态 DHCP 租约,使用apt很容易安装。这是我的/etc/udhcpd.conf:
start 192.168.2.2
end 192.168.2.16
interface eno2 # eno1 interface connects to the internet
max_leases 32
static_lease 0C:C4:7A:80:09:1F 192.168.2.2
static_lease 0C:C4:7A:8A:18:87 192.168.2.12
static_lease AC:1F:6B:20:F6:F9 192.168.2.3
static_lease 0C:C4:7A:ED:F1:76 192.168.2.13
static_lease AC:1F:6B:24:1E:FF 192.168.2.4
static_lease AC:1F:6B:2F:98:52 192.168.2.14
您可能会注意到 3 台机器有 6 条记录。以.1x结尾的是指IPMI——每个塔中的独立计算单元,用于远程管理状态,例如,打开电源或查看屏幕。IPMI 不需要特殊的设置:插入以太网电缆,访问 HTTPS 的网络接口。

超微的 IPMI 截图。图片作者。
我选择了一个基于 Ansible 的传统配置管理解决方案来管理机器。这没有 Terraform 的定制 PXE 那么花哨,但嘿,你不需要私人直升机去市区度假。Ansible 的核心就像在预定义的主机上自动执行 SSH 命令一样简单。我用 GPU 塔名称填充了/etc/ansible/hosts:
[cluster]
moscow
madrid
campos
我用cluster.yml来描述配置,并用ansible-playbook -K cluster.yml来应用它。下面是一个示例,用于确保我的用户存在,并且可以在 GitHub 上使用我的带有指纹的私钥进行 SSH:
---
- hosts: cluster
become: yes
become_user: root
tasks:
- name: Group "docker"
group:
name: docker
- name: User "vadim"
user:
name: vadim
shell: /bin/bash
groups: adm,sudo,cdrom,docker,dip,plugdev,lxd
append: yes
uid: 1000
create_home: yes
- name: vadim's SSH keys
authorized_key:
user: vadim
state: present
key: [https://github.com/vmarkovtsev.keys](https://github.com/vmarkovtsev.keys)
当然,我需要在机器上运行一个 SSH 服务器。Ubuntu 安装程序方便地允许在第一次启动前设置一个 SSH 服务器。
Ansible 也是一个很好的增量解决方案。您不必在第 0 天强制配置所有内容。反而可以在有时间的时候和配置债打一场。
安装 Kubernetes
我决定试试 k0s 。有几个优点吸引了我:
- 轻松自举。下载一个没有外部依赖的大二进制,复制到每个节点,运行
k0s install,就大功告成了。 - 使用相同的
k0s命令轻松进行初始配置。 - 一组合理的内置电池,例如, Calico 网络和 etcd 集群状态数据库。
- 香草 Kubernetes,这样我就不用学习 DevOps 技术的另一个雪球。
Kubernetes 是运行在一台或多台物理机器上的服务联盟。有两种操作模式:控制器和工人。管制员管理工人。两者都可以水平扩展,即增加实例的数量。如果用户不关心高可用性和故障转移,只产生一个控制器就足够了。
官方文档目前缺乏细节,所以让我一步步地走完部署 k0s 的过程。在控制器上运行以下命令:
sudo k0s install controller
该命令将创建/etc/systemd/system/k0scontroller.service,它将 k0s 控制器实例打包成一个 systemd 服务,您可以方便地sudo systemctl start|stop|restart。因此我们开始它:
sudo systemctl start k0scontroller.service
下一个缺失的元素是kubectl——人人都使用的 Kubernetes 命令行命令。我更喜欢用snap安装:
sudo snap install kubectl --classic
k0s 为 kubectl 提供了一个管理配置,又名KUBECONFIG,我们将使用它来创建普通用户:
sudo cp /var/lib/k0s/pki/admin.conf .
sudo chown $(whoami) admin.conf
export KUBECONFIG=$(pwd)/admin.conf
export clusterUser=$(whoami)
kubectl create clusterrolebinding $clusterUser-admin-binding --clusterrole=admin --user=$clusterUser
export KUBECONFIG=
mkdir -p ~/.kube
sudo k0s kubeconfig create --groups "system:masters" $clusterUser > ~/.kube/config
最后,我们必须将工作者加入集群的控制器。文档钉住了那个程序,我就不重复了。
在成功完成上述设置后,我发现了两个恼人的问题。
kubectl logs和kubectl exec超时有 80%几率。错误信息总是一样的:error dialing backend: dial tcp …: connection timed out。kube-system名称空间中的系统盒无法引导,状态为“ImagePullBackOff”。kubectl describe pod表示 DNS 解析超时,例如 registry-1 . Docker . io—Docker 容器注册表。然而,当我用kubectl get pod -n kube-system <whatever> -o yaml | kubectl replace --force -f -手动重启 pods 时,有 50%的时间图像都是成功的。
kubectl logs直接连接到 Kubernetes worker 并请求指定 pod 的日志。如果 pod 包含多个集装箱,您必须指定要寻址的集装箱。该命令的工作方式类似于docker logs。
kubectl exec直接连接到 Kubernetes 工作器,并在指定的 pod 中执行任意命令。同样,您必须指定 pod 运行多个容器。该命令的工作方式类似于docker exec。
那些问题在普通的工作机器上没有重现。Kubernetes 官方文档中的“调试 DNS 解析”中的建议没有帮助。花了几个小时调试之后,我发现:
kubectl logs和kubectl exec超时,因为 kubelet-s 监听了错误的网络接口。每个 GPU 塔有两个物理以太网插座,网络在eno2连接,而eno1保持未配置。Kubernetes 无法找出主要接口和 Calico 的路由中断。我仍然不完全理解为什么这些命令有时会起作用。我通过执行以下命令解决了这个问题:
kubectl set env daemonset/calico-node -n kube-system IP_AUTODETECTION_METHOD=interface=eno2
2.在控制器上运行(黑客的)DNS 服务器是个坏主意。虽然我没有提到,但我最初使用以下服务配置将 DNS 转发到 systemd-resolved :
[Unit]
Description = Forward DNS lookups from 192.168.2.0/24 to 127.0.0.53
After = network.target[Service]
ExecStart = /usr/bin/socat UDP-LISTEN:53,fork,reuseaddr,bind=192.168.2.1 UDP:127.0.0.53:53[Install]
WantedBy = multi-user.target
实用开发者合理化你糟糕的黑客工作。
systemd-resolved 是 Ubuntu 内置的 DNS 中间件,所以我偷工减料,搬起石头砸自己的脚。我用 socat 做的黑客工作出奇的好,除了容器。在/etc/hosts中,我打算避免配置全功能 DNS 服务器和硬编码 IP。
容器运行时是提取和执行容器映像的引擎。Kubernetes 过去默认使用 Docker 运行时。最近已经切换到了 CRI 和 Docker 运行时本身所基于的较低级别的 containerd 运行时。互联网上的大多数 GPU 集成手册都假定了 Docker 运行时,因此不再适用于现代的 Kubernetes。
还有最后一件事需要配置:NVIDIA GPU 调度。它实际上的意思是当吊舱规格像这样
metadata:
spec:
...
containers:
- ...
limits:
nvidia.com/gpu: 2
然后 Kubernetes 确保/dev/nvidia0和/dev/nvidia1存在于容器内部。
k0s 在文档中简单提到了如何启用 GPU,但实际过程要复杂一点。有一个迈克尔·韦贝尔关于 k3s 中解决任务的很棒的帖子,k0s 应该也有类似的调整。
首先,在每个 GPU 塔上安装 NVIDIA 驱动程序。NVIDIA 提供了一个可行的角色来实现自动化。在rc.local中添加nvidia-smi,在引导时创建设备。按照 NVIDIA 文档通过安装nvidia-container-runtime。按照约瑟夫·borġ's 博客文章中的描述,在 worker 节点上修补 containerd 配置,除了您应该用/etc/k0s/containerd.toml替换/etc/containerd/config.toml并如下更改头:
version = 2
root = "/var/lib/k0s/containerd"
state = "/run/k0s/containerd"
...[grpc]
address = "/run/k0s/containerd.sock"
然后,从kubectl version开始计算 Kubernetes 服务器版本,比如说 1.20,并应用 Google 的 daemonset,以便集群学习新的资源类型nvidia.com/gpu:
kubectl apply -f [https://raw.githubusercontent.com/kubernetes/kubernetes/release-1.20/cluster/addons/device-plugins/nvidia-gpu/daemonset.yaml](https://raw.githubusercontent.com/kubernetes/kubernetes/release-1.20/cluster/addons/device-plugins/nvidia-gpu/daemonset.yaml)
然后,您必须将工作节点标记为 NVIDIA 友好的:
kubectl label nodes --all cloud.google.com/gke-accelerator=true
瞧啊。用kubectl get daemonset -n kube-system nvidia-gpu-device-plugin检查状态。它应该输出 n / n ,其中 n 是 GPU 塔的数量:
NAME DESIRED CURRENT READY UP-TO-DATE
nvidia-gpu-device-plugin 3 3 3 3
您可以通过 SSH 访问一个 worker、
sudo apt install containerd、sudo systemctl disable containerd.service(Kubernetes 运行自己的),并使用sudo ctr --address /run/k0s/containerd.sock -n k8s.io发出命令来访问 k0s 的 gory containerd 内部。例如,下面的命令将列出所有拉出的图像:sudo ctr --address /run/k0s/containerd.sock -n k8s.io image list。界面类似于docker。
分布式文件系统
Kubeflow 的文档详细介绍了现有 Kubernetes 集群的安装。他们多次强调缺省设置的必要性,原因是:没有共享文件系统=没有 ML。定义了在 Kubernetes 中的 pods 中存储和挂载持久卷的后端。该类在集群中统一工作,以便一个 pod 中的文件更改可以被另一个 pod 看到。我们必须返回到 OS 和 Kubernetes 配置。
我决定部署牧场主的本地路径供应器和一个很穷但很骄傲的人的基于 NFS 十字坐骑和 mergerFS 的分布式 FS。我将从 DFS 开始。
NFS 代表网络文件系统,由 Linux、macOS 和 Windows 10 原生支持。这是一个比博客作者还要古老的协议。不要让它的年龄欺骗了你:NFS 通常是快速和可靠的。
我以前有过患 GlusterFS 的经验。虽然它以前工作稳定,但我对它的性能并不满意。在类似的集群配置中,写入、读取和删除大量小文件(例如 ImageNet)所需的时间是不可接受的。当时,GlusterFS 是由出色的 DevOps 工程师 Maartje Eyskens 和 Rafael Porres Molina 部署的,因此糟糕的性能应该不是由糟糕的配置造成的。
所以我设计了一个机器间 NFS 安装的全连接图。

NFS 全对全连接方案。图片作者。
节点 X 通过 NFS 导出/data/X,并通过 NFS 挂载剩余的/data子目录。这还不是一个共享的文件系统:我们需要将所有的子目录联合在一起。Linux 中存在几种合并目录或映像的文件系统,比如 OverlayFS——Docker 用它来堆叠容器层。我们的目标与 Docker 的不同,因为我们没有层级,所有 4 个子/data都是等价的。mergerFS 是一个很好的 FUSE(不需要内核模块)工具来达到这个目标。以下是项目自述文件中的一个示例:
A + B = C
/disk1 /disk2 /merged
| | |
+-- /dir1 +-- /dir1 +-- /dir1
| | | | | |
| +-- file1 | +-- file2 | +-- file1
| | +-- file3 | +-- file2
+-- /dir2 | | +-- file3
| | +-- /dir3 |
| +-- file4 | +-- /dir2
| +-- file5 | |
+-- file6 | +-- file4
|
+-- /dir3
| |
| +-- file5
|
+-- file6
mergerFS 支持如何执行文件系统操作的各种策略,它称之为策略。当用户创建一个目录时,它可以出现在所有合并的/data -s 中,也可以只出现在其中一个中;当用户创建一个文件时,它可以去本地的/data或者有最多空闲空间的地方。例如,这就是我如何在moscow上配置/etc/fstab以在/dfs挂载合并的目录(为了清楚起见,制表符被替换为新行):
/data/moscow:/data/campos:/data/madrid:/data/controller
/dfs
fuse.mergerfs allow_other,use_ino,cache.files=partial,dropcacheonclose=true,category.create=all
/etc/fstab定义主机上的本地文件系统。操作系统在启动时挂载列出的项目。
当我们在moscow上写一个新文件时,我们在本地/data/moscow上操作,其他机器通过 NFS 访问它。另一方面,目录结构到处复制。
让我们考虑一下这样的 DFS 的利弊。
优点:
- 不可能腐败。文件作为一个整体存储在节点上,而不是分散的块中。
- 如果我们使用本地文件,我们的性能与本机磁盘 IOPS 相当。
- 外部文件的对等 NFS 读取也是有性能的。
- 快速文件删除。
缺点:
- 如果某台机器坏了,我们就无法访问它的文件。但是,当我们有 4 台机器时,这不是问题。
- 读写非本地存储的大文件比在真正的 DFS-s 上运行要慢,DFS-s 将文件块分散在各个节点上,因此当您读写它们时,您可以并行聚合数据。我们可以通过本地复制大文件来缓解这个问题,老实说,如果磁盘有足够的空闲空间,这是典型 ML/DL 任务的最佳方法。
NFS 挂载是用
nofail,soft,retry=1,timeo=10配置的,这样内核就不会无限期地等待一个断开的共享重新出现,从而阻塞用户空间进程并引发混乱和破坏。
剩下的工作是在 Kubernetes 上部署本地路径StorageClass,这样工作人员就可以在/dfs上持久化数据:
wget [https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml](https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml)
sed -i 's/\/opt\/local-path-provisioner/\/dfs/g' local-path-storage.yaml
kubectl apply -f local-path-storage.yaml
kubectl patch storageclass local-path -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
完成这些操作后,您应该会看到类似的内容:
$ kubectl get storageclass
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
local-path (default) rancher.io/local-path Delete WaitForFirstConsumer false 13d
安装 Kubeflow
理论上,如果所有先决条件都满足,部署 Kubeflow 就很容易:
sudo mkdir /opt/my-kubeflow && cd /opt/my-kubeflow
chown $(whoami) .
export BASE_DIR=/opt
export KF_NAME=my-kubeflow
export KF_DIR=${BASE_DIR}/${KF_NAME}# Download kfctl from [https://github.com/kubeflow/kfctl/releases](https://github.com/kubeflow/kfctl/releases)# Suppose that the version is 1.2
wget [https://raw.githubusercontent.com/kubeflow/manifests/v1.2-branch/kfdef/kfctl_istio_dex.v1.2.0.yaml](https://raw.githubusercontent.com/kubeflow/manifests/v1.2-branch/kfdef/kfctl_istio_dex.v1.2.0.yaml) -o kfctl_istio_dex.yaml
kfctl apply -V -f kfctl_istio_dex.yaml
不幸的是,练习并不顺利。kfctl打印出一切都部署好了,只是没有。我和 katib 遇到了一个棘手的问题。Katib 是 Google 针对 Kubernetes/Kubeflow 的 AutoML 解决方案。例如,它可以进行超优化。
$ kubectl get pods -n kubeflowNAME READY STATUS RESTARTS
katib-db-manager-... 0/1 CrashLoopBackOff 235
katib-mysql-... 0/1 CrashLoopBackOff 24
日志消息信息不多,所以我花了几个小时才明白失败的原因。我应该简要回顾一下 Kubernetes 中的就绪性和活性探测。
Kubernetes 通过执行就绪探测来了解发射的吊舱是否准备好工作。它定期运行一个 shell 脚本并检查退出代码。如果退出代码为 0,Kubernetes 会将 pod 标记为就绪。
Kubernetes 通过执行活性探测来了解启动的 pod 是否起作用(“活性”)。它定期运行一个 shell 脚本并检查退出代码。如果退出代码不是 0,Kubernetes 将重新启动 pod。
katib-mysql 在第一次启动时初始化一个 mysql 数据库。该配置将活动探测延迟 30 秒。偏偏 30 秒太少,吊舱无法按时完成初始化。Kubernetes 杀了它。不幸的是,DB 初始化是不可抢占的,重启的 pod 再次失败。
该问题的解决方案是增加活性探针的initialDelaySeconds。
KUBE_EDITOR=nano kubectl edit deployment katib-mysql -n kubeflow
# locate livenessProbe and set initialDelaySeconds to 300
# save and exit# Important! Delete the old screwed database, e.g.
# pvc-25dc2b81-9873-430f-8bc4-365fe5ff0357_kubeflow_katib-mysqlkubectl delete pod -n kubeflow katib-mysql-...
最后,我们必须设置草稿端口转发来访问 web 界面。我写了一个 systemd 服务:
[Unit]
Description=kubeflow port forwarding
ConditionFileIsExecutable=/snap/bin/kubectlAfter=k0sserver.service
Wants=k0sserver.service[Service]
StartLimitInterval=5
StartLimitBurst=10
Environment="KUBECONFIG=/var/lib/k0s/pki/admin.conf"
ExecStart=/snap/bin/kubectl port-forward svc/istio-ingressgateway -n istio-system 8080:80...
Istio 是 Kubeflow 的一部分,负责组织服务网络和管理流量。例如,Kuberflow 使用 Istio 以受控和统一的方式将内部服务公开给外部,这样您就不必使用
kubectl port-forward单独的 pod。
你好,库伯弗洛!

Kuberflow 起始页。图片作者。
包裹
我试图从零开始勾勒出建立一个裸机集群来做 ML 的过程。这绝对是一种痛苦。我必须解决大量的问题,我不能在帖子中描述所有的问题,因为否则它会爆炸。然而,对于一个经验丰富的 DevOps 工程师来说,这并不复杂。2021 年的 MLOps 肯定比几年前容易。然而,如果你没有做好心理准备来打开现代 DevOps 技术的潘多拉魔盒——因为你不会在不了解自己在做什么的情况下解决不可避免的问题——我建议忘记裸机,继续在云中飞行。
正如一些人意识到的那样,我在走了很多捷径。一个专门的 DevOps 团队将重建集群,以充分利用 Kubernetes 和底层硬件。我估计我的努力是 2 周的全职工作。另一方面,配置越先进,对维护人员的依赖性就越强,暴露组件不当行为和损坏的面就越广。
请在 Twitter 上订阅 @vadimlearning ,这样你就不会错过我的下一篇博文。非常感谢 @Miau_DB 的资助、支持和宝贵意见;@艾纳 _ 菲奥进行校对。我们正在进行咨询,如果感兴趣,请发邮件到 fragile.tech 的 guillem。
使用 EFS 在 AWS Lambda 上部署大型包
理解大数据
AWS Lambda 是一个非常方便的工具,可以轻松地在线部署简单的功能。但是如果你碰巧有一个大项目或者依赖于一个大的库,这可能会变成一场噩梦。
AWS Lambda 还是挺方便的。在云上部署一个功能真的很简单,不用担心设置。你可以在几分钟内让它运行起来。但是,它的一个主要限制是部署大小,您不能部署大于 250MB 的任何东西。
您自己的代码不太可能那么大,但是您可能需要基本设置中不包含的库,这些库很容易达到几百 MB 或几 GB。当您使用现有的模型和您的模型的特定 ML 包来训练模型或运行推理时,通常就是这种情况。
在这种情况下,AWS EFS(弹性文件系统)来拯救。EFS 是一个文件系统,可以从不同的实例挂载,包括 Lambda 函数。一个主要的警告是,所有这些资源应该在同一个安全组和 VPC(虚拟私有云)中。

架构的高级视图[图片由作者创建]
该设置包括以下步骤:
- 创建一个 VPC 和一个安全组,在以下所有步骤中使用该 VPC 和安全组。
- 创建一个 EFS
- 创建 EC2 实例
- EC2 实例中的 EFS 山
- 安装所需的软件包
- 创建 AWS Lambda 函数
- 在 Lambda 函数中挂载相同的 EFS 文件系统
一旦安装了软件包,您就可以关闭 EC2 实例,不再需要它了。
这个系统的整体架构并不复杂,但是 AWS 界面的复杂性和部署中的某些变化使得设置起来更加困难。所需的库和 CLI 命令发生了变化,而 AWS 博客上的指南已经过时。在撰写本文时,我将尝试提供一个详细的分步说明。我将使用 AWS 网络控制台(【https://console.aws.amazon.com】T2)。如果您不熟悉 AWS 控制台,可以简单地搜索相关资源。
创造 VPC
除非你知道你在做什么,否则我建议你使用 VPC 向导。默认情况下,VPC 是隔离的,它不能访问互联网。将 internet 接入添加到 VPC 涉及一长串详细的步骤,如创建路由表、公共和私有子网、NAT 和 internet 网关等。(【https://stackoverflow.com/a/55267891】)。VPC 向导可以为你做这些。只需从 AWS 控制台转到 VPC 部分,然后单击启动 VPC 向导按钮。

VPC 巫师
拥有公共和私有子网的 VPC将为您的 lambda 功能提供互联网接入。但是由于 NAT 网关的使用,这可能具有更高的成本。如果你不要求,你可以用一个公共子网去 VPC。但是你应该在做那件事之前深思熟虑,这一步之后就很难改变了。

VPC 细节
你所需要做的就是给你的 VPC 一个名字,并选择一个弹性 IP,你可以让其余的保持原样,并创建一个 VPC。
创建安全组
现在我们有了一个 VPC,我们需要创建一个安全组。出于本指南的目的,我将只创建一个允许所有传入/传出流量。您当然可以创建一个更适合您的安全需求的,但要确保它给你访问权限。

确保您已经选择了我们创建的 VPC。你喜欢怎么命名都行。

网络访问的入站和出站规则
出于本指南的目的,我简单地设置了所有允许的传入和传出流量。理想情况下,您应该只授权访问您自己的 IP 地址和您需要的端口(即 SSH)。
现在我们有了 VPC 和安全组,我们可以创建我们的 EFS、EC2 实例和 Lambda 函数。
创建一个 EFS
您可以在创建 EC2 实例的过程中自动创建一个 EFS,但是您仍然需要对其进行更改,以便从 Lambda 函数中进行访问。因此,更简单的方法是预先创建一个包含所有必需细节的 EFS。
要创建 EFS,您必须转到 AWS 控制台上的 EFS 页面。您会在 EFS 主页上看到一个“创建文件系统”按钮。

创建文件系统对话框
创建文件系统后,我们需要创建一个访问点。当您进入新创建的文件系统时,有一个“访问点”选项卡,您可以在其中单击“创建访问点”按钮。

接入点选项卡

创建接入点对话框
您可以输入任意数量的用户和组 id 值。设置这些值会为挂载创建一个默认的根目录。
我已经将权限设置为 777,这将允许任何人写访问。这只是为了方便。当您以后不再需要写入时,您可以创建一个单独的只读访问点。那会更安全。
创建 EC2 实例
现在我们有了一个 EFS 文件系统,我们需要在同一个 VPC 中有一个 EC2 实例,以便装载和访问存储。虽然 AWS 可以在创建实例时自动创建 EFS 文件系统,但它不会创建访问点,没有访问点 Lambda 函数就无法挂载它。
转到控制台上的 EC2 仪表板,并单击“启动实例”按钮。您需要选择一个 Linux 或 OSX 实例,因为您不能在 Windows 设备上挂载 EFS。我将继续使用默认选择,一个符合条件的免费 Amazon Linux 2 AMI 实例 t2.micro。

实例详细信息
确定您选择了一个子网(装载 EFS 所需的)并将“自动分配公共 IP”设定为“已启用”。
在下面你会看到文件系统的设置。

添加文件系统选项
单击“添加文件系统”按钮将允许您选择我们创建的 EFS。您可以在这里设置 EFS 将被挂载到哪个文件夹。我们将在稍后安装软件包时使用它。
我们不必创建新的安全组,因此您可以取消选择它。但是要确保进入“配置安全组”步骤来选择安全组。

安全组步骤
现在可以启动实例了。确保下载密钥文件,我们将需要它来 ssh 到 EC2 实例中。
安装软件包和库
现在您可以 SSH 到 EC2 实例并安装您需要的库。例如,如果您需要安装 Python 包,只需使用 pip 安装在已挂载的 EFS 文件夹中。
sudo pip3 install — target /mnt/efs/fs1 pandas
“/mnt/efs/fs1”是我们在创建 EC2 实例时为文件系统挂载设置的文件夹。
你可以安装所有你想要的软件包,并上传你自己的文件。您也可以上传大型模型文件。所有文件都可以使用挂载文件夹直接从 Lambda 函数中访问。
您可以使用 scp 上传文件,但不能直接上传到挂载的驱动器,因为它需要 root 权限。您必须首先更改文件夹的权限:
sudo chmod 777 /mnt/efs/fs1
同样的概念也适用于其他语言。如果您正在开发一个节点应用程序,您可以简单地使用 npm 将库安装到挂载的 EFS 中。稍后我们可以通过 Lambda 函数访问它们。
完成安装包和上传文件后,您可以停止或终止 EC2 实例。如果需要进行其他更改,可以重新启动实例,甚至按照相同的步骤创建一个新实例。
λ函数
现在,您可以转到 AWS 控制台上的 Lambda 仪表板,创建您的 Lambda 函数,命名它并展开高级设置部分。

Lambda 高级设置
在这里,确保您已经选择了 VPC,以及我们之前创建的安全组。然后,您可以创建 Lambda 函数。这可能需要几分钟时间。
一旦创建了 Lambda 函数,并且您看到了确认消息,请进入 Lambda 函数的“配置”选项卡的“文件系统”部分。

单击“Add file system”按钮将允许您选择我们之前创建的文件系统和访问点。

Lambda 中的文件系统设置
请注意,这里的挂载路径略有不同。只需复制这个路径,我们将在环境变量部分使用它。

环境变量
对于 Python,我们有 PYTHONPATH 环境变量。在“环境变量”选项卡下,只需单击“编辑”并添加此变量,使用我们在上一步中使用的挂载路径(即/mnt/fs1)。对于 node.js 应用程序,您可以设置 NODE_PATH 变量等等。
现在你都准备好了。你安装的包可以直接从你的 Lambda 函数中加载,不需要做任何其他事情。您还可以从同一个 Lambda 函数中访问添加到 EFS 的其他文件。
将机器学习和数据科学项目部署为公共 Web 应用程序
实践教程
如何从本地 Jupyter 笔记本开发环境中获取数据科学项目,并将其发布为公开可用的 web 应用程序

介绍
许多有用的机器学习和数据科学应用是在 Jupyter 笔记本环境中开发的,但是当它们完成并准备好与内部客户或外部数据科学社区共享时,这些笔记本如何共享呢?
有许多不同的方法可以实现这一点,但这篇文章解释了如何使用 voila 和 mybinder 部署 Jupyter 笔记本,使用这种方法是因为它快速、有效且免费。
在配置和设置方面有一些细微差别,本文的其余部分将通过详细的解释和屏幕截图,以易于遵循的步骤解释如何实现这种部署…
第一步:在笔记本上写一个“应用程序”
第一步是在 Jupyter 笔记本中编写一个“应用程序”,它可以以用户可以与之交互的方式显示或呈现。
大多数数据科学家更熟悉编写机器学习算法,而不是 web 应用程序,但幸运的是,有一个易于使用的库,使 Jupyter 笔记本能够作为 web 应用程序交付,这就是 IPython widgets (ipywidgets)。
解释如何使用 ipywidgets 创建一个交互式应用程序超出了本文的范围,但是网上有一套优秀的文档可以帮助您入门——https://ipywidgets.readthedocs.io/en/stable/user_guide.html
步骤 1a:创建示例应用程序
我们将需要一个使用 ipywidgets 的应用程序来用于这个示例,为此,我修改了我在以前的一篇文章中写的一个笔记本,该笔记本计算正态和二项式分布的置信区间。
如果你想看看这篇文章,其中包含了所有的细节和解释,请看看这个链接—https://towards data science . com/how-to-build-an-interactive-confidence-interval-calculator-in-python-6 EAA 08d 69 be 3
同时,这是修改后的代码,将用于我们的示例-
它看起来比实际更复杂,因为每个控件都有单独的代码行,但是如果您想要详细的代码解释,只需使用我以前文章的链接即可—https://towards data science . com/how-to-build-a-interactive-confidence-interval-calculator-in-python-6 EAA 08d 69 be 3
步骤 2:在本地部署应用程序
我们现在有一些数据科学代码来计算 Jupyter 笔记本中呈现的置信区间。输出组织得相当好,运行得相当好,但是有几个问题-
- 如果我们想将它分发给用户,这些用户必须能够访问 Jupyter 笔记本环境。
- 代码都混在“应用程序”中,这可能会让那些只想使用计算器而不关心它是如何实现的用户感到困惑。
这就是 Voilà Jupyter 服务器扩展的用武之地。
一旦 Voilà安装完成,它将像 Jupyter 一样运行笔记本电脑,但有一个重要的区别。它去掉了所有的单元格输入,只留下包含 ipywidgets 和 markdown 的输出。通过这种方式,python 代码被删除,剩下的就是一个功能完整的 web 应用程序。
Voilà必须按照以下方式安装-
- 通过从命令行运行
pip install voila或从 Jupyter 笔记本内部运行!pip install voila来安装 voila 库。 - 通过在命令行运行
jupyter serverextension enable voila –sys-prefix或者在笔记本中使用前缀!来启用扩展。 - 重新启动计算机,否则新的服务器扩展不会被选中,也不会启动。
安装并运行 Voilà后,您可以将任何笔记本电脑作为 web 应用程序运行,如下所示-
- 启动 Jupyter 笔记本应用程序。
- 编辑地址栏中的网址,将
/tree替换为/voila,如果你使用的是端口 8888 -http://localhost:8888/voila-

作者图片
3.浏览文件夹结构,直到找到要作为 web 应用程序运行的笔记本,然后单击。ipynb 笔记本文件。
您的笔记本现在将呈现为一个全功能的 web 应用程序-

作者图片
如果您想查看 Voilà的完整文档,请使用此链接—https://voila.readthedocs.io/en/stable/index.html。
恭喜您,您现在拥有了一个完整的、可工作的 web 应用程序,可将数据科学代码直接部署到 web 浏览器用户界面中!
唯一的问题是,你是这个世界上唯一可以使用它的人,这有点违背了网络应用的目的…
步骤 3:将应用程序部署到 Github
为了公开部署这款应用,我们需要使用另外两个工具——GitHub 和 mybinder。GitHub 将用于保存一个公开可用的 web 应用程序源代码库,mybinder 将用于托管应用程序及其运行时环境,并向用户提供一个公开的 URL。
创建 GitHub 存储库有几种方法。一些数据科学家喜欢使用命令行来完成这项工作,但我更喜欢使用 GitHub 桌面应用程序。如果你还没有桌面应用程序,而你想完全按照下面的步骤操作,你需要使用此链接https://desktop.github.com/下载并安装它。
您还需要一个 GitHub 帐户,您可以通过访问 GitHub 主站点—【https://github.com/】T2 来创建该帐户。
启动 GitHub 桌面应用程序,选择“文件|新建存储库”…

作者图片
很长一段时间,我发现库的创建是反直觉的,我努力在正确的地方创建我的代码库。我发现这些建议非常有用-
- 当创建一个想要上传到 GitHub 作为资源库的文件夹时,不要在名称中使用任何空格。例如,使用“置信区间”而不是“置信区间”。
- 您在“名称”框中选择的名称必须与存储代码和项目文件的文件夹名称完全匹配。
- “本地路径”必须准确地指向您用来存储代码的文件夹的父文件夹,而不是指向文件夹本身(这一点非常重要,因为如果您弄错了,您将得到一个空的存储库,这是我一直弄错的一步!).
- 出现提示时,您应该为您的私有代码选中“私有”,但对于公共 web 应用程序和 mybinder 项目,您必须取消选中“私有”,以便新存储库是公共的,即任何人都可以浏览并查看它(但不能更改它)。
现在,您可以使用 GitHub 桌面作为您的“命令中心”,通过提交和推送更改、在您选择的外部编辑器中打开代码、在文件资源管理器中查看存储库文件或在 GitHub 中在线打开存储库页面,与您的 GitHub 源代码存储库进行交互..

作者图片
在这个阶段,我们有一个工作的本地 web 应用程序,我们已经将它部署到 GitHub 中的一个公共存储库中。接下来,我们需要在云中创建一个运行时环境来执行我们的应用程序,完成部署并创建一个公共 URL -
步骤 4:使用 mybinder.org 创建云运行时环境
有许多不同的基于云的工具可以用于这一步,但我选择了 mybinder.org,因为它快速、免费且易于使用。在本文结束之前,我们将探索和理解一些缺点。
步骤 4.1 创建一个“environment.yaml”配置文件
下一个任务很关键,我在网上没有找到太多关于它的参考资料;在使用 mybinder 创建运行时环境之前,您必须在 Jupyter 笔记本代码所在的目录下创建一个“environment.yaml”文件,然后确保它被提交并推送到 GitHub。
这个文件确切地告诉 mybinder 运行您的项目需要哪些库和先决条件。如果您还记得,我们的 web 应用程序使用了以下库…
…最重要的是,它依赖于 voila 库和相关的服务器扩展。
指示 mybinder 创建这些依赖项所需的“environment.yaml”文件如下…
name: voila-gallery-country-indicators
channels:
- conda-forge
dependencies:
- ipywidgets
- scipy
- numpy
- jupyterlab>=3.1
- voila>=0.2.11
如果你不包含“environment.yaml”文件,什么都不会起作用,如果你错过了库,你的 web 应用程序将会崩溃,如果你不包含 voila,我的 binder 将无法呈现 web 应用程序,因此遵循这一步骤至关重要。
步骤 4.2 将 web 应用从 GitHub 部署到 mybinder
my binder(https://mybinder.org/)是一个令人惊叹的云实用程序,它可以有效地从任何 GitHub 存储库中获取代码,并提供一个可配置的运行时环境来执行和交付笔记本应用程序。
让一切都正确地排列起来有点棘手,但是如果你按照本文中的步骤去做,它应该完全按照预期的那样工作。
第一步是导航到 https://mybinder.org/的 T2,输入一些非常基本的信息告诉我的 binder 在哪里可以找到你部署的应用程序
- 在“GitHub”字段中输入 GitHub 存储库的 URL(如果您找不到 GitHub URL,只需点击 GitHub 桌面内的“打开存储库页面…”链接,它会直接将您带到那里)。
- 点击“文件”下拉菜单,将其更改为“网址”。
- 在“要打开的 URL”字段中,输入“/voila/render/notebook filename . ipynb”(例如/voila/render/Confidence % 20 interval % 20 app . ipynb)
- 单击复制粘贴图标将完整的 URL 复制到粘贴缓冲区。
- 点击“启动”按钮。
确保精确地执行这些步骤,尤其是将“文件”更改为“URL ”,并输入正确的路径到/voila/render/您的笔记本名称。
如果你得到了正确的,你会看到完整的网址包含“urlpath ”,如果你错过了第 3 步,它将包含“labpath ”,这将不会工作。
字段应该是这样的…

作者图片
单击“launch”后,mybinder 需要一点时间来构建和部署环境。在构建过程中,您将看到各种消息输出到控制台窗口,当构建完成时,您将在浏览器窗口中看到您完成的 web 应用程序…

作者图片
步骤 4.3 从 web 应用程序 url 中创建一个 tinyurl
请务必注意,正确的 URL 是在步骤 4.2 中复制到粘贴缓冲区的 URL,编号为第 4 项,而不是显示在浏览器 URL 栏中的 URL。正确的 URL 看起来像这样-
每次您或用户访问正确的 url 时,它都会在浏览器中解析成不同的最终 URL,但是在步骤 4.3 中复制到粘贴缓冲区中的 URL 是永久的,并且可以通过访问 https://tinyurl.com/app/的转换成 tinyurl

作者图片
您可以通过访问此链接来试用我已完成和部署的置信区间计算器—【https://tinyurl.com/9sfcf
结论
这涉及到很多步骤,你必须把它们都做好才能达到目的,但是这个目的是值得努力的!
一旦您以这种方式部署了一个机器学习或数据科学应用程序,只需片刻即可完成下一个应用程序,然后您就可以快速、高效、免费且易于使用的方式将您的 Jupyter 笔记本电脑作为全功能网络应用程序共享给客户、同事和同行。
我注意到的一个缺点是,没有办法发布一个公共的 web 应用程序,只能将程序代码保密;您必须在您创建的 GitHub 存储库中公开您的代码,否则 mybinder 阶段无法工作。
这可能是 mybinder 的未来功能,我想在某个阶段,他们可能会发布带有附加功能的付费版本,这样的事情就可以完成了。
另一个主要缺点是,这个过程有点笨拙,而且很容易犯错误,没有将 mybinder.org 页面中的“文件”下拉列表改为“URL ”,如果弄错了,就会阻止 web 应用程序打开。
作为最后一个提示,我总是将 bear 最少的代码放在 GitHub 的应用程序库中,只有当我对它的完成感到满意时才发布它,这样它就不需要不断地重新发布,这可能会影响到你已经将链接分发给的最终用户。
总之,一旦你学会了这些怪癖,这是一个相对简单的过程,如果你按照本文中的步骤去做,它每次都会起作用。
您可以从我的 GitHub 资源库下载完整的源代码
- https://github.com/grahamharrison68/Confidence-Intervals
- https://Github . com/grahamharrison 68/Public-Github/tree/master/Web % 20 deployment
感谢您的阅读!
如果你喜欢读这篇文章,为什么不去 https://grahamharrison-86487.medium.com/的看看我的其他文章呢?此外,我很乐意听到您对这篇文章、我的任何其他文章或任何与数据科学和数据分析相关的内容的看法。
如果你想联系我讨论这些话题,请在 LinkedIn 上找我—【https://www.linkedin.com/in/grahamharrison1 或者发电子邮件给我ghar rison @ Lincoln college . AC . uk。
如果你想通过订阅来支持作者和全世界 1000 个为文章写作做出贡献的人,请使用这个链接——https://grahamharrison-86487.medium.com/membership(注意:如果你使用这个链接注册,作者将收到一定比例的费用)。
将机器学习部署到生产中:不要做实验室。

众所周知 87%的数据科学项目没有进入生产。问题有据可查(见这里,这里这里,这里这里)。
根据我在加拿大百思买构建分析产品的经验,应用数据科学项目很少因为科学而失败。他们之所以失败,是因为这种模式无法整合到现有的系统和业务运营中。我们已经有了显示良好准确性的可靠模型,甚至有了证明价值的概念证明,但仍然无法部署到生产中。挑战不在于概念验证,而在于扩展。
具体来说,开发模型的数据科学家和将其实施到系统中的工程师之间的差距是一个反复出现的挑战。数据科学家倾向于在一个孤立的环境中开发他们的 ML 模型,远离日常消防甚至客户互动。在“实验室”玩数据这意味着我们错过了关键问题的领域知识和背景,错过了与集成、支持和使用模型的工程师和业务用户意见一致的机会。
在实验室里很少有机会感受到用户的痛点。反过来,数据科学家解决错误问题、开发难以实施的解决方案或未能在用户眼中增加价值的几率也很高。实验室工作很难部署到生产中。
这个问题是复杂的,因为事实上接触百万美元的赚钱生产系统是高风险的。代码可能是创始人的代码和附加补丁的混合,与十几个其他系统集成在一起。有很多未知。所以集成模型输出太快,我们会冒导致不可预见的问题的风险。慢慢来,其他优先事项可能会接管。我们需要平衡展示 ML 模型价值的需求和发展软件特性和维持正常运行时间的需求。
一些同事提到,将模型投入生产是一个创建 API 的例子。API 是很好的交付工具,但是认为它们解决了所有的生产挑战就有点简单化了。如果 API 在每小时赚 1000 万美元的生产软件上失败了怎么办?数据科学家会放下实验室的一切,与工程团队一起提供支持吗?谁负责设计迭代扩展的实验?如果数据有限,当前的开发环境甚至允许测试 ML 模型吗?我们如何监控不可预见的结果(想想亚马逊的人工智能招聘工具对女性的偏见)。我们数据科学家需要与生产软件团队携手应对这些挑战,而我们在实验室里做不到这一点。
所以我们百思买不再做实验室了。
将数据科学产品部署到生产中的大多数尝试都集中在使集成更容易的工具上,或者有点令人困惑的流程改进(让顾问带头)。然而,他们未能弥合结构性差距:数据科学家在远离生产环境的实验室中开发算法的事实。反过来,未能部署到生产中的结果保持不变。(结构- >流程- >结果是医疗保健行业中一个行之有效的质量改进框架,值得我们借鉴。)
为了从结构上提高我们的机会,我们的数据科学家现在与技术产品团队携手合作。

基思·约翰斯顿在 Unsplash 上的照片
我们已经将数据科学家嵌入到各自的产品团队中,该团队拥有我们想要颠覆的特定技术。我们在生产中发展权利。真实的世界。这符合我们的核心价值观之一,即作为一个团队比赛,作为一个团队输赢。我们认为,在实验室开发一个模型并传递给工程团队,就像一个四分卫把球传给了没有人准备好接球的区域。我们想确保团队准备好了。
例如,为了建立一个优化库存分配的模型,我们的分析团队与库存技术团队合作。我们吃他们吃的东西,看他们看的相同的系统和代码,最重要的是,对他们相同的指标和领导者负责。信任是在传统上来自两个不同世界的数据科学家和软件工程师之间有机建立的。
这种结构迫使我们从一开始就提出尖锐的问题。我们今年有资源交付解决方案吗?相对于其他产品功能,这款 ML 作品有什么价值?谁将在生产中帮助支持该系统?在我们扩大规模之前,需要进行哪些实验和测试?
符合每个人期望的一个关键问题是:我们有能力做什么?承认我们可以在生产中实际部署和支持的东西,可以避免开发无法集成的东西。例如,如果没有资源将所需的数据放入数据湖并创建自动化管道,那么更好的第一步可能是进行描述性分析并实现静态数据集,直到数据工程团队准备好支持我们的计划(有时来自描述性分析的结果也一样好)。
嵌入式模型的另一个关键元素是让负责生产软件的产品经理也为 ML 模型设置开发优先级。他们可能没有机器学习或分析专业知识;他们可能需要分析技术产品经理的帮助来共同制定解决方案和路线图。但是他们需要成为领导者和主动性的代言人。如果产品经理主动要求分析解决方案来解决他们的问题,并且如果他们是向用户销售解决方案的人,那么部署到生产中自然是优先考虑的。这也有利于数据科学团队:他们可以专注于交付价值,即收集数据、测试模型、提炼、测试和扩展,而不是销售结果,向高管推销新的 ML 模型的价值。
应用数据科学家是为了解决问题而存在的。不只是做很酷的科学。嵌入式让我们能够直接感受到业务痛点,并设计出生产工程师和业务用户乐于实施的解决方案。
从生产团队的实验室工作中获益
然而,在实验室中开发模型确实有一些好处。这里有三个我们正在努力复制到我们的嵌入式结构。
#1:系统思维:实验室为更多的系统思维提供了空间。我最喜欢的关于阿科夫博士的系统思维的演讲强调了确保我们改善各个部分如何相互作用以改善系统整体的重要性。

卡洛斯·阿兰达在 Unsplash 上的照片
嵌入一个团队有一个危险,那就是只关注对团队重要的事情,系统的一小部分。如果没有解决中间环节或库存方面的挑战,仅仅提高最后一英里的交付速度可能无法实现更快的履行。
为了避免目光短浅,我们发现在融入团队之前,给整体问题研究留出适当的时间是成功的。这使我们能够与涉及业务领域的任何人和每个人交谈,探索他们的挑战,并对问题和机会所在做出整体评估。在专注于一个部分之前,它给了好奇和探索的空间。这也确保了我们嵌入到我们预测会产生最大影响的业务领域。
#2:理想设计:恰好阿科夫有一本关于理想设计的书,围绕解决根本问题的概念(如果你什么都不做,什么会扼杀你的生意,为什么为什么为什么……)。不要让今天的解决方案和约束限制了我们的想象力。换句话说,扰乱,不要调整。

通过嵌入和只致力于我们今年能做的事情,我们冒着仅仅是调整而不是破坏的风险。例如,让当前的库存分配运行得更好 10%,而不是把它拆开,让它更好 100%。
在这方面,我们从理想的角度开始解决方案设计过程。设置北极星。只有当最终目标明确时,我们才承认团队的能力,并剔除版本 1。成功意味着逐步部署到产品中,然后让每个新版本让我们更接近北极星。这是一个双赢的局面,因为我们可以在现实世界中快速测试我们的模型,而业务团队可以立即看到业务成果。
#3:不断创新:在实验室工作的最大好处是有空间设计新工具,而不会陷入支持现有系统的困境。给探索、测试、迭代的空间。

照片由 Goh Rhy Yan 在 Unsplash 上拍摄
在嵌入式模式下,部署到生产中的内容也需要得到数据科学家的支持。这花费了改进模型的时间和精力:探索新的分析、新的数据特征、新的算法等等。
我们仍在制定最佳实践,并真诚地欢迎对此的评论,但在一定程度上已经奏效的做法是将整个冲刺阶段(即 2 周)只专注于创新,而忽略了这段时间的支持工作。这可以防止上下文切换和分心。我们都知道,试图将每次冲刺的支持率保持在 30%以下,往往会适得其反。
通过合作增加成功几率
祈祷我们的模型能够投入生产是不够的。我们需要认真解决这个问题。扭转对我们有利的局面。
将失败率从 87%降低到 50/50,需要团队结构、过程和工具的综合改进。数据科学团队可以比创业公司做得更好,成功的机会只有 1/10。通过与生产软件和业务团队携手构建他们想要的解决方案,更重要的是,根据他们可以部署的规范,产品与市场的契合度可以在第一天就存在。
使用 Flask 将机器学习模型部署到网站中
从模型开发到应用…一段有趣(有时也不愉快)的旅程。

内森·达席尔瓦在 Unsplash 上的照片
经过 3 年多对数据科学领域关键概念的研究,开发实施、设计和评估机器学习和预测模型的必要技能已成为常态。
然而,随着对具有将机器学习模型集成和部署到各种软件架构中的技能的专业人员的需求开始飙升,其应用程序继续以指数速度增长。
有趣的是,在我迄今为止的学术经历中,很少或没有接触到部署这种模型。大学和学院过于强调机器学习的理论而没有展示其背后的实用性。
让我们面对现实吧,如今许多数据科学专业人士都是全栈式的。
我说的全栈是什么意思?实际上,现在你应该在数据科学开发周期的每一步中都掌握一些技能,从需求/业务分析开始,一直到将这些模型扩展和部署到公司的现有基础设施中。
数据科学家的技能在不断变化,这些技能包括:
- 数学:微积分、线性代数、最优化、统计/概率。
- 计算机科学:算法、数据结构、编程
- 人工智能:神经网络,分类,回归,聚类,调整。
- 最近,软件工程实践:版本控制,文档,测试。
更不用说特定领域的知识了。
正是因为这些技能,我们现在被认为是“万金油……无所不能的大师”,或者换句话说是“独角兽”(不是字面上的意思)。
然而,这提出了一个有趣的问题…
如果这些实用的概念不在他们的学习中出现,毕业生们又如何能跟上这些日益增长的需求呢?
答案是,项目…很多项目。
事实上,我们不能改变教育体系,我们必须主动在其他地方拓展我们的技能。如果你对进入 STEM 感兴趣,请了解…
你必须全身心地投入到学习的生活中。
在很多情况下,课外学习。
在本文中,我将介绍我最近的一个个人项目,该项目旨在使用 Python 的 Flask 框架将预测房价的多元线性回归模型部署到一个网站应用程序中。
所以系好安全带,让我们开始吧!
首先,我们需要涵盖这个应用程序的一些关键指标和目标。
目标?预测美国某些大都市地区的房价。
我们还需要了解一些要观察和研究的关键变量/指标。使用来源于 Kaggle 的数据集:
美国住房:https://www.kaggle.com/vedavyasv/usa-housing
要观察的变量有:
- 平均地区收入
- 平均面积房屋年龄
- 房间的平均面积数量
- 卧室的平均面积数量
- 区域人口
- 价格
- 地址
首先,“地址”与我们的分析无关,因为我们的预测是基于数字变量。
应用程序的目的是预测房屋的价格,因此我们的响应变量将是“价格”。至于地区收入、房龄、房间数量、卧室数量和地区人口,它们可以显著影响房屋的价格。
现在,让我们对数据集进行一些探索性分析。

查看上面的关联热图,我们可以看到,所有 6 个预测变量之间的大多数正面响应都与响应变量“价格”有关。有趣的是,Avg 之间似乎存在正相关关系。卧室面积和平均面积。房间数量。我们还可以观察到,最大的相关性是在 Avg。收入和价格。考虑到房屋的质量和价值可能取决于该地区的平均收入,这一点尤其有意义。
现在让我们看看其他一些观察结果:

我们可以看到,所有变量中的大多数都是正态分布的。“卧室面积数”具有不同程度的分布和概率。至于右边的散点图,除了“平均”,所有变量似乎都显示出正的线性趋势。卧室面积数”。因此,卧室的数量可能不会对结果产生积极影响。
让我们来看看一些样本统计数据:

我们有足够数量的相同大小的样品。这可能是为什么我们的变量是正态分布的原因之一,与中心极限定理联系在一起。
此外,大多数 50%的人:
- “平均地区收入”的收入在 75,783.34 美元和 61,480.56 美元之间。
- “平均房龄”在 6.65 到 5.32 岁之间。
- “平均房间数”在 7.67 至 6.30 间房间之间
- “平均面积:卧室数量”有 4.49 和 3.14 间卧室
- “地区人口”分别为 42861.29 人和 29403.93 人
- “价格”介于 1417210 美元和 997577 美元之间
最后,让我们检查空值:

谢天谢地,我们没有。
因此,我们可以得出结论,除了卧室数量之外,所有变量都是正态分布和相关的,没有空值。
现在我们对数据背后有了一些了解,让我们开始讨论我们的数据,以获得正确的预测和响应变量。我们还将把它们的数据类型转换成整数:
不久之后,我们将把数据分成训练集和测试集,并开始模型拟合:
让我们来看看模型的性能:
该模型显示训练集的 R2 分数为 89.396%,测试集的为 89.028%。这表明我们的模型显示了我们的反应和预测变量之间的强线性关系和趋势。让我们也看看 RMSE 以及我们的预测的可视化:
我们的模型的 RMSE 为 114729.221,这表明我们的残差在很大程度上从最佳拟合线分散开来,表明其周围的残差集中度较低。但是请记住,RMSE 是规模依赖的,没有一个具体的阈值来衡量好坏,但根据经验法则……越小越好。

散点图 y _ 测试与预测

y_train 与预测值的散点图
至于图,预测值与真实值显示了强有力的、积极的和线性的关系,具有良好的相关性,因此可以用前面的 R2 分数来解释。
总的来说,至少可以说是一个不错的模型,但从长远来看,我们可以改进它。现在,让我们开始在 Flask 中部署它,这是这个项目的焦点。
首先,我们需要保存我们的模型。通过 pickle 库,我们将使用以下脚本来保存我们的回归模型:
理解 Flask 的基本机制花了我几个小时来理解,特别是路由、设置我的环境和创建我的工作树目录。但是在最终理解了这些概念之后,我带着下面的程序来了:
上面的代码有助于控制我们网站的路由和模板使用。具体来说,def predict()负责返回给定用户输入的预测房价,这些输入是使用 request.form.values()收集的。最后,我们在 debug 设置为“True”的情况下运行应用程序,这样我们就可以在本地设备上看到网站的开发和环境状态。
我还使用了下面的树形目录来完成这个项目:
/project
app.py
model.py
model.pkl
/template
/index.html #home page
/static
/img #all images stored in this folder
/styles #all CSS styles are stored here
最后,我们的 html 文档的基本结构是:
当我们在命令提示符下运行程序时(在我的例子中是 Anaconda,因为我的程序在 Anaconda 虚拟环境中运行),我们会得到下面的 web 页面:

很可怕吧?让我们用下面的 CSS 样式来改进设计:
请原谅我和我的 CSS 和 HTML 脚本的笨拙。我真的需要找到更多的机会来使用它。
看,最终产品:

按下“预测”,我们会得到一个预测价格…

现在看看那些前端开发人员…现在正在坟墓里打滚…
我本来可以添加一个更令人印象深刻的背景图片,但你知道…版权是一个问题。
有趣的是,CSS 样式花费的时间比开发应用程序和模型加起来还要长。
这个项目,虽然从整体上看相对简单,但却是我完成的所有项目中最有洞察力的。为什么你会问?因为从头开始构建一个 ML 应用程序,而不是纯粹地展示和报告您的发现,这种感觉是纯粹的狂喜。爱它的每一分钟:)
也许,在不久的将来,我甚至会在 Heroku 甚至 AWS 上部署它!好吧,现在让我们把注意力集中在设计上,不要想太多。学习是一个循序渐进的过程,我们不能错过每一步。
你有它!一个相对简单的应用程序,结合了最好的理论和实践。此外,它还深入介绍了用于开发这些应用程序的一些技术和框架。这个微不足道的网站需要 3 种不同的语言,多个框架…和一些脑细胞。但最终这一切都是值得的,这是一次前所未有的学习经历。
希望这篇文章能够启发你在不久的将来开发更复杂的应用程序和 ML 模型!
记住,学习不仅仅局限于你的学习,在其他地方探索和征服那些技能!
为生产中的 ML 模型提供 FastAPI 和芹菜
使用异步 Celery 任务和 FastAPI 为您的模型服务的完整工作示例。

阿诺·弗朗西斯卡在 UnSplash 上的照片
概观
网上有大量关于建立和训练各种机器学习模型的材料。然而,一旦一个高性能的模型被训练出来,将它投入生产的材料就少得多了。
这篇文章介绍了一个使用 Celery 和 FastAPI 服务 ML 模型的工作示例。所有代码都可以在这里的资源库中找到。
我们不会专门讨论本例中使用的 ML 模型,但是它是使用示例银行客户流失数据(【https://www.kaggle.com/sakshigoyal7/credit-card-customers)进行训练的。存储库中有一个笔记本,概述了 LightGBM 模型的培训,包括超参数优化和性能评估。
潜在选项
下面总结了将训练好的模型部署到生产中的可能方法:
- 直接在应用程序中加载模型:这个选项包括直接在主应用程序代码中加载预训练的模型。对于小型模型,这可能是可行的,但是大型模型可能会引入内存问题。这个选项还在主应用程序中引入了对模型的直接依赖(耦合)。
- 离线批量预测:不需要接近实时预测的用例可以使用这个选项。该模型可用于对以规定时间间隔运行的流程中的一批数据进行预测(例如,一夜之间)。一旦批处理作业完成,应用程序就可以利用这些预测。只有在批处理运行时才需要用于预测的资源,这可能是有益的。
- API:第三种选择是将模型部署为自己的微服务,并通过 API 与之通信。这将应用程序从模型中分离出来,并允许从多个其他服务中利用它。ML 服务可以以下面描述的两种方式之一来服务请求。
同步:客户端请求预测,并且必须等待模型服务返回预测。这适用于需要少量计算的小型模型,或者客户端在没有预测的情况下无法继续其他处理步骤的情况。
异步:模型服务将返回任务的唯一标识符,而不是直接返回预测。当模型服务完成预测任务时,客户可以自由地继续其他处理。然后可以使用唯一的任务 id 通过结果端点获取结果。
工艺流程
以下步骤描述了处理预测请求所采取的操作:

架构示例(图片由作者使用来自维基共享的标识)
- 客户端向 FastAPI 预测端点发送 POST 请求,请求体(JSON)中包含相关的特性信息。
- FastAPI 根据定义的模型验证请求主体(即检查是否提供了预期的功能)。如果验证成功,则创建芹菜预测任务,并将其传递给已配置的代理(例如 RabbitMQ)。
- 如果任务创建成功,唯一 id 将返回给客户端。
- 预测任务由代理交付给一个可用的工作者。一旦交付,工人使用预先训练的 ML 模型生成预测。
- 生成预测后,使用 Celery 后端(例如 Redis)存储结果。
- 在步骤 3 之后的任何时候,客户机都可以使用惟一的任务 id 开始轮询 FastAPI 结果端点。一旦预测就绪,它将被返回给客户端。
现在让我们看一些实现这个架构的示例代码。
项目结构
项目结构如下:
serving_ml
│ app.py
│ models.py
│ README.md
│ requirements.txt
│ test_client.py
│
├───celery_task_app
│ │ tasks.py
│ │ worker.py
│ │ __init__.py
│ │
│ ├───ml
│ │ │ model.py
│ │ │ __init__.py
- app.py :包含路线定义的 FastAPI 应用。
- models.py: 用于 API 验证和响应结构的 Pydantic 模型定义。
- test_client.py :用于测试设置的脚本。我们稍后将更详细地讨论这一点。
- celery _ task _ app \ tasks . py:包含 Celery 任务定义,具体来说就是我们案例中的预测任务。
- celery _ task _ app \ worker . py:定义 celery 应用程序实例和相关配置。
- celery _ task _ app \ ml \ model . py:用于加载预训练模型和服务预测的机器学习模型包装类。
ML 模型
首先,让我们看看我们将如何加载预训练模型和计算预测。下面的代码为预训练模型定义了一个包装类,它在创建时从文件中加载,并在其 predict 方法中计算类概率或成员资格。
只要模型有 predict 和 predict_proba 方法(即 Scikit-Learn 或 Keras 实现),这个实现就可以在各种 ML 模型中重复使用。
在我们的示例中,保存的模型实际上是一个 Scikit-Learn 管道对象,它包含一个预处理步骤,因此我们不需要担心在预测之前有额外的预处理代码。我们可以简单地用特征数据创建一个数据帧,并调用管道预测方法。
芹菜
Celery 是一个简单的任务队列实现,可以用来跨线程和/或机器分配任务。实施需要一个代理和一个后端(可选):
- Broker:这是用来在客户和工人之间传递消息的。为了启动一个任务,客户机向队列中添加一条消息,然后代理将这条消息传递给一个工人。RabbitMQ 通常用作代理,并且是 Celery 使用的默认设置。
- 后端:这是可选的,它唯一的功能是存储任务结果以备日后检索。Redis 常用作后端。
首先让我们看看如何定义我们的芹菜应用程序实例:
这个应用程序定义非常简单,但是可以定义大量的附加配置选项(例如时区、序列化)。
include 参数用于指定为 Celery 应用程序定义任务的模块。在这种情况下,我们在 tasks.py: 中定义一个任务
我们的任务实现比平常稍微复杂一些。大多数简单的任务可以使用 task decorator 来定义,它覆盖了 Celery 的基本任务类的 run 方法。然而,如果我们使用这种方法,它将导致定义一个模型类,并因此为每个处理的任务从磁盘加载。
通过扩展 Celery 任务对象,我们可以覆盖默认行为,这样 ML 模型只在任务第一次被调用时加载一次。随后的调用可以使用相同的加载模型。
尽管这比每次运行任务时都加载模型要好,但仍有一些注意事项:
- 每个工作进程都有一个 PredictTask 对象。因此,如果一个工作线程有四个线程,那么模型将被加载四次(每个线程都存储在内存中……)。
- 这为每个工作进程引入了一个冷启动场景,其中第一个任务会很慢,因为需要加载模型。有不同的方法可以用来解决这个问题,而任务是异步的这一事实使得这个问题变得不那么严重。
然后我们可以使用通常的装饰方法并指定 base=PredictTask ,这样 Celery 就知道使用我们的自定义任务类而不是默认的。 bind 参数允许我们使用 self 访问模型属性(就像我们直接在类中定义 run 方法一样)。
FastAPI
最后,我们可以创建一个 API 来生成任务,并根据客户端请求从后端获取结果。
需要两个端点:
- …/churn/predict (POST):客户端发送包含所需特性的 JSON。返回了唯一的任务 id。
- …/churn/result/ <task_id>: (GET):检查任务结果在后端是否可用,如果可用则返回预测。</task_id>
我们按如下方式实现这些端点:
在结果路由中实现特定的响应,以处理任务结果未准备好的情况。客户机可以用它来轮询结果端点,直到结果准备好(我们将用它来测试……)。
测试
为了检查一切是否按预期工作,我们可以创建一个单独的 Python 脚本来模拟预测请求。为此,我们利用 Python 的请求包。
一旦代理和后端服务器都在运行,我们就可以使用 uvicorn 启动 API:
uvicorn app:app
接下来启动一个工作进程:
celery -A celery_task_app.worker worker -l info
运行 test_client.py 将执行以下操作(代码见 repo):
- 一个示例特征 JSON 被发送到预测端点。这些特性被硬编码在脚本的字典中。
- 如果成功,返回的任务 id 将用于轮询结果端点。在每次请求之间,虚拟客户端将等待 5 秒钟,最多尝试 5 次。
- 如果任务成功,结果(在这种情况下,属于类 1 的概率)将被打印出来。
(venv) python.exe test_client.py
0.011178750583075114
后续步骤
上面讨论的解决方案只是一个工作示例,应该通过更高级的 Celery 和 FastAPI 配置进行调整,以供全面生产使用。
另一种可能性是对整个解决方案进行分级,以便它可以轻松地部署在云基础架构上。
使用 AWS ECS 和 Docker 存储部署完美服务器
如何使用在 ECS Fargate 上运行的带有私有 Docker 注册表的 Prefect 来编排和自动化工作流
这篇文章一步一步地介绍了我如何使用私有注册中心上的 Docker 存储来部署带有 Fargate ECS 集群的完美服务器。有几篇文章介绍了使用完美的云以及不同的运行器和存储组合进行部署。当我在部署这个特定的架构时遇到一些问题,我决定在本文中详述这些步骤。

约书亚·阿拉贡在 Unsplash 上拍摄的照片
本教程结束时,我们将拥有:
- 运行在 EC2 上的完美服务器
- EC2 上运行的 ECSAgent
- 将我们的流打包到私有注册中心的 docker 映像中
- 通过 UI 和 GraphQL API 在 ECS 集群中运行流
你可以选择使用不同的代理和存储选项,这篇文章只是对许多提督选项的基本指导。虽然我不会详细介绍 Prefect 和 AWS 的概念,但是您可以找到相关文档的参考资料来帮助您。
先决条件:
- AWS 帐户
- 码头工人登记处
- 基本的 Python 技能
如果这是您第一次使用 Prefect,我建议您首先尝试在本地部署它,以便更容易掌握 Prefect 的概念。
部署完美服务器
第一步是在 EC2 实例上部署完美服务器。创建并启动 EC2 实例。当我在其上部署多个服务时,我使用了一个 g4dn.2xlarge 实例,但是如果您计划在其上只使用 Prefect,那么一个小实例就足够了。您需要更新安全规则,以允许端口 8080 上的 TCP 连接访问 UI,并允许端口 4200 访问后端。
如果您的实例上还没有 docker-compose 的话,您可能需要安装它。
接下来,在您的实例上安装 SSH 并运行:
pip install “prefect[aws]”
在此查看完美安装的其他选项。
prefect backend server
创建文件 ~/。提督/配置. toml 包含以下信息:
[server]
[server.ui]
apollo_url = “http://X.X.X.X:4200/graphql"
用您的实例公共地址替换 X.X.X.X ,因为它允许将 UI 连接到后端。
现在,您可以从以下内容开始:
prefect server start

完美服务器已启动
从现在开始,你可以通过 http://X.X.X.X:8080 从任何机器(由你的安全规则授权)连接到 UI
部署 AWS 代理
代理负责启动和监控您的运行。这里,我们将它部署在与 Prefect Server 相同的 EC2 实例上。您可以选择在第二个实例上部署它,方法是在 config.toml 文件中或通过命令行提供完美服务器的实例 IP 地址。
在这两种情况下,您都需要添加:
[cloud]
api = “[http://X.X.X.X:4200](http://x.x.x.x:4200)"
到 config.toml 文件,用 X.X.X.X 把公共 IP 地址传给提督主机。
AWS 任务需要这个变量来连接到后端(即使我们运行的是 Prefect Server 而不是 Cloud)。您可以关注这个问题以获得关于这个端点配置的更多信息。
如果您还没有 ECS fargate 集群,那么您应该现在就创建它。使用 Prefect 不需要特殊的配置,所以根据您的任务需求进行选择。请将 ARN 集群放在身边,因为您很快就会用到它。
然后,创建一个拥有权限 AmazonECS_FullAccess 的 AWS 用户,这是为代理提供权限以代表您在 ECS 集群中启动任务所必需的。将访问密钥 id 和秘密访问密钥存储在将托管代理的实例上的配置文件中:
创建一个文件 ~/。aws/config 包含:
[default]
aws_access_key_id=SECRET_KEY_ID
aws_secret_access_key=SECRET_ACCESS_KEY
region=REGION
现在,部署代理:
prefect agent ecs start -cluster arn:your-cluster-arn -label your-label

提督代理已启动
“群集”选项允许您指定将使用哪个群集来运行您的任务。“标签”选项允许您为代理提供标签。请注意,只有当代理的标签完全匹配时,代理才能拾取流,这有助于控制哪个代理将运行您的流。点击了解有关代理配置的更多信息。
检查用户界面,你可以看到你的代理正在运行。现在提督准备运行你的流量!

代理在完美用户界面上注册
创建一个流程
让我们创建一个流程。以下是 Hello world job 的一个示例:
import prefect
from prefect.run_configs import ECSRun
from prefect.storage import Docker
from prefect import task, Flow, Parameter@task
def hello_world(name):
logger = prefect.context.get(“logger”)
logger.info(“Hello “+name)with Flow(“Hello”) as flow:
name = Parameter(‘name’, default = ‘Bob’)
hello_world(name)flow.storage = Docker(
registry_url=’your-registry-url’,
image_name=”hello_container”,
base_image=”python:3.8"
)flow.run_config = ECSRun(
task_definition={
‘containerDefinitions’:[
{
‘name’: ‘flow’,
‘image’: ‘your-registry-url/hello_container:latest’,
‘repositoryCredentials’: {
‘credentialsParameter’: ‘arn:aws:secretsmanager:your-secret-arn’
}
}
],
‘networkMode’ : ‘awsvpc’,
‘memory’:’2 GB’,
‘cpu’:’1024'
},
execution_role_arn=’arn:aws:iam::your-arn-role’,
labels=[‘your-label’]
)flow.register(project_name=”Hello_Project”)
这个脚本定义了一个执行一个任务并接受一个输入参数“name”的流。
flow.storage 定义存储策略。当您想要控制流中包含哪些文件时,Docker 存储非常有用,因为其他存储选项仅存储流文件。您可以使用公共存储库,在这种情况下,您只需指定注册地址。在这里,我详细描述了私有注册中心所需的配置:
为了允许提督推送映像,在代理的实例上运行 SSH
docker login <registry_address>
并遵循身份验证步骤。然后,我们需要允许 ECS 集群提取图像:在 AWS 上创建一个秘密来存储您的注册表登录,这个 ARN 在 credentialsParameter 参数中给出。
现在,转到角色管理部分,创建一个对这个秘密具有读权限的新角色,然后在 execution_role_arn 中给出这个角色的 ARN。
ECS 代理允许两种类型的角色:执行和任务角色。根据您的流程,您可能需要更多的角色。有关角色的信息,请参见提督的文档。
这里需要 task_definition 参数,这是为私有注册中心提供凭证的唯一方式。网络模式、内存和 cpu 字段为必填字段,阅读本文档了解更多信息
如果您使用公共注册表,您可以简单地提供注册表和映像名称。
当我将图像推送到注册表时,我遇到了超时,因为我的图像太大了(在我的例子中是 2GB,这是由于机器学习的依赖性)。一个快速的解决方法是手动推送第一个图像,这样具有较大依赖性的公共层已经在我的注册表中可用,下一次推送可以重用它们。
最后,根据您的代理的标签添加标签,您的流就可以注册了。
要在您的本地机器上执行 Prefect 命令,您可以安装 Prefect 并创建 ~/。比如 EC2 实例上的文件。每个提督命令现在将连接到您的提督服务器实例。
您可以运行:
prefect create project ‘Hello_Project’
或者通过用户界面创建项目。然后,执行 python 脚本:
python flow.py
您将看到映像正在构建并被推送到您的注册表中。

注册流程
运行流程
然后,您可以直接从 UI 启动您的流程,快速运行允许您使用默认参数运行流程。

任务概述
您可以通过命令行触发它:
prefect run flow -name “Hello” -project “Hello_Project”
我们也可以通过 GraphQL API 启动这个流。这个方法允许您从任何地方触发一个流(这是您的 Prefect Server EC2 实例上的安全规则所允许的!)只需要一个 HTTP 请求。下面是一个使用流 ID 的示例脚本:
import json
import urllib.parse
import urllib.requestPREFECT__FLOW_ID = 'your-flow-id'
PREFECT__CLOUD__API='http://X.X.X.X:4200/graphql'def trigger_flow(flow_id, host):
create_mutation = """
mutation {
create_flow_run(input: { flow_id: "%s" }) {
id
}
}
""" % (flow_id) inputs = dict(flowId=flow_id)
variables = dict(input=inputs)
data = json.dumps(
dict(query=create_mutation, variables=json.dumps(variables))
).encode("utf-8") req = urllib.request.Request(host, data=data)
req.add_header("Content-Type", "application/json") resp = urllib.request.urlopen(req) return json.loads(resp.read().decode())if __name__ == "__main__":
print(trigger_flow(PREFECT__FLOW_ID, PREFECT__CLOUD__API))
更多选项此处。以下是运行该脚本后产生的日志:

流量日志
结论
我们在本文中详细介绍了如何在 EC2 上部署一个完美的服务器,以及如何使用带有私有注册中心的 Docker 存储在 ECS 集群上运行任务。现在,您已经准备好创建自己的任务了!
资源:
- https://towards data science . com/server less-data-pipelines-made-easy-with-prefect-and-aws-ECS-fargate-7 e 25 BAC b450 c # 4a 07和https://www . le Jimmy . com/distributed-data-pipelines-with-AWS-ECS-fargate-and-prefect-cloud/提供了关于 AWS 配置的更多细节
- https://docs.prefect.io/提督文档
- https://prefect-slackin.herokuapp.com/提督社区懈怠
在 Android 上部署预训练的 TF 对象检测模型
📱移动机器学习
从训练有素的检查站到安卓应用

由塞巴斯蒂安·贝德纳雷克在 Unsplash 上拍摄的照片
在移动设备上部署机器学习模型是 ML 即将开始的新阶段。视觉模型,主要是对象检测模型,已经与语音识别、图像分类、文本完成等一起进入移动设备。这些模型通常运行在支持 GPU 的计算机上,当部署在移动设备上时,有大量的用例。
为了演示如何将 ML 模型,特别是对象检测模型引入 Android 的端到端示例,我们将使用来自Victor Dibia/hand trackingrepo 的 Victor Dibia 的手部检测模型进行演示。该模型可以从图像中检测人手,并使用 TensorFlow 对象检测 API 制作。我们将使用来自 Victor Dibia 的 repo 的经过训练的检查点,并将其转换为 TensorFlow Lite ( TFLite)格式,该格式可用于在 Android(甚至 iOS、Raspberry Pi)上运行模型。
接下来,我们转到 Android 应用程序,创建运行模型所需的所有必要的类/方法,并通过实时摄像头显示其预测(边界框)。
我们开始吧!
内容
👉 1。 设置 TF 对象检测 API
👉 2。 将检查点转换为冻结图形
👉 3。 将冻结的图形转换到 TFLite 缓冲区
👉 1。 为 CameraX、Coroutines 和 TF Lite 添加依赖
👉 2。 初始化 CameraX 和 ImageAnalysis。分析器
👉 3。 实现手部检测模式
👉 4。 在相机进给上绘制边界框
作者的项目/博客
将模型检查点转换为 TFLite
我们的第一步将是将 Victor Dibia 的 repo (麻省理工学院许可证)中提供的训练模型检查点转换为 TensorFlow Lite 格式。TensorFlow Lite 提供了一个在 Android、iOS 和微控制器设备上运行 TensorFlow 模型的高效网关。为了运行转换脚本,我们需要在我们的机器上设置 TensorFlow 对象检测 API 。你也可以使用这个 Colab 笔记本在云中执行所有转换。
我推荐你使用 Colab 笔记本(特别是针对 Windows),因为我个人在这样做的时候犯了很多错误。
1.设置 TF 对象检测 API
TensorFlow 对象检测 API 提供了许多预训练的对象检测模型,这些模型可以在自定义数据集上进行微调,并直接部署到移动设备、web 或云中。我们只需要能够帮助我们将模型检查点转换成 TF Lite 缓冲区的转换脚本。
手部检测模型本身是使用 TensorFlow 1.x 的 TF OD API 制作的。因此,首先我们需要安装 TensorFlow 1.x 或 TF 1 . 15 . 0(1 . x 系列中的最新版本),然后克隆包含 TF OD API 的 tensorflow/models repo。
代码片段 1:设置 TF OD API。在作者的 GitHub 上托管。
此外,我们将克隆 Victor Dibia 的手跟踪回购来获得模型检查点,
!git clone https://github.com/victordibia/handtracking
2.将检查点转换为冻结图
现在,在[models/research/object_detection](https://github.com/tensorflow/models/tree/master/research/object_detection)目录中,您将看到一个 Python 脚本[export_tflite_ssd_graph.py](https://github.com/tensorflow/models/blob/master/research/object_detection/export_tflite_ssd_graph.py),我们将使用它将模型检查点转换成一个 TFLite 兼容的图形。这些检查点可以在[handtracking/model-checkpoint](https://github.com/victordibia/handtracking/tree/master/model-checkpoint)目录中找到。ssd代表“单次检测器”,这是手部检测模型的架构,而mobilenet表示 MobileNet ( v1 或 v2)的主干架构,这是一种专门用于移动设备的 CNN 架构。

工作流->将模型检查点转换为 TFLite 缓冲区。(图片来源:作者)
导出的 TFLite 图包含固定的输入和输出节点。我们可以在export_ssd_tflite_graph.py脚本中找到这些节点(或张量)的名称和形状。使用这个脚本,我们将把模型检查点转换成一个 TFLite 兼容图,给出三个参数,
pipeline_config_path:包含所用 SSD Lite 型号配置的.config文件路径。trained_checkpoint_prefix:我们希望转换的已训练模型检查点的前缀。max_detections:要预测的包围盒的数量。这很重要,因为它是添加到图表中的非最大抑制后处理操作的重要参数。
代码片段 2:将模型检查点转换为 TFLite 兼容图。在作者的 GitHub 上托管。
脚本执行后,我们剩下两个文件,tflite_graph.pb和tflite_graph.pbtxt,它们是 TFLite 兼容的图形。
3.将冻结的图形转换到 TFLite 缓冲区
现在我们将使用第二个脚本(或者更准确地说,一个实用程序)将步骤 2 中生成的冻结图形转换成 TFLite 缓冲区(.tflite)。由于 TensorFlow 2.x 排除了Session和Placeholder的使用,我们无法在这里将冻结的图形转换为 TFLite。这也是我们在第一步安装 TensorFlow 1.x 的原因之一。
我们将使用[tflite_convert](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/python/tflite_convert.py)实用程序将冻结的图形转换成 TFLite 缓冲区。我们也可以使用[tf.lite.TFLiteConverter](https://www.tensorflow.org/versions/r1.15/api_docs/python/tf/lite/TFLiteConverter) API,但是现在我们将坚持使用命令行实用程序。
代码片段 3:将冻结的图形转换成 TFLite 缓冲区。在作者的 GitHub 上托管。
一旦执行完成,您将在outputs目录中看到一个model.tflite文件。为了检查输入/输出形状,我们将使用[tf.lite.Interpreter](https://www.tensorflow.org/api_docs/python/tf/lite/Interpreter)加载 TFLite 模型,并调用.get_input_details()或.get_output_details()分别获取输入和输出细节。
提示:使用
pprint获得漂亮的输出。
代码片段 4:检查 TFLite 模型的输入和输出形状。在作者的 GitHub 上托管。
在 Android 中集成 TFLite 模型
一旦我们得到了 TFLite 模型及其输入和输出形状的所有细节,我们就可以在 Android 应用程序中运行它了。在 Android Studio 中创建一个新项目,或者随意派生/克隆 GitHub repo 来开始!
1.为 CameraX、协程和 TF Lite 添加依赖项
因为我们要在直播摄像头上检测手,我们需要在我们的 Android 应用程序中添加 CameraX 依赖项。类似地,为了运行 TFLite 模型,我们将需要tensorflow-lite依赖项以及 Kotlin 协程依赖项,以帮助我们异步运行模型。在应用程序级的build.gradle文件中,我们将添加以下依赖项:
代码片段 5:为 CameraX、Coroutines 和 TensorFlow Lite 添加依赖项。在作者的 GitHub 上托管。
确保你添加了aaptOptions{ noCompress "tflite" },这样模型就不会被系统压缩来缩小你的应用程序。现在,为了在我们的应用程序中放置 TFLite 模型,我们将在app/src/main下创建一个assets文件夹。将 TFLite 文件(.tflite)粘贴到该文件夹中。

将“model.tflite”放在资产文件夹中。(图片来源:作者)
2.初始化 CameraX 和 ImageAnalysis。分析者
我们将使用 CameraX 包中的一个[PreviewView](https://developer.android.com/reference/kotlin/androidx/camera/view/PreviewView)向用户显示实时摄像机反馈。在它上面,我们将放置一个覆盖图,称为[BoundingBoxOverlay](https://github.com/shubham0204/Hand_Detection_TFLite_Android/blob/main/app/src/main/java/com/shubham0204/ml/handdetection/BoundingBoxOverlay.kt),在摄像机画面上绘制边界框。我不会在这里讨论实现,但是您可以从源代码或我的这个故事中了解它,
https://proandroiddev.com/realtime-selfie-segmentation-in-android-with-mlkit-38637c8502ba
因为我们要预测实时帧数据上的手的边界框,所以我们还需要一个ImageAnalysis.Analyzer对象,它返回来自实时摄像机馈送的每一帧。请看来自[FrameAnalyzer.kt](https://github.com/shubham0204/Hand_Detection_TFLite_Android/blob/main/app/src/main/java/com/shubham0204/ml/handdetection/FrameAnalyser.kt)的片段,
代码片段 FrameAnalyser 类。在作者的 GitHub 上托管。
[BitmapUtils](https://github.com/shubham0204/Hand_Detection_TFLite_Android/blob/main/app/src/main/java/com/shubham0204/ml/handdetection/BitmapUtils.kt)包含一些有用的静态方法来操作Bitmap。isFrameProcessing是一个布尔变量,它决定了输入帧是否必须被丢弃或传递给模型。正如您可能观察到的,我们在CoroutineScope中运行模型,因此您将不会观察到模型产生推理时的延迟。
3.实现手部检测模型
接下来,我们将创建一个名为[HandDetectionModel](https://github.com/shubham0204/Hand_Detection_TFLite_Android/blob/main/app/src/main/java/com/shubham0204/ml/handdetection/HandDetectionModel.kt)的类,它将处理所有的 TFLite 操作并返回给定图像的预测(作为Bitmap)。
代码片段 7:创建“HandDetectionModel”类。
我们将在上面的代码片段中分别理解每个术语,
modelImageInputDim是我们模型的输入图像的大小。我们的模型将接受大小为 300 * 300 的图像。maxDetections代表我们的模型做出的预测的最大数量。它决定了boundingBoxesTensorShape、confidenceScoresTensorShape、classesTensorShape和numTensorShape的形状。outputConfidenceThreshold用于过滤我们的模型做出的预测。这不是 NMS,但我们只拿分数大于这个阈值的盒子。inputImageProcessorQuantized和inputImageProcessorNonQuantized是TensorOperator的实例,它们将给定的图像调整到modelImageInputDim*modelInputImageDim的大小。在量化模型的情况下,我们用平均值和标准偏差都等于 127.5 来标准化给定的图像。
现在,我们将实现一个方法run(),它将获取一个Bitmap图像并以List<Prediction>的形式输出边界框。[Prediction](https://github.com/shubham0204/Hand_Detection_TFLite_Android/blob/main/app/src/main/java/com/shubham0204/ml/handdetection/Prediction.kt)是一个保存预测数据的类,比如置信度得分和边界框坐标。
代码片段 8:hand detection model 类。
confidenceScores、boundingBoxes、classes和numBoxes是保存模型输出的四个张量。processOutputs方法将过滤边界框,只返回那些置信度得分大于阈值的框。
代码片段 9:过滤我们模型的输出。
4.在相机馈送上绘制边界框
一旦我们收到了边界框,我们想把它们画在摄像机的画面上,就像我们用 OpenCV 做的那样。我们将创建一个新的类[BoundingBoxOverlay](https://github.com/shubham0204/Hand_Detection_TFLite_Android/blob/main/app/src/main/java/com/shubham0204/ml/handdetection/BoundingBoxOverlay.kt)并将其添加到[activity_main.xml](https://github.com/shubham0204/Hand_Detection_TFLite_Android/blob/main/app/src/main/res/layout/activity_main.xml)中。这个类看起来像,
代码片段 BoundingBoxOverlay 类。
仅此而已!我们刚刚在一个 Android 应用程序中实现了一个手部检测器!你可以在检查完所有代码后运行这个应用程序。

运行手部检测模型的 Android 应用程序。每个框中间的文本表示该预测的可信度。
结束了
希望你喜欢这个故事!欢迎在【equipintelligence@gmail.com】或在下面的评论中发表你的想法。
亲爱的开发者,祝你有美好的一天!
在谷歌云函数上部署 python 函数
部署 python 函数从未如此简单

安德里克·朗菲尔德在 Unsplash 上拍摄的照片
介绍
部署应用程序总是一个需要分析的过程。应用程序的复杂性、大小等等都是影响应用程序部署位置和方式的因素。
当您的应用程序很小,并且不需要大量资源时,如大型数据库查询和硬处理,您可以使用 Google Cloud 功能来部署它。不需要设置一个虚拟机和使用气流(举例来说),你只需要准备你的代码并把它发送到 GCF,google 会处理所有需要的资源来部署和运行你的功能。
总之,GCF 是一个工具,它允许您部署“可伸缩随用随付功能即服务(FaaS ),无需服务器管理就能运行您的代码。”一些功能包括:
- 没有要供应、管理或升级的服务器;
- 根据负载自动缩放;
- 集成监控、记录和调试功能;
- 基于最小特权原则的角色和每个功能级别的内置安全性;
- 针对混合云和多云场景的关键网络功能;
- 一个不错的免费层,允许你免费使用它;
部署
设置功能
使用谷歌云功能进行部署的方式有很多种。我将在本文中展示更简单的方法,在下一篇文章中,我将展示我更喜欢的方法(通过与 github 的持续集成)。
- 首先,进入谷歌控制台,在左边栏选择云函数,然后点击创建一个函数。应该会出现下面的模式

这里有些字段应该解释一下:
- 功能名称:您要部署的功能的名称。选择合适的名称很重要,因为它将帮助您在需要时找到您的功能。
- 区域:将部署该功能的地方。将函数的区域设置为应用程序的相同区域。
- 触发器:你的函数将如何被调用。有很多方法可以调用你的函数。这里我会选择 HTTP,这是最通用的一个。
- URL: 你的功能在 google 上的地址;
- 验证:您的函数是否需要验证才能被调用。我将在这里检查允许未经验证的调用。
之后,单击保存,然后单击运行时、构建、连接…

这里我们有很多字段,每个字段可能需要一篇文章。我将尝试只对内存,超时和自动缩放。在接下来的文章中,我们将深入讨论其他领域。
- 分配的内存:为运行该功能而分配的 ram 内存。最大值是 8 Gb,这就指向了我上面说的事实:GCF 不是针对需要很多资源的函数。我会把它设置在 256 Mb。这对我们的测试来说足够了
- 超时:允许运行您的功能的最长时间。
“如果云功能在超时期限内没有完成,那么该功能将被终止。默认值为 60 秒,但可以在 1 秒到 540 秒(9 分钟)之间。一般来说,我将它设置为最大值,因为 GCF 具有冷启动功能,第一次调用该函数会比接下来的调用慢得多。” - 自动缩放:你是否会为你的函数创建更多的实例,以允许多个调用同时进行。"为了提高性能,您可以将最小实例数设置为大于 0。您还可以为用例设置最大实例数,例如限制成本。突然的流量高峰可能会导致暂时超出限制。留空或设置为 0 可清除此控件,并根据需要自动创建新实例。
源代码
之后,单击下一步,应该会出现如下页面:

- 运行时:源代码的语言。将其更改为您在函数中使用的 python 版本。
- 入口点:代码执行过程中首先调用的 python 函数。
- 源代码:你的代码的来源。让我们在这个例子中使用内联编辑器,但是在第二篇文章中我们将使用云存储库。
让我们在部署函数之前检查一下代码:

正如我们所见,默认情况下我们有两个文件,main.py 和 requirements.txt。在 requirements 中,我们需要编写运行代码所需的库及其版本。在 main.py 中,该示例接收一个 HTTP 请求,并检查请求中是否存在字段消息。如果是,它将返回消息(和文本)。否则,它返回 Hello World。
现在,点击按钮展开,等待展开过程结束。

允许未经授权的访问
现在我们需要允许任何人调用这个函数:

点击页面左侧的复选框选择您的功能。点击权限后。
点击添加委托人,输入 allUsers ,在选择角色,选择云函数调用者,如下图。这样做,你将允许互联网上的任何人访问你的功能。有很多方法可以让这个过程更安全,但是我们暂时先不做。

之后,会出现一个窗口。点击允许..
测试它
现在,让我们使用一个简单的脚本来测试它,如下所示:

URL 保存了我们函数的地址。可以在 gcp 控制台点击我们的功能。
代码的第一部分只是一个 get 请求,所以它不发送任何信息。因此,request_json(来自 main.py)为空,因此我们的函数返回 Hello World!。在代码的第二部分,我们发出一个 post 请求,并通过 json 发送一条消息。在这种情况下,我们的函数返回了消息,这是正确的,因为现在 request_json 不再是空的,并且具有字段 message。
结论
Google cloud functions 是一项让简单功能的部署过程变得更加简单的服务。部署一个功能的完整过程可以在不到 1 小时的时间内完成,当您需要设置一个简单功能的快速部署时,这是一个很好的工具。在通过 GCF 部署一个功能的过程中,可以配置很多东西,但是大多数都很容易理解和配置。
在下一篇文章中,我们将讨论使用 git hub 在 google 云功能上的持续集成。在那里见!
参考
【https://cloud.google.com/functions
将 Python GitHub 操作部署到市场
将 Python 脚本作为没有 Dockers 的操作运行

杰佛森·桑多斯在 Unsplash 上拍摄的照片
查看此处开发的动作:
https://github.com/kaustubhgupta/readme-projects-display
为什么是 Python?
我使用 GitHub actions 已经有一段时间了,我相信它比目前的用法有更大的潜力。我见过很多 GitHub 动作自动化任务的用例,但是一个值得注意的事情是,这些动作主要是使用 Javascript 和 Dockers 完成的。如果你在 GitHub 中搜索“ GitHub Action ”这个词,你会看到一长串使用或者做出这个动作的库。根据所选的编程语言,结果如下:

来自 GitHub 搜索结果的截图(数字在 28/03/21)
这些数字清楚地表明,使用 Python 的存储库非常少。主要原因是 GitHub 在为市场构建动作的同时正式支持 Docker 和 Javascript。

来自行动文件的截图
这并不意味着不支持其他语言,但是它们的解决方法很复杂。需要对 Dockers 有很好的理解,如果动作使用当前 repo 中的文件,那么如何管理动作的路径。
在本文中,我将向您展示在没有 Dockers 的情况下发布基于 Python 的 GitHub 操作的最佳方式!
形势
我在本文中构建的 GitHub 动作是为了用用户在其 GitHub 帐户上托管/推送的项目信息更新 GitHub 概要自述文件。这个特殊的自述文件显示在公开的个人资料上,这已经成为一种趋势,每个人都试图让它尽可能吸引人。GitHub 统计数据、最新的博客帖子显示或提交活动是用户已经集成到他们的个人资料中的一些著名的工作流类型。

统计数据示例(作者图片)
我想创建一个类似的动作,更新用户的项目信息,如星星,描述中的任何变化,或任何其他新的项目添加。让我们看看我是如何制作基本工作流程的。
编码时间!
逻辑非常简单。由于人们不能从 100 个储存库中确定以下哪些储存库有资格显示在简档部分上,因此这项工作必须由用户手动完成。我们的工作是将“项目”主题添加到每个存放项目文件的存储库中。这个标签将帮助我筛选出将包含在项目部分中的存储库。

标记为项目的我的存储库示例
接下来,我需要提出这样的逻辑,即每次触发动作时,只修改自述文件的特定部分,而不是整个文件。为此,我参考了的自述工作流程。我修改了一般用法的逻辑。另外,在我之前的项目中,还有一点被忽略了,那就是只有当内容发生变化时,才应该提交。这部分采取了一系列的点击和试验,想出了一个解决方案。整个脚本并没有花太多时间来编码,下面是代码的样子:
我从用户那里获得 4 个输入:GitHub 访问令牌、readme 文件的名称、检出存储库的路径(我将在下面详细讨论)以及存储库描述的最大字符数。所有这些输入都来自命令行。下一步也是最后一步是将脚本作为工作流中的操作运行。
操作、工作流和发布
我在以前的一篇文章中描述了动作和工作流之间的区别,所以我在这里简单介绍一下。动作是任务,可以是称为工作流的任何更大任务的一部分。实际上,配置文件自述文件可以有一个工作流,其中包含多个更新不同部分的操作。我上面展示的脚本实际上是一个动作,在它公开后可以成为任何工作流的一部分。
GitHub 制作了一个流程,用于制作一个动作供其他用户使用。必须在动作存储库的根目录下创建一个名为 action.yml 的文件,该文件包含动作的所有输入输出。此外,它还定义了操作运行的环境。这就是 Python 脚本需要额外步骤的地方。
在运行参数中,我们需要使用组合。composite 采用强制步骤参数,steps 参数采用两个强制参数:run 和 shell。YAML 文件最好的部分是它们本质上是分层的,缩进定义了参数的级别。下面是我如何定义我的 action.yml runs 参数:
重要的事情:无论你什么时候公开动作,文件的路径都不会一样。要在操作运行时获取文件的确切路径,可以使用 github.action_path 变量。这些变量被称为上下文信息,GitHub 提供了大量的上下文变量,可以在运行操作时使用。查看这个文档获取完整列表。
我使用了 action_path 和 workspace 路径,因为这两个路径服务于不同的目的。动作路径是存储动作文件的位置。它们存储在:
/home/runner/work/_ actions/{ git _ username }/{ action _ repo }/master/
工作区路径是当前存储库被检出的地方,在那里触发了这个动作(称之为克隆的)。
/home/runner/work/{检查的回购名称}/{检查的回购名称}/
来试试动作吧!
既然动作是公开的,我们可以在任何配置文件中使用它。此操作要求您在自述文件中添加特殊注释:
<!-- PROJECTS START -->
<!-- PROJECTS END -->
接下来,创建一个目录:
.github/workflows/<any_name>.yml
并粘贴以下起始代码:
现在,该特定部分将使用您的项目信息进行更新!

结论
使用 Github 动作、上下文变量和触发器可以实现很多事情。这个特别的动作是受博客-文章-工作流程的启发。
查看我的其他以 Python 为中心的文章:
💔-ways-to-convert-python-app-into-apk-77f4c9cd55af>
使用 AWS Lambda 部署无服务器空间转换器模型
关于如何部署 NER 变压器模型无服务器的分步指南

约书亚·索蒂诺在 Unsplash 上拍摄的照片
介绍
由于 transformer 无与伦比的性能,它已成为许多 NLP 任务的基本工具,每天都有各种有用且有影响力的 NLP 模型被创建出来。然而,许多 NLP 实践者发现将模型部署到生产中是一个挑战。根据这份报告,90%的机器学习模型从未投入生产。
模型部署使您能够在服务器环境中托管您的模型,例如,当被 API 调用时,它可以用于输出预测。
在本教程中,我将向你展示如何将 NER 空间转换器模型推送到 Huggingface,并在 AWS Lambda 上部署该模型来运行预测。
根据 AWS 网站:
“AWS Lambda 是一种无服务器计算服务,让您无需配置或管理服务器、创建工作负载感知集群扩展逻辑、维护事件集成或管理运行时即可运行代码。有了 Lambda,您几乎可以为任何类型的应用程序或后端服务运行代码——所有这些都无需管理。”
部署模型而无需管理后端服务器是一个游戏规则改变者。它将使没有 devops 资源的开发人员和小型初创公司能够开始部署准备用于生产的模型。
以下是我们将要遵循的步骤:
- 在 Huggingface 中部署一个经过训练的空间变形器模型
- 将模型存储在 S3
- 在 AWS Lambda 中部署模型
- 运行 AWS Lambda 函数,根据用户输入输出预测
在 Huggingface 中部署空间变压器模型
在本教程中,我们对变压器 NER 模型 SciBert 进行了微调,以从科学摘要中提取材料、流程和任务。使用 UBIAI 文本注释工具完成注释。我们遵循了在我之前的文章中介绍的相同方法,我们利用 google colab 来训练模型。训练模型后的下一步是在 huggingface 上托管它,这样它就可以被 API 访问。更多关于如何将空间模型推送到 huggingface 的信息,请查看这个链接。
首先,从 pip 安装 spacy-huggingface-hub:
pip install spacy-huggingface-hub
从经过训练的空间管道构建一个. whl 文件(确保事先创建输出目录):
huggingface-cli login
python -m spacy package ./model_science_scibert/model-last ./output --build wheel
将砂轮锉推入轮毂:
cd ./output/en_scibert_ScienceIE-0.0.0/dist
python -m spacy huggingface-hub push en_scibert_ScienceIE-0.0.0-py3-none-any.whl
让我们检查一下模型是否已经成功上传到 Huggingface:

作者图片
既然这个模型已经被推送到 huggingface 库中,我们可以在一个科学摘要上测试它了:

作者图片
太棒了—它像预期的那样工作!我们现在可以直接用 API 查询模型:
import requests
API_URL = "https://api-inference.huggingface.co/models/UBIAI/en_scibert_ScienceIE"
headers = {"Authorization": "[API Token]"}
def query(payload):
response = requests.post(API_URL, headers=headers, json=payload)
return response.json()
output = query({"inputs": "*We report exptl. and theor. evidence for the formation of chiral bobbers-an interfacial topol. spin texture-in*"})
下一步是将模型与 AWS Lambda 集成,这样我们就不会受到 Huggingface 的 API 使用的限制。
在 AWS Lambda 上部署:
在本节中,我们将在 S3 上存储训练好的模型,并将其导入 lambda 函数进行预测。以下是步骤:
- 将训练好的模型存储在 S3 上(或者,我们可以直接从 huggingface 库下载模型)
- 基于容器图像设置推理 Lambda 函数
- 将容器图像存储在您帐户内的 Amazon 弹性容器注册库 (ECR)中
- 在 Amazon 弹性文件系统存储上导入并缓存训练好的模型,以改善推理延迟
- 对 AWS Lambda 运行预测
为了加快这个过程,我们按照 AWS 的教程自动提供基于容器图像的 Lambda 函数。首先,让我们按照教程中所示克隆回购:
git clone https://github.com/aws-samples/zero-administration-inference-with-aws-lambda-for-hugging-face.git
安装所有要求:
pip install -r requirements.txt
安装自动气象站 CDK:
npm install -g aws-cdk
接下来,我们将添加推理文件以从我们的模型中获得预测。
将目录更改为推理文件夹,并添加一个新的 python 文件来运行模型,对于本教程,我添加了 science_ie.py 文件:

作者图片
现在,我们将在 science_ie.py 中创建两个函数:
- 一个从 S3 下载模型的函数,将其解压缩并存储在缓存文件夹/mnt/hf_models_cache 中。
- 第二个函数查询我们的模型并返回提取的实体。
import os
import urllib.request
import spacy
import spacy_transformers
from zipfile import ZipFile
from pathlib import Path
#Download the model from S3
def download(model, dest):
save_path = Path(dest) / model
if not os.path.exists(save_path):
print(**'Downloading...'**)# Enter url path to the model on S3
url = **f'https://[bucket name].s3.us-west-2.amazonaws.com/**{model}**.zip'** filename = Path(dest) / **f'**{model}**.zip'** res = urllib.request.urlretrieve(url, filename)
with ZipFile(filename, **'r'**) as f:
print(dest)
f.extractall(path=dest)
print(**'finished extracting'**)
dirname = model.split(**'-'**)[0]
return save_path
#Handler function for predictions
def handler(event, context):
doc = nlp(event[**'text'**])
response = [
{
**'text'**: ent.text,
**'label'**: ent.label_,
**'start'**: ent.start_char,
**'end'**: ent.end_char
}
for ent in doc.ents
]
return response
model = **'model-last'** mnt_path = **'/mnt/hf_models_cache'** model_path = download(model, mnt_path)
nlp = spacy.load(mnt_path)
我们现在准备部署。只需运行下面的命令来部署 CDK 应用程序(注意:我在运行下面的命令时发现了一个错误,如果发生这种情况,只需在 cdk.json 文件的“app”行中用 python 替换 python 3:“python app . py”):
cdk bootstrap
cdk deploy
一旦部署开始,我们将开始看到进展,这将需要一些时间来完成全面部署。完成后,转到 AWS 控制台中的 AWS Lambda 并选择 test 选项卡:

作者图片
按如下方式输入测试文本,然后按下测试按钮:
{
"text": "*We report exptl. and theor. evidence for the formation of chiral bobbers-an interfacial topol. spin texture-in FeGe films grown by mol. beam epitaxy. After establishing the presence of skyrmions in FeGe/Si(111) thin-film samples through Lorentz transmission electron microscopy and the topol. Hall effect, we perform magnetization measurements that reveal an inverse relationship between the film thickness and the slope of the susceptibility (d?/dH). We present evidence for the evolution as a function of film thickness L from a skyrmion phase for L<LD/2 to a cone phase with chiral bobbers at the interface for L>LD/2, where LD?70nm is the FeGe pitch length. We show using micromagnetic simulations that chiral bobbers, earlier predicted to be metastable, are in fact the stable ground state in the presence of an addnl. interfacial Rashba Dzyaloshinskii-Moriya interaction.*"
}
以下是预测:
[
{
"text": "exptl. and theor. evidence for the formation of chiral bobbers",
"label": "TASK",
"start": 10,
"end": 72
},
{
"text": "FeGe films",
"label": "MATERIAL",
"start": 111,
"end": 121
},
{
"text": "skyrmions",
"label": "MATERIAL",
"start": 186,
"end": 195
},
{
"text": "FeGe/Si(111) thin-film samples",
"label": "MATERIAL",
"start": 199,
"end": 229
},
{
"text": "transmission electron microscopy",
"label": "PROCESS",
"start": 246,
"end": 278
},
{
"text": "topol. Hall effect",
"label": "PROCESS",
"start": 287,
"end": 305
},
{
"text": "magnetization measurements",
"label": "PROCESS",
"start": 318,
"end": 344
},
{
"text": "film",
"label": "MATERIAL",
"start": 393,
"end": 397
},
{
"text": "evolution as a function of film thickness",
"label": "TASK",
"start": 482,
"end": 523
},
{
"text": "skyrmion phase",
"label": "PROCESS",
"start": 533,
"end": 547
},
{
"text": "chiral bobbers",
"label": "MATERIAL",
"start": 580,
"end": 594
},
{
"text": "FeGe pitch length",
"label": "MATERIAL",
"start": 645,
"end": 662
},
{
"text": "micromagnetic simulations",
"label": "PROCESS",
"start": 679,
"end": 704
},
{
"text": "chiral bobbers",
"label": "MATERIAL",
"start": 710,
"end": 724
}
]
瞧,我们从 AWS Lambda 上的模型中得到了预测,而无需担心设置服务器基础设施。
结论:
在本教程中,我们演示了如何在 Huggingface 上部署一个经过训练的 transformer 模型,将其存储在 S3 上,并使用 AWS lambda 函数获得预测,而无需设置服务器基础架构。
如果您有任何问题,请不要犹豫,在下面提问或发送电子邮件至 admin@ubiai.tools。
如果你喜欢这篇文章,请喜欢并分享!
在 Twitter 上关注我们 @UBIAI5 或订阅这里!
在 Google Cloud 上部署简单代码
自从我从学术界转到私营部门,我意识到企业面临的一个极端挑战是开发过程的可伸缩性。换句话说,构建流程(可能是简单的数据流、仪表板或更复杂的 ML 管道)是一回事,但部署流程以便执行和监控是可调度的、自动的且易于调试是另一回事。
在这篇文章中,我将介绍我在一个项目需求中使用的一种方法(一个每天更新的仪表板),以及我如何使用谷歌云平台(GCP)来扩展项目以允许自动更新。
商业案例
在这个项目中,我被要求提供一个交互式仪表板,用于监控一系列 KPI 和其他与公司数字通信相关的指标。
像往常一样,第一步包括查询数据位置、构建数据管道,最后构建仪表板。我有另一个帖子更侧重于这种过程,所以我不会在这里关注这方面。
一旦构建了管道,我需要每天早上执行它,以便向仪表板提供新的数据。真烦人。我需要开发一个可扩展的系统,允许管道按计划执行,并允许用户监控管道是否被正确执行。
谷歌云平台
GCP 是一个了不起的工具,不断得到改进和功能。我自己学会了如何使用 GCP,所以不要把我的过程当成最佳实践。可能还有其他我不知道的功能,可以让你以更有效的方式运行这个过程。
第一步是将管道导出到 GCP,在云上运行。
GCP 的出口管道
我首先在 GCP 上的AI Platform / Notebooks下创建了一个虚拟机实例。这个部分提供了JupyterLab接口,允许您在一个笔记本框架中探索数据。
创建实例后,您可以启动虚拟机。请注意,您将会收到运行实例的账单,所以请确保您在完成后停止了它们。

显示笔记本界面的屏幕截图。该图显示了三台虚拟机,其中第一台已经启动。图片作者。
一旦进入JupyterLab界面,你就可以打开一个终端,Git 克隆你的库。我假设读者知道 Git,并把它的库放在某种在线存储库上。

图片作者。
一旦您的 repo 被克隆,您将获得包含您的库的文件夹,它被复制到您的虚拟机上,在我的例子中,它包含几个文件和文件夹,如下所示:

图片作者。
现在你的代码已经在云上了,你可以在虚拟机上运行所有的计算,并确保一切按预期运行。如果您的代码是在不同的操作系统下编写的,可能会有一些问题,所以在这里重新启动代码并确保输出是需要的总是一个好主意。
使用 Docker 来封装你的代码
Docker 本身是一种轻量级虚拟机,它包含了运行应用程序所需的所有组件。你可以把它看作一个气泡,一个应用程序的快照,它允许你和其他人在完全相同的条件下在其他地方重新运行你的代码。你可以在这里找到更多关于 Docker 的信息,现在我假设你知道使用 Docker 的基本知识
既然你知道基础知识;),你知道你应该使用一个Dockerfile来具体说明如何构建和运行你的容器。Dockerfile是一个文本文件,用这个术语命名,包含运行应用程序所需的所有命令。
您可以在文件夹根目录下创建一个 docker 文件,并根据项目需要添加命令。在我的情况下,它需要以下内容:
- 在 Python 环境中运行—
FROM Python: 3.8 - 复制容器中的一系列文件,包括:
- 全部。源文件中包含的 py 文件—
COPY ./src/jhl001_digital_communication ./ - requirements.txt 中包含的项目依赖关系—
COPY ./requirements.txt ./requirements.txt - 谷歌令牌凭证文件—
COPY ./dat_ini/mycreds.txt ./mycreds.txt - Google 帐户的访问密钥—
COPY ./dat_ini/client_secrets.json ./client_secrets.json
3.安装必要的库
RUN pip install -r requirements.txt
4.运行 Python 文件
ENTRYPOINT ["python", "run_pipe_all.py"]
文件run_pipe_all.py包含我需要执行的管道,都在一个文件中。提醒一下,这条管道从不同的位置获取数据,对其进行处理,然后在另一个位置将其导出,以提供给 Tableau 仪表板。
文件看起来就像这样,有几行注释,是我测试后不需要的文件。

DockerFile 示例。图片作者。
不错!所以构建容器的一切都准备好了,您可以通过在终端中运行下面一行来轻松完成
docker build . -t gcr.io/PROJECT_NAME/CONTAINER_NAME:latest
在我的例子中,我使用了一个测试项目(你可以在 GCP 的项目部分找到你的项目的 ID ),我将容器命名为dashboard。:latest通知 Docker 容器应该被构建为最新版本。

图片作者。
现在,您已经将应用程序/代码容器化了。运行容器应该和在 VM 中运行最后一行代码一样,其中所有的依赖项都已经安装在 Python 环境中
您可以通过在终端中键入以下命令进行测试
docker run -ti gcr.io/PROJECT_NAME/CONTAINER_NAME:latest

图片作者。
在我的例子中,执行 python 文件和管道,我把它们放在一个文件中。
很好!您的代码现在已经打包好了,您可以使用这个容器与其他人共享它,或者通过这个接口轻松地执行它。
现在,让我们看看是否可以使用其他 GCP 特性来分解这段代码,并定期执行它
将容器推送到 Google 容器注册表
为了共享你的容器,你可以使用下面的命令行push它:
docker push gcr.io/PROJECT_NAME/CONTAINER_NAME:latest
这将把您的容器放在容器注册表中,以便从其他接口访问它

图片作者。
如果你现在进入容器注册(左 GCP 工具栏),你应该看到你的容器位于列表中

图片作者。
你可以看到我的容器,它的latest图像,现在出现在容器注册中。仅供参考,docker 映像是运行容器时需要构建的蓝图。
很好,现在您已经推送了您的容器映像。让我们使用 GCP 的其他特性来安排它的执行和监控!
谷歌计算引擎(GCE)
一旦您的映像出现在注册表中,下一步就是在 GCE VM 上部署容器。GCE 的一个很好的特性是,它会自动提供一个带有 Docker 安装程序的容器优化操作系统。这意味着一旦 VM 启动,就会执行容器。
下面,您可以看到我创建的名为update-dashboard的新 VM 来托管容器映像。
注意在AT Platform / Notebook接口下创建的 VM dashboard-communication是如何出现在 GCE 中的。

图片作者。
为此:
- 在 GCE 上创建一个虚拟机,并设置所需的区域
- 在容器部分,选中将容器映像部署到这个虚拟机实例
- 提供容器图像。这是集装箱成像仪的实际位置,在我的例子中是 fcr.io/gcp-test-project-260513/dashboard:latest 的
- 我将重启策略设置为失败并且以特权身份运行设置为真**
- 最后,勾选为标准输入分配一个缓冲区和分配一个伪 TTY* 框,因为我们需要这些选项链接到容器。*

图片作者。
现在,您的容器托管在一个 GCE VM 中。
现在让我们使用两个 GCP 组件,Cloud Scheduler和Cloud Functions。我使用这个 Google 文档来实现这些功能,这很容易理解。
创建云函数
下面的步骤摘自谷歌文档,但是我把它们放在这里是为了保持一致
要创建云函数来启动虚拟机实例,请执行以下操作:
- 转到云功能页面
- 创建功能
- 将函数 Nae 设置为 startInstancePubSub
- 保留区域的默认值。
- 对于触发器类型,选择云发布/订阅。
- 对于选择云发布/订阅主题,请选择创建主题…
- 应该会出现一个新的发布/订阅主题对话框。
- 在主题 ID 下,输入开始实例事件。
- 单击创建主题以完成对话框。
- 单击触发器框底部的保存。
- 单击页面底部的下一步。
- 对于运行时,选择 Node.js 10。
- 对于入口点,输入 startInstancePubSub。
- 在代码编辑器的左侧,选择 index.js。
- 用下面的代码替换启动代码,您将在这里和下面找到。

16.在代码编辑器的左侧,选择 package.json。
17.将启动代码替换为您将在此处和以下找到的代码。

18.现在,您可以单击“部署”。
Stop 函数(如果你需要的话)是按照相同的步骤创建的,查看 Google 文档,找到正确的代码片段。
准备好这两个功能后,您应该会在主窗格中看到它们:

图片作者。
您可以通过进入函数并进入测试模式来测试该函数是否正确启动了 VM。还是那句话,跟着 Google Doc 走,信息量很大;)
使用 Google Scheduler 来控制你的容器/虚拟机
最后一步是使用 Google Scheduler 来定义 VM 应该何时启动和停止。因为容器是在 VM 启动时启动的,所以启动它将自动启动您的代码。
在 Google 日程安排页面上:
- 创建作业
- 定义名称
- 输入执行频率
- 这遵循一个非常容易理解的 CRON 作业语法。如果你不熟悉那个,请检查[这个]。
- 在目标中选择
Pub/Sub - 创建一个主题,如
start-VM-instance
现在,您需要指定需要执行的虚拟机的标签。这是通过在 GCE 中查找虚拟机的标签来完成的。转到您之前在 GCE 中创建的 VM 实例,并查找分配的标签。在这种情况下,它是:container-vm=cos-stable-85-13310-1041-24

图片作者。
7.因此,在 Cloud Scheduler 的 payload 部分,输入以下内容:
- {"zone":"europe-west1-b "," label ":" container-VM = cos-stable-85–13310–1041–24 " }
您最终会看到这样一个窗口,在我的例子中,它定义了一个每天早上 6:35 开始的作业:

图片作者。
您可以通过采取类似的步骤来创建停止调度程序作业。
这将为您带来两个计划作业:

图片作者。
您也可以通过按下启动和稍后停止作业上的RUN NOW按钮来测试作业是否正常工作。他们应该分别启动和停止您的 GCE 虚拟机。
搞定了。
就是这样!我们在 GCP 上导入了一个回购协议,将其打包,并使用 GCP 的功能来安排其执行。通过访问 GCE 虚拟机中的Logs窗口,可以相对容易地完成对流程的监控:

图片作者。
此窗口将允许您观察代码的日志。正如你从上面的截图中看到的,我可以看到print命令在每一行中输出,这对于首次展示和监控你的应用程序是如何部署和执行的非常有用。
在后续的帖子中,我将讨论如何使用 Python 从 GCP 导出和导入文件。保持联系!
附加参考
以下是我在执行这个项目时使用的一些参考资料
- 关于如何使用我在这里描述的一些 GCP 组件的很好的教程。
- 另一个教程更详细地介绍了在 GCP 上部署应用的细节
大规模部署时间序列预测模型(第一部分)
如何利用 Flow-Forecast、Docker、Terraform、Airflow、Kubernetes 和 ONNX 轻松地将深度时间序列模型扩展到生产工作负载。

部署机器学习模型仍然是许多公司的症结所在,时间序列预测模型也不例外。据 VentureBeat 报道,大约 90%的车型从未投入生产。虽然这可能有许多原因(例如,模型本质上是探索性的,最终目标不是生产,等等),但足以说许多有前途的模型在这个阶段被搁置。对于经常有许多活动部件的深度学习模型来说尤其如此。
在本文中,我们将讨论将时间序列预测模型用于生产的一般技术。然后,我们将更具体地探讨如何使用流量预测训练 PyTorch 模型,为部署做好准备。在本系列文章的第二部分中,我们将实际描述使用 FastAPI、Docker、Terraform 和 Kubernetes 部署示例模型。最后,在第三部分中,我们将监控它们,并展示如何定期更新它们,以及如何根据增加的工作负载进行扩展。另一个系列将处理深度学习模型的分布式训练。
考虑
培训前
正如我在之前的文章中提到的,在你选择一个模型进行训练之前,你应该权衡你的最终目标。可解释性重要吗?我需要什么样的推理速度?我需要置信区间吗?还是只有一个预测值就好?这些考虑和分析应该告知您最初选择训练哪个模型。
其次,在培训前规划阶段,您还应该考虑应用程序将如何与现有软件基础架构交互,以及它将接收何种类型的时态数据。例如,如果模型需要对 Kafka 数据流进行实时预测,那么您如何为部署做好准备将与模型只需要从 GCP 桶中摄取静态 CSV 文件有很大不同。这也可能导致 scaler 之类的东西中断,因为以前它们可能会缩放整个 CSV 文件并附加所有最新的数据,而现在为了便于快速推断,我们将无法重新计算 scaler 或 CSV 文件。
最后,你要考虑重新训练或者继续训练模型需要多长时间。如果你要定期获取新数据,如果你的模型每次都需要从头开始重新训练(例如由于灾难性的遗忘),这将消耗大量资源。
选择您的总体预测长度
预测长时间序列数据仍然是一个很大的瓶颈,因为模型只能预测与其输出预测长度一样长的值。这意味着,如果您有一个一次仅预测一个时间步长的模型,并且想要预测未来的 200 个时间步长,您将需要运行 200 次向前传递(至少对于大多数模型)加上追加操作。而如果你一次建立了 10 个时间步长预测模型,你只需要 20 个。因此,当长预测长度不会降低性能时,您应该使用它们。
测试损失最低的模型真的是最好的模型吗?
通常,测试损失最大的模型在全面生产环境中可能表现不佳。这主要是由于数据的分布变化和评估指标的选择不当。因此,您会希望在部署之前以严格的方式评估您的模型。为了做到这一点,我建议分析总体测试损失、最新数据的测试损失和可解释性图表。你也可以看看你的模型在极端情况下做了什么。即使预测问题很复杂,我们通常对应该发生什么或预测的大致方向有基本的直觉。例如,如果您有一个预测河流流量的模型,而该河流通常每月只有 2 英寸的降雨量,您可以尝试在一个小时内输入 20 英寸的降雨量。显然,河流流量预测应该会上升到史诗般的高度(不管正常的时间滞后是多少)。如果没有,那你就知道有问题了。
双重检查生产流程
在这一阶段,经常会有“意想不到的来源”的分布变化。理想情况下,您应该编写单元测试,以确保模型在生产中做出与测试数据相同的预测。我不能夸大这一点,检查你的输入数据。预处理中极小的差异往往会导致精度上的巨大差异。很多时候,人们会很快归咎于一个有缺陷的模型,但是很多时候不适当的数据清理和改变数据格式是罪魁祸首。您还应该与您的数据工程/后端团队沟通,看看他们是否预计到数据格式的变化。最后,您可以编写端到端的测试,以确保模型与预处理和后处理相结合产生合理的结果。
单个型号或多个型号
初始模型选择的另一个区别是您需要部署单个还是多个模型。例如,您可以为每个要预测的商店训练一个单独的 DNN,或者为所有商店训练一个 DNN。在后者中,您的模型将需要在推理时访问商店 id(和其他信息)以及时态信息。在这种情况下,您还需要跟踪模型输出(尤其是当您一次将多个商店位置分批处理时)。在前一种情况下,您将需要部署更多的模型,但是由于它们是独立的,它们至少在推理方面更具并行性。
通过流量预测为部署准备好模型
Flow Forecast 有许多内置工具可帮助您完成模型部署过程。我们有一个易于使用的自动推理 API,它提供了 evaluator 类的全部功能。除非您需要用不同的语言部署您的模型,或者需要非常低的推理速度,否则我们建议您只需将该类封装到您的 Python (web)应用程序中,或者使用我们预先构建的 Docker 容器之一来创建自动推理 API。然而,即使您决定需要导出它,您仍然希望从推理 API 开始,因为它使下面的两个步骤变得容易。
- 鲁棒性测试
使用流量预测推理 API,您可以轻松地绘制出模型在不同时间段的表现。我们的标准可解释性度量套件已经自动记录到权重和偏差中。要查看如何工作的完整示例,您可以查看这个笔记本。
使用 FF 推理模式实例化模型的示例。
2。推断速度测试和加速
我们在流量预测中的另一个功能是自动计时您的模型在各种设备上预测不同预测长度所需的时间,以及 vanilla 模型、TorchScript 和 ONNX 之间的差异。此外,我们正在研究几个新的增强功能,以加快推断速度,例如在大批量中生成置信区间,以及更快地记录绘图。
3。导出到 TorchScript 和 ONNX
截至流量预测 0.95,我们已经支持 TorchScript,我们计划在 0.96 之前支持 ONNX。然而,使用这些方法有几个缺点,包括置信区间的损失。要将模型放入 TorchScript/ONNX 中,需要调用model.eval(),这意味着所有预测都是相同的,因此没有置信区间。也就是说,如果您想要将模型转换为 TorchScript(假设您已经遵循了上面要点中的步骤),您基本上应该这样做:
from flood_forecast.deployment.inference import convert_to_torch_script convert_to_torch_script(d, "torch_script_save_path.pt")
更多信息见此链接。
4。当前数据接收和未来版本
目前,推理模式仅支持从 CSV 加载推理数据。然而,我们希望在不久的将来改变这种情况,允许从许多不同的数据源加载数据。具体来说,我们优先考虑直接从 SQL 表、Parquet 文件和 HDFS 加载数据。稍后在我们的路线图中,我们计划允许流数据源,如 Kafka 订阅、Redis 或 Pub/Sub。
在本文中,我们介绍了部署模型的一些准备步骤。一旦你完成了这些事情,你就可以开始关注实际的部署阶段了。在第二篇文章中,我们将研究如何通过使用流量预测推理 Docker 容器、我们的 Terraform 模板和 Google 云平台来执行实际部署。这篇文章将更加直观,包含更多代码示例。如果你有任何问题,请随时提问。
部署您的第一个机器学习 API
使用 FastAPI 和 Deta 轻松开发和部署机器学习 API。

图片作者|元素作者 vectorjuice
介绍
在这个项目中,我们将学习如何为您的机器学习模型构建应用程序编程接口(API ),然后用简单的代码部署它。我花了一个小时学习 FastAPI,花了五分钟学习如何将它部署到 Deta 服务器。我们还将使用 Python 请求 在本地服务器和远程服务器上测试我们的 API。让我们更深入地了解一下我们将在项目中使用的技术。

作者图片
宽大的
与用于实验和评估的著名 NLTK Python 库相比,spaCy 对应用程序和部署更加友好。spaCy 附带预构建的统计神经网络 NLP 模型,具有强大的功能,易于在您的项目中使用和实施。我们将使用一个非常简单的小型预建英语模型来从我们的文本中提取实体。
FastAPI
FastAPI 是一个用 python 构建 API 的快速 web 框架,它具有更快的查询时间,简单且最小化代码,让您在几分钟内设计出您的第一个 APIFastAPI。在我们的项目中,我们将学习 FastAPI 如何工作,以及如何使用我们预先构建的模型从英文文本中获取实体。
二亚乙基三胺
我们将为我们的 API 使用 Deta Micros 服务,并在没有 docker 或 YAML 文件的情况下部署项目。Deta 平台具有易于部署的 CLI、高可扩展性、安全的 API 认证密钥、更改子域的选项以及 web 流量的日志记录。这些功能在 Deta 上完全免费使用。在我们的项目中,我们将使用 Deta CLI 通过几行脚本部署我们的 Fast API。
2021 年 10 月的顶级 KDnuggets 博客
密码
在我学习 FastAPI 的时候,我偶然发现了 YouTube 上的视频激励我写这篇文章。 Sebastián Ramírez 解释了 Fast API 的工作原理,以及它是目前最快的 python web 框架的原因。我们将编写两个 Python 文件。一个文件包含机器学习模型,另一个文件包含您的 API 代码。
要求
在开始之前,我们需要用一个 requirements.txt 文件创建一个新目录。您可以在下面找到我们将要使用的所有必要的库👇
fastapi
spacy
uvicorn
https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.1.0/en_core_web_sm-3.1.0.tar.gz
您可以逐个安装它们,也可以使用🔻
$ pip install -r requirements.txt
我们将为这个项目使用一个预训练的 NLP 模型,所以我们需要从 GitHub 库https://github.com/explosion/spacy-models下载它,或者只是运行需求文件,它会自动下载并安装它。
机器学习模型
我们将使用预训练的空间自然语言处理模型从文本中提取实体。如果你用的是 Jupyter notebook,试着用 %%writefile 在你的目录下创建 python 文件。
首先,我们加载 NLP 模型,然后从 CBS News 文章中提取实体。只需几行代码,你就可以运行你的第一个机器学习模型。您也可以使用相同方法加载已训练模型。
API 文件
这是您的主文件,其中包含:
- read_main :使用 GET ,从资源中请求数据,在我们的例子中,它将显示一条消息说 欢迎使用。
- 类文章:使用pydanticbase model定义将用于你的 API (helpmanual.io) 的对象和变量。在我们的例子中,我们将内容定义为字符串,将注释定义为字符串列表。
- analyze_article :它从 ml 文件中获取带有注释的文本列表,并使用 NLP 对象显示实体。
我知道这相当混乱,所以我们把它分解成更小的部分,以便更好地理解它。
分解
我们已经创建了一个 FastAPI 的对象,然后使用 @app 将它作为函数的装饰器。得到("/")。
- @app 是你 FastAPI 对象的装饰器
- 。获取或。post if 返回数据或处理输入的 HTTP 方法
- (“/”)是 web 服务器上的位置。在我们的例子中是主页。如果要添加另一个目录,可以使用("/ < new_section > /)
我们已经创建了 read_main 函数在主页上显示消息,就这么简单。
现在我们将创建一个 Article 类,它从 BaseModel 继承函数和变量。这个函数帮助我们创建将要在 POST 方法中使用的参数类型。在我们的例子中,我们创建了字符串变量形式的内容和字符串列表形式的注释。
在最后一部分中,我们为我们的 API 创建了一个方法("/article/")。这意味着我们将创建一个新的部分,它将参数作为输入,并在处理后返回结果。
- ****文章类作为参数:使用文章列表创建文章参数,这将允许我们添加多个文本条目。
- ****从文章中提取数据:创建循环,从文章列表中提取数据,然后从评论列表中提取数据。它还向数组添加注释。
- ****加载文本到 NLP 模型:加载内容到 nlp 预训练模型。
- ****提取实体:从 nlp 对象中提取实体,然后添加到 ents 数组中。这将堆叠结果。
- ****显示:该函数将返回实体和注释的列表。
测试
Fast API 建立在 uvicon 上,所以服务器也运行在 uvicon 上。在 Jupyter notebook 中,您可以使用👇或者在终端中输入uvicon然后输入 main 文件和带有 FastAPI 对象的 app 。
我们的服务器运行流畅,所以让我们使用 request.get 方法来访问它。API 通过在主页上显示“欢迎”消息来工作。
现在让我们尝试在列表中添加单个文本和注释作为字典。我们将使用 POST request 方法和 /article/ 来访问我们的 NLP 模型函数。将你的输出转换成 。json() 使提取数据变得容易。
我们有自己的字典键: ['ents ',' comments']
让我们检查一下我们的整个输出是什么样子的。看起来我们已经有了带有标签和实体列表的。同样适用于 注释 键
现在让我们提取单个实体及其文本来检查输出的灵活性。在我们的例子中,我们从输出中提取第二个实体。
结果显示出完美。
部署
转到您的终端,或者您可以在 Jupyter 笔记本电脑中执行相同的步骤,但添加“!“先于任何剧本。首先,您需要使用 cd 访问您的目录,其中包含您的 main.py 和 ml.py 文件。
**cd ~”/FastAPI-ML-Project”**
Deta 需要的三个主文件是 ml.py , main.py ,和requirements . txt。

作者图片|项目目录
如果您使用的是 Windows ,请在 PowerShell 中使用下面的命令下载并安装 Deta CLI
**iwr [https://get.deta.dev/cli.ps1](https://get.deta.dev/cli.ps1) -useb | iex**
对于 Linux
**curl -fsSL [https://get.deta.dev/cli.sh](https://get.deta.dev/cli.sh) | sh**
然后使用 deta 登录 ,它会带你到浏览器,要求你输入用户名和密码。如果您已经登录,认证将需要几秒钟时间。
**deta login**

Deta 认证| deta
你终端里的这两个字就是魔法字,两分钟就能上传文件,部署好你的 app。
**deta new**
您的应用程序已上传至端点链接。在我们的情况下https://93t2gn.deta.dev/
**Successfully created a new micro{“name”: “FastAPI-ML-Project”,“runtime”: “python3.7”,“endpoint”: “https://93t2gn.deta.dev/",“visor”: “enabled”,“http_auth”: “disable”}Adding dependencies…Collecting fastapi…Successfully installed ……**
如果您使用 deta 日志 查看错误检查日志,进行一些更改,然后使用 deta 部署 更新更改。
如你所见,我们的应用程序部署并运行在 Deta 服务器上。

项目概要| 详细资料
可以去 Deta 提供的链接自己查一下。

作者图片
测试 Web API
最后,让我们在 Deta 平台上将远程 API 作为微服务进行测试。这一次,我们将添加 Deta 端点链接,而不是添加本地 IP。我们可以在没有头文件的情况下运行,因为我们没有启用 API 认证。当认证被启用时,Deta 还提供免费的 API 密钥。这意味着只有你或拥有 API 密匙的人才能访问网络服务器。要了解更多关于认证和子域的信息,我建议你阅读文档。
我们将添加相同的参数和相同的代码,以获得相同的结果,瞧,这很神奇。您的 API 是在线的,可以通过使用链接轻松访问。
结论
在学习 FastAPI 之后,我一直在思考下一步该做什么,所以有一天在浏览网页时,我偶然发现了引起我注意的 Deta。我花了几分钟在远程服务器上安装 Deta CLI 和部署我的 API。他们的子域和免费 API 关键特性给我留下了深刻的印象。我很快就明白了这项服务是如何工作的,以及我将如何在未来的项目中使用它。
我们学了几个机器学习模型之后都会问这个问题。
我知道如何训练我的模型并获得预测,但下一步是什么?我如何与他人分享我的模型?这样他们就可以看到我构建的东西,并在他们的项目中使用这些特性。
这就是像 Heroku 、 Google 、 Azure 这样的云平台的用武之地,但是这些平台非常复杂,你需要学习为 Docker 文件编码,这有时会令人沮丧。 Deta 用简单的两个字的脚本解决您的所有问题,它将在几秒钟内部署并运行您的应用。
你也可以查看我对这个项目的 GitHub 回购:kingabzpro/FastAPI-ML-Project。**
你可以在 LinkedIn 和 Polywork 上关注我,我每周都会在那里发表文章。
别忘了给你的👏
使用 Streamlit 和 Ngrok 部署您的 ML 模型
关于如何使用 Streamlit 创建和部署模型的完整指南

弗洛里安·奥利佛在 Unsplash 上拍摄的照片
如果你一直在处理数据,那么你很有可能至少做过一次机器学习模型。我们每天都会遇到各种各样的机器学习模型。每个模型都是不同的,用于不同的目的。我们有各种各样的问题,为了建立一个好的模型,我们需要使用不同的算法。但是我们有了模型之后该做什么呢?大多数人制作模型,但是他们忽略了一个事实,没有部署模型就没有多大用处。在这篇博客中,我们将介绍创建一个模型并将其部署到 web 上的完整过程。
让我们从导入数据集开始。我们将使用来自 Kaggle 的数据集,其中包含不同的栏目,如学生的 GRE 成绩、托福成绩、CGPA 等等。我们将利用这些数据来预测一个学生是否能够进入研究生项目。让我把整个过程分解一下:
- 我们将从创建一个模型开始,我们的数据有连续的值,这意味着线性回归将足以帮助我们。
- 一旦我们有了模型,我们将把它存储在一个。pkl”或 pickle 文件。
- 我们将在新的 jupyter 笔记本中使用这个 pickle 文件,在其中我们将使用 streamlit 和 ngrok 将我们的模型部署到 web 上。
让我们首先从导入数据和创建模型开始。
在上面的代码中,我们只是导入我们将用来读取和可视化数据集的库,然后我们检查前 5 行,看看我们的数据到底是什么样子。

这是我们的数据,我们有学生的 GRE 和 TOEFL 成绩以及 CGPA 和其他栏,如 LOR 和学生是否写了研究论文。我们现在将做一些数据预处理和可视化我们的数据。

如您所见,我们的数据中没有空值。让我们假设我们很幸运,因为获得没有空值的数据是一个奇迹。让我们看看 describe 方法做了什么。

既然我们知道了这些重要的细节。我们将会看到一些情节,并试图从这些情节中获得深刻的见解。

该图向我们展示了大学评级栏中每个大学评级的条目数量分布。正如我们所看到的,这一栏中的大多数大学的评分为 3。最少的是评级为 1 的大学和中等数量的评级为 5 的大学,这是我们数据中大学的最高评级。

上面的图显示了我们的数据中有多少人写了一篇研究论文。研究论文在决定一个人是否能够进入研究生项目中起着关键作用,正如我们可以看到的,在我们的数据中有许多人写过研究论文。让我们看看通过可视化学生的分数以及输出栏(即被某个项目录取的机会)可以发现什么。

这张图向我们展示了 GRE 分数的分布与被某个特定项目录取的几率。我们可以观察到的是,这些点有些线性分布。较暗的六边形有更多的相关值,反之亦然。我们也来对比一下托福成绩吧。

我们也可以看到类似的趋势。在上面的情节中,我们有相当数量的托福成绩在 100 分以上的人。在进入建模部分之前,我们还将比较 CGPA 列。

正如我们所看到的,CGPA 列也具有与其他列相似的分布。可视化这些列的目的是选择制作模型的最佳列。我们首先处理我们的数据,然后将其可视化,在这一切之后,我们有了将用于制作模型的列。让我们开始建模。
在上面的代码片段中,我们导入了可以帮助我们制作模型的库。然后我们选择我们的列,我们也知道我们的输出列。然后,我们将进行一次拆分,从而得到两个集合——一个训练集和一个测试集。下一步是使用线性回归建立我们的模型。
这就是我们创建模型的方式。我们使用 Sci-Kit learn 中的线性回归来帮助建立我们的模型。我们将我们的训练数据拟合到这个模型中,然后调用 predict 方法,通过向模型提供测试数据来进行预测。我们拆分数据的主要原因很简单,并且可以与一个简单的现实世界场景联系起来。假设你有一个测试,如果我们给你所有的测试问题,你只是练习这些问题,你就可以把所有的东西都记下来,并在实际测试中取得好成绩。但是这里并没有真正的学习,你只是在强记东西。模型也是如此。我们用我们的训练数据训练它,然后用测试数据测试它的表现好坏。
我们使用的度量标准是 MSE 或均方误差。你可以使用这个链接来了解它背后的数学原理。经过评估,我们知道这个模型相当不错,MSE 为 0.005。让我们用一些输入来测试这个模型,然后我们将把这个模型放在一个。这样我们可以在以后的部署中使用它。
因此,我们用一些用户给定的输入来检查模型,与实际值的偏差非常小,这意味着我们在正确的轨道上。然后,我们导入了 pickle,它帮助我们存储模型以用于部署。我们刚刚做了自己的机器学习模型!现在是时候部署它了。
为了部署我们的模型,我们将使用 Streamlit 和 Ngrok。Streamlit 是一个 python 库,它帮助我们创建易于构建的出色的 web 应用程序。也是开源的!我建议你浏览一下 streamlit 文档以便更好地理解整个框架的工作。让我们从加载模型和导入库开始。
既然我们已经有了可以使用的库和加载的模型,我们就可以开始设计我们的 web 页面了。
因此,我们有许多 Streamlit 提供的功能,可以用来设计我们的网页。在上面的代码片段中,我们使用 streamlit 特性来创建不同的特性,如侧边栏、创建标题等等。一旦我们完成了页面的设计,我们就可以使用我们加载的模型,通过用户在文本框或者滑块的帮助下输入的信息来进行预测。所有这些都是由 Streamlit 提供给我们的,所以我们不需要任何 web 开发的一般知识,但拥有一些 web 开发知识总是有利的。
在这里,我们正在创建滑块,这将有助于用户在给用户输入。我们为所有的输入值创建滑块,我们将使用这些值作为我们给模型的输入。然后我们创建一个按钮,点击它,我们就得到结果。最后,我们打印结果供用户查看。
我们现在有了完整的网页设置,它也能够根据我们给模型的输入给出输出。现在,我们部署的最后一步是使用 Ngrok。但是它有什么用呢?用最简单的话来说,它把我们的本地开发服务器放到互联网上。你可以在这里了解更多关于 Ngrok 的信息。让我们使用 Ngrok 在互联网上部署我们的模型。
有了这段代码,我们就可以创建服务器并在互联网上运行我们的模型。它将被托管在 Ngrok 的子域之一,因此我们不需要任何公共域或 IP。一旦我们这样做了,我们就可以转到生成的 URL,我们将能够查看我们的 web 应用程序。
至此,我们结束了创建机器学习模型并将其部署到 web 上的整个过程。完整的代码将被链接下来供您查看。这是它的这一个。因此,继续构建一些模型并部署它们,并且不要忘记在您这样做的同时享受一些乐趣!
链接到模特-https://github.com/AM1CODES/PythonWeek-GraduateAdmission
这里和我连线-【https://www.linkedin.com/in/aayushmishra1512/
将您的 ML 模型部署到 AWS SageMaker
为了 2021 年夏季奥运会,我们创建了这个 web 应用程序来预测人类裁判会给跳水视频打多少分。我们使用 Streamlit.io 库制作了我们的应用程序。

由 Suhyun Kim 创建的 GIF
我们在使用 Streamlit.io 时遇到了一些困难,所以我们决定将我们的 ML 模型部署到 AWS SageMaker。你可以在这里看到我们的 SageMaker 实现。本文的目的是提供一个示例教程,展示如何将 ML 模型部署到 AWS SageMaker。本教程只涉及部署没有在 SageMaker 中培训过的 ML 模型。部署在 AWS SageMaker 之外训练的 ML 模型比在 SageMaker 内训练模型并进行端到端部署要复杂得多。有一些例子代码是关于如何部署你的内部培训模型的,但是这不足以支持我们的产品,所以我们必须更进一步。我将首先描述 SageMaker 如何与模型部署一起工作的高层架构,然后提供一步一步的指导。
如果你想使用 SageMaker 作为服务来部署你的模型,涉及到部署到 3 个 AWS 服务: AWS SageMaker , AWS 弹性容器注册中心(ECR) ,为容器镜像提供版本控制和访问控制, AWS 简单云存储(S3) 。下图详细描述了该过程。

由 Suhyun Kim 创建的图像
首先,将您的打包 ML 模型放入 AWS S3 桶。然后您将 Docker 映像部署到 AWS ECR,它将由您的 SageMaker 使用。Docker 用于将你的 ML 推理逻辑代码打包到一个容器化的环境中。SageMaker 也会在 S3 消费你的模型。作为客户机,您只与 SageMaker 端点交互,它首先从 S3 下载您的模型,然后从 ECR 调用您的 ML 推理代码。
首先,我想描述一下 AWS 提供的示例代码中有什么,它描述了 ECR 下的架构。示例代码遵循基本的服务器架构,该代码将被部署到 ECR。
- Nginx 是一个 web 服务器,它是 HTTP 请求首先到达的地方。它处理请求的方式是只允许有效的请求通过。
- Gunicorn 是“一个 WSGI 预分叉工作服务器,它运行应用程序的多个副本,并在它们之间进行负载平衡。”(引用)当请求进来时,它调用你的 Python 代码。
- Flask 是一个 python web 框架,可以让你指定如何处理 ML 推理请求的逻辑。它允许您响应 /ping 和/调用。
示例代码提供 build_and_push.sh ,通过运行脚本构建 docker 容器并推送到 AWS ECR。在运行脚本之前,我建议您转到 AWS ECR 页面,尝试手动将图像发布到 ECR。然后,您将在 ECR 页面上推荐的脚本中看到相同的命令。
现在我将描述 AWS SageMaker 部分需要做什么。这是为您的推理声明硬件实例的地方。您还创建了一个端点,您的客户机通过它与您的 ML 服务进行通信。为了获得一个功能完整的实例,您需要创建一个 SageMaker 模型、SageMaker 端点配置和 SageMaker 端点。
- 型号指的是 docker 容器和您的 ML 型号的位置。需要注意的一点是,您可以将 ML 模型附加到 docker 容器中,也可以将压缩模型(必须是 thing 格式)放在 S3 中。然后 SageMaker 将下载压缩的模型文件到 opt/ml/model 目录中,在您的推理代码中,您需要引用该目录中的模型。
- 端点配置是将模型(来自步骤 1)连接到端点(步骤 3)的地方。端点是 Sagemaker 与外界接口的一部分。您可以创建不同的变体,以便 beta 和 prod 使用不同的模型。这样,您还可以配置进入不同变体的流量。例如,如果您想对您的 ML 模型进行 A/B 测试,您可以使用生产变量来划分流量,并查看您的每个 ML 模型的执行情况。对于我们的示例代码,除了 prod,我没有使用生产变量。
- 端点是您从服务中调用的,以使用您的 ML 模型进行推理。您可以用 python、java、javascript 或 shell 调用您的端点。这里是的例子。
第一步。写一个 Docker 文件
在我们的示例中,我们从公共存储库中提取一个映像,并用 Ubuntu 版本 18.04 设置基本映像。大多数 docker 文件以 FROM 指令开始,图像可以是任何有效的图像。由于我们有了一个全新的映像,我们正在安装必要的库,并在运行后设置变量,这将执行 docker 映像中的命令。然后,SageMaker 的推理代码包被复制到工作目录,以便代码可用于后续指令。
第二步。在/ping 函数中编写健康检查代码,在/调用中编写推理逻辑
需要定义两个必要的函数: /ping 和 /invocations 。
一旦调用 CreateEndpoint 和 UpdateEndpoint APIs,容器就会启动。容器启动后,SageMaker 通过不时地持续 ping 服务来检查容器的健康状况,以查看容器是否启动并运行。健康检查 ping 通过 /ping ,您将看到该函数已准备好返回静态 200 响应。您可以在此呼叫中添加其他健康检查,如打印报表。如果容器在启动后的 4 分钟内没有发送 200 响应,CreateEndpoint 将失败,因此 UpdateEndpoint 将无法完成。
当 SageMaker 端点被调用时,默认情况下,调用被路由到 /invocations ,因此推理代码需要在调用函数下。你可以从 flask 的 request 对象中获取这个函数附带的内容,比如这里:https://github . com/gitskimp/AQA _ sage maker/blob/main/getPredScore/predictor . py # L61
第三步。本地测试:验证功能
为了在本地测试 docker 映像功能中的推理逻辑,我们将通过创建一个 docker 容器来进行测试,该容器对模型位置的路径进行了一些更改。确保在测试之前下载 docker 并运行它。Sagemaker 会自动下载位于 S3 的 /opt/program/models/ 目录下的模型,当您部署代码时,您应该编写代码,以便它在该目录中查找它的模型。但是为了在本地测试功能,我们需要在本地重新定位模型,并引用本地模型位置。当您创建一个容器时,如上面的脚本所示,我们需要 AWS 凭证,因为我们提供输入数据作为到 S3 的链接。我们为什么这样做的详细描述将在后续文章中描述。
第四步。使用 build_and_push.sh 进行部署
starter 示例代码附带了 build_and_push.sh bash 脚本来自动化部署。你只需要chmod+x build _ and _ push . sh .然后输入 运行脚本。/build_and_push.sh. 要自动创建三个主要组件(模型、端点配置和端点),可以使用 Cloud Formation 或 SageMaker Studio。您可以通过 Sagemaker Studio python 控制台创建所有三个组件,如下所示:https://github . com/git skim/AQA _ sage maker/blob/main/sage maker _ one _ click _ create _ with _ integ _ test . py
总之,我们的想法是创建一个 docker 容器并将其部署到 AWS ECR,并创建一个 SageMaker 实例来使用 ECR 映像。我希望你发现这个解释和附加的代码是有用的,但是值得一提的是,与 SageMaker 的整个交互是相当令人沮丧的。
令人惊讶的是,SageMaker 的 ML 部署工具既原始又复杂。SageMaker 几乎只提供了最低限度的部署,它需要很多意想不到的部署和维护步骤,特别是对于在 AWS SageMaker 之外训练的 ML 模型。对于这样一个推广良好的平台,我们期望更成熟的部署和版本控制工具。虽然给出了 boiler plate 代码,但是使用 nginx、gunicorn 和 flask 会导致系统变得笨重,难以维护。我不妨在 AWS EC2 中创建自己的机器学习服务器。
好在 AWS 还在继续努力改进 SageMaker。AWS re:invent 2021 为 SageMaker 展示了一个新的无服务器推理功能,在这个功能中,您不必指定一种主机来运行您的 SageMaker 代码。然而,我上面解释的架构仍然存在,没有太大的变化,所以新版本没有完全消除将 ML 模型部署到 SageMaker 所带来的复杂性和繁琐的设计。另外,我想知道这个特性有多大用处,因为我们已经有了一个方便的无服务器选项:AWS Lambda。
出于上述原因,在我们 ML 服务的实际实现中,我们使用了 AWS Lambda。它的无服务器功能可处理扩展、容错,并实现我们服务的高可用性。2020 年 12 月,AWS 开始支持将 Docker 容器映像部署为 lambda 函数的功能。这意味着 docker 容器映像可以部署到 lambda,而不是 zip 文件。这对于 ML 部署来说是一个有用的特性,因为它现在为 ML 服务的大文件和依赖性提供了空间。然而,也有缺点,包括现有的λ问题,比如启动延迟。此外,特定于 ML 部署的特性,如连续模型部署和模型版本控制,需要实现额外的层。它们不是作为方便的特征提供的。
说到底,SageMaker 对 ML Ops 来说并不方便;在 SageMaker 之外训练的模型的 ML 部署特别差。因此,我们使用 AWS Lambda 进行 ML 模型部署,因为它便于集成。将会有另一篇文章描述我们基于 AWS Lambda 的 ML 系统的架构。
我与 延庆戴 合作写了这篇博客。
注意
我和 延庆戴 开始了我的自由职业生涯。我们接受专注于生产机器学习服务、数据工程和分布式系统的自由职业者的工作。
云计算中的部署模型
了解私有云、公共云和混合云之间的区别

介绍
术语云计算指的是按需访问一组资源,如存储、应用程序、计算能力和其他 IT 服务。云用户可以即时访问根据单个使用案例的需求扩展的调配服务。
然而,有几种不同的云部署模式,即私有、公共和混合。在今天的文章中,我们将讨论每种可用的部署模型以及每种模型最流行的提供商。
私有云
私有云是指在单租户环境中提供的一组云服务(这意味着在单个组织中共享),并且不向公众公开。这种部署模式通常用于安全原因,有时也可能与法律甚至业务需求相关。
私有云可以托管在组织自身的内部基础架构上,也可以托管在通常由提供私有云服务的第三方组织提供的独立基础架构上。
一些最受欢迎的私有云提供商是 RackSpace、VMware 和 RedHat。
公共云
现在,在公共云部署模式中,基础设施和资源由第三方提供商拥有、维护和运营,例如亚马逊网络服务(AWS)、谷歌云平台(GCP)或微软 Azure、等等。
这些第三方提供商本质上向公众提供基础设施和计算机资源,用户可以按需访问,并以按需付费的方式使用。这意味着用户也能够相应地扩展这些资源,因为他们几乎可以立即增加或处置资源。
总的来说,公共云为组织省去拥有、维护和运营自己的基础架构的麻烦。换句话说,他们交易资本支出(硬件、基础设施、租金等。)用于运营费用。
混合部署模型
最后,云计算中的最后一种部署模式是混合模式,它位于我们之前讨论过的公共云和私有云的交汇处。
这种特定的云计算模式混合了内部、私有云和公共云服务,它们之间也需要某种编排才能正常运行。
当组织希望利用公共和私有云计算服务的优势时,这种模式非常有用。
最后的想法
在今天的文章中,我们探讨了云计算环境中的三种基本部署模型,即公共、私有和混合模型。
尽管云计算作为一个概念已经相当成熟,但我认为我们仍处于过渡期。由于需要满足法规和立法的要求,许多公司目前更喜欢混合部署模式。
看看这些公司将如何应对这种性质的障碍,以及是否会转向纯云模式,这将是非常有趣的。
成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。
https://gmyrianthous.medium.com/membership
你可能也会喜欢
https://betterprogramming.pub/5-things-to-consider-when-choosing-your-aws-region-484e800cb6f0 https://pub.towardsai.net/data-versioning-for-efficient-workflows-with-mlflow-and-lakefs-892df1f8e7d8
部署应该是任何商业数据科学项目中的优先事项
意见
为什么你应该关心数据工程,即使是作为一名数据科学家
介绍
我开始我的职业生涯时是一名核心科学家,所以将我的研究应用于生产从来不是我的主要关注点。幸运的是,我作为自然地理学家的背景确实迫使我永远不要将数据科学视为一项孤立的努力,而总是作为解决地理问题的一种手段。当我转换到一个行业职位时,我越来越相信将我的模型投入生产应该是我工作流程中不可或缺的一部分。在本文中,我想给出一些我变得确信每个数据科学家都应该学习一些数据工程技能(或者与一些数据工程师成为朋友)的原因。我想从两个角度来阐述我的观点:一个更技术性的观点和一个关注用户体验的观点。

技术性
从技术的角度来看,我不认为在我自己的笔记本电脑上安装一个好的模型就一定能保证这个解决方案可以扩展到生产。生产中的数据量可能太多、太频繁甚至太少,以至于您的小型研究模型无法扩展到生产中。此外,数据的漂移可能很大,以至于几周后你的模型就过时了。只有当你积极地将你的模型尽早地、经常地投入生产时,你才需要面对这种偏差。此外,您所面临的数据工程挑战(如扩展数据存储、模型的版本控制和计算扩展)最好不要留到项目的最后。
用户体验
我想关注的第二个角度是用户体验。我认为普通的数据科学家很难代表最终用户。因此,让最终用户参与到你的项目中是真正获得用户体验的关键。即使有一个真正了解最终用户的好的产品负责人,也不等同于让用户使用你的解决方案。例如,在我参与的一个项目中,我们有一个我合作过的最好的产品负责人。即便如此,在我们与实际最终用户的第一次试验中,他们还是拒绝使用我们的产品。当他们忙于修理机器故障时,我们请他们花时间研究我们的产品。这不是一个选项,机器应该首先被修理。甚至我们的 rockstar 产品负责人也没有预见到这一点。
用户参与最好通过让实际用户使用该解决方案来完成,而不仅仅是让他们在房间里进行演示。即使他们在演示期间很热情,这也不一定意味着如果他们不得不使用产品本身,他们会很高兴。能够尽快将您的模型部署到最终用户是至关重要的。
生产价值
总之,我认为任何商业数据科学项目都应该优先部署他们的解决方案。它迫使您面对只在生产中出现的技术和 UX 问题,并可能严重限制您的解决方案的附加值。这当然不是一个简单的任务,但如果你的重点是创造现实世界的价值,这是值得的。
我是谁?
我叫 Paul Hiemstra,是荷兰的一名教师和数据科学家。我是科学家和软件工程师的混合体,对与数据科学相关的一切都有广泛的兴趣。你可以在 medium 上关注我,或者在 LinkedIn 上关注我。
如果你喜欢这篇文章,你可能也会喜欢我的其他一些文章:
最小二乘回归器和分类器的推导
基本机器学习推导
一个基本但功能强大的分类器和回归器,它们的派生以及它们工作的原因

作者图片
在本文中,我推导了最小二乘回归和分类算法的伪逆解。
虽然不是很复杂,但在一些问题中,它仍然是一个非常强大的工具,今天仍然被用作其他机器学习模型的核心,如集成方法或神经网络(其中感知机提供了非常相似的算法)。如果你刚刚开始进入机器学习的世界,这是迄今为止让你头脑清醒的最重要的话题之一!
线性回归
让我们首先推导回归问题的最小二乘解。
我们尝试从数据矩阵 x 中估计目标向量 y。为此,我们尝试优化权重向量 w,使误差平方和最小化,如下所示:

其中 E 是误差平方和,y 是目标向量,X 是数据矩阵,w 是权重向量
最小二乘问题有一个解析解。当用 w 对误差求微分时,当导数等于零时,求 w 得到伪逆解:

最小平方分类器
通过尝试寻找最佳决策边界,最小二乘解也可用于解决分类问题。
如果试图在二维问题中进行分类,可以按以下方式调整最小二乘算法:
首先注意,目标张量不再是 Nx1 向量,而是 Nxc 张量,其中 c 是我们试图分类的类别的数量。此外,权重向量需要额外的维度来表示决策边界的截距:

其中 w0 是决策边界的截距,w 可以用作梯度。

数据矩阵 X 也必须适应要兼容的维度。将一个向量串联起来增加维度就达到了这个目的。

新的数据矩阵和目标向量 t 可用于导出解析解。结果是最小二乘分类器及其伪逆解。
这里是一个二元高斯分类器的小例子,用上面显示的方法实现,与默认的 SK-learn 分类器相对。

作者图片
决策边界的等式简单来说就是 ax + by + c = 0。权重向量是[a,b,c]。孤立 y 我们发现分类器的梯度是-a/b,分类器的截距是-c/b。
值得注意的是,这是二元高斯问题的最大后验估计量,对于无限数据,它将趋于完美的结果。
结论
在我攻读硕士学位时,线性回归是一个反复出现的话题。它的简单性和它与最大后验解的关系是它在机器学习领域成功的原因。我希望这篇文章能帮助您理解如何将它应用于分类问题。
支持我👏
希望这对你有所帮助,如果你喜欢,你可以 关注我!
你也可以成为 中级会员 使用我的推荐链接,获得我所有的文章和更多:https://diegounzuetaruedas.medium.com/membership
你可能喜欢的其他文章
Softmax 函数的导数和分类交叉熵损失
简单快速的推导
在这篇短文中,我们将计算 softmax 函数的雅可比矩阵。通过应用一个优雅的计算技巧,我们将使推导非常短。使用获得的雅可比矩阵,我们将计算分类交叉熵损失的梯度。
Softmax 函数
softmax 函数的主要用途是获取任意实数的向量,并将其转换为概率:

(图片由作者提供)
上面公式中的指数函数确保获得的值是非负的。由于分母中的归一化项,获得的值总和为 1。此外,所有值都在 0 和 1 之间。softmax 函数的一个重要属性是它保留了其输入值的等级顺序:

Softmax 函数的雅可比矩阵
形式上,softmax 函数是所谓的矢量函数,它将一个矢量作为输入,并产生一个矢量作为输出:

所以,我们在讲 softmax 函数的导数时,其实讲的是它的雅可比矩阵,雅可比矩阵是所有一阶偏导数的矩阵:

在哪里

请注意,softmax 函数的每个输出如何依赖于所有输入值(由于分母)。由于这个原因,雅可比矩阵的非对角线元素不为零。
由于 softmax 函数的输出是严格的正值,因此我们可以通过应用以下技巧来使下面的求导非常简短:我们不求输出的偏导数,而是求输出的对数的偏导数(也称为“对数导数”):

其中右边的表达式直接来自链式法则。接下来,我们重新排列上面的公式,得到:

左手边正是我们要找的偏导数。我们很快就会看到,右边简化了导数的计算,因此我们不需要导数的商法则。我们必须首先取𝑠:的对数

所得表达式的偏导数为:

让我们看看右边的第一项:

可以使用指示符函数 1{ }简明地写出。如果 indicator 函数的参数为真,则该函数的值为 1,否则为 0。
右边的第二项可以通过应用链式法则来计算:

在上面的步骤中,我们使用了自然对数的导数:

获得和的偏导数是很简单的:

将结果代入公式得出:

最后,我们必须用𝑠乘上表达式,如本节开头所示:

我们的推导到此结束。我们已经得到了雅可比矩阵所有元素的公式(对角的和非对角的)。对于𝑛 = 4 的特殊情况,我们得到:

看看对角线元素与非对角线元素有何不同。
分类交叉熵损失
分类交叉熵损失与 softmax 函数密切相关,因为它实际上仅用于输出处有 softmax 图层的网络。在我们正式引入分类交叉熵损失(通常也称为 softmax 损失)之前,我们必须先澄清两个术语:多类分类和交叉熵。
分类问题可以细分为以下两类:
- 多类别分类,每个样本只属于一个类别(互斥)
- 多标签分类,每个样本可能属于多个类别(或不属于任何类别)
类别交叉熵损失专门用于多类分类任务,其中每个样本恰好属于 𝙲 类之一。因此,分配给每个样本的真实标签由 0 和 𝙲 -1 之间的单个整数值组成。标签可以由大小为 𝙲 的独热编码向量来表示,对于正确的类,该向量的值为 1,而在其他地方为 0,参见下面的示例,其中 𝙲 = 4:

交叉熵将两个离散的概率分布(简单地,其元素位于 0,..,1 和 sum to 1)并输出单个实值(!)表示两种概率分布相似性的数字:

其中 𝙲 表示不同类别的数量,下标𝑖表示向量的𝑖-th 元素。交叉熵越小,两个概率分布越相似。
当交叉熵被用作多类分类任务中的损失函数时,𝒚被馈送一个热码编码标签,并且由 softmax 层生成的概率被放入 𝑠 。这样我们就不会取零的对数,因为数学上 softmax 永远不会真正产生零值。
通过最小化训练期间的损失,我们基本上迫使预测的概率逐渐类似于真正的独热编码向量。

(图片由作者提供)
为了启动反向传播过程,如本文帖子所述,我们必须计算损耗 w.r.t 对输出层的加权输入 𝑧的导数,见上图:

让我们代入上一节得到的导数:

并在最后一项中扩展产品:

对于𝑖 = 𝑗,指示符函数 1 { 0 }取值为 1,其他地方取值为 0:

接下来,我们将𝑠从总和中剔除,因为它不依赖于𝑖:指数

在最后一步中,我们使用了这样一个事实,即独热编码向量𝒚和为 1。请记住,一个独热编码向量可以被解释为一个概率分布,其概率质量以单个值为中心。在简明的矢量符号中,我们得到:

更多阅读
使用知识图技术从健康数据中获得洞察力
业内笔记
知识图技术如何帮助临床自然语言处理
本文描述了knowledge graph technologies如何帮助健康数据科学,特别是自由文本电子健康记录。这是基于我在第一届循证人工智能和医学国际研讨会上的一次受邀演讲。

对于那些想知道一点什么是知识图的人来说,你可能会发现这个知识图介绍很有用。
我将使用真实世界的例子来介绍知识图技术如何帮助临床自然语言处理。我将在《医疗保健知识图谱的挑战和未来方向》中,用我自己的一点想法来完成这个故事。
我知道不是每个人都对技术细节感兴趣。所以,我会用一种讲故事的方式来做演讲。
为什么要使用自由文本的临床笔记呢?
世界上很大一部分数据都是非结构化格式的,如新闻文章、推文和博客。有人说我们 80%的数据是非结构化的,而其他人估计更多。不足为奇的是,这种现象在医疗保健领域也能观察到,比如医院的电子健康记录。如果您想知道自由文本数据为什么/如何有用,请查看这个小故事。
两个故事,一个超硬的要求
现在,让我们讨论知识图如何对健康数据科学有用,特别是在本文中对临床自然语言处理有用。
我先说两个我自己研究经历的故事。两者都以几乎不可能实现的相同要求而告终。

图片由作者提供——伦敦南部和 Maudsley 医院:欧洲最大的精神健康服务提供商
- 故事# 12016 年来自伦敦南部。我与伦敦南部的和 Maudsley 医院(简称 SLaM)的同事一起工作,这是欧洲最大的精神健康服务提供商,2016 年有> 33 万个独特的患者记录。SLaM 是英国使用 NLP 从自由文本文档中导出有用临床特征的先驱之一,例如吸烟状况、抑郁症状和自杀想法。当我在那里开始工作时,他们已经这样做了 7 年,他们有 60 个 NLP 应用程序例行运行在他们的数据上。大多数应用程序都是为识别心理健康相关功能而开发的。我加入的项目有点雄心勃勃,要识别所有的身体疾病(如糖尿病、心脏病等),因为他们对研究精神和身体状况之间的界面感兴趣。从技术上讲,他们有兴趣从 ICD-10 中识别所有 69k 人类疾病。ICD-10 是国际疾病分类第 10 版,是我们之前讨论的 BioPortal 的 T-box 之一。

苏格兰公共卫生部提供的图像 —这是一个与苏格兰公共卫生部合作的项目,旨在使苏格兰成像数据可用于研究
- 故事#2 来自苏格兰爱丁堡,始于 2019 年。这仍然是一个活跃的项目。我与苏格兰公共卫生部合作苏格兰医学影像项目,该项目旨在使苏格兰所有的医学影像数据可供研究访问。在这里,我们只讨论自由文本结构化报告,即当您在医院做 MRI 或 CT 扫描时会得到的那些报告。数据集中有> 33m 个结构化报表。PHS 不愿意让研究人员直接接触到这些报告。原因是可以理解的,因为自由文本报告包含大量个人信息,几乎不可能 100%匿名。因此,他们建议使用 NLP 来查看所有疾病、症状和临床发现,以便将结果保存到结构化数据库中。然后,研究人员可以访问数据库,而不是原始的自由文本报告。本质上,他们要求的是一个 NLP 模型,该模型识别的疾病远不止之前故事中的 69k 种,而是总共约 400 万种的所有生物医学概念(我们将在后面看到)。
不可能的任务?
因此,两个不同的故事,但都要求同样的事情:一个超级 duper NLP 模型,识别所有疾病和表型。如果你不知道什么是表现型,不用担心。基本上,对医疗保健很重要的是任何临床属性,如头痛、出汗、药物使用、不良事件等。
实现这样一个超级自然语言处理模型几乎是一个不可能完成的任务,不仅仅是对我们——一群学术界研究人员来说,甚至对谷歌和亚马逊这样的科技巨头来说也是非常具有挑战性的。让我们做一点分析,看看为什么会这样。
两个主要挑战和一个次要挑战。
实现这样一个超级 NLP 模型有两个挑战——我称之为主要挑战。还有一个次要的挑战是,即使你有这样一个系统,它也很难用于最终用户,即临床研究人员。

作者图片——剖析传统临床 NLP 流程,以确定大规模表型分析任务中的两个主要挑战
让我们对典型的 NLP 管道(上图)进行一点剖析,以理解实现超级 NLP 模型的挑战。请注意,这里的管道是出于解释的目的,并不适用于所有的 NLP 方法,尤其是那些使用大型神经网络语言模型的方法,如伯特或 GPT 。但是,我们讨论的挑战具有普遍性。
如上图所示,临床 NLP 模型通常将一组临床笔记作为输入,并做出推断来回答问题患者是否患有 xx?这样的管道通常有几个组件,每个组件在自由文本上执行一个特定的任务。所有人联合起来实现这个推论。让我们忽略所有细节,只看与我们的挑战相关的两组组件。
- 管道中的第二个组件叫做地名词典。本质上,它是一个字典,定义了我们想要从自由文本数据中识别的一组概念。对于每个概念,它需要列出所有的同义词。比如腹泻,有> 20 种不同的叫法。显然,他们都需要列出来。此外,还需要定义概念的子类型。例如,我支持了一项关于肝病的研究,我发现有 70 种不同类型的肝病。当然,每个子类型及其同义词也需要包括在内。所以,对于所有的 69k 疾病,你可以计算出
69k x 70 x 20也就是> 1 亿个名字。而且,像 ICD-10 这样的疾病分类系统是不合适的,因为它没有同义词。本质上,我们需要一个全面的地名录来定义所有这些关于人类疾病的信息。这是一个巨大的努力,不是一个小团队能在短时间内完成的。我称之为知识表达挑战。如果你还记得我们在知识图表中使用的术语,这就是我们需要的 T-box。 - 管道中的最后两个组件是那些从自由文本中识别概念的重要组件。在机器学习术语中,这是一个受监督的学习过程,意味着需要提供基本事实(即大多数情况下人类标记的数据)供计算机学习。显然,要求医生标注所有 69k 疾病的数据几乎是不可能的。所以,这是第二个主要挑战——没有或没有足够的标记数据用于学习。这被称为低资源学习挑战。
使用大型 NLP 结果数据的第二个挑战是
最后一个挑战是次要的。当你有了这样一个识别所有疾病和表型的系统,显然,这将是一个大数据空间。你需要搜索空间,找到与你的学习最相关的内容。而且,有效地做到这一点可能很有挑战性。让我们看一个 SLaM 医院的真实使用案例。
首先,介绍一下这个用例的临床背景:
情绪稳定剂是用于治疗双相情感障碍的药物,双相情感障碍是一种精神疾病。
假设我们的用例是通过寻找服用情绪稳定剂的人来识别躁郁症患者。现在,假设我们已经在整个 SLaM 数据上应用了 super-duper NLP 系统,并识别了所有内容。为了找到所有的躁郁症患者,人们必须知道所有的情绪稳定剂药物。这当然不是一个用户,甚至是一个有经验的临床医生,可以不容易提供的东西。
解决方案
【SemEHR:】SemEHR:一个通用语义搜索系统,用于从临床记录中提取语义数据,以用于定制护理、试验招募和临床研究
吴等,《美国医学信息学协会杂志》,第 25 卷,第 5 期,2018 年 5 月,第 530-537 页,
好吧,挑战太多了。现在,让我们看看解决方案。我将谈谈我们在利用知识图谱技术应对这三个挑战方面的工作。这是我们从 2016 年到 2017 年做的一个工作,这个软件叫做 SemEHR。该系统已在英国多家医院部署。技术细节在 2018 年发表在《美国医学会杂志》上的 a 论文(见上图)中,也在本次 Github Repo 中。在这里,我给出了与知识图相关的方法的非常高层次的描述。
应对知识表示的挑战
【统一医疗语言系统】(UMLS) 【UMLS】整合并分发关键术语、分类和编码标准以及相关资源,以促进创建更有效且可互操作的生物医学信息系统和服务,包括电子健康记录。https://www.nlm.nih.gov/research/umls/index.html
如果你还记得,第一个主要挑战是知识表示挑战。本质上,我们使用了一个本体,叫做 统一医学语言系统 。它涵盖了广泛的概念——2020 年发布的 440 万个。此外,UMLS 整合了大量的生物医学本体——准确地说是 215 个。

作者图片——在 UMLS,1 型糖尿病有 56 种不同的名称
在 UMLS,每一个概念都有一套标签,定义了所有的同义词,在不同的语言中也是如此。例如,对于1 型糖尿病,在 UMLS 有 56 种不同的同义词或缩写(见上图)。它还有一个 prefLabel 属性,该属性给出了概念的首选标签。这些属性对于我们的 NLP 任务非常有用。

作者图片——1 型糖尿病的文字描述:清晰明确的概念描述,包括表型、病因和治疗。它提到了关键的临床特征(上面蓝色的文字)。这样的信息允许计算机通过数学表示(如文档嵌入)来捕捉语义。
除了结构化属性,UMLS 还提供了每个概念的文本描述(见上面的例子),这本质上是概念的临床或生物医学解释。这些信息对于计算机以某种数学表示形式捕捉概念的meaning非常有用。例如,使用 word2vect 或 doc2vect 模型。这种表征将有助于 NLP 任务显著地特别是在歧义消除任务中,即“她感冒了”中的感冒不同于“今年冬天感冒了”中的感冒。

按作者分类的图像-以机器可以“理解”和进行推理的方式表示知识。(这是一个简化的表示,整合了来自各种本体的数据。)
此外,UMLS(与其他本体互连)还以图形格式提供概念之间的关联。了解哪些概念与一个概念相关,以及它们是如何关联的,使得计算机能够进行大量智能计算,其中一些将做出临床上合理的推断。例如,知道 1 型和二型糖尿病都是一种特定类型的糖尿病,二甲双胍用于治疗二型糖尿病,计算机可能会推断这种药物可能对 1 型糖尿病有用。从计算上来说,这个推论是通过在图上走几步来做出的(见上文)。这样的推论实际上具有临床意义,正如一些临床指南所建议的:
二甲双胍可用于超重的 1 型糖尿病患者,他们希望改善血糖控制,同时尽量减少胰岛素的剂量。
应对低资源学习挑战
现在让我们看看第二个主要挑战——低资源学习,这意味着我们没有针对所有疾病或表型的足够的训练数据。
为了解决这个问题,我们实现了两种方法。第一种方法的想法很简单:因为我们不能提供一个超级好的 NLP 模型,我们提供一个基线模型,它可以给你 NLP 结果,对某些研究来说可能足够好,也可能不够好。在基线模型之上,我们实现了一个验证和迭代改进机制,使每个用户能够通过手动评估随机选择的一小组 NLP 结果来检查性能。该系统将从评估中生成性能指标,如果性能足够好(由用户决定),那么每个人都很高兴。NLP 结果已准备好供下游使用。如果不够好,评估基本上是一小组标记数据,它们将作为进一步的训练数据反馈给 NLP 系统,以进一步改进 NLP 模型。反复进行这样的评估和改进将有希望达到性能足够好的阶段。通常,它需要 5-6 次迭代。当然,也有模型无法改进的情况。
由于篇幅所限,第二种做法我就不说了。相反,如果你有兴趣,请查看这篇论文:https://doi.org/10.2196/14782。
将这些结合起来解决两个主要挑战

图片作者——seme HR 系统架构:基线 NLP 使用 KG +持续学习解决两个主要挑战
让我们来看看在 SemEHR 中,为了应对两个主要挑战,事情是如何结合在一起的。这个图是 SemEHR 的系统架构。让我们跳过单个组件的细节。三个水平的灰色矩形表示三个子系统。最上面的一个是生产子系统,它利用 UMLS(又名生物医学 T-box)来生产基线 NLP 系统。这解决了知识表示的第一个主要挑战。
中间的灰色矩形是所谓的持续学习子系统,它实现了一个迭代学习框架,以实现基于用户验证反馈的逐步改进。
底部的矩形是处理第三个挑战的消费子系统,我称之为使用该系统的第二个挑战。让我们用一个用例来说明知识图是如何对此有所帮助的。
缓解挑战#3 的自动推理
2017 年,我支持了一项关于情绪稳定剂和心脏病之间联系的研究。

按作者分类的图像—知识图格式的自然语言处理结果
假设我们的 NLP 结果生成了这样一个简单的结构化知识图。它说:一个病人Pat001开了一个 ID 为13965000的东西的处方,这个东西有一个更好的名字叫做Valproic acid;同样,这个病人有一个 ID 为doc0123的文档,它提到了另一个 ID 为HP_0001658的东西,它有一个 preferredName Mayocardial infarction。
好了,现在,为了回答我们的研究问题,我们有第一个问题:
有服用情绪稳定剂的病人吗?
只看 A-box 数据(上图),电脑可能会说不,我没有看到任何服用该药的患者。但是,请记住,我们使用知识图技术从自由文本中填充数据。知识图还有另一个重要的组成部分,叫做 T-box。

作者照片——SnO med-CT 称丙戊酸是一种情绪稳定剂
在这种情况下,从一个叫做 SNOMED CT 的临床术语中,集成了 UMLS,有一个公理说这个东西13965000是358927005的一个子类,它有一个标签叫做mood stablizing drug。

作者照片——计算机用 T-box 知识扩展你的 A-box,推断 Pat001 实际上是情绪稳定器
有了这个公理,实际上,计算机可以用一个新的断言扩展我们的 A-box,这告诉我们Pat001实际上是在一种类型的情绪稳定器上。(见左)
好,我们研究问题的第二个疑问是
情绪稳定剂使用者有心脏病吗?

作者照片——来自两个本体论的 T-box 公理,说心肌梗死实际上是一种心脏病
同样,使用 A-box 只有计算机会说不。但是,使用 T-box 扩展,在这种情况下,使用两个本体(见上文),A-box 可以被扩展。现在,我们知道Pat001实际上患有一种叫做myocardial infarction的心脏病。
最终的知识图包括使用的 T-box 公理和扩展的 A-box 断言,如下所示。

作者图片—包括相关 T-box 公理+扩展 A-box 的完整知识图
基于规则的推理
我们刚才看到的推理都是基于 T 盒中公理的推理的子类。此外,还有基于规则的推理,使计算机更加智能。例如,我们知道ischemic stroke是一种stroke类型,大脑的血液和氧气被阻断。所以,如果我们给计算机一个基于 T-box 概念的规则,说任何人都有STROKE和BLOCKED BRAIN BLOOD VESSEL,那么这个人很可能有ISCHEMIC STROKE。所有这些大写单词都是 T 字盒中的概念,例如 UMLS。

按作者分类的图像-使用特定于域的规则推断笔画子类型
然后,有了这个规则和这个 A 框,计算机就能推断出Patient 001有ischemic stroke。
案例研究:从自然语言处理到知识驱动的表型分析
开发英国生物银行疾病分型的自动化方法:一项关于中风的范例研究。
rannikme 等《BMC 医学信息学与决策》第 21 卷,文章编号:191 (2021)。https://doi.org/10.1186/s12911-021-01556-0
最近,我们与英国生物银行合作,应用这种知识图技术从自由文本数据中自动进行疾病分型(rannikme 等人 DOI:10.1186/s 12911–021–01556–0)。英国生物库是一项大型长期生物库研究,有 50 万参与者。在之前的研究中,我们发现 40%的中风发病率被编码为未指定,这意味着对于这些患者,结构化数据无法告诉您患者患有何种类型的中风。我们知道不同的中风需要不同的治疗方法。只知道未指明的中风在临床上用处不大。
我们的假设是,我们可以使用知识图+ NLP 技术从自由文本数据中自动导出中风亚型。我们获得了这些患者的脑成像报告,并使用 SemEHR 来识别所有中风相关的表型。

作者图片——诊断蛛网膜下腔出血中风的神经科医生书面规则
然后,我们请领域专家,即神经学家,写下他们诊断中风亚型的规则。这些规则随后被编码到我们的 T-box 中。然后,前面提到的推论被应用于从 NLP 结果中自动推断中风亚型。我们证明了这种方法对中风非常有效。
显然,这是一个超越 NLP 进行患者水平表型分析的范例研究,这要感谢知识图技术的力量。
虽然我们在这种情况下只专注于中风,但这样的技术肯定适用于广泛的疾病,因为我们使用的知识图涵盖了所有人类疾病。
总结:反思与思考
好了,这就是我想和你分享的所有主要内容。现在,让我们花点时间快速回顾一下我们讨论的内容,以及我对医疗保健知识图表挑战的一些想法。
- 我们已经讨论了知识图的概念,知识图由描述领域中的概念及其关系的 T 盒和描述实体及其关系的 A 盒组成。
- 我介绍了 SemEHR 系统,它使用知识图和 NLP 技术从自由文本健康数据中识别所有人类疾病。
- 具体来说,我们讨论了这些技术如何帮助解决三个挑战:实现中的两个主要挑战和使用中的一个挑战。
在医疗保健中使用知识图谱的作品有哪些?
因此,如果我必须用一句话来总结知识图表对医疗保健的好处,那将是:提供超级有价值的生物医学 T-box 加上轻量级推理机制。
医疗保健知识图谱缺少什么?
当前健康知识图表中缺少什么?我想说的第一件事是患者层面的知识缺失。当你把一个病人生命时间线上的事情结合起来,事情确实是互相冲突或者有因果关系的。但是目前的知识图技术不能代表这些。例如,我们知道,如果一个人患有 1 型糖尿病,他/她就不太可能患有二型糖尿病。但是我们没有在任何本体论中表达这种冲突的知识。
同样,缺血性卒中和出血性卒中都有可能吗?思维敏捷的人可能会说不,因为这两种机制不兼容。但是,如果一个病人发生了缺血性中风,然后摔了一跤呢?同样,我们在患者水平上没有这样的机制知识表示。
从头开始推导抵押贷款摊销公式
通过 Python 可视化探索房地产中的数学之美
一.定义
如果你在抵押贷款上付了首付,很可能你是在申请分期偿还贷款。
分期偿还贷款是指你每月支付的确切金额,以便在贷款期限结束时还清债务和利息。
每月摊销包括利息支付和本金支付。利息支付归入利息,而本金支付归入你的实际债务。

Source Huy Bui
值得注意的是,当你的债务减少时,下个月的利息减少,本金增加。你支付的利息越少,你就能投入越多的钱来减少潜在的债务。
比如你买了一套 30 万美元的房子,首付 20%。利率是 3.5%,你打算在 30 年内还清。这是你每年必须支付的费用。

来源:卡尔的抵押贷款计算器
本金栏的总和是房贷的 80%(首付 20%),利息栏的总和是贷款人的利润。请注意,每一期你都支付相同的金额。
二。衍生物
让我们从表示不同的变量开始:

每个月j我们支付相同的金额x,

每个月的利息都是按照余额来计算的。重复这个逻辑,我们得到:

通过首先展开所有的项,递归可以转化为一个排他的公式…

…然后观察模式来推断出本金,

N期的总额是原始本金加上所有月份的总利息,

因此,

因为分母看起来像几何和,

我们可以进一步简化,得到月付款 x,

这些公式将有助于我们稍后开发 Python 代码。
三。密码
应用公式(1)、(2)和(3),我们获得以下代码:
假设我们借 24 万,30 年后年息 3.5%。结果是:

最后,我们用 Plotly 添加了一些可视化

您可以在此访问互动版本。
我们只是从零开始推导摊销公式,并用 Plotly 可视化我们的结果。
你可以在 LinkedIn 上找到我
利用交叉熵损失推导反向传播
最小化分类模型的损失
你可以为你的神经网络选择无数的损失函数。损失函数的选择对于网络的性能是必不可少的,因为最终网络中的参数将被设置为使得损失最小化。

可爱的狗和猫[1]
如果手头的问题是一个分类问题,交叉熵损失是一个流行的选择,并且它本身可以被分类为类别交叉熵或多类交叉熵(二元交叉熵是前者的特例)。)如果你对这些有多大的不同感到困惑,我会在深入研究它们的起源之前尝试介绍每一个。
让我们从分类交叉熵开始。对于这个损失函数,我们的 y 被一键编码以表示我们的图像(或任何东西)所属的类别。因此,对于任何 x, y 的长度等于类的数量,并且我们的模型中的最后一层对于每个类有一个神经元。我们在最后一层使用 Softmax 来得到 x 属于每个类的概率。这些概率总和为 1。

范畴交叉熵举了一个例子。 aᴴ ₘ是最后一层(h)的第个个神经元
我们将这个故事作为一个检查点。在那里,我们考虑了二次损失,最后得到了下面的等式。

L=0 是第一个隐藏层,L=H 是最后一层。δ是∂J/∂z
注意,最后一层的输出(激活向量)是 aᴴ ,在索引符号中,我们将写 aᴴₙ 来表示最后一层中的第个神经元。这同样适用于预激活向量 z ᴴ.
在上面的系统中,我们期望改变的唯一方程是δ ᴴ 的方程,因为我们使用了损失函数的显式公式来找到它。因此,我们将只处理推导过程中的最后一层,所以我们现在也可以去掉上标,并且记住,每当我们写 a 、 z 或 δ 时,我们都是针对最后一层的。
由此,损失函数为

范畴交叉熵。
随着最后一层中第个第 n个神经元的激活

Softmax 激活。我们将在下面多次使用它。牢记在心。
请注意,第个神经元的激活取决于该层中所有其他神经元的预激活。如果最后一层涉及 Sigmoid 或 ReLU 激活,情况就不会如此。由于这个原因,为了找到最后一层中某个神经元的δ,我们使用链式法则

等式 1.0
如果我们把它写成

考虑 m=n 且 m≠n,然后相加
从∂J/∂开始我们可以写一个 ₙ

第 n 个神经元是∂ 和ₙ求和的唯一幸存者
对于∂,我们有一个ₙ/∂zₙ

你可以用商法则得到导数,但是还有其他方法值得一试。
现在把我们的结果相乘,代入原来的方程,我们得到

通过插入等式。一
对于剩余的总和,让我们首先通过写来计算∂J/∂ a ₘ

如果一个公式包含所有内容的总和,你可以随时改变指数以避免混淆
然后对于∂ 一个 ₘ/∂zₙ ( m≠n )我们有

你也可以使用商法则得到同样的结果。
现在将两个结果相乘,我们得到

并将其传播回我们得到的原始方程

这可以简化为

假设 y 是一个热矢量,我们知道σₘyₘ=1;因此,我们可以写

或者在重新加上上标(H 表示最后一层)后以矢量形式显示

为了结束证明,让我们把反向传播方程更新为

只有红色的变了。
我们还没有完全做到。使用分类交叉熵,你的模型可以很好地将下面的图片分类为一只狗;但是,您的数据集可能包含许多既有猫又有狗的图像。在这种情况下,如果图像中存在两个类, y 不再是一个热点向量(而是看起来类似于[0 1 0 0 1]。)于是,我们使用多类交叉熵,在最后一层避免使用 Softmax 相反,我们使用乙状结肠。如果一个类的 Sigmoid 激活大于某个阈值(例如 0.5),则我们推断该类存在于图像中。)

快乐的狗[2]
一个例子的多类交叉熵损失函数由下式给出

aᴴ ₘ是最后一层(h)中的第个神经元**
如果我们回到去掉上标,我们可以写

因为我们使用乙状结肠,我们也有

不像 Softmax a ₙ只是 zₙ的一个功能;因此,为了找到最后一层的 δ ,我们需要考虑的是

情商。2
或者更准确地说

哪个是

通过微分(就像我们之前做的那样)然后把我们得到的两个分数相加

现在我们需要在代入方程 2.0 之前考虑∂是ₙ/∂zₙ

这只是 Sigmoid 函数的导数

用ₙ代替它的定义,我们得到

你可能已经知道了。
现在使用原始方程中的两个结果

因此,

现在重新加上上标,用向量的形式写出来

这与我们用 Softmax 作为激活的范畴交叉熵得到的结果非常相似。所以我们仍然使用

作为我们的反向传播方程。
如果你喜欢阅读,并希望看到更多这样的故事,那么请考虑给帖子一些掌声,并跟我来。下次见,再见。
参考文献:
[1] Pixabay ,2021,https://pix abay . com/de/photos/haustiere-nied lich-katze-hund-3715733/。【2021 年 10 月 2 日访问。
[2]洛罗伊,波林。“照片由 Pauline Loroy 在 Unsplash 上拍摄”。Unsplash.Com2021 年https://unsplash.com/photos/U3aF7hgUSrk.2021 年 10 月 2 日访问。
贝叶斯定理的简易推导
基本原则
从基本概念到更深层次的理解

在 Unsplash 上由 Zuzana Ruttkay 拍摄的照片
我还记得第一次看到贝叶斯定理的方程。我对概率论或数学符号一无所知,完全不知所措。
我迷失了,因为我根本没有概率论基础。
在本文中,我们将构建这个基础。使我们能够推导和理解贝叶斯定理,该定理在工业(例如金融)和机器学习(例如分类、贝叶斯优化)中仍然发挥着重要作用
打基础

为了能够推导出贝叶斯定理,我们首先需要放下一些基本概念。扎实的基础,以及强烈的直觉,会让我们更容易、更深刻地理解贝叶斯定理。
在接下来的章节中,我们将学习条件概率、乘法法则、全概率定理,最后是贝叶斯定理。
但首先,让我们创建一个真实世界的场景,使我们能够非常直观地推导出基本概念。
场景:机器缺陷率

机器缺陷率示例[图片由作者提供]
在我们的场景中,我们使用三台机器,每台机器生产相同类型的产品,但产出比例不同。例如,总产量的 20%由机器 A 生产,30%由机器 B 生产,50%由机器 C 生产。此外,每台机器都有特定的缺陷率,例如机器 C 生产的产品有 1%有缺陷。
到目前为止,我们将很快回到这个例子,但首先,让我们走一个小弯路。
条件概率
想象一下,我们知道一个人在随机的一天咳嗽的概率大约是 5%。现在想象我们也知道这个人感冒了。这难道不会改变我们对这个人咳嗽可能性的看法吗?
条件概率测量一个事件 A 发生的概率,假设另一个事件 B 已经发生。换句话说,可以看作是概率 B 与 a 相交的分数。

A 和 B 的交集[图片由作者提供]
形式上,条件概率可以定义 (Kolmogorov 定义)如下:给定 B 的概率等于 A 和 B 相交的概率除以 B 的概率。

我们可以重新排列上面的等式,它直接把我们引向乘法法则。
乘法法则
不严格地说,乘法规则允许我们在我们的示例中沿着分支乘以概率。所以可以解释为 B 的概率乘以 A 的概率,假设 B 已经发生。

现在让我们将我们的新知识应用到我们的场景中。机器 A 生产的产品有缺陷的概率是多少?
我们知道机器 A 生产一个单位的概率是P(A) = 0.2并且一个产品有缺陷的概率是P(B|A) = 0.05使用沿着“顶部分支”的乘法规则,我们得到以下结果:

因此,有 1%的机会,一个单位是由机器 A 生产的,是有缺陷的。
全概率定理
全概率定理表达了几个不同事件的结果的全概率。在我们的场景中,这将是一个项目有缺陷的总概率的问题。
为了计算总概率,我们只需将乘法规则应用于所有“有缺陷率的分支”并将结果相加。

代入我们场景中的概率,我们得到的总概率是 2.4%。

贝叶斯定理
最后,我们收集了推导贝叶斯定理所需的所有部分,如下式所示:

到目前为止,我们应该能够认识到等式中一些熟悉的部分。
分子 P(B|A)P(A)无非是乘法法则或者一个条件概率的定义,我们之前用过。分母 P(B)就是全概率定理,我们在前面的部分也应用了。
但是贝叶斯定理有什么特别之处呢?
贝叶斯定理允许我们从经验中学习,基于相关条件的知识更新我们先前的信念。
假设我们想知道机器 C 生产随机选择的缺陷产品的概率。根据产量比例,我们的先验信念可能是P(C) = 0.5,因为机器 C 生产了总产量的一半。
然而,我们现在得到了额外的信息,因为我们知道这个项目是有缺陷的。这个相关条件允许我们应用贝叶斯定理,并用后验置信更新我们的先验概率。
计算概率我们得到以下结果:

C =机器 C;E =缺陷项目
虽然机器 C 生产了总产量的一半,但它生产的次品与总产量的比率要小得多。因此,我们先前 50%的概率可以更新为 20.83%。
结论
在本文中,我们学习了条件概率的定义和乘法法则。我们还利用全概率定理最终导出了贝叶斯定理,这多少是偶然的。
尽管贝叶斯定理是在将近 250 年前发明的,但它仍然很重要。它的核心是整合新获得的信息的能力,或者换句话说,从经验中学习。
喜欢这篇文章吗?成为 中等会员 继续无限学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。
https://medium.com/@marvinlanhenke/membership
参考资料/更多资料:
视频讲座:麻省理工学院 2012 年春季课程概率导论
从数据中获取最有利可图的电影情节
实践教程
一种情感驱动的方法来识别哪种情节线可以最大化收益。

图片来自 Pixabay 的 Igor Ovsyannykov 。
介绍
在当今世界,故事(在电视节目、电影、书籍、甚至商业广告中)通常采用几个著名的情节之一。例如,有一个“白手起家”的故事,主角开始于冲突,结束于幸福(例如汉瑟尔和葛丽特、灰姑娘、奥斯汀的傲慢与偏见等)。).有一个“洞里的人”故事(最常见的一个),主角快乐地存在,但经历痛苦和损失来解决问题,最终最终回到他们的快乐中(例如迪士尼的海底总动员,托尔金的霍比特人等)。).有些故事不符合任何特定的模式,但仍然保留了其他类别的特征。
尽管如此,电影还是吸引了每个人的注意力。尤其是在 2020 年(到目前为止是在 2021 年),电影是人们娱乐的方式!所有的注意力都集中在电影上,一个相关的问题是:
哪种类型的故事弧线最成功?在电影界会赚钱的「理想」故事情节是怎样的?
为了找到答案,我提取了一些电影元数据(收入、片名等。)从 Kaggle 上的一个数据集中找到了另一个包含了维基百科大约 35000 部电影的情节描述。你可以在我的 GitHub 上找到这个项目的代码,这里。
数字化电影的情感
我的方法是用电影情节来传达电影中特定时刻的整体情感。更具体地说,我想对一部电影进行完整的情节总结,并逐句进行情感分析,以构建故事曲线。比如下面是灰姑娘的剧情描述 : 的节选
灰姑娘是一个善良的年轻女子,她与邪恶的继母和丑陋的继姐妹住在一起。他们虐待她,把她当成女佣。灰姑娘认为她在这个世界上是孤独的,但不知道有一位仙女教母一直在帮助她。
情绪分析程序可能会查看这些简短的句子,并将前两个句子解释为明显的否定,而将第三个句子解释为带有一点肯定的否定(因为“help”是句子的关键部分)。因此,我们可以得出结论,在电影的这一点上,事情看起来对灰姑娘不是很好。
我的目标是用这种方法构建每部电影的情节,然后根据它们的成功程度(电影的年收入)进行加权平均。这也可以解释为大多数人喜欢看的电影。这样我更关注表现好的情节。
在我对情节描述进行情感分析后,我最终得出了描绘出电影大致情节的数字。对于大部分电影来说,它真的很好。这是《T2》的灰姑娘(1950 年)的剧情曲线:

灰姑娘的剧情曲线。灰姑娘开始贫穷(1),发现她有一个仙女教母(2),在午夜钟声敲响时离开王子(丢失了她的拖鞋)(3),然后最终与白马王子在一起,从此幸福快乐(4)。图片作者。
注意 y 轴上的负数对应的是负面情绪。灰姑娘从消极开始,变得积极,再次变得消极,然后最终以积极结束。
另一个更复杂的例子是十二怒汉 (1957):

十二怒男剧情曲线。这部电影以相当积极的态度开始(1),然后随着人们争论(2),改变立场(3) (4)而遇到问题,最后达成决议(5) (6)。图片作者。
结果:“理想”电影
对所有情节进行简单的平均会得出有史以来最常见的电影情节:

电影的平均曲线展示了一个“洞里的人”的情节。图片作者。
不出意外,是“洞里的人”故事情节。这看起来有点道理,因为这是一个更容易创造的弧线,让观众最终感到完整和满足(对儿童电影尤其有用!).更多这样的例子你可能知道:迪士尼的怪兽公司,刘易斯·卡罗尔的爱丽丝梦游仙境和后天 (2004)。
但我试图回答的问题不是哪种弧最常见,而是哪种弧最成功。
我按总收入对每部电影进行了加权(本质上是少关注表现不那么好的电影,多关注成功的电影),并重新计算了电影情节。

收入加权平均电影曲线。arc 还是“洞里人”的变种!图片作者。
“理想的”故事弧线是…那个“洞里的人”!这种情节极其常见(这意味着有大量的失败和成功,但大多数是失败,因为在电影中做好是一项艰巨的任务),但它表现如此之好的事实充分说明了其他主题和角色赋予简单情节的力量。
世界上如此多的古代神话(从希腊人到古印度人到阿兹特克人)主要基于洞中男人的故事情节是有原因的。我个人觉得很有趣的是,一个最古老和最受欢迎的故事类型继续在我们的现代世界中存在,甚至通过多种媒介。
描述性统计:期望与现实(探索性数据分析)
一种简单的描述性统计方法,通过对每个探索性数据分析过程的集中趋势测量和扩散测量来总结数字和分类数据变量。

凯瑟琳·汉隆在 Unsplash 上的照片
关于探索性数据分析(EDA)
EDA 是数据分析过程的第一步。它允许我们通过描述** 和 总结数据集的主要特征来理解我们正在处理的数据,通常通过可视化** 方法如条形图和饼图、直方图、箱线图、散点图、热图等等。
EDA 为什么重要?
- 最大限度地洞察数据集(能够倾听您的数据)
- 揭示潜在的结构/模式
- 检测异常值和异常情况
- 提取和选择重要变量
- 提高计算效率
- 测试潜在假设(如商业直觉)
此外,为了能够探索和解释数据集的特征及其所有属性,获得数据的洞察力和有效的数字摘要,我们需要描述性统计的帮助。
统计分为两个主要领域:
- 描述性统计:描述和汇总数据;
- 推断统计学:利用样本数据对总体做出一般性结论(推断)的方法。
本教程重点介绍数字变量和分类变量的描述性统计数据,分为两部分:
- 集中趋势的度量;
- 展开的措施。
描述统计学
也称为单变量分析(一次一个特征分析),简而言之,描述性统计通过给出关于样本和数据测量的简短数字摘要来帮助描述和理解特定数据集的特征。
描述性统计仅仅是探索,因为它们不允许我们在已经分析的数据之外做出结论,或者得出关于我们可能做出的任何假设的结论。
数字和分类变量,正如我们将很快看到的,有不同的描述性统计方法。
让我们回顾一下变量的类型:

变量类型-按作者分类的图像
- 数值连续:数值不可数,有无限多种可能(某人的年龄:25 岁 4 天 11 小时 24 分 5 秒等等到无限)。
- 数值离散:数值是可数的,有有限个可能(欧盟不可能数出 27.52 个国家)。
- 分类序数:层次中隐含着一个顺序(一月总是在二月之前,十二月之后)。
- 分类名词:等级中没有隐含的顺序(女性/男性,或者风向:北、南、东、西)。
数字变量

数值连续变量的直方图。作者图片
- 集中趋势的测量:平均值、中间值
- 扩散的度量:标准差、方差、百分位数、最大值、最小值、偏斜度、峰度
- 其他:大小、唯一、唯一数量
一种显示数据的方法是通过箱线图。它给出了 5 个基本统计数据,如最小值、第一个四分位数(第 25 个百分位数)、中值、第三个四分位数(第 75 个百分位数)和最大值。

数值连续变量的箱线图。作者图片
分类变量

分类序数变量的条形图。作者图片
- 集中趋势的测量:模式(最常见)
- 扩散的度量:唯一数
- 其他:大小,%最高唯一
理解:
集中趋势测量
- 均值(平均值):数值总和除以总观测值。平均值对异常值高度敏感。
- 中位数(中心值):一个有序数字序列的总计数除以 2。中位数不受异常值的影响。
- 模式(最常见):最常观察到的值。同一个变量中可以有多个模态值。
传播的量度
- 方差(平均值的可变性):标准差的平方。它也会受到异常值的影响。
- 标准差(集中在平均值周围):偏离平均值的标准量(距离)。std 受到异常值的影响。它是方差的平方根。
- 百分位数:数据百分比低于该值的值。第 0 个百分点是最小值,第 100 个百分点是最大值,第 50 个百分点是中间值。
- 最小值:最小或最低值。
- 最大值:最大或最高值。
- 唯一数(完全不同):完全不同的观察值的总数。
- unique(distinct):观察到的不同值或值组。
- 偏斜度(对称):一个分布从正态分布中派生出来的程度。 > >在下一节解释歪斜的概念。
- 峰度(离群值的数量):尾部有多长,分布的峰值有多尖锐。
> >在下一节解释峰度概念。
其他人
- 计数(大小):观察值的总和。计算平均值、中值和众数也需要计数。
- %
歪斜
在理想情况下,数据的分布假定为钟形曲线(高斯或正态分布),但在现实世界中,数据分布通常是不对称的(=偏斜的)。
因此,偏斜度表示我们的分布从正态分布(偏斜度值为零或非常接近)派生的程度。

偏斜曲线。作者图片
有三种通用类型的分布:
- 对称【中值=均值】:在正态分布中,均值(平均值)在中值或接近中值处对称地划分数据。
- 正偏斜【中位数<均值】:分布不对称,尾部向曲线右侧偏斜/变长。在这种类型中,大部分观察值集中在左尾,偏度值为正。
- 负偏斜【中值>均值】:分布不对称,尾部向曲线左侧偏斜/变长。在这种类型的分布中,大多数观察值集中在右尾,偏度值为负。
经验法则:
- 对称分布:数值在- 0.5 到 0.5 之间。
- 中度歪斜:数值在- 1 和-0.5 和 0.5 和 1 之间。
- 高偏斜:值 < -1 或 > 1 。
峭度
峰度是量化分布形状的另一个有用工具。它测量了尾部有多长,但最重要的是,以及分布的峰值有多尖锐。
如果分布具有更尖锐、更高的峰和更短的尾部,则它具有更高的峰度,而当分布的峰更平坦且尾部更细时,可以观察到低峰度。峰度有三种类型:

峰度曲线。作者图片
- Leptokurtic :分布高瘦。轻子的值必须是> 3。
- 这个分布看起来与正态分布相同或非常相似。一个“正常的”中间黑洞的值是= 3。
- Platykurtic :分布具有更平坦、更宽的峰值和更细的尾部,这意味着数据适度分散。platykurtic 的值必须是< 3。
峰度值仅决定异常值的数量。
峰度是通过将标准化数据的平均值提高到四次方来计算的。如果我们将任何标准化数字(小于 1)提升到 4 次方,结果将是一个非常小的数字,接近于零。如此小的值不会对峰度有太大贡献。结论是,对峰度有影响的值应该是远离峰值区域的值,换句话说,就是异常值。
Jupyter 笔记本— IPython
在本节中,我们将给出关于数据集的集中趋势和离散度的不同度量的简短数字统计摘要。
让我们通过熊猫的描述性统计环境来研究一些实际的例子。
> 回购代码此处 。
从导入所需的库开始:
import pandas as pd
import numpy as np
import scipy
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
加载数据集:
打印数据:

作者图片
在进行任何统计演算之前,我们先来看一下的数据 :
df.info

作者图片
数据集由 310 个观察值和 2 列组成。一个属性是数字的,另一个是分类的。两列都没有缺失值。
数字变量
我们要分析的数值变量是age。第一步是目视观察变量。让我们画一个直方图和一个箱线图。
plt.hist(df.age, bins=20)
plt.xlabel(“Age”)
plt.ylabel(“Absolute Frequency”)
plt.show()

年龄直方图。作者图片
sns.boxplot(x=age, data=df, orient="h").set(xlabel="Age", title="Numeric variable 'Age'");

年龄箱线图。作者图片
也可以结合直方图和箱线图直观地观察变量。我发现这是一个有用的图形组合,并在我的报告中大量使用。
age = df.agef, (ax_box, ax_hist) = plt.subplots(2, sharex=True, gridspec_kw= {"height_ratios": (0.8, 1.2)})mean=np.array(age).mean()
median=np.median(age)sns.boxplot(age, ax=ax_box)
ax_box.axvline(mean, color='r', linestyle='--')
ax_box.axvline(median, color='g', linestyle='-')sns.distplot(age, ax=ax_hist)
ax_hist.axvline(mean, color='r', linestyle='--')
ax_hist.axvline(median, color='g', linestyle='-')plt.legend({'Mean':mean,'Median':median})
plt.title("'Age' histogram + boxplot")ax_box.set(xlabel='')
plt.show()

年龄直方图和箱线图。作者图片
集中趋势测量
1.的意思是:
T4
35.564516129032256
2.中位数:
df.age.median()
32.0
传播的量度
3.标准差:
df.age.std()
18.824363618000913
4.方差:
354.3566656227164
5.a) 百分位数 25% :
df.age.quantile(0.25)
23.0
b) 百分位数 75% :
df.age.quantile(0.75)
45.0
c)在一气呵成 : df.age.quantile(q=[.25, .75)
0.25 23.0
0.75 45.0
Name: age, dtype: float64
6.最小值和最大值 :
df.age.min(), df.age.max()
(3, 98)
7.偏斜度(带 scipy):
scipy.stats.skew(df.age)
0.9085582496839909
8.峰度(带 scipy):
scipy.stats.kurtosis(df.age)
0.7254158742250474
其他人
9.尺寸(行数):
df.age.count()
310
10.唯一数(完全不同)
df.age.nunique()
74
11.独特的(独特的):
df.age.unique()
array([46, 22, 54, 33, 69, 35, 11, 97, 50, 34, 67, 43, 21, 12, 23, 45, 89, 76, 5, 55, 65, 24, 27, 57, 38, 28, 36, 60, 56, 53, 26, 25, 42, 83, 16, 51, 90, 10, 70, 44, 20, 31, 47, 30, 91, 7, 6, 41, 66, 61, 96, 32, 58, 17, 52, 29, 75, 86, 98, 48, 40, 13, 4, 68, 62, 9, 18, 39, 15, 19, 8, 71, 3, 37])
分类变量
我们要分析的分类变量是city。让我们画一个条形图,并得到一个变量的视觉观察。
df.city.value_counts().plot.bar()
plt.xlabel("City")
plt.ylabel("Absolute Frequency")
plt.title("Categoric variable 'City'")
plt.show()

“城市”酒吧地块。作者图片
集中趋势测量
1.模式:
'Paris'
传播的量度
2.唯一数:
df.city.nunique()
6
3.独特的(独特的):
df.city.unique()
array(['Lisbon', 'Paris', 'Madrid', 'London', 'Luxembourg', 'Berlin'], dtype=object)
4.最频繁 唯一(数值计数):
df.city.value_counts().head(1)
Paris 67
Name: city, dtype: int64
其他人
5.尺寸(行数):
df.city.count()
310
- %
21.6%
describe()方法显示在一个表中收集的描述性统计数据。默认情况下,统计数字数据。结果被表示为熊猫数据帧。

作者图片
添加其他非标准值,例如“方差”。

作者图片
显示分类数据。
df.describe(include=["O"]) <=>df.describe(exclude=['float64','int64']) <=>df.describe(include=[np.object])

作者图片
通过传递参数include='all',同时显示数字和类别变量。
df.describe(include='all')

作者图片
结论
在 Pandas、Numpy、Scipy、Matplolib 和/或 Seaborn 的帮助下开发探索性数据分析项目时,这些是描述性统计的基础。如果执行得好,这些统计数据有助于我们理解和转换数据,以便进一步处理。
记住永远保持怀疑的态度。用自己的眼睛看数据(不要完全依赖统计数据),用图形直观化变量(视觉效果的使用和滥用)。
> 回购代码此处 。
查看您可能也想阅读的其他文章:
联系人
好的阅读,伟大的编码!
用 Tableau 设计动态数据仪表板
创建您自己的数据仪表板的分步指南

欧洲在 Unsplash 上拍摄的照片
*这篇文章有很多 gif。他们可能加载得有点慢。
在本文中,我将解释如何使用 Tableau 构建动态数据仪表板,以便用户可以选择指标和年份来评估销售业绩。
我将为这个项目使用 Tableau Public,它是免费的,您可以从这里下载:
https://public.tableau.com/en-us/s/
问题陈述
我将使用的数据集由 Udacity 数据可视化课程提供。这是一个超市数据集样本,可在以下位置找到:
基于数据集,我们的目标是建立一个动态仪表板。从仪表板上,观众应该能够了解到以下见解:
- 年度顶级收入、利润、利润比率和销售量。
- 按客户群(客户群是指公司、消费者、家庭办公室)划分的同比绩效。
- 按活动指标(从收入、利润、利润率和销售量)查看子类别绩效。
- 对于所选指标,每个客户群中表现最佳的子类别。
总的来说,构建这个仪表板有四个主要步骤:
- 首先,在 Tableau 中将顶级 KPI 格式化为 BANs。
- 然后,用折线图直观显示客户群的同比表现。
- 然后,用柱状图直观显示每个客户群下的年同比子类别绩效。
- 最后,定义指标和年度用户选择下拉列表。

仪表板概述
*我将订单日期列重命名为年份。很抱歉在下面的演示中可能会有混乱。
KPI
为主要 KPI 创建一个 BANs,如利润、收入、平均利润率和销售单位,这总是向不太了解数据集细节的观众展示您的见解的好方法。
我将一步一步地指导你如何在 Tableau 中创建这样一个 BANs。

KPI 演示第 1 部分
在第一部分中,我首先选择了我希望纳入禁令的 KPI。然后,我将每个度量拖到标记部分的标签中。默认情况下,Tableau 假定聚合是度量值的总和。但是,对于利润率,我们希望计算平均值,而不是总和。您可以通过右键单击标记 部分中的聚合度量来将其更改为平均值。

KPI 演示第 2 部分
在第二部分中,我通过右键单击年并选择显示过滤器来创建一个年过滤器。然后,通过左键点击标记部分的文本并选择三个点,我们可以更改 BANs 中正文文本的字体、大小和颜色。

KPI 最终版本
现在,我们已经完成了 KPI 部分,但是您可能会发现年度筛选器并不是可视化控制的最佳方式。例如,如果我们有多个工作表,并且每个工作表都包含一个年份过滤器,那么最终的仪表板看起来会非常混乱。因此,在本文的最后一部分,我将向您展示如何通过创建新的参数和计算字段在 Tableau 中添加自定义选择下拉列表。
同比细分市场绩效
除了之前的顶级见解,观众可能希望进一步了解每个细分市场的同比表现。
现在,我将指导您完成创建符合要求的线图的过程。

同比细分市场绩效
您也可以通过左键点击 SUM(Profit) 的箭头来编辑线图的颜色。
回到仪表板的要求,观众也应该能够看到一个活跃的指标(从收入,利润,利润率和销售单位)的表现。正如 KPI 部分末尾提到的,我们将在文章的最后部分创建活动指标和年度选择下拉列表。
同比子类别绩效
在这一步中,我将使用条形图显示在所选指标利润下每个细分市场的同比子类别绩效。

同比子类别绩效
此外,您还可以通过点击聚合度量并选择编辑颜色来编辑条形图颜色。
您可能会发现,在此图中,year 过滤器再次出现,它已经出现在前两个图中。没有必要在最终仪表板中保留每个图表的所有三年过滤器。
因此,现在我将介绍如何构建和连接年度和指标(来自收入、利润、利润率和销售量)过滤器的用户选择下拉列表。
用户选择

用户选择
我们想要实现的下拉列表将在最终的数据仪表板中显示如上。两个选择下拉列表,一个用于活动指标,一个用于选定的年份。
从 KPI 开始,我们需要将选择年定义为新的参数,将选择年定义为新的计算字段。

创建年度选择
由于您可以在其他工作表中使用新创建的参数和计算字段,您可以简单地用新的选择的年份替换图表中的任何年份变量,并重复显示参数步骤。它应该也适用于其他两个工作表。
最后,我们正在创建选择指标,它实际上比选择年份更容易。

创建度量选择
类似于选择年份,选择指标参数和**选择度量计算字段可以在其他表中找到。不同之处在于每个筛选器中的数据类型和公式。
最后,要创建一个仪表板并调整其布局,只需点击新仪表板图标,拖动您需要的工作表并将其作为您的设计进行移动。
我的最终仪表板如下所示:

最终数据仪表板快照
摘要
设计一个伟大的数据仪表板实际上涉及的不仅仅是数据科学。通常,我们希望它既有知识性(有见地)又有美感。有时,每个部分的文字大小、字体风格和颜色对浏览者是否会喜欢它并愿意停留更长时间有很大的影响。
在设计过程中,我发现了一些很棒的工具/网站,可以帮助你创建自己的数据仪表板。我会把它们列在灵感部分。
感谢您的阅读!希望你喜欢这篇文章,觉得有帮助~
灵感
**https://www.thedataschool.co.uk/ellie-mason/tableau-tip-formatting-bans https://blog.graphiq.com/finding-the-right-color-palettes-for-data-visualizations-fcd4e707a283 **
用七个步骤设计一个联合学习系统
构建企业联合学习系统时,您应该考虑什么?

介绍
像谷歌和苹果这样的公司已经开创了联合学习,作为一种在分布式数据集上建立更高性能的机器学习模型而不损害隐私的方式。今天,谷歌使用联邦学习来支持 Gboard 中的键盘预测,苹果使用它来提高 Face ID 和 Siri 的准确性。
但是如何开始呢?
虽然有很多很棒的资源描述了什么是联合学习,但是没有很多信息涵盖如何在你的业务中应用它。
本文旨在作为一个指南,帮助您建立一个可伸缩的联邦学习系统。因为不同用户和用例的需求可能不同,所以本指南不会为您提供所有答案。但是,它应该为您提供关键问题和注意事项,以帮助您设计适合您的系统。
在 integrate.ai (我是这里的工程主管),我们专注于让联合学习更容易实现。以下是我们发现的七个步骤:
- 第一步:挑选你的模型框架
- 第二步:确定网络机制
- 第三步:构建集中式服务
- 第四步:设计客户端系统
- 步骤 5: 设置培训流程
- 第六步:建立模型管理系统
- 第 7 步:解决隐私和安全问题
联合学习 101
在我们开始之前,让我们确保您对联邦学习有一个基本的了解。
与需要将数据集中起来进行训练的传统机器学习技术不同,联合学习是一种在分布式数据集上训练模型的方法。机器学习模型的部分在数据所在的地方被训练(例如,这些可以是来自两个或更多公司的私有数据集),并且模型参数在参与者之间被共享以产生改进的模型。没有数据在系统内移动,这意味着组织可以在不损害隐私或敏感知识产权的情况下进行协作,同时避免通过传统方式传输数据的痛苦和费用。
下面是一些可以使用联合学习的例子:
- 通过使用来自多个企业的数据改进机器人过程自动化解决方案中的自然语言处理模型
- 使用来自信用卡公司和银行的数据提高欺诈检测模型的准确性
- 利用广告商和出版商的数据改进归因模型
- 使用来自不同消费企业的数据增强个性化和推荐系统
- 使用来自多家医院的数据改进医疗诊断的计算机视觉模型
- 避免了出于机器学习目的将数据库迁移到一个集中位置的需要
是时候开始学习如何建立一个联合学习系统了。
为了简单起见,让我们假设我们正在进行水平联合学习。在这种情况下,机器学习任务的目标变量和输入在数据集之间是相同的,但是需要更多的样本来建立更好的模型。
步骤 1:选择你的模型框架

克里斯托夫·高尔在 Unsplash 上拍摄的照片
第一步是选择您的底层模型实现。您需要为您的应用程序选择一个对联邦学习有一定支持的模型框架。选择标准包括领域(如图像、NLP 或表格数据)、团队对技术的熟悉程度以及框架与现有基础设施的兼容性等项目。
PyTorch 或 TensorFlow 是热门选择;这些库为联合学习提供了一些工具,但要获得完整的解决方案,还需要添加额外的生产就绪组件。主要组件如下所述。
步骤 2:确定网络机制
接下来,您需要确定使用什么样的网络机制。这种机制是在联合学习网络中的每个参与者之间传递指令的消息格式和框架。
有几个选项可供选择,包括:
- PyTorch——open mined 的一个 py torch 框架,支持联合学习
- Flower —抽象消息流以支持多种建模框架的通用框架。
- tensor flow Federated—tensor flow 分配模型操作的方法
决定哪个选项适合您通常归结为您需要跨建模框架的网络机制有多灵活。例如,如果您的团队希望主要在 PyTorch 中工作,并且需要较低级别的建模操作,那么 PySyft 可能是一个不错的选择。
如果您希望优先考虑灵活性,那么 Flower 是一个不错的选择,因为它支持在不同的建模框架上进行联合学习。
网络和核心模型框架的选择也依赖于组织内部或多个组织之间的应用程序。在后一种情况下,选择需要为所有参与组织所接受。
现在,我们已经有了一些基础,可以开始构建一个联合学习系统了。
步骤 3:构建集中式服务

由罗德里戈·库格纳斯基在 Unsplash 上拍摄的照片
一旦选择了模型框架和网络机制,就需要建立一个集中的服务来管理参与者。这项服务将负责协调参与者之间的沟通,并监督培训进度。
从运营角度来看,该服务可能需要:
- 内置认证和授权机制,以及保持其可靠性的支持结构;这包括确保服务是无状态的,以帮助负载平衡,这意味着需要选择一种存储机制来保存客户端之间传递的中间信息。
- 以满足联合学习系统的需求。
- 能够管理培训课程。
从功能角度来看,还需要考虑其他关键的设计因素。例如:
- 是否需要添加授权或服务隔离来分隔不同的数据网络?也就是说,一些参与者可以一起协作,但不能在组之间协作。
- 客户可以触发培训课程吗?还是必须集中管理?
- 客户端断开连接和重新连接将如何影响培训?参加培训的缔约方的数量增加了这一问题。
- 在培训期间应该收集哪些统计数据,如何设置监控,以便系统可以测量被培训模型的质量?
- 该服务将如何管理以不同速度运行的参与客户端?
- 如果客户变得不可靠,系统如何知道何时放弃客户,以便模型仍然可以继续被训练?
花时间设计一个考虑到这些因素的系统对于确保您将要实现的系统是可靠的、灵活的和有价值的是至关重要的。
步骤 4:设计客户端系统

照片由 Unsplash 上的 israel palacio 拍摄
现在是时候考虑客户机系统的可能设计了。该系统需要能够执行客户端训练操作,并与中央服务协调模型参数。客户端系统还需要从网络中的其他客户端获取新参数,以更新本地模型。
为了设计和交付一个可靠的客户端应用程序,您应该尝试回答以下问题:
- 客户机系统应该是一个可安装的包,还是应该像 docker 映像一样?如何管理依赖关系版本?
- 客户端将如何进行身份验证并与服务器通信?
- 如何监控培训过程?
- 在模型训练过程中如何处理错误恢复?
步骤 5:设置培训流程
联合学习系统需要知道应该使用来自每个客户端的什么私有数据来训练特定会话的本地模型。
该信息需要来自另一个用户或中央服务。因此,必须以某种形式管理关于可用数据的元信息;这通常由中央服务来完成。
这也要求客户端注册关于哪些数据集可用于其他客户端的元信息。类似地,需要从中央服务中检索每个客户端的元数据,关于哪些数据集应该用于训练会话。
第六步:建立模型管理系统
训练会话的输出是机器学习模型。联邦学习系统需要管理模型度量和访问,以便适当的用户可以使用经过训练的模型。
以下问题可用于指导系统如何管理模型:
- 是所有的参与者都可以访问模型的副本,还是只有部分参与者可以访问它?
- 模型将存储在哪里(通常由集中服务存储)?
步骤 7:解决隐私和安全问题

最终模型对一个或多个参与者是本地可用的。因为该模型是通过在不同方之间共享权重来训练的,所以反转该模型以检索关于底层训练数据的洞察是可能的。
因此,确定模型本身的可接受风险非常重要。这些风险可能包括能够重新识别特定训练集中的个人或重新生成训练集本身,这可能包含参与者不想暴露的敏感 IP。
减轻这些风险有不同的方法;一个例子是在传输到中央服务之前对模型权重应用差分隐私。通过调整隐私预算,可以平衡最终模型的效用和您认为可接受的风险量。
优化模型风险与模型性能取决于用例,因此在做出决策时让合适的利益相关者参与进来非常重要。
结论
联合学习有巨大的潜力成为数据科学家的关键工具,使他们能够在分布式数据集上训练更好的模型,而不会损害隐私或敏感的知识产权。然而,理解在企业中从哪里以及如何开始实现联合学习似乎是一项艰巨的任务。
我希望上面的步骤有助于指导您使用联邦学习。如果你对本指南有任何问题或反馈,我很乐意在评论中讨论。
用 pytorch 设计神经形态预测网络结构
用脉冲神经元网络进行深度学习——脉冲神经网络是未来吗?
朋友们好,今天我们将看到一个非常有趣的话题,用第三代神经网络构建一个脉冲神经元网络,即脉冲神经网络(SNN)。我们将看到低代码解决方案“ pynmsnn ”是一个 python 库,可以轻松用于设计&部署这样一个具有 snn 的神经形态预测模型。
为什么要建立神经形态 SNN 预测模型?
神经形态结构非常类似于我们用来进行计算的生物大脑结构。简单地说:神经形态脉冲神经网络密切模仿我们的生物神经元的工作方式。人们可以使用这些类型的网络来绕过具有少量样本或数据点的数据中传统的学习规则的缺乏,并且还特别针对没有潜在模式和趋势的数据,该数据基于原理“一起激发的神经元,连接在一起”,这是来自 hebbian learning 的著名习语。在 SNNs 中,有一个时间轴和神经网络通过时间看到数据,并且激活函数是超过某个预激活阈值的尖峰。如果神经元不够兴奋,预激活值会不断减弱。把它想象成一个时间分布的 ReLU,在特定的时间步长上有尖峰或者没有尖峰。
更多细节请看这里
为什么是 pynmsnn?
pynmsnn 是一个开源的低代码 python 库到使用【尖峰神经网络(SNNs)】构建神经形态预测模型(分类&回归问题) 。
谁可以使用 pynmsnn?
PYNMSNN 是一个开源库,非常适合:-
- 偏爱低代码解决方案的数据科学家。
- 希望提高模型准确性和生产力的经验丰富的数据科学家。
- 参与构建概念验证(POC)项目的数据科学专业人员和顾问。
- 快速概念验证的研究人员。
- ML/AI 爱好者。
有关安装步骤和先决条件,请查看此处的和
开始—让我们为回归问题创建一个尖峰神经网络架构。
演示回归:房价数据集。这个博客的完整代码可以在这里找到
首先,我们将导入所有必要的库& T4 pynmsnn T5 库。对于这个回归问题,我们从模块中导入了“ spiking_regressor ”。
接下来,我们创建一个名为“ run_regressor 的函数,该函数将分别分配计算资源、加载数据集、预处理数据、分配预测器&响应变量以及将数据集分割成 train-val-test 集合。
我们还定义了模型参数,并使用数据加载器创建了 pytorch 数据集,使您的数据易于管理,并有助于简化您的机器学习管道。
然后,我们创建我们的尖峰神经网络架构。我们为网络模型使用 3 个隐藏层。
让我们来看看创建的网络模型

作者提供的图片:显示正在使用的计算设备、数据集信息、train-val-test 大小和 SNN 网络架构
此外,我们初始化创建的模型,选择适当的优化器,以及相应的损失函数(在本例中为 MSE)。我们创建了一个字典来存储每个时期的训练丢失和验证丢失。然后,从模型训练开始。显示列车和阀门组在每个时期的相应损失。此外,我们使用所有常见的回归指标来评估模型的性能。这里,我使用了库“regressormetricgraphplot”对设计的 SNN 回归器模型进行评估。这个包有助于简化回归模型的通用评估指标的绘制。该库的度量部分包括皮尔逊相关系数(r)、决定系数(r 平方)、均方误差(mse)、均方根误差(rmse)、均方根相对误差(rmsre)、平均绝对误差(mae)、平均绝对百分比误差(mape)等。

作者图片:显示培训和验证损失

作者图片:评估指标

作者图片:显示测试集上的训练和验证损失/时期和模型性能的图
查看更多分类和回归问题的示例,代码如下
- 在这里找到 Spiking 神经网络多类分类器预测模型演示的笔记本:-https://github . com/ajayarunachalam/pynmsnn/blob/main/pyNM/Spiking-multi class-classifier-model . ipynb
- 在这里找到非尖峰神经网络多类分类器预测模型演示的笔记本:-https://github . com/ajayarunachalam/pynmsnn/blob/main/pyNM/Non Spiking-multi class-classifier-model . ipynb
- 在此处找到 Spiking 神经网络二元分类器预测模型演示的笔记本:-https://github . com/ajayarunachalam/pynmsnn/blob/main/pyNM/Spiking-Binary-classifier-model . ipynb
- 在此找到非尖峰神经网络二元分类器预测模型演示的笔记本:-https://github . com/ajayarunachalam/pynmsnn/blob/main/pyNM/nonspiking-Binary-classifier-model . ipynb
- 在这里找到 Spiking 神经网络回归器预测模型演示的笔记本:-https://github . com/ajayarunachalam/pynmsnn/blob/main/pyNM/Spiking-Regressor-model . ipynb
- 在这里找到非尖峰神经网络回归器预测模型演示的笔记本:-https://github . com/ajayarunachalam/pynmsnn/blob/main/pyNM/nonspiking-Regressor-model . ipynb
连接
你可以在 ajay.arunachalam08@gmail.com 找到我
我们上 linkedin 连线吧,干杯:)
参考
https://en.wikipedia.org/wiki/Spiking_neural_network
https://www . Intel . com/content/www/us/en/research/neuromorphic-computing . html
https://towards data science . com/neuromorphic-and-spiking-or-not-894 a 836 DC 3 b 3
https://www . embedded . com/neuromorphic-ai-chips-for-spiking-neural-networks-处女作/
https://www . frontier sin . org/articles/10.3389/fnins . 2018.00774/full
https://arxiv.org/ftp/arxiv/papers/1809/1809.09707.pdf
https://www.frontiersin.org/articles/10.3389/fnins.2020.00662/full https://pytorch.org/
Web 应用程序的设计考虑
从 Jupyter 笔记本到全功能网络应用

来源: Dota2 Wiki ,可在 CC BY-NC-SA 3.0 下获得
不久前,我为 DOTA2 创建了一个 ward cluster finder,并在 medium 和 Reddit 上的 DOTA2 社区分享了它。目标是解析职业比赛并识别职业球员的防守模式。此外,我想将我的发现与付费的 DOTA Plus 服务的建议进行比较。
我觉得把一个附带的项目变成了有实际价值的东西很有成就感。除了好评,我还收到了很多关于如何改进的反馈。这篇文章的目的是探索数据科学 web 应用程序的设计考虑因素、用户反馈的重要性以及如何预测未来的需求。
要跳到最终产品,请点击下面的链接:
https://share . streamlit . io/nadimkawwa/dotawardfinder/main/appward objectives . py
对于存储库:
https://github.com/NadimKawwa/DOTAWardFinder
观众是谁?
在创建任何东西之前,思考谁将使用它以及如何使用它是很重要的。我预计这个项目主要是 DOTA2 玩家,一些数据科学家,或许还有玩 DOTA2 的数据科学家使用。这意味着使用大量的技术术语可能会令人不快,应该避免。此外,它有助于将你自己放在观众的位置上,在这种情况下,这意味着玩一些 DOTA2 游戏来很好地掌握游戏机制。
获得用户的初步反馈
在各种论坛上分享项目的好处是用户的反馈和改进建议。由于害怕某个东西不完美,或者某处有致命的缺陷,所以推迟发布它是完全正常的。就我个人而言,我担心这个项目还没有完成到值得任何人反馈的程度。然而,请记住,我们被允许失败,批评是一种有效的改进方式。我最终部署了这个模型,并在接下来的几周里思考我收到的反馈。
有三个想法不断出现,并在这个项目中得以实施。下图取自原始项目,显示了 30-40 分钟之间的换班示例。在接下来的小节中,我将解释这个情节的缺点,以及我是如何解决用户所关心的问题的。

作者图片
更少的簇,更多的圈
一个观察者守卫提供一个区域的视野,如果使用者在那个区域有视野,一个哨兵守卫显示不可见的单位。前面的图显示了病房聚类,每种颜色对应一个不同的聚类(红色、橙色、粉色等)。
我了解到,虽然这显示了病房集中的地方,但并没有真正显示它们覆盖的区域。用户想知道:被监控的一般区域是什么?因此,我用各自的平均质心替换了聚类,并在它周围画了一个圆。
此外,属于同一团队和类别的所有病房的配色方案将是相同的。结果是一个更简洁的表示,并且用户识别守卫点的工作量更少。
作为目标的函数,而不是时间的函数
也许最深刻的观察是,并非所有的游戏都遵循同样的节奏。事实上,一些游戏只需 25 分钟就能结束,而另一些则需要一个多小时。游戏的节奏是由占领目标决定的,比如塔和兵营。
因此,基于时间的结界是相当误导的,因为它没有考虑到我们在游戏中领先了多远。我修改了分段过程,使其成为目标而不是时间的函数。
更少的图像意味着更少的困惑
一些用户的帖子大意如下:
- 如果你在手机上,很难看到任何东西。
- 情节标题很小,很难阅读。
- 为什么我们看不到并排的星团?
解决这个问题的方法是将四个小的次要情节合并成一个更大的,包罗万象的情节。它允许用户以统一的格式查看所有内容,并有望防止眯着眼看小字体。
实施反馈
结果是如下图所示。一个额外的增强是显示塔的状态,以便情节是自明的。例如,辐射最后剩下的塔在第三层,两个队都竞争在那里有一个岗哨。

作者图片
其他设计考虑
用户反馈打开了反思之前选择的大门。事实上,一旦我们开始改变事情,我们就开始质疑是否需要重写整个代码段。这一节将介绍这些被完全重写的代码部分。
计算工作量
选择的聚类算法是 DBSCAN,并且计算量可能很大。此外,寻找最佳参数需要多次迭代。最后但同样重要的是,随着数据集变得越来越大,它阐述了计算工作,这让我们产生了一个问题:训练算法应该托管在云平台上吗?
答案是不,不一定。为什么要强迫云服务一遍又一遍地计算同样的事情呢?此外,为什么让用户等待计算完成呢?解决方案是在本地一次手动完成所有计算,然后将静态图上传到存储服务上(我想到了 AWS S3)。这简化了事情,因为所有的代码只是获取一个图像并显示给用户。
要求用户输入太多信息
这个项目的前一个版本要求用户做三件事:
- 匹配时间范围
- ε参数
- 最小样本参数
对于几乎没有数据科学背景的人来说,最后两个要点不是很清楚。因此,这些输入会导致不必要的麻烦。事实上,在没有花费大量时间探索数据的情况下,如何猜测最佳参数呢?
这些参数被一个简单的问题所代替:请陈述在守卫的时候什么塔是活的?
罗山坑
罗山的坑是一个相当奇特的目标,不需要杀死罗山就可以赢得游戏。后者放弃了不朽之盾,这给了玩家死后的轮回。而且,随着游戏的进行,玩家越来越强大,罗山也是如此。
另一个有趣的事实:罗山在一定的时间间隔内重生,并且可以被杀死多次(在一场团队液体游戏中多达 7 次)。
罗山的守卫图是一个特例,需要反映被捕获目标的平均状态。因此,塔被部分着色以反映游戏的平均进度。例如,如果在罗山死亡时,45%的第二层塔还活着,那么塔的 45%是红色的,55%是灰色的。
此外,通常在罗兴(杀死罗山的行为)前 2 分钟放置病房,并且只考虑这些病房。另一个简化是只扫描位于地图左上象限的病房。
结果是下面的图像,显示了一个守卫坑的入口的竞争。

作者的情节
边缘案例
总共有 6 个通道,每个通道可以有四种状态,从没有塔被带走到第 3 层塔在该特定通道中被摧毁。这意味着我们要考虑 4096 种组合。
前面的说法只是部分正确,因为这些案例大多不存在或数据点太少。因此,让用户知道他们在处理一个边缘情况是有帮助的。
履行
解释完所有设计注意事项后,我们可以继续实施了。简化的解决方案是一系列滑块,将用户输入转换为静态图的路径。只需将值滑动到所需的状态,点击“显示塔楼病房”并观看结果清单。

作者图片
额外收获:对于数据科学家来说
对于那些对在本地运行脚本感兴趣的人,可以随意克隆 GitHub repo ,特别是笔记本#7 。下面的代码片段显示了一个模拟 scikit-learn 熟悉度方法的示例运行。
结论
第一步是分享一些东西,不管它是如何“完成”的,并希望有人觉得它有用。在设计应用程序时,收集用户的反馈,并尝试预测他们的需求。此外,如果没有 DOTA2 社区的宝贵意见,我不可能把这个项目进行到现在。
机器学习的设计模式
将最佳 ML 实践抽象成可重用的设计模式

凯利·西克玛在 Unsplash 上的照片
随着机器学习无处不在,获取最佳实践和解决方案来解决常见的 ML 问题变得越来越重要。设计模式是捕捉这些问题的一种方式,并使用通用的和经过良好验证的 ML 设计提供可重用的答案。它们是设计解决方案或构建 ML 系统时的思考方式。
现在的问题是,我们能把最好的机器学习实践抽象成设计模式吗?
根据维基百科,“设计模式是程序员在设计应用程序或系统时可以用来解决常见问题的形式化的最佳实践”。
这里有一本最近出版的关于这个主题的新书,“机器学习设计模式”。这本书详细介绍了机器学习中的 30 种设计模式,这些模式被分为几类,如问题表示、模型训练、弹性服务、可再现性和负责任的人工智能。
在这篇文章中,我将重点总结书中一些我感兴趣的设计模式。
1。再平衡 : 问题表现设计模式
不平衡数据集是欺诈检测、异常检测、垃圾邮件检测等分类问题中的常见场景。但是用于分类的典型 ML 模型在假设所有类别都是平衡的情况下工作,因此导致较差的预测性能。用于处理不平衡数据集的一些最常用策略如下:
1。 选择正确的性能指标 :虽然准确性是最常用的指标,但在不平衡数据集的情况下,它可能不是最好的指标,因为类分布是偏斜的。这种情况下的目标是最大化精确度和召回率,因此 F1 分数或 AUC 等指标更有效地评估性能。
2。采样方法 :重采样是一种广泛采用的技术,用于平衡数据集中类内的样本。
a) 过采样:这种方法涉及过采样少数类。简单的方法包括从少数类中复制样本,这不会向数据集添加任何附加信息。其他高级技术,如 SMOTE(合成少数过采样技术)从现有数据中合成新样本。
b) 下采样:这种方法涉及选择多数类的随机子集,以达到少数类的相同大小,这可能会导致信息丢失。
3。加权类 : 这种方法包括使用惩罚学习算法,这增加了少数类中错误分类的成本。也就是说,少数民族分类错误的成本与少数民族代表性不足的程度成正比。
2。转换:Re 生产性设计模式
这种设计模式的关键思想是将输入与功能分离。为了训练模型,我们从原始输入中提取特征。但是在大多数机器学习问题中,输入并不直接作为特征使用。许多转换,如标准化、缩放、编码等。应用于输入,将它们转换为输入算法的特征。但是,如果这些转换是作为预处理步骤执行的,那么在预测时再现它们就成了一个问题,因为预测的输入仍然是原始格式。因此,清楚地将输入从特征中分离出来、封装预处理步骤并将其包含到模型中以确保可重复性是很重要的。这种设计原则允许通过分离输入、特征和转换,将机器学习模型容易地移植到生产中。TensorFlow 提供 tf.transform 来高效地执行转换并保存它们,以便在预测时间内通过应用 tf.serving 来再现它们。
3。检查点: 模型训练设计模式
弹性和容错是可伸缩系统的主要特征。检查点是模型内部状态(包括权重、当前学习率)的快照,因此训练可以在以后的任何时间点从该状态恢复。断电、操作系统故障、任务抢占或任何其他不可预见的错误都可能在培训过程中发生,尤其是深度学习模型,这可能会导致整个时间和资源的损失。包括 TensorFlow、Keras 和 PyTorch 在内的大多数深度学习框架都启用了检查点。实现检查点的方法之一可以是:
1。在每个时期结束时保留一个检查点
2。以最佳精度保存模型
TensorFlow 和 Keras 提供了 tf 等 API。Estimator API 和 ModelCheckpoint API,模型权重可以保存在 PyTorch 中实现检查点。
4。工作流程: 再现性设计模式
这种设计模式旨在将机器学习工作流的各个步骤隔离并封装到一个有组织的工作流中,以确保可维护性和可扩展性。机器学习开发工作流通常是单一的,它包含从数据收集到训练模型及其评估的一系列任务。但是机器学习任务本质上是迭代的。但是在开发过程中,跟踪工作流中所有的小变化变得很复杂,因为过程迭代的次数越来越多。这引入了 MLOps 的概念,它包含与 DevOps 中类似的概念,如持续集成和持续交付(CI/CD ),但还包含持续评估和持续培训的其他概念。MLOps 和 DevOps 的主要区别在于,在 MLOps 中,不仅是代码,数据也必须不断地进行测试和验证。工作流中每个任务的容器化是实现这种设计模式的方法。作者提出了 ML 流水线,它是 ML 步骤的可执行 DAG(有向无环图), ML 步骤是容器。它解决的主要问题是“相关性跟踪”,这样,如果在流水线的某个步骤中发生了变化,只有相关的步骤才会重新运行,从而确保可再现性。
5。可解释的预测 : 负责任的人工智能设计模式
机器学习模型一般都是黑箱。但是对模型行为有一个清晰的理解对于诊断错误和识别潜在的偏差以决定是否可以使用它们是非常重要的。在机器学习中引入可解释性是负责任的人工智能的一个主要因素。因此,这种模式的关键思想是解释机器学习模型,以理解模型为什么以及如何以某种方式做出预测。但是,当前的评估指标只谈论给定数据集的预测的相对正确性,但它们没有提供任何关于模型为什么会得出该预测的见解。ELI5、SHAP 和 LIME 是模型可解释性方面使用最广泛的 Python 库。
尽管上述技术在大多数机器学习实践中得以实现,但定义设计模式有助于为常见问题创建通用的可重用解决方案。它们有助于工程师之间的沟通,并通过提供现成的解决方案来快速解决常见问题。
快乐学习!!
机器学习中的设计模式
我们能把最佳实践抽象成真正的设计模式吗?
根据它的定义,设计模式是一个常见问题的可重用解决方案。在软件工程中,这个概念可以追溯到 1987 年,当时 Beck 和 Cunningham 开始将其应用于编程。到了 2000 年,设计模式——尤其是面向对象的坚实设计原则——被认为是程序员的常识。快进 15 年,我们来到了软件 2.0 的时代:机器学习模型开始在越来越多的代码中取代经典函数。今天,我们将软件视为传统代码、机器学习模型和底层数据的融合。这种融合需要这些组件的无缝集成,考虑到这些领域通常不同的历史和发展,这通常不是微不足道的。
今天,我们将软件视为传统代码、机器学习模型和底层数据的融合。
然而,设计模式还没有被扩展来处理这个新时代的挑战。在软件 2.0 中,常见的挑战不仅出现在代码层面,还出现在问题定义、数据表示、训练方法、缩放以及人工智能系统设计的伦理方面。这为机器学习反模式的实践创造了肥沃的土壤。不幸的是,今天甚至博客帖子和会议有时也以反模式为特色:认为可以改善事情,但实际上却使事情变得更糟的实践。因为反模式也需要技能,所以它们通常不被从业者认可。因此,在下面,我将给出两个常见 ML 挑战的例子,但是,我将首先介绍它们的解决方案反模式,而不是从设计模式开始。
该模型在评估指标上表现不佳
在常见的场景中,在收集、清理和准备数据之后,工程师训练第一个模型,并发现它在测试数据上表现不佳。一个常见的反模式是用一个更复杂的模型(例如,通常是梯度提升树)替换第一个模型,并以此提高性能。这个反模式的一个变体可以遵循这个步骤,通过模型平均来组合几个模型。

Donald Knuth 的名言“过早优化是万恶之源”已有近 50 年的历史,现在仍然适用。经 tddcomics 许可的图像。
这些方法的问题在于,它们只关注问题的一部分,即模型,并选择通过增加模型的复杂性来解决问题。这些步骤迫使我们接受过度拟合的高风险,用可解释性换取额外的预测能力。虽然有有效的做法来减轻这种选择的副作用(如石灰),我们不能完全消除它们。
设计模式是错误分析。在实践中,这意味着通过评估模型在不同测试集上的适用性,或者甚至通过查看我们的模型出错的个别案例,来查看我们的模型在哪里出错。尽管我们都听说过“垃圾进,垃圾出”,但仍然很少有人意识到这是真的,即使是数据中很小的不一致。也许标签来自不同的评分者,每个人都有自己的,对标签指南略有不同的解释。也许收集数据的方式已经随着时间的推移而改变了。对于小数据问题,误差分析的效果尤其明显。然而,我们还应该记住,在大数据的很大一部分情况下,我们还会处理长尾事件(例如,从入学考试中识别稀有人才)。
错误分析的真正力量来自于这样一个事实,即我们不会通过应用它来交换可解释性或过度拟合的风险,事实上,单独应用它会产生关于数据分布的关键知识。此外,错误分析使我们能够选择以模型为中心(例如更复杂的模型)和以数据为中心(例如进一步的清理步骤)的解决方案。
部署模型的性能随着时间的推移而下降
该模型经过了广泛的验证,并被部署到生产中。用户很高兴,并给予积极的反馈。然后,一个月/一个季度/一年后,关于预测缺陷的报告接踵而至。这通常是概念漂移的一种表现,即你的模型所了解到的输入和输出之间的联系已经随着时间而改变。在有些地方,这种概念漂移是众所周知的(单词语义、垃圾邮件检测器),但“概念”漂移可能发生在任何领域。例如,面具和社会距离的规定也挑战了许多以前部署的计算机视觉模型。

没有再训练的 ML 系统假设输入和输出之间的学习关系没有变化。经TDD 经济组许可的图像。
一种常见的反模式是将这些例子归因于噪声,并期望情况随着时间的推移而稳定下来。这不仅意味着缺乏行动,也意味着错误的归因,这在数据驱动的企业中通常是不鼓励的。稍微好一点的反模式是通过快速重新训练和部署新模型来对报告做出反应。这是一个反模式,即使在团队假设他们遵循敏捷软件开发原则并因此选择快速响应变化的情况下。问题是,这种解决方案解决了症状,但没有解决系统设计中的缺陷。
设计模式是对性能的持续评估,这意味着您预期会发生偏差,因此,设计系统以尽快注意到它。这是一种完全不同的方法,因为重点不是反应速度,而是检测速度。这使得整个系统处于更加可控的过程中,为任何反应的优先化提供了更多的空间。持续评估意味着建立流程和工具,为一小部分新数据持续生成基础事实。在大多数情况下,这涉及到人工标签,通常使用众包服务。不过,在某些情况下,我们可以使用其他更复杂但在部署环境中不可行的模型和设备来生成地面实况标签。例如,在自动驾驶汽车的开发中,来自一个传感器(例如激光雷达)的输入可以用于为另一个传感器(例如摄像机)生成地面实况。
机器学习的坚实设计原则
我写设计模式的原因是,这个领域已经达到了成熟的水平,我们不仅应该分享我们的最佳实践,而且应该能够将它们抽象为真正的设计模式。幸运的是,这项工作已经由多个小组开始了。事实上,最近已经出版了两本关于这个主题的书[ 1 ,[ 2 ]。我喜欢阅读它们,但我仍然有一种感觉,尽管我们正朝着正确的方向前进,但我们距离为 ML 从业者制定坚实的设计原则仍有几步之遥。我相信,虽然基础知识已经可用,并用于构建今天的人工智能产品,但设计模式和反模式方面的工作是迈向软件 2.0 时代的重要一步。

设计模式是机器学习技术的基础。经TDD 经济组许可的图像。

https://www.kdnuggets.com/2021/08/top-stories-2021-jul.html
Tableau 中的设计思维
可视化
使用业务模型画布的插图

Tableau 中的商业模式画布(Design⁴,⁵,⁶)(图片来源:作者提供)
D 设计思维是一个基于以用户为中心的设计的过程,有助于建立用户同理心,引导寻求突破性创新。同样,通过使用业务模型画布,设计思维可以被用于战略性地构建新业务模型的开发或现有业务模型的文档。业务模型画布作为一个有价值的模板,根据业务如何创造、交付和获取价值,可视化地设计和原型化业务的重要方面。
但是想象一下,如果你能够将设计思维和数据驱动的分析结合起来,你会怎么样!通过这种方式,你可以拥有一个动态的商业计划和实时的洞察力。这在计划合作时变得特别重要和有帮助,尤其是当你想开始一项新的商业冒险时。这正是本文所阐述的如何使用 Tableau 开始并实现这个概念。
我们将首先查看主画布的实现细节,然后查看它与实时洞察的链接,
数据来源:我们将首先创建一个表格格式的 Excel 文件,包含两个工作表,即版本和画布详细信息。版本表由需要在画布表头填写的详细信息组成,有四个字段,分别是设计人、设计人、日期和版本。使标题动态化可以确保正确的版本控制。

单张版(来源:图片由作者提供)
Canvas Details 表由九个模块的主要 Canvas 字段组成,即关键合作伙伴、关键活动、关键资源、价值主张、客户关系、渠道、客户群、成本结构、和收入流。

床单画布细节(来源:图片由作者提供)
连接数据源:在数据源面板中,选择数据- >新建数据源。选择 Microsoft Excel 文件数据源,并找到您在上述步骤中创建的文件。由于我们的两个 excel 表是分离的,记住创建两个数据源连接,一个带有画布细节,另一个带有版本表,如下图所示。

数据源连接(来源:图片由作者提供)
为了促进团队协作,仪表板应该发布到 Tableau 服务器,确保您使用的是实时连接到保存在共享位置的 excel 文件,并且服务器可以访问该文件。这样,不同的用户可以编辑和更新,所做的更改会自动反映在画布上。
画布的设计和实现:首先,在一个普通的仪表板(自定义尺寸 1400 x 827)上,布局&根据 template⁴,⁵和以下组件设计业务模型画布:
视图: 总共创建 10 个页面,每个模块一个,包括版本页面。通过将相关的 excel 字段拖放到行和将计算的空白字段拖放到标记卡上的文本来创建文本视图。
使用的格式: 标题-Comic Sans MS (15 磅),字段-Calibri (11 磅),调色板:#D0EEF7,#FFD5C2,#FAE99F

主要合作伙伴的示例表(来源:图片由作者提供)
使用的格式:Title-Comic Sans MS (11 磅),Fields-Calibri (11 磅)

版本的样张(来源:图片由作者提供)
Header: 使用Objects->Text(Comic Sans MS-18 pt)添加画布标题。此外,从表单窗格中,拖放版本的表单,完成画布的标题。相应地,对齐并调整割台部件。

画布页眉(来源:作者图片)
主画布: 为了创建不同的块,通过使用容器( Objects- > Horizontal,Vertical )来相应地安排仪表板上的布局。然后,这些容器将容纳相应的纸张。然后从料板面板将相应的料板拖放到容器中。

工作表窗格(来源:作者图片)
为了使仪表板更有创意,继续将您选择的相关 icons⁶作为对象- >按钮(图像)添加到每个块中。这些按钮反过来将有助于导航到数据分析仪表板。

按钮配置键合作伙伴(来源:图片由作者提供)
此外,通过放置 arrows⁶作为对象 - >图像来完成设计,以可视化仪表板流程。最终的画布看起来会像这样,

Tableau 中的商业模式画布(Design⁴,⁵,⁶)(图片来源:作者提供)
链接数据驱动的洞察:一旦画布的设计和实现完成,我们可以进一步为九个块中的每一个创建单独的仪表板,并通过图像按钮提供它们从主画布的来回导航。这些单独的仪表板,例如这里的关键合作伙伴(修改后的 illustration⁷)提供了深入的统计数据和分析,以了解不同的关键合作伙伴以及如何衡量他们对业务的影响。这些单独的控制面板是数据分析控制面板,以直观的可视化形式呈现与每个块相关的关键数据。此处可视化的数据可以从各种数据源(包括数据库、excel 等)中收集。

主要合作伙伴的说明性 Dashboard⁷(来源:图片由作者提供)
不要忘记在每个独立的块仪表板上添加一个统一的图像按钮,以导航到主画布。

按钮配置(来源:图片由作者提供)
最后,这里以关键合作伙伴的端到端流程为例,看起来像这样,

块关键合作伙伴的说明性流程(来源:图片由作者提供)
此外,可以同时实现其他块的仪表板。最终,我们将拥有一个完整直观的动态流程,您的业务计划与深入分析仪表板相链接,从而帮助您简化、战略性地规划&管理您的业务。
总而言之,这篇文章展示了如何使用商业智能(BI)工具将设计思维与数据分析结合起来,创建结构化的流程,进而发现新的可能性。由于基本思想保持不变,本文中的实现步骤是说明性的,可以根据您选择的 BI 工具进行调整。作为例子,你可以参考我的另一篇文章Power BI中的设计思维,它是这篇文章的另一个变体。
参考
https://en.wikipedia.org/wiki/Business_Model_Canvas
[3]https://kb . tableau . com/articles/how to/automatically-updating-data-in-server-workbook-that-uses-live-connection-to-excel?_ ga = 2.1685672916685.766666666667
[5]https://online . visual-paradigm . com/diagrams/templates/business-model-canvas/categorized/
[6]图标:根据知识共享署名(CC BY) 获得许可。
名词项目中 Prashanth Rapolu 的勾选图标。
Gift 图标由 Vectorstall 从名词项目中取出。
客户图标由 shashank singh 从名词项目中获得。
名词项目中 Ralf Schmitzer 的收入图标。
箭头图标由来自名词项目的 Subur Imam Hidayat 制作。
https://www.tableau.com/learn/classroom/desktop-two
设计你自己的情感分数
Python 熊猫中的情感分析

照片由来自 Unsplash 的 Markus Winkler 拍摄
情感分析是一种常用的 NLP(自然语言处理)技术,用于确定文本是正面的、负面的还是中性的。它经常被用来根据评论情绪来查看客户满意度,或者在我们对文本数据进行分析时作为一个额外的视角。
有 python 包可以像 NLTK Vadar 一样直接计算情绪得分(样例代码在后面)。然而,本文的主要目的是帮助您根据自己的逻辑设计和创建自己的情感得分。
为什么我们要创造自己的情感得分?
- 你知道你得到了什么(因为你设计了情感分数的计算逻辑)
- 您可以根据需要灵活地更改逻辑。(例如,如果你在做餐馆评论情感分析,你可以使用与用餐相关的正面和负面词汇列表)
- 当您使用多种逻辑来计算情感得分时,您有多种特征可供分析
好了,现在让我们来看例子!
我们使用的数据:
餐馆评论数据:我们使用的样本是来自 Yelp 的餐馆评论数据。数据可以从 Kaggle 下载。餐馆评论的输出可用于评估不同餐馆的顾客满意度。
正反词列表:这是我们在网上找到的与餐厅相关的正反词列表。它们以 positive-words.txt 和 negative-words.txt 的形式存在。你可以在网上找到一个版本,并根据你所关注的行业继续添加。
停用词:经常出现但没有任何情感价值的词的列表,通常如“the”、“to”等。我使用 nltk 包中的停用词,因为它非常标准。
数据预处理:
首先将所有数据导入熊猫数据框。
import pandas as pd
# Import data
sample=pd.read_csv(file_path+'/train.csv')
sample.columns=['rating','review']
train['review_id']=train.index
positive=pd.read_csv(file_path+'/positive-words.txt',header=None)
positive.columns=['words']
negative=pd.read_csv(file_path+'/negative-words.txt',header=None)
negative.columns=['words']
stop_words=stopwords.words('english')
数据预处理:复习通常包含许多对我们确定情绪没有用处的标点符号、数字或停用词。
原始评论文本将被词干化(包括小写和单词词干化)、标记化(被分解成单词)、移除数字和停用词。
下面是一个例子,说明我们如何从预处理的每一步中得到最终的单词。(移动用户可能需要放大才能清楚地看到步骤)

文本预处理示例,示例文本来自 Yelp 数据集
import re
import nltk
nltk.download('punkt')
nltk.download('stopwords')
from nltk.corpus import stopwords
from nltk.stem.porter import *
stemmer = PorterStemmer()#preprocess function
stem_words=lambda x: stemmer.stem(x)
break_into_words = lambda x : re.findall("[a-zA-Z0-9]+", x)
skip_stop_words = lambda x: [w for w in x if w not in list(stop_words)]
skip_numeric = lambda x : [w for w in x if not w.isnumeric()]#apply pre-processing steps
processed_text=sample['review'].map(to_lower)\
.map(break_into_words)\
.map(skip_stop_words)\
.map(skip_numeric)sample['processed']=processed_text
统计正面和负面单词的出现次数:
基于正面和负面单词列表,您可以为每个评论生成正面和负面单词出现的计数。请注意,这一步会很慢,因为这是一个多对多的映射。如果您的数据量非常大,您可以考虑切换到 Hive Sparks 以获得更快的执行速度。

正面和负面单词计数示例
#count number of positive words
positive_words_count=processed_text.map(lambda x: len([w for w in x if w in list(positive['words'])]))#count number of negative words
negative_words_count=processed_text.map(lambda x: len([w for w in x if w in list(negative['words'])]))sample['positive']=positive_words_count
sample['negative']=negative_words_count
最后,计算情感得分:
方法一:用正计数-负计数计算绝对分数

sample['sentiment_score_1']=sample['positive']-sample['negative']
赞成和反对:这是一个直接而简单的计算评价的正面/负面程度的方法。好处是直截了当,简单易懂。然而,分数可能有利于更长的评论,因为它们往往有更多的正面/负面词汇,即使它们有相同的情感。
例如,“出色的食物和服务,但背景音乐可以改进”和“我认为这家餐厅的优点是食物很好,服务员很友好,我喜欢他们的食谱设计,但背景音乐很糟糕,等等”可能是相同的情感,但第二句的得分要大得多,因为文本较长。
方法 2:根据评论的长度将分数标准化

sample['normalized_sentiment_score']=(sample['positive']-sample['negative'])/(len(sample['processed'])
这里的逻辑是用复习的长度来归一化分数,因为问题出在方法 1 上。你可以通过除以正面字数+负面字数 来调整逻辑(那么分数会在-1 到 1 之间变化)。
利弊:评分考虑了评论文本的长度,但数量可能非常小,很难区分。您可以选择将所有分数乘以一个固定的数字,以便于比较。
方法三:计算正负字数之比

sample['positive_negative_ratio']=sample['positive']/(sample['negative']+1)
方法 3 考虑了正面和负面评论的极性。这个比率也部分地规范了文本的长度,因为对于更长的评论,正面和负面分数的计数往往一起增加。分数范围在 0–无穷大之间,分数在 1 左右被认为是中性的。
利弊:这是归一化和解释之间更平衡的计算方式。这种逻辑的缺点是,你将更难确定中性情绪的范围,因为分母有“+1”
使用 Vadar 包计算情感得分
最快速、最简单的方法——无需文本预处理:)
import nltk
nltk.download('vader_lexicon')
from nltk.sentiment.vader import SentimentIntensityAnalyzeranalyser = SentimentIntensityAnalyzer()
sample['review'].map(lambda x: analyser.polarity_scores(x))
限制
- 我们只探究了积极和消极的单个单词。然而,可以有多个单词组合,比如“必须尝试”,我们可以将它们放入正面单词列表中。如果我们想要合并 2-gram 或 3-gram 短语,计算量会更大。
- 不同的正面词被赋予相同的分数 1,但是例如“优秀”比“良好”具有更大的范围,因此我们可以为不同级别的词赋予不同的分数,然后相加
- 双重否定短语在这里不像“不错”,这可以通过使用两个或三个肯定或否定单词列表来部分缓解。
结论
个人比较喜欢方法三的情感评分计算。然而,这三种方法只是例子,你可以有无限的新方法来设计和计算你自己的情感分数。您应该根据您的项目需求来设计您的逻辑。另外,如果你觉得只是想快速拥有一个情感分,可以选择使用如上图的 NLTK Vadar 方法。
如果您有一个标记良好的数据集(具有真实的情感得分),您可以考虑使用分类方法。更多细节请参考我下面的另一篇文章
设计数据质量指数
获得对用户重要的数据集分数
衡量数据质量并不是什么新鲜事。市场上有许多数据分析工具可以帮助数据分析人员了解数据中的差距并挖掘根本原因。
您可以在此阅读如何创建数据质量仪表板
尽管有各种各样的工具,但回答以下问题并不容易:
-这组数据的总体质量如何?
-数据质量在过去一个月有所提高吗?
-该数据集的可信度如何?

随着数据湖和数据仓库的高度重要性以及越来越多的数据活动,数据质量不仅仅是专家用户应该知道的事情。新兴的现代 BI 和自助服务分析角色,如数据分析师、数据科学家或数据工程师,他们不关注数据质量细节,可以使用简单的指标来获得他们想要使用的数据集的质量概览。
如何设计一个好的数据质量评分?
应该从不同的角度看,涵盖了不同的维度,公式就不那么清晰了。让我们看看它应该满足的要求:
1.简单易懂。查看大量数据集目录的用户应该很快就能初步了解其可信度,而无需深入了解细节
2.缩放证明-如果分数是在一个较小但有代表性的样本上运行的,它应该或多或少是相似的。
3.与其他数据质量分数相当。不同数据集的度量标准可能不同,但即使数据集的大小相差很大,它也应该为用户提供高水平的比较。
4.标准化—清楚地提供最高和最低分数和基准,以了解可以预期的结果以及我们离完美还有多远
数据质量指标应显示数据集如何符合用户的期望。这意味着我们可以为属性找到很多缺失的值,但是我们可能对此有所期待,甚至不在乎。这是我们建立数据质量分数的基础。
对列/属性的期望:
-标记为强制完成
-根据有效值的定义内联完成
-根据参考数据源中定义的值完成
-数据集之间的关系设置列之间的依赖性或相关性
如何定义数据质量问题 —关于属性或记录或元素组的数据质量问题类型的报告,如果 100 个强制值中有 15 个缺失,那么我们可以说数据质量为 85%。置信度代表数据质量问题是一个真实的业务问题的概率
记录中单个属性的数据质量(一个单元格)
-真值或假值要么满足标准,要么不满足标准。
属性的数据质量得分
-基于为这些属性设置的规则的特定属性或列分数。
一条记录的数据质量得分:
可以使用的方法很少,它们应该反映企业的数据使用情况:
- 属性分数的基本平均值,如果 5 个必需属性中有 1 个违反了数据规则,我们可以说数据 80%符合
- 仅计算完全符合的记录,因此如果该记录有 0 个不符合的属性,则该记录是合格的,否则其分数为 0。
- 使用记录所需的最低资格。例如:
记录有 10 个属性,但其中 4 个是最低质量要求
如果这 4 个属性中有一个是错误的,那么该记录将被标记为错误。 - 加权平均分数,因此某些属性比其他属性更重要
数据席位的数据质量指数应基于业务用例,但最常见的方法是所有记录得分的平均值
最后,一个非数据总结的质量分数可以给非数据质量专家一个数据集可靠性的有用概述。高质量的数据导致高质量的信息并做出高质量的决策。指标可以显示分析师从一开始就站在哪里。
订阅更多,在 twitter 关注我。
为你的 ML 模型设计一个公平的工作流程
公平与偏见,值得信赖的 AI
你如何确保你的模型从头到尾都是公平的?
与拉塞尔·霍尔茨合著。

照片由 Gio Bartlett 在 Unsplash 上拍摄
在本系列的第一篇博文中,我们讨论了创建全面公平工作流以确保机器学习模型结果公平的三个关键点。它们是:
- 识别偏差(两个或更多组的不同结果)
- 执行根本原因分析以确定差异是否合理,以及
- 采用有针对性的缓解策略。
然后,在本系列的第二篇文章中,我们深入研究了一个模型如何变得有偏差。
但这些如何将公平的意图转化为公平的机器学习模型,并随着时间的推移继续保持公平?
数据科学家可以创建确保持续公平的工作流。在此,我们强调一些对实现公平工作流程至关重要的方面:
- 通过阐明工作流程的独特之处,使公平具有目的性,避免滥用公平这一概念。
- 支持根本原因分析,挖掘任何偏差的来源以及它们是否合理。
- 定期向相关利益相关方报告,重点介绍一段时间内的关键分析和结果
对于以下工作流程步骤,我们将参考 TruEra 诊断解决方案,并使用该解决方案的屏幕截图来说明如何创建工作流程。然而,这些步骤只是一个一般性的解释——让我们使用现有的工具重新设想一个公平性分析工作流程。

图片作者。公平工作流涉及到模型生命周期中每一步的仔细考虑。
有意实现公平
公平分析不被误用是至关重要的。比较公平性时考虑两个任意段是没有意义的;该模型可能完全有理由偏爱某一部分。例如,信贷审批环境中的“高负债”部分与“低负债”部分是可变处理的合理示例。缺乏意图会导致不加选择地使用公平工具包,而不考虑为什么和如何使用。
相反,确定某个细分市场是否受到法律或监管标准的“保护”至关重要。为了解决这个问题,在开始公平工作流之前,明确地将数据段标记为受保护是很重要的。在 TruEra Diagnostics 中,段管理页面允许用户这样做。尽管仍然允许对任意段进行特别的公平性分析,但在评估和报告流程中会突出显示关于如何将段设置为受保护的明确警告和指导。

作者图片。预先设置受保护的段使得工作流是有意的。
如果您使用管理公平性的解决方案,用户可以集中精力持续监控受保护数据段的公平性指标。理想情况下,您将能够快速查看导致任何差异来源的特征,如下图所示。
如果您不使用解决方案,而是设置自己的监控,您将需要定期运行受保护细分市场的分析,以确保模型输出随着时间的推移保持公平。审查的频率和一致性很重要,这样可以快速识别和解决任何偏差。今天,生产模型的公平性审查经常不进行,或者进行得如此之少,以至于增加了不良结果的风险和组织的业务风险。

作者图片。一旦设置了受保护的数据段,就可以持续监控公平性,从而节省了使用任意审查窗口创建临时审查的时间。
根本原因分析—快速缓解的关键
一旦差异被识别,识别差异的特征级贡献者的根本原因分析可以帮助模型开发人员和验证人员了解偏差是如何进入 ML 模型的,我们在之前的 TDS 博客文章中讨论过这个问题,“我的 ML 模型是如何变得不公平的?”检查关键影响特征有助于确定偏差是否合理,并指导缓解策略的选择。
让我们用一个具体的例子来说明这一点。假设我们正在一个类似于 UCI 的成人数据的数据集上训练一个模型。该模型使用人口普查数据来预测一个家庭的年收入是否大于 5 万美元。数据集包含一些人口统计特征,如性别和种族,但这些特征不会提供给模型,因为开发人员不希望模型使用受保护的属性来进行预测。开发人员决定不同的影响比率(被分配积极结果的男女比例之间的比率)是用于该问题的适当的公平性度量。
在训练该模型时,开发人员发现,与男性相比,女性在该模型中处于不利地位,因此给予她们较低的分数:


作者图片。根本原因分析的第一步—发现对受保护组的不同影响。
开发人员对为什么会出现这种情况感到困惑,并执行根本原因分析来挖掘造成差异的功能级别的因素。本质上,这项分析着眼于男性比女性获得更高模型分数的核心驱动因素。很明显,“婚姻状况”是造成男女不平等的最主要因素:

作者图片。深入挖掘,找到差距的驱动因素:婚姻状况。
开发人员进一步探究了“婚姻状况”,并注意到在测试数据中,女性报告自己婚姻状况为“单身”的比例远高于男性,尽管现实世界中男女结婚率大致相等。然后,开发人员用模型验证器确认这种数据异常是意外的,并对数据进行重新采样,使得男性和女性以大致相同的比率报告“单身”的婚姻状态。他们的缓解策略不必对关键影响因素的知识视而不见,使用重采样方法,使用完全不同的影响比率指标,与男性相比,女性仅略微处于不利地位:

图片作者。在测试数据问题被识别并且数据被重新采样之后,差异的影响被减轻。
“人在回路”的合理性和重要性
任何公平工作流程的一个关键组成部分是合理性。我们发现,受保护的特征,如性别,有时与收入等特征相关,合理的模型可以也应该使用这些特征。在这些情况下,模型应该而不是立即被宣布为不公平。它可能是以一种敏感的方式使用收入特征,而没有创造一个性别的代理。一个人需要参与进来,因为专家可以理清模型的行为是否合理。

图片作者。
为了捕捉这种合理行为的想法,模型验证者或数据科学家能够“证明”模型偏差是很重要的。在这个工作流程中,人可以进入循环,系统地检查偏差,并确定模型是否仍然适合生产。我们建议任何模型的公平报告都包含这种专家分析的明确部分,这为评论任何偏见的合理性提供了空间。

作者图片。举例说明专家如何对公平性评估进行审查,以确定偏见是否合理。
定期报告:满足利益相关者和合规性要求
多个组织利益相关者通常对机器学习模型的公平性感兴趣。由于潜在公平性问题的重要性和敏感性,报告和传达模型的公平性至关重要。诊断报告应该使数据科学家和模型验证者能够轻松地向同行和其他业务利益相关者共享和呈现报告。这些报告应该代表完整工作流程的单一快照,并允许用户理解和剖析公平分析的组成部分。以下是来自 TruEra 的示例报告,但是任何组织都可以使用即席监控分析、用于可视化的集成商业智能解决方案以及使用幻灯片或文字处理解决方案的模板的组合来创建自己的报告。
与公平监控分析本身类似,报告应该定期进行,特别是在那些有法规遵从性要求的行业,如金融服务。

作者图片。公平性报告允许数据科学家、模型开发人员和业务利益相关者轻松地就模型的公平性进行交流。
语言和视觉化:细节决定成败
您可能已经注意到,我们选择了术语“公平工作流”,而不是“偏见工作流”这是故意的。我们的团队投入了相当多的时间来讨论关于公平工作流的语言和视觉元素的微妙问题。公平的抽象本质重视与用户的清晰交流。
由于这个原因,工作流程被重新命名为公平而不是偏见。“公平”从根本上说是确保算法符合社会标准;由于机器学习中的术语超载,“偏差”导致了混乱。此外,“公平”隐含地传达了工作流程的积极意图。
把所有的放在一起
本系列涵盖了很多领域,并总结了一个完整的公平工作流程。我们讨论了公平的理论、实践和社会基础。我们还认为,完整的公平工作流程将识别偏差,执行根本原因分析以确定偏差是否合理,然后采用有针对性的缓解策略。我们还后退一步,揭示了 AI/ML 模型最初是如何变得不公平的。
然后,为了让它变得真实,我们将这些概念与以人为中心的设计联系起来。工作流应该是有目的的,并且在自动化过程的同时,为人留有余地。一个清晰的、自动化的工作流程将会帮助任何与 ML 模型交互的开发人员、验证人员或者商业利益相关者。同样重要的是要指出,虽然这些工作流存在解决方案,但随着时间、努力和意图,它们也可以从现有的工具中创建并整合到现有的流程中。随着人工智能成为我们生活中更重要的一部分,确保模型的开发考虑到公平并受到监控以确保持续的公平是企业和社会的一个巨大优先事项。
设计限速器
系统设计基础知识
你如何设计限速服务?

系统设计是软件工程中最重要的概念之一。对于一个新手来说,学习设计变得很混乱,因为各种软件架构书籍中没有固定的指南,很难理解。你检查的每个地方似乎都有不同的方法。
于是,我根据自己学习建筑课程的经验,着手设计一个系统。这是初学者系统设计系列的一部分(下面给出了链接)。对于本文,让我们设计一个速率限制器服务。
什么是速率限制?
速率限制是一个容易理解的概念,但是对于大规模系统来说却是至关重要的。它用于安全目的以及性能改进。例如,一个服务每秒可以处理有限数量的请求。但是,如果一个服务一次接收大量的请求,服务器可能无法处理。在这种情况下,甚至服务器可能会关闭。为了处理这类问题,我们需要某种限制机制,只允许一定数量的服务请求。
简单来说,限速就是用某个阈值限制某些操作。如果超过这些阈值,系统将返回错误。您可能会说速率限制限制了在给定时间内执行的操作数量。

图 1:速率限制器拒绝第三个请求(图片由作者提供)
速率限制可以分层实施。例如,网络请求可以被限制为每秒 1 个请求、每分钟 4 个请求、每 5 分钟 10 个请求。
为什么需要限速?
需要速率限制来保护系统不被黑客破坏。要了解速率限制的重要性,我们必须了解 DOS 攻击。
拒绝服务攻击,通常被称为 DOS 攻击,是指黑客试图在短时间内用大量请求淹没系统以关闭系统。因为服务器在一定时间内可以处理的请求数量是有限的。因此,系统不能适当地处理请求的洪流;它不能恰当地处理它们。
速率限制可以防止这种情况发生,因为它可以防止系统被有意的不必要的请求淹没。超过阈值后,系统返回错误。
比方说,在 Leetcode 或一些我们可以执行代码的网站上,可能需要速率限制,这样用户就不会不必要地发送垃圾代码执行服务。
我们可以用各种方式限制系统的速率,比如基于用户 id。比方说,我们可以将用户对服务器的请求操作限制为 5 次/分钟。速率限制的其他方式可以基于 IP 地址、区域等。
甚至我们可以对整个系统使用速率限制。例如,系统可能不会处理超过 20K 分钟的请求。如果用户请求总数在一分钟内超过这个数字,系统将返回错误。
系统的定义:
系统设计是一个很大的话题;如果我们不把它缩小到一个特定的目的,那么设计系统就会变得复杂,尤其是对于新手来说。在本文中,我们设计了一个速率限制器服务,它将在一个时间范围内限制客户端对服务器的请求数量。

系统的要求和目标
在这一部分,我们需要详细说明系统的功能。要求分为两部分:
功能需求:
- 客户端可以在一个时间窗口内向服务器发送有限数量的请求,例如每秒 10 个请求。
- 如果单个服务器或不同服务器组合的请求超过了定义的阈值限制,客户端应该会收到一条错误消息。
非功能性需求:
- 该系统应该是高度可用的,因为它保护我们的服务免受外部攻击。
- 性能是任何系统的重要因素。因此,我们需要小心,速率限制器服务不应该给系统增加大量的延迟。
内存估计:
让我们假设我们将所有的数据保存在一个散列表中。假设我们有一个键值对结构。密钥将是用户 ID 的散列值,并且值将是计数和开始时间的结构,例如用户 ID {计数,开始时间}用户 ID {计数,开始时间}
现在,让我们假设' UserID '占用 8 个字节,2 个字节用于' Count ',它可以计数到 65k,这对于我们的用例来说足够了。虽然结束时间需要 4 个字节,但我们只能存储分钟和秒钟部分。如果我们不考虑一个小时的窗口,小时部分是不必要的。现在,它需要 2 个字节。所以,我们总共需要 12 个字节来存储一个用户的数据。
现在,如果我们的哈希表每个记录有 20 字节的开销,并且我们需要随时跟踪 100 万个用户,那么我们需要的总内存是:
(12 + 20)字节* 100 万=> 32MB
如果我们需要一个 4 字节的数字来锁定每个用户的记录,以解决我们的原子性问题,我们将需要总共 36MB 的内存。
领域模型/概要设计:
当一个新的请求从客户端到达时,服务器首先要求速率限制器决定它是被服务还是被拒绝。如果请求没有被拒绝,那么它将被传递到内部 API 服务器。
速率限制器的责任是决定哪个客户请求将被服务,哪个请求将被拒绝。

图:领域模型/高层设计(图片由作者提供)
固定窗口算法:
在该算法中,我们可以考虑从开始到结束时间单元的时间窗口。例如,我们的窗口周期可以被认为是 0–60 秒,一分钟,而不考虑客户端请求服务器的时间范围。我们已经想到了 count 和 startTime 的结构,例如 UserId {Count,StartTime}

图一:速率限制器允许客户端每分钟发出两个请求(图片由作者提供)
图 1 显示了一个客户端每分钟可以发出两个请求的场景。因此,速率限制器允许请求 1 和请求 2。但是来自同一用户的第三个请求在 1 分钟内被阻塞。这种算法被命名为固定窗口算法。在这个算法中,一个周期被认为是 1 分钟(对于这个例子),而不管两个 API 请求被允许的时间范围。
特定客户端发出第一个请求 1 分钟后,将为该用户重置开始时间。这是限速器的一种简单方法。但是这种方法有一些缺点。
缺点:
它可以允许每分钟两倍的请求数。假设用户在一分钟的最后一秒(12:01:59)发送了两个请求,并在下一分钟的第一秒(12:02:00)立即又发送了两个请求。对于两个请求来说,这似乎是个小问题。但是如果请求的数量高得多(例如,50 个请求)或者时间范围低得多(例如,15 秒),则它会导致对服务器的大量请求。特别是我们在这里只考虑一个用户。想象一下,服务于数百万用户的服务将会发生什么。
此外,在分布式系统中,“先读后写”的行为会产生竞争条件。例如,想象一下,如果客户机的当前请求计数是 2,并且又发出了两个请求。如果两个独立的进程服务于这些请求中的每一个,并且在它们中的任何一个更新计数值之前并发地读取该计数值,则该进程将导致客户端没有达到速率限制。因此,我们可能需要锁定每条记录。
滑动窗口算法:
如果我们在一个时间范围内跟踪每个用户的每个请求,我们可以将每个请求的时间戳存储在哈希表的“值”字段中的一个排序集中。但是,这需要很大的内存。因此,我们可以在计数器上使用滑动窗口。现在,考虑一下,如果我们使用多个固定时间窗口来跟踪每个用户的请求计数。
例如,如果我们有一个每小时一次的窗口,当我们收到一个计算限制的新请求时,我们可以计算每分钟的请求数,并计算过去一小时所有计数器的总和。这将减少我们需要的内存。
假设我们将速率限制在每小时 500 个请求,每分钟 10 个请求。这意味着,当过去一小时内计数器的总和超过限制请求时,客户端已经超过速率限制(500)。
对于较小的时间范围,客户机每分钟不能发送超过 10 个请求。这将是一个混合和合理的考虑,因为我们可能认为没有一个真正的用户会发送如此频繁的请求。即使他们这样做,他们将获得重试成功,因为他们的限制得到重置每分钟。
分布式环境中的问题:
在分布式系统的情况下,我们讨论的算法会有一些问题。你可以查看下图,找出问题所在。允许用户在一分钟内请求 3 次。场景是用户已经发出了 2 个请求,并且在 2 秒钟内发出了两个新请求。来自用户的请求到达两个不同的负载平衡器,然后到达两个不同的速率限制器服务。由于 DB 已经包含计数值 2,速率限制器服务获得低于阈值的值并允许请求。因此,我们现在允许同一个用户在一分钟内发出 4 次请求,这打破了速率限制器的限制。这就是不一致的问题。

图 1:分布式环境中的问题(图片由作者提供)
作为一个解决方案,我们可以使用粘性会话负载平衡来确保一个用户的请求将总是到达相同的速率限制器服务。但这里的问题是,这不是一个容错设计。因为如果限速器服务关闭,系统将无法满足用户的请求。
我们可以使用锁来解决这个问题。一旦服务使用了数据库中的计数器数据,它就会锁定它。因此,在计数器数据更新之前,其他服务不能使用它。但是这个程序也有它自己的问题。这将为锁定增加额外的等待时间。因此,我们需要在可用性和性能之间做出权衡。
缓存:
这个系统可以从缓存最近的活跃用户中获得巨大的好处。在访问后端服务器之前,服务器可以快速检查缓存是否包含用户的计数器值。这应该比每次都去数据库要快。
我们可以通过仅更新缓存中的所有计数器和时间戳来使用回写缓存策略。然后,我们可以以固定的时间间隔(例如 1 小时)写入数据库。这可以确保用户请求的最小延迟,从而改善锁延迟问题。
当服务器读取数据时,它总是首先命中缓存。当用户达到最大限制时,这将非常有用。速率限制器读取没有任何更新的数据。
我们可以使用最近最少使用(LRU)作为我们系统的缓存回收策略。

图 1:限速器的最终设计(图片由作者提供)
DoS 攻击:
为了防止系统受到 DoS 攻击,我们可以采取其他策略来限制 IP 地址或用户的速率。
IP: 在这个策略中,我们限制每个 IP 的请求;这可能不是区分普通用户和攻击者的好方法。但是,有一些保护总比什么都没有好。
基于 IP 的速率限制的最大问题是当多个用户共享一个公共 IP 时。例如,在网吧或智能手机中,用户正在使用同一个网关。另一个问题可能是,黑客甚至可以从一台计算机上获得大量 IPv6 地址。
用户:在用户认证之后,系统将向用户提供一个令牌,用户将在每次请求时传递这个令牌。这将确保我们可以对具有有效身份验证令牌的 API 进行速率限制。但问题是,我们必须对登录 API 本身进行速率限制。
这种策略的弱点是黑客可以通过提供最大限度的错误凭证来对用户进行拒绝服务攻击;之后,实际用户可能无法登录。
因此,我们可以同时使用这两种方法。但是,这可能会导致更多的缓存条目,每个条目包含更多的详细信息。因此,我们需要更多的内存和存储。
结论:
速率限制器可以限制实体(用户、IP 等)的事件数量。)可以在一个时间窗口中执行。例如,用户每分钟只能发送五个请求。我们可以基于“用户标识”对数据进行分片来分发用户的数据。我们应该使用一致的散列法来实现容错和复制。我们可以为每个用户或 IP 的不同 API 设置不同的速率限制器。
速率限制器的任务是限制进出系统的请求数量。速率限制最常用于限制来自用户的传入请求数量,以防止 DoS 攻击。系统可以基于 IP 地址、用户帐户等来实施它。
我们应该小心的是,正常的 DoS 攻击可以通过速率限制来防止。但是在分布式 DoS 攻击的情况下,可能就不够了。
本文是系统设计基础的一部分。这里给出了该系列的一些文章链接:
谷歌驱动 系统设计分析
参考:钻研系统设计面试课程。
感谢您阅读本文。 过得愉快
在 PyTorch 中设计自定义 2D 和 3D CNNs
带代码的教程

来源:维基百科(知识共享许可)。
本教程基于我的知识库 pytorch-computer-vision ,其中包含 pytorch 代码,用于根据自定义数据训练和评估自定义神经网络。学完本教程后,您应该能够:
- 在 PyTorch 中设计定制的 2D 和 3D 卷积神经网络;
- 了解图像维度、滤镜维度、输入维度;
- 了解如何选择内核大小、步幅和填充;
- 了解 PyTorch 相关的面向对象编程基础;
- 了解如何使用 nn。更好的模型组织顺序。
第一步:下载代码。
包含所有代码的库是https://github.com/rachellea/pytorch-computer-vision
如果您想继续学习本教程和/或使用代码,您应该克隆或下载存储库。想了解更多关于使用 Git 的背景知识,请看这篇文章。
第二步:创建 conda 环境
在存储库中,有一个 yml 文件 tutorial_environment.yml,它包含了运行教程代码所需的所有依赖项。为了创建包含所有依赖项的 conda 环境,
(a)安装 Anaconda。https://docs.anaconda.com/anaconda/install/
创造康达环境:
conda env create -f tutorial_environment.yml
请注意,在 conda 环境中,Python 版本和包版本并不“前沿”,因此该环境应该可以在 Linux、Mac 或 Windows 上工作。关于 Anaconda 的更多背景知识以及它为什么对机器学习项目有用,请看这篇文章。
2D 卷积神经网络
这篇文章主要关注卷积神经网络(CNN),它在计算机视觉任务中很受欢迎。关于 CNN 的 5 分钟介绍,见本帖;更长的介绍见本帖。
对于许多任务,使用现有的 CNN 架构是合适的,比如预定义的 ResNet 。在其他情况下,您可能想要修改现有的 CNN,例如,在使用预训练的卷积特征提取器之后,添加一些定制的卷积层。最后,也许你想完全从头开始编写自己的 CNN,没有任何预定义的组件。在这篇文章中,你将学习如何在 PyTorch 中构建你自己的 2D 和 3D CNNs。
图像尺寸
2D CNN 可以应用于 2D 灰度或 2D 彩色图像。2D 图像有 3 个维度:[通道,高度,宽度]。
灰度图像有一个颜色通道,用于不同的灰度。灰度图像的尺寸为[1,高度,宽度]。

胸部 CT 扫描显示气胸。2D 灰度图像(1 个颜色通道),例如尺寸【1,400,500】。来源:维基百科(授权:CC)
彩色图像有三个通道,分别用于红色、绿色和蓝色(RGB)。因此,彩色图像的尺寸是[3,高度,宽度]。

沙滩上的萨摩耶。2D 彩色图像(3 个颜色通道),例如尺寸【3400500】。来源:维基百科(公共领域)
尽管这些“2D”图像实际上有三个维度(通道、高度、宽度),我们仍然认为它们是“2D ”,因为当它们向人们展示时,只有两个空间维度被明确显示。
过滤器尺寸
一个“2D”CNN 有三维过滤器:[频道,高度,宽度]。关于展示 2D CNN 3D 滤镜的动画,请看这个链接。
接受灰度图像的 CNN 的输入层必须指定 1 个输入通道,对应于输入灰度图像的灰色通道。
接受彩色图像的 CNN 的输入层必须具有 3 个输入通道,对应于输入彩色图像的红-绿-蓝颜色通道。
总输入尺寸
总的来说,一个“2D”CNN 有 4D 输入:[批量大小,频道,高度,宽度]。batch_size 维度索引到一批示例中。一批样本是从整个数据集中选出的样本的子集。该模型一次训练一批。

4D 输入到 2D CNN 的灰度图像示例。图片作者。

示例 4D 输入到 2D 有线电视新闻网的彩色图像。图片作者。
在 PyTorch 中定义 2D CNN 图层
在 PyTorch 中,定义 2D 卷积层的函数是 nn。Conv2d 。以下是一个图层定义示例:
nn.Conv2d(in_channels = 3, out_channels = 16, kernel_size = (3,3), stride=(3,3), padding=0)
在上面的定义中,我们定义了 3 个输入通道(例如,3 个输入颜色通道)。out_channels 可以被认为是我们想要在该层中检测的不同模式的数量。一个 CNN 层的 out_channels 的数量将变成下一个 CNN 层的 in_channels 的数量。

解剖 2D CNN 层。图片作者。
代号为的 2D CNN 小品
这是一个 2D CNN 的草图:

2D CNN 小品。图片作者。来自无线媒体的正常 CT 切片
所示的该 CNN 的 2 层的 PyTorch 代码是:
self.conv_two_layers = nn.Sequential(
nn.Conv2d(in_channels = 1, out_channels = 8,
kernel_size = (2,2), stride=(2,2), padding=0),
nn.Conv2d(in_channels = 8, out_channels = 16,
kernel_size = (2,2), stride=(2,2), padding = 0))
请注意,在本例中,我们的 1 通道灰度输入图像是如何通过第一个 CNN 层的处理转换为 8 通道中间表示的。在由第二 CNN 层处理之后,该 8 声道中间表示变成了 16 声道中间表示。
CNN 的一层中 out_channels 的数量决定了该层的输出中将出现的通道/特征的数量。
内核大小(过滤器大小)
在 CNN 中,内核(过滤器)滑过图像并检测图像中的某些模式。内核检测到的模式取决于内核的权重。反过来,核的权重是在训练过程中学习的。
2D CNN 中的内核大小由高度和宽度指定。下面是几个不同的 kernel_size 选项的可视化。(注意,内核元素的实际数值不太可能像这里显示的值那么大,它们肯定不会是精确的整数——显示这些数字只是为了强调内核是一个有组织的数字集合):

不同内核大小的示例。图片作者。
ResNet 是一种流行的预定义 CNN 架构。在 ResNet 论文中,他们总结了一些 ResNet 架构:

下表显示了几种 ResNet 的 CNN 架构的定义:ResNet-18(“18 层”)、ResNet-34(“34 层”)、ResNet-50(“50 层”)、ResNet-101(“101 层”)和 ResNet-152(“152 层”)。从表中可以看出,3×3 是一个流行的内核大小。
1×1 内核/ 1×1 卷积
从这个表中还可以看出,有时会使用 1×1 内核。乍一看,1×1 卷积似乎没有用,一次只考虑一个元素有什么意义呢?
这里的关键是要记住内核实际上是三维的。您在编写代码时指定了所需的高度和宽度,但是生成的实际内核也将覆盖整个通道维度。几乎在每种情况下,都会有不止一个通道,因此,即使是 1×1 内核也会覆盖不止一个数字。例如,将 1×1 卷积核应用于具有 16 个通道、32 个高度和 32 个宽度的表示,将产生具有 1 个通道、32 个高度和 32 个宽度的输出表示。
(仅存在 1 个通道的一种情况是对于输入灰度图像;然而,这里你不会应用 1×1 内核,因为这没有意义。)
以下是 2×2 内核与 1×1 内核应用于 8 通道表示的对比图:

作者图片
从图中我们可以看到,即使是 1×1 内核也在计算多个数字,在本例中,它涵盖了 8 个数字,每个数字来自 8 个通道。
2×2 内核的整体大小实际上是 2×2×8 = 32。
1×1 内核的整体大小实际上是 1×1×8 = 8。
使用 1×1 卷积有什么意义?重点是组合不同通道/特征的信息,而完全不压缩空间维度。
大步流星
“步幅”是内核的“步长”——它在两次计算之间移动的距离。步幅越大,输出贴图越小。
填充是指附加的数字,通常是零,连接到表示的边界。可以使用填充的原因包括:
- 默认情况下,输入边缘上的像素只与内核边缘交互。如果我们希望每个边缘像素都有机会与内核的任何其他部分进行交互,我们需要使用填充。
- 默认情况下,如果不填充,表示将在空间上变得更小,因为内核始终保持在输入的边界内(参见下面的 gif)。如果我们使用填充,我们可以选择保留整个 CNN 的空间大小。
请注意,填充并不是绝对必要的,许多 CNN 在没有填充的情况下也能正常工作。
vdumoulin/conv 算术有一些很棒的步幅和填充的可视化效果。在这些可视化中,蓝色贴图是输入,青色贴图是输出。这里显示了一些可视化效果:
没有填料,就没有步伐。您可以从这个可视化效果中看到,在没有填充的情况下,青色输出小于蓝色输入,因为滤镜没有超出输入的边界。另请注意,“无步长”与“步长为 1”相同,即每次步长为 1 个像素:

没有填充,是的大步走。大步意味着过滤器一次“跳跃”预先指定的像素数。这里的步幅为 2,因此滤波器跳过 2 个像素:

有垫高,无跨步。你可以看到这里,添加了很多填充。事实上,添加了如此多的填充,以至于青色输出甚至比蓝色输入还要大。这是一个相当大的填充量,在实践中并不常用,但它有利于说明:

是的填充,是的大步走。在这个例子中,填充和步幅都被使用。

以上 4 个 gif 是 vdumoulin 的 2016 版权所有,可在 MIT 许可下使用(免费使用、复制、发布和分发)。请访问 vdumoulin/conv 算术查看填充、步长、转置卷积和扩张卷积的其他动画。
选择内核大小、步长和填充
通常选择相同的内核大小和步距
- kernel_size=(1,1)和 stride=(1,1)
- kernel_size=(2,2)和 stride=(2,2)
- kernel_size=(3,3)和 stride=(3,3)
然而,内核大小和步幅不必相同,内核大小也不必如此之小。例如,GoogLeNet 包括具有以下组合的层(参见本文,表 1):
- kernel_size=(7,7)和 stride=(2,2)
- kernel_size=(3,3)和 stride=(2,2)
- kernel_size=(3,3)和 stride=(1,1)
- kernel_size=(7,7)和 stride=(1,1)
流行的内核大小包括(3,3),(5,5),有时是(7,7)。
PyTorch 中的默认填充为 0,即没有填充。
关于内核大小、步幅和填充的其他观点,请参见“卷积神经网络填充和步幅的简明介绍”
3D 卷积神经网络
图像尺寸
3D CNN 可以应用于 3D 图像。有许多不同种类的 3D 图像,包括视频和医学图像,如 CT 扫描或磁共振成像。3D 图像有 4 个维度:[通道、高度、宽度、深度]。

狗飞奔的视频。来自维基百科(公共领域)。该灰度视频具有 1 个颜色通道、2 个空间维度(高度 x 宽度)和 1 个时间维度,总共 4 个维度。

扑翼飞机的视频。来自维基百科(公共领域)。该彩色视频具有 3 个颜色通道、2 个空间维度(高度 x 宽度)和 1 个时间维度,总共 4 个维度。

CT 扫描体积图像。来自维基百科(知识共享许可)。CT 扫描是“非堆叠的”,因此有可能一次欣赏所有 3 个空间维度。这种 CT 有 1 个彩色通道(灰色)和 3 个空间维度(高 x 宽 x 深)。
过滤器尺寸
一个 3D CNN 过滤器有 4 个维度:[通道,高度,宽度,深度]。
总体输入尺寸
3D CNN 具有 5 维输入:[批量大小、通道、高度、宽度、深度]。
在 PyTorch 中定义 3D CNN 图层
PyTorch 中定义 3D CNN 层的函数是 nn。Conv3d 。示例:
nn.Conv3d(in_channels = 3, out_channels = 16, kernel_size = (3,3,3), stride=(3,3,3), padding=0)
请注意,这与定义 2D CNN 层非常相似,只是我们可以为内核定义 3 个维度,为步幅定义 3 个维度。
注意,这些维度都不需要相同——如果我们愿意,我们可以将 kernel_size 定义为(1,2,5 ),将 stride 定义为(2,4,3 )(尽管很难想出选择这种看似随机的内核大小和步数的原因)。
如同 3D CNNss 一样,在 3D CNN 中,通常选择相同的核大小和步距。
这是一个展示 3D CNN 的 4D 过滤器的插图。这是一个输入为医学图像的示例,我们提取了 512 个不同的特征,其中每个特征的维度对应于输入的 3D 维度(右/左、前/后和上/下=颈/胸/腹):

作者图片
py torch 中完整 2D CNN 的结构
这是 PyTorch 中一个功能齐全的小型自定义 2D CNN,您可以将其作为自己自定义 CNN 的起点:

作者图片
此代码可从这里获得。所有模型定义都可以在 models/custom_models_base.py 中找到。(将重复使用的网络存储在单独的模块中通常很方便。例如,如果您有一组要在许多不同模型中使用的卷积层,您可以将该组层存储在 components.py 中。)
【PyTorch 模型的面向对象编程
如果您不是面向对象编程方面的专家,不要担心——为了开始在 PyTorch 中构建自己的 CNN,您不需要了解太多。本节涵盖了您需要了解的关于面向对象编程的一切,以便成功地构建您自己的 CNN。
首先让我们看看 TinyConv 内部的方法。要在 PyTorch 中定义 CNN,至少需要两个方法:一个叫做 init()另一个叫做 forward()。
init()定义模型的层。从技术上讲,这些层不必按照任何特定的顺序来定义,但是如果按照它们被使用的顺序来定义,视觉效果会更好。
forward()定义了模型应该如何计算输入 x。注意,我们已经将 x 传递给 forward,as forward(self,x)。如前所述,输入“x”对于 2D CNN 是 4 维的[批处理大小,通道,高度,宽度],对于 3D CNN 是 5 维的[批处理大小,通道,高度,宽度,深度]。
类和对象
下图总结了类、对象和属性:

作者图片
PyTorch 中的每个 CNN 都是用一个“类”定义的——因此代码的第一行定义了“class TinyConv(nn。模块)”。
单词“方法”仅仅意味着“在类内部定义的函数”
TinyConv 是类的名称。该类可以随意命名,甚至可以命名为 superawesomemodeltsolveeverything。
如果我们使用这个类来创建一个模型的实例,我们实际上将使用它来进行训练、验证和测试,例如通过运行下面这行代码:
mymodel=TinyConv()
那么这个实例“我的模型”就被称为“对象”“对象”是一个类的实例。
属性
在 TinyConv 的 init()方法中,我们定义了 self.conv 和 self.fc。这些属性定义了构成模型的层。
单词“self”使这些属性可以在 TinyConv 中的任何地方被访问,而不需要显式地将它们作为参数传入。你需要在一些地方使用“自我”:
- 作为所有方法的参数:init(self)和 forward(self,x)
- 定义所有属性时:例如 self.conv = something
- 当您使用任何属性时,例如 x = self.conv(x)
面向对象编程的一个优点是你不必像传递参数一样传递那么多的“东西”,因为我们可以直接使用属性。
继承
通过查看最上面一行,您会注意到,class TinyConv(nn。Module)我们正在使用“nn.Module”,nn 是什么?模块?

作者图片
nn。模块是 PyTorch 中所有神经网络的“基类”。在 PyTorch 文档中,你可以在这里阅读更多关于 T2 的内容。简单来说,nn。模块为您的定制模型提供了大量的功能,包括允许您的模型跟踪其可训练参数,并允许您在 CPU 和 GPU 之间切换模型。
你不需要担心通读 nn.Module 的所有代码。你需要做的就是确保你的定制模型“继承”nn.Module。当你的模型“继承”nn 时。模块,您的模型将获得 nn。模块提供。
继承就像贴 nn 一样简单。模块,如 TinyConv 示例所示。
类 TinyConv()不从 nn 继承。模块,并且不会工作。
类 TinyConv(nn。模块)确实继承自 nn。模块,并将正常工作。
为了使继承正常工作,您需要的另一部分是这行代码:
super(TinyConv, self).__init__()
在这里,您可以将“TinyConv”替换为您为定制模型指定的任何名称。
关于 super()在做什么的更多细节,可以看这些参考资料: ref1 、 ref2 、 ref3
用神经网络组织模型。顺序
你会注意到在 TinyConv 中,我们使用了一个叫做 nn.Sequential. nn 的东西。PyTorch 提供了 Sequential 来帮助组织神经网络的层。这里是同一个 TinyConv 网络,定义时使用和不使用 nn。顺序:

作者图片
你也可以在这里查看 TinyConv 和 TinyConvLessOrganized 的代码。
技术上来说 nn。不一定要使用顺序——但最好使用它,因为它有助于保持代码更有组织。
代码演示:微小数据上的微小 CNN(在 CPU 上运行)
您可以使用这个库中的代码运行几个定制 CNN 的演示。要运行演示,您需要做的就是更新演示文件中的路径,以指定您想要存储结果和数据的位置。
演示 1 将在微小的数据上训练和评估一个微小的 CNN,特别是 CNN“tinyconvewithetsequential ”,这是上面显示的模型,其中 NN。不使用顺序。请注意,这个 CNN 和数据集非常小,因此您应该可以在任何计算机上运行 Demo 1,包括带有小 CPU 且没有 GPU 的小型笔记本电脑。
要运行演示 1,请更新 Demo-1-tinyconvewithoutsequential-tiny data . py 中的结果路径,然后在一个解释器中运行下面的命令,该解释器具有本文开头描述的 conda 环境:
python Demo-1-TinyConvWithoutSequential-TinyData.py
演示 2 将在微小的数据上训练和评估一个微小的 CNN,特别是模型“TinyConv”,如上所示,它使用了 nn.Sequential。
下面是如何运行演示 2:
python Demo-2-TinyConv-TinyData.py
如果您看一下演示代码,您可以看到正在使用的模型和数据集被定义为演示配置的一部分。这意味着您可以轻松地换入您自己的模型和数据集,并使用这些代码来训练、评估和测试您感兴趣的问题。
代码演示:更大数据上的更大 CNN(需要 GPU)
演示 3 将在的 PASCAL VOC 2012 自然图像数据集上训练和评估 CNN,使用一个带有在 ImageNet 上预先训练的 VGG-16 特征提取器的模型。要运行这个演示,您可能需要使用 GPU。
python Demo-3-VGG16-PASCAL.py
最后,演示 4 将使用带有 VGG-16 特征提取器的模型,在 PASCAL VOC 2012 数据上训练和评估几个不同的 CNN 变体。在 VGG 特征提取器之后,不同的 CNN 具有稍微不同的层。一些 CNN 使用在 ImageNet 上预先训练的特征提取器,而其他的使用随机初始化的特征提取器。
python Demo-4-VGG16Customizable-PASCAL.py
请注意,为了运行演示 3 或演示 4,您需要取消演示文件中的一些代码的注释,以下载 PASCAL VOC 2012 数据集。下载完数据后,您可以重新注释这些代码行并运行演示。
使用 src/run_experiment.py 进行训练、评估和测试
模块 src/run_experiment.py 包括实际运行实验的所有核心代码。run_experiment.py 提供了一个类来训练、评估和测试不同的模型。你可以传入任何数据集,也可以传入任何用多标签分类交叉熵损失训练的模型。(如果您看一下代码,也可以直接将交叉熵损失替换为您想要的任何类型的损失。)run_experiment.py 还包括重新启动已经崩溃的模型的功能,提前停止的代码,以及性能指标 AUROC 和平均精度的计算(通过导入 evaluate.py)。
run_experiment.py 的几个关键部分包括这些方法:
- 运行模型(第 166 行)
- 火车(206 线)
- 有效(第 213 行)
- 测试(第 243 行)
- iterate _ through _ batches(258 行)
run_model()初始化模型(第 167 行),初始化优化器(第 172 行),然后执行指定的任何任务—“train _ eval”(在训练集上训练并在验证集上评估)、“restart_train_eval”(在模型崩溃后重新开始训练/验证)、“predict_on_valid”(在验证集上进行预测)或“predict_on_test”(在测试集上进行预测,这应该仅在模型开发完成后进行)。
train()将模型置于“训练模式”(第 207 行),然后通过调用 iterate_through_batches 进行实际的训练。它还调用函数来保存丢失的值以用于日志记录,并绘制性能度量(第 210 行)。
valid()与 train()类似,只是它指定模型应该处于评估模式(第 214 行),并且还确保不会计算任何梯度(第 215 行)。它还执行早期停止检查。早期停止是一种基于验证集上的性能停止训练的技术。你可以在这里阅读更多关于早停的内容。
test()将加载一个保存的模型,并使用该保存的模型对测试集进行预测,并计算测试集性能。
最后,iterate_through_batches()提供了训练、验证和测试过程的核心——它支持遍历数据集并将数据提供给模型。在训练期间,数据上的预测将与实际情况进行比较,以便更新模型的参数。在验证和测试期间,模型将用于对验证或测试数据进行预测。
在 iterate_through_batches()中,我们存储每个批次的预测概率和基本事实,以便在一个时期结束时(即,当我们检查完数据集的所有批次时),我们可以计算整个时期的整体性能指标。一个关键的技巧是,只使用预先分配的 numpy 数组来存储批次间的预测概率和基本事实。使用预分配的数组(第 263–266 行)可以更好地利用内存。我根据经验发现,使用 numpy 数组串联(而不是预先分配的 numpy 数组)会导致疯狂的内存碎片,并降低训练速度,尤其是在批量很小时。如果 Python 垃圾收集器正确地处理掉了旧的 numpy 数组,那么串联实际上不应该是一个大问题…但是在任何情况下,我已经看到了在一些不同的设置中发生的串联内存问题,这就是为什么我现在总是使用预分配的 numpy 数组来跨批存储预测和基本事实。
构建定制 CNN 的技巧
- 如果您正在构建一个分类 CNN,通常如果您使用预训练的卷积特征提取器,而不是完全从零开始构建的 CNN,您将获得更好的性能或至少更快的收敛。你可以使用一个预先训练好的特征提取器,然后是定制层,如示例模型vgg 16 可定制所示。
- 您要在一个图层中使用的滤镜数量在概念上类似于您要在该图层中检测的“模式”数量。
- 一层中的滤波器数量定义为该层的 out_channels 数量。
- 层的入通道数等于(a)输入图像中的通道数(如果是第一层),或者(b)对于 CNN 中的后续层,层的入通道数等于前一层的出通道数。
从卷积层过渡到全连接层的技巧
- 如果要从卷积层过渡到全连通层,首先需要扁平化表示:[batch_size,channels,height,width]必须变成[batch_size,channelsheightwidth]。例如,[batch_size,64,4,4]必须变成[batch_size,1024]。这个展平步骤的一个例子显示在第 128 行这里通过 x = torch.flatten(x,start_dim=1,end_dim=-1)行。
- 请注意,全连接图层的输入维度需要等于您将输入到该全连接图层的输入数据的实际大小。你可以在前一个卷积层的输出的基础上计算这个输入维度,这将需要一点算术来计算出那个卷积层的输出形状应该是基于所有在前层的。或者,如果你想节省时间并跳过算术运算,你可以只为完全连接的层输入指定一些任意的维度,让模型崩溃,然后检查展平步骤输出的实际形状,以了解你需要什么形状作为完全连接的层的输入形状(这在使用 pdb,Python 调试器时效果最好)。
- 从卷积层过渡到全连接层时要小心。如果试图指定一个太大的完全连接的图层,很容易就会耗尽内存。如果需要减少全连接层的输入大小,可以尝试(a)通过指定较小的 out_channels 数量或使用后续的 1×1 卷积来减少前一卷积层的通道数量,(b)增加前一卷积层的滤波器大小和步幅,添加自适应平均池或最大池等池操作,或者(d)简单地添加几个无填充的卷积层,使表示更小。
构建定制 CNN 的清单
- 你在你的第一层中选择了正确的输入通道数吗?(1 用于灰度输入,3 用于彩色输入)
- 您是否确保了特定卷积层的输入通道等于前一个卷积层的输出通道?
- 您是否记得在您的 CNN 模型定义中定义了 init()和 forward()方法?
- 您是否记得将“self”指定为 init()和 forward()方法的参数?
- 您是否记得在 init()中定义的、您希望在 forward()方法中使用的任何属性的名称前使用“self”?如 self.conv2d,self.fc,self.first_conv,self.classifier…
- 您是否记得从 forward()方法返回一些东西,以便您的模型实际上发出它的最终预测?
- 你记得继承 nn 吗?模块,方法是使用语法“模型的类名(nn。模块)”定义你的模型的时候?
- 有没有记得更新 line super(NameOfModel,self)。init()与您的模型的实际名称,以便继承正常工作?如果这个超级行与您在定义类时选择的名称不匹配,您将遇到一个错误。
总结
PyTorch 让你可以自由定义任何你喜欢的 CNN 模型。在本教程中,我们介绍了 pytorch-computer-vision 库,用于在任何数据集上训练、验证和测试任何定制 CNN。我们已经概述了图像/内核/输入维度、CNN 结构、内核大小、步幅、填充、一些面向对象的编程,以及 PyTorch CNN 模型定义的关键组件。
快乐造型!
原载于 2021 年 2 月 6 日 http://glassboxmedicine.comhttps://glassboxmedicine.com/2021/02/06/designing-custom-2d-and-3d-cnns-in-pytorch-tutorial-with-code/。
设计自定义 ggplot2 主题
给你的图表一种态度

作者的原创艺术
R 与 Python 的辩论是数据科学家最喜欢的话题。然而,当谈到数据可视化时,your truly有一个非常明确的偏好:ggplot2in R all way。
除了数据处理和格式化的便利性,ggplot2在它的可定制性方面表现出色。默认设置看起来很棒,虽然非常独特,但是通过一点规划,你完全可以改变可视化效果,以适应任何可以想象的审美。在这篇文章中,我将介绍如何创建一个自定义的ggplot2主题,可以应用到你的图表中。
重要的事情先来
打开一个新的 R 脚本,它将包含您的定制。为了使您的设置可用,您将在构建任何可视化之前运行该脚本。你也可以把它打包成一个库,尽管这不是绝对必要的。
确保加载必要的库。这里没有什么令人惊讶的,只是确保ggplot和scales在你做任何其他事情之前被载入。
library("ggplot2")
library("scales")
字体
新字体,新的你。对吗?在图形中使用自定义字体有几种选择。
第一种选择是使用你机器上已经有的字体。要访问它们,加载extrafont库并将所有字体导入 r。警告:这很慢。一旦你运行了font_import(),把它注释掉,不要管它。如果你不确定哪些字体是可能的,使用system_fonts()查看列表。
library("extrafont")
font_import() # only run this once then comment out. It's slow!
extrafont::loadfonts()library("systemfonts")
system_fonts() # shows you available fonts
第二个选择是添加谷歌字体。showtext库将允许您使用font_add_google()功能从谷歌字体页面导入字体。在这个例子中,我导入了 Reenie Beanie 字体以获得有趣的手写效果。
library("showtext")
## Loading Google fonts ([https://fonts.google.com/](https://fonts.google.com/))
graphFont = "Reenie Beanie"
font_add_google(graphFont)
主题
在正常情况下,您可能会使用theme()参数对默认设置进行小的更改。因为ggplot2是分层的,将+theme()添加到可视化的末尾将覆盖任何之前的设置。
我们可以通过定义一个定制的主题来利用这种行为,该主题可以添加到任何可视化的末尾。这意味着你甚至可以回到旧的工作,应用你的新主题来实现一个一致的投资组合。在这个例子中,我定义了一个简单的主题,将所有的文本变成黑色,指定各种背景填充,并设置字体。不带运行themeR 中的括号会显示所有可能的主题选项。
theme_custom = function(){
theme(
panel.background = element_blank(),
panel.grid = element_blank(),
axis.ticks = element_blank(),
axis.text = element_text(color = "black"),
legend.box.background = element_blank(),
legend.key = element_rect(fill = NA),
text = element_text(graphFont),
plot.title = element_text(size = 16)
)
}
色阶
设置颜色预先计划的色阶可以节省大量时间——告别猜测你上次使用的洋红色的阴影。我喜欢用 coolors app 创建调色板,然后创建一个十六进制代码的矢量。
请记住,您需要为scale_color_manual()和scale_fill_manual()设置一个比例,以说明不同的几何图形。
pal_custom = c("#9e0a0a", "#115035", "#ff9e97", "#f6cb4c")### Scales
custom_color_manual = function(){
scale_color_manual(values = pal_custom)
}
custom_fill_manual = function(){
scale_fill_manual(values = pal_custom)
自定义几何图形
如果您希望特定类型的图形具有特定的行为,那么定制 geoms 是一种不错的方法。update_geom_defaults()功能完成了这个任务。在这些例子中,我要求点的大小至少为 3,条的轮廓为白色,线的大小为 1。
update_geom_defaults("point", list(size = 3))
update_geom_defaults("bar", list(color = "white"))
update_geom_defaults("line", list(size = 1))
分层主题
如果一个主题还不够,你可以将主题分层。例如,如果你只是对一个现有的 [ggplot](https://ggplot2.tidyverse.org/reference/ggtheme.html) 主题做一些小的改动,你可以先运行原来的,然后再添加你的改动。
在这个例子中,我使用了 Emilio Torres-Manzanera 的 xkcd 主题来实现轴的手绘外观,然后在最后应用了我的自定义主题。
ggplot(data=iris, aes(x=Sepal.Width)) +
geom_histogram(binwidth=0.1, aes(fill=Species)) +
custom_fill_manual() +
xlab("X-axis title") +
ylab("Y-axis title") +
ggtitle("Main chart title") +
theme_xkcd() +
xkcdaxis(range(iris$Sepal.Width),range(c(0, 30))) +
theme_custom()
之前和之后
这个特殊的主题可能不适合你,但它肯定不同于默认的外观:


默认 ggplot2 主题(左)与自定义主题(右)的对比
测试
为你的可视化建立一个定制的美学需要一些迭代和测试。我建议构建一些测试视觉效果,可以在更新主题时运行——这将让您预览不同图表类型的效果。拥有少量的测试图也可以让你进行可访问性检查,并确保你的主题是用户友好的。我使用 Sim Daltonism 应用来评估调色板,使用 Accessibility Insights 扩展来检查网页元素。
knitter(.Rnw)或 R Markdown ( .Rmd)脚本非常适合测试,因为它可以很容易地重新编译以生成一个可共享的文档。像这样简单的事情就能达到目的:
\documentclass[a4paper]{article}
\begin{document}<<projections, include=FALSE, cache=FALSE>>==
source("branding.R")
opts_chunk$set(dev='cairo_pdf')
@<<renderimage, echo = FALSE, fig.height = 3, fig.width = 5, fig.align='center'>>==ggplot(data=iris, aes(x=Sepal.Width)) +
geom_histogram(binwidth=0.1, aes(fill=Species)) +
custom_fill_manual() +
xlab("X-axis title") +
ylab("Y-axis title") +
ggtitle("Main chart title") +
theme_xkcd() +
xkcdaxis(range(iris$Sepal.Width),range(c(0, 30))) +
theme_custom()@\end{document}
就是这样!我希望这能给你一些如何为自己的ggplot2作品创建自定义主题的想法。从小处着手,看看什么有效,然后在此基础上进行构建。你的图表很快就会引人注目。
思考数据可视化中的可访问性?太好了!以下是一些开始的方法:
使用 Apache 气流设计电信性能测量的数据管道系统
实践教程
为绩效监控建立自动报告系统

照片由在 Unsplash 上拍摄
最近,我为一个新部署的 5G 移动网络设计了一个数据管道系统,用于网络性能监控。我想分享我是如何设计的,我使用过的工具,以及对原始数据的一些特殊处理。
首先,并非所有人都来自电信行业,让我们了解一下什么是绩效管理。
性能管理
性能管理(PM)是由电信管理网络(TMN)定义的功能。它负责监控、分析和控制网络性能。性能管理是通过定期收集网络、设备、功能、服务或其他对象的性能数据,并集中存储和管理收集的数据来实现的。负责操作这些任务的系统称为操作支持系统(OSS)。
数据流

简化系统图。这张和下面所有的图都是作者准备的。
- OSSs 定期通过北向接口将 CSV 文件上传到 SFTP 服务器。
- ETL 服务器从 SFTP 服务器获取 CSV 文件,将其转换并插入 Greenplum DB 和 MySQL。
- 基于原始数据在 Greenplum DB 和 MySQL 上创建关键性能指数(KPI)视图。
- 仪表板从 MySQL 的视图中查询 PM KPI 数据。
- 对于报告生成,ETL 服务器从 Greenplum DB 的视图中查询 PM KPI 数据,修改 Excel 模板的数据页,并将报告发送给收件人。
- 由 Streamlit 构建的 Data Explorer 应用程序直接查询 Greenplum DB。
数据准备
数据格式

CSV 样本

由特殊字符组成的列名
结果时间:这是收集时间。
粒度周期:测量任务的采样间隔,单位为分钟。
对象名称:被测网元及功能。
可靠性:这个测量是否可靠。
之后各种计数器。
处理特殊字符
正如您在图片中看到的,在列名中有空格、大写字母、小写字母,甚至还有特殊字符,如 ()-/ 。在数据库列中使用空格和特殊字符不是一个好主意,我们需要在使用下面的代码将数据插入数据库之前处理它们。
counter_column_mapping = {}for counter in df.columns:
column_name = ''.join(e if e.isalnum() else "_" for e in counter).lower()
counter_column_mapping[column_name] = counter
df.rename(columns={counter: column_name}, inplace=True)
对于每个列和字符,我们检查它是否是一个字母或数字,如果不是,我们将其更改为 _。然后使所有字符小写。
表列名映射
OSS 输出数据文件的一个棘手的特性是列的数量是可变的。这种变化可能是由网络元件的软件升级引起的。可以添加新的计数器和移除旧的计数器。有时,计数器名称可能会改变。如果我们需要在每次软件升级时手动更改数据库模式,这将是乏味且容易出错的。因此,我们设计了一个自动处理列修改的过程。
我们创建一个名为 table_column_name_mapping 的表,并将修改后的列名和原始的计数器名映射存储到数据库中,以便进一步处理。我们每次都检查这个表,以验证数据文件中是否有新的列。如果在数据文件中发现了新列,我们首先将新列添加到相关的表中,然后插入数据。

表 _ 列 _ 名称 _ 映射(1)

表 _ 列 _ 名称 _ 映射(2)
修剪列名长度
一些计数器名称超过 63 个字符,不符合我们的数据库限制。我们通过将字符串缩减为 59 个字符并在字符串末尾添加三个随机选择的字母来防止重复的列名,从而解决了这个问题。(见上图第 148 行)
for col in df.columns:
if not col in mapping_col.original_column_name.tolist():
if len(col) > 63:
while True:
new_col = col[:59] + '_' + ''.join(random.choice(string.ascii_letters.lower()) for x in range(3))
if len(mapping_col[mapping_col.modified_column_name == new_col].values) == 0:
break
df.rename(columns={col: new_col}, inplace=True)
else:
new_col = col
提取、转换和加载(ETL)
我使用气流构建了 ETL 管道。在其官方网站上,它声明 Airflow 是一个由社区创建的平台,用于以编程方式创作、调度和监控工作流。它使用标准的 Python 特性来创建工作流,包括用于调度的日期时间格式和用于动态生成任务的循环。
我最喜欢的 Airflow 特性之一是,您可以通过一个强大的现代 web 应用程序来监控、调度和管理您的工作流。我可以全面了解已完成和正在进行的任务的状态和日志。

DAG 运行状态
我为数据插入构建了三个重要的 Dag,分别是“sensor”、“insert_data”、“create_view”。传感器 DAG 会定期检查 SFTP 服务器是否有新的 CSV 文件,并通过 API 触发 insert_data DAG。
在下面的链接中找到更多关于 Airflow REST API 的信息。
有一个名为 sense_master 的表,用于存储“传感器检测到并触发“插入数据”过程的所有文件名。每隔 5 分钟,传感器会将 SFTP 服务器目录中的文件列表与数据库表中存储的文件列表进行比较。它将需要处理的文件名传递给 insert_data DAG。
insert_data DAG 然后执行数据准备并插入到数据库中相应的表中。
create_view 使用公式表创建 KPI 的视图。KPI 是根据收集的原始计数器计算的。让我们看看下面的例子。KPI“CSCF 成功初始注册 UE 原因的比率”通过以下公式使用四个原始计数器值进行计算。
SUM(Number of S-CSCF Successful Initial Registrations + Number of 401 Responses of Initial Registration Sent by S-CSCF — Number of REGISTER Requests Sent by UE to S-CSCF After UE Receives 401 Responses from S-CSCF)/NULLIF(SUM(Number of S-CSCF Initial Registration Attempts), 0) * 100
同样,KPI 和公式之间的映射存储在数据库中,并在每次触发 create_view 时进行查询。
报表生成
对于报告生成,Excel 报告模板中有几个隐藏的“数据页”。图表链接到相应的数据页面。“daily _ report”DAG 查询相应的视图并自动替换数据。然后将生成的 Excel 报告以附件的形式发送给电子邮件收件人列表。
我用来操作 Excel 的 Python 库叫做 openpyxl 。我所做的基本上是将从数据库视图中读取的整个数据帧复制到 Excel 表中。如果你们感兴趣,我可以写另一篇关于如何使用 openpyxl 用 Python 操作 Excel 的文章。
未来的改进
这个数据管道系统此时是同步的。传感器通过 API 请求直接触发 insert_data DAG。它不是一个分离的架构,因为一个流程故障可能导致整个系统的故障。在我们的示例中,如果 Greenplum DB 长时间失败,并且 insert_data 达到其重试限制,数据将会丢失,因为传感器已经“检测”到数据文件,它将不会再次触发该过程。
更好的方法是事件驱动架构。传感器找到需要处理的新数据文件后,会向事件总线发送一条消息。insert_data DAG 从事件总线中提取并处理它需要处理的任何数据。在这种情况下,如果 Greenplum database 出现故障,数据插入不会完成,但消息/事件仍包含在事件总线中。一旦数据库恢复,需要处理的数据文件被再次提取并插入数据库。
我还在学习事件驱动架构。我希望将来我能构建一个事件驱动的架构,并再次与大家分享。
如果您想了解更多关于 Apache Airflow 的知识,Udemy 上有一个很好的课程,可以教授 Airflow 的基础知识,还可以动手构建数据管道。如果您有兴趣,请参考以下附属链接:
https://click.linksynergy.com/deeplink?id=0wsuN4lypZM&mid=39197&murl=https%3A%2F%2Fwww.udemy.com%2Fcourse%2Fthe-complete-hands-on-course-to-master-apache-airflow%2F https://click.linksynergy.com/link?id=0wsuN4lypZM&offerid=916798.19111388448&type=2&murl=https%3A%2F%2Fwww.coursera.org%2Flearn%2Fetl-and-data-pipelines-shell-airflow-kafka
用 R 语言设计和实现 NFL 分析工具
让自己在日常生活中运用分析技巧

戴夫·阿达姆松在 Unsplash 上拍摄的照片
作为一名数据科学专业人员,我欣赏分析工具的设计和实施,这些工具为组织内的关键利益相关者提供数据驱动的见解。这些工具的结构和功能各不相同,从嵌入在业务报告应用程序中的生产级机器学习系统,到针对半常规用例跨多种编程语言手动执行的脚本。不管一个工具看起来像什么,创造和开发的过程是这些工具成功背后的驱动力,可以应用于商业和娱乐。随着 2021 年国家橄榄球联盟赛季的开始,我决定建立一个解决方案,让我能够灵活地分析 NFL 的比赛数据,以收集见解。通过这个,我希望展示一些我在职业生涯中使用的成功实践。我很感激对这篇文章内容的任何评论。
你可能会觉得有趣的是,我将在这个项目中使用 R。目前,Python 似乎是数据科学和分析专业人士首选的主要编程语言;以至于有些文章甚至觉得没有必要明确指出他们是在用 Python 编码。我相信这两种语言都为我可能会在这里做的绝大多数事情提供了很好的解决方案,而且在 dplyr 被创造出来之前我就已经在使用 R 了,所以我对它更加得心应手。可能的话,我会用不同的方式来计算事物,以展示语言的多样性。最后,我在 PC 上通过 RStudio 使用 R 4.0.4。
让我们从确定项目范围和目的开始。
定义目的&分析解决方案的范围
对项目范围的全面考虑将引出分析解决方案的目的。在这个发现阶段,我向组织提出的一些问题包括:
- 用例影响哪些业务部门?
- 谁是解决方案的最终用户或消费者?这些观众的专业技术水平如何?
- 该解决方案要解决的关键难点是什么?
- 对关键利益相关者来说,成功是什么样的?
- 需要哪些数据?需要外部获取吗?
- 这是一次性的事情,还是一个重复的过程?
- 什么类型的定量工具可以增加价值而不牺牲效用?

图一。作者图片
我还考虑任何项目的高级过程流,以识别核心结构和功能。通常,分析解决方案从数据源开始。提取、转换、预处理和特征工程被执行以“清洗”数据流;这包括操作和网络安全方面的考虑。探索性数据分析将确定数据完整性和准确性问题。一旦完成这些步骤(有时不止一次),清理后的数据将以可访问的方式存储在长期和/或短期存储中,并根据需要创建连续收集和存储的方法。
在构建了这个关键的基础设施之后,功能层提供了进一步的处理和量化方法来满足项目的需求。
考虑到我对这种解决方案的随意使用,我不必太担心耐用性或生产化。我是最终用户。只是一个真正喜欢看和分析 NFL 比赛的人。我在几个梦幻足球联盟踢球,并且住在一个体育博彩合法的州。我希望有一种方法来动态地检查游戏,测试假设,并比较玩家和团队。灵活性对我来说将是关键,因为我想随着赛季的进展增加功能。我认为现在这个解决方案的目的是为我编写函数和脚本提供上面 R 中描述的基础设施。
就我的数据要求而言,这意味着什么?我想要至少三年的详细数据。我最有可能使用 web 抓取或 API 来收集这些数据。我想在本地存储清理后的数据;我不需要不断地导入和处理多年的数据。我想每周收集新数据。
建立或利用现有的数据管道
通常,我不想以可靠和准确的形式编写已经存在的代码。比如我不手动计算 vector 的平均值;我总是用表示(x)。它存在,它是正确的,它节省我的时间。我会一直尝试以合法的方式识别和利用来自知名来源的现有软件包。考虑到我目前没有任何内部数据源,我将把我的数据收集选项限制为从一个数据源手动抓取这些数据或者识别一个可靠且准确的 API。我发现了一些开源的 R 包,它们提供了获取、清理和转换 NFL 比赛数据的高级功能,NFL scrapr&NFL fastr。前者通过 NFL.com JSON 提要获取数据,而后者依赖于第三方 JSON 提要。在查阅文档之后,我决定使用 nflfastR ,主要是因为它似乎是一个更大的生态系统 nflverse 的一部分。我鼓励你通过上面的链接查看他们的网站,以便你自己进行评论。在这个集合中还有其他几个有趣的包,稍后我将会看一看。
在我开始使用这个包之前,我想尽可能多地了解所使用的方法。这样,我将能够预测输出并识别边缘情况,以及了解解决方案将使用哪些功能,以及我必须定制或在其他地方找到哪些功能。官方文档和用户指南为使用和实施提供了很好的信息。
首先,我需要检查任何其他的包依赖或需求。根据您的设置,您可能需要安装或更新某些项目。您可以使用 utils 中的 available.packages() 来检查包的依赖性和导入,并查找相应的包:
pkgs<-available.packages()
pkgs["nflfastR", c("Depends","Imports")]
我最后不得不安装 gsisdecoder 来解码玩家 id 和更新 Rcpp。
经过审查, nflfastR 通过一个由几种不同格式的文件组成的 Github 存储库提供 NFL 的详细比赛数据(你可以在本文末尾找到版权和许可信息)。对于倾向于 Python 的人,该团队提供了一种在他们的站点上导入这些数据的简洁方法。首先,您必须从fast _ scraper _ schedules():atible中获取 17 列的结果。第一列称为 game_id ,用作获取数据的输入。让我们获取数据并进行探索;注意为了简洁起见,我将排除一些输出:
- 标识返回的数据对象的类别
- 看看数据对象的结构
- 看一个实际数据的例子
- 确定游戏的总数
- 按赛季周检查比赛数量
library(gsisdecoder)
library(nflfastR)game_ids_2021<-fast_scraper_schedules(2021)class(game_ids_2021)
# [1] "tbl_df" "tbl" "data.frame"str(game_ids_2021)
# tibble [269 x 17] (S3: tbl_df/tbl/data.frame)
# $ game_id : chr [1:269] "2020_01_HOU_KC" "2020_01_SEA_ATL" "2020_01_CLE_BAL" "2020_01_NYJ_BUF" ...
# $ season : int [1:269] 2020 2020 2020 2020 2020 2020 2020 2020 2020 2020 ...
# $ game_type : chr [1:269] "REG" "REG" "REG" "REG" ...
# $ week : int [1:269] 1 1 1 1 1 1 1 1 1 1 ...
# $ gameday : chr [1:269] "2020-09-10" "2020-09-13" "2020-09-13" "2020-09-13" ...
# $ weekday : chr [1:269] "Thursday" "Sunday" "Sunday" "Sunday" ...
# $ gametime : chr [1:269] "20:20" "13:00" "13:00" "13:00" ...
# $ away_team : chr [1:269] "HOU" "SEA" "CLE" "NYJ" ...
# $ home_team : chr [1:269] "KC" "ATL" "BAL" "BUF" ...
# $ away_score : int [1:269] 20 38 6 17 34 27 20 43 11 17 ...
# $ home_score : int [1:269] 34 25 38 27 30 23 27 34 21 27 ...
# $ home_result: int [1:269] 14 -13 32 10 -4 -4 7 -9 10 10 ...
# $ stadium : chr [1:269] "Arrowhead Stadium" "Mercedes-Benz Stadium" "M&T Bank Stadium" "New Era Field" ...
# $ location : chr [1:269] "Home" "Home" "Home" "Home" ...
# $ roof : chr [1:269] "outdoors" "closed" "outdoors" "outdoors" ...
# $ surface : chr [1:269] "astroturf" "fieldturf" "grass" "astroturf" ...
# $ old_game_id: chr [1:269] "2020091000" "2020091300" "2020091301" "2020091302" ...head(game_ids_2021)head(game_ids_2021)nrow(game_ids_2021)
# [1] 272count(game_ids_2021, week)
# A tibble: 18 x 2
# week n
# <int> <int>
# 1 1 16
# 2 2 16
# 3 3 16
# 4 4 16
# 5 5 16
# 6 6 14
# 7 7 13
# 8 8 15
# 9 9 14
# 10 10 14
# 11 11 15
# 12 12 15
# 13 13 14
# 14 14 14
# 15 15 16
# 16 16 16
# 17 17 16
# 18 18 16
现在我们知道了返回对象的列名和数据类型。不要忘记,由于多了一场常规赛,我们今年还有 18 周。此外,请注意数据流的节奏似乎足以满足我的需求;我们有所有第 1 周的数据,而且似乎每天都在更新。这可以通过上面链接的 Github repo 看出来。
这个包的主要功能是加载和解析原始的逐场播放数据,这个功能是 fast_scraper(),,它从fast _ scraper _ schedules()中提取结果的一个子集,这是一个tible,列为 game_id。同时,通过 clean_pbp() 执行清理原始数据的动作。本质上,这个函数构建了我们将要保存和构建功能的数据结构。还有几种创建特征的方法,包括 add_qb_epa()、add_xyac()、add_xpass() 。这个包背后的团队已经开发了build _ nflfastR _ pbp(),这是一个调用这五个函数的高级函数,以及 decode_player_ids() ,它为所有球员创建了一个标准的 GSIS ID 字段,用于以后的球员统计。
# Subset the 2021 schedule to obtain Week 1 games;
# You can do it many different ways.
# Through dplyr, with and without the standard syntax:game_ids<-subset(game_ids_2021, week == 1, select = “game_id”)
game_idsgame_ids<-game_ids_2021$game_id %>% filter(week ==1)
game_ids<-game_ids$game_id# Or use vectorization
game_ids<-game_ids_2021[game_ids_2021$week == 1, colnames(game_ids_2021)==”game_id”]# Run the ETL pipeline
pbp_data_2021<-build_nflfastR_pbp(game_ids, decode = TRUE)
现在我们已经有了管道的结果,让我们研究数据以了解它的结构并检查质量问题。虽然我在这里只处理一些事情,但是这是您想要进行 EDA 最佳实践的地方。
- 查看数据集的结构,包括它的维度
- 通过一些关键分组变量检查观察值的分布
- 查找任何缺少的值,并获取键列的不同值
# Understand the structure of the play-by-play datastr(pbp_data_2021)
class(pbp_data_2021)
# [1] "tbl_df" "tbl" "data.frame"
ncol(pbp_data_2021)
# [1] 372
nrow(pbp_data_2021)
# [1] 2911# Look at the number of plays by game for Week 1count(pbp_data_2021, game_id)
# A tibble: 16 x 2
# game_id n
# <chr> <int>
# 1 2021_01_ARI_TEN 182
# 2 2021_01_BAL_LV 213
# 3 2021_01_CHI_LA 155
# 4 2021_01_CLE_KC 165
# 5 2021_01_DAL_TB 203
# 6 2021_01_DEN_NYG 159
# 7 2021_01_GB_NO 156
# 8 2021_01_JAX_HOU 206
# 9 2021_01_LAC_WAS 178
# 10 2021_01_MIA_NE 164
# 11 2021_01_MIN_CIN 212
# 12 2021_01_NYJ_CAR 175
# 13 2021_01_PHI_ATL 191
# 14 2021_01_PIT_BUF 189
# 15 2021_01_SEA_IND 169
# 16 2021_01_SF_DET 194# Look for NAs/missing values in the play_id columnnrow(pbp_data_2021[is.na(pbp_data_2021$play_id),])
# [1] 0# Obtain distinct values for the column play_typepbp_data_2021 %>% distinct(play_type)
# A tibble: 10 x 1
# play_type
# <chr>
# 1 NA
# 2 kickoff
# 3 run
# 4 pass
# 5 punt
# 6 no_play
# 7 field_goal
# 8 extra_point
# 9 qb_spike
# 10 qb_kneel
在这一点上,我们已经取得了 2021 年 NFL 的比赛数据,净化了它,并审查了结果的问题和见解。一旦我感到满意,我会将结果保存到本地驱动器,以备将来使用。
save(pbp_data_2021, file = “nfl_pbp_data_2021.RData”)
在这篇文章中,我应用了我在专业数据科学环境中使用的一些原则,为我的一个爱好设计和构建了一个分析解决方案。我希望我已经激励你也这样做了。虽然我的工具的基础结构已经设计好了,但是在这个基础结构上构建功能将是以后文章的主题。我也将进行分析来检查 NFL 的所有事情,希望我能把我获得的经验传递给其他人。我将以一个小例子来结束,说明我们如何从数据中获取有价值的信息。
出于各种原因,看看 NFL 进攻的跑位/传球分类可能会很有趣。让我们使用 dplyr 的 left_join() 函数来检查第 1 周的情况。请注意,team 的 NA 值表示暂停和季末等比赛,应该忽略。
# Get run and pass plays by team and join togetherrun_plays<-pbp_data_2021[pbp_data_2021$play_type == “run”,]
run_plays<-count(run_plays, posteam)
pass_plays<-pbp_data_2021[pbp_data_2021$play_type == “pass”,]
pass_plays<-count(pass_plays, posteam)
off_plays_by_team<-left_join(run_plays, pass_plays, by = “posteam” )
colnames(off_plays_by_team)<-c(“team”,”run_plays”,”pass_plays”)# Calculate run and pass play percentages and use cbind() to combinerun_percent<-off_plays_by_team$run_plays/(off_plays_by_team$run_plays + off_plays_by_team$pass_plays)
pass_percent<-off_plays_by_team$pass_plays/(off_plays_by_team$run_plays + off_plays_by_team$pass_plays)
off_plays_by_team<-cbind(off_plays_by_team, run_percent, pass_percent)
off_plays_by_team
# team run_plays pass_plays run_percent pass_percent
# 1 ARI 33 34 0.4925373 0.5074627
# 2 ATL 26 38 0.4062500 0.5937500
# 3 BAL 33 33 0.5000000 0.5000000
# 4 BUF 25 54 0.3164557 0.6835443
# 5 CAR 24 36 0.4000000 0.6000000
# 6 CHI 26 43 0.3768116 0.6231884
# 7 CIN 36 31 0.5373134 0.4626866
# 8 CLE 27 30 0.4736842 0.5263158
# 9 DAL 18 59 0.2337662 0.7662338
# 10 DEN 28 38 0.4242424 0.5757576
# 11 DET 24 62 0.2790698 0.7209302
# 12 GB 15 37 0.2884615 0.7115385
# 13 HOU 40 34 0.5405405 0.4594595
# 14 IND 31 41 0.4305556 0.5694444
# 15 JAX 15 52 0.2238806 0.7761194
# 16 KC 21 39 0.3500000 0.6500000
# 17 LA 19 27 0.4130435 0.5869565
# 18 LAC 26 49 0.3466667 0.6533333
# 19 LV 21 57 0.2692308 0.7307692
# 20 MIA 20 29 0.4081633 0.5918367
# 21 MIN 22 52 0.2972973 0.7027027
# 22 NE 30 40 0.4285714 0.5714286
# 23 NO 37 21 0.6379310 0.3620690
# 24 NYG 19 38 0.3333333 0.6666667
# 25 NYJ 18 44 0.2903226 0.7096774
# 26 PHI 32 35 0.4776119 0.5223881
# 27 PIT 18 34 0.3461538 0.6538462
# 28 SEA 27 26 0.5094340 0.4905660
# 29 SF 27 26 0.5094340 0.4905660
# 30 TB 14 50 0.2187500 0.7812500
# 31 TEN 22 42 0.3437500 0.6562500
# 32 WAS 27 22 0.5510204 0.4489796
# 33 <NA> 116 116 0.5000000 0.5000000
我将引用这段话。虽然它是关于“真正的”足球,我认为它也适用于美国版本。
有些人认为足球是生死攸关的事情。我向你保证,比那严重得多。—比尔·香克利
不隶属于国家足球联盟。
nflverse 和 nflfastR 版权 2020 Sebastian Carl 本·鲍德温并在麻省理工学院许可下分发。
通过 nflfastR 函数从李夏普通过NFLGameData.com获得的数据。
用 R 语言设计简单的明信片网站
拥有一个简单的网站,展示您当前的项目和互联网存在,对于数据科学社区的任何人来说都是必不可少的。

作者用 R. Image 明信片包装设计的网站。
我喜欢墨西哥食物。在新冠肺炎疫情酒店住了大约两个月后,我和妻子准备从我们最喜欢的墨西哥餐馆叫外卖。长话短说,我们最终没有向他们订购。为什么?他们没有一个网站列出他们的菜单或如何联系他们外卖。
这家餐馆因为没有网站而失去了我的生意。虽然企业拥有一个网站是必不可少的,但对于职场人士来说,拥有一个设计良好的网站也变得越来越重要。
我总是鼓励学生和年轻的专业人士花时间开发一个网站,展示他们的专业成就和他们正在从事的项目。至少,一个完善的 LinkedIn 个人资料可以做到这一点。特别是对于数据科学社区的专业人士来说,一个作为登录页面的网站可以为你的同事、客户和潜在雇主指明方向,这可以让你与众不同,让你的工作大放异彩。
如果你不在网上,你就不存在
对于那些从未有过网站的人来说,在线建站工具的数量是压倒性的。它们中的许多(例如 Squarespace 和 Wix)都很昂贵,并且能够做的事情远远超过了数据科学专业人员的需求,例如维护一个提供当前项目信息和联系信息的网站。
对于那些已经有一个或多个网站的人来说,你可能没有一个“登陆页”来指向你正在做的所有项目。这些可以包括专业和个人的追求和冒险。许多人还与多个机构和组织有联系(如学术机构),您可能希望通过一个网页向您的观众展示您参与的项目的多样性。
这就是为什么我喜欢明信片,这是一个 R 包,它使用 R Markdown 创建简单的网站和登陆页面。当罗杰·彭在《努力报告》播客中提到他有一个新网站时,我知道了这件事。我很感兴趣,因为看起来他的网站是用 R Markdown 设计的,这让我想到了明信片包装。
R 中的明信片包装
明信片的开发版可以安装在 R:
remotes::install_github("seankross/postcards@main")
任何网页都可以在一个 R Markdown 文档中创建。如果您使用的是 RStudio,导航到文件->-新项目 - > 新目录,创建一个新项目。然后导航至明信片网站项目类型:

使用 RStudio 创建明信片网站。
然后,指定要存储项目的目录。从四个模板中选择一个来设计你的网站。我为我的明信片网站选择了 Trestles 模板,因为它允许以易于阅读的格式添加更多文本:

现在,更改标题,将标签和 URL 更新到社交媒体空间和您想要指向的其他页面,并添加一些文本。RStudio 的 R Markdown 网页为那些想了解更多 Markdown 语言的人提供了极好的信息和一份备忘单。在您创建 R 项目的目录中,添加您自己的 JPEG 图像。下面是我用 Jolla 模板为一个树木玩具网站创建的一些信息:

明信片网站的降价版本。
这是用明信片构建的最终渲染网页:

一个用 r 语言明信片搭建的简单网站。
要让你的网站活起来,我推荐 Netlify Drop 。GitHub pages 是另一种可以使用的方法。在 Netlify Drop 中,拖放您为明信片网站创建的 R 项目文件夹,其中包含 HTML 文件,一切就绪。Netlify Drop 提供免费托管和 URL:

Netlify 下降。
您可以选择通过 Netlify 购买自定义域,而不是所提供的默认站点 URL。我每年为 mbrussell.org 支付 10.99 美元,这给你的网页增加了一些个性化。该站点将被设置为手动部署。
结论
拥有一个简单的网站,展示您当前的项目和互联网存在,对于数据科学社区的任何人来说都是必不可少的。R 包明信片使用 R Markdown 创建一个优雅的网站。可以使用 RStudio 将新网站设置为项目,然后使用 Netlify Drop 等工具部署到 web 上。
—
特别感谢 Sean Kross 的 明信片 包裹。
设计双双 Sudo-Staccato 浓缩咖啡
咖啡数据科学
再往下是分层射击兔子洞
sudo-staccato 技术是真正的 staccato espresso shot 的绝佳替代品,但我很难提高提取率。我一直在切割用过的冰球,并测量剩余的咖啡,结果表明,粗糙和中间层提取的咖啡比精细层少。结果我一直在看怎么把这个镜头设计的更好,结果就是双双 Sudo-Staccato。如果我用筛子来做两个不同的层面,这将是一个双重的断奏。
首先,我开始修改 sudo-staccato 镜头的中层和粗糙层的研磨尺寸,但是在修改层和修改流之间有一个平衡。我还是想要更高的提取率。我不得不重新考虑拍摄,所以让我们去掉粗糙的图层,但保持流畅。
不是三个研磨设置,而是堆叠在四层中的两个怎么样?好的,粗糙的,好的,粗糙的,或者像有些人说的,一个双双的。
设计双双
薄的精细层将限制沟道效应,而粗糙层将允许在下一层之前进行流动校正。两个目标之间的平衡将导致更高的提取率:
- 降低平均粒度(研磨设置)
- 保持流速
我的目标是得到一个更好的整体研磨设置。通常,当我拨入一颗咖啡豆时,我会在壁龛上设置 13。我一直在研究粒子分布,设置 5 和 15 的差别很大。我在这里画了 5,10 和 15,其中 10 是 5 和 15 之间的平均值。

所有图片由作者提供
镜头准备与其他分层镜头类似:

这是提取后颠倒的照片。这张照片有一点暗点,流动不均匀,但仍然是一张好照片。

镜头性能指标
我将这些定义放在这里,因为在这一节之后,我将使用这些指标评估不同数量的纸质过滤器。
最终得分是 7 个指标(强烈、浓郁、糖浆、甜味、酸味、苦味和余味)记分卡的平均值。当然,这些分数是主观的,但它们符合我的口味,帮助我提高了我的拍摄水平。分数有一些变化。我的目标是保持每个指标的一致性,但有时粒度很难,会影响最终得分。
使用折射仪测量总溶解固体(TDS ),该数字用于确定提取到杯中的咖啡的百分比,并结合一杯咖啡的输出重量和咖啡的输入重量,称为提取率(EY)。
开发过程中的提取和品尝
随着时间的推移,我绘制了前几个镜头,因为我对精细和粗糙层的研磨尺寸进行了一些调整。我的品味(最终得分)和 EY 稳步上升。由于与布料过滤器相关的问题,出现了一些颠簸。

我根据各层的加权平均值及其研磨尺寸计算了平均研磨值。有一个总的趋势是地面越来越高。作为参考,大多数时候我在设置 13 左右拨入一个常规镜头。

我们也可以看看这些镜头中的个别研磨设置。我没有看到任何一个层研磨大小的趋势,但我没有探究它们,看看事情在哪里崩溃。

然后,我将 TDS 和 EY 与其他分层镜头进行了比较,以了解这些镜头的趋势,似乎它们比 Sudo-Staccato 镜头的斜率略高,但它的趋势不太像 Staccato 镜头。

断奏的镜头如果做得好,是惊人的和令人兴奋的,但这需要筛选,这是典型的爱的劳动。然而,通过使用研磨设置和多层,可以在不需要筛选的情况下对典型的镜头进行很大的改进。
如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡视频和浓缩咖啡相关的东西。你也可以在 LinkedIn 上找到我。也可以在 Medium 或者 Patreon 上关注我。
我的进一步阅读:
为低资源语言设计标记化器
为什么为迪维希·ދިވެހި这样的语言构建 NLP 标记器如此困难

作者图片
我一直在和马尔代夫的伊斯梅尔·阿什拉克讨论自然语言处理。印度洋上一个美丽的群岛,令人难以置信地稳定在平均 25.2-31.6 摄氏度(对于那些生活在 18 世纪的人来说,那是 77.4-88.9 华氏度)。
Ashraq 向我介绍了迪维希语(或马尔代夫语),这种语言令人着迷。它使用一种叫做 Thaana 的复杂书写系统,我完全无法理解其中的任何一种。它与我所知道的任何事物都大相径庭——但是,就像这个群岛一样,它看起来棒极了。

NLP 和马尔代夫不是我通常会在同一背景下想到的两个事物。然而,事实证明,有很多人这样做。
Ashraq 就是其中之一,他描述了将 NLP 应用于他的母语迪维希语的困难。这有几个原因:
- 迪维希几乎有- 零预训车型。即使是涵盖数百种语言的多语言模型也错过了迪维希。
- 非结构化的迪维希文本数据很难找到,带标签的数据更难找到。
- 许多现有的 transformer 模型不仅从未见过 Dhivehi,而且由于独特的脚本,现有的 transformer tokenizers 无法处理 Dhivehi 字符(只输出未知的令牌)。
这些都是困难的障碍,但并非不可能克服。本文将探讨我们如何解决构建一个有效的 Dhivehi 单词片段分词器的第一步。
文章的视频演示。
获取数据
在构建我们的标记器之前,我们应该首先找到或创建一些数据。这里有几个迪维希数据集,质量还算合理。但是我们需要更大更干净的东西。
Ashraq 整合了一个新的迪维希语数据集,包含了从网上搜集的 1600 多万个迪维希语样本。它并不完美——但它是很好的,也是目前构建我们的标记器(以及后来的模型)的最佳公开可用资源。
为了下载数据集,我们使用:
我们已经设置了streaming=True来避免将整个数据集下载到我们的本地机器。这样,我们将迭代地下载每个样本。
因为我们将把数据提供给标记器训练函数,所以我们需要修改生成器输出,只生成 Dhivehi 文本,而不是包含 Dhivehi 文本的字典。
这个输出是我们需要的格式,所以现在让我们把数据留在这里,继续进行 wordpartecokenizer 的设置。
构建标记器
令牌化过程包括几个子步骤,它们是:
- 规范化 —文本清理,如小写,用 Unicode 规范化去除重音或怪异字符等。
- 预标记化 —分裂成多个部分,通常分裂成由空格字符指示的单词或子单词标记。
- 模型——例如“标记化”或将字符或子词合并成更大的逻辑组件。
- 后处理 —添加特殊令牌,将令牌转换为令牌 id 等。
- 解码器 —获取标记化数据并将其转换回人类可读文本的过程。这一步不是“标记化”过程的一部分,但对于理解任何基于文本的模型输出是必需的。
我们将利用优秀的🤗 分词器 库把所有这些都放在一起。我们必须首先初始化模型,因为我们将通过 tokenizer 模型属性添加剩余的步骤。
现在我们可以添加前两步,规范化和预标记化。
正常化
迪维希语既不包含大写字符,也不包含小写字符。迪维希语中根本就没有“格”这个词,老实说,英语中有这个奇怪的概念不奇怪吗?
奇怪的是,小写字母的发展(很可能)是因为抄写员急于写得更快——产生了一种更随意的小写字母。
随着时间的推移,将重要的句子和单词(比如你的名字)的开头大写成了标准做法。数百年前,印刷店将单个字母“印刷品”保存在名为盒的盒子里。
打印店将那些不常用的正式大写字母保存在难以接触到的大写字母中,而更常用的小写字母保存在容易接触到的小写字母中。
有时,看似不起眼的小物品的起源故事可能会引人入胜。反正,回到我们迪维正常化。
虽然我们不需要担心小写或大写的 Dhivehi,但我们的数据仍然会包含一些非 Dhivehi 文本。这个非 Dhivehi 文本不是我们关注的焦点,所以我们将所有内容都小写,以尽量减少可能产生的标记。
为什么?假设我们在训练数据中找到单词“hello”和“Hello”。如果没有小写,我们可能会产生两个令牌;Hello和hello。对于小写,我们只创建一个令牌;hello。
因此,我们在标记化中的第一个组件是一个小写函数,用于最小化非 Dhiveh 标记。
另一个好的规范化组件是 Unicode 规范化。我们不会深入讨论这个问题(更多信息,请点击),但它允许我们匹配以下内容:
ℕ𝕃ℙ == NLP
对于一个角色来说,通常有不同的角色代表,对我们人类来说,代表着同一个事物——比如ℕ𝕃ℙ和 NLP。但是,变压器不会将这些视为相同。Unicode 标准化允许我们解决这个问题,将这些字符变体映射到单个字符。
在应用 NFKD 规范化之后,我发现了 600,000 个样本发生了变化。对于 1670 万个样本来说,这个变化似乎很显著,所以我在标记器中添加了一个 NFKD 规范化步骤。
我们小写并将 NFKD Unicode 规范化应用于所有传入的文本进行规范化。
我们继续下一个部分。
预标记化
预标记化组件描述了将文本串分成初始块/标记。这里的标准做法是将文本分成单词和标点符号。意思是这句话:
"hello world! hey have you seen my pet koala?"
变成了:
['hello', 'world', '!', 'hey', 'have', 'you', 'seen', 'my', 'pet', 'koala', '?']
要做到这一点,我们只需要一个Whitespace预归类器。
目前,这就是我们将添加到记号赋予器的全部内容。培训完后,我们将返回到后处理组件。
训练分词器
前三个组件、规范化、预处理和标记化模型初始化后,我们可以继续训练标记化器。
我们需要迪维希数据(已经存储在🤗 数据集 迭代器)并指定几个分词器训练参数。
这里我们指定:
vocab_size—标记器词汇表中目标标记的数量。数字越大意味着令牌越多,但训练时间越长,令牌化器文件也越大。special_tokens—将在我们的 vocab 中包含的特殊令牌,BERT 模型稍后将需要这些令牌。min_frequency—“合并”在训练数据中出现的最少次数将被视为成为新令牌。continuing_subword_prefix—单词片段标记器在子单词标记前附加一个特殊字符。单词upright可能会变成['up', '##right'],而单词right可能会变成['right']。令牌##right和right不一样。第一个是子词标记。
这样,我们的记号赋予器trainer就准备好了,我们现在要做的就是调用一个tokenizer训练方法,并把它传递给我们的dv_text()生成器和训练器。因为我们将数据存储在一个可迭代的dataset对象中,所以我们可以调用train_from_iterator方法。
培训结束后,我们可以进入第四步——后处理。
后加工
我们将的后处理步骤定义留在训练之后,因为它使用将在我们的标记化器词汇表中定义的特殊标记,该词汇表是在训练步骤期间构建的。
在我们的后处理步骤中,我们定义了要应用于我们的标记器的输出的任何转换。

后处理步骤应用于标记化步骤的输出。
这个后处理步骤具体应该做什么?我们正在为 BERT 构建这个标记器,其他 BERT 模型使用的标准格式(翻译成可读文本)是:

带有特殊【CLS】和【SEP】标记的典型 BERT 输入格式。
为了定义这种格式化,我们使用了一个叫做TemplateProcessing的东西。这个类允许我们指定如何处理单句或双句输入。但是,如果在预处理过程中不使用NextSentencePradio(NSP),我们就不一定需要使用对语句格式。
在那些模板定义中有一些东西需要解开。首先,我们有两个特殊的令牌;[CLS]和[SEP],它们分别是‘序列开始’classi fier 和 sep arator 令牌。
我们将传递给分词器的第一句定义为$A,将第二句(如果给定的话)定义为$B。使用这种格式,句子"hello world"将被后处理为[CLS] hello world [SEP]。或者对于两个句子"hello world"和"pet koala",我们会看到[CLS] hello world [SEP] pet koala [SEP]。
还有一件事是已经提到的每个组件后面的:0和:1。这些定义了各个组件的token_type_id值(BERT 使用token_type_ids来区分不同的句子)。
这就是我们的令牌化组件,但是还有最后一个额外的组件要添加。
解码器
解码器步骤是将转换器可读的令牌 id 翻译回人类可读的文本。当我们使用单词片段标记化时,我们设置decoder属性来使用WordPiece解码器,并指定前面定义的子单词前缀。
节约
我们的标记器现在已经完全定义好了。剩下的就只有救了!这样我们就可以直接从🤗 变形金刚 (而不是用),我们必须将当前tokenizer加载到一个变形金刚记号化器对象中:
我们还再次指定了每个特殊标记。之后,我们保存记号赋予器,现在,我们可以像加载任何其他 变形金刚 记号赋予器一样加载它。
使用
现在可以通过from_pretrained方法加载 Dhivehi 分词器了,就像加载其他分词器一样。
然后,我们可以继续对迪维希语文本进行标记。
这就是为低资源语言构建标记器的介绍。非常感谢 Ashraq 向我介绍了他的迪维希项目,并让我也参与其中。他正在做一堆很酷的以迪维希语为中心的 NLP 项目,我很期待看到它的进展。
tokenizer 是为迪维希语言模型和工具建立更多支持的早期步骤。很自然,下一步是创建一个迪维希预训练的 BERT——我们将很快介绍它。
如果你想马上使用迪维希模特,你可以在我自己的和阿什拉克的拥抱脸简介上找到她们。
同时,你可以通过这个链接获得最新的文章。我还在 YouTube 上上传 ML 和 NLP 的每周视频。
感谢阅读!
*除另有说明外,所有图片均出自作者之手
摧毁你和 Julia 的所有编程概念
使用 Julia 打破计算机编程的传统方法

(src =https://pixabay.com/images/id-1994520/
介绍
在给计算机编程的艺术中,有许多不同的方法来完成工作。这个描述中的“作业”是类型、操作(方法)和数据之间的交互。从历史上看,对于计算机科学来说,这是一个非常独特的实验领域。现实情况是,有很多方法和途径,有些当然更适合不同的任务。
也就是说,Julia——对于我的应用程序来说,通常会完全颠覆人们对范式的典型看法。在我们进入我提到的内容之前,让我们快速地回顾一下编程范例的主题,以防我的读者对这个概念不熟悉。
范例
在 Lisp 编程语言发布之前,编程范式的存在并不像以前那样被定义。在此之前,有一些我们现在称之为命令式编程语言的语言,但是这些语言和它们各自的类型系统就像今天一样——混乱不堪。
Lisp 编程语言引入了函数式编程范式,随后是另一种众所周知的现代编程范式,面向对象编程。许多程序员可能熟悉这两个主题,但不确定它们的确切含义。
编程范式是不同定义的数据与编程语言中的操作进行交互的方式。例如,在面向对象编程范例中,我们看到方法通常是类型的属性。类型不是在方法参数中调用,而是作为结构的子级调用。这提供了一些语法上的优势,比如不需要为一些函数调用传递任何参数,此外还使得在每次方法调用时不再需要调用函数想要使用的类型成为可能。这种范式也非常强调子类型和分类。所有这些都来自于 Simula 编程语言中的思想,可以肯定地说,Simula 编程语言是所有面向对象编程之父。
尽管大多数编程语言都有一个特定的范例,但大多数现代编程语言都遵循一个流行趋势——多范例编程。多范例编程需要什么?有一个完全独立的能力联盟,也可以用来改变或增强编程语言的范式,这些被称为泛型编程概念。人们使用的大多数编程语言可能不是纯粹的 X 或 Y 语言,而是几种语言的混合。
例如,没有多重分派和其他编程泛型的 Julia 将是一种具有简单类型和函数的普通函数式语言。然而,多分派,参数多态,不需要太多的阅读就可以意识到将方法作为定义应用到它们各自的结构并不是一个函数声明性的概念。也就是说,Julia 仍然这样做,因为它可以,当然,当涉及到面向对象编程之类的东西时,这个特性并不那么有用,所以函数范式的应用更有意义。另一个例子是更流行的语言 Python。Python 有全局定义的变量和方法——这在任何情况下都不是面向对象编程的特性。在纯面向对象编程中,情况并非如此。然而,我们看到 Python 是如何从这种泛型编程概念中受益的,因为如果不是这样,它就不太可能被广泛用于数据科学。
摧毁范式
既然我们已经了解了范例,现在让我们用一些非常有趣(并且令人困惑)的代码来摧毁我们刚刚了解的一切。这个项目的代码是一个名为 OddFrames.jl 的包。这是一个面向对象的基于索引的 Julia 数据帧模块,旨在使处理数据更容易,更像 Python 的 API。如果你想了解更多关于这个项目的信息,你可以查看这里链接的 Github 页面:
https://github.com/ChifiSource/OddFrames.jl
这个项目还很年轻,这也是为什么很多方法仍然存在问题的原因。现在,请允许我揭示这个包的面向对象特性是如何工作的,这是接下来的怪异之处的先决条件。它从外部构造函数开始调用:
mutable struct OddFrame <: AbstractOddFrame labels::Array{Symbol} columns::Array{Any} coldata::Array{Pair} head::Function drop::Function dropna::Function dtype::Function
此类型由外部构造函数构成。我们能够传递该函数中使用的所有数据,并从局部范围将其放入类型中。这意味着,如果我们想查看数据帧,我们不需要使用
head(::OddFrame)
相反,在面向对象的场景中,我们可以这样称呼它:
OddFrame.head()
内部构造函数相对较短,因为它练习提取,所以我当然可以分享整个函数——并逐一运行每一行,这样我们就可以了解这个函数真正是如何工作的。我有一篇文章是关于为什么抽取实际上是一个很好的编程实践,如果你有兴趣了解更多的话,你可以看看这篇文章,但是我认为下面的演示肯定会准确地演示为什么这是编程时的一个很好的实践。不管怎样,这篇文章是这样的:
[## 更多的方法意味着更好的代码
towardsdatascience.com](/more-methods-means-better-code-1d3b237f6cf2)
function OddFrame(p::Pair ...)# Labels/Columnslabels = [pair[1] for pair in p]columns = [pair[2] for pair in p]length_check(columns)name_check(labels)types = [typeof(x[1]) for x in columns]# coldatacoldata = generate_coldata(columns, types)# Headhead(x::Int64) = _head(labels, columns, coldata, x)head() = _head(labels, columns, coldata, 5)# Dropdrop(x) = _drop(x, columns)drop(x::Symbol) = _drop(x, labels, columns, coldata)drop(x::String) = _drop(Symbol(x), labels, columns, coldata)dropna() = _dropna(columns)dtype(x::Symbol) = typeof(coldata[findall(x->x == x,labels)[1]][1])dtype(x::Symbol, y::Type) = _dtype(columns[findall(x->x == x,labels)[1]], y)# typeself = new(labels, columns, coldata, head, drop, dropna, dtype);select!(self)return(self);end
因为这是一个接受 pairs 的函数,所以这个函数的第一步是将它们从一个组中取出并放入一个数组中。这是为了让我们能够有效地与我们的搭档合作。如果我们不这样做,您可能会对其局限性感到惊讶。我希望有一些我知道的更简单的方法,比如 Array{Pair}() cast,但是我不知道这样的事情:
labels = [pair[1] for pair in p]columns = [pair[2] for pair in p]
我还借此机会分离标签、每对的第一个索引和列,它们应该是包含我们的观察值的数组。接下来,我运行一些快速检查,以确保我们的数据实际上可以包含在一个数据帧中。这些要求只是没有一个列的名称是相同的,并且所有列的长度都是相同的。
length_check(columns)name_check(labels)
接下来,我们必须获得每条数据的类型,这实际上非常重要——我想我在早期低估了跟踪数据类型的重要性。实际上,你会惊讶于仅从字符串中找出这一点有多难,例如在 CSV 读取的场景中,我实际上写了另一篇关于这一点的文章,因为我用于编写它的代码非常令人沮丧,你可以在这里阅读它——解决方案当然很有趣:
types = [typeof(x[1]) for x in columns]
接下来,我们为每一列生成列数据:
coldata = generate_coldata(columns, types)
我真的很想稍微修改一下,让外部构造函数保存类型,而不是像现在这样包含它的 coldata。不管怎样,接下来我们创建函数——然后奇怪的事情发生了:
# Headhead(x::Int64) = _head(labels, columns, coldata, x)head() = _head(labels, columns, coldata, 5)# Dropdrop(x) = _drop(x, columns)drop(x::Symbol) = _drop(x, labels, columns, coldata)drop(x::String) = _drop(Symbol(x), labels, columns, coldata)dropna() = _dropna(columns)dtype(x::Symbol) = typeof(coldata[findall(x->x == x,labels)[1]][1])dtype(x::Symbol, y::Type) = _dtype(columns[findall(x->x == x,labels)[1]], y)
类型部分是事情变得奇怪的地方。通常,这个 new()方法用作构造函数的最后一部分,因为它提供了我们新构造的类型的返回,该类型将被返回:
self = new(labels, columns, coldata, head, drop, dropna, dtype);select!(self)return(self);
然而,在这个实例中,在返回它之前,我们调用这个 select!()方法,我们把它赋给了一个变量。
这是干什么用的?
这就是这个包的范例变得有点古怪的地方。这个包中使用的大多数函数都被本地化为构造类型。例如,考虑包含这些类型的主文件。如果我折叠所有的类型,我们会看到在全局范围内声明的函数是如此之少。

(图片由作者提供)
所有全局定义的方法都放在 methods.jl 中,这是整个文件:
import Base: show, size, lengthshape(od::AbstractOddFrame) = [length(od.labels), length(od.columns[1])]size(od::AbstractOddFrame) = [length(od.labels), length(od.columns[1])]length(od::AbstractOddFrame) = length(od.columns[1])width(od::AbstractOddFrame) = length(od.labels)show(od::AbstractOddFrame) = od.head(length(od))function select!(od::OddFrame)global head = getfield(od, :head)global drop = getfield(od, :drop)global dropna = getfield(od, :dropna)global dtype = getfield(od, :dtype)end
因此,这个包当然更多地存在于面向对象的范例中,而不是函数式编程范例中。这个包实际上具有那个范例的所有特性——包括子类型。但是,我想请你注意选择!()函数:
function select!(od::OddFrame)global head = getfield(od, :head)global drop = getfield(od, :drop)global dropna = getfield(od, :dropna)global dtype = getfield(od, :dtype)end
这是我们在创建类型后调用的函数,它做什么,为什么在这里?嗯,我在 Julia 中使用这种面向对象的方法遇到了一个重要的问题—
文档。
你不能打电话吗?(od.whatever)在朱莉娅的任何种类的代码。基本上没有办法有效地记录类型的局部方法。除了我们将要使用的改变范例的方法之外,解决这样一个问题的唯一可用的方法是将方法文档添加到类型的文档中,例如它是如何在车床中完成的。
"""## Ordinal Encoder### DescriptionOrdinally Encodes an array.\n--------------------\n### InputOrdinalEncoder(x)\n--------------------\n#### Positional ArgumentsArray{Any} - x:: Array for which the original scaler should be basedoff of.\n--------------------\n### Outputencoder :: A Lathe Preprocesser object.---------------------\n### FunctionsPreprocesser.predict(xt) :: Returns an ordinally encoded xt.\n"""mutable struct OrdinalEncoder{P} <: Encoderpredict::Plookup::Dictfunction OrdinalEncoder(array::Array)lookup = Dict(v => i for (i,v) in array |> unique |> enumerate)predict(arr::Array) = map(x->lookup[x], arr)predict(df::DataFrame, symb::Symbol) = map(x->lookup[x], df[!, symb])P = typeof(predict)return new{P}(predict, lookup)endend
不用说,这可能会造成一些混乱。对于 Julia 程序员来说尤其如此,他们可能不期望面向对象的接口。同样,这意味着上面例子中 predict()方法的唯一文档就是我们想要放入这个函数部分的内容。实际上,每种方法都需要它自己的文档,这些文档可以更深入地举例说明。
另外,OddFrames.jl 只是一个不同的项目。这个项目将需要更多的方法来处理单个类型,这意味着如果我们使用车床方法,函数部分将绝对是巨大的,难以阅读,并且通常是糟糕的文档。幸运的是,有一种方法可以让我们拥有全局文档,我们可以在函数风格中使用一个方法定义——并且为每个函数拥有全局文档。
function select!(od::OddFrame)global head = getfield(od, :head)global drop = getfield(od, :drop)global dropna = getfield(od, :dropna)global dtype = getfield(od, :dtype)end
回顾我们的选择!()方法,它由我们刚刚定义的 oddframe 提供。注意,所有这些方法都可以通过简单地调用 select!()方法,如果最终用户决定选择!()一个不同的 Oddframe,或者如果创建了一个新的 OddFrame,它将被自动选择。我们使用 getfield()方法来获取我们的函数,尽管代码还没有出来,下一步是使用@doc 宏,如下所示:
@doc " Displays the first five observations of a given OddFrame" head()
@doc " Displays a given number (x) of observations of a given OddFrame" head(::Int64)
请记住,由于这些方法现在是全局定义的,它们现在是函数式的、非常声明性的调用,可以在典型的函数式风格中使用——只有一个例外——我们根本不需要提供类型。相反,这个现在的全局函数被定义为自动提供类型。记住,如果我们像这样调用 head()方法:
head()
那么我们将得到我们的 OddFrame 的前五个观察值!
结论
我认为这是我们在朱莉娅能做的一件非常奇怪的事情。由于其独特和难以置信的灵活范式,Julia 拥有各种有趣的怪癖和能力。如果你有一个问题,Julia 往往能够做你可能需要做的任何事情来解决你的问题——即使它变得非常奇怪,就像这个例子一样。然而,我真正喜欢 Julia 的一点是,尽管找出一个解决方案可能非常困难,尤其是在缺乏大量语言用户的情况下,但语言永远不会碍事。
感谢您的阅读。我很高兴我有这个平台来分享我和 Julia 一起做的所有这些非常有趣和古怪的事情。祝您愉快,编程愉快!
简单线性回归的详细解释,评估,和用 ANOVA 的推断

Clark Van Der Beken 在 Unsplash 上拍摄的照片
一步一步的讨论和例子,手动实现和 R
两个变量之间的线性关系很常见。因此,许多数学和统计模型被开发出来,以利用这一现象并提取更多关于数据的信息。本文将解释统计学中非常流行的方法简单线性回归(SLR)。
本文涵盖:
开发一个简单的线性回归模型
评估模型的拟合程度
使用 ANOVA 表进行假设检验
如果你读这篇文章是为了学习,那么一天之内你要学的东西会很多。所有主题都将包含一个工作示例。请自己动手做例子,以便更好地理解它。
开发单反机型应该不会太难。这很简单。只需使用公式并找到您的模型或使用软件。两者都很简单。
如果你完全是新手,评估和假设检验部分可能会令人困惑。你可能要慢慢的看几遍。我会尽量做到准确和中肯。
简单线性回归
当观察到两个定量变量之间的线性关系时,简单的线性回归可用于进一步解释和评估该数据。下面是两个变量之间线性关系的一个例子:

作者图片
图表中的点显示了积极的上升趋势。这意味着如果学习时间增加,考试成绩也会提高。换句话说,学习时间和考试成绩成正相关。从这样的图表中,可以推测出两个变量的相关性的强度和方向。但是不可能量化这种相关性,也不可能量化每增加一个小时的学习,考试分数会发生多大的变化。如果你能量化这一点,就有可能预测考试成绩,如果你知道学习时间的话。这将是非常有用的,对不对?
简单线性回归(SLR)就是这么做的。它使用的是我们在学校都学过的直线公式。公式如下:
y = c + mx
这里,
y 是因变量,
x 是独立变量,
m 是斜率,并且
c 是截距
在上图中,考试分数是 y,学习时间是 x。考试分数取决于学习时间。所以,考试分数是因变量,学习时间是自变量。
使用简单的线性回归确定斜率和截距。

作者图片
线性回归就是拟合通过这些点的最佳拟合线,并找出截距和斜率。如果你能做到这一点,你就能量化考试分数,如果你有可用的学习时间数据。现在,对考试分数的准确估计将取决于更多的信息。我们会慢慢到达那里。
在统计学中,β0 和β1 是代替 c 和 m 的常用术语。因此,上面的等式看起来像这样:

上图中的红色虚线应该尽可能靠近圆点。最常用的方法是最小二乘回归法。
回归方程
上图中的红色虚线称为最小二乘回归线。这条线应该尽可能地靠近这些点。

这里 y_hat 是因变量的估计值或预测值(上例中的考试成绩)。
记住,预测值可能与因变量的初始值不同。在上图中,原始数据点是分散的。但是上面等式中的预测值或期望值将在红色虚线上。所以,原始 y 和预测值 y_hat 之间会有差异。
β0 和β1 可以使用最小二乘回归公式计算,如下所示:

这里,
y_bar 是“y”变量的样本平均值。
x_bar 是“x”变量的样本平均值。
Sx 是“x”变量的样本标准偏差
Sy 是“y”变量的样本标准偏差
开发线性回归模型的示例
我希望上面的讨论是清楚的。如果没有,也没关系。现在,我们将研究一个例子,它将使一切变得清晰。
以下是用于本示例的数据集:

作者图片
该数据集包含 30 个人的臂长和腿长。散点图如下所示:

作者图片
请随意下载该数据集并跟随:
https://github.com/rashida048/Simple-Linear-Regression/blob/main/arm_leg.csv
这里有一个线性趋势。让我们看看是否可以使用数据开发一个线性回归方程,该方程可以使用臂长合理地预测腿长。
这里,
臂长是 x 变量
腿长是 y 变量
让我们看看上面的公式。如果我们想找到基于臂长的 y 的计算值,我们需要计算β0 和β1。
计算β1 所需的参数:相关系数,臂长标准差,腿长标准差。
计算β0 所需的参数:腿长的平均值β1 和臂长的平均值。
使用数据集可以非常容易地计算出所有参数。我用 R 来计算它们。你可以使用任何你觉得舒服的语言。
首先,将数据集读入 RStudio:
al = read.csv('arm_leg.csv')
我之前已经展示了整个数据集。它有两列:“胳膊”和“腿”,分别代表人的胳膊和腿的长度。
为了方便计算,我将把手臂的长度和腿的长度保存在单独的变量中:
arm = al$arm
leg = al$leg
以下是如何找到“臂”和“腿”列的平均值和标准偏差:
arm_bar = mean(arm)
leg_bar = mean(leg)s_arm = sd(arm)
s_leg = sd(leg)
r 还有一个“cor”函数来计算两列之间的相关性:
r = cor(arm, leg)
现在,我们有了计算β0 和β1 所需的所有信息。让我们使用之前描述的β0 和β1 的公式:
beta1 = r*s_leg/s_arm
beta0 = leg_bar - beta1*arm_bar
β1 和β0 分别为 0.9721 和 1.9877。
我想解释从头开始研究线性回归问题的过程。
否则,R 具有“lm”函数,您可以简单地向其传递两个变量,它输出斜率(β1)和截距(β0)。
m = lm(leg~arm)
输出:
Call:
lm(formula = leg ~ arm)Coefficients:
(Intercept) arm
1.9877 0.9721
插入斜率和截距的值,该数据集的线性回归方程为:
y = 1.9877 + 0.9721x
如果你知道一个人的手臂长度,你现在可以用这个等式估计他或她的腿的长度。例如,如果一个人的手臂长度为 40.1,那么这个人的腿的长度估计为:
y = 1.9877 + 0.9721*40.1
一共是 40.99。这样,你也可以得到其他不同手臂长度的人的腿的长度。
但请记住,这只是对那个人腿长的估计或计算值。
不过,有一点需要注意。当你用手臂的长度来计算腿的长度时,记住不要外推。这意味着要注意你在模型中使用的数据范围。例如,在这个模型中,我们使用的臂长在 31 到 44.1 厘米之间。不要计算 20 厘米手臂长度的腿长。那可能不会给你一个正确的估计。
用通俗易懂的语言解释斜率和估计值:
0.9721 的斜率代表手臂长度每改变一个单位,腿的长度平均会增加 0.9721 个单位。请把注意力集中在“平均”这个词上。
每一个手臂长度为 40.1 的人,可能都没有 40.99 的腿长。可能会有点不同。但我们的模型显示,平均而言,它是 40.99。如你所见,并非所有的点都在红线上。红色虚线是所有平均值的直线。
1.9877 的截距意味着,如果臂的长度为零,则腿的平均长度仍然是 1.9877。臂的长度为零是不可能的。所以,在这种情况下,它只是理论上的。但在其他情况下,这是可能的。例如,考虑学习时间与考试分数之间的线性关系。可能存在线性关系,即考试分数随着学习时间的增加而增加。但是即使一个学生根本没有学习,她/他仍然可以获得一些分数。
这个估计有多好?
这是个好问题,对吧?我们可以估计。但是这个估计和那个人腿的真实长度有多接近。
要解释这一点,我们需要先看看回归线。
使用“abline”函数,可以在 R 中绘制一条回归线:
plot(arm, leg, main="Arm Length vs Leg Length",
xlab="Length of Arms", ylab = "Length of Legs")
abline(m, lty = 8, col="red")

作者图片
看这张照片。原来的点(黑点)分散在周围。估计的点数将直接落在红色虚线上。在这种情况下,对于该数据集,估计的腿长度通常会与实际的腿长度不同。
因此,检查回归线与数据的吻合程度非常重要。
为了找到答案,我们需要真正理解 y 变量。对于任何给定的数据点,可能有三个 y 变量需要考虑。
- 有真实的或观察到的 y 变量(我们从数据集中获得。在这个例子中是腿的长度)。让我们把这些“y”数据中的每一个都称为“y_i”。
- 预测的 y 变量(我们可以通过线性回归方程计算的腿长。请记住,这可能不同于原始数据点 y_i)。在这个演示中,我们称它为“y_ihat”。
- y 变量的样本平均值。我们已经计算并保存在变量 y_bar 中。
为了评估回归模型与数据集的拟合程度,所有这些 y_i、y_ihat 和 y_bar 将非常重要。
y_ihat 和 y_bar 之间的距离称为回归分量。
回归分量= y_ihat — y_bar
原始 y 点 y_i 和计算出的 y 点 y_ihat 之间的距离称为残差分量。
剩余分量= y_i — y_ihat
经验法则是,与数据拟合良好的回归线的回归分量大于所有数据点的残差分量。相反,不适合数据的回归线的残差分量将大于所有数据点的回归分量。
有道理,对吧?如果观察到的数据点与计算出的数据点相差太大,则回归线拟合得不好。如果所有的数据点都落在回归线上,那么残差分量将为零或接近于零。
如果我们将回归分量和残差分量相加:
total =y _ ihat—y _ bar+y _ I—y _ ihat = y _ I—y _ bar
这个怎么量化?你可以简单地从观察到的 y 值(y_i)中减去平均值‘y’(y _ bar)。但这会给你一些正值和负值。而负值和正值会互相抵消。这意味着,这并不代表平均 y 值和观察到的 y 值的真正差异。
一种流行的量化方法是求平方和。这样的话,就不会有什么负面影响了。
总平方和或“总 SS”为:

回归平方和或“Reg SS”为:

残差平方和或“Res SS”为:

总 SS 也可以计算为“Reg SS”和“Res SS”的总和。
总 SS = Reg SS + Res SS
一切准备就绪!现在是计算 R 平方值的时候了。如前所述,R 平方是表示回归线与数据拟合程度的度量。以下是 R 平方的公式:
r 平方= Reg SS /总 SS
如果 R 平方值为 1,这意味着,响应变量(y 变量)的所有变化都可以用解释变量(x 变量)来解释。
相反,如果 R 平方值为 0,这意味着响应变量中的任何变化都不能用解释变量来解释。
方差分析表
这是评估模型与数据拟合程度的最流行方法之一。
下面是方差分析表的一般形式。您已经知道了表中使用的一些参数。我们将在餐桌后讨论其余的问题。

作者图片
此表中的关系和参数在回归分析中非常重要。这实际上有助于我们评估模型。我们已经学习了术语 Reg SS、Res SS 和 Total SS 以及如何计算它们。
上表中的 Reg df 是回归平方和的自由度。这等于除截距之外的估计参数的数量。在简单线性回归(SLR)中,它是 1。对于多元回归 k > 1。
Res df 是自由度的残差平方和。它的计算方法是数据点数(n)减去 k 减去 1 或(n-k-1)。我们之前提到过,对于单反来说 k 永远是 1。所以,单反的 Res df 是 n-2。
p 值是可以观察到的检验统计的观察值或更极端值的概率。
这里还需要提到一个术语。如果你在 R 中计算 R 的平方,就会得到两个 R 的平方值。我们之前已经讨论过一个 R 平方值和计算方法。但是还有一个。这是经过调整的 R 平方。公式如下:

这里,Sy 是 y 变量的标准差。它表示模型可以解释的 y 变量的方差的比例。
对于大 n (n =数据点的数量):

所有的表格和方程式都准备好了。我们来评估一下之前开发的模型!
计算 R 平方和方差分析表以评估模型和从中得出的推论
首先,生成一个包含所有参数的表:

作者图片
请随意从此链接下载 excel 文件,这样您就可以看到实现和公式:
https://github.com/rashida048/Simple-Linear-Regression/blob/main/ss_ms_total.xlsx
注意在表的末尾。我们使用公式计算了“总 SS ”,并将其作为“Reg SS”和“Res SS”的总和。两个“总 SS”几乎相同(490.395 和 490.372)。我们可以使用其中任何一个。从该表中:
总 SS = 490.372
Reg SS = 261.134
Res SS = 229.238
计算 R 平方和 R 平方调整值:
r 平方= Reg SS/Total SS = 261.134/490.372 = 0.5324
r 平方调整= 1–8.187/(s _ leg)* * 2 = 0.5159
正如所料,它们几乎是一样的。
这意味着腿长度的 51.59%的可变性可以由臂的长度来解释。
这个 R 平方值很好地估计了臂长和腿长之间的关系。
但是为了证实这两个变量之间有显著的线性关系,有必要进行假设检验。
如果你对假设检验完全陌生,你可能会想为什么我们需要确认它?我们已经开发了模型并计算了相关性。
但是我们只研究了 30 个样本,并在这 30 个样本上开发了模型。如果我们想从中推断出关于总人口的结论,我们需要假设检验。下面是一篇关于假设检验概念的详细文章:
在这个例子中,我们将使用我们之前描述的 ANOVA 表进行假设检验。
使用 ANOVA 表的假设检验示例
有两种不同的等价检验来评估这些假设:1) t 检验和 2) F 检验。
我选择用 f 检验来做。如果你已经知道如何进行 t 检验,那就继续吧。对我来说,f 检验和 t 检验的工作量是一样的。所以,哪一个都好。下面是如何进行 f 检验
F-test
这个 f 检验有五个步骤。这几乎是一个普遍规律。你将能够在许多其他问题中使用同样的过程。
第一步:
建立假设:我们在开始时建立了两个假设。零假设和替代假设。然后根据证据,我们拒绝或未能拒绝零假设。
零假设:
β1 = 0
从线性回归方程中记住,β1 是回归线的斜率。我们将零假设设为β1 = 0 意味着我们假设臂长和腿长之间没有线性关联。
替代假设:
beta1!= 0
另一种情况是β1 不等于零,这意味着臂长和腿长之间存在线性关联。
设置显著性水平α= 0.05。这意味着 95%的置信度。如果您需要重温置信区间的概念,请查看这篇文章:
第二步:
选择适当的测试统计。这里我们选择 F 统计量。
第三步:
定义决策规则。这意味着决定何时拒绝零假设。
由于这是一个 f 检验,我们需要从 f 分布中确定适当的值。您可以使用该表来确定 F 值。但是该表没有包括所有的 F 值。我更喜欢用 r,非常简单容易。r 有这个“qf”函数,它取置信水平和自由度。我们已经讨论了两种类型的自由度:“规则自由度”和“结果自由度”。
qf(0.95, df1 = 1, df2 = 28)
输出:
4.196
所以如果 F 大于或等于 4.196,拒绝零假设。否则,不要拒绝零假设。这是我们的决策规则。
第四步:
计算检验统计量。
有两种方法,我将在这里展示。首先,我将手动显示步骤。然后,我将简单地使用 r 的“anova”函数,我们已经知道了“Reg SS”、“Res SS”和自由度。这是方差分析表:

作者图片
请随意下载我做这些计算的原始 excel 文件:
https://github.com/rashida048/Simple-Linear-Regression/blob/main/anova table.xlsx
注意,我没有计算表中的 p 值。因为我想在这里展示计算。我将使用 R 从 F 统计量计算 p 值。
1-pf(31.896, 1, 28)
输出:
4.742e-06
您可以直接从 r 中的“anova”函数获得 anova 表。“ANOVA”函数采用线性回归模型。记得我们一开始得到了线性回归模型,并把它保存在变量‘m’里。请回去检查一下。我们将在“anova”函数中传递“m ”,以使用 R:
anova(m)
输出:
Analysis of Variance TableResponse: leg
Df Sum Sq Mean Sq F value Pr(>F)
arm 1 261.16 261.157 31.899 4.739e-06 ***
Residuals 28 229.24 8.187
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
仔细查看输出。ANOVA 表从 Df(自由度)、Sq 均值(之前计算表中的 SS(平方和))、Mean Sq (MS(均方))、F 值、p 值开始。如果你注意到这些值,它们几乎是一样的。
第五步:
得出结论。我们之前定义了决策规则,如果 F ≥ 4.196,我们将拒绝零假设。f 值为 31.899。所以我们可以拒绝零假设。这意味着我们有足够的证据表明,在α= 0.05 的水平上,臂长和腿长之间存在显著的线性关系。我们的 p 值也小于α。这提供了另一个证据,证明我们可以拒绝零假设。
结论
如果你能完成所有这些,恭喜你!那是许多工作。这是最简单的模型之一,但却很受欢迎。许多其他模型都是基于线性回归的。把这个学得很好,掌握基本概念很重要。假设检验也是统计学和数据分析中常见的日常任务。因此,本文涵盖了许多有用且广泛使用的材料。希望这对你有帮助。
欢迎在推特上关注我,喜欢我的 T2 脸书页面。
多元线性回归模型、评估和推理的详细指南

模型开发、解释、方差计算、f 检验和 t 检验
线性回归是仍然流行的老派统计建模方法之一。随着新语言和库的发展,它现在有了更好的版本,也更容易操作。
多元线性回归是简单线性回归的扩展。在简单线性回归中,我们研究一个自变量或解释变量和一个因变量或响应变量之间的关系。简单线性回归使用这个非常常见的通用公式:
y = mx + c
在哪里,
y =因变量或响应变量
x =独立变量或解释变量
m =斜率
c =截距
如果 x 和 y 共享一个线性关系,如果有可用的“x”数据,就可以预测“y”。
在统计学中,用β0 和β1 代替 c 和 m,因此,公式变为:

当你在利润和销售、手臂长度和腿长度、收缩压和舒张压等之间建立关系时,这个等式就足够好了。这意味着只有一个解释变量和一个响应变量。
但是在现实世界的场景中,我们经常想要分析一个响应变量和几个解释变量之间的关系。当响应变量是考试分数时,可能有几个解释变量,如学习时间、在学校的出勤率、游戏时间和睡眠时间。我们要分析所有可能的解释变量与响应变量(考试分数)之间的关系。
在这种情况下,线性回归方程变为:
方程式 1

如果我们想到前面提到的例子中的考试分数,y 就是考试分数。x1、x2 和 x3 是学习时间、上学时间、游戏时间。我们需要确定β0、β1、β2、β3 的值…..
在 r 中,计算 betas 值非常简单明了。让我们看一个例子。
模型开发、解释和评估
在本次演示中,我们将使用一个包含年龄、体重、体重指数(身体质量指数)和收缩压的数据集。我们将收缩压视为因变量,体重、身体质量指数和年龄视为自变量或解释变量。我将在开始时把年龄作为唯一的解释变量。然后逐个添加重量和身体质量指数,以了解它们中的每一个对模型和响应变量(收缩压)的影响。
如果您想练习,请随意下载数据集并跟随:
让我们先导入数据集。
data = read.csv("health_data.csv")
head(data)

因为我们将首先检查年龄和收缩压之间的关系,所以看到年龄和收缩压的散点图将是有趣的。这是散点图:
plot(data$Age, data$Systolic_blood_pressure,
main= "Systolic Blood Pressure vs Age",
xlab = "Age", ylab = "Systolic Blood Pressure")

呈线性趋势。虽然周围有很多噪音。在 R 中,我们可以使用' lm '函数直接找到线性回归模型。我将把这个模型保存在一个变量' m '中。
m = lm(data$Systolic_blood_pressure ~ data$Age)
m
输出:
Call:
lm(formula = data$Systolic_blood_pressure ~ data$Age)Coefficients:
(Intercept) data$Age
94.872 0.635
输出显示截距(β0)为 94.872,斜率为 0.635(β1)。我们认为 x1 是年龄。所以线性回归方程变成了:
y = 94.872+0.635 *年龄
因为我们只考虑了一个解释变量,没有 x2、x3 或β2、β3。
在这里,截距 94.872 意味着如果年龄为零或非常接近零,收缩压仍将为 94.872。在这个数据集中,数据集中的最小年龄是 18 岁(请自行检查)。所以,谈论零年龄远远超出了这个数据集的范围。这就是为什么在这种情况下不太合理。
0.635 的斜率意味着如果年龄增加 1 个单位,收缩压将平均增加 0.635 个单位。
如果你知道一个人的年龄,用这个方程你可以计算出他的收缩压。例如,如果一个人 32 岁,计算的收缩压将是:
y = 94.872 + 0.635*32 = 115.192
现在,这个估计有多正确,我们将在本文后面确定。是时候再添加一个变量了。
给模型添加权重:
这很简单。在“m”模型中,我们只考虑了一个解释变量“年龄”。这次我们将有两个解释变量:年龄和体重。这可以使用相同的“lm”函数来完成,我将把这个模型保存在变量“m1”中。
m1 = lm(data$Systolic_blood_pressure ~ data$Age + data$Weight)
m1
输出:
Call:
lm(formula = data$Systolic_blood_pressure ~ data$Age + data$Weight)Coefficients:
(Intercept) data$Age data$Weight
84.2799 0.6300 0.1386
这里截距(beta0)是 84.28。如果你注意到它不同于“m”(94.87)中的截距。年龄变量的时间斜率(β1)变为 0.63,与模型“m”中的β1 差别不大。这个斜率意味着当体重变量被控制或固定时,如果年龄增加 1 个单位,收缩压将平均增加 0.63 个单位。
另一方面,体重变量(β2)的斜率为 0.1386 意味着如果体重增加 1 个单位,当年龄变量被控制或固定时,收缩压将平均增加 0.1386 个单位。
线性回归方程变为:
y = 84.2799 + 0.63*年龄+ 0.1386 *体重
如果你知道一个人的年龄和体重,你就可以用这个公式来估计这个人的收缩压。
将身体质量指数加入本款
最后,我们把身体质量指数加入这个模型,看看身体质量指数是否改变了这个模型的动态。让我们再次使用“lm”函数,并将此模型保存在名为“m2”的变量中。
m2 = lm(data$Systolic_blood_pressure ~ data$Age + data$Weight+data$BMI)
m2
输出:
Call:
lm(formula = data$Systolic_blood_pressure ~ data$Age + data$Weight +
data$BMI)Coefficients:
(Intercept) data$Age data$Weight data$BMI
89.5218 0.6480 0.3209 -0.7244
请仔细注意输出。截距又变了。这次是 89.52。年龄的斜率现在是 0.648。上一款是 0.63。重量的斜率是 0.3209,而在以前的模型中是 0.1386。因此,在模型中加入身体质量指数后,β0、β1 和β2 的值发生了相当大的变化。身体质量指数变量的斜率是-0.7244。
线性回归方程变为:
y = 89.5218+0.648 *年龄+0.3209 *体重-0.7244 *身体质量指数
呜!我们的多元线性回归模型准备好了!现在,如果我们知道一个人的年龄、体重和身体质量指数,我们将能够计算出这个人的收缩压!
从这个方程计算出的收缩压有多精确?
让我们找出答案。在多元线性回归中,评估数据拟合度的一种非常常见和流行的方法是变异系数(R 平方)。R 平方的公式与简单线性回归相同:

这里,
y_calc 是响应变量的计算值。在这种情况下,使用线性回归模型计算的收缩压值
y_mean 是原始收缩压值的平均值
y 是来自数据集的原始收缩压
R 平方值表示可由解释变量解释的响应变量的比例。
我会用 R 来计算 R 的平方。在 r 中非常简单,我们有三个模型,我们把它们保存在三个不同的变量 m,m1,和 m2 中。看到每个模型的适合度会很好。我将计算所有三个模型的 R 平方值。这是第一个模型“m”的 R 平方值,其中解释变量仅为“年龄”。
R_squared1 = sum((fitted(m) - mean(data$Systolic_blood_pressure))**2) / sum((data$Systolic_blood_pressure - mean(data$Systolic_blood_pressure))**2)
R_squared1
输出:
0.3795497
这意味着 37.95%的收缩压可以由年龄来解释。
第二个模型“m1”的 R 平方值,其中解释变量为“年龄”和“体重”:
R_squared2 = sum((fitted(m1) - mean(data$Systolic_blood_pressure))**2) / sum((data$Systolic_blood_pressure - mean(data$Systolic_blood_pressure))**2)
R_squared2
输出:
0.3958562
39.58%的收缩压可以由“年龄”和“体重”共同解释。在给模型增加权重后,看起来 R 平方有所改善。
最后,模型 m2 的 R 平方值,其中解释变量为“年龄”、“体重”和“身体质量指数”。
R_squared3 = sum((fitted(m2) - mean(data$Systolic_blood_pressure))**2) / sum((data$Systolic_blood_pressure - mean(data$Systolic_blood_pressure))**2)
R_squared3
输出:
0.4099555
40.99%的收缩压可以用“年龄”、“体重”和“身体质量指数”来解释。
如果你不熟悉置信区间或假设检验的概念,接下来的步骤对你来说可能有点难以完全理解。下面是一篇学习置信区间概念的文章:
这是一篇关于假设检验的文章。请检查:
推论
在本节中,我们将进行 f 检验,以确定模型是否显著。这意味着如果至少有一个解释变量与响应变量有线性关系。
执行假设检验有五个步骤:
第一步:
设置假设并选择 alpha 级别:
我们设置了一个零假设和一个替代假设。零假设是所有变量的斜率为零。这意味着任何变量和响应变量之间都没有关联。这是无效假设:

如果我们没有找到足够的证据证明零假设是真的,那么我们将拒绝零假设。这将为我们提供证据,至少有一个斜率不等于零。这意味着至少有一个解释变量与响应变量有线性关系。这是另一个假设:

我将阿尔法值设置为 0.05。这意味着置信度为 95%。
第二步:
选择适当的测试统计。这里我们将使用 f 检验。测试统计数据为:

这里,df 是自由度。这就是解释变量的数量。在本例中是 3(年龄、体重和身体质量指数)。
n 是行数或数据点的数量。在这个数据集中,有 100 行。所以,n = 100。请使用“nrows(数据)”功能随意检查
我们稍后会讨论如何计算 F-stat。
第三步:
陈述决策规则:
我们需要从 df = 3,n-k-1 = 100–3-1 = 96,α= 0.05 的 F 分布中确定适当的值。
有两种方法可以找到合适的值。可以用 f 分布表。但我更喜欢用 R,这是用 R 计算的 F 分布的值:
qf(0.95, 3, 96)
输出:
[1] 2.699393
f 分布的合适值是 2.699。
决策规则是:
如果 F ≥ 2.699,拒绝零假设
否则,不要拒绝零假设。
第四步:
计算 F 统计量。
这是计算 F 统计量的表格。

在上表中,
Reg SS 是可以用此公式计算的回归平方和

Res SS 是残差平方和,下面是计算它的表达式:

总 SS 也可以计算为“Reg SS”和“Res SS”的总和。下面的表达式也将给出与 Reg SS 和 Res SS 之和相同的结果。

Reg df 或回归自由度是解释变量的数量。在这个例子中是 3。
n 是数据的行数。
我将使用 R 来计算 Reg SS、Res SS 和 n:
regSS = sum((fitted(m2) - mean(data$Systolic_blood_pressure))**2)
resSS = sum((data$Systolic_blood_pressure - mean(data$Systolic_blood_pressure))**2)
输出:
[1] 16050.88
[1] 39091.84
查找数据中的行数:
nrow(data)
输出:
[1] 100
现在可以计算表中的其余元素了。我使用 excel 表格来生成表格。虽然在 r 中可以找到所有的东西,但是为了做成表格,我用了 excel。结果如下:

F 统计值为 13.139。
请随意在此下载该 excel 文件:
第五步:
结论: F 为 13.139,大于 2.699。所以,我们有足够的证据来拒绝零假设。这意味着至少有一个解释变量与响应变量有线性关系。所以,这个模型意义重大。
通过 f 检验,我们知道这个模型是有意义的。这意味着至少有一个解释变量与响应变量有线性关系。这将有助于准确了解哪些变量与反应变量(收缩压)具有线性关联。
我们将对此进行 t 检验。
对个别解释变量进行 t 检验
上述 f 检验表明该模型是显著的。现在,我们可以测试每个解释变量是否有线性关联。正如我们之前已经陈述过五步法则。我不会在这里一一讲述。
第一步:假设和 alpha 与上面的 f 检验完全相同。
第二步:
在步骤 2 中,检验统计量将是自由度为 n -k-1 的 t 统计量。我们将在后面的步骤 4 中使用 R 来寻找 t 统计量。
第三步:
在第三步中,我们需要从 t 分布中找到合适的值。有一个“t 分布”表来找出适当的值。我更喜欢用 r。
qt(0.975, 96)
输出:
[1] 1.984984
如果任何解释变量的 t 统计量大于或等于 1.985,则拒绝零假设。
否则,不要拒绝零假设。
第四步:
计算测试统计数据:
这就是 t 检验如此简单的原因。如果你对 R 中的线性回归模型进行总结,得到 t 统计量和 p 值。我将对模型“m2”进行总结,因为我们在该模型中包含了所有三个解释变量。
summary(m2)
输出:
Call:
lm(formula = data$Systolic_blood_pressure ~ data$Age + data$Weight +
data$BMI)Residuals:
Min 1Q Median 3Q Max
-33.218 -10.572 -0.187 8.171 47.071Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 90.14758 8.34933 10.797 < 2e-16 ***
data$Age 0.64315 0.08109 7.931 3.97e-12 ***
data$Weight 0.32226 0.14753 2.184 0.0314 *
data$BMI -0.73980 0.47751 -1.549 0.1246
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1Residual standard error: 15.49 on 96 degrees of freedom
Multiple R-squared: 0.4106, Adjusted R-squared: 0.3922
F-statistic: 22.29 on 3 and 96 DF, p-value: 4.89e-11
仔细查看输出。这里有每个解释变量的 t 统计量。以及它们各自的 p 值。
第五步:
以下是测试得出的结论:
根据我们的决策规则,如果 t 统计量大于或等于 1.985,我们应该拒绝零假设。你可以看到年龄和体重变量的 t 统计量大于 1.985。所以,我们可以拒绝两者的零假设。下面就一个一个说吧。
根据 t 检验,当控制体重和身体质量指数时,年龄变量是显著的,并且与收缩压呈线性相关。
同样,当年龄和身体质量指数得到控制时,体重变量也是显著的,并与收缩压呈线性相关。
另一方面,身体质量指数变量的 t 统计量为-1.549,小于 1.985。所以,我们没有足够的证据来拒绝身体质量指数变量的零假设。这意味着当年龄和体重得到控制时,身体质量指数变量与收缩压没有线性关系。
也可以用 p 值得出结论。如果 p 值大于或等于α水平(在本例中为 0.05),我们就有足够的证据来拒绝零假设。如果您在上面的摘要输出中注意到,对于年龄和体重变量,p 值小于 alpha 级别 0.05。因此,这样我们也可以得出结论,年龄和体重变量与收缩压有线性关系。另一方面,身体质量指数的 p 值大于 0.05。使用 p 值也可以确定身体质量指数变量与收缩压没有线性关系。
如果你读了我关于简单线性回归的文章,你可能会奇怪为什么我在这里没有使用方差分析进行推断。在多元线性回归中使用方差分析不是一个好主意。因为如果你把响应变量按不同的顺序排列,会得到不同的结果。变得非常混乱。尝试在 R 中对“年龄”、“体重”和“身体质量指数”使用一次“anova()”函数。和体重,年龄,身体质量指数一次。你可能会得到一个不同的方差分析表。
结论
我希望这有所帮助。这是本文涵盖的大量材料。如果所有这些材料对你来说都是全新的,你可能需要一些时间来真正掌握所有这些想法。这些不是唯一的测试。统计学中还有其他几个测试。这些只是一些常见和流行的假设检验。我建议,拿一个你自己的数据集,试着开发一个线性回归模型,并像本文一样进行假设检验。如果你读这个是为了学习,那是学习的唯一途径。
欢迎在推特上关注我,喜欢我的 T2 脸书页面。
用贝叶斯推理和 PyMC3 检测变化点
用观察到的数据更新你的信念
动机
想象一下,你使用谷歌分析来跟踪你的网站的浏览量。查看视图后,您怀疑某个日期后视图数量可能会突然变化。
如果确实存在一个浏览量突然变化的日期,如何找到那个日期?
如果你能利用观察到的数据和一些信念来高度确定地猜测变化点,那不是很好吗?

作者图片
这就是贝叶斯推理派上用场的时候。在本文中,我们将学习什么是贝叶斯推理,以及如何使用 PyMC3 来执行贝叶斯分析。
什么是贝叶斯推理?
贝叶斯推理是一种技术,其中贝叶斯定理用于指定一个人应该如何根据观察数据更新自己的信念。
例如,我们先前的信念可以是硬币是有偏差的,它遵循 Beta(1.36,2.36)分布。然而,在投掷硬币超过 100 次(观察真实数据)后,我们的信念转变为均值为 0.5 的正态分布。

作者 GIF 使用视觉理论创建
我们可以看到,收集更多数据后,后验分布可能与先验分布有很大不同。
探索数据
我们将使用显示从 2021 年 1 月到 2021 年 7 月从我的网站数据科学简化版收集的浏览量的数据。
现在,我们如何找到视图数量分布发生变化的日期?
让我们从寻找时间τ和视图数量的先验分布开始。
先验分布
视图数量的先验分布
由于视图的数量是计数数据,因此可以使用离散分布(如泊松分布)对其建模。
泊松分布显示了一个事件在固定的时间间隔内可能发生的次数。泊松分布使用参数 λ 来控制其形状。

作者图片
让我们画一个泊松分布来看看它是什么样子的。
λ = 1.5 的泊松分布:

作者图片
当增加 λ 时,我们给更大的值增加更多的概率。例如,将 λ 的值从 1.5 增加到 3 会将分布的平均值向右移动:

作者图片
从上面的图中,我们可以看到视图的平均数量接近于 λ。

作者图片
酷!现在我们知道了如何对视图数量的先验分布进行建模,我们如何找到一个合适的 λ ?
λ 的先验分布
我们不知道 λ,的具体值,但是我们知道存在一个时间𝜏,在该时间之后,视图数量的分布发生显著变化。因此,我们可以说, λ = 𝜆₁在时间𝜏之前,而 λ = 𝜆₂在时间𝜏.之后

作者图片

作者图片
但是,我们如何对𝜆₁和𝜆₂的先验分布建模呢?由于𝜆₁和𝜆₂是连续随机变量,我们可以用指数分布来模拟他们的先验分布。
指数分布通常用于模拟事件之间经过的时间。指数分布也使用一个参数,比如𝛼,来控制它的形状。

作者图片
给定一个特定的𝛼,𝜆的期望值等于𝛼.的倒数

作者图片
让我们看看指数分布是什么样的。
𝛼 = 0.1 的指数分布:

作者图片
𝛼 = 1 的指数分布:

作者图片
现在,𝛼的价值是什么?我们可以把前面找到的两个方程结合起来估算𝛼.的值

作者图片
根据上面的等式,将𝛼设置为等于视图数量的反均值是合理的。

作者图片
时间的先验分布
因为所有日期都同样可能是𝜏,所以我们可以使用均匀分布来模拟𝜏.的先验分布
由于总共有 182 天,我们可以写:

作者图片
这意味着𝜏的概率等于𝑘的日期:

作者图片
让我们想象一下这种均匀分布的样子:

作者图片
从上面的图中我们可以看出,所有日期都同样可能是𝜏.
使用 PyMC3 的贝叶斯分析
接下来,我们将使用 PyMC3 执行贝叶斯分析。PyMC3 是一个 Python 包,使用直观的语法进行贝叶斯统计建模。
要安装 PyMC3,请键入:
pip install pymc3
模型变量
首先为𝜆₁、𝜆₂和𝜏.创建 PyMC3 变量
接下来,我们使用pm.math.switch给𝜆.赋值𝑡的日期代表𝜆的日期。如果𝑡比𝜏小,它会将𝜆₁的值赋给𝜆.否则,它会将𝜆₂的价值分配给𝜆。


作者图片
接下来,我们使用 Poisson(𝜆分布对视图数量进行建模:
注意,到目前为止,我们只模拟了𝜆₁、𝜆₂和𝜏.的先验分布为了从𝜆₁、𝜆₂和𝜏的后验分布中获得一些样本,我们将使用马尔可夫链蒙特卡罗(MCMC)。
使用 MCMC 获取后验分布的样本
MCMC 是一种随机抽样概率分布的方法,它尊重样本之间的概率相关性。
基于 C am Davidson-Pilon ,一般来说,执行 MCMC 的算法有:
1.从当前位置开始。
2.提议换一个新的职位。
3.基于职位对数据和先前分配的坚持,接受/拒绝新职位。
4.如果你接受:转到新的职位。返回步骤 1。
否则:不要跳槽。返回步骤 1。
5.经过大量迭代后,返回所有接受的位置。
下面的 GIF 展示了 Metropolis-Hastings 的搜索策略,一种 MCMC 方法。

作者 GIF—来源
让我们使用 MCMC 从𝜆₁、𝜆₂和𝜏.的后验分布中获得数千个随机变量
接下来,想象一下这些随机变量的样子:

作者图片
从上面的图中,我们可以看出:
- 𝜆₁的后验分布和𝜆₂.的后验分布之间存在显著差异这表明确实存在一个日期𝜏,在该日期之后,观看次数的分布发生变化。
- 𝜏 = 91 的概率是 99.99%。这说明变化点有非常高的几率是 91。
查找预期的视图数量
现在我们有𝜆₁、𝜆₂和𝜏的 40k 个样本,让我们得到每天的预期浏览量。
计算𝑡:日期的预期浏览量的步骤
- 选择一个日期𝑡
- 对于每个𝜏样本,查看𝑡的日期是在𝜏.的日期之前还是之后
- 如果𝑡在𝜏之前,𝜆的价值就是𝜆₁.如果𝑡在𝜏之后,𝜆的价值就是𝜆₂.
- 取𝑡日期𝜆所有值的平均值
例如,如果只有𝜆₁、𝜆₂和𝜏的 3 个样本,我们的计算将类似于以下内容:

作者图片
使用上面的计算方法来计算每天的预期浏览量:
绘制每天的预期浏览量:
相当酷!我们可以看到,在第 91 天之后,预期的视图数量发生了变化。这与我们从真实数据中看到的相符。
结论
在结束本文之前,我们应该花点时间来欣赏一下贝叶斯推理是多么强大。我们仅使用观察到的数据和一些初始信念就能如此确定地得到变化点。
另外,我们得到了数据在变化点前后的分布。这些分布比单一值能告诉我们更多。

作者图片
希望这篇文章能给你使用贝叶斯推断和 PyMC3 分析身边其他有趣数据的知识和动力。
随意发挥,并在这里叉这篇文章的源代码:
我喜欢写一些基本的数据科学概念,并尝试不同的数据科学工具。你可以在 LinkedIn 和 T2 Twitter 上与我联系。
星这个回购如果你想检查我写的所有文章的代码。在 Medium 上关注我,了解我的最新数据科学文章,例如:
参考
j . brown lee(2019 年 9 月 24 日)。关于概率的马尔可夫链蒙特卡罗的温和介绍。机器学习精通。检索于 2021 年 12 月 10 日,来自https://machine learning mastery . com/Markov-chain-Monte-Carlo-for-probability/。
c .戴维森-皮隆(2016 年)。黑客的贝叶斯方法:概率编程和贝叶斯推理。艾迪森-韦斯利。
检测财务数据中的欺诈和异常情况
如何在内部审计、财务和会计或控制等领域进行数据分析

帕特里克·亨德利在 Unsplash 上的照片
像 SAP 这样的软件处理公司的所有业务流程,如记账、控制、销售等。它还托管大量数据,尤其是财务数据,这些数据可能会带来重要的见解,需要由商业智能、会计或内部审计等部门进行控制。下面对常见检查的概述应该提供了一个实用的分析用例列表。在本文中,以 SAP FiCo 为例进行了说明,但是其他系统也有类似的情况。
可疑的变化
在 CDHDR 和 CDPOS 表的帮助下,您可以分析表中的变化,还可以识别可疑的过程,如订单中的不同值,该值从 20.000 €变为 19.999 €,刚好低于现有的限制。您需要的是对提到的表的访问(至少是读取),对这些表如何工作的理解和一些 SQL。
示例:SQL 结果—值的变化:
UDATE |CHANGENR |VALUE_NEW |VALUE_OLD 01/01/2020 |1234 |20.000 |
02/03/2020 |1234 |19.999 |20.000
另一个例子是查看客户的信用额度的变化频率[1]。某个订单之前的许多更改或更新也值得一看。
示例:SQL 结果—计数变化:
OBJECTCLAS |OBJECTID |FNAME |Count_Changes KLIM |543 |KLIMK |6
检查重复项
为了监控主数据的质量,同时防止不正确的预订甚至欺诈,检查重复数据总是一个好主意—一个著名的例子是 SAP 数据中的客户数据。对于像这样的更深入的分析,您可能需要 SQL 之外的其他方法,并且您可能更喜欢 python 笔记本。
示例:使用 Python 进行字符串相似性检查[2]:
import distance
distance.levenshtein("customer_abc", "customer_abcd")
双重支付
重复支付意味着赔钱,因此你可以检查 BSEG 表中的财务记录是否有重复。以下 SQL 连接 BSEG 的 BSEG,以标识具有相同公司代码、金额等的记录。但是具有不同文档编号。
示例:SQL 检查重复项[3]:
SELECT B1.MANDT,B1.BUKRS,B1.GJAHR,B1.BELNR BELNR1,B1.BUZEI BUZEI1,B2.BELNR BELNR2,B2.BUZEI BUZEI2,B1.DMBTR FROM BSEG BSEG_1 JOIN BSEG BSEG_2 ON (BSEG_1.MANDT=BSEG_2.MANDT AND BSEG_1.BUKRS=BSEG_2.BUKRS AND BSEG_1.DMBTR=BSEG_2.DMBTR AND BSEG_1.SHKZG=BSEG_2.SHKZG) WHERE B1.BELNR!=B2.BELNR
周末和节假日交易
由于权责发生制会计(年度账目、流转税的提前返还等),在不寻常的日期过账可能会有风险。)或者诈骗。要获得带有创建日期或更改日期的记录,您可能需要来自 getfestivo [4]之类的开放 API 的假日日期。
不寻常的预订文本
要确定不应该存在的费用,您可以在 BKPF 表中使用以下内容搜索不寻常的预订文本:
SQL 文本搜索示例:
... FROM BKPF
WHERE UPPER(BKTXT) LIKE = “Cancellation”
OR UPPER(BKTXT)= “Credit note”
UPPER(BKTXT)= “fee”
UPPER(BKTXT)= “Switzerland”
.....
结论
这些只是 SAP 系统中少数可能的分析问题,但由于我们讨论的是财务数据,这是一个重要的话题,您和您的公司应该意识到这些问题,并渴望培养分析能力。在本文中,示例与 SAP 相关,但是其他具有财务模块的 ERP 系统(如 Oracle 或 DATEV)也将以相同的方式工作,并且案例也是相似的。如何将 SAP 与强大的谷歌云分析平台(BigQuery、Data Studio 或 recently looker 等数据分析工具的提供商)相结合,以获得强大的数据分析平台和宝贵的见解。如果您对 SAP 数据的实用数据分析方法感兴趣,这篇文章可能也会让您感兴趣。
进一步的资料和阅读
[1]石,董,(2015)使用 CAATs 对 SAP 进行审计。
[2]pypi.org,【https://pypi.org/project/Distance/】T4(2021)
[3]DAB-GmbH,https://www . da b-Europe . com/file admin/public data/Downloads/2016 _ 04 _ DAB _ Gesamtkatalog _ es . pdf(2016)
[4]费斯蒂沃,https://getfestivo.com/documentation(2021)
用 Python 检测和测量不公正的选区划分
变更数据
快速介绍偏角以及它如何成为检测不公正选区划分的有力工具
我解决的每一个问题都变成了一条规则,以后用来解决其他问题。—勒内·笛卡尔

如果你读过最近的新闻,你可能会意识到各州正在重新划分选区,这是一个十年一次的过程,政治边界被重新划分以反映人口变化。如果你是经验主义者,你可能会合理地问是否有一些量化的方法来描述伤害的程度。在一个计划的偏差成为一个法律问题的地方,有没有一条数学界线?
在本帖中,我们将讨论一种叫做倾角的工具,它可以帮助我们解决这些问题。这是一个在天文学和物理学中广泛使用的几何概念,最近由佛蒙特大学的 Greg Warrington 教授作为一个启发引入。有一些实证方法探索这类事情,但我相信这在投票稀释的情况下是特别有趣的启发。它优雅、直观、方便。
但是在我们进入数学之前,让我们快速讨论一下定律。最终,我们这里的权威是 1965 年的选举权法案——除了别的以外,它禁止选票稀释。

曼尼·韦塞拉在 Unsplash 上的照片
选票稀释是有意削弱少数群体影响选举的权力。它有两种形式:包装或裂解。这两种策略都有效地将执政党与竞争隔离开来,并阻止了边缘社区的有意义的代表性。
这些计划听起来像做的那样。打包意味着将尽可能多的少数民族打包到一个选区中——通常达到该群体占总投票人口的 60%或更多。这个想法是,虽然该地区变得有利于少数群体,但更广泛的计划通过防止边界附近的社区受到邻近地区不受欢迎的影响而有利于大多数人。由国会议员詹姆斯·克莱伯恩代表的南卡罗来纳州第六国会选区是包装黑人选民的一个例子。
破解颠倒了思路。在地图上搜索临界数量的少数民族,而不是将群体集中到一个地区,会使他们分裂——将一个原本有凝聚力的社区分成几个地区。没有一个地区的规模大到足以具有竞争力。伯明翰和奥斯汀是他们各自国会地图破裂的例子。
偏角量化了这些现象。沿着 x 轴绘制计划的地区,我们能够查看每个地区的民主党投票百分比。自然,一些地区人口很少,而另一些地区人口很多。当你从左向右移动时,随着人口的增加,人们会认为会有一个拐点。在这一点上,我们发现一个向上的断裂角,因为选区从执政党控制变为反对党控制。该角度跟踪人口统计百分比;由于种族和党派关系之间的高度相关性(这种相关性使得计算成为可能),它会断开。
然而,休息的度是我们发现洞察力的地方。沃林顿博士研究了全国各地受 VRA 挑战的地区,发现角度的严重程度与选区划分的严重程度直接相关。随着包装变得更加明显,倾斜角增加。

由戴夫重划选区应用程序制作。【https://davesredistricting.org/maps#home
本周,我的家乡德克萨斯州被司法部以种族不公正划分选区为由起诉。我们可以看到上面美国众议院计划的倾斜角为 22.05%。该角度是在靠近 X 轴中间的倒数第二个共和党选区之后创建的。
该情节的一个启示性特征是红色共和党选区如何与民主党投票份额在 30%左右持平;曲线很快到达那个点,然后变平,并尽可能长时间保持在那个位置。这表明了地图设计的意图。
回到包装和裂解,包装区在 x 轴最右边。一般来说,一个选区多数席位的上限是 60%左右;这不是一个硬性规定,但当你进入 70 年代的游戏时,它就开始引人注目了。将近一半的民主党席位超过了这个门槛。
最后,我们如何将这种方法应用到我们遇到的地图上?有几个很棒的应用程序无需代码就能帮你做到这一点。我用戴夫的选区重划应用程序制作了上面的图,这是一个很棒的资源。竞选法律中心通过其 appplan score提供偏差计算。两个都免费!
import numpy as np
import mathdef calculate_declination_angle(dem_vote_share):
majority_wins = sorted(filter(lambda x: x <= 0.5, dem_vote_share))
minority_wins = sorted(filter(lambda x: x > 0.5,
dem_vote_share))
theta = np.arctan((1 - 2 * np.mean(majority_wins)) * len(dem_vote_share) / len(majority_wins))
gamma = np.arctan((2 * np.mean(minority_wins)-1) * len(dem_vote_share) / len(minority_wins))
declination_angle = 2 * (gamma - theta) / np.pi
return declination_angle
如果您正在操作 shapefiles,或者使用代码分析地图,也可以使用上面代码片段中的 Python 函数。只需将每个选区的民主党投票份额列表(在一次或一组选举中)作为浮点值传递给它。它将计算结果作为标量值返回。正如我所分享的,这是一个快速简单的计算,您可以将其集成到您的工作流程中。
我们应该将此理解为一种诊断工具,而不是责任的明确证明。正确的分析应该包含更丰富的数据集,当然,还需要一位经验丰富的投票权律师的指导。俗话说,所有的模型都是错的,但有些是有用的。
我希望这是教育。我也希望这是鼓舞人心的。我们生活在一个拥有更好工具的时代;我们应该利用他们来要求更好的代表性。
检测和处理 Python 中的异常值—第 3 部分
处理异常值的实践指南——winsoring 和插补

图片由 RF 提供。_.来自像素的工作室
在从事数据科学项目时,探索性数据分析(EDA)至关重要。了解您的底层数据、其性质和结构可以简化对特性、算法或超参数的决策。EDA 的一个关键部分是异常值的检测和处理。异常值是在总体的随机样本中严重偏离其他数据点的观察值。
在之前发表的两篇文章中,我讨论了如何使用众所周知的统计方法检测不同类型的异常值。一篇文章关注的是单变量,另一篇文章关注的是多变量异常值。
在这最后一篇帖子里,我想讨论一下一旦检测到极端值该如何对待。在理论介绍之后,我将提供两个用 python 编写的实际例子。为此,我将像在我以前的帖子中一样使用波士顿住房数据集。
处理异常值:一项主观任务
类似于根本不检测异常值,处理异常值可能会承担对分析或机器学习模型的结果产生重大影响的风险。在实践中,如何处理异常观测值往往不是很明显。
好消息是:从数学的角度来看,对于如何看待外围观测值,没有正确和错误的答案。除了数学之外,一个更重要的角色可以赋予你在离群值决策过程中可用的定性信息。例如,知道一个异常值最初是如何产生的,对极值决策是有益的。
因此,在深入探讨异常值处理的可用选项之前,我想强调异常值的可能来源。
异常值的来源
除了单变量和多变量之间的区别之外,极值可以通过来源来区分。误差异常值是由不准确的测量、错误的数据输入或数据处理导致的异常观察值。在这种情况下,这些数据点通常不是感兴趣人群的一部分。
另一方面,非误差异常值,也称为有趣的或随机异常值,是感兴趣群体的一部分,可能包含有趣的信息。
处理误差异常值
错误异常值应该被移除或校正。最简单的方法是删除通过不准确的测量或数据处理出现的观察值。假设有一个原始版本的底层数据可用。在这种情况下,值得追溯数据点的原始条目,以避免由于删除而造成的大量信息丢失。
但是,如果您手头没有原始数据版本,但您确定您看到的是一个异常错误(例如,一个人的身高测量值为 4 米/200 英寸或一个维度的第四类,尽管您知道应该只有三个变量类),您的最佳选择是简单地删除这些条目。
处理非错误异常值
关于如何处理非错误异常值,有三种不同的选择:
- 保持
- 删除
- 重新编码
保持
当大多数检测到的异常值是非错误异常值,并且理所当然地属于感兴趣的总体时,这是一个好策略。此外,您通常很难确定某个极值是否是感兴趣总体的一部分。
当保留异常值时,要意识到它们会扭曲你实际任务的结果:例如,导致拒绝零假设或过于乐观的预测。因此,报告您的发现可能是值得的,包括异常值和排除异常值,以突出它们可能产生的影响。
另一个选择是用于实际预测任务或分析的健壮方法。这些方法使用更稳健的统计(例如中值)或其他非参数设置(例如秩检验、自举或支持向量机)来减少极值的影响。
对于单变量和多变量异常值:
- 通过在分析中包含和排除异常值来收集定性信息,以评估它们的实际影响
- 使用稳健的方法来减少异常值的影响
- 如果离群值可能属于感兴趣的人群,则保留离群值,并在做出决策时注意它们带来的风险
- 而且永远也是最重要的:报告所有发现!
删除
最直接的选择是删除任何无关的观察。然而,这种策略具有丢失信息的高风险。尤其是如果你发现很多外围数据点,尽量避免这种情况。此外,删除感兴趣和有影响的异常值(属于感兴趣总体的点)可能会错误地影响任何输出,例如,您想要实现的预测或测试结果。
对于单变量和多变量异常值:
- 移除低尺度上的异常值和那些不太可能来自另一个群体的异常值
- 如果你选择删除,总是提供两份你的分析或结果的报告:一份有,一份没有异常观察
重新编码
重新编码离群值是处理离群值并同时保留尽可能多的信息的好选择。这种选择应该总是伴随着合理的推理和解释。有几种不同的方法来记录异常值,在本文中,我想重点介绍两种广泛使用的方法:
- Winsorizing
- 归罪
Winsorizing
Winsorizing 由 Tukey & McLaughlin 于 1963 提出,并经常在处理异常值处理的研究论文(如 2013 或 2019 )中推荐。使用 winsorizing,在变量分布的每一侧,高于或低于百分位 k 的任何变量值都将被第 k- 百分位本身的值替换。例如,如果 k =5,则高于第 95 个百分位数的所有观察值被重新编码为第 95 个百分位数的值,低于第 5 个百分位数的值被重新编码。与修剪相比,winsorizing 是一个不太极端的选择,它通过重新编码离群值而不是完全删除它们。

左:原始数据的值。右:k=5 的重新编码值-所有高于第 95 百分位的值都替换为第 95 百分位的值(此处为 2.5)。图片由作者提供。
Winsorization 还直接干预离群值检测过程。处理高于或低于某个阈值的数据点,不需要独立的检测方法。然而,它与 Tukey 的箱线图方法密切相关,因为通常建议将 k 设置在样本的外部围栏(平均值周围的 3 个标准偏差)。这通常在 k=5 时,因此用作默认值。
让我们看一个来自之前使用的波士顿住房数据集的例子。对于城镇的人均犯罪率,我们发现了 30 个可能的异常值(使用 Tukey 方法)。首先,我将重用第一篇教程中的一些代码来确定外部栅栏。
变量“CRIM”的上部外栅栏约为 14.46,而下端为零下。因为零以下的犯罪率是没有意义的,数据应该只在它的右边T21【winsorized】。现在,我们可以查看不同百分点的值来设置 k 。**
看起来 92.5% (13.54)和 95% (15.79)处的值最接近上外部围栏。由于 95%更常见,我将使用 scipy 中的 winsorize 函数对 k=5 上的数据进行 winsorize:
随着 winsorizing,人均平均犯罪率从 3.61 变为 2.80 (95%)。
对于单变量异常值:
- Winsorize 保留尽可能多的数据
- 要找到合适的 winsorization 级别,了解你的数据!接近外围栏的一个百分点被认为是最佳做法
- **如果变量的值不能低于零,零限值可能有意义
- 在 winsorizing 前后报告主要统计数据(例如,平均值、标准差)
为多元异常值:
- 对于多元异常值,winsorizing 是在椭球上完成的(保存来自多个变量的信息)
- 似乎没有现有的 python 包处理椭球上的 winsorization。然而,作为 R 包 sdcMicro 的一部分,存在一个名为 mvTopCoding 的函数,该函数能够消除由(稳健的)Mahalanobis 距离定义的椭球上的异常值。
归罪
插补是处理缺失数据时经常使用的一种方法。但是,在处理极值时也适用。当使用插补时,异常值被移除(并成为缺失值)并替换为基于剩余数据的估计值。
有几种插补技术。一种经常使用的,但带有强烈偏见的方法是简单均值替换法。这里,所有异常值或缺失值都被变量的平均值所替代。另一种更好、更可靠的插补方法是多重插补。
在多重插补中,缺失值或异常值由从预测模型中检索的 M 个似是而非的估计值替代。离群值成为预测模型(例如回归、随机森林等)的因变量。),并且基于观察中的剩余信息非缺失/非异常值来估计。

第一行:变量 1-变量 4(红色)帮助预测变量 5(黄色)的 M 个可能值。图片作者。
为缺失值或异常值选择正确数量的可信估计值 M 在文献中经常讨论,并且经常推荐M:
在中等缺失情况下,使用 m = 5-20 就足够了[…]
实际上,python 中的多重插补不像 R 中那样简单(例如,mice、missForest 等)。然而, sklearn 库有一个可用于多重插补的迭代插补器。它基于 R 包 小鼠 ,目前仍处于实验阶段。
Sklearns 的默认版本非常基本,使用均值替换,但可以通过将其他回归变量传递给函数来轻松调整,如线性回归、KNN 或决策树。为了获得多个估计值,就像 mice 在 R 中提供的那样,需要多次运行估算器(例如,在 for 循环中)。
回到我们的人均犯罪率的例子,我们首先需要将异常值转换为缺失值。为此,我使用 Tukey 方法检测到的可能异常值列表(参见第 1 篇文章)。
作为一个估计量,我选择了正则化线性回归(BayesianRidge),为了简单起见,我将设置 m=1(单次插补)。如前所述,sklearns 用户指南中也写道,估算器可用于多重估算
“通过在
sample_posterior=True时用不同的随机种子重复应用它[……]”。
同样,人均犯罪率从 3.61 变为 2.36。
对于单变量异常值:
- 仅次于处理缺失数据,常用于记录异常值的技术
- 多重插补更稳健,单一(如平均值)插补有偏差
- 对于插补,R 提供了比 python 更成熟、更灵活的包。
对于多元异常值:
- 插补对于多元异常值没有真正意义,因为它们被定义为多个变量的异常值观察值(对于多个异常值,所有条目都将变成缺失值,几乎没有预测空间)
包扎
外围数据点的处理是一项高度主观的任务,因为没有数学上正确或错误的解决方案。定性信息,如了解异常值的来源或异常值的影响,可以简化治疗决策。错误异常值最好被纠正或删除,而非错误异常值可以保留、删除或重新编码。极值有几种重新编码的方法,其中最流行的是 winsorizing 和多重插补。
一项基本任务是报告有无异常值的结果,并在处理异常值时提供合理的推理和解释。
资源:
- 【http://www.hermanaguinis.com/ORMoutliers.pdf 号
- *【https://www.rips-irsp.com/articles/10.5334/irsp.289/ *
- https://stefvanbuuren.name/fimd/sec-howmany.html
- https://sci kit-learn . org/stable/modules/impute . html # iterative-imputr
- https://www . r-bloggers . com/2019/01/a-new-way-to-handle-variable-outliers/
- https://WW2 . amstat . org/meetings/ices/2007/proceedings/ices 2007-000210。PDF



浙公网安备 33010602011771号