.__skip_array_function__
-Funktionsattribut hinzu, um das Versenden von __array_function__
-Versand zu ermöglichen. (https://github.com/numpy/numpy/pull/13389)numpy/core/overrides.py
in C für Geschwindigkeit neu implementieren (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
und 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__
sollte sich nicht auf __array_function__
(https://github.com/numpy/numpy/pull/12212)stacklevel
sollte für umschlossene Funktionen um 1 erhöht werden, damit Tracebacks auf die richtige Stelle zeigen (gh-13329).Es kann sinnvoll sein, ein vorläufiges "Dekorieren Sie alle öffentlichen NumPy-Funktionen mit @array_function_dispatch" für einige hochkarätige Funktionen zusammenzuführen und nachgeschaltete Benutzer des Protokolls aufzufordern, es auszuprobieren
Sobald wir https://github.com/numpy/numpy/pull/12099 zusammenführen, habe ich eine weitere PR bereit, die Versanddekorateure für die meisten von numpy.core
hinzufügt. Es wird ziemlich einfach sein, die Dinge zu erledigen - die Zusammenstellung dauerte weniger als eine Stunde.
cc @eric-wieser @mrocklin @mhvk @hameerabbasi
Unter https://github.com/shoyer/numpy/tree/array-function-easy-impl finden Sie np.block
, np.einsum
und eine Handvoll Multiarray-Funktionen, die vollständig in C geschrieben sind (z. B. np.concatenate
). Ich werde dies in eine Reihe von PRs aufteilen, sobald wir mit # 12099 fertig sind.
Beachten Sie, dass ich keine Tests für Überschreibungen für jede einzelne Funktion geschrieben habe. Ich möchte ein paar Integrationstests hinzufügen, wenn wir fertig sind (z. B. ein Entenarray, das alle angewendeten Vorgänge protokolliert), aber ich denke nicht, dass es produktiv wäre, Versandtests für jede einzelne Funktion zu schreiben. Die Überprüfungen in # 12099 sollten die häufigsten Fehler bei Dispatchern auffangen, und jede Codezeile in Dispatcher-Funktionen sollte von vorhandenen Tests ausgeführt werden.
@shoyer - bei den Tests stimme ich zu, dass es nicht besonders nützlich ist, Tests für jeden einzelnen zu schreiben; Stattdessen kann es innerhalb von numpy am sinnvollsten sein, die Überschreibungen in MaskedArray
relativ schnell zu verwenden.
@mhvk klingt gut für mich, obwohl ich jemanden, der MaskedArray verwendet / kennt, die Führung übernehmen lassen werde.
Siehe https://github.com/numpy/numpy/pull/12115 , https://github.com/numpy/numpy/pull/12116 , # 12119 und https://github.com/numpy/numpy/pull/ 12117 für PRs, die die Unterstützung von __array_function__
für in Python definierte Funktionen implementieren.
@shoyer -
reshape
, bot die ursprüngliche Funktionalität bereits eine Möglichkeit, sie zu überschreiben, indem eine reshape
-Methode definiert wurde. Wir lehnen dies für jede Klasse ab, die __array_function__
.np.median
wurde durch die sorgfältige Verwendung von np.asanyarray
und ufuncs sichergestellt, dass Unterklassen diese bereits verwenden können. Auf diese Funktionalität kann jedoch nicht mehr direkt zugegriffen werden.Ich denke, insgesamt sind diese beiden Dinge wahrscheinlich Vorteile, da wir die Benutzeroberfläche vereinfachen und die Implementierungen für reine ndarray
optimieren können - obwohl letztere vorschlägt, dass ndarray.__array_function__
die Konvertierungslisten usw. übernehmen sollte. auf ndarray
, damit die Implementierungen diesen Teil überspringen können). Trotzdem dachte ich, ich würde es bemerken, da ich Angst habe, dies für Quantity
ein bisschen mehr zu implementieren, als ich dachte - sowohl in Bezug auf den Arbeitsaufwand als auch auf den möglichen Leistungseinbruch.
Letzteres schlägt jedoch vor, dass ndarray .__ array_function__ die Konvertierung von Listen usw. in ndarray übernehmen sollte, damit die Implementierungen diesen Teil überspringen können.
Ich bin mir nicht sicher, ob ich hier folge.
Wir lehnen in der Tat die alte Methode zum Überschreiben von Funktionen wie reshape
und mean
, obwohl die alte Methode immer noch unvollständige Implementierungen der NumPy-API unterstützt.
Ich bin mir nicht sicher, ob ich hier folge.
Ich denke, das Problem ist, dass, wenn wir __array_function__
für eine einzelne Funktion implementieren, die vorherigen Mechanismen vollständig kaputt gehen und es keine Möglichkeit zum Failover gibt. Aus diesem Grund schlage ich vor, dass wir meinen NotImplementedButCoercible
-Vorschlag erneut prüfen.
@hameerabbasi - ja, das ist das Problem. Obwohl wir hier vorsichtig sein müssen, wie einfach wir es machen, uns auf Klebebandlösungen zu verlassen, die wir wirklich lieber loswerden würden ... (weshalb ich oben geschrieben habe, dass meine "Probleme" tatsächlich Vorteile sein können ...) . Vielleicht gibt es einen Grund, es wie in 1.16 zu versuchen und dann über die tatsächliche Erfahrung zu entscheiden, ob wir einen Rückfall von "Ignoriere meine __array_function__
für diesen Fall" bereitstellen möchten.
Betreff: Dispatcher-Stil: Meine Einstellungen zum Stil basieren auf Überlegungen zur Speicher- / Importzeit und zur Ausführlichkeit. Führen Sie ganz einfach die Disponenten zusammen, bei denen die Signatur wahrscheinlich gleich bleibt. Auf diese Weise erstellen wir die geringste Anzahl von Objekten und die Cache-Treffer sind ebenfalls höher.
Trotzdem bin ich nicht zu sehr gegen den Lambda-Stil.
Der Stil zum Schreiben von Dispatcher-Funktionen ist jetzt in einigen PRs aufgetaucht. Es wäre gut, eine konsistente Auswahl für NumPy zu treffen.
Wir haben einige Möglichkeiten:
Option 1 : Schreiben Sie für jede Funktion einen eigenen Dispatcher, z.
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):
...
Vorteile:
sin(x=1)
-> TypeError: _sin_dispatcher() got an unexpected keyword argument 'x'
.Nachteile:
Option 2 : Dispatcher-Funktionen innerhalb eines Moduls wiederverwenden, z.
def _unary_dispatcher(a):
return (a,)
@array_function_dispatch(_unary_dispatcher)
def sin(a):
...
@array_function_dispatch(_unary_dispatcher)
def cos(a):
...
Vorteile:
Nachteile:
sin(x=1)
-> TypeError: _unary_dispatcher() got an unexpected keyword argument 'x'
Option 3 : Verwenden Sie lambda
-Funktionen, wenn die Dispatcher-Definition in eine Zeile passt, z.
# 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):
...
Vorteile:
Nachteile:
TypeError: <lambda>() got an unexpected keyword argument 'x'
)@shoyer : Bearbeitet, um den zweizeiligen PEP8-Abstand hinzuzufügen, um den Aspekt "Codezeilen" realistischer zu gestalten
Beachten Sie, dass die Fehlermeldungen durch Rekonstruktion des Codeobjekts behoben werden können, obwohl dies mit Kosten für die Importzeit verbunden ist. Vielleicht lohnt es sich, nachzuforschen und @nschloes Thunfisch
Ja, das Decorator-Modul könnte auch zum Generieren der Funktionsdefinition verwendet werden (es verwendet einen etwas anderen Ansatz für die Codegenerierung, ein bisschen mehr wie namedtuple, da es exec()
).
Solange der Fehler nicht behoben ist, müssen wir uns meiner Meinung nach an die Optionen eines Dispatchers halten, der einen eindeutigen Namen hat. Ich würde die Dispatcher aus Speichergründen leicht bündeln (2), würde dann aber die Fehlermeldung sehr im Auge behalten und daher vorschlagen, den Dispatcher so etwas wie _dispatch_on_x
.
Wenn wir den Fehler ändern können, ändern sich die Dinge. Zum Beispiel kann es so einfach sein, Ausnahmen abzufangen, <lambda>
durch den Funktionsnamen im Ausnahmetext zu ersetzen und dann erneut auszulösen. (Oder macht diese Kette heutzutage etwas?)
Ich bin damit einverstanden, dass die Fehlermeldung klar sein muss, sich im Idealfall überhaupt nicht ändern sollte.
OK, im Moment denke ich, dass es am besten ist, die Verwendung von lambda
unterbrechen, es sei denn, wir haben eine Art Codegenerierung zum Laufen gebracht.
https://github.com/numpy/numpy/pull/12175 fügt einen Entwurf hinzu, wie Überschreibungen für Multiarray-Funktionen (in C geschrieben) aussehen könnten, wenn wir den Python-Wrapper-Ansatz verwenden.
@mattip wo sind wir bei der Implementierung von matmul
als Ufunc? Sobald wir alle diese __array_function__
Overrides abgeschlossen haben, ist dies meiner Meinung nach das Letzte, was wir brauchen, um die öffentliche API von NumPy vollständig überladbar zu machen. Es wäre schön, alles für NumPy 1.16 bereit zu haben!
PR # 11175, das NEP 20 implementiert, hat langsame Fortschritte gemacht. Es ist ein Blocker für PR # 11133, der den Matmul-Loop-Code enthält. Dieser muss noch aktualisiert und dann über Benchmarks überprüft werden, dass der neue Code nicht langsamer als der alte ist.
Ich habe vier PRs zur Überprüfung, die den vollständigen Satz von Überschreibungen vervollständigen sollten. Abschließende Überprüfungen / Abmeldungen / Zusammenführungen sind willkommen, damit wir ernsthaft mit dem Testen von __array_function__
! 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
Das Hinzufügen von Überschreibungen zu np.core
dass einige Pandas-Tests fehlschlugen (https://github.com/pandas-dev/pandas/issues/23172). Wir sind uns noch nicht ganz sicher, was los ist, aber wir sollten es definitiv herausfinden, bevor wir es veröffentlichen.
Unter https://github.com/numpy/numpy/issues/12225 kann ich am besten erraten, warum dies zu Testfehlern bei Dask / Pandas führt.
Einige Benchmarks für Importzeiten (auf meinem MacBook Pro mit Solid-State-Laufwerk):
decorator.decorate
(# 12226): 183.694 msMein Benchmark-Skript
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)
Irgendeine Vorstellung von der Speichernutzung (vorher / nachher)? Das ist auch nützlich, insbesondere für IoT-Anwendungen.
Wissen Sie, wie Sie die Speichernutzung für ein Modul zuverlässig messen können?
Am Samstag, den 20. Oktober 2018 um 06:56 Uhr Hameer Abbasi [email protected]
schrieb:
Irgendeine Vorstellung von der Speichernutzung (vorher / nachher)? Das ist irgendwie nützlich als
gut, besonders für IoT-Anwendungen.- -
Sie erhalten dies, weil Sie erwähnt wurden.
Antworte direkt auf diese E-Mail und sieh sie dir auf GitHub an
https://github.com/numpy/numpy/issues/12028#issuecomment-431584123 oder stumm schalten
der Faden
https://github.com/notifications/unsubscribe-auth/ABKS1k_IkrJ2YmYReaDrnkNvcH2X0-ZCks5umyuogaJpZM4W3kSC
.
Ich denke, ein Skript mit import numpy as np
schreiben, eine Sleep-Anweisung hinzuzufügen und den Prozessspeicher zu verfolgen, sollte gut genug sein. https://superuser.com/questions/581108/how-can-i-track-and-log-cpu-and-memory-usage-on-a-mac
Möchten andere Core-Entwickler unter https://github.com/numpy/numpy/pull/12163 einen kurzen Blick darauf werfen (wirklich, es enthält nur zwei Funktionen!) array_function_dispatch
zu internen Numpy-Funktionen hinzufügt.
Als Referenz ist hier der Leistungsunterschied, den ich beim Deaktivieren von __array_function__
sehe:
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.
Eine Tabelle finden Sie auch unter https://docs.google.com/spreadsheets/d/15-AFI_cmZqfkU6mo2p1znsQF2E52PEXpF68QqYqEar4/edit#gid = 0.
Es überrascht nicht, dass der größte Leistungsunterschied bei Funktionen besteht, die andere numpy-Funktionen intern viele Male aufrufen, z. B. für np.block()
.
@shoyer - Ich war etwas beunruhigt über die zusätzliche Zeit ... Wahrscheinlich sollten wir wirklich eine C-Implementierung haben, aber in der Zwischenzeit habe ich eine PR mit einigen kleinen Änderungen gemacht, die einige Zeit für den allgemeinen Fall von nur einer einzigen Zeit ndarray
. Siehe # 12321.
@shoyer - Ich habe zwei Probleme auf der Mailingliste erwähnen sind:
types
? (und nicht nur die von Argumenten, die eine Überschreibung liefern.) Es scheint hilfreich zu sein, dies für Implementierungen zu wissen. (siehe # 12327).ndarray.__array_function__
Unterklassen akzeptieren, auch wenn sie __array_function__
überschreiben? Dies wäre angesichts des Liskov-Substitutionsprinzips und angesichts der Tatsache, dass die Unterklasse bereits eine Chance auf Kaution hatte, angemessen. Dies würde bedeuten, dass die Implementierung und nicht die öffentliche Funktion in ndarray.__array_function__
. (Und etwas Ähnliches in __array_ufunc__
...) Siehe # 12328 für eine Testversion nur für __array_function__
.@shoyer - siehe # 12327 für eine schnelle Implementierung von (1) - wenn wir diesen Weg gehen, sollten wir auch den NEP anpassen.
Und # 12328 für einen Test von (2), hauptsächlich um zu sehen, wie es aussieht.
Ich bin +1 bei beiden Modifikationen hier.
Der Name der Dispatcher-Funktionen in Fehlermeldungen wurde erneut unter https://github.com/numpy/numpy/pull/12789 angezeigt , wo jemand überrascht war, TypeError: _pad_dispatcher missing 1 required positional argument
Zusätzlich zu den oben beschriebenen Alternativen https://github.com/numpy/numpy/issues/12028#issuecomment -429377396 (wir verwenden derzeit 2) werde ich eine vierte Option hinzufügen:
Option 4 : Schreiben Sie für jede Funktion einen separaten Dispatcher mit demselben Namen wie die Funktion:
def sin(a):
return (a,)
@array_function_dispatch(sin)
def sin(a):
...
def cos(a):
return (a,)
@array_function_dispatch(cos)
def cos(a):
...
Vorteile:
Nachteile:
pad
die falschen Argumente erhalten hat (aber wir haben Tests, um zu überprüfen, ob sie synchron gehalten werden).Ich denke, um den aktuellen Code am Laufen zu halten, muss die eigentliche Funktion nach dem Dispatcher kommen.
Richtig, aber wir können ihm den gleichen Namen geben wie dem Dispatcher. Der Name des Dispatchers wird überschrieben.
Es wäre großartig, benutzerdefiniertes Dispatching für Funktionen wie np.arange oder np.empty definieren zu können.
Ich denke, eine Option wäre, dass NumPy sowohl auf Skalaren als auch auf Arrays versendet. Ist das nicht mit der NEP vereinbar? Würde irgendetwas mit dieser Änderung brechen?
Weitere Informationen zu np.arange
finden Sie unter https://github.com/numpy/numpy/issues/12379.
Ich sehe nicht ein, wie np.empty()
den Versand durchführen könnte - es gibt nichts zu versenden, nur eine Form und einen D-Typ. Aber sicherlich könnte np.empty_like()
mit einer überschriebenen Form versenden - genau darum geht es bei https://github.com/numpy/numpy/pull/13046 .
Option 4 : Schreiben Sie für jede Funktion einen separaten Dispatcher mit demselben Namen wie die Funktion:
Haben Sie Einwände gegen die Einführung dieser Option? Ich denke, es ist aus Anwendersicht wahrscheinlich die freundlichste Wahl.
Ich sehe nicht ein, wie np.empty () den Versand durchführen könnte - es gibt nichts zu versenden, nur eine Form und einen D-Typ
Möglicherweise möchten Sie eine der beiden versenden. Hier ist beispielsweise ein benutzerdefiniertes Formobjekt, auf das wir möglicherweise anders versenden möchten.
Dieses Beispiel ist nicht sehr nützlich, aber die Idee ist, dass ich ein faules Objekt habe, das sich wie eine Form verhält, aber keine ganzen Zahlen zurückgibt, sondern Ausdrücke zurückgibt. Zum Beispiel wäre es schön, so etwas tun zu können:
class ExprShape:
def __getitem__(self, i):
return ('getitem', self, i)
def __len__(self):
return ('len', self)
numpy.empty(ExprShape())
Was ich überschreiben möchte, um so etwas wie ExprArray('empty', ExprShape())
.
Ja, im Prinzip könnten wir auch in Form versenden. Dies würde dem Protokoll zusätzliche Komplexität / zusätzlichen Aufwand hinzufügen. Haben Sie Anwendungsfälle, in denen die Verwendung eines Arrays als Vorlage (wie empty_like
mit shape
) nicht ausreicht?
Die anderen Fälle, an die ich denken kann, sind das Argument size
für np.random.RandomState
Methoden, aber beachten Sie, dass wir diese derzeit überhaupt nicht unterstützen - siehe http://www.numpy.org/ neps / nep-0018-array-function-protocol.html # aufrufbare -Objekte-generiert-zur Laufzeit
Haben Sie Anwendungsfälle, in denen die Verwendung eines Arrays als Vorlage (wie leer_ähnlich mit Form) nicht ausreicht?
Wenn wir eine vorhandene API verwenden, die von NumPy abhängt und transparent auf einem anderen Backend arbeiten soll, ohne den vorhandenen Quellcode zu ändern.
Nehmen wir zum Beispiel an, wir haben versucht, scipy.optimize.differential_evolution
mit NP-ähnlichen Arrays aufzurufen, die ein Aufrufdiagramm erstellen, anstatt es sofort auszuführen.
Sie können hier sehen , dass es hilfreich wäre, wenn wir np.full
ändern könnten, um ein symbolisches Array anstelle eines Standard-Numpy-Arrays zu erstellen, wenn die darin übergebene Eingabe auch symbolisch wäre.
Wenn wir eine vorhandene API verwenden, die von NumPy abhängt und transparent auf einem anderen Backend arbeiten soll, ohne den vorhandenen Quellcode zu ändern.
Dies ist im Allgemeinen nicht möglich. Explizite Array-Konstruktionen wie np.array()
definitiv neu geschrieben werden, um mit der Ententypisierung kompatibel zu sein.
In diesem Fall scheint das Umschalten von energies = np.full(num_members, np.inf)
auf energies = np.full_like(population, np.inf, shape=num_members)
eine einfache und lesbare Änderung zu sein.
Dies ist im Allgemeinen nicht möglich. Explizite Array-Konstruktionen wie np.array () müssen definitiv neu geschrieben werden, um mit der Ententypisierung kompatibel zu sein.
Gibt es einen Vorschlag für diese Art von Änderung oder sagen Sie, dass die Unterstützung des Versands von np.array
wirklich schwierig wäre und wir daher niemals zu 100% Unterstützung kommen können?
In diesem Fall scheint das Umschalten von Energien = np.full (num_members, np.inf) auf Energien = np.full_like (Bevölkerung, np.inf, Form = num_members) eine einfache und lesbare Änderung zu sein.
Bestimmt. Es gibt jedoch viele Fälle, in denen Sie entweder den Quellcode nicht kontrollieren oder Benutzer dabei unterstützen möchten, die Funktionen, die sie kennen und lieben, so gut wie möglich zu nutzen.
Es gibt andere Möglichkeiten, Benutzern diese Erfahrung zu bieten:
Diese beiden Optionen sind möglicherweise in bestimmten Fällen erforderlich (z. B. wenn Benutzer np.full
aufrufen und derzeit ein symbolisches Ergebnis zurückgeben). Wenn ich das jedoch richtig verstehe, besteht das Ziel von NEP-18 darin, zu versuchen, zu begrenzen, wann diese benötigt werden und lassen Sie die Leute in mehr Fällen das Original NumPy verwenden.
Ich verstehe, dass es hier einen Kompromiss zwischen Leistung und Komplexität gibt, und das könnte ein guter Grund sein, diese nicht zu implementieren. Es könnte Benutzer jedoch dazu zwingen, andere Mittel zu erkunden, um die gewünschte Flexibilität zu erhalten.
Gibt es einen Vorschlag für diese Art von Änderung oder sagen Sie, dass die Unterstützung des Versands von
np.array
wirklich schwierig wäre und wir daher niemals zu 100% Unterstützung kommen können?
In NEP 22 werden die Optionen hier erörtert. Ich glaube nicht, dass wir die Semantik von np.asarray()
sicher ändern können, um etwas anderes als ein numpy.ndarray
Objekt zurückzugeben - wir werden dafür ein neues Protokoll benötigen.
Das Problem ist, dass np.asarray()
derzeit die idiomatische Art des Castings in ein numpy-Array-Objekt ist, das can verwendet und erwartet, dass es genau mit numpy.ndarray
übereinstimmt, z. B. bis zum Speicherlayout.
Es gibt sicherlich viele Anwendungsfälle, in denen dies nicht der Fall ist, aber das Umschalten dieses Verhaltens würde viele nachgelagerte Codes beschädigen, sodass es sich nicht um einen Starter handelt. Nachgelagerte Projekte müssen sich zumindest für diesen Aspekt der Array-Ententypisierung entscheiden.
Ich verstehe, dass es hier einen Kompromiss zwischen Leistung und Komplexität gibt, und das könnte ein guter Grund sein, diese nicht zu implementieren. Es könnte Benutzer jedoch dazu zwingen, andere Mittel zu erkunden, um die gewünschte Flexibilität zu erhalten.
Ja. NEP 18 soll keine vollständige Lösung für Drop-In-NumPy-Alternativen sein, ist jedoch ein Schritt in diese Richtung.
Ich habe eine Überarbeitung von NEP-18 entworfen, um ein __numpy_implementation__
-Attribut hinzuzufügen:
https://github.com/numpy/numpy/pull/13305
Mir fällt ein, dass wir vergessen haben, die Funktionen in numpy.testing
zu verzerren: https://github.com/numpy/numpy/issues/13588
Ich werde das in Kürze tun ...
Es gibt eine Revision, die ich gerne bei der NEP sehen würde, insbesondere um zu klären, welche Garantien NEP-18 für Autoren von Unterklassen bietet: https://github.com/numpy/numpy/pull/13633
Ich habe die Usability-Aufgaben als abgeschlossen markiert, seit gh-13329 behoben wurde. Wir haben entschieden, dass # 13588 bis nach der Veröffentlichung von 1.17 warten kann. Damit bleiben Dokumentationsverbesserungen und arange
gh-12379 für die Aufnahme in 1.17 offen.
Es gibt auch # 13728 - ein Fehler im Dispatcher für histogram[2d]d
Damit bleiben Dokumentationsverbesserungen und der Bereich gh-12379 für die Aufnahme in 1.17 offen.
Ein Dokumentationsproblem fehlte, daher öffnete ich gh-13844. Ich denke, Dokumente sind viel wichtiger als das offene Problem arange
.
@shoyer können wir das schließen?
Hilfreichster Kommentar
In NEP 22 werden die Optionen hier erörtert. Ich glaube nicht, dass wir die Semantik von
np.asarray()
sicher ändern können, um etwas anderes als einnumpy.ndarray
Objekt zurückzugeben - wir werden dafür ein neues Protokoll benötigen.Das Problem ist, dass
np.asarray()
derzeit die idiomatische Art des Castings in ein numpy-Array-Objekt ist, das can verwendet und erwartet, dass es genau mitnumpy.ndarray
übereinstimmt, z. B. bis zum Speicherlayout.Es gibt sicherlich viele Anwendungsfälle, in denen dies nicht der Fall ist, aber das Umschalten dieses Verhaltens würde viele nachgelagerte Codes beschädigen, sodass es sich nicht um einen Starter handelt. Nachgelagerte Projekte müssen sich zumindest für diesen Aspekt der Array-Ententypisierung entscheiden.
Ja. NEP 18 soll keine vollständige Lösung für Drop-In-NumPy-Alternativen sein, ist jedoch ein Schritt in diese Richtung.