Python numpy 如何優雅的進行矩陣的平行計算

Python sunhk25 • at 2021-04-19 18:05:23 • 3 Views

有一列表對其自身的矩陣求和。 現在是通過雙迴圈來計算的,numpy 有什麼優雅的寫法嗎?

import numpy as np
def how(x, y):
    return x + y
arr = [1, 2, 3, 4, 5, 6]
match_arr = np.zeros((len(arr), len(arr)))
for i in range(0, len(arr)):
    for j in range(0, len(arr)):
        if j >= i:
            X = how(arr[i], arr[j])
            match_arr[i, j] = X
            match_arr[j, i] = X

print(match_arr)
[[ 2.  3.  4.  5.  6.  7.]
 [ 3.  4.  5.  6.  7.  8.]
 [ 4.  5.  6.  7.  8.  9.]
 [ 5.  6.  7.  8.  9. 10.]
 [ 6.  7.  8.  9. 10. 11.]
 [ 7.  8.  9. 10. 11. 12.]]

Total: 18
  • hsfzxjy 2021-04-19 18:15:56
    arr = np.array([...])
    match_arr = arr[None] + arr[:, None]
  • geelaw 2021-04-19 18:15:57
    arr = np.array(arr)
    match_arr = np.reshape(arr, (-1, 1)) + np.reshape(arr, (1, -1))

    大概是這麼個意思,參考 broadcast 的概念。

    如果每個元素的計算過程不能用 numpy 內建的運算表達則無法實現,因為 GIL 的存在。
  • princelai 2021-04-19 18:19:57
    ```python
    a,b = np.meshgrid(arr,arr)
    match_arr = a+b
    ```
    不一定高效,但是簡單
  • princelai 2021-04-19 18:11:57
    還有一種方法,原理一樣
    ```python
    match_arr = np.mgrid[1:7,1:7].sum(axis=0)
    ```
  • sunhk25 2021-04-19 18:17:57
    @geelaw 那就是說用自定義的 how 函式來迴圈計算時還是沒有優化方法唄
  • sunhk25 2021-04-19 18:19:57
    @princelai sum 是我自定義的一個函式
  • princelai 2021-04-19 19:15:57
    @sunhk25 #6 你是想說 how 是你自定義的函式?你不是簡單的相加是嗎?那上 numba,迴圈放到 numba 裡很快,比 numpy 還快。或者你都有兩個傳播好的 array 了,你改一下 how 函式不就完了
  • sunhk25 2021-04-19 19:16:57
    @princelai 對 是這個意思。我研究一下 numba,謝謝
  • nikan999 2021-04-19 19:17:57
    先用 numba 如果還想快 就上程序
  • hsfzxjy 2021-04-19 19:17:57
    除了 numba,cython 也可以試試。門檻有點高,但是效能優化的上限也高
  • kickcellardoor 2021-04-19 20:18:57
    numba,資料量夠大甚至可以 PyTorch, GPU 上來並行
  • Harry1993 2021-04-20 07:13:42
    樓上說 PyTorch,那我來說 TensorFlow 吧
  • necomancer 2021-04-21 00:11:11
    In [4]: from numba import guvectorize, float64, jit
    In [5]: @jit(nopython=True)
    ...: def how(x, y):
    ...: return x + y
    In [6]: @guvectorize([(float64[:], float64[:,:])], '(n)->(n, n)', nopython=True)
    ...: def f(arr, ret):
    ...: for i in range(arr.shape[0]):
    ...: for j in range(arr.shape[0]):
    ...: if j >= i:
    ...: tmp = how(arr[i], arr[j])
    ...: ret[i, j] = tmp
    ...: ret[j, i] = tmp
    In [11]: arr = [np.arange(3), np.arange(10, 13)]

    In [12]: f(arr)
    Out[12]:
    array([[[ 0., 1., 2.],
    [ 1., 2., 3.],
    [ 2., 3., 4.]],

    [[20., 21., 22.],
    [21., 22., 23.],
    [22., 23., 24.]]])
    In [13]: arr = np.arange(3)

    In [14]: f(arr)
    Out[14]:
    array([[0., 1., 2.],
    [1., 2., 3.],
    [2., 3., 4.]])
  • necomancer 2021-04-21 00:11:11
    想要速度一定要用 nopython=True,但是程式碼得注意一定不能有 object
  • necomancer 2021-04-21 00:11:11
    這狗 shit 的排版……
  • necomancer 2021-04-21 00:12:11
    另,guvectorize 可以 target='cpu', 'gpu', 'parallel'
  • necomancer 2021-04-21 00:08:11
    我測試了一下,有個簡單一點的方法,但是會慢一些:
    arr = np.arange(3)
    def how(x, y):
    ....if x < y:
    ........return x + y
    ....return x * y
    np.frompyfunc(how, 2, 1)(arr[:,None], arr)

    frompyfunc 會返回一個 ufunc,從而讓 numpy 可以 broadcast 自定義的函式。但是效率似乎沒有 numba 的 vectorize/guvectorize 高,尤其是 numba 可以 target='gpu'或者'parallel'
  • sunhk25 2021-04-21 08:08:17
    @necomancer target 引數學習了
Add a reply
For Commenting you need to Login. If you dont have a Account you need to Register.