Sidewalk Labs:市政建模
目录
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 并刷新即可解决问题。