Notes
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Les tenseurs DirectML, qui sont pris en charge par les tampons Direct3D 12, sont décrits par les propriétés connues sous le nom de tailles et strides du tenseur. Les dimensions du tenseur décrivent les dimensions logiques du tenseur. Par exemple, un capteur 2D peut avoir une hauteur de 2 et une largeur de 3. Logiquement, le tenseur possède 6 éléments distincts, les tailles ne spécifient cependant pas la façon dont ces éléments sont stockés en mémoire. Les strides du tenseur décrivent la disposition en mémoire physique des éléments du tenseur.
Tableaux bidimensionnels (2D)
Considérez un capteur 2D qui a une hauteur de 2 et une largeur de 3 ; les données comprennent des caractères textuels. En C/C++, cela peut être exprimé à l’aide d’un tableau multidimensionnel.
constexpr int rows = 2;
constexpr int columns = 3;
char tensor[rows][columns];
tensor[0][0] = 'A';
tensor[0][1] = 'B';
tensor[0][2] = 'C';
tensor[1][0] = 'D';
tensor[1][1] = 'E';
tensor[1][2] = 'F';
La vue logique du tenseur ci-dessus est visualisée ci-dessous.
A B C
D E F
En C/C++, un tableau multidimensionnel est stocké dans l’ordre principal des lignes. En d’autres termes, les éléments consécutifs le long de la dimension de largeur sont stockés contiguëment dans l’espace mémoire linéaire.
Décaler : | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
Valeur : | Un | B | C | D | E | F |
L’intervalle d’une dimension est le nombre d’éléments à ignorer pour accéder à l’élément suivant dans cette dimension. Strides exprime la disposition du tensor en mémoire. Avec un ordre principal de ligne, le pas de la dimension de largeur est toujours 1, car les éléments adjacents le long de la dimension sont stockés contiguëment. Le pas de la dimension de hauteur dépend de la taille de la dimension de largeur ; dans l’exemple ci-dessus, la distance entre les éléments consécutifs le long de la dimension de hauteur (par exemple, A à D) est égale à la largeur du tenseur (qui est 3 dans cet exemple).
Pour illustrer une autre disposition, envisagez l’ordre principal des colonnes. En d’autres termes, les éléments consécutifs le long de la dimension de hauteur sont stockés contiguëment dans l’espace mémoire linéaire. Dans ce cas, le pas de hauteur est toujours égal à 1, et le pas de largeur est de 2 (la taille de la dimension de largeur).
Décaler : | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
Valeur : | Un | D | B | E | C | F |
Dimensions supérieures
Lorsqu'il s'agit de plus de deux dimensions, il est peu pratique de faire référence à une disposition en termes d'ordre de lignes ou d'ordre de colonnes. Par conséquent, le reste de cette rubrique utilise des termes et des étiquettes comme ceux-ci.
- 2D : « HW » : la hauteur est la dimension de plus haut niveau (en ordre de lignes).
- 2D : « WH » : la largeur est la dimension de classement le plus élevé (colonne principale).
- 3D : « DHW » : la profondeur est la dimension de classement le plus élevé, suivie de la hauteur, puis de la largeur.
- 3D : « WHD » : la largeur est la dimension de classement le plus élevé, suivie de la hauteur, puis de la profondeur.
- 4D : « NCHW » : nombre d’images (taille du lot), nombre de canaux, hauteur, largeur.
En règle générale, la progression emballée d’une dimension est égale au produit des tailles des dimensions inférieures. Par exemple, avec une disposition « DHW », le pas D est égal à H * W ; le pas H est égal à W ; et le pas W est égal à 1. On dit que les strides sont emballés lorsque la taille physique totale du tenseur est égale à la taille logique totale du tenseur ; en d’autres termes, il n’y a pas d’espace supplémentaire ni de chevauchement d’éléments.
Étendons l’exemple 2D à trois dimensions, afin que nous disposions d’un tenseur de profondeur 2, de hauteur 2 et de largeur 3 (pour un total de 12 éléments logiques).
A B C
D E F
G H I
J K L
Avec une disposition « DHW », ce tensor est stocké comme suit.
Décaler : | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Valeur : | Un | B | C | D | E | F | G | H | Je | J | K | L |
- D-stride = hauteur (2) * largeur (3) = 6 (par exemple, la distance entre 'A' et 'G').
- H-stride = width (3) = 3 (par exemple, distance entre 'A' et 'D').
- W-stride = 1 (par exemple, la distance entre 'A' et 'B').
Le produit de points des index/coordonnées d’un élément et les strides fournit le décalage à cet élément dans la mémoire tampon. Par exemple, le décalage de l’élément H (d=1, h=0, w=1) est 7.
{1, 0, 1} } { 6, 3, 1} = 1 * 6 + 0 * 3 + 1 * 1 = 7
Tenseurs emballés
Les exemples ci-dessus illustrent les tenseurs emballés . Un capteur est dit être emballé lorsque la taille logique du capteur (dans les éléments) est égale à la taille physique de la mémoire tampon (dans les éléments) et que chaque élément a une adresse/décalage unique. Par exemple, un tensoriel 2x2x3 est emballé si la mémoire tampon est de 12 éléments de longueur et qu’aucune paire d’éléments ne partage le même décalage dans la mémoire tampon. Les tenseurs emballés sont le cas le plus courant ; mais les progrès permettent des dispositions de mémoire plus complexes.
Diffusion avec des progrès
Si la taille de mémoire tampon d’un tenseur (en éléments) est inférieure au produit de ses dimensions logiques, il en découle qu’il doit y avoir un chevauchement d’éléments. Le cas habituel est connu sous le nom de radiodiffusion ; où les éléments d’une dimension sont un doublon d’une autre dimension. Par exemple, examinons l’exemple 2D. Supposons que nous voulons un tenseur de dimensions logiques 2x3, mais dont la deuxième ligne est identique à la première. Voici comment ça ressemble.
A B C
A B C
Cela peut être stocké sous la forme d’un tenseur HW/row-major compacté. Mais un stockage plus compact ne contiendrait que 3 éléments (A, B et C) et utiliserait une hauteur de 0 au lieu de 3. Dans ce cas, la taille physique du capteur est de 3 éléments, mais la taille logique est de 6 éléments.
En général, si le pas d'une dimension est 0, tous les éléments dans les dimensions de rang inférieur sont répétés dans la dimension diffusée ; par exemple, si le tenseur est NCHW et que le pas de C est 0, chaque canal a les mêmes valeurs pour H et W.
Remplissage avec des pas
Un tenseur est dit être rembourré si sa taille physique est supérieure à la taille minimale nécessaire pour contenir ses éléments. Lorsqu'il n'y a ni diffusion ni chevauchement d'éléments, la taille minimale du tenseur (en éléments) est simplement le produit de ses dimensions. Vous pouvez utiliser la fonction DMLCalcBufferTensorSize
d’assistance (consultez les fonctions d’assistance DirectML pour obtenir une liste de cette fonction) pour calculer la taille minimale de la mémoire tampon pour vos tenseurs DirectML.
Supposons qu’une mémoire tampon contient les valeurs suivantes (les éléments « x » indiquent des valeurs de remplissage).
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
Un | B | C | x | x | D | E | F | x | x |
Le tenseur rembourré peut être décrit en utilisant un pas de 5 au lieu de 3. Au lieu de passer à pas par 3 éléments pour accéder à la ligne suivante, l’étape est de 5 éléments (3 éléments réels plus 2 éléments de remplissage). Le remplissage est courant dans les graphismes informatiques, par exemple, pour s’assurer qu’une image est alignée sur une puissance de deux.
A B C
D E F
Descriptions des tenseurs de mémoire tampon DirectML
DirectML peut fonctionner avec une variété de dispositions de tenseur physique, car la structure DML_BUFFER_TENSOR_DESC possède à la fois des membres Sizes
et Strides
. Certaines implémentations d’opérateur peuvent être plus efficaces avec une disposition spécifique. Il n’est donc pas rare de modifier la façon dont les données tensoriels sont stockées pour de meilleures performances.
La plupart des opérateurs DirectML nécessitent des tenseurs 4D ou 5D, et l’ordre des tailles et des strides est fixe. En corrigeant l'ordre des tailles et des valeurs de progression dans une description de tenseur, il est possible pour DirectML d'inférer différentes dispositions physiques.
4D
- DML_BUFFER_TENSOR_DESC ::Sizes = { N-size, C-size, H-size, W-size }
- DML_BUFFER_TENSOR_DESC ::Strides = { N-stride, C-stride, H-stride, W-stride }
5D
- DML_BUFFER_TENSOR_DESC ::Sizes = { N-size, C-size, D-size, H-size, W-size }
- DML_BUFFER_TENSOR_DESC ::Strides = { N-stride, C-stride, D-stride, H-stride, W-stride }
Si un opérateur DirectML nécessite un tenseur 4D ou 5D, mais que les données réelles ont un rang plus petit (par exemple, 2D), les dimensions avant doivent être remplies avec des 1. Par exemple, un tensoriel « HW » est défini à l’aide de DML_BUFFER_TENSOR_DESC ::Sizes = { 1, 1, H, W }.
Si les données de tenseur sont stockées dans NCHW/NCDHW, il n’est pas nécessaire de définir DML_BUFFER_TENSOR_DESC::Strides, sauf si vous souhaitez une diffusion ou un remplissage. Vous pouvez définir le champ strides sur nullptr
. Toutefois, si les données de tenseur sont stockées dans une autre disposition, telle que NHWC, vous avez besoin de strides pour exprimer la transformation de NCHW à cette disposition.
Pour obtenir un exemple simple, considérez la description d’un tensor 2D avec la hauteur 3 et la largeur 5.
Packed NCHW (strides implicites)
- DML_BUFFER_TENSOR_DESC ::Sizes = { 1, 1, 3, 5 }
-
DML_BUFFER_TENSOR_DESC ::Foulées =
nullptr
Packed NCHW (strides explicites)
- Foulée N = taille C * taille H * taille W = 1 * 3 * 5 = 15
- Foulée C = taille H * taille W = 3 * 5 = 15
- Foulée en H = Taille en W = 5
- Foulée en W = 1
- DML_BUFFER_TENSOR_DESC ::Sizes = { 1, 1, 3, 5 }
- DML_BUFFER_TENSOR_DESC ::Strides = { 15, 15, 5, 1 }
NHWC bondé
- Foulée N = taille H * taille W * taille C = 3 * 5 * 1 = 15
- Foulée en H = taille W * taille C = 5 * 1 = 5
- W-stride = C-taille = 1
- Foulée en C = 1
- DML_BUFFER_TENSOR_DESC ::Sizes = { 1, 1, 3, 5 }
- DML_BUFFER_TENSOR_DESC ::Strides = { 15, 1, 5, 1 }