【问题标题】:How can I improve python code performance using numpy如何使用 numpy 提高 python 代码性能
【发布时间】:2016-01-14 05:50:44
【问题描述】:

我读过this blog,它展示了一个算法如何通过使用 numpy 实现 250 倍的加速。我曾尝试使用 numpy 改进以下代码,但无法使其工作:

    for i in nodes[1:]:
        for lb in range(2, diameter+1):
            not_valid_colors = set()
            valid_colors = set()

            for j in nodes:
                if j == i:
                    break

                if distances[i-1, j-1] >= lb:
                    not_valid_colors.add(c[j, lb])
                else:
                    valid_colors.add(c[j, lb])

                c[i, lb] = choose_color(not_valid_colors, valid_colors)

    return c

说明

上面的代码是用于计算图的自相似维度的算法的一部分。它的工作原理基本上是构建对偶图 G',其中如果节点之间的距离大于或等于给定值 (Lb),则它们之间的节点相互连接,然后计算这些对偶网络上的图着色。

算法描述如下:

  1. 为所有网络节点分配一个从 1 到 N 的唯一 ID,但尚未分配任何颜色。
  2. 对于所有 Lb 值,将颜色值 0 分配给 id=1 的节点,即 C_1l = 0。
  3. 设置 id 值 i = 2。重复以下操作,直到 i = N。
    • a) 计算从 i 到网络中 id j 小于 i 的所有节点的距离 l_ij。
    • b) 设置 Lb = 1
    • c) 从 l_ij ≥ Lb 的所有节点 j
    • d) 将 Lb 增加 1 并重复 (c) 直到 Lb = Lb_max。
    • e) 将 i 增加 1。

wrote it in python 但尝试将它用于具有 100 个节点且 p=0.9 的小型网络时需要一分钟以上。

由于我还是 python 和 numpy 的新手,我没有找到提高其效率的方法。

是否可以通过使用 numpy.where 找到路径比给定 Lb 长的位置来删除循环?我试图实现它,但没有奏效......

【问题讨论】:

  • 但是在 SO 上的 numpy 知识渊博的海报比在 CR 上的要多得多。 CR 也往往对问题格式非常挑剔。 “矢量化”是 SO numpy 上的一个常见话题。
  • numpy 如果您的问题本质上是平行的,则可以大大加快处理速度 - 对元素执行相同的操作,无论顺序如何。但如果问题是串行的——第 i 个元素的动作取决于之前对“i-1”的动作,那么numpy 通常无济于事。
  • 同意@hpaulj 提出的性能问题,在此处矢量化相关问题。同样对于 OP,如果在寻找矢量化代码时使用 numpy 数组而不是集合、列表甚至更好,会更容易。
  • 请添加 nodesdistances 的最小示例,并尝试使用 numpy 进行矢量化。
  • 使用 for j in nodes[:i] 比使用显式 if ... then break 更符合 Python 风格。

标签: python algorithm python-3.x numpy optimization


【解决方案1】:

使用 numpy 数组的向量化运算速度很快,因为实际计算是使用 BLASLAPACK 等底层库完成的,没有 Python 开销。使用循环密集型操作,您将看不到这些好处。

您通常必须想出一种方法来向量化操作(通常可以通过巧妙地使用数组切片来实现)。但是,某些操作本质上是循环密集型的,有时将它们矢量化并不容易(您的代码似乎就是这种情况)。

在这些情况下,您可以先尝试Numba,它会从 Python 函数生成优化的机器代码,无需任何修改。 (您只需对函数进行注释,它会自动为您完成)。我没有很多经验,也没有尝试将它用于复杂的功能。

如果这不起作用,那么您可以使用Cython,它会自动将类似 Python 的代码(带有类型变量)转换为高效的 C 代码,并生成一个 Python 扩展模块,您可以在 Python 中导入和使用该模块。对于循环密集型操作,这通常会给您至少一个数量级(通常是两个数量级)的加速。我通常发现 Cython 易于使用,因为与纯 C 不同,可以直接在 Cython 代码中访问您的 numpy 数组。

我推荐使用Anaconda Python distribution,因为您可以轻松安装这些软件包。很抱歉,我没有针对您的代码的具体答案。

【讨论】:

  • 感谢您的解释和建议,我会尝试两个选项并让您知道结果!
  • 您不必使用numpy 也可以使用Cython。事实上,使用常规 Python 列表操作可能更有效 - 请查看其文档。
  • 我从来没有说过你必须这样做。 :)
  • 再次感谢@joon,我已经测试了 cython,性能更好。我确信它可以进一步改进,所以我提出了另一个问题来跟进如何改进 cython 代码。你可以在stackoverflow.com/questions/33160102看到它
【解决方案2】:

如果你想去 numpy,你可以把列表改成数组, 例如 distances[i-1][j-1] 在您将距离声明为 numpy 数组后变为 distances[i-1, j-1]。与c[i][lb] 相同。关于valid_colorsnot_valid_colors,您应该多考虑一下,因为使用 numpy 数组您不能追加内容:数组具有固定长度,因此您应该在之前确定最大大小。另一个想法是,在 numpy 中拥有所有内容之后,您可以对代码进行 cythonize http://docs.cython.org/src/tutorial/cython_tutorial.html 这意味着您的所有循环都将变得非常快。无论如何,如果您不想要 cython 并查看博客,您会看到 distancesmain() 中声明为数组

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-11
    • 2016-04-12
    • 2016-11-27
    • 2016-06-20
    • 2018-01-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多