The layer normalization primitive performs a forward or backward layer normalization operation on a 2-5D data tensor.
The layer normalization operation performs normalization over the last logical axis of the data tensor and is defined by the following formulas. We show formulas only for 3D data, which are straightforward to generalize to cases of higher dimensions. Variable names follow the standard Naming Conventions.
\[ \dst(t, n, c) = \gamma(c) \cdot \frac{\src(t, n, c) - \mu(t, n)} {\sqrt{\sigma^2(t, n) + \varepsilon}} + \beta(c), \]
where
Mean and variance are computed at runtime or provided by a user. When mean and variance are computed at runtime, the following formulas are used:
Inputs: \(\src\)
Outputs: \(\dst\), \(\mu\), \(\sigma^2\)
Inputs: \(\diffdst\), \(\src\), \(\mu\), \(\sigma^2\)
Outputs: \(\diffsrc\)
Inputs: \(\diffdst\), \(\src\), \(\mu\), \(\sigma^2\)
Outputs: \(\diffsrc\)
Inputs: \(\src\), \(\mu\), \(\sigma^2\)
Outputs: \(\dst\)
Inputs: \(\src\), \(\mu\), \(\sigma^2\)
Outputs: \(\dst\)
Inputs: \(\diffdst\), \(\src\), \(\mu\), \(\sigma^2\)
Outputs: \(\diffsrc\)
Inputs: \(\diffdst\), \(\src\), \(\mu\), \(\sigma^2\)
Outputs: \(\diffsrc\)
Inputs: \(\src\), \(\gamma\), \(\beta\)
Outputs: \(\dst\)
Inputs: \(\src\), \(\gamma\), \(\beta\)
Outputs: \(\dst\), \(\mu\), \(\sigma^2\)
Inputs: \(\diffdst\), \(\src\), \(\mu\), \(\sigma^2\), \(\gamma\), \(\beta\)
Outputs: \(\diffsrc\), \(\diffgamma\), \(\diffbeta\)
Inputs: \(\diffdst\), \(\src\), \(\mu\), \(\sigma^2\), \(\gamma\), \(\beta\)
Outputs: \(\diffsrc\)
dnnl_use_global_stats | dnnl_use_scaleshift
Inputs: \(\src\), \(\mu\), \(\sigma^2\), \(\gamma\), \(\beta\)
Outputs: \(\dst\)
Inputs: \(\src\), \(\mu\), \(\sigma^2\), \(\gamma\), \(\beta\)
Outputs: \(\dst\)
Inputs: \(\diffdst\), \(\src\), \(\mu\), \(\sigma^2\), \(\gamma\), \(\beta\)
Outputs: \(\diffsrc\), \(\diffgamma\), \(\diffbeta\)
Inputs: \(\diffdst\), \(\src\), \(\mu\), \(\sigma^2\), \(\gamma\), \(\beta\)
Outputs: \(\diffsrc\)
When executed, the inputs and outputs should be mapped to an execution argument index as specified by the following table.
| Primitive input/output | Execution argument index |
|---|---|
| \(\src\) | DNNL_ARG_SRC |
| \(\gamma, \beta\) | DNNL_ARG_SCALE_SHIFT |
| mean ( \(\mu\)) | DNNL_ARG_MEAN |
| variance ( \(\sigma\)) | DNNL_ARG_VARIANCE |
| \(\dst\) | DNNL_ARG_DST |
| \(\diffdst\) | DNNL_ARG_DIFF_DST |
| \(\diffsrc\) | DNNL_ARG_DIFF_SRC |
| \(\diffgamma\), \(\diffbeta\) | DNNL_ARG_DIFF_SCALE_SHIFT |
flags parameter that is passed to the operation descriptor initialization function (e.g., dnnl::layer_normalization_forward::desc::desc()). Multiple flags can be set using the bitwise OR operator (|).The operation supports the following combinations of data types:
| Propagation | Source / Destination | Mean / Variance / ScaleShift |
|---|---|---|
| forward / backward | f32 | f32 |
| forward | f16 | f32 |
The mean ( \(\mu\)) and variance ( \(\sigma^2\)) are separate tensors with number of dimensions equal to ( \(data\_ndims - 1\)) and size \((data\_dim[0], data\_dim[1], ..., data\_dim[ndims - 2])\).
The corresponding memory object can have an arbitrary memory format. Unless mean and variance are computed at runtime and not exposed (i.e., propagation kind is dnnl_forward_inference and dnnl_use_global_stats is not set), the user should provide a memory descriptor for statistics when initializing the layer normalization descriptor. For best performance, it is advised to use the memory format that follows the data memory format; i.e., if the data format is dnnl_tnc, the best performance can be expected for statistics with the dnnl_tn format and suboptimal for statistics with the dnnl_nt format.
If used, the scale ( \(\gamma\)) and shift ( \(\beta\)) are combined in a single 2D tensor of shape \(2 \times C\).
The format of the corresponding memory object must be dnnl_nc (dnnl_ab).
The layer normalization primitive works with an arbitrary data tensor; however, it was designed for RNN data tensors (i.e., dnnl_nc, dnnl_tnc, dnnl_ldnc). Unlike CNN data tensors, RNN data tensors have a single feature dimension. Layer normalization performs normalization over the last logical dimension (feature dimension for RNN tensors) across non-feature dimensions.
The layer normalization primitive is optimized for the following memory formats:
| Logical tensor | Implementations optimized for memory formats |
|---|---|
| NC | dnnl_nc (dnnl_ab) |
| TNC | dnnl_tnc (dnnl_abc), dnnl_ntc (dnnl_bac) |
| LDNC | dnnl_ldnc (dnnl_abcd) |
| Engine | Name | Comments |
|---|---|---|
| CPU/GPU | Layer Normalization Primitive Example | This C++ API example demonstrates how to create and execute a Layer normalization primitive in forward propagation mode. Key optimizations included in this example:
|