当我使用较小的浮点数时,为啥 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 应用程序中从图库中加载图像时,为啥位图返回较小的图像?

将两列文本文件中的浮点数读入Python中的数组时出错

为啥 % 运算符不能用于 C/C++ 中的浮点数但可以用于 Java 和 C#? [复制]

为啥不使用基于二进制补码的浮点数?

__builtin_unreachable 与 GCC 中的浮点数

当我需要存储不同精度的浮点数时,如何定义 HTML 输入字段?