Bagaimana cara menentukan tupel dalam tanda tangan Numba Vectorize?

Saya sedang mendefinisikan suatu fungsi dan ingin menggunakan Numba Vectorize untuk mempercepatnya, dengan cuda. Saya mengalami masalah dengan tanda tangan fungsi. Fungsi ini akan mengembalikan nilai float64. Saya ingin meneruskan dua nilai float64, yang akan divektorkan, dan sebagai tambahan 9 tupel nilai float64, yang akan menjadi skalar.

Ini header fungsi saya:

from numba import vectorize

@vectorize(['float64(float64, float64, UniTuple(float64, 9))'], target='cuda')
def fn_vec(E, L, fparams):
    # calculations... 
    return result

tapi ini memberikan kesalahan:

TypeError: data type "(float64 x 9)" not understood

Saya telah mencoba banyak variasi, termasuk (float64, ..., float64) sebagai pengganti UniTuple(), tetapi tidak berhasil. Bagaimana saya melakukan ini?


person kevinea    schedule 19.04.2019    source sumber


Jawaban (1)


Bagaimana cara menentukan tupel dalam tanda tangan Numba Vectorize?

Dalam fungsi numba.vectorize Anda tidak dapat menggunakan Tuple. Itu karena vectorize membuat vektorisasi kode untuk array jenis ini.

Jadi menggunakan tanda tangan float, float, tuple membuat fungsi yang mengharapkan dua array berisi float dan satu array berisi tupel. Masalahnya adalah tidak ada dtype untuk array yang berisi tupel - ini bisa berfungsi jika Anda menggunakan array terstruktur alih-alih array yang berisi tupel tetapi saya belum mencobanya.

Bagaimana cara menentukan tupel di tanda tangan Numba jit?

Cara yang benar untuk menentukan UniTuple pada tanda tangan numba adalah dengan numba.types.containers.UniTuple. Dalam kasus Anda:

nb.types.containers.UniTuple(nb.types.float64, 9)

Jadi tanda tangan yang benar adalah seperti ini:

import numba as nb

@nb.njit(
    nb.types.float64(
        nb.types.float64, 
        nb.types.float64, 
        nb.types.containers.UniTuple(nb.types.float64, 9)))
def func(f1, f2, ftuple):
    # ...
    return f1

Saya sering menghindari mengetikkan fungsi numba saya secara eksplisit - tetapi ketika melakukannya saya merasa sangat berguna untuk menggunakan numba.typeof, misalnya:

>>> nb.typeof((1.0, ) * 9)
tuple(float64 x 9)

>>> type(nb.typeof((1.0, ) * 9))
numba.types.containers.UniTuple

>>> help(type(nb.typeof((1.0, ) * 9)))  # I shortened the result:
Help on class UniTuple in module numba.types.containers:

class UniTuple(BaseAnonymousTuple, _HomogeneousTuple, numba.types.abstract.Sequence)
 |  UniTuple(*args, **kwargs)
 |  
 |  Type class for homogeneous tuples.
 |  
 |  Methods defined here:
 |  
 |  __init__(self, dtype, count)
 |      Initialize self.  See help(type(self)) for accurate signature.

Jadi semua informasinya ada di sana: Ini adalah numba.types.containes.UniTuple dan Anda membuat instance dengan dua argumen, dtype (di sini float64) dan nomor (dalam hal ini 9).

Jika Anda ingin melakukan vektorisasi pada array float saja

Jika Anda tidak ingin memvektorkan fungsi untuk argumen Tuple, Anda cukup membuat fungsi yang divektorkan di dalam fungsi lain dan memanggilnya di sana:

import numba as nb
import numpy as np

def func(E, L, fparams):
    @nb.vectorize(['float64(float64, float64)'])
    def fn_vec(e, l):
        return e + l + fparams[1]  # just to illustrate that the tuple is available
    return fn_vec(E, L)

Ini membuat tuple tersedia di dalam fungsi vectorized. Namun ia harus membuat fungsi dalam dan mengompilasinya setiap kali Anda memanggil fungsi luar, jadi ini mungkin sebenarnya lebih lambat. Saya juga tidak yakin ini akan berhasil dengan target="cuda", Anda mungkin perlu mengujinya sendiri.

person MSeifert    schedule 20.04.2019
comment
Terima kasih atas tanggapannya. Sayangnya, ini tidak berhasil untuk saya. Saya menggunakan @vectorize, bukan @njit; mungkin itu alasannya? Saya mencoba@nb.vectorize( nb.types.float64( nb.types.float64, nb.types.float64, nb.types.containers.UniTuple(nb.types.float64, 9))) def fn_vec2(E, L, fparams): # calcs... return E tetapi saya mendapatkan TypeError: 'Signature' object is not iterable - person kevinea; 21.04.2019
comment
Vectorize mengharapkan tanda tangan yang dapat diubah, apakah Anda lupa daftar di sekitar tanda tangan? - person MSeifert; 21.04.2019
comment
Anda benar, saya lupa daftarnya. Jadi sekarang dekorator saya adalah @nb.vectorize([nb.types.float64( nb.types.float64, nb.types.float64, nb.types.containers.UniTuple(nb.types.float64, 9))]), dan saya mendapatkan kesalahan NotImplementedError: (float64 x 9) tidak dapat direpresentasikan sebagai Numpy dtype` - person kevinea; 18.05.2019
comment
@kevinea Bisakah Anda memberikan contoh kecil bagaimana Anda memanggil fungsi tersebut. Betulkah saya menyebutnya kira-kira seperti ini: fn_vec(np.ones(10), np.ones(10), tuple(np.ones(9)))? - person MSeifert; 18.05.2019
comment
Ya, itu benar sekali. Dan sekali lagi terima kasih telah merespons! - person kevinea; 19.05.2019
comment
terima kasih atas pekerjaan ini. Contoh Anda memang berfungsi sekarang, tetapi seperti yang Anda duga, ini cukup lambat ketika fungsi vektorisasi ada di fungsi dalam. Saya sudah mengonfirmasi bahwa itu berfungsi, dan target="cuda" juga berfungsi. - person kevinea; 23.05.2019