Numpy: perilaku gufunc pada bentuk yang salah

Dibuat pada 2 Jun 2020  ·  5Komentar  ·  Sumber: numpy/numpy

Dari diskusi di sini: https://github.com/numpy/numpy/pull/15162#discussion_r434122175

Contoh berikut tampaknya tidak menimbulkan kesalahan saat bentuk keluar salah atau menyiarkan masukan ke keluaran, tetapi diam-diam mengisi keluaran dengan nilai hasil + sampah.

import numpy as np
from numpy.core import _umath_tests as umt
from numpy.testing import assert_raises
a = np.arange(6).reshape(3, 2)
b = np.ones(2)
out = np.empty((5, 3))
umt.inner1d(a, b, out)
print(out)

Hasil:

[[ 1.00000000e+000  5.00000000e+000  9.00000000e+000]
 [ 6.91217735e-310 -1.45681599e+144 -1.45681599e+144]
 [-1.45681599e+144 -1.45681599e+144 -1.45681599e+144]
 [-1.45681599e+144 -1.45681599e+144 -1.45681599e+144]
 [-1.45681599e+144 -1.45681599e+144  6.32404027e-322]]
00 - Bug numpy.core numpy.ufunc

Komentar yang paling membantu

Ah, ini sangat sederhana:

diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c
index 19876d641..85820e3a0 100644
--- a/numpy/core/src/umath/ufunc_object.c
+++ b/numpy/core/src/umath/ufunc_object.c
@@ -2614,7 +2614,7 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc,
      * dimensions.
      */
     broadcast_ndim = 0;
-    for (i = 0; i < nin; ++i) {
+    for (i = 0; i < nop; ++i) {
         int n = PyArray_NDIM(op[i]) - op_core_num_dims[i];
         if (n > broadcast_ndim) {
             broadcast_ndim = n;

mungkin semua yang ada untuk itu. Kemudian kita mendapatkan penyiaran yang benar dari input ke output, dan pemikiran apa pun untuk mencela ini hanya dapat ditunda untuk diri sendiri di masa depan jika itu muncul.

EDIT: Ditambah pemeriksaan nol op ...

Semua 5 komentar

Hehe, memikirkan hal ini sebentar…. Juga ping @mhvk untuk berjaga-jaga.

Flag NPY_ITER_NO_BROADCAST , anehnya tampaknya hampir selalu digunakan dengan cara di mana Anda dapat mengambil operan itu sepenuhnya untuk penemuan bentuk (misalnya sebagai op keluaran). Tapi, itu akan menjadi pemutusan yang tidak kompatibel jika kita hanya menggunakannya untuk mengatasi masalah itu.

Jadi saya mempertimbangkan untuk menambahkan NPY_ITER_OUTPUT_OPERAND . Atau buat NPY_ITER_OUTPUT_OPERAND dan tanda lain NPY_ITER_DOES_NOT_AFFECT_SHAPE sehingga tanda operan keluaran bisa menyertakan tanda "alokasikan" dan "tidak ada siaran".

Rasanya seperti kombinasi antara mengalokasikan dan tidak ada siaran, mungkin sudah menyiratkan hal ini. Tetapi pertanyaannya adalah jika kita ingin melakukan perubahan seperti itu, secara teori hal itu dapat mempengaruhi perpustakaan eksternal yang menggunakan NpyIter. (Kecuali jika kita menjadikannya VisibleDeprecationWarning saat dijalankan, tetapi tidak yakin itu sangat rapi untuk diterapkan.)

Saya pikir itu bisa mengatasi masalah ini. Ada kasus-kasus sampingan yang menarik, seperti sumbu yang hanya digunakan oleh satu (atau lebih) larik keluaran. Seseorang dapat mencoba untuk mendukung itu (pada titik tertentu?), Tetapi itu mungkin menambahkan terlalu banyak kerumitan tanpa keuntungan nyata.
Saya benar-benar tidak melihat banyak kasus penggunaan untuk (),()->(k) gufunc. Sesuatu seperti bukan (),()->(3,3) atau ->(3,3) masuk akal tentu saja, tetapi tidak ada masalah.

Agak bingung tentang semua benderanya, harus saya akui. Tetapi seorang gufunc moments dengan tanda tangan ()->(k) mungkin bisa menghitung momen hingga k dalam keluarannya. Tentu saja, sangat tidak masuk akal, tetapi perasaan saya adalah tidak secara eksplisit mengecualikannya (atau kode secara eksplisit untuk mengizinkannya!).

Sedikit lebih relevan dengan masalah di sini, di mana keluaran memiliki bentuk luar yang tidak konsisten, adalah bahwa ada preseden dari ufunc biasa:

np.add(1, 1, out=np.empty((3,)))
# array([2., 2., 2.])

Ini juga menyarankan untuk gufunc, bentuk luar harus ditentukan dari semua input dan output. Jelas, akan menyebabkan perhitungan yang tidak perlu, tapi biarlah ...

Oh, entah bagaimana saya tidak berharap itu benar-benar berhasil. Saya kira dalam hal itu kita dapat membiarkan output menyebabkan penyiaran di input (dan dengan demikian menyesuaikan bentuknya). Pada dasarnya hanya mempertahankan perilaku saat ini.

jadi, jangan lakukan apa-apa di sini, kecuali untuk memastikan (g) ufunc dipanggil beberapa kali (ini akan menjadi cara yang lambat untuk mendapatkan hasil dalam banyak kasus, tetapi itu adalah masalah pemanggil). Meskipun menurut saya tidak penting untuk mendukung ini, saya juga melihat tidak ada masalah dengan melakukannya.

Tapi kami masih perlu memperbaiki masalah ini di gufuncs jelas!

Ah, ini sangat sederhana:

diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c
index 19876d641..85820e3a0 100644
--- a/numpy/core/src/umath/ufunc_object.c
+++ b/numpy/core/src/umath/ufunc_object.c
@@ -2614,7 +2614,7 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc,
      * dimensions.
      */
     broadcast_ndim = 0;
-    for (i = 0; i < nin; ++i) {
+    for (i = 0; i < nop; ++i) {
         int n = PyArray_NDIM(op[i]) - op_core_num_dims[i];
         if (n > broadcast_ndim) {
             broadcast_ndim = n;

mungkin semua yang ada untuk itu. Kemudian kita mendapatkan penyiaran yang benar dari input ke output, dan pemikiran apa pun untuk mencela ini hanya dapat ditunda untuk diri sendiri di masa depan jika itu muncul.

EDIT: Ditambah pemeriksaan nol op ...

Apakah halaman ini membantu?
0 / 5 - 0 peringkat