25

Cython から numpy で利用できる内積、行列反転、およびその他の基本的な線形代数演算を使用しようとしています。numpy.linalg.inv(反転)、numpy.dot(内積)、X.t(行列/配列の転置)などの関数。Cython 関数から呼び出すとオーバーヘッドが大きくnumpy.*、関数の残りの部分は Cython で記述されているため、これは避けたいと思います。

numpyユーザーがインストールしたと仮定した場合、次のような方法はありますか?

#include "numpy/npy_math.h"

として、externこれらの関数を呼び出しますか? または、代わりにBLASを直接呼び出しますか(または、これらのコア操作に対してnumpyが呼び出すものは何でも)?

例を挙げると、Cython に多くのことを行う関数があり、最終的に内積と逆行列を含む計算を行う必要があるとします。

cdef myfunc(...):
  # ... do many things faster than Python could
  # ...
  # compute one value using dot products and inv
  # without using 
  #   import numpy as np 
  #   np.*
  val = gammaln(sum(v)) - sum(gammaln(v)) + dot((v - 1).T, log(x).T)

これはどのように行うことができますか?Cython でこれらを実装するライブラリが既にある場合は、それも使用できますが、何も見つかりませんでした。これらの手順が直接 BLAS ほど最適化されていない場合でもnumpy、Cython から Python モジュールを呼び出すオーバーヘッドがないため、全体的に高速になります。

呼び出したい関数の例:

  • 内積 ( np.dot)
  • 逆行列 ( np.linalg.inv)
  • 行列乗算
  • 転置を取る ( x.Tnumpy に相当)
  • gammaln 関数 ( scipy.gammalnC で利用できる同等の関数)

numpy メーリング リスト ( https://groups.google.com/forum/?fromgroups=#!topic/cython-users/XZjMVSIQnTE ) で述べられているように、大きな行列でこれらの関数を呼び出すと意味がないことに気付きました。 numpyから呼び出すと、numpyが呼び出す最適化されたCコードに費やされる時間の大部分が発生するため、Cythonから実行します。ただし、私の場合、小さな行列でこれらの線形代数操作を何度も呼び出しています。その場合、Cython から numpy に戻って Cython に戻ることを繰り返すことによって生じるオーバーヘッドは、実際に操作を計算するのに費やされる時間をはるかに上回ります。 BLAS。したがって、これらの単純な操作のためにすべてを C/Cython レベルに保ち、Python を使用しないようにしたいと思います。

別の依存関係が追加され、GSL がアクティブに維持されているかどうかが不明であるため、GSL を使用しないことをお勧めします。コードのユーザーには既に scipy/numpy がインストールされていると想定しているため、これらのライブラリに関連するすべての関連 C コードを持っていると安全に想定できます。そのため、そのコードを利用して呼び出すことができるようにしたいだけですシトンから。

編集: BLAS を Cython ( https://github.com/tokyo/tokyo ) でラップするライブラリを見つけました。これは近いですが、探しているものではありません。numpy/scipy C 関数を直接呼び出したいと思います (ユーザーがこれらをインストールしていると仮定しています)。

4

3 に答える 3

25

Scipy にバンドルされている BLAS を呼び出すのは「かなり」簡単です。行列の乗算を計算するために DGEMM を呼び出す例を次に示し ます: https://gist.github.com/pv/5437087 lda/b/c パラメータ)、したがってorder="F"double[::1,:]これらは正しく機能するために必要です。

dgesv逆行列の計算は、恒等行列にLAPACK 関数を適用することで同様に実行できます。署名については、こちらを参照してください。これにはすべて、かなり低レベルのコーディングにドロップダウンする必要があり、一時的な作業配列を自分で割り当てる必要があります。 --- ただし、これらは独自の便利な関数にカプセル化するか、関数を関数ポインターtokyoに置き換えることでコードを再利用することができますlib_*上記の方法で Scipy から取得します。

Cython のメモリビュー構文 ( double[::1,:]) を使用する場合、転置はx.T通常と同じです。または、配列の要素を対角線上で交換する独自の関数を記述して、転置を計算することもできます。Numpy は実際にはこの操作を含んx.Tでおらず、配列のストライドのみを変更し、データを移動しません。

tokyoScipy によってエクスポートされた BLAS/LAPACK を使用するようにモジュールを書き直して、それを にバンドルすることはおそらく可能scipy.linalgですfrom scipy.linalg.blas cimport dgemm。誰かがそれに取り掛かりたい場合は、プルリクエストが受け入れられます。


ご覧のとおり、すべては関数ポインタを渡すことに要約されます。上記で示唆したように、Cython は実際には、関数ポインタを交換するための独自のプロトコルを提供します。例として、考えてみてくださいfrom scipy.spatial import qhull; print(qhull.__pyx_capi__)--- これらの関数は Cython 経由でアクセスできますfrom scipy.spatial.qhull cimport XXXX(ただし、これらの関数は非公開なので、そうしないでください)。

ただし、現在のところ、scipy.specialこの C-API は提供していません。しかし、scipy.special のインターフェースモジュールが Cython で書かれていることを考えると、実際にはそれを提供するのは非常に簡単です。

の重い仕事をしている関数にアクセスするための健全で移植可能な方法は現時点ではないと思いますgamln(ただし、UFuncオブジェクトをスヌープすることはできますが、それは健全な解決策ではありません:)ので、現時点ではおそらくソースコードの関連部分を scipy.special から取得してプロジェクトにバンドルするか、GSL などを使用するのが最善です。

于 2013-04-22T18:16:24.380 に答える