Sidewalk Labs:市政建模

我是谁?

我是 Brett Naul。我在 Sidewalk Labs 工作。

我试图解决什么问题?

我在 Sidewalk 的团队(“Model Lab”)使用机器学习模型研究城市中的人类出行行为,并生成都市区域出行模式/流量的高保真模拟。我们的流程主要有三个步骤:

  • 根据人口普查数据和其他人口统计信息来源构建“合成人口”;该人口在统计上代表真实人口,但不包含任何实际可识别的个体。

  • 使用匿名移动位置数据训练机器学习模型,以了解该区域的行为模式(例如,人们何时去吃午餐,哪些因素影响个人使用公共交通的可能性等)。

  • 对于合成人口中的每个人,从这些模型生成预测,并将结果活动整合成该区域所有活动的单一模型。

更多信息请参阅我们的博客文章 引入 Replica:下一代城市规划工具

Dask 如何提供帮助

为数百万合成个体生成活动计算量巨大;例如,即使使用 96 核实例,最初模拟一个大型区域的一天也需要几天时间。对我们来说,重要的是能够在一夜之间从头开始运行新的模拟,而使用 Dask 将计算扩展到数百/数千个核心、跨越众多 worker,使我们能够实现目标。

我们最初选择 Dask 的原因,以及这些原因随时间如何变化

我们的代码由遗留的研究级代码和较新的生产级代码(大部分是 Python)混合而成。在我开始之前,我们使用 Google Cloud Dataflow(仅支持 Python 2,可大规模扩展但通常使用/调试起来极其痛苦)和 multiprocessing(最多约 96 个核心)。

Dask 使我们能够在仅对数据管道进行最小改动的情况下扩展到单机之外。如果从头开始,我认为很可能会选择不同的方向(例如 C++ 或 Go 微服务,特别是考虑到我们与 Google 的紧密联系),但从我作为混合基础设施工程师/数据科学家的角度来看,将所有模型都放在 Python 中使得实验和调试统计问题变得容易。

在我们的问题中使用 Dask 的一些痛点

有很多只有我才拥有的 Dask 特殊知识,例如:

  • 我们可以用哪些格式序列化数据,以便高效地重新加载?有时可以使用 parquet,有时应该使用 CSVs,以便在运行时轻松地动态分块。

  • 有时我们在 client 上加载数据并 scatter 到 worker 上,有时我们直接在 worker 上加载数据块。

  • 与本地代码相比,调试过程要复杂得多,这使得其他人更难协助解决在 worker 上出现的问题。

  • 调度器是我们大多数扩展问题的来源:当任务/数据块的数量过大时,调度器往往会以某种方式静默崩溃。

    其中一些故障可能与 Kubernetes 有关(如果我们耗尽了 RAM,看不到 OOM 错误;pod 会直接消失,作业会重启)。我们不得不手动调整一些参数,例如超时时间,以使其更稳定,并且经过了大量的反复试验才达到相对可靠的状态。

  • 这更多地与我们的部署过程有关,但有时我们会遇到调度器和 worker 运行不同版本的 dask/distributed 的情况,这会导致在提交任务时崩溃,而不是在建立连接时崩溃,这使得诊断需要一段时间(此外,错误往往是一些难以理解的东西,例如 KeyError: ...,除了我之外的其他人完全不知道如何解释)。

我们在 Dask 周边使用的一些技术

  • Google Kubernetes Engine:许多 worker 实例(通常每个 16 核),1 个 scheduler,1 个 job runner client(加上其他一些微服务)

  • Make + Helm

  • 为了调试/监控,我通常使用 kubectl port-forward 到 8786 和 8787,并查看仪表板/手动提交任务。当有很多 worker 时,通过 port-forward 查看仪表板不是很可靠(由于某种原因,websocket 连接会反复中断),但只需重新连接到 pod 并刷新即可解决问题。