当我使用较小的浮点数时,为啥 sklearn 中的 KNN 实现会变慢?
Posted
技术标签:
【中文标题】当我使用较小的浮点数时,为啥 sklearn 中的 KNN 实现会变慢?【英文标题】:Why is the KNN implementation in sklearn slower when I use a smaller float?当我使用较小的浮点数时,为什么 sklearn 中的 KNN 实现会变慢? 【发布时间】:2017-10-19 08:12:53 【问题描述】:我在我的应用程序中使用 KNN 搜索。大数组会消耗大量内存,我正在尝试减小数组的大小。
在不影响结果的情况下减少维度数量对我来说太难了。所以我希望通过使用更小的dtype
来减小大小:
In [46]: features = np.random.random((500000, 128)).astype('float32')
In [47]: smaller = features.astype('float16')
In [48]: nbrs = NearestNeighbors(n_neighbors=20, algorithm='brute', metric='l2').fit(f
...: eatures)
In [49]: smaller_nbrs = NearestNeighbors(n_neighbors=20, algorithm='brute', metric='l2
...: ').fit(smaller)
In [50]: %timeit nbrs.kneighbors(features[3:4])
10 loops, best of 3: 61.7 ms per loop
In [51]: %timeit smaller_nbrs.kneighbors(smaller[3:4])
1 loop, best of 3: 526 ms per loop
如您所见,切换到 float16
会使 kneighbors
调用慢 10 倍左右。
为什么会这样?有什么办法可以让它像使用 float32
时一样快吗?
【问题讨论】:
作为在黑暗中的刺,NearestNeighbors 需要 float32,所以它正在转换为 float32。它如何随着输入的大小而扩展? @aryamccarthy 是对的。顺便说一句,kNN 是一个惰性加载器,因此您应该尝试减少样本数量和/或特征向量的长度以缩短预测时间。 @DariusMorawiec 不,他错了。不会发生到 float32 的转换,只是numpy.einsum
在某种程度上使用 float32 比使用 float16 更快。
【参考方案1】:
32b 浮点数比 16b 浮点数工作得更快的原因是大多数现代 CPU 原生支持 32b 浮点数,而 16b 浮点数可能需要一些特殊处理(例如转换为 float32)。因此,当您节省 RAM 时,您会在计算上花费更多。 当使用适当的 CPU 指令时,这种情况可以得到缓解,这可能不是这里的情况(英特尔在 2012 年引入了特殊的半精度操作码;see)。需要注意的是,只有当您的阵列大于 256K(这显然是您的情况)时,您才能实现任何明显的加速,但改进在 20% 到 40% 之间,这很容易通过阵列的非最佳遍历而丢失(缓存未命中)。
另外,另一个需要考虑的因素是内存数据对齐,通常使用完整字时效果更好(对于许多 CPU:32b 或 64b)。您可以在Scott Myers' presentation 中找到有关内存对齐和缓存使用影响的大量详细信息。
【讨论】:
以上是关于当我使用较小的浮点数时,为啥 sklearn 中的 KNN 实现会变慢?的主要内容,如果未能解决你的问题,请参考以下文章
当我在我的 android 应用程序中从图库中加载图像时,为啥位图返回较小的图像?
为啥 % 运算符不能用于 C/C++ 中的浮点数但可以用于 Java 和 C#? [复制]