Como usar operadores fundidos para aprimorar o desempenho
Alguns operadores DirectML dão suporte a um conceito conhecido como fusion. A fusão do operador é uma maneira de melhorar o desempenho mesclando um operador (normalmente, uma função de ativação) em um operador diferente para que eles sejam executados juntos sem necessidade de ir até a memória e voltar.
Quando fundir ativações
As ativações fundidas são uma otimização de desempenho. Um cenário extremamente comum em muitos modelos de aprendizado de máquina (ML) é aplicar uma não-linearidade (uma função de ativação) à saída de cada camada no modelo.
Normalmente, isso requer uma viagem de ida e volta para a memória gráfica. Por exemplo, se uma Convolução for seguida por uma ativação de Relu não fundida, a GPU deverá aguardar que os resultados da Convolução sejam gravados na memória da GPU antes de começar a calcular a camada de ativação Relu. Como a carga de trabalho de computação da maioria das funções de ativação tende a ser pequena, essa viagem de ida e volta para a memória gráfica pode ser um grande gargalo de desempenho.
A fusão do operador permite que a função de ativação (Relu no exemplo acima) seja executada como parte do operador anterior (Convolução, por exemplo). Isso permite que a GPU compute a função de ativação sem esperar que os resultados do operador anterior sejam gravados na memória — e isso melhora o desempenho.
Como as ativações fundidas produzem o mesmo resultado, mas são mais rápidas em muitos casos, recomendamos que você elimine as camadas de ativação fundindo-as em seu operador anterior sempre que possível.
Como fundir ativações
Os operadores que dão suporte a ativações fundidas têm um parâmetro opcional adicional em sua estrutura de operador, const DML_OPERATOR_DESC* FusedActivation
. A convolução, por exemplo, suporta ativação fundida e tem um FusedActivation correspondente em sua descrição de operador (consulte DML_CONVOLUTION_OPERATOR_DESC).
struct DML_CONVOLUTION_OPERATOR_DESC
{
const DML_TENSOR_DESC* InputTensor;
const DML_TENSOR_DESC* FilterTensor;
_Maybenull_ const DML_TENSOR_DESC* BiasTensor;
const DML_TENSOR_DESC* OutputTensor;
DML_CONVOLUTION_MODE Mode;
DML_CONVOLUTION_DIRECTION Direction;
UINT DimensionCount;
_Field_size_(DimensionCount) const UINT* Strides;
_Field_size_(DimensionCount) const UINT* Dilations;
_Field_size_(DimensionCount) const UINT* StartPadding;
_Field_size_(DimensionCount) const UINT* EndPadding;
_Field_size_(DimensionCount) const UINT* OutputPadding;
UINT GroupCount;
_Maybenull_ const DML_OPERATOR_DESC* FusedActivation;
};
Para fundir uma ativação, construa um DML_OPERATOR_DESC que descreva o tipo de ativação a ser fundida. Por exemplo, para fundir uma função Relu, o tipo de operador correto seria DML_OPERATOR_ACTIVATION_RELU.
Observação
Ao construir a descrição do operador para a função de ativação, você deve definir os parâmetros InputTensor e OutputTensor para a função de ativação como NULL.
Exemplo
DML_ACTIVATION_LEAKY_RELU_OPERATOR_DESC leakyReluDesc;
leakyReluDesc.InputTensor = nullptr;
leakyReluDesc.OutputTensor = nullptr;
leakyReluDesc.Alpha = 0.01f;
DML_OPERATOR_DESC activationDesc = { DML_OPERATOR_ACTIVATION_LEAKY_RELU, &leakyReluDesc };
DML_CONVOLUTION_OPERATOR_DESC convDesc;
// ...
convDesc.FusedActivation = &activationDesc;
Para obter um exemplo completo, o exemplo DirectMLSuperResolution utiliza ativações fundidas para melhorar o desempenho.
Operadores que oferecem suporte à ativação fundida
A lista abaixo é baseada em constantes da enumeração DML_OPERATOR_TYPE. Cada constante nesse tópico vincula-se à estrutura de descrição apropriada a ser usada.
- DML_OPERATOR_BATCH_NORMALIZATION
- DML_OPERATOR_BATCH_NORMALIZATION_TRAINING
- DML_OPERATOR_CONVOLUTION
- DML_OPERATOR_ELEMENT_WISE_ADD1
- DML_OPERATOR_GEMM
- DML_OPERATOR_MEAN_VARIANCE_NORMALIZATION
- DML_OPERATOR_MEAN_VARIANCE_NORMALIZATION1
Ativações com suporte para fusão
A lista abaixo é baseada em constantes da enumeração DML_OPERATOR_TYPE. Cada constante nesse tópico vincula-se à estrutura de descrição apropriada a ser usada.
- DML_OPERATOR_ELEMENT_WISE_CLIP
- DML_OPERATOR_ACTIVATION_LINEAR
- DML_OPERATOR_ACTIVATION_SIGMOID
- DML_OPERATOR_ACTIVATION_HARD_SIGMOID
- DML_OPERATOR_ACTIVATION_TANH
- DML_OPERATOR_ACTIVATION_SCALED_TANH
- DML_OPERATOR_ACTIVATION_RELU
- DML_OPERATOR_ACTIVATION_LEAKY_RELU
- DML_OPERATOR_ACTIVATION_THRESHOLDED_RELU
- DML_OPERATOR_ACTIVATION_ELU
- DML_OPERATOR_ACTIVATION_CELU
- DML_OPERATOR_ACTIVATION_SCALED_ELU
- DML_OPERATOR_ACTIVATION_SOFTPLUS
- DML_OPERATOR_ACTIVATION_PARAMETRIC_SOFTPLUS
- DML_OPERATOR_ACTIVATION_SOFTSIGN
- DML_OPERATOR_ACTIVATION_IDENTITY
- DML_OPERATOR_ACTIVATION_SHRINK
- DML_OPERATOR_ACTIVATION_GELU
Os operadores que não estão nesta lista não têm suporte para ativação fundida.