Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Il pacchetto System.Numerics.Tensors fornisce Tensor<T>, TensorSpan<T>e ReadOnlyTensorSpan<T> per i dati multidimensionali. Le shape dei tensori descrivono le dimensioni logiche; gli stride descrivono la distanza, in elementi, tra posizioni successive lungo ogni dimensione.
Il comportamento descritto qui è incluso nel pacchetto nei framework di destinazione supportati. L'aggiornamento del pacchetto può influire sulle app destinate a versioni precedenti di .NET.
Questi tipi condividono molte convenzioni con NumPy, ma non sono intercambiabili. Tenere conto delle differenze seguenti quando si esegue il porting di un algoritmo.
Forme vuote e risultati scalari
Quando si crea un tensore da una forma vuota ([]) senza dati sottostanti, il tensore ha forma [0] e nessun elemento. In NumPy la shape () ha rango zero e contiene un elemento scalare. In particolare, np.empty(()) alloca un scalare con un valore non inizializzato; "vuoto" non significa che non abbia elementi.
Al contrario, quando si omettono le lunghezze in un costruttore tensor-span su dati esistenti, il costruttore deduce una forma unidimensionale dalla matrice o dallo span fornito.
Quando si comprime un tensore con forma [1, 1], il risultato ha la forma [1], non la forma () di rango zero di NumPy. Entrambi i risultati contengono un elemento e possono essere sottoposti a broadcast come uno scalare, ma il codice che esamina il rango, seleziona gli assi o indicizza il risultato deve tenere conto della dimensione mantenuta.
Quando gli stride vengono omessi, qualsiasi forma che contiene una dimensione di lunghezza zero ha zero stride in ogni dimensione. Il numero di elementi e lo spazio di archiviazione richiesto sono zero, indipendentemente dalle lunghezze delle altre dimensioni. Le lunghezze negative rimangono non valide. Gli stride espliciti devono comunque soddisfare la convalida del layout.
Stride e dati invertiti
Le stride devono essere non negative. NumPy può rappresentare una visualizzazione invertita con uno stride negativo, ad esempio array[::-1].
Per invertire il primo asse, chiamare Tensor.ReverseDimension con la dimensione 0:
using System.Numerics.Tensors;
Tensor<int> source = Tensor.Create(new[] { 1, 2, 3, 4 }, new nint[] { 2, 2 });
Tensor<int> reversed = Tensor.ReverseDimension<int>(source.AsReadOnlyTensorSpan(), 0);
Gli elementi logici di reversed sono [3, 4, 1, 2]. L'overload di allocazione produce un nuovo tensore; non è una vista con stride negativo sulla memoria originale.
Ridimensionare un tensore
Tensor.Resize e Tensor.ResizeTo riempiono gli elementi logici aggiunti con default(T). Ad esempio, se si aumentano [1, 2] fino a cinque int elementi, il risultato contiene [1, 2, 0, 0, 0]. Il np.resize di NumPy invece ripete l'input e produce [1, 2, 1, 2, 1].
Se la destinazione è più piccola, l'operazione rimuove gli elementi oltre il numero di elementi logici della destinazione. Se è più grande, l'operazione inizializza gli elementi di destinazione logici rimanenti anche quando la destinazione presenta spazi vuoti tra gli elementi. L'archiviazione all'esterno della destinazione logica non fa parte dell'operazione di ridimensionamento.
Tensor.ResizeTo e la concatenazione in una destinazione esistente rifiutano una dimensione zero-stride che contiene più di un elemento logico. Tale dimensione fa sì che più posizioni di output facciano riferimento alla stessa memoria e non possano contenere valori di output distinti. Gli stride pari a zero nelle dimensioni singleton e le destinazioni vuote non creano questo conflitto.
Sorgenti e destinazioni sovrapposte
Gli oggetti tensor e gli intervalli separati possono fare riferimento a aree sovrapposte dello stesso array. I casi supportati dipendono sia dall'operazione che dal layout:
| Operazione | Sovrapposizione supportata |
|---|---|
CopyTo e TryCopyTo |
Origine e destinazione dense con conteggi di elementi uguali o viste esattamente identiche. Le copie dense usano la copia di intervalli sicura in caso di sovrapposizione. |
FlattenTo e TryFlattenTo |
Una fonte densa e l'estensione di destinazione. |
| Operazioni element per elemento con una destinazione | Un input e un output hanno lo stesso riferimento iniziale, lunghezze e passi, purché la vista non includa posizioni di archiviazione logiche ripetute. Ogni input viene controllato in modo indipendente. |
Tensor.ResizeTo |
Sorgente e destinazione dense. La sovrapposizione strided non supportata viene rifiutata. |
| Ritorno nella stessa visualizzazione | Una visualizzazione densa può essere invertita direttamente. Sono supportate anche le inversione no-op. |
Altri layout sovrapposti non supportati generano un'eccezione ArgumentException prima che l'operazione scriva l'output. Un tensore denso da solo non garantisce il supporto per ogni operazione: ad esempio, una destinazione densa spostata è supportata per una copia, ma non per un'operazione elementwise.
I TryCopyTo metodi e TryFlattenTo restituiscono false senza copiare quando la destinazione è troppo breve.
TryCopyTo restituisce false anche per forme di origine e di destinazione incompatibili. Per le forme compatibili con capacità di destinazione sufficiente, questi metodi possono comunque generare un'eccezione per sovrapposizione non supportata; Try non elimina le eccezioni di layout non valide.
Ad esempio, la sorgente strided seguente e la destinazione di arrivo densa si sovrappongono:
int[] storage = { 1, 2, 3, 4, 5, 6 };
ReadOnlyTensorSpan<int> source = new(storage, new nint[] { 2, 2 }, new nint[] { 3, 1 });
TensorSpan<int> destination = new(storage, new nint[] { 2, 2 });
Per copiare da questo layout sovrapposto non supportato, acquisire prima uno snapshot in una risorsa di archiviazione indipendente:
int[] snapshot = new int[checked((int)source.FlattenedLength)];
source.FlattenTo(snapshot);
ReadOnlyTensorSpan<int> independentSource = new(snapshot, source.Lengths);
independentSource.CopyTo(destination);
Lo snapshot contiene [1, 2, 4, 5]. La copia scrive tali elementi nella destinazione senza modificare i valori originali prima che vengano letti.
Per un'operazione element-wise con destinazione, allocare un tensore di risultati separato o creare uno snapshot di ogni input sovrapposto prima di scrivere l'output. Per una destinazione broadcast con posizioni di archiviazione ripetute, usare invece l'archiviazione di output indipendente; uno snapshot di input non rende tale destinazione in grado di contenere valori distinti.
La libreria non alloca in modo implicito uno snapshot full-tensor per supportare layout arbitrari sovrapposti. Le copie strided non sovrapposte non richiedono la memoria temporanea.