Python 为什么sklearn在CPU上比GPU上的Theano更快?

Python 为什么sklearn在CPU上比GPU上的Theano更快?,python,scikit-learn,gpu,theano,euclidean-distance,Python,Scikit Learn,Gpu,Theano,Euclidean Distance,我使用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_t

我使用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工具包学习慢的原因可能是传输时间。所以我用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>)
==27105==NVPROF正在分析过程27105,命令:python./EDM_test.py
使用gpu设备0:GeForce GTX 580(CNMeM已禁用,cuDNN不可用)
数据形状:(10000,40)
get_EDM_GPU运行时间:1.84863090515(s)
get_EDM_CPU运行时间:8.09937691689(s)
get_-EDM_-sk运行时间:1.10968112946(s)
比率:4.38128395145
==27105==分析应用程序:python./EDM_test.py
==27105==警告:在结果中发现9条无效记录。
==27105==警告:这可能是因为分析时设备内存不足。
==27105==分析结果:
时间(%)时间调用平均最小最大名称
71.34%1.28028s 9998 128.05us 127.65us 128.78us内核减少01节点316e2e1cbfbe8cfb8e4a101f329ffeec 0(int,int,float const*,int,int,float*,int)
19.95%357.97ms 9997 35.807us 35.068us 36.948us内核子节点bc41b3f8f12c93d29f2c4360ad445d80_0_2(无符号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内核\u Sqrt\u节点\u 23508f8f49d12f3e8369d543f5620c15\u 0连续(无符号整数,浮点常量*,浮点*)
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内核减少节点减少节点97496c4d3cf9a06dc4082cc141f918d2 0(无符号整数,浮点常量*,浮点*)
0.00%2.0090us 1 2.0090us 2.0090us 2.0090us无效复制_内核(cublasCopyParams)
传输[CUDA memcpy DtoH]执行了两次
{1.248[us],131.38[ms]}

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

传输时间约为131.639ms(131.88ms+259.73us)。 但是GPU和scikit learn之间的间隔约为700毫秒(1.8秒-1.1秒),因此,间隔是在传输时间内

它是否只从对称矩阵计算上三角矩阵

是什么让scikit学习如此之快?

是什么让scikit学习(在纯CPU端)如此之快? 我最初的候选人包括:

  • 在最快的[ns]距离内高效使用可用的CPU内核L1-/L2-大小
  • 智能
    numpy
    矢量化执行
    对CPU缓存线友好
  • 数据集如此之小,它可以完全保持不从缓存中逐出(测试以将审查中的数据集扩展到二级/三级缓存大小之上,以查看DDRx内存成本对观察到的性能的影响(详细信息见下面的URL))
  • 如果避免
    .astype()
    转换(测试它),可能会在
    numpy
    上享受更好的计时
GPU方面的事实
  • 与手动调整的内核设计相比,自动生成的GPU内核没有太多机会获得最终级别的全局内存延迟掩蔽,而是根据各自的GPU硅结构/体内观察到的延迟进行定制
  • 大于几KB的数据结构仍然需要支付大约数百[ns]的GPU-SM/GDDR-MEM距离,接近[us]-v/s-与CPU/L1/L2/L3/DDRx上的小单元~几十[ns]相比参考>>>
  • 由于这项任务的数据点重用率明显较低,数据集大小超出了GPU/SM硅限制,因此无法享受GPU/SMX的大部分功能,这导致并且必须导致GPU/SM寄存器容量在任何类型的GPU内核设计尝试和调整中溢出
  • 全局任务的异步、孤立(非通信孤岛)数学上密集,但SMX本地GPU内核处理步骤最少(没有太多计算来调整附加开销和昂贵的SMX/GDDR内存成本)

GPU-s可以展示其最佳性能,如果在
[m,n,o]
上进行足够密集的卷积再处理操作(如在大规模/高分辨率图像处理中),卷积核矩阵非常小,因此所有这些
m*n*o
常量值都可以驻留在SM的本地,在一组可用的SMX-SM_寄存器内,如果GPU内核启动器通过3D tblock/grid processing布局几何图形进行优化调整,以使全局内存访问延迟达到最佳屏蔽性能,让所有GPU线程都在硬件扭曲对齐SMx:WarpScheduler循环线程调度功能中执行(如果GPU内核代码中的执行路径不同,则第一次从循环切换到贪婪的WarpSchedule模式将失去整个战斗).

第一个图形上的CPU和GPU是什么?@Worthy7 CPU表示它使用for循环语句计算欧几里德距离矩阵,GPU表示它使用带GPU的Ano库计算矩阵。不,但CPU是一块硬件,SKLEARN是一个python框架。你不能把这两个放在一张图上。无论如何,我认为你的意思是运行纯python而不是使用sklearn right。sklearn在内部进行了优化——就是这么简单。请尝试更大的数据集:)比如说100倍bigger@Worthy7西亚诺