.__skip_array_function__
untuk memungkinkan melewatkan pengiriman __array_function__
. (https://github.com/numpy/numpy/pull/13389)numpy/core/overrides.py
dalam C untuk kecepatan (https://github.com/numpy/numpy/issues/12028):get_overloaded_types_and_args
array_function_implementation_or_override
ndarray.__array_function__
?array_function_dispatch
?numpy.core
np.core.defchararray
(# 12154)np.einsum
dan np.block
(https://github.com/numpy/numpy/pull/12163)numpy.lib
numpy.fft
/ numpy.linalg
(https://github.com/numpy/numpy/pull/12117)arange?
] (https://github.com/numpy/numpy/issues/12379)ndarray.__repr__
tidak boleh bergantung pada __array_function__
(https://github.com/numpy/numpy/pull/12212)stacklevel
harus ditingkatkan 1 untuk fungsi yang dibungkus, jadi traceback mengarah ke tempat yang benar (gh-13329)Mungkin bagus untuk menggabungkan "Hiasi semua fungsi NumPy publik dengan @array_function_dispatch" awal untuk beberapa fungsi profil tinggi dan meminta konsumen hilir protokol untuk mencobanya
Setelah kami menggabungkan https://github.com/numpy/numpy/pull/12099 saya memiliki PR lain yang siap yang akan menambahkan dekorator pengiriman untuk sebagian besar numpy.core
. Akan sangat mudah untuk menyelesaikan semuanya - yang ini membutuhkan waktu kurang dari satu jam untuk menyelesaikannya.
cc @ eric-werer @rocklin @hvk @hameerabbasi
Lihat https://github.com/shoyer/numpy/tree/array-function-easy-impl untuk cabang saya yang menerapkan semua penggantian "mudah" pada fungsi dengan pembungkus Python. Bagian yang tersisa adalah np.block
, np.einsum
dan beberapa fungsi multiarray yang seluruhnya ditulis dalam C (misal, np.concatenate
). Saya akan membagi ini menjadi beberapa PR setelah kita selesai dengan # 12099.
Perhatikan bahwa saya belum menulis tes untuk menimpa pada setiap fungsi individu. Saya ingin menambahkan beberapa tes integrasi ketika kita selesai (misalnya, array bebek yang mencatat semua operasi yang diterapkan), tetapi menurut saya tidak akan produktif untuk menulis tes pengiriman untuk setiap fungsi individu. Pemeriksaan di # 12099 harus menangkap kesalahan paling umum pada petugas operator, dan setiap baris kode dalam fungsi petugas operator harus dijalankan oleh pengujian yang ada.
@ shoyer - pada tes, saya setuju bahwa menulis tes untuk masing-masing tes tidak terlalu berguna; sebaliknya, dalam numpy, mungkin masuk akal untuk mulai menggunakan penggantian relatif cepat di MaskedArray
.
@mhvk kedengarannya bagus untuk saya, meskipun saya akan membiarkan orang lain yang menggunakan / tahu MaskedArray memimpinnya.
Lihat https://github.com/numpy/numpy/pull/12115 , https://github.com/numpy/numpy/pull/12116 , # 12119 dan https://github.com/numpy/numpy/pull/ 12117 untuk PR yang mengimplementasikan __array_function__
dukungan pada fungsi yang ditentukan dengan Python.
@ shoyer - melihat beberapa implementasinya, saya punya dua kekhawatiran:
reshape
, fungsionalitas asli telah menyediakan cara untuk menimpanya, dengan mendefinisikan metode reshape
. Kami secara efektif menghentikan itu untuk setiap kelas yang mendefinisikan __array_function__
.np.median
, penggunaan np.asanyarray
hati-hati dan ufuncs memastikan bahwa subclass sudah bisa menggunakannya. Tetapi fungsionalitas itu tidak dapat lagi diakses secara langsung.Saya pikir secara keseluruhan kedua hal ini mungkin menguntungkan, karena kita menyederhanakan antarmuka dan dapat membuat implementasi dioptimalkan untuk ndarray
murni - meskipun yang terakhir menyarankan bahwa ndarray.__array_function__
harus mengambil alih daftar konversi, dll., ke ndarray
, sehingga implementasi dapat melewati bagian itu). Namun, saya pikir saya akan mencatatnya karena itu membuat saya takut menerapkan ini untuk Quantity
sedikit lebih dari yang saya kira - dalam hal jumlah pekerjaan dan kemungkinan hit dalam kinerja.
meskipun yang terakhir menyarankan bahwa ndarray .__ array_function__ harus mengambil alih mengubah daftar, dll., ke ndarray, sehingga implementasi dapat melewati bagian itu).
Saya tidak yakin saya mengikuti di sini.
Kami memang secara efektif menghentikan cara lama untuk mengganti fungsi seperti reshape
dan mean
, meskipun cara lama masih mendukung implementasi API NumPy yang tidak lengkap.
Saya tidak yakin saya mengikuti di sini.
Saya pikir masalahnya adalah jika kita mengimplementasikan __array_function__
bahkan untuk satu fungsi, mekanisme sebelumnya rusak total dan tidak ada cara untuk melakukan fail-over. Itulah sebabnya saya mengusulkan agar kami mengunjungi kembali proposal NotImplementedButCoercible
.
@hameerabbasi - ya, itulah masalahnya. Meskipun kita perlu berhati-hati di sini betapa mudahnya kita membuatnya bergantung pada larutan lakban yang sebenarnya ingin kita singkirkan ... (itulah sebabnya saya tulis di atas bahwa "masalah" saya sebenarnya bisa bermanfaat ...) . Mungkin ada kasus untuk mencoba seperti di 1.16 dan kemudian memutuskan pengalaman aktual apakah kami ingin memberikan fall-back "abaikan __array_function__
untuk kasus ini".
Re: dispatcher styling: Preferensi saya pada gaya didasarkan pada pertimbangan memori / waktu impor, dan verbositas. Sederhananya, gabungkan petugas operator di mana tanda tangannya kemungkinan besar tetap sama. Dengan cara ini, kami membuat objek paling sedikit dan cache yang ditemukan akan lebih tinggi juga.
Meski begitu, saya tidak terlalu menentang gaya lambda.
Gaya penulisan fungsi dispatcher kini muncul di beberapa PR. Sebaiknya buat pilihan yang konsisten di seluruh NumPy.
Kami memiliki beberapa opsi:
Opsi 1 : Tulis dispatcher terpisah untuk setiap fungsi, misalnya,
def _sin_dispatcher(a):
return (a,)
@array_function_dispatch(_sin_dispatcher)
def sin(a):
...
def _cos_dispatcher(a):
return (a,)
@array_function_dispatch(_cos_dispatcher)
def cos(a):
...
Keuntungan:
sin(x=1)
-> TypeError: _sin_dispatcher() got an unexpected keyword argument 'x'
.Kekurangan:
Opsi 2 : Gunakan kembali fungsi operator dalam modul, misalnya,
def _unary_dispatcher(a):
return (a,)
@array_function_dispatch(_unary_dispatcher)
def sin(a):
...
@array_function_dispatch(_unary_dispatcher)
def cos(a):
...
Keuntungan:
Kekurangan:
sin(x=1)
-> TypeError: _unary_dispatcher() got an unexpected keyword argument 'x'
Opsi 3 : Gunakan fungsi lambda
ketika definisi dispatcher cocok di satu baris, misalnya,
# inline style (shorter)
@array_function_dispatch(lambda a: (a,))
def sin(a):
...
@array_function_dispatch(lambda a, n=None, axis=None, norm=None: (a,))
def fft(a, n=None, axis=-1, norm=None):
...
# multiline style (more readable?)
@array_function_dispatch(
lambda a: (a,)
)
def sin(a):
...
@array_function_dispatch(
lambda a, n=None, axis=None, norm=None: (a,)
)
def fft(a, n=None, axis=-1, norm=None):
...
Keuntungan:
Kekurangan:
TypeError: <lambda>() got an unexpected keyword argument 'x'
)@shoyer : diedit untuk menambahkan spasi dua baris PEP8 untuk membuat aspek "baris kode" lebih realistis
Perhatikan bahwa masalah pesan kesalahan dapat diperbaiki dengan merekonstruksi objek kode , meskipun itu akan menimbulkan beberapa biaya waktu impor. Mungkin perlu diselidiki, dan temukan tuna
Ya, modul dekorator juga dapat digunakan untuk menghasilkan definisi fungsi (ini menggunakan pendekatan yang sedikit berbeda untuk pembuatan kode, sedikit lebih mirip dengan nametuple yang menggunakan exec()
).
Selama kesalahan tidak terpecahkan, saya pikir kita harus tetap menggunakan opsi dengan dispatcher yang memiliki nama yang jelas. Saya akan sedikit membundel dispatcher bersama-sama (2) untuk alasan memori, meskipun kemudian akan mengingat pesan kesalahan sangat banyak, jadi saya akan menyarankan memanggil dispatcher sesuatu seperti _dispatch_on_x
.
Meskipun jika kita bisa mengubah kesalahan, banyak hal berubah. Misalnya, ini mungkin sesederhana menangkap pengecualian, mengganti <lambda>
dengan nama fungsi di teks pengecualian, dan kemudian menaikkan kembali. (Atau apakah itu rantai hari ini?)
Saya setuju bahwa pesan kesalahan harus jelas, idealnya tidak boleh berubah sama sekali.
OK, untuk saat ini saya pikir yang terbaik adalah menunda menggunakan lambda
, kecuali kita mendapatkan semacam pembuatan kode yang berfungsi.
https://github.com/numpy/numpy/pull/12175 menambahkan draf tentang apa yang menimpa fungsi multiarray (ditulis dalam C) jika kita mengambil pendekatan pembungkus Python.
@ Mattip di mana kita sedang mengimplementasikan matmul
sebagai ufunc? Setelah kita menyelesaikan semua penggantian __array_function__
, saya pikir itu adalah hal terakhir yang kita butuhkan untuk membuat API publik NumPy sepenuhnya dapat kelebihan beban. Akan menyenangkan jika semuanya siap untuk NumPy 1.16!
PR # 11175, yang menerapkan NEP 20, mengalami kemajuan yang lambat. Ini adalah pemblokir untuk PR # 11133, yang memiliki kode loop matmul. Yang itu masih perlu diperbarui dan kemudian diverifikasi melalui tolok ukur bahwa kode baru tidak lebih lambat dari yang lama.
Saya memiliki empat PR untuk ditinjau yang seharusnya menyelesaikan set penggantian lengkap. Ulasan akhir / persetujuan / penggabungan akan dihargai sehingga kita dapat mulai menguji __array_function__
dengan sungguh-sungguh! https://github.com/numpy/numpy/pull/12154 , https://github.com/numpy/numpy/pull/12163 , https://github.com/numpy/numpy/pull/12119 , https: //github.com/numpy/numpy/pull/12175
Menambahkan penggantian ke np.core
menyebabkan beberapa pengujian panda gagal (https://github.com/pandas-dev/pandas/issues/23172). Kami belum yakin apa yang sedang terjadi tetapi kami harus mencari tahu sebelum merilisnya.
Lihat https://github.com/numpy/numpy/issues/12225 untuk tebakan terbaik saya mengapa hal ini menyebabkan kegagalan pengujian di dask / pandas.
Beberapa tolok ukur waktu impor (di macbook pro saya dengan solid state drive):
decorator.decorate
(# 12226): 183,694 mdSkrip patokan saya
import numpy as np
import subprocess
times = []
for _ in range(100):
result = subprocess.run("python -X importtime -c 'import numpy'",
shell=True, capture_output=True)
last_line = result.stderr.rstrip().split(b'\n')[-1]
time = float(last_line.decode('ascii')[-15:-7].strip().rstrip())
times.append(time)
print(np.median(times) / 1e3)
Ada gagasan tentang penggunaan memori (sebelum / sesudah)? Itu juga berguna, terutama untuk aplikasi IoT.
Apakah Anda tahu cara mengukur penggunaan memori untuk sebuah modul dengan andal?
Pada Sabtu, 20 Okt 2018 pukul 6:56 Hameer Abbasi [email protected]
menulis:
Ada gagasan tentang penggunaan memori (sebelum / sesudah)? Itu berguna sebagai
baik, terutama untuk aplikasi IoT.-
Anda menerima ini karena Anda disebutkan.
Balas email ini secara langsung, lihat di GitHub
https://github.com/numpy/numpy/issues/12028#issuecomment-431584123 , atau nonaktifkan
utasnya
https://github.com/notifications/unsubscribe-auth/ABKS1k_IkrJ2YmYReaDrnkNvcH2X0-ZCks5umyuogaJpZM4W3kSC
.
Saya pikir menulis skrip berisi import numpy as np
, menambahkan pernyataan tidur dan memori proses pelacakan harus cukup baik. https://superuser.com/questions/581108/how-can-i-track-and-log-cpu-and-memory-usage-on-a-mac
Pengembang inti lainnya ingin melihat sekilas (sungguh, ini hanya mencakup dua fungsi!) Di https://github.com/numpy/numpy/pull/12163? Ini PR terakhir yang menambahkan array_function_dispatch
ke fungsi numpy internal.
Untuk referensi, inilah perbedaan kinerja yang saya lihat saat menonaktifkan __array_function__
:
before after ratio
[45718fd7] [4e5aa2cd]
<master> <disable-array-function>
+ 72.5±2ms 132±20ms 1.82 bench_io.LoadtxtCSVdtypes.time_loadtxt_dtypes_csv('complex128', 10000)
- 44.9±2μs 40.8±0.6μs 0.91 bench_ma.Concatenate.time_it('ndarray', 2)
- 15.3±0.3μs 13.3±0.7μs 0.87 bench_core.CountNonzero.time_count_nonzero_multi_axis(2, 100, <type 'object'>)
- 38.4±1μs 32.7±2μs 0.85 bench_linalg.Linalg.time_op('norm', 'longfloat')
- 68.7±3μs 56.5±3μs 0.82 bench_linalg.Linalg.time_op('norm', 'complex256')
- 80.6±4μs 65.9±1μs 0.82 bench_function_base.Median.time_even
- 82.4±2μs 66.8±3μs 0.81 bench_shape_base.Block.time_no_lists(100)
- 73.5±3μs 59.3±3μs 0.81 bench_function_base.Median.time_even_inplace
- 15.2±0.3μs 12.2±0.6μs 0.80 bench_core.CountNonzero.time_count_nonzero_multi_axis(3, 100, <type 'str'>)
- 2.20±0.1ms 1.76±0.04ms 0.80 bench_shape_base.Block2D.time_block2d((1024, 1024), 'uint64', (4, 4))
- 388±20μs 310±10μs 0.80 bench_lib.Pad.time_pad((10, 10, 10), 3, 'linear_ramp')
- 659±20μs 524±20μs 0.80 bench_linalg.Linalg.time_op('det', 'float32')
- 22.9±0.7μs 18.2±0.8μs 0.79 bench_function_base.Where.time_1
- 980±50μs 775±20μs 0.79 bench_shape_base.Block2D.time_block2d((1024, 1024), 'uint32', (4, 4))
- 36.6±1μs 29.0±1μs 0.79 bench_ma.Concatenate.time_it('unmasked', 2)
- 16.4±0.7μs 12.9±0.6μs 0.79 bench_core.CountNonzero.time_count_nonzero_axis(3, 100, <type 'str'>)
- 16.4±0.5μs 12.9±0.4μs 0.79 bench_core.CountNonzero.time_count_nonzero_axis(2, 100, <type 'object'>)
- 141±5μs 110±4μs 0.78 bench_lib.Pad.time_pad((10, 100), (0, 5), 'linear_ramp')
- 18.0±0.6μs 14.1±0.6μs 0.78 bench_core.CountNonzero.time_count_nonzero_axis(3, 100, <type 'object'>)
- 11.9±0.6μs 9.28±0.5μs 0.78 bench_core.CountNonzero.time_count_nonzero_axis(1, 100, <type 'int'>)
- 54.6±3μs 42.4±2μs 0.78 bench_function_base.Median.time_odd_small
- 317±10μs 246±7μs 0.78 bench_lib.Pad.time_pad((10, 10, 10), 1, 'linear_ramp')
- 13.8±0.5μs 10.7±0.7μs 0.77 bench_reduce.MinMax.time_min(<type 'numpy.float64'>)
- 73.3±6μs 56.6±4μs 0.77 bench_lib.Pad.time_pad((1000,), (0, 5), 'mean')
- 14.7±0.7μs 11.4±0.3μs 0.77 bench_core.CountNonzero.time_count_nonzero_axis(2, 100, <type 'str'>)
- 21.5±2μs 16.5±0.6μs 0.77 bench_reduce.MinMax.time_min(<type 'numpy.int64'>)
- 117±4μs 89.2±3μs 0.76 bench_lib.Pad.time_pad((1000,), 3, 'linear_ramp')
- 43.7±1μs 33.4±1μs 0.76 bench_linalg.Linalg.time_op('norm', 'complex128')
- 12.6±0.6μs 9.55±0.2μs 0.76 bench_core.CountNonzero.time_count_nonzero_multi_axis(2, 100, <type 'int'>)
- 636±20μs 482±20μs 0.76 bench_ma.MA.time_masked_array_l100
- 86.6±4μs 65.6±4μs 0.76 bench_lib.Pad.time_pad((1000,), (0, 5), 'linear_ramp')
- 120±4μs 90.4±2μs 0.75 bench_lib.Pad.time_pad((1000,), 1, 'linear_ramp')
- 160±5μs 119±8μs 0.74 bench_ma.Concatenate.time_it('ndarray+masked', 100)
- 14.4±0.6μs 10.7±0.3μs 0.74 bench_core.CountNonzero.time_count_nonzero_multi_axis(1, 100, <type 'str'>)
- 15.7±0.4μs 11.7±0.6μs 0.74 bench_core.CountNonzero.time_count_nonzero_multi_axis(2, 100, <type 'str'>)
- 21.8±2μs 16.1±0.7μs 0.74 bench_reduce.MinMax.time_max(<type 'numpy.int64'>)
- 11.9±0.6μs 8.79±0.3μs 0.74 bench_core.CountNonzero.time_count_nonzero_axis(2, 100, <type 'bool'>)
- 53.8±3μs 39.4±2μs 0.73 bench_function_base.Median.time_even_small
- 106±20μs 76.7±4μs 0.73 bench_function_base.Select.time_select
- 168±10μs 122±4μs 0.72 bench_shape_base.Block2D.time_block2d((512, 512), 'uint32', (2, 2))
- 12.5±0.5μs 8.96±0.4μs 0.72 bench_core.CountNonzero.time_count_nonzero_multi_axis(1, 100, <type 'int'>)
- 162±10μs 115±5μs 0.71 bench_function_base.Percentile.time_percentile
- 12.9±1μs 9.12±0.4μs 0.71 bench_random.Random.time_rng('normal')
- 9.71±0.4μs 6.88±0.3μs 0.71 bench_core.CorrConv.time_convolve(1000, 10, 'full')
- 15.1±0.8μs 10.7±0.4μs 0.71 bench_reduce.MinMax.time_max(<type 'numpy.float64'>)
- 153±9μs 108±7μs 0.71 bench_shape_base.Block2D.time_block2d((1024, 1024), 'uint8', (2, 2))
- 109±5μs 76.9±5μs 0.71 bench_ma.Concatenate.time_it('ndarray+masked', 2)
- 34.3±1μs 24.2±0.6μs 0.71 bench_linalg.Linalg.time_op('norm', 'complex64')
- 9.80±0.2μs 6.84±0.5μs 0.70 bench_core.CorrConv.time_convolve(1000, 10, 'same')
- 27.4±6μs 19.1±2μs 0.70 bench_core.CountNonzero.time_count_nonzero_axis(1, 10000, <type 'bool'>)
- 9.35±0.4μs 6.50±0.3μs 0.70 bench_core.CorrConv.time_convolve(50, 100, 'full')
- 65.2±4μs 45.2±1μs 0.69 bench_shape_base.Block.time_block_simple_row_wise(100)
- 12.9±1μs 8.89±0.3μs 0.69 bench_core.CountNonzero.time_count_nonzero_axis(3, 100, <type 'bool'>)
- 19.6±3μs 13.5±0.4μs 0.69 bench_core.CountNonzero.time_count_nonzero_multi_axis(3, 100, <type 'object'>)
- 75.6±2μs 52.1±3μs 0.69 bench_lib.Pad.time_pad((10, 10, 10), (0, 5), 'reflect')
- 12.4±1μs 8.51±0.4μs 0.69 bench_core.CountNonzero.time_count_nonzero_multi_axis(3, 100, <type 'bool'>)
- 172±30μs 117±4μs 0.68 bench_ma.Concatenate.time_it('unmasked+masked', 100)
- 23.1±0.5μs 15.8±0.9μs 0.68 bench_linalg.Linalg.time_op('norm', 'int16')
- 8.18±0.9μs 5.57±0.1μs 0.68 bench_core.CorrConv.time_correlate(1000, 10, 'full')
- 153±5μs 103±3μs 0.68 bench_function_base.Percentile.time_quartile
- 758±100μs 512±20μs 0.68 bench_linalg.Linalg.time_op('det', 'int16')
- 55.4±6μs 37.4±1μs 0.68 bench_ma.Concatenate.time_it('masked', 2)
- 234±30μs 157±5μs 0.67 bench_shape_base.Block.time_nested(100)
- 103±4μs 69.3±3μs 0.67 bench_linalg.Eindot.time_dot_d_dot_b_c
- 19.2±0.4μs 12.9±0.6μs 0.67 bench_core.Core.time_tril_l10x10
- 122±7μs 81.7±4μs 0.67 bench_lib.Pad.time_pad((10, 10, 10), 3, 'edge')
- 22.9±1μs 15.3±0.5μs 0.67 bench_linalg.Linalg.time_op('norm', 'int32')
- 16.6±2μs 11.0±0.3μs 0.66 bench_core.CountNonzero.time_count_nonzero_multi_axis(1, 100, <type 'object'>)
- 9.98±0.3μs 6.58±0.1μs 0.66 bench_core.CorrConv.time_convolve(1000, 10, 'valid')
- 118±6μs 77.9±4μs 0.66 bench_shape_base.Block2D.time_block2d((512, 512), 'uint16', (2, 2))
- 212±50μs 140±8μs 0.66 bench_lib.Pad.time_pad((10, 10, 10), (0, 5), 'mean')
- 21.9±0.7μs 14.4±0.5μs 0.66 bench_linalg.Linalg.time_op('norm', 'int64')
- 131±5μs 85.9±5μs 0.65 bench_lib.Pad.time_pad((10, 10, 10), 3, 'constant')
- 56.8±2μs 37.0±3μs 0.65 bench_lib.Pad.time_pad((1000,), (0, 5), 'constant')
- 58.9±3μs 38.1±1μs 0.65 bench_lib.Pad.time_pad((10, 100), (0, 5), 'reflect')
- 72.1±2μs 46.5±3μs 0.64 bench_lib.Pad.time_pad((10, 100), (0, 5), 'constant')
- 8.66±0.3μs 5.58±0.2μs 0.64 bench_core.CorrConv.time_correlate(50, 100, 'full')
- 300±30μs 193±10μs 0.64 bench_shape_base.Block2D.time_block2d((1024, 1024), 'uint8', (4, 4))
- 15.9±5μs 10.2±0.3μs 0.64 bench_core.CountNonzero.time_count_nonzero_axis(3, 100, <type 'int'>)
- 13.7±0.5μs 8.80±0.1μs 0.64 bench_random.Random.time_rng('uniform')
- 8.60±0.5μs 5.50±0.2μs 0.64 bench_core.CorrConv.time_correlate(1000, 10, 'same')
- 44.7±2μs 28.5±0.7μs 0.64 bench_lib.Pad.time_pad((1000,), 1, 'reflect')
- 72.7±3μs 46.2±2μs 0.64 bench_lib.Pad.time_pad((10, 10, 10), 3, 'wrap')
- 567±50μs 360±40μs 0.63 bench_shape_base.Block2D.time_block2d((512, 512), 'uint64', (2, 2))
- 58.0±3μs 36.7±2μs 0.63 bench_lib.Pad.time_pad((10, 100), 3, 'reflect')
- 219±30μs 138±7μs 0.63 bench_lib.Pad.time_pad((10, 100), 1, 'mean')
- 261±60μs 164±10μs 0.63 bench_lib.Pad.time_pad((10, 100), 1, 'linear_ramp')
- 825±100μs 519±30μs 0.63 bench_shape_base.Block2D.time_block2d((512, 512), 'uint64', (4, 4))
- 121±5μs 75.7±2μs 0.63 bench_lib.Pad.time_pad((10, 10, 10), 1, 'constant')
- 8.16±0.2μs 5.08±0.4μs 0.62 bench_core.CorrConv.time_convolve(50, 100, 'same')
- 66.6±3μs 41.3±2μs 0.62 bench_lib.Pad.time_pad((1000,), 3, 'constant')
- 53.1±3μs 32.9±0.8μs 0.62 bench_lib.Pad.time_pad((10, 100), 3, 'wrap')
- 285±60μs 177±10μs 0.62 bench_lib.Pad.time_pad((10, 10, 10), (0, 5), 'linear_ramp')
- 8.30±0.9μs 5.14±0.1μs 0.62 bench_core.CorrConv.time_correlate(1000, 10, 'valid')
- 115±3μs 71.2±3μs 0.62 bench_shape_base.Block2D.time_block2d((256, 256), 'uint64', (2, 2))
- 19.1±0.5μs 11.8±0.6μs 0.62 bench_linalg.Linalg.time_op('norm', 'float64')
- 95.3±5μs 58.6±2μs 0.62 bench_lib.Pad.time_pad((10, 100), 1, 'constant')
- 44.6±1μs 27.2±0.9μs 0.61 bench_lib.Pad.time_pad((1000,), (0, 5), 'edge')
- 447±20μs 270±10μs 0.61 bench_shape_base.Block2D.time_block2d((1024, 1024), 'uint16', (4, 4))
- 53.9±2μs 32.6±2μs 0.60 bench_lib.Pad.time_pad((10, 100), 1, 'wrap')
- 11.6±1μs 6.97±0.4μs 0.60 bench_reduce.MinMax.time_max(<type 'numpy.float32'>)
- 95.9±5μs 57.7±2μs 0.60 bench_lib.Pad.time_pad((10, 100), 3, 'constant')
- 47.2±2μs 28.2±2μs 0.60 bench_lib.Pad.time_pad((1000,), (0, 5), 'reflect')
- 5.51±0.2μs 3.27±0.07μs 0.59 bench_core.CountNonzero.time_count_nonzero(3, 100, <type 'object'>)
- 74.3±3μs 44.0±2μs 0.59 bench_lib.Pad.time_pad((10, 10, 10), (0, 5), 'wrap')
- 76.2±3μs 45.0±0.8μs 0.59 bench_lib.Pad.time_pad((10, 10, 10), 1, 'reflect')
- 57.1±1μs 33.5±2μs 0.59 bench_lib.Pad.time_pad((10, 100), (0, 5), 'wrap')
- 52.0±2μs 30.4±1μs 0.58 bench_lib.Pad.time_pad((1000,), 1, 'edge')
- 42.6±2μs 24.9±0.9μs 0.58 bench_lib.Pad.time_pad((1000,), 3, 'wrap')
- 15.0±3μs 8.73±0.3μs 0.58 bench_core.CountNonzero.time_count_nonzero_multi_axis(1, 100, <type 'bool'>)
- 16.0±3μs 9.29±0.3μs 0.58 bench_core.CountNonzero.time_count_nonzero_multi_axis(3, 100, <type 'int'>)
- 53.1±1μs 30.9±2μs 0.58 bench_lib.Pad.time_pad((1000,), 3, 'edge')
- 88.0±8μs 51.1±3μs 0.58 bench_lib.Pad.time_pad((10, 10, 10), 3, 'reflect')
- 44.6±2μs 25.9±1μs 0.58 bench_lib.Pad.time_pad((1000,), (0, 5), 'wrap')
- 90.3±5μs 51.9±1μs 0.57 bench_shape_base.Block2D.time_block2d((512, 512), 'uint8', (2, 2))
- 15.6±0.5μs 8.93±0.3μs 0.57 bench_linalg.Linalg.time_op('norm', 'float32')
- 102±6μs 58.3±0.9μs 0.57 bench_lib.Pad.time_pad((10, 10, 10), 1, 'edge')
- 80.1±4μs 45.6±3μs 0.57 bench_lib.Pad.time_pad((10, 100), 3, 'edge')
- 44.2±2μs 24.9±1μs 0.56 bench_lib.Pad.time_pad((1000,), 1, 'wrap')
- 71.6±8μs 39.5±1μs 0.55 bench_lib.Pad.time_pad((10, 10, 10), 1, 'wrap')
- 81.7±10μs 44.8±2μs 0.55 bench_lib.Pad.time_pad((10, 100), 1, 'edge')
- 420±90μs 230±10μs 0.55 bench_shape_base.Block.time_3d(10, 'block')
- 114±20μs 62.3±2μs 0.55 bench_lib.Pad.time_pad((10, 10, 10), (0, 5), 'constant')
- 5.76±0.1μs 3.13±0.08μs 0.54 bench_core.CorrConv.time_convolve(50, 10, 'same')
- 5.30±0.1μs 2.84±0.08μs 0.54 bench_core.CorrConv.time_correlate(50, 100, 'valid')
- 92.5±4μs 49.3±1μs 0.53 bench_shape_base.Block2D.time_block2d((256, 256), 'uint32', (2, 2))
- 13.5±3μs 7.07±0.2μs 0.52 bench_reduce.MinMax.time_min(<type 'numpy.float32'>)
- 7.66±1μs 3.88±0.2μs 0.51 bench_core.CorrConv.time_convolve(50, 100, 'valid')
- 29.0±3μs 14.5±0.8μs 0.50 bench_shape_base.Block.time_no_lists(10)
- 6.62±0.3μs 3.30±0.2μs 0.50 bench_core.CorrConv.time_convolve(1000, 1000, 'valid')
- 74.2±7μs 36.2±0.9μs 0.49 bench_shape_base.Block2D.time_block2d((256, 256), 'uint16', (2, 2))
- 5.55±0.3μs 2.70±0.2μs 0.49 bench_core.CorrConv.time_convolve(50, 10, 'valid')
- 73.9±20μs 35.8±2μs 0.48 bench_lib.Pad.time_pad((10, 100), 1, 'reflect')
- 224±20μs 107±7μs 0.48 bench_shape_base.Block2D.time_block2d((256, 256), 'uint64', (4, 4))
- 3.87±0.1μs 1.83±0.06μs 0.47 bench_core.CountNonzero.time_count_nonzero(2, 100, <type 'str'>)
- 109±30μs 51.5±3μs 0.47 bench_lib.Pad.time_pad((10, 10, 10), (0, 5), 'edge')
- 240±20μs 112±4μs 0.47 bench_shape_base.Block2D.time_block2d((512, 512), 'uint16', (4, 4))
- 337±40μs 158±7μs 0.47 bench_shape_base.Block2D.time_block2d((512, 512), 'uint32', (4, 4))
- 188±8μs 88.0±2μs 0.47 bench_shape_base.Block2D.time_block2d((512, 512), 'uint8', (4, 4))
- 4.39±0.2μs 2.04±0.09μs 0.47 bench_core.CountNonzero.time_count_nonzero(3, 10000, <type 'bool'>)
- 73.2±4μs 33.9±0.5μs 0.46 bench_shape_base.Block2D.time_block2d((128, 128), 'uint64', (2, 2))
- 5.48±1μs 2.44±0.1μs 0.45 bench_core.CountNonzero.time_count_nonzero(2, 100, <type 'object'>)
- 4.46±0.1μs 1.97±0.08μs 0.44 bench_core.CorrConv.time_correlate(50, 10, 'full')
- 30.4±9μs 13.3±0.3μs 0.44 bench_shape_base.Block.time_no_lists(1)
- 7.05±0.2μs 3.05±0.06μs 0.43 bench_reduce.SmallReduction.time_small
- 7.35±1μs 3.12±0.2μs 0.42 bench_core.CorrConv.time_convolve(50, 10, 'full')
- 4.36±0.1μs 1.84±0.07μs 0.42 bench_core.CorrConv.time_correlate(50, 10, 'same')
- 3.51±0.2μs 1.46±0.05μs 0.42 bench_core.CountNonzero.time_count_nonzero(1, 100, <type 'object'>)
- 4.03±0.05μs 1.66±0.1μs 0.41 bench_core.CorrConv.time_correlate(1000, 1000, 'valid')
- 199±10μs 80.1±3μs 0.40 bench_shape_base.Block2D.time_block2d((256, 256), 'uint32', (4, 4))
- 3.98±0.2μs 1.60±0.08μs 0.40 bench_core.CountNonzero.time_count_nonzero(2, 10000, <type 'bool'>)
- 61.8±2μs 24.8±1μs 0.40 bench_shape_base.Block2D.time_block2d((256, 256), 'uint8', (2, 2))
- 4.13±0.1μs 1.62±0.05μs 0.39 bench_core.CorrConv.time_correlate(50, 10, 'valid')
- 61.6±2μs 23.9±1μs 0.39 bench_shape_base.Block2D.time_block2d((128, 128), 'uint32', (2, 2))
- 184±10μs 70.5±3μs 0.38 bench_shape_base.Block2D.time_block2d((256, 256), 'uint16', (4, 4))
- 56.1±4μs 21.0±0.9μs 0.38 bench_shape_base.Block2D.time_block2d((64, 64), 'uint64', (2, 2))
- 40.0±2μs 15.0±0.6μs 0.37 bench_shape_base.Block.time_block_simple_column_wise(10)
- 121±2μs 45.1±2μs 0.37 bench_shape_base.Block.time_nested(1)
- 179±4μs 66.1±4μs 0.37 bench_shape_base.Block2D.time_block2d((128, 128), 'uint64', (4, 4))
- 59.8±2μs 22.0±1μs 0.37 bench_shape_base.Block2D.time_block2d((128, 128), 'uint16', (2, 2))
- 3.19±0.05μs 1.17±0.02μs 0.37 bench_core.CountNonzero.time_count_nonzero(1, 100, <type 'str'>)
- 54.0±3μs 19.7±1μs 0.37 bench_shape_base.Block2D.time_block2d((32, 32), 'uint64', (2, 2))
- 56.9±1μs 20.7±0.7μs 0.36 bench_shape_base.Block2D.time_block2d((64, 64), 'uint32', (2, 2))
- 3.14±0.1μs 1.14±0.04μs 0.36 bench_core.CountNonzero.time_count_nonzero(1, 10000, <type 'bool'>)
- 92.7±2μs 33.7±2μs 0.36 bench_shape_base.Block.time_block_complicated(1)
- 104±4μs 37.8±1μs 0.36 bench_shape_base.Block.time_block_complicated(10)
- 128±5μs 45.5±2μs 0.36 bench_shape_base.Block.time_nested(10)
- 196±100μs 69.4±3μs 0.35 bench_ma.Concatenate.time_it('unmasked+masked', 2)
- 153±5μs 53.9±2μs 0.35 bench_shape_base.Block2D.time_block2d((128, 128), 'uint16', (4, 4))
- 39.4±2μs 13.8±0.5μs 0.35 bench_shape_base.Block.time_block_simple_column_wise(1)
- 53.5±2μs 18.7±1μs 0.35 bench_shape_base.Block2D.time_block2d((32, 32), 'uint8', (2, 2))
- 55.2±2μs 19.3±0.6μs 0.35 bench_shape_base.Block2D.time_block2d((32, 32), 'uint16', (2, 2))
- 16.9±1μs 5.89±0.5μs 0.35 bench_core.Core.time_dstack_l
- 60.6±3μs 21.1±0.6μs 0.35 bench_shape_base.Block2D.time_block2d((128, 128), 'uint8', (2, 2))
- 25.5±0.2μs 8.88±0.3μs 0.35 bench_shape_base.Block.time_block_simple_row_wise(10)
- 54.6±3μs 19.0±0.6μs 0.35 bench_shape_base.Block2D.time_block2d((16, 16), 'uint64', (2, 2))
- 52.6±2μs 18.2±0.7μs 0.35 bench_shape_base.Block2D.time_block2d((16, 16), 'uint16', (2, 2))
- 6.57±2μs 2.25±0.08μs 0.34 bench_core.CountNonzero.time_count_nonzero(3, 100, <type 'str'>)
- 24.3±1μs 8.30±0.6μs 0.34 bench_shape_base.Block.time_block_simple_row_wise(1)
- 148±3μs 50.0±3μs 0.34 bench_shape_base.Block2D.time_block2d((16, 16), 'uint32', (4, 4))
- 171±8μs 57.9±4μs 0.34 bench_shape_base.Block2D.time_block2d((256, 256), 'uint8', (4, 4))
- 159±5μs 53.8±1μs 0.34 bench_shape_base.Block2D.time_block2d((64, 64), 'uint64', (4, 4))
- 171±20μs 57.7±2μs 0.34 bench_shape_base.Block2D.time_block2d((128, 128), 'uint32', (4, 4))
- 3.15±0.3μs 1.06±0.03μs 0.34 bench_core.CountNonzero.time_count_nonzero(3, 100, <type 'int'>)
- 55.7±5μs 18.7±0.2μs 0.34 bench_shape_base.Block2D.time_block2d((16, 16), 'uint8', (2, 2))
- 158±7μs 52.6±3μs 0.33 bench_shape_base.Block2D.time_block2d((128, 128), 'uint8', (4, 4))
- 153±4μs 50.7±1μs 0.33 bench_shape_base.Block2D.time_block2d((32, 32), 'uint64', (4, 4))
- 152±7μs 50.3±1μs 0.33 bench_shape_base.Block2D.time_block2d((16, 16), 'uint8', (4, 4))
- 53.6±3μs 17.7±0.4μs 0.33 bench_shape_base.Block2D.time_block2d((16, 16), 'uint32', (2, 2))
- 156±4μs 51.4±3μs 0.33 bench_shape_base.Block2D.time_block2d((64, 64), 'uint8', (4, 4))
- 148±3μs 48.2±2μs 0.33 bench_shape_base.Block2D.time_block2d((16, 16), 'uint16', (4, 4))
- 160±10μs 52.0±1μs 0.33 bench_shape_base.Block2D.time_block2d((64, 64), 'uint32', (4, 4))
- 159±8μs 51.4±3μs 0.32 bench_shape_base.Block2D.time_block2d((64, 64), 'uint16', (4, 4))
- 59.8±3μs 19.3±1μs 0.32 bench_shape_base.Block2D.time_block2d((32, 32), 'uint32', (2, 2))
- 153±4μs 49.4±2μs 0.32 bench_shape_base.Block2D.time_block2d((32, 32), 'uint32', (4, 4))
- 15.6±0.6μs 5.03±0.3μs 0.32 bench_core.Core.time_vstack_l
- 154±7μs 49.7±2μs 0.32 bench_shape_base.Block2D.time_block2d((32, 32), 'uint8', (4, 4))
- 59.6±6μs 19.1±0.8μs 0.32 bench_shape_base.Block2D.time_block2d((64, 64), 'uint8', (2, 2))
- 3.03±0.4μs 969±30ns 0.32 bench_core.CountNonzero.time_count_nonzero(2, 100, <type 'int'>)
- 120±10μs 38.4±2μs 0.32 bench_shape_base.Block.time_3d(1, 'block')
- 156±5μs 49.3±1μs 0.32 bench_shape_base.Block2D.time_block2d((16, 16), 'uint64', (4, 4))
- 164±10μs 49.3±2μs 0.30 bench_shape_base.Block2D.time_block2d((32, 32), 'uint16', (4, 4))
- 65.7±10μs 19.6±0.7μs 0.30 bench_shape_base.Block2D.time_block2d((64, 64), 'uint16', (2, 2))
- 2.82±0.08μs 732±30ns 0.26 bench_core.CountNonzero.time_count_nonzero(1, 100, <type 'int'>)
- 2.77±0.07μs 664±30ns 0.24 bench_core.CountNonzero.time_count_nonzero(2, 100, <type 'bool'>)
- 2.61±0.1μs 624±20ns 0.24 bench_core.CountNonzero.time_count_nonzero(1, 100, <type 'bool'>)
- 16.8±3μs 3.97±0.2μs 0.24 bench_core.Core.time_hstack_l
- 2.78±0.1μs 637±20ns 0.23 bench_core.CountNonzero.time_count_nonzero(3, 100, <type 'bool'>)
- 2.36±0.2μs 207±5ns 0.09 bench_overrides.ArrayFunction.time_mock_broadcast_to_numpy
- 2.68±0.1μs 221±7ns 0.08 bench_overrides.ArrayFunction.time_mock_concatenate_numpy
- 2.58±0.1μs 201±10ns 0.08 bench_overrides.ArrayFunction.time_mock_broadcast_to_duck
- 3.02±0.2μs 222±6ns 0.07 bench_overrides.ArrayFunction.time_mock_concatenate_duck
- 4.29±0.3μs 216±6ns 0.05 bench_overrides.ArrayFunction.time_mock_concatenate_mixed
- 142±20μs 213±8ns 0.00 bench_overrides.ArrayFunction.time_mock_concatenate_many
SOME BENCHMARKS HAVE CHANGED SIGNIFICANTLY.
lihat juga https://docs.google.com/spreadsheets/d/15-AFI_cmZqfkU6mo2p1znsQF2E52PEXpF68QqYqEar4/edit#gid = 0 untuk spreadsheet.
Tidak mengherankan, perbedaan performa terbesar adalah untuk fungsi yang memanggil fungsi numpy lainnya secara internal berkali-kali, misalnya untuk np.block()
.
@shoyer - Saya sedikit bingung dengan waktu ekstra yang diambil ... Mungkin, kita benar-benar harus menerapkan C, tetapi sementara itu saya membuat PR dengan beberapa perubahan kecil yang memangkas beberapa waktu untuk kasus umum hanya satu jenis, dan untuk kasus di mana satu-satunya jenis adalah ndarray
. Lihat # 12321.
@shoyer - Saya mengangkat dua masalah di milis yang mungkin bagus untuk
types
? (bukan hanya argumen yang memberikan timpaan.) Tampaknya bermanfaat untuk mengetahui implementasi. (lihat # 12327).ndarray.__array_function__
menerima subclass meskipun mereka menimpa __array_function__
? Hal ini masuk akal mengingat prinsip substitusi Liskov dan subclass tersebut sudah memiliki kesempatan untuk mendapatkan jaminan. Ini akan menyiratkan memanggil implementasi daripada fungsi publik di dalam ndarray.__array_function__
. (Dan sesuatu yang serupa di __array_ufunc__
...) Lihat # 12328 untuk percobaan seharga __array_function__
saja.@ shoyer - lihat # 12327 untuk implementasi cepat (1) - jika kita melakukan rute ini, saya pikir kita juga harus menyesuaikan NEP.
Dan # 12328 untuk uji coba (2), sebagian besar untuk melihat tampilannya.
Saya memberi +1 pada kedua modifikasi di sini.
Nama fungsi dispatcher dalam pesan kesalahan muncul lagi di https://github.com/numpy/numpy/pull/12789 , di mana seseorang terkejut melihat TypeError: _pad_dispatcher missing 1 required positional argument
Selain alternatif yang diuraikan di atas https://github.com/numpy/numpy/issues/12028#issuecomment -429377396 (saat ini kami menggunakan 2), saya akan menambahkan opsi keempat:
Opsi 4 : Tulis dispatcher terpisah untuk setiap fungsi, dengan nama yang sama dengan fungsinya:
def sin(a):
return (a,)
@array_function_dispatch(sin)
def sin(a):
...
def cos(a):
return (a,)
@array_function_dispatch(cos)
def cos(a):
...
Keuntungan:
Kekurangan:
pad
menerima argumen yang salah (tetapi kami memiliki tes untuk memverifikasi bahwa mereka tetap sinkron).Saya pikir untuk menjaga kode saat ini bekerja, fungsi sebenarnya harus datang _setelah_ operator.
Benar, tapi kita bisa memberinya nama yang sama dengan petugas operator. Nama petugas operator akan ditimpa.
Akan sangat bagus untuk dapat mendefinisikan pengiriman kustom untuk fungsi seperti np.arange atau np.empty.
Saya kira satu pilihan adalah untuk NumPy untuk mengirimkan skalar serta array. Apakah ini tidak sesuai dengan NEP? Apakah ada yang akan merusak perubahan ini?
Untuk diskusi tentang np.arange
, lihat https://github.com/numpy/numpy/issues/12379.
Saya tidak melihat bagaimana np.empty()
dapat melakukan pengiriman - tidak ada yang perlu dikirim, hanya bentuk dan tipe. Tapi tentu saja np.empty_like()
dapat melakukan pengiriman dengan bentuk yang ditimpa - itulah yang https://github.com/numpy/numpy/pull/13046 tentang dukungan.
Opsi 4 : Tulis dispatcher terpisah untuk setiap fungsi, dengan nama yang sama dengan fungsinya:
Adakah keberatan untuk mengadopsi opsi ini? Saya pikir itu mungkin pilihan paling ramah dari sudut pandang pengguna.
Saya tidak melihat bagaimana np.empty () dapat melakukan pengiriman - tidak ada yang perlu dikirim, hanya bentuk dan tipe
Anda mungkin ingin mengirimkan salah satu dari itu. Misalnya, berikut adalah objek bentuk kustom, yang mungkin ingin kami kirim secara berbeda.
Contoh ini tidak terlalu berguna, tetapi idenya adalah saya memiliki objek malas yang berperilaku seperti bentuk, tetapi tidak mengembalikan bilangan bulat, ia mengembalikan ekspresi. Misalnya, alangkah baiknya bisa melakukan sesuatu seperti ini:
class ExprShape:
def __getitem__(self, i):
return ('getitem', self, i)
def __len__(self):
return ('len', self)
numpy.empty(ExprShape())
Yang mana yang ingin saya ganti untuk mengembalikan sesuatu seperti ExprArray('empty', ExprShape())
.
Ya, pada prinsipnya kami juga dapat mengirimkan sesuai bentuk. Itu akan menambah kompleksitas / overhead tambahan ke protokol. Apakah Anda memiliki kasus penggunaan di mana menggunakan array sebagai template (seperti empty_like
dengan shape
) tidak cukup?
Kasus lain yang dapat saya pikirkan adalah argumen size
menjadi np.random.RandomState
metode, tetapi perhatikan bahwa saat ini kami tidak mendukungnya sama sekali - lihat http://www.numpy.org/ neps / nep-0018-array-function-protocol.html # callable -objects-generated-at-runtime
Apakah Anda memiliki kasus penggunaan di mana menggunakan array sebagai template (seperti empty_like with shape) tidak cukup?
Jika kita menggunakan API yang ada yang bergantung pada NumPy dan ingin membuatnya bekerja secara transparan pada backend yang berbeda, tanpa mengubah kode sumber yang ada.
Sebagai contoh, katakanlah kita mencoba memanggil scipy.optimize.differential_evolution
dengan NP seperti array, yang membangun grafik panggilan alih-alih langsung dieksekusi.
Anda dapat melihat di sini akan sangat membantu jika kita dapat mengubah np.full
untuk membuat array simbolik daripada array numpy default, jika input yang dilewatkan juga simbolik.
Jika kita menggunakan API yang ada yang bergantung pada NumPy dan ingin membuatnya bekerja secara transparan pada backend yang berbeda, tanpa mengubah kode sumber yang ada.
Ini tidak mungkin secara umum. Konstruksi array eksplisit seperti np.array()
pasti perlu ditulis ulang agar kompatibel dengan pengetikan bebek.
Dalam kasus ini, mengalihkan energies = np.full(num_members, np.inf)
ke energies = np.full_like(population, np.inf, shape=num_members)
sepertinya merupakan perubahan yang mudah dan dapat dibaca.
Ini tidak mungkin secara umum. Konstruksi array eksplisit seperti np.array () pasti perlu ditulis ulang agar kompatibel dengan pengetikan bebek.
Apakah ada usulan untuk membuat perubahan semacam ini atau apakah Anda mengatakan bahwa mendukung pengiriman np.array
akan sangat sulit sehingga kami tidak bisa mendapatkan dukungan 100%?
Dalam kasus ini, mengalihkan energi = np.full (num_members, np.inf) ke energi = np.full_like (populasi, np.inf, shape = num_members) tampak seperti perubahan yang mudah dan dapat dibaca.
Pastinya. Namun ada banyak kasus di mana Anda tidak mengontrol kode sumber, atau Anda ingin mendukung pengguna dalam menggunakan fungsi yang mereka kenal dan sukai sebanyak mungkin.
Ada cara lain untuk memberikan pengalaman tersebut kepada pengguna seperti:
Kedua opsi tersebut mungkin diperlukan dalam kasus tertentu (seperti membiarkan pengguna memanggil np.full
dan mengembalikan hasil simbolis saat ini), tetapi jika saya mengerti dengan benar, tujuan NEP-18 adalah mencoba membatasi kapan itu diperlukan dan biarkan orang menggunakan NumPy asli dalam lebih banyak kasus.
Saya memahami ada tradeoff kinerja / kompleksitas di sini dan itu mungkin alasan yang baik untuk tidak menerapkannya. Tapi mungkin memaksa pengguna untuk mengeksplorasi cara lain untuk mendapatkan fleksibilitas yang mereka inginkan.
Apakah ada usulan untuk membuat perubahan semacam ini atau apakah Anda mengatakan bahwa mendukung pengiriman
np.array
akan sangat sulit sehingga kami tidak bisa mendapatkan dukungan 100%?
NEP 22 membahas beberapa opsi di sini. Saya tidak berpikir kita dapat dengan aman mengubah semantik np.asarray()
untuk mengembalikan apa pun selain objek numpy.ndarray
- kita akan membutuhkan protokol baru untuk ini.
Masalahnya adalah bahwa np.asarray()
saat ini merupakan cara idiomatis untuk mentransmisikan ke objek array numpy, yang menggunakan can dan memang mengharapkan untuk sama persis dengan numpy.ndarray
, misalnya, ke tata letak memori.
Tentu ada banyak kasus penggunaan yang tidak terjadi, tetapi mengalihkan perilaku ini akan merusak banyak kode downstream, jadi ini bukan pemulai. Proyek hilir harus memilih setidaknya aspek pengetikan bebek array ini.
Saya memahami ada tradeoff kinerja / kompleksitas di sini dan itu mungkin alasan yang baik untuk tidak menerapkannya. Tapi mungkin memaksa pengguna untuk mengeksplorasi cara lain untuk mendapatkan fleksibilitas yang mereka inginkan.
Iya. NEP 18 tidak dimaksudkan sebagai solusi lengkap untuk alternatif NumPy drop-in, tetapi merupakan langkah ke arah itu.
Saya telah menyusun revisi NEP-18 untuk menambahkan atribut __numpy_implementation__
:
https://github.com/numpy/numpy/pull/13305
Terpikir oleh saya bahwa kita lupa membengkokkan fungsi di numpy.testing
: https://github.com/numpy/numpy/issues/13588
Saya akan segera melakukannya ...
Ada satu revisi yang ingin saya lihat pada NEP, khususnya untuk mengklarifikasi jaminan apa yang ditawarkan NEP-18 kepada penulis subkelas: https://github.com/numpy/numpy/pull/13633
Saya menandai tugas kegunaan selesai sejak gh-13329 diperbaiki. Kami memutuskangh- # 13588 bisa menunggu sampai setelah rilis 1,17. Itu membuat perbaikan dokumentasi dan arange
gh-12379 masih terbuka untuk dimasukkan dalam 1.17.
Ada juga # 13728 - bug di operator untuk histogram[2d]d
Itu membuat perbaikan dokumentasi dan arange gh-12379 masih terbuka untuk dimasukkan dalam 1,17.
Masalah dokumentasi hilang, jadi saya membuka gh-13844. Menurut saya dokumen jauh lebih penting daripada terbitan terbuka arange
.
@ shoyer bisakah kita menutup ini?
Komentar yang paling membantu
NEP 22 membahas beberapa opsi di sini. Saya tidak berpikir kita dapat dengan aman mengubah semantik
np.asarray()
untuk mengembalikan apa pun selain objeknumpy.ndarray
- kita akan membutuhkan protokol baru untuk ini.Masalahnya adalah bahwa
np.asarray()
saat ini merupakan cara idiomatis untuk mentransmisikan ke objek array numpy, yang menggunakan can dan memang mengharapkan untuk sama persis dengannumpy.ndarray
, misalnya, ke tata letak memori.Tentu ada banyak kasus penggunaan yang tidak terjadi, tetapi mengalihkan perilaku ini akan merusak banyak kode downstream, jadi ini bukan pemulai. Proyek hilir harus memilih setidaknya aspek pengetikan bebek array ini.
Iya. NEP 18 tidak dimaksudkan sebagai solusi lengkap untuk alternatif NumPy drop-in, tetapi merupakan langkah ke arah itu.