

最近数値計算をpythonではじめましたのですが、  
例えば、以下のような

[code]

    import numpy as np
    A = np.zeros(500,4,4)    
    B = np.identity(4)
    
[/code]

三次元配列Aと行列Bがあったとします。  
ここではAはゼロ行列ですが、実際は非ゼロであるとしてください。

[code]

    for i in range(0, 500):
        B = np.dot(A[i,:,:], B)
    
[/code]

3次元配列Aの要素に対し奥行き方向に向かって、

A[499,:,:].dot(A[498,:,:])….dot(A[2,:,:]).dot(A[1,:,:]).dot(A[0,:,:])

と言った具体にドット積を求める際に  
上記のようなfor文を使ってしまうと時間がかかってしまいます。  
同じ処理結果でより高速な計算を行う記述の仕方はありませんでしょうか。

補足  
上の、500*4*4の三次元配列Aを順に計算していく過程を数十回繰り返すつもりでいます。  
得た結果をフィッティングにも用いたいのでなるべく処理速度を早めたいのです。  
一連の過程で最も時間を要した部分がこのループであったため現状は痛手です。

計算するマシンにもよりますが、私の環境ですと、三次元配列を奥行方向へ1,2,…,499,500と  
ドット積を計算するだけに要する時間は約0.4秒です。  
目標は0.1秒程度まで縮めたいと考えておりました。


CC BY-SA 3.0
2017-10-03T06:43:58.497
38386
2018-03-21T07:40:42.613
2017-10-13T13:37:27.147
25752
25752
question
python numpy
for文を使わずに三次元配列に対し奥行方向にドット積を求める方法


`ufunc.reduce`というのを見つけて、これでいけるんじゃないかと思ったのですが、残念ながら`np.dot`は`ufunc`ではないので`np.dot.reduce`とすることはできないようです。  
<https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.ufunc.reduce.html>

しかし任意の関数から`ufunc`を作れる`np.frompyfunc`というものがあるようです。  
<https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.frompyfunc.html#numpy.frompyfunc>

これを使い、無理やり`np.dot`の`ufunc`バージョンを作ります。

[code]

    udot = np.frompyfunc(np.dot, 2, 1)
    
[/code]

そして`udot.reduce`でAのドット積を求めることができます。

[code]

    udot.reduce(A)
    
[/code]

...しかし結局pythonの関数を使っているので、たぶん遅いと思います。

ここでも似た議論がされていますが、いい結論は出ていないようです。  
<https://stackoverflow.com/questions/27993153/how-to-fold-accumulate-a-numpy-
matrix-product-dot>


CC BY-SA 3.0
2017-10-03T08:07:31.830
38388
2017-10-03T08:07:31.830
20206
38386
answer


行列積は結合法則が成り立つので、multiprocessingを用いて

500個の行列(A1~A500)を分割し(A1~A100,A101~A200,,,A401~A500)、  
各グループの行列積を並列に演算し、  
各結果の積を求める

とすれば処理時間は短くなります。  
ただ、その場合でもfor文は必須ですし、  
GPUを駆使した方がベターです。


CC BY-SA 3.0
2017-10-03T23:29:57.523
38396
2017-10-03T23:29:57.523
23008
38386
answer