Apresentando THOAD, derivados de alta ordem para gráficos de pytorch

Estou animado para compartilhar a diferenciação automática de alta ordem do Pytorch), uma biblioteca apenas Python que calcula derivados parciais de pedidos arbitrários diretamente em um gráfico computacional de Pytorch. O pacote foi desenvolvido em um projeto de pesquisa na Universidad Pontificia de Comillas (ICAI), e estamos pensando em publicar um artigo acadêmico no futuro que revisa os detalhes matemáticos e o design da implementação. Na sua essência, o Thoad pega uma saída, muitas entradas da visualização do gráfico e empurra derivados de alta ordem de volta aos tensores da folha. Embora um problema de 1 → n possa ser reescrito como 1 → 1, concatenando as entradas achatadas, como em abordagens funcionais como Jax.Jet ou Functorch, a formulação do THOAD CNOWE CONSTRAIXA ALIMENTE UMA Otimização baseada em dimensões independentes unificadoras (especialmente lote). Isso fornece uma escala assintoticamente melhor em relação ao tamanho do lote. Calculamos derivativos vetorialmente, em vez de componente por componente, que é o que torna uma implementação pura de pytorch prática sem recorrer a C ++ ou CUDA personalizados. O pacote é fácil de manter, porque é escrito inteiramente em Python e usa o Pytorch como sua única dependência. A implementação permanece em alto nível e se inclina nas operações vetorizadas da Pytorch, o que significa que não há ligações personalizadas de C ++ ou CUDA, nenhum sistema de construção para gerenciar e menos problemas específicos da plataforma. Com uma única dependência, as atualizações e as revisões de segurança são mais simples, a integração contínua é mais leve e os colaboradores podem ler e modificar o código rapidamente. O UX segue Pytorch de perto, portanto, desencadear um passe para trás de alta ordem parece chamar Tensor.backward (). Você pode instalar no Github ou Pypi e iniciar imediatamente: em nossos benchmarks, o Thoad supera a tocha. Veja o caderno que reproduz a comparação: a experiência do usuário tem sido uma de nossas principais preocupações durante o desenvolvimento. O Thoad foi projetado para alinhar -se de perto com a filosofia da interface de Pytorch, portanto, executar o passe para trás de alta ordem é praticamente indistinguível de chamar o próprio para trás de Pytorch. Quando você precisa de controle mais refinado, pode manter ou reduzir as simetrias de Schwarz, as variáveis ​​de grupo para restringir parciais mistas e buscar a derivada mista exata necessária. Formas e metadados da independência também são expostos para manter a interpretação direta. Usando o pacote Thoad expõe duas interfaces primárias para calcular derivados de alta ordem: thoad.backward: uma interface baseada em função que se assemelha a tocha.tensor.backward. Ele fornece uma maneira rápida de calcular gradientes de alta ordem sem precisar gerenciar um objeto de controlador explícito, mas oferece apenas a funcionalidade principal (computação e armazenamento derivado). THOAD.Controller: uma interface baseada em classe que envolve o subgrof do tensor de saída em um objeto controlador. Além de executar o mesmo passe para trás de alta ordem, ele fornece acesso a recursos avançados, como buscar parciais mistas específicos, inspecionar otimizações de dimensão em lote, substituindo implementações de função reversa, retendo parciais intermediários e registrando ganchos personalizados. Thoad.backward A função Thoad.Backward calcula derivados parciais de alta ordem de um determinado tensor de saída e os armazena em cada atributo .hgradado de cada tensor de folhas. Argumentos: Tensor: Um tensor de pytorch a partir do qual iniciar o passe para trás. Esse tensor deve exigir gradientes e fazer parte de um gráfico diferenciável. Ordem: Um número inteiro positivo especificando a ordem máxima dos derivados para calcular. Gradiente: um tensor com a mesma forma que o tensor para semear o produto vetor-jacobiano (ou seja, gradiente personalizado a montante). Se omitido, o padrão é usado. Travessias: uma bandeira booleana (padrão = false). Se definido como true, os derivados parciais mistos (ou seja, derivados que envolvem mais de um tensor de folha distintos) serão calculados. Grupos: Um iterável de grupos disjuntos de tensores de folhas. Quando cruzamentos = falsos, apenas aqueles parciais misturados cujos tensores de folhas participantes estão em um único grupo serão calculados. Se cruzamentos = verdadeiros e grupos forem fornecidos, um ValueError será levantado (eles são mutuamente exclusivos). Keep_batch: um sinalizador booleano (padrão = false) que controla como as dimensões de saída são organizadas nos gradientes calculados. Quando Keep_batch = false **: ** Os gradientes são retornados em uma forma totalmente achatada. Concretamente, pense no tensor de gradiente como tendo: um único eixo de “saída” que lista todos os elementos do tensor de saída original (achatado em uma dimensão). Um eixo por ordem derivada, cada um listando todos os elementos da entrada correspondente (também achatados). Para um derivado n-fés de ordem de um tensor de folha com elementos input_numel e uma saída com elementos de output_numel, a forma do gradiente é: eixo 1: Indexos todos os eixos de saída de output; Você pode visualizá -lo como: Eixo 1 Aplica todos os elementos do tensor de saída (size = output_numel). Os eixos 2 … (k+1) correspondem exatamente a cada dimensão do tensor de saída (se a saída foi a forma (D1, D2, …, DK), esses eixos têm tamanhos d1, d2, …, dk). Eixos (k+2) … (k+n+1) Cada um achate todos os elementos input_numel do tensor da folha, um eixo por ordem derivada. No entanto, se um eixo de saída específico não influenciar o gradiente para uma determinada folha, esse eixo não é expandido e, em vez disso, se tornará uma dimensão tamanho-1. Isso significa apenas as dimensões de saída que realmente afetam o gradiente de uma folha específica “espalhada” nos eixos de entrada; Quaisquer eixos intocados permanecem como 1, salvando memória. keep_schwarz: uma bandeira booleana (padrão = false). Se for verdade, as permutações simétricas (Schwarz) são retidas explicitamente, em vez de serem canônicas/reduzidas-usadas para depurar ou inspecionar layouts não reduzidos. Retornos: uma instância de thoad.controller envolvendo o mesmo tensor e gráfico. importar a tocha importar thoad da tocha.nn Importar funcional como f #### Normal pytorch fluxo de trabalho x = Torch.rand (size = (10,15), requer_grad = true) y = tcorch.rand (size = ((15,20), requer_grad =) Z = f.scaled_dot_dt_attion (QUERS), requer_grad = zey = f.scaled_dot_dt_atts Ordem para trás = 2 thoad.backward (tensor = z, ordem = ordem) #### verifica ## Verifique as formas derivadas para O no intervalo (1, 1 + ordem): afirme x.hgradado[o – 1].Shape == (Z.Numel (), * (O * Tuple (X.Shape))) afirmam y.hgradado[o – 1].Shape == (z.numel (), * (o * tupla (y.shape))) ## Verifique os primeiros derivativos (jacobianos) fn = lambda x, y: f.scaled_dot_product_attion (x, yt, yt) j = toch.[0].flatten (), x.hgrad[0].flatten (), atol = 1e-6) afirmam torch.allclose (j[1].flatten (), y.hgrad[0].flatten (), atol = 1e-6) ## Verifique os segundos derivativos (hessianos) fn = lambda x, y: f.scaled_dot_product_attention (x, yt, yt) .sum () h = tch.autograd.functional.hessian (fn (x, y)[0][0].flatten (), x.hgrad[1].SUM (0) .FLATTEN (), ATOL = 1E-6) ASSERT TORCH.ALLCLOSE (H[1][1].flatten (), y.hgrad[1].SUM (0) .Flatten (), ATOL = 1E-6) Digite o modo de tela cheia de tela cheia. Instanciação Use o construtor para criar um controlador para qualquer tensor que requer gradientes: controlador = thoad.Controller (tensor = go) ## leva o tensor de saída do gráfico Digite o modo de tela cheia de tela cheia tensor: um tensor de pytorch com requer_grad = um true e não-nona grad_fn. Propriedades .Tensor → Tensor o tensor de saída subjacente a este controlador. Setter: substitui o tensor (após a validação), reconstrua o gráfico de computação interna e invalida quaisquer gradientes previamente calculados. .Compatible → BOOL indica se toda função reversa no subgrafista do tensor tem uma implementação de alta ordem suportada. Se falso, alguns derivados podem recuar ou não estarem disponíveis. .index → ​​dict[Type[torch.autograd.Function]Tipo[ExtendedAutogradFunction]]Um mapeamento das classes Base Pytorch AutoGRAD.FUNCIONS para as implementações de função estendida do Thoad. Setter: valida e injeta suas extensões de alta ordem personalizadas. Métodos principais .backward (ordem, gradiente = nenhum, cruzamentos = false, grupos = nenhum, keep_batch = false, ket_schwarz = false) → Nenhum executa a passagem para trás de alta ordem para a ordem de derivada especificada, armazenando todos os parciais calculados no atributo. Ordem (int> 0): Ordem de derivado máximo. gradiente (opcional[Tensor]): Gradiente a montante personalizado com a mesma forma que o controlador.tensor. cruzamentos (bool, padrão false): se verdadeiro, derivados parciais mistos em diferentes tensores de folhas serão calculados. grupos (opcional[Iterable[Iterable[Tensor]]]padrão, nenhum): Quando as cruzes = falsas restringem parciais mistos àqueles cujos tensores da folha estão todos dentro de um único grupo. Se as cruzes = verdadeiras e os grupos forem fornecidos, um ValueError será aumentado. keep_batch (bool, padrão false): controla se os eixos de saída independentes são mantidos separados (lotados) ou mesclados (achatados) em gradientes armazenados/recuperados. keep_schwarz (bool, padrão false): se verdadeiro, retém permutações simétricas explicitamente (sem redução de schwarz). .Display_Graph () → Nenhum imprime uma representação de árvore do subgraffão atrasado do tensor. Os nós suportados são mostrados normalmente; Os não suportados são anotados com (não suportado). .register_backward_hook (variáveis: sequência[Tensor]gancho: chamável) → Nenhum registra um gancho fornecido pelo usuário para ser executado durante o passe para trás sempre que os gradientes para qualquer uma das variáveis ​​de folhas especificadas são calculadas. variáveis ​​(sequência[Tensor]): Tensores de folha para monitorar. gancho (chamável[[Tuple[Tensor, Tuple[Shape, …]Tupla[Indep, …]]dito[AutogradFunction, set[Tensor]]]Tupla[Tensor, Tuple[Shape, …]Tupla[Indep, …]]]): Recebe o atual (Tensor, Shapes, Independs), além de informações contextuais e deve retornar o triplo modificado. .require_grad_ (variáveis: sequência[Tensor]) → Nenhum marca as variáveis ​​folhas fornecidas para que todos os parciais intermediários envolvendo sejam retidos, mesmo que não sejam necessários para os gradientes finais solicitados. Útil para inspecionar ou reutilizar intermediários de ordem superior. .Fetch_HGrad (Variáveis: Sequência[Tensor]Keep_batch: bool = false, Keep_schwarz: bool = false) → Tupla[Tensor, Tuple[Tuple[Shape, …]Tupla[Indep, …]Vperm]]recupera a parcial de alta ordem pré-computada correspondente à sequência ordenada de variáveis ​​foliares. variáveis ​​(sequência[Tensor]): Os tensores da folha cujo parcial misto você deseja. keep_batch (bool, padrão false): se verdadeiro, cada eixo de saída independente permanece uma dimensão em lote separada no tensor retornado; Se falsos, os eixos independentes são distribuídos/mesclados em dimensões derivadas. keep_schwarz (bool, padrão false): se true, retorna derivativos que retêm as permutações simétricas explicitamente. Retorna um par: Tensor de gradiente: os derivados parciais computados, moldados de acordo com as dimensões de saída e entrada (respeitando o KEEND_BATCH/KEEND_SCHWARZ). Formas de tupla de metadados (tupla[Shape, …]): A forma original de cada tensor de folhas. Independes (tupla[Indep, …]): Para cada variável, indica quais eixos de saída permaneceram independentes (lote) vs. que foram mesclados em eixos derivados. Vperm (tupla[int, …]): Uma permutação que mapeia o layout de derivado interno para a ordem das variáveis ​​solicitadas. Use a combinação de informações e formas de dimensão independente para remodelar ou interpretar o tensor de gradiente retornado no seu fluxo de trabalho. Importar a importação de importação da tocha.nn Importar funcional como f #### Normal pytorch fluxo de trabalho x = Torch.rand (size = (10,15), requer_grad = true) y = tcorch.rand (size = (15,20), requer_grad =) z = f.scaled_dot_production_attnt), requer_grad =) z, f.scaled_dot_product. THOAD CONTROLADOR E CALL ORDER ACT para = 2 controlador = thoad.Controller (tensor = z) controlador.backward (Ordem = Ordem, cruzamentos = true) #### Fetch Derivados parciais ## busque T0 e T1 Derivados de 2ª ordem (xxx, x) _). controlador.fetch_hgrad (variáveis ​​= (y, y)) afirmam torch.allclose (parcial_xx, x.hgradado[1]) afirme Torch.allClose (Parcial_yy, y.hgradado[1]) ## buscar derivados cruzados parcial_xy, _ = controller.fetch_hgrad (variáveis ​​= (x, y)) parcial_yx, _ = controlador.fetch_hgrad (variáveis ​​= (y, x)) Entre no modo de tela cheia de saída do modo de tela cheia nota. Um guia do usuário mais detalhado com exemplos e a passo a passo que está disponível no caderno: se você tentar, eu adoraria feedback sobre a API, casos de esquina e modelos em que você deseja melhor plug and play suporta.

Fonte

Você pode ter perdido