【问题标题】:Why is sklearn faster on CPU than Theano on GPU?为什么 sklearn 在 CPU 上的速度比在 GPU 上的 Theano 快?
【发布时间】:2018-02-13 05:47:24
【问题描述】:

我使用 Python 比较了 theano(CPU)、theano(GPU) 和 Scikit-learn(CPU) 的处理时间。 但是,我得到了奇怪的结果。 看看我绘制的图表。

处理时间比较:

你可以看到 scikit-learn 比 theano(GPU) 更快的结果。 我检查其经过时间的程序是从具有 n * 40 个元素的矩阵计算欧几里德距离矩阵。

这是代码部分。

points = T.fmatrix("points")
edm = T.zeros_like(points)

def get_point_to_points_euclidean_distances(point_id):
    euclideans = (T.sqrt((T.sqr(points- points[point_id, : ])).sum(axis=1)))

    return euclideans

def get_EDM_CPU(points):
    EDM = np.zeros((points.shape[0], points.shape[0])).astype(np.float32)
    for row in range(points.shape[0]):
        EDM[row, :] = np.sqrt(np.sum((points - points[row, :])**2, axis=1))

    return EDM

def get_sk(points):
    EDM = sk.pairwise_distances(a, metric='l2')

    return EDM

seq = T.arange(T.shape(points)[0])
(result, _) = theano.scan(fn = get_point_to_points_euclidean_distances, \
outputs_info = None , \
sequences = seq)

get_EDM_GPU = theano.function(inputs = [points], outputs = result, allow_input_downcast = True)

我认为 GPU 比 sci-kit learn 慢的原因可能是传输时间。所以我用 nvprof 命令对 GPU 进行了分析。然后我得到了这个。

==27105== NVPROF is profiling process 27105, command: python ./EDM_test.py
Using gpu device 0: GeForce GTX 580 (CNMeM is disabled, cuDNN not available)
data shape :  (10000, 40)
get_EDM_GPU elapsed time :  1.84863090515 (s)
get_EDM_CPU elapsed time :  8.09937691689 (s)
get_EDM_sk elapsed time :  1.10968112946 (s)
ratio :  4.38128395145
==27105== Profiling application: python ./EDM_test.py
==27105== Warning: Found 9 invalid records in the result.
==27105== Warning: This could be because device ran out of memory when profiling.
==27105== Profiling result:
Time(%)      Time     Calls       Avg       Min       Max  Name
 71.34%  1.28028s      9998  128.05us  127.65us  128.78us  kernel_reduce_01_node_316e2e1cbfbe8cfb8e4a101f329ffeec_0(int, int, float const *, int, int, float*, int)
 19.95%  357.97ms      9997  35.807us  35.068us  36.948us  kernel_Sub_node_bc41b3f8f12c93d29f2c4360ad445d80_0_2(unsigned int, int, int, float const *, int, int, float const *, int, int, float*, int, int)
  7.32%  131.38ms         2  65.690ms  1.2480us  131.38ms  [CUDA memcpy DtoH]
  1.25%  22.456ms      9996  2.2460us  2.1140us  2.8420us  kernel_Sqrt_node_23508f8f49d12f3e8369d543f5620c15_0_Ccontiguous(unsigned int, float const *, float*)
  0.12%  2.1847ms         1  2.1847ms  2.1847ms  2.1847ms  [CUDA memset]
  0.01%  259.73us         5  51.946us     640ns  250.36us  [CUDA memcpy HtoD]
  0.00%  17.086us         1  17.086us  17.086us  17.086us  kernel_reduce_ccontig_node_97496c4d3cf9a06dc4082cc141f918d2_0(unsigned int, float const *, float*)
  0.00%  2.0090us         1  2.0090us  2.0090us  2.0090us  void copy_kernel<float, int=0>(cublasCopyParams<float>)

传输 [CUDA memcpy DtoH] 执行了两次{ 1.248 [us], 131.38 [ms] }

传输 [CUDA memcpy HtoD] 执行了 5x { min: 640 [ns], max: 250.36 [us] }

传输时间约为 131.639 ms(131.88 ms + 259.73 us)。 但是 GPU 和 scikit-learn 之间的差距大约是 700ms (1.8 s - 1.1 s) 所以,差距超过了传输时间。

它只计算对称矩阵的上三角矩阵吗?

是什么让 scikit-learn 这么快?

【问题讨论】:

  • 第一张图上的 CPU 和 GPU 是什么?
  • @Worthy7 CPU表示使用for循环语句计算欧几里得距离矩阵,GPU表示使用theano库和GPU计算矩阵。
  • 不但是CPU是一个硬件,SKLEARN是一个python框架。你不能把这两个放在一个图表上。无论如何,我认为您的意思只是运行纯 python 与正确使用 sklearn。 sklearn 在内部进行了优化——就这么简单。请尝试更大的数据集:) 假设要大 100 倍
  • @Worthy7 Theano 同时拥有 CPU 和 GPU 后端。他正在谈论使用它。
  • 很公平。更大的测试!

标签: python scikit-learn gpu theano euclidean-distance


【解决方案1】:

是什么让 scikit-learn(在纯 CPU 端)如此之快?

我最初的候选人将是:

  • 在最快 [ns] 距离内高效使用可用 CPU 内核 L1-/ L2- 尺寸
  • 智能numpy矢量化执行对CPU缓存线友好
  • 数据集如此小,它可以完全保持不从缓存中逐出(测试以将数据集-under-review 的方式扩展到 L2-/L3-缓存大小之上,以查看 DDRx-memory-对观察到的性能的成本影响(详细信息在下面的 URL 中))
  • 如果避免.astype() 转换,可能会在numpy 上享受更好的时机(测试一下)

GPU 方面的事实

  • 与手动调整的内核设计相比,自动生成的 GPU 内核没有太多机会获得最终级别的全局内存延迟屏蔽,适合相应的 GPU 芯片架构/体内观察到的延迟李>
  • 大于几 KB 的数据结构仍然需要支付大约数百 [ns] 的 GPU-SM/GDDR-MEM 距离,与小单位相比,几乎是 [us] -v/s- 大约几十 [ns ] 在 CPU/L1/L2/L3/DDRx ) 参考。计时细节在 >>> https://stackoverflow.com/a/33065382
  • 无法充分享受 GPU/SMX 的强大功能,因为该任务对数据点的重用率明显较低,并且数据集大小超出了 GPU/SM-silicon 的限制,这导致并且必须导致 GPU/SM-register 容量任何类型的 GPU 内核设计尝试和调整都会产生溢出效应
  • 全局任务没有最小合理数量的异步、隔离(非通信孤岛)数学上密集但 SMX 本地、GPU 内核处理步骤(没有太多需要计算以适应附加开销和昂贵的 SMX/GDDR 内存成本)

如果在[m,n,o]-convolution-kernel 上发生足够多的密集卷积再处理操作(例如在大规模/高分辨率图像处理中),GPU-s 可以很好地展示其最佳性能矩阵如此之小,以至于所有这些m*n*o 常量值都可以驻留在 SM 的本地,在一组可用的 SMX-SM_registers 内,并且如果 GPU 内核启动器通过 3D-tblock/网格处理布局几何图形进行了最佳调整,因此全局内存访问延迟处于其最佳屏蔽性能,所有 GPU 线程都在硬件 WARP 对齐的 SMx:WarpScheduler RoundRobin 线程调度功能中强制执行(从 Round-Robin 到 Greedy-WarpSchedule 模式的第一次交换如果 GPU-kernel-code 中的执行路径不同,则会输掉整场战斗。

【讨论】:

    猜你喜欢
    • 2020-10-18
    • 2018-12-22
    • 1970-01-01
    • 1970-01-01
    • 2017-08-19
    • 2022-01-19
    • 2019-02-28
    • 2020-10-29
    相关资源
    最近更新 更多