Compartilhar via


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.

Confira também