zl程序教程

您现在的位置是:首页 >  IT要闻

当前栏目

从 CPU 切换到 GPU 进行纽约出租车票价预测

2023-04-18 14:45:36 时间

你有没有问过数据科学家是否希望他们的代码运行得更快?询问地球是否是平的,您可能会得到更多样化的回答。它确实与技术领域的其他任何事物没有任何不同,几乎总是越快越好。显着改善处理时间的最佳方法之一是(如果您还没有的话)从 CPU 切换到 GPU。感谢 Andrew NG 和 Fei-Fei Li 等先驱,GPU 因在深度学习技术方面表现特别出色而成为头条新闻。

今天,深度学习和 GPU 几乎是同义词。虽然深度学习很好地利用了显卡的处理能力,但它并不是唯一的用途。根据 Kaggle机器学习和数据科学状态 2020 的一项民意调查,卷积神经网络是受访者中最流行的深度学习算法,但它甚至没有进入前三名。事实上,只有 43.2% 的受访者表示使用CNN。领先于最流行的深度学习方法的是 (1) 83.7% 的线性或逻辑回归,(2) 78.1% 的决策树或随机森林,以及 (3) 61.4% 的梯度提升机。

图片来源:Kaggle

让我们重新审视我们的第一个问题:您是否曾问过数据科学家是否希望他们的代码运行得更快。我们知道每个数据科学家都希望花更多的时间探索数据,而不是花更少的时间观察 jupyter 单元的运行,但是我们交谈的绝大多数客户在使用前 3 名最流行的算法都没有使用 GPU %,或者80%的数据科学都不是在训练模型(如果这对你来说是新闻,谷歌数据科学 80/20)。

根据我的经验,数据科学家不将 GPU 用于深度学习之外的工作负载有 3 个主要原因(除了显而易见的:成本):

  1. 数据太小(果汁不值得挤)
  2. 使用 GPU 配置环境所需的时间
  3. 重构 CPU 代码所需的时间

我想说的很清楚。如果您的数据不太可能达到数百万的行数,您可能可以忽略此博客(也就是说,除非您想学习新东西)。但是,如果您实际上正在处理大量数据,即行数 > 1M,那么开始使用 GPU 进行数据科学的障碍,即原因 2 和 3,可以通过Cloudera 机器学习和NVIDIA RAPIDS轻松解决.

Cloudera 机器学习 (CML) 是Cloudera 数据平台中提供的众多数据服务之一。CML 提供您期望从现代数据科学平台获得的所有功能,例如可扩展的计算资源和对首选工具的访问,以及由 Cloudera 的共享数据体验或 SDX管理、治理和保护的好处。

NVIDIA RAPIDS 是一套软件库,可让您完全在 GPU 上运行端到端数据科学工作流。RAPIDS 依靠 NVIDIA CUDA 原语进行低级计算优化,但通过用户友好的 Python 界面展现了高性能。

CML 和 NVIDIA 共同提供RAPIDS 版机器学习运行时。ML Runtime是安全、可定制和容器化的工作环境。RAPIDS 版运行时建立在社区构建的 RAPIDS docker 映像之上,使数据科学家只需单击一下按钮即可在 GPU 上启动和运行,他们需要的所有资源和库都触手可及。原因2得以解决。

注意:上图是在 Cloudera Machine Learning 中启动会话的对话框。它提供对您公司的 ML 运行时目录和启用的资源配置文件的访问。这里我只选择了一个 GPU,但您可以根据需要选择多个。

这仍然给我们留下了为什么数据科学从业者对使用 GPU 犹豫不决的原因 3。数据科学已经是许多领域的一个领域。您需要精通编程、统计、数学、通信以及您所从事的领域。您最不想做的就是学习一堆新的库,或者更糟的是,学习一种新的编程语言!为此,让我们探索 RAPIDS 提供的 Python 接口。

NVIDIA 声称 RAPIDS Python 界面是用户友好的。但该声明未能完全概括这些接口对经验丰富的 Python 数据科学程序员的友好程度。RAPIDS库,例如cuDF为dataframes和cuML机器学习基本上是他们的CPU同行panda和GPU版本scikit学习。这就像搬到一所新学校并发现你最好朋友的双胞胎在你家的房间里。

当我第一次开始使用 RAPIDS 库时,我持怀疑态度。我认为语法的基础知识类似于他们旨在加速的 CPU 库,但远非抄袭。所以我对其进行了测试,仅使用基于 CPU 的 Python 库导入、清理、过滤、特征化,并使用纽约出租车的行程数据训练模型。然后我用相应的 NVIDIA 库替换了 CPU 库,但保留了它们绑定的名称。例如,我使用import cudf 作为 pd而不是import pandas as pd。

猜猜发生了什么!它不起作用……但它几乎起作用了。

差异

就我而言,对于 RAPIDS Release v0.18,我发现了两个 cuDF 和 Pandas 不同的边缘情况,一个涉及处理日期列(为什么世界不能就通用日期/时间格式达成一致?)另一个应用自定义功能。我将讨论我如何在脚本中处理这些,但请注意,我们只需要稍微更改 100 多行代码中的 3 行。

第一个问题的根本原因是 cuDF 的parse_dates不能像Pandas一样处理异常或非标准格式。不过,修复很容易,只需为日期列明确指定dtype='date',您将获得与使用Pandas相同的 datetime64 日期类型。

第二个问题稍微复杂一些。cuDF 不像其他Pandas操作员那样为DataFrame.apply提供精确的副本。相反,您需要使用DataFrame.apply_rows。这些函数的预期输入不一样,但很相似。

NVIDIA最近发布RAPIDS 21.12的每晚构建(NVIDIA转自SemVer到CalVer在八月为他们的版本方案)是应该复制DataFrame.apply在Pandas功能。在发布时,我无法验证此功能,但是 21.12 之后的构建应该只需要对数据类型进行一次微小的更改,即可利用该项目的 CML 中的 GPU 性能。

就我而言,我正在应用一个函数来计算两个纬度/经度坐标之间的半正弦距离。这是该函数以及如何将其应用于Pandas 中的数据帧 ( taxi_df ),从而生成一个新列 ( hav_distance ):

def haversine_distance(x_1, y_1, x_2, y_2): haversine_distance(x_1, y_1, x_2, y_2):
x_1 = pi/180 * x_1= pi/180 * x_1
y_1 = pi/180 * y_1= pi/180 * y_1
x_2 = pi/180 * x_2= pi/180 * x_2
y_2 = pi/180 * y_2= pi/180 * y_2


dlon = y_2 - y_1= y_2 - y_1
dlat = x_2 - x_1= x_2 - x_1
a = sin(dlat/2)**2 + cos(x_1) * cos(x_2) * sin(dlon/2)**2= sin(dlat/2)**2 + cos(x_1) * cos(x_2) * sin(dlon/2)**2


c = 2 * asin(sqrt(a)) = 2 * asin(sqrt(a))
r = 6371 # Radius of earth in kilometers= 6371 # Radius of earth in kilometers
return c * rreturn c * r


taxi_df['hav_distance'] = taxi_df.apply(lambda row:haversine_distance(row['pickup_latitude'],['hav_distance'] = taxi_df.apply(lambda row:haversine_distance(row['pickup_latitude'],
row['pickup_longitude'],['pickup_longitude'],

相比之下,这里是cuDF中应用的haversine函数:

def haversine_distance(pickup_latitude, haversine_distance(pickup_latitude,
pickup_longitude,,
dropoff_latitude,,
dropoff_longitude,,
hav_distance):):
for i, (x_1, y_1, x_2, y_2) in enumerate(zip(pickup_latitude,for i, (x_1, y_1, x_2, y_2) in enumerate(zip(pickup_latitude,
pickup_longitude,,
dropoff_latitude,,
dropoff_longitude)):)):


x_1 = pi/180 * x_1= pi/180 * x_1
y_1 = pi/180 * y_1= pi/180 * y_1
x_2 = pi/180 * x_2= pi/180 * x_2
y_2 = pi/180 * y_2= pi/180 * y_2


dlon = y_2 - y_1= y_2 - y_1
dlat = x_2 - x_1= x_2 - x_1
a = sin(dlat/2)**2 + cos(x_1) * cos(x_2) * sin(dlon/2)**2= sin(dlat/2)**2 + cos(x_1) * cos(x_2) * sin(dlon/2)**2


c = 2 * asin(sqrt(a)) = 2 * asin(sqrt(a))
r = 6371 # Radius of earth in kilometers= 6371 # Radius of earth in kilometers


hav_distance[i] = c * r[i] = c * r


taxi_df = taxi_df.apply_rows(haversine_distance,= taxi_df.apply_rows(haversine_distance,
incols=['pickup_latitude',=['pickup_latitude',
'pickup_longitude','pickup_longitude',
'dropoff_latitude','dropoff_latitude',
'dropoff_longitude'],'dropoff_longitude'],
outcols=dict(hav_distance=np.float64),=dict(hav_distance=np.float64),
kwargs=dict())=dict())

函数的逻辑是相同的,但是如何处理函数输入以及如何将用户定义的函数应用于 cuDF 数据帧与 Pandas 有很大不同。请注意,我必须压缩然后枚举hasrsine_distance函数中的参数。

此外,当将此函数应用于数据帧时,apply_rows函数需要具有特定规则的输入参数。例如,传递给 incols 的值是传递给函数的列的名称,它们必须与函数中的参数名称匹配,或者您必须传递一个将列名称与其对应的匹配的字典函数参数。

有关在 cuDF 数据帧中使用用户定义函数的更深入解释,您应该查看RAPIDS 文档。

速度与激情的结果

因此,经过一些小的修改后,由于 RAPIDS,我能够成功地在 GPU 上运行 pandas 和 scikit-learn 代码。

现在,事不宜迟,你们一直在等待的那一刻。我将通过一系列图表展示从 pandas 和 scikit-learn 切换到 cuDF 和 cuML 时的实际速度改进。第一个比较 GPU 和 CPU 之间在较短任务上花费的秒数。如您所见,CPU 和 GPU 运行时之间的比例实际上并不相同。

接下来让我们检查运行时间较长的任务的运行时间(以秒为单位)。我们谈论的是,你猜对了,我们知道的用户定义函数传统上对 Pandas 数据帧的性能很差。请注意 CPU 和 GPU 之间的性能差异。运行时间减少了 99.9%!

迄今为止,我们 CPU 代码的 UDF 部分的性能最差,为 526 秒。下一个最接近的部分是“Read in the csv”,需要 63 秒。

现在将其与在 GPU 上运行的部分的性能进行比较。您会注意到“应用半正弦 UDF”不再是表现最差的部分。事实上,它与表现最差的部分相差甚远。cuDF FTW!

最后,这是一张图表,其中包含在 CPU 和 GPU 上运行的实验的完整端到端运行时间。总之,cuDF 和 cuML 代码将运行时间减少了 98% !最重要的是,只需切换到 RAPIDS 库并更改几行代码即可。

结论

GPU 不仅用于深度学习,还具有 RAPIDS 库 GPU 可用于加速完整的端到端数据科学生命周期的性能,而对所有数据科学家都知道和喜爱的 CPU 库进行最少的更改。

如果你想了解更多关于这个项目的信息,你应该参加11 月 8 日至 11 日举行的NVIDIA GTC,我将在那里展示“从 CPU 到 GPU 和 Cloudera 机器学习”。立即注册以参加本次会议和其他会议。

其他资源

如果您想自己运行实验,请点击以下链接:

  • 视频– 观看涵盖此用例的简短演示视频
  • 教程- 按照分步说明设置和运行此用例
  • 聚会/录音-参加一个聚会互动直播流解决这个用例由Cloudera的专家领衔
  • Github——自己看代码

最后,不要忘记查看用户页面以获取更多出色的技术内容。

原文作者:Jacob Bengtson

原文链接:https://blog.cloudera.com/switching-from-cpus-to-gpus-for-nyc-taxi-fare-predictions-with-nvidia-rapids/