Remarque
L’accès à cette page requiert une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page requiert une autorisation. Vous pouvez essayer de modifier des répertoires.
Le package System.Numerics.Tensors fournit Tensor<T>, TensorSpan<T>et ReadOnlyTensorSpan<T> pour les données multidimensionnelles. Les formes des tenseurs décrivent les dimensions logiques ; les strides décrivent la distance, dans les éléments, entre les positions successives le long de chaque dimension.
Le comportement décrit ici est inclus dans le package pour les frameworks cibles pris en charge. La mise à jour du package peut affecter les applications qui ciblent les versions antérieures de .NET.
Ces types partagent de nombreuses conventions avec NumPy, mais ils ne sont pas interchangeables. Tenez compte des différences suivantes lorsque vous portez un algorithme.
Formes vides et résultats scalaires
Lorsque vous créez un tenseur à partir d’une forme vide ([]) sans données sous-jacentes, le tenseur a une forme [0] et aucun élément. Dans NumPy, la forme () a le rang zéro et contient un élément scalaire. En particulier, np.empty(()) alloue un scalaire avec une valeur non initialisée ; « vide » ne signifie pas qu’il n’a aucun élément.
En revanche, lorsque vous omettez les longueurs dans un constructeur tensor-span sur des données existantes, le constructeur déduit une forme unidimensionnelle à partir du tableau ou du span fourni.
Lorsque vous compressez un tenseur avec une forme [1, 1], le résultat a une forme [1], et non la forme () de rang zéro de NumPy. Les deux résultats contiennent un élément et peuvent être diffusés en tant que scalaire, mais le code qui examine le rang, sélectionne les axes ou indexe le résultat doit tenir compte de la dimension conservée.
Lorsque les strides sont omis, toute forme qui contient une dimension de longueur nulle a des strides nuls dans chaque dimension. Son nombre d’éléments et le stockage requis sont zéro, quelles que soient les autres longueurs de dimension. Les longueurs négatives restent non valides. Les pas explicites doivent toujours satisfaire à la validation de l’agencement.
Strides et données inversées
Les pas doivent être non négatifs. NumPy peut représenter une vue inversée avec un stride négatif, par exemple array[::-1].
Pour inverser le premier axe, appelez Tensor.ReverseDimension avec la dimension 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);
Les éléments logiques de reversed sont [3, 4, 1, 2]. La surcharge d’allocation produit un nouveau tenseur ; ce n’est pas une vue à pas négatif sur le stockage d’origine.
Redimensionner un tenseur
Tensor.Resize et Tensor.ResizeTo remplissent les éléments logiques ajoutés avec default(T). Par exemple, si vous augmentez [1, 2] à cinq int éléments, le résultat contient [1, 2, 0, 0, 0]. Le np.resize de NumPy répète à la place l’entrée et produit [1, 2, 1, 2, 1].
Si la destination est plus petite, l’opération supprime les éléments après le nombre d’éléments logiques de la destination. Si elle est plus grande, l’opération initialise les éléments de destination logique restants, même lorsque la destination a des écarts entre les éléments. Le stockage en dehors de la destination logique ne fait pas partie de l’opération de redimensionnement.
Tensor.ResizeTo et la concaténation dans une destination existante rejettent une dimension à pas nul qui contient plusieurs éléments logiques. Une telle dimension fait que plusieurs positions de sortie référencent le même espace de stockage et ne peut pas contenir de valeurs de sortie distinctes. Des pas nuls dans les dimensions singleton et les destinations vides ne créent pas ce conflit.
Chevauchement des sources et des destinations
Des objets tenseur distincts et des étendues peuvent faire référence à des régions qui se chevauchent du même tableau. Les cas pris en charge dépendent à la fois de l’opération et de la disposition :
| Operation | Prise en charge du chevauchement |
|---|---|
CopyTo et TryCopyTo |
Source et destination denses avec nombres d’éléments égaux ou vues exactement identiques. Les copies denses utilisent la copie de segment sûre en cas de chevauchement. |
FlattenTo et TryFlattenTo |
Une source dense et la plage de destination. |
| Opérations au niveau des éléments avec une destination | Une entrée et une sortie peuvent avoir la même référence de départ, les mêmes longueurs et les mêmes pas, à condition que la vue n’ait pas d’emplacements de stockage logique répétés. Chaque entrée est vérifiée indépendamment. |
Tensor.ResizeTo |
Source et destination compactes. Le chevauchement non pris en charge est rejeté. |
| Retour à la même vue | Une vue dense peut être inversée en place. Les annulations sans effet sont également prises en charge. |
D’autres dispositions qui se chevauchent non prises en charge génèrent ArgumentException avant que l’opération n’écrive la sortie. Un tenseur dense seul ne garantit pas la prise en charge de chaque opération : par exemple, une destination dense décalée est prise en charge pour une copie, mais pas pour une opération élément par élément.
Les méthodes TryCopyTo et TryFlattenTo retournent false sans copier lorsque la destination est trop courte.
TryCopyTo retourne également false pour des formes source et de destination incompatibles. Pour les formes compatibles avec une capacité de destination suffisante, ces méthodes peuvent toujours lever une exception en cas de chevauchement non pris en charge ; Try ne supprime pas les exceptions de disposition non valides.
Par exemple, la source à pas et la destination dense suivantes se chevauchent :
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 });
Pour copier à partir de cette disposition superposée non prise en charge, commencez par prendre un instantané dans un stockage indépendant :
int[] snapshot = new int[checked((int)source.FlattenedLength)];
source.FlattenTo(snapshot);
ReadOnlyTensorSpan<int> independentSource = new(snapshot, source.Lengths);
independentSource.CopyTo(destination);
L’instantané contient [1, 2, 4, 5]. La copie place ces éléments dans la destination sans modifier les valeurs d’origine avant qu’elles ne soient lues.
Pour une opération élément par élément avec destination, allouez un tenseur de résultat distinct ou créez un instantané de chaque entrée chevauchante avant d’écrire la sortie. Pour une destination de diffusion avec des emplacements de stockage répétés, utilisez plutôt un stockage de sortie indépendant ; un instantané d’entrée ne rend pas cette destination capable de contenir des valeurs distinctes.
La bibliothèque n’alloue pas implicitement un instantané du tenseur complet pour prendre en charge des dispositions qui se chevauchent arbitrairement. Les copies à pas sans chevauchement ne nécessitent pas ce stockage temporaire.