Diferenciação automática - Automatic differentiation

Em matemática e álgebra computacional , a diferenciação automática ( AD ), também chamada de diferenciação algorítmica , diferenciação computacional , auto-diferenciação ou simplesmente autodiff , é um conjunto de técnicas para avaliar a derivada de uma função especificada por um programa de computador. AD explora o fato de que cada programa de computador, não importa o quão complicado seja, executa uma sequência de operações aritméticas elementares (adição, subtração, multiplicação, divisão, etc.) e funções elementares (exp, log, sin, cos, etc.). Aplicando a regra da cadeia repetidamente a essas operações, as derivadas de ordem arbitrária podem ser calculadas automaticamente, com precisão de trabalho e usando no máximo um pequeno fator constante mais operações aritméticas do que o programa original.

Figura 1: Como a diferenciação automática se relaciona com a diferenciação simbólica

A diferenciação automática é diferente da diferenciação simbólica e da diferenciação numérica (o método das diferenças finitas). A diferenciação simbólica pode levar a um código ineficiente e enfrenta a dificuldade de converter um programa de computador em uma única expressão, enquanto a diferenciação numérica pode introduzir erros de arredondamento no processo de discretização e cancelamento. Ambos os métodos clássicos têm problemas com o cálculo de derivadas mais altas, onde a complexidade e os erros aumentam. Finalmente, ambos os métodos clássicos são lentos para calcular derivadas parciais de uma função em relação a muitas entradas, como é necessário para algoritmos de otimização baseados em gradiente . A diferenciação automática resolve todos esses problemas.

A regra da cadeia, acumulação direta e reversa

Fundamental para AD é a decomposição de diferenciais fornecidos pela regra da cadeia . Para a composição simples

a regra da corrente dá

Normalmente, dois modos distintos de AD são apresentados, acumulação direta (ou modo direto ) e acumulação reversa (ou modo reverso ). A acumulação direta especifica que se atravessa a regra da cadeia de dentro para fora (ou seja, primeiro calcule e depois e por último ), enquanto a acumulação reversa faz a travessia de fora para dentro (primeiro calcule e depois e por último ). Mais sucintamente,

  1. a acumulação direta calcula a relação recursiva: com , e,
  2. a acumulação reversa calcula a relação recursiva: com .

Acumulação para frente

Figura 2: Exemplo de acumulação direta com gráfico computacional

Na acumulação direta AD, primeiro fixa-se a variável independente em relação à qual a diferenciação é realizada e calcula-se a derivada de cada subexpressão recursivamente. Em um cálculo de caneta e papel, isso envolve a substituição repetida da derivada das funções internas na regra da cadeia:

Isso pode ser generalizado para várias variáveis ​​como um produto da matriz de Jacobianos .

Comparada à acumulação reversa, a acumulação direta é natural e fácil de implementar, pois o fluxo de informações derivadas coincide com a ordem de avaliação. Cada variável w é aumentada com sua derivada (armazenada como um valor numérico, não uma expressão simbólica),

conforme indicado pelo ponto. As derivadas são então calculadas em sincronia com as etapas de avaliação e combinadas com outras derivadas por meio da regra da cadeia.

Como exemplo, considere a função:

Para maior clareza, as subexpressões individuais foram rotuladas com as variáveis w i .

A escolha da variável independente para a qual a diferenciação é realizada afeta os valores de sementes 1 e 2 . Dado o interesse na derivada desta função em relação a x 1 , os valores iniciais devem ser definidos para:

Com os valores iniciais definidos, os valores se propagam usando a regra da cadeia, conforme mostrado. A Figura 2 mostra uma representação pictórica desse processo como um gráfico computacional.

Operações para calcular o valor Operações para calcular a derivada
(semente)
(semente)

Para calcular o gradiente desta função de exemplo, que requer as derivadas de f em relação a não apenas x 1, mas também x 2 , uma varredura adicional é realizada no gráfico computacional usando os valores iniciais .

A complexidade computacional de uma varredura de acumulação direta é proporcional à complexidade do código original.

A acumulação direta é mais eficiente do que a acumulação reversa para as funções f  : R nR m com mn visto que apenas n varreduras são necessárias, em comparação com m varreduras para acumulação reversa.

Acumulação reversa

Figura 3: Exemplo de acumulação reversa com gráfico computacional

Na acumulação reversa AD, a variável dependente a ser diferenciada é fixa e a derivada é calculada em relação a cada subexpressão recursivamente. Em um cálculo de caneta e papel, a derivada das funções externas é substituída repetidamente na regra da cadeia:

Na acumulação reversa, a quantidade de juros é o adjunto , denotado por uma barra ( ); é uma derivada de uma variável dependente escolhida em relação a uma subexpressão w :

A acumulação reversa atravessa a regra da cadeia de fora para dentro ou, no caso do gráfico computacional da Figura 3, de cima para baixo. A função de exemplo tem valor escalar e, portanto, há apenas uma semente para o cálculo da derivada e apenas uma varredura do gráfico computacional é necessária para calcular o gradiente (de dois componentes). Esta é apenas metade do trabalho quando comparada à acumulação direta, mas a acumulação reversa requer o armazenamento das variáveis ​​intermediárias w i , bem como as instruções que as produziram em uma estrutura de dados conhecida como lista de Wengert (ou "fita"), que pode consumir memória significativa se o gráfico computacional for grande. Isso pode ser mitigado até certo ponto, armazenando apenas um subconjunto das variáveis ​​intermediárias e, em seguida, reconstruindo as variáveis ​​de trabalho necessárias, repetindo as avaliações, uma técnica conhecida como rematerialização . O ponto de verificação também é usado para salvar estados intermediários.

As operações para calcular a derivada usando acumulação reversa são mostradas na tabela abaixo (observe a ordem reversa):

Operações para calcular a derivada

O gráfico de fluxo de dados de um cálculo pode ser manipulado para calcular o gradiente de seu cálculo original. Isso é feito adicionando-se um nó adjacente para cada nó primário, conectado por arestas adjacentes que são paralelas às arestas primárias, mas fluem na direção oposta. Os nós no gráfico adjunto representam a multiplicação pelas derivadas das funções calculadas pelos nós no primário. Por exemplo, adição nas causas primárias fanout no adjunto; fanout no primário causa adição no adjunto; uma função unária y = f  ( x ) no primário causa = ȳ f  ′ ( x ) no adjunto; etc.

A acumulação reversa é mais eficiente do que a acumulação direta para as funções f  : R nR m com mn visto que apenas m varreduras são necessárias, em comparação com n varreduras para acumulação direta.

O modo reverso AD foi publicado pela primeira vez em 1976 por Seppo Linnainmaa .

A retropropagação de erros em perceptrons multicamadas, uma técnica usada no aprendizado de máquina , é um caso especial do modo reverso AD.

Além da acumulação direta e reversa

A acumulação direta e reversa são apenas duas formas (extremas) de ultrapassar a regra da cadeia. O problema de calcular um Jacobiano completo de f  : R nR m com um número mínimo de operações aritméticas é conhecido como o problema de acumulação Jacobiana ótima (OJA), que é NP-completo . Central para esta prova é a ideia de que dependências algébricas podem existir entre as parciais locais que rotulam as arestas do gráfico. Em particular, duas ou mais etiquetas de borda podem ser reconhecidas como iguais. A complexidade do problema ainda está aberta se for assumido que todos os rótulos de aresta são únicos e algebricamente independentes.

Diferenciação automática usando números duais

A diferenciação automática do modo progressivo é realizada aumentando a álgebra de números reais e obtendo uma nova aritmética . Um componente adicional é adicionado a cada número para representar a derivada de uma função no número, e todos os operadores aritméticos são estendidos para a álgebra aumentada. A álgebra aumentada é a álgebra de números duais .

Substitua cada número pelo número , onde é um número real, mas é um número abstrato com a propriedade (um infinitesimal ; consulte Análise infinitesimal suave ). Usando apenas isso, a aritmética regular dá

e da mesma forma para subtração e divisão.

Agora, os polinômios podem ser calculados nesta aritmética aumentada. Se então

onde denota a derivada de em relação ao seu primeiro argumento, e , chamado de semente , pode ser escolhido arbitrariamente.

A nova aritmética consiste em pares ordenados , elementos escritos , com aritmética ordinária no primeiro componente e aritmética de diferenciação de primeira ordem no segundo componente, conforme descrito acima. Estender os resultados acima em polinômios para

funções analíticas fornece uma lista da aritmética básica e algumas funções padrão para a nova aritmética:
e em geral para a função primitiva ,
onde e são os derivados de em relação ao seu primeiro e segundo argumentos, respectivamente.

Quando uma operação aritmética básica binária é aplicada a argumentos mistos - o par e o número real - o número real é primeiro elevado a . A derivada de uma função no ponto agora é encontrada calculando usando a aritmética acima, que fornece o resultado.

Argumentos e funções de vetor

As funções multivariadas podem ser tratadas com a mesma eficiência e mecanismos que as funções univariadas, adotando-se um operador derivado direcional. Ou seja, se for suficiente calcular a derivada direcional de at na direção , isso pode ser calculado usando a mesma aritmética acima. Se todos os elementos de forem desejados, as avaliações da função serão necessárias. Observe que em muitas aplicações de otimização, a derivada direcional é de fato suficiente.

Alta ordem e muitas variáveis

A aritmética acima pode ser generalizada para calcular derivadas de segunda ordem e superiores de funções multivariadas. No entanto, as regras aritméticas tornam-se rapidamente complicadas: a complexidade é quadrática no grau de derivação mais alto. Em vez disso, pode ser usada a álgebra polinomial de Taylor truncada . A aritmética resultante, definida em números duais generalizados, permite um cálculo eficiente usando funções como se fossem um tipo de dados. Uma vez que o polinômio de Taylor de uma função é conhecido, as derivadas são facilmente extraídas.

Implementação

O modo avançado AD é implementado por uma interpretação não padronizada do programa em que os números reais são substituídos por números duais, as constantes são elevadas para números duais com um coeficiente épsilon zero e os primitivos numéricos são elevados para operar em números duais. Essa interpretação não padronizada é geralmente implementada usando uma de duas estratégias: transformação do código-fonte ou sobrecarga do operador .

Transformação do código fonte (SCT)

Figura 4: Exemplo de como a transformação do código-fonte poderia funcionar

O código-fonte de uma função é substituído por um código-fonte gerado automaticamente que inclui instruções para calcular os derivados intercalados com as instruções originais.

A transformação do código-fonte pode ser implementada para todas as linguagens de programação e também é mais fácil para o compilador fazer otimizações de tempo de compilação. No entanto, a implementação da ferramenta AD em si é mais difícil.

Sobrecarga do operador (OO)

Figura 5: Exemplo de como a sobrecarga do operador poderia funcionar

A sobrecarga do operador é uma possibilidade para o código-fonte escrito em uma linguagem que o suporte. Objetos para números reais e operações matemáticas elementares devem ser sobrecarregados para atender à aritmética aumentada descrita acima. Isso não requer nenhuma mudança na forma ou sequência de operações no código-fonte original para que a função seja diferenciada, mas geralmente requer mudanças nos tipos de dados básicos para números e vetores para suportar sobrecarga e frequentemente também envolve a inserção de operações de sinalização especiais.

A sobrecarga do operador para acumulação direta é fácil de implementar e também possível para acumulação reversa. No entanto, os compiladores atuais ficam para trás na otimização do código quando comparados à acumulação direta.

A sobrecarga do operador, para acumulação direta e reversa, pode ser adequada para aplicações em que os objetos são vetores de números reais em vez de escalares. Isso ocorre porque a fita compreende operações vetoriais; isso pode facilitar implementações computacionalmente eficientes, onde cada operação vetorial realiza muitas operações escalares. Técnicas de diferenciação algorítmica adjunta de vetor (vetor AAD) podem ser usadas, por exemplo, para diferenciar valores calculados por simulação de Monte-Carlo.

Exemplos de implementações que sobrecarregam o operador de diferenciação automática em C ++ são as bibliotecas Adept e Stan .

Veja também

Notas

Referências

Leitura adicional

links externos

implementação de diferenciação automática baseada em modelo C ++
  • Derivativos tangentes de origem a origem depuráveis
  • [1] , Gregos exatos de primeira e segunda ordem por diferenciação algorítmica
  • [2] , Diferenciação Algorítmica Adjunta de um Aplicativo Acelerado por GPU
  • [3] , Métodos Adjuntos em Ferramentas de Software de Finanças Computacionais para Diferenciação Algorítmicaop