31

Python と Numpy を使用してオーディオ アルゴリズムを開発しています。ここで、そのアルゴリズムの一部を C で実装することにより、そのアルゴリズムを高速化したいと考えています。以前は、cython を使用してこれを実行しました。今度は、新しいcffiを使用して同じことをしたいと思います。

テスト目的で、単純な C 関数を作成しました。

void copy(float *in, float *out, int len) {
    for (int i=0; i<len; i++) {
        out[i] = in[i];
    }
}

ここで、2 つの numpy 配列を作成し、それらをこの関数で処理したいと考えています。私はそれを行う方法を見つけました:

import numpy as np
from cffi import FFI

ffi = FFI()
ffi.cdef("void copy(float *in, float *out, int len);")
C = ffi.dlopen("/path/to/copy.dll")

float_in = ffi.new("float[16]")
float_out = ffi.new("float[16]")

arr_in = 42*np.ones(16, dtype=np.float32)

float_in[0:16] = arr_in[0:16]
C.copy(float_in, float_out, 16)
arr_out = np.frombuffer(ffi.buffer(float_out, 16*4), dtype=np.float32)

ただし、このコードを改善したいと思います。

  1. それらをコピーせずに、numpy 配列の基になる浮動小数点バッファーに直接アクセスする方法はありますか?
  2. ffi.bufferC 配列の内容を Numpy 配列にすばやく変換するのに非常に便利です。個々の要素をコピーせずに、numpy 配列を C 配列にすばやく変換する同等の方法はありますか?
  3. 一部のアプリケーションでfloat_in[0:16] = arr_in[0:16]は、データにアクセスする便利な方法です。ただし、その逆はarr_out[0:16] = float_out[0:16]機能しません。なぜだめですか?
4

5 に答える 5

27

ndarrayのctypes属性は、ctypes モジュールと対話できます。たとえば、ndarray.ctypes.data配列のデータ アドレスです。これをポインターにキャストしてから、float *ポインターを C 関数に渡すことができます。

import numpy as np
from cffi import FFI

ffi = FFI()
ffi.cdef("void copy(float *in, float *out, int len);")
C = ffi.dlopen("ccode.dll")

a = 42*np.ones(16, dtype=np.float32)
b = np.zeros_like(a)
pa = ffi.cast("float *", a.ctypes.data)
pb = ffi.cast("float *", b.ctypes.data)

C.copy(pa, pb, len(a))
print b

質問 3 の場合:

ffi配列は、内部バッファにアクセスするために必要な情報をnumpyに提供していないと思います。そのため、numpy は失敗した浮動小数点数に変換しようとしました。

私が考えることができる最善の解決策は、最初にリストに変換することです:

float_in[0:16] = list(arr_in[0:16])
于 2013-04-30T00:17:01.697 に答える
16

これに対する更新: 最新バージョンの CFFI にはffi.from_buffer()、(numpy 配列などの) 任意のバッファー オブジェクトをchar *FFI ポインターに変換する があります。直接できるようになりました:

cptr = ffi.cast("float *", ffi.from_buffer(my_np_array))

または呼び出しの引数として直接 (char *は自動的に にキャストされますfloat *):

C.copy(ffi.from_buffer(arr_in), ffi.from_buffer(arr_out), 16)
于 2016-08-31T07:33:06.510 に答える
2

CFFI バージョン 1.12 以降、次の 1 回の呼び出しで、NumPy 配列への適切に型指定されたポインターを作成できますFFI.from_buffer

array = np.zeros(16, dtype=np.float32)
pointer = ffi.from_buffer("float[]", array)

このポインターの背後にある配列に書き込む C コードは、元の NumPy 配列を直接変更します。「結果を出す」必要はありません。

配列にメモリ レイアウトnumpy.ascontiguousarrayがない可能性がある場合は、バッファに渡す前に呼び出すことができます。C_CONTIGUOUS

于 2020-10-18T17:32:08.723 に答える