2017-09-05 112 views
2

我用Python比较了theano(CPU),theano(GPU)和Scikit-learn(CPU)的处理时间。 但是,我得到了奇怪的结果。 这里看看我绘制的图。为什么在GPU上Skyline比Theano更快?

处理时间比较:

Processing Time Comparison

你可以看到的结果scikit学习比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学习慢的原因可能是转换时间。所以我用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]进行5倍{ min: 640 [ns], max: 250.36 [us] }

传送时间为约131.639毫秒(131.88毫秒+ 259.73我们的转印)。但是GPU和scikit-learn之间的差距大约是700ms(1.8s - 1.1s)所以差距超过了传输时间。

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

什么让scikit学习如此之快?

+0

第一张图上的CPU和GPU是什么? – Worthy7

+0

@ Worthy7 CPU意味着它使用for-loop语句计算欧几里得距离矩阵,而GPU意味着它通过使用带有GPU的theano库来计算矩阵。 – Holden

+0

不,但CPU是一块硬件,SKLEARN是一个python框架。你不能只把这两个放在图上。无论如何,我认为你的意思是运行纯python vs使用sklearn。 sklearn内部优化 - 就是这么简单。 请尝试更大的数据集:)让我们假设100X更大 – Worthy7

回答

2

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

我的初始候选人将是一个组合:

  • 高效利用可用的CPU核芯 L1-/L2-尺寸最快[NS]内-distances
  • 智能numpy向量化执行对CPU高速缓存行友好
  • 数据集如此小,它可以完全保持不被从高速缓存中驱逐(测试以缩放数据集 - unde r查看方式高于L2-/L3高速缓存大小以查看DDRx内存成本对观察到的性能的影响(详细信息在下面的URL中))
  • 如果避免.astype()转换可能会享受更好的时间numpy (测试)

事实在GPU上侧

  • 自动生成的GPU核函数没有太多机会获得全局内存延迟掩蔽的最终水平,相比手动调整了内核级设计,适合于在体内观察到的相应GPU-硅架构/延迟
  • 大于几KB的数据结构仍然支持大数百[ns],几乎[us] -v/s-与小单元〜小数十[ns]相比的GPU-SM/GDDR-在CPU/L1/L2/L3/DDRx)参考。时间细节>>>https://stackoverflow.com/a/33065382
  • 由于此任务明显低于GPU/SM-silicon限制之外的数据点和数据集大小,因此无法享受GPU/SMX的大部分功能,导致并且必须在任何种类的GPU内核设计尝试中调整GPU/SM寄存器容量溢出并且调整全局任务不具有最小合理数量的异步,隔离(非通信岛)数学密集但SMX本地,GPU内核处理步骤(没有太多的计算,以便调整附加开销和昂贵的SMX/GDDR内存成本)

GPU-s可以展现它的最佳性能,我f足够的密集卷积重新处理操作发生 - 如在大规模/高分辨率图像处理 - 在很小的卷积核矩阵上,因此所有这些常数值可以驻留在本地到SM,在一组可用的SMX-SM_registers中,以及GPU内核启动器是否通过3D-tblock /网格处理布局几何图形进行了最佳调整,以便全局内存访问延迟处于最佳屏蔽性能, GPU线程在硬件WARP对齐的SMx:WarpScheduler RoundRobin线程调度功能中执行(从Round-Robin到Greedy-WarpSchedule模式的第一个交换失去了在GPU内核代码中发散执行的不同执行路径的整个战斗) 。