Pytorch: Integrando tensores complexos

Criado em 16 fev. 2017  ·  128Comentários  ·  Fonte: pytorch/pytorch

Nova descrição de @ezyang :

O trabalho está em andamento em https://github.com/Roger-luo/pytorch-complex

Princípios organizacionais

  • O suporte a tensores complexos é importante para o PyTorch, e aceitaremos patches no núcleo que adicionam pequenas quantidades de código para adicionar suporte complexo.
  • Adicionar complexo envolve escrever muitos novos kernels e códigos: gostaríamos que esse código ficasse inicialmente fora do repositório, para que seja mais fácil para as pessoas iterar rapidamente neles sem precisar passar pelo processo de revisão de código principal do PyTorch. NÃO nos comprometeremos a revisar novos kernels grandes no curto prazo, mas eventualmente gostaríamos que todos os kernels voltassem ao PyTorch.
  • A biblioteca externa poderá ser construída separadamente do PyTorch, então você poderá mantê-la como um repositório separado sem precisar mesclar com o PyTorch (e lidar com muitos conflitos de mesclagem).

    • O PyTorch pode ocasionalmente fazer alterações importantes na API C++; se você trouxer isso ao nosso conhecimento, faremos o possível para ajudar a resolver esses problemas.

  • Os ganchos necessários para isso NÃO serão fornecidos com o PyTorch 1.0, mas serão fornecidos com uma versão lançada do PyTorch em um futuro não muito distante.

Como vou trabalhar em kernels complexos?

Aqui está a aparência do fluxo de trabalho no estado estável.

O PyTorch conterá nativamente APIs para se referir ao dtype complexo, mas não fará nada por padrão. PyTorch define torch.complex64 e torch.complex128 referindo-se a tensores complexos. No entanto, se você tentar construir um tensor dessa maneira, por padrão, o PyTorch apresentará um erro:

>>> torch.zeros({2,2}, dtype=torch.complex64)
RuntimeError: complex64 not supported by PyTorch

@ezyang forneceu um patch que adiciona esses dtypes ao PyTorch. https://github.com/pytorch/pytorch/pull/11173

No médio prazo, mesclaremos o suporte para a funcionalidade básica (como alocar um tensor de zeros) para ser suportado pelo PyTorch nativamente. Um proxy razoável para o que o suporte é “básico” é o suporte nativo do PyTorch para semitensores de CPU (que são extremamente empobrecidos).

PyTorch publica uma interface para registrar uma implementação de tensores complexos. A implementação herda da classe TypeDefault (https://github.com/pytorch/pytorch/pull/11013) e substituirá métodos nessa classe para definir implementações de funções para as quais temos implementações complexas. Vai parecer algo assim:

struct CPUComplexFloatType final : public TypeDefault {
  virtual Tensor add(const Tensor & self, const Tensor & other, Scalar alpha=1) const override {
    // Your implementation of add for complex tensors
  }
  // ...
}

Essa classe substituirá exatamente os tipos que são suportados por complexos; todas as outras implementações são fornecidas pelo TypeDefault e apresentarão erros por padrão.

Haverá uma lista canônica de métodos suportados em Type (a interface geral) como um arquivo gerado automaticamente que é verificado no repositório de origem do PyTorch; comunicaremos as alterações da API por diferenças para este arquivo. Em geral, os métodos estão em correspondência um-para-um com seus nomes correspondentes no frontend do PyTorch.

Em geral, quando você usa uma operação que ainda não implementou,

AVISO: Pretendemos refatorar o Type em um novo sistema que também suporte o registro aberto de novas operações (isso obviamente não funciona se você tiver uma única superclasse que defina todos os métodos aos quais você pode querer dar suporte). Portanto, tente não ficar muito preso à estratégia de implementação específica de escrever Type como uma subclasse.

Para publicar novas operações apenas complexas, você usará a API de extensão C++. A API de extensão C++ está documentada em https://pytorch.org/tutorials/advanced/cpp_extension.html Essencialmente, você pode escrever uma função C++ como:

at::Tensor imag(at::Tensor z) {
  ...
}

E, em seguida, a API de extensão C++ gerará uma ligação Python para que você invoque essa função do Python.

Algumas operações serão “fáceis” de integrar ao PyTorch como existe hoje. Por exemplo, para implementação de operações binárias, provavelmente faz mais sentido estender add_kernel em BinaryOpsKernel.cpp para que ele despache sobre tipos complexos (e então você o obtém gratuitamente, porque std::complex implementa adição). Desde que esses patches sejam pequenos e independentes, prometemos mesclá-los em tempo hábil.

SEMPRE deve ser possível desbloquear, apenas escrevendo uma substituição em Type em vez de usar a infraestrutura existente e fazendo uma colagem de cópia liberal. Mas vamos evitá-lo quando é fácil!

Autograd. Contanto que você esteja trabalhando em operações que já tenham fórmulas derivadas definidas para elas, você obterá “automaticamente” suporte autograd, contanto que implemente suporte complexo para todas as funções constituintes que são invocadas na implementação inversa de derivadas.yaml .

Em alguns casos, talvez seja necessário ajustar as fórmulas autograd para que funcionem para números complexos; por exemplo, o gradiente de 'abs' não é 'grad . self.sign()'. Nesses casos, tudo o que precisamos fazer é corrigir o upstream de alterar a fórmula autograd de 'abs' para 'abs_backward', que é uma função que pode ser substituída.

Para propagação de retorno de valor complexo geral, existem algumas referências:

  1. “Redes Neurais de Valor Complexo” de Akira.
  2. https://giggleliu.github.io/2018/02/01/complex_bp.html

Geralmente, não precisaremos modificar o autograd, pois na maioria dos casos calculamos apenas as derivadas de uma função de valor real (a perda).

Plano de trabalho

Muitas das peças necessárias estão no lugar hoje, mas não são montadas de uma forma completa. Aqui está o que precisa ser feito.

  • [X] Codemod TH para não ifdef real https://github.com/pytorch/pytorch/pull/11163
  • [X] Suporte integrado para torch.complex64 e torch.complex128 dtypes. https://github.com/pytorch/pytorch/pull/11173
  • [X] Uma interface para registrar CPUComplexType, etc., para que essa implementação seja invocada quando você solicita um tensor complexo com dtype=torch.complex64 ou faz uma operação em tensores complexos.
  • [X] Terreno https://github.com/pytorch/pytorch/pull/11013
  • [X] Um exemplo de ponta a ponta, incluindo um sistema de construção funcional, de um programa C++ compilável separadamente que se conecta com a libtorch e usa a interface mencionada para implementar a alocação de tensor complexa.

Plano de integração de curto prazo. Essas operações são “fáceis” de implementar e, portanto, devemos colocá-las no PyTorch o mais rápido possível.

  • [X] Fábricas básicas de tensores: torch.empty, torch.zeros, torch.ones
  • [ ] Operações binárias da CPU: add, sub, mul, div #11641
  • [ ] FFT
  • [ ] ???

Implementação do kernel:

TODO: Gerar uma lista com base em https://github.com/Roger-luo/TH/blob/master/ChangeLog.md

Outras tarefas relacionadas complexas:

  • [ ] Descubra as regras de promoção de tipo para tensores complexos e implemente-as em promoteTypes #11641

Conteúdo histórico do problema

Comentário original de @PhilippPelz

Eu queria saber se há interesse em incorporar tensores complexos em pytorch.
Para suporte à CPU, existe o ztorch e escrevi z-cutorch ( https://github.com/PhilippPelz/z-cutorch ) há algum tempo. É um fork off cutorch antes da refatoração para CudaHalfTensor (ainda não tenho o hardware).
Se não for muito trabalho, gostaria de integrá-lo lentamente ao pytorch. Estou usando o matplotlib para plotar via fb.ptyhon e é uma dor enorme toda vez que reinstalo meu sistema (compilando todas as dependências), além disso, parece que o pytorch funcionará no Windows em breve, no qual um dos meus PCs experimentais é executado.
Eu também precisaria de gradientes complexos, então mais cedo ou mais tarde tocaria em autograd também.
Embora o tf suporte tensores complexos per se, parece que muitas operações ainda não o suportam (https://github.com/tensorflow/tensorflow/issues/2255), além de parecer um pouco pesado para meus propósitos.

Talvez alguém possa dizer algumas palavras sobre como e por onde começar com isso, se for uma ideia bem-vinda.

feature complex triaged

Comentários muito úteis

@sunilkpai , @boeddeker , @Randl ,

Obrigado pelo relatório sobre as derivadas complexas. Vou tentar seguir isso e voltarei na próxima semana. Eu pensei em adicionar alguns links aqui e descrever o status do projeto.

O status de números complexos não é oficialmente suportado e deve ser adicionado via extensão PyTorch:

Cada extensão contém duas coisas:

  • Um .cpp que contém qualquer registro de kernel matemático necessário.
  • Uma pasta test/ que contém versões muito simplificadas dos scripts de teste pytorch.
    Procure nos scripts de teste para ver quais kernels são suportados (e por que outros não são).

Por que não consigo imprimir um tensor complexo no console?

  • O objeto python do Tensor tem uma formatação de impressão bonita que chama algumas funções que não são suportadas.

    • Você pode modificar o conteúdo de tensor.py para ignorar a formatação de impressão.

    • Ou você pode simplesmente converter tensores Pytorch em matrizes Numpy e depois imprimir.

Status atual do projeto:

  • A cobertura da CPU é muito boa.

    • Os Kernels são implementados dentro do PyTorch em 'aten/src/ATen/native/cpu/ </li> <li>Complex number specific code is under 'aten/src/ATen/native/cpu/zmath.h

    • A aceleração Intel AVX256 está em 'aten/src/ATen/cpu/vec256/`



      • @sunilkpai : Eu não conhecia a otimização do exp. Esta é a pasta onde você adiciona isso.


      • Deixe-me saber se você se sente à vontade para fazer a alteração.



  • A cobertura da GPU é limitada a operações binárias e unárias:

    • Os Kernels são implementados dentro do PyTorch em 'aten/src/ATen/native/cuda/* </li> <li>Complex number specific code is under 'aten/src/ATen/native/cuda/zmath.cuh

    • Os tipos de dados thrust::complex<T> são usados ​​e incluem os kernels otimizados.

Desenvolvimento atual:

  • Aguardando que os kernels TH baseados em C sejam portados para a pasta C++ ATen.

    • A função rand() é necessária para portar os casos de teste para os testes internos do pytorch.

    • Algumas operações de indexação não são portadas no momento.

    • Existem atualmente 168/1300 kernels matemáticos (abaixo de 230 em outubro) que precisam ser portados de TH para Aten.

  • Tentarei adicionar suporte a números complexos à medida que esses kernels se tornarem disponíveis no Aten.

--

Todos 128 comentários

Acho que estaríamos interessados ​​em adicionar um suporte opcional para tensores complexos. A melhor maneira seria bifurcar e trabalhar nas bibliotecas C em torch/lib . Isso deve ser livre de conflitos com o mestre, para que você possa fazer isso por um longo tempo. Depois de colocar as bibliotecas em um estado utilizável, você pode começar a escrever as ligações, e é aqui que podemos fornecer algumas orientações sobre como evitar conflitos nesse momento.

Eu tenho TH com compilação de tipos complexos. O que preciso adicionar para a integração do python?

@PhilippPelz você quer dizer como: https://github.com/facebook/ztorch/tree/master/lib/THZ ? ou você construiu seu próprio fork de TH que permite tipos complexos?

@killeent tem algumas notas sobre como o TH está vinculado ao Python, ele pode compartilhá-las.

Em geral, para obter tensores complexos, prefiro o THZ, pois possui testes, etc.

Construir um backend CUDA para tensores complexos, porém, é um esforço bastante grande, ainda nem começamos isso.

Eu escrevi z-cutorch ( https://github.com/PhilippPelz/z-cutorch ) um tempo atrás. É um fork off cutorch antes da refatoração para CudaHalfTensor (ainda não tenho o hardware).

Isso é ótimo. Acho que você já fez um grande esforço nessa direção :)

@soumith eu fiz um fork do TH com tipos complexos. Basicamente um THGenerateComplexTypes.h + rotinas BLAS + LAPACK adicionadas o resto foi quase de graça. Parecia muito menos trabalhoso para mim do que verificar quais partes do THZ são compatíveis e depois copiar e colar.

Estou preso a compilar o THPP agora, descobrindo mensagens do compilador como

/home/philipp/projects/pytorch/torch/lib/tmp_install/include/TH/generic/THBlas.h:6:40: erro: esperado ',' ou '...' antes do token '*'
TH_API void THBlas_(swap)(long n, real *, long incx, real *, long incy);

é um pouco complicado.

Gostaria de ajuda sobre como habilitar a integração python. O backend CUDA deve ser principalmente copiar e colar do z-cutorch.

@PhilippPelz aqui estão algumas notas sobre o PyTorch wraps TH: https://gist.github.com/killeent/4675635b40b61a45cac2f95a285ce3c0

@killeent obrigado, parece muito útil. lib/build_all.sh está compilando agora, acho que posso olhar para o diretório csrc.

Isso agora é executado:

importar tocha como th
importar numpy como np

a = np.array([1+1j,2+2j])
b = np.array([3+3j,4+4j])
ath = th.from_numpy(a)
bth = th.from_numpy(b)
ath_cuda = ath.cuda()
ath_cuda += bth.cuda()
ath = ath_cuda.cpu()
print(ath.numpy())

Fora: [ 4.+4.j 6.+6.j]

juntamente com a maioria das funções matemáticas.
Vou adicionar funções de conveniência e ffts nas próximas semanas. Eu acho que precisa haver testes para tudo antes que você possa mesclar isso. Se você conhece alguém que esteja interessado em tensores complexos e esteja disposto a contribuir para escrever os testes, isso seria incrível. Este artigo vem à mente: Deep Complex Networks , talvez esses caras estejam interessados.
Não terei tempo de escrever todos os testes sozinho.

@PhilippPelz Obrigado por seus comentários. Estou verificando sua implementação. E em primeiro lugar, não tenho certeza sobre sua implementação ger . Algumas funções blas complexas não estão incluídas em seu THBlas.c como você definiu GER como zger_ e cger_ nos cabeçalhos de geração, mas não há função blas com cger_ no generic/THBlas.c . No entanto, posso usar seu gemv e algumas outras funções. E IMO talvez você deva adicionar .gch ao .gitignore? Você empurrou todas as suas extensões para o seu fork? Posso fazer uma solicitação de pull para seu mestre com base em sua implementação primeiro.

E para DOT acho que talvez para vetores complexos, dotc rotinas para ponto são mais comuns?

E sim, se apenas usar real será mais fácil de implementar, eu estava me sentindo estranho quando real é realmente um complexo ...

E para testes, não vi nenhum teste anterior para TH. Onde devo escrever esses testes? ou nós apenas escrevemos alguns testes python

Sim, desculpe, vejo que posso não ter empurrado tudo o que é necessário. Vou verificar novamente na segunda-feira. Algumas declarações estão faltando, por exemplo. zger e cger

Para DOT estou usando cdotc e zdotc, parecem estar faltando, atualizarei semana que vem.

Verifique com os mantenedores do pytorch qual nome eles preferem de verdade. Eu gosto mais da sua versão, só não me esforcei ainda.

Sim, testes python para as coisas matemáticas. Deve ser facilmente alterado para que a maioria das funções também inclua verificações de número compelx.

Legal que você também está olhando para isso!

Ok, eu empurrei algumas alterações. As rotinas TH blas estão lá agora para tarefas complexas

@PhilippPelz Acabei de fazer um pull request para seu repositório. E para camadas lineares complexas e alguns outros operadores. poderia haver muitas operações hermitianas (como bp para camada linear complexa). Talvez adicionar alguma função para um tensor? Você verificou a parte THNN?

Sim Hermitian é útil. cuda fft está funcionando agora. cpu fft pode ser encapsulado a partir de numpy. Eu não toquei THNN ou THCUNN ainda.

@PhilippPelz Adicionei um simples eremita no PR. E você poderia revisá-lo. Assim, podemos ver se essas mudanças são adequadas e passar para a próxima etapa. Obrigado! PS. parece que você perdeu alguns cabeçalhos, eu também corrijo isso e alguns outros avisos. Para função complexa com saída real, devemos retornar um tensor real em vez de um tensor complexo? Implementei métodos de cópia entre tipos complexos e reais, então é possível.

Farei o rebase de todos os commits após sua revisão.

@PhilippPelz Oi, estou bastante confuso com a parte THPP que você implementou. Por que tem dependência de empuxo em Traits.hpp ?. Isso causará erro ao compilar sem cuda. É possível usar apenas comoouem Traits.hpp ? Eu não descobri. Talvez você possa oferecer algumas pistas?

@Roger-luo Sim, também estou tendo alguns problemas com isso em outros lugares. Os tipos complexos que estamos usando devem ser de complex.h ou std::complex. Como o THPP é o wrapper do C++, talvez std::complex seja mais apropriado. Você pode por favor mudar isso?

O Thrust também está causando problemas exatamente pelo mesmo motivo ao tentar criar extensões cffi. No momento, estou fazendo uma solução alternativa, mas a maneira correta seria alterar o tipo complexo para cuFloatComplex/cuDoubleComplex no THC. para que o compilador cffi não reclame. Eu só quero continuar com a pesquisa agora, isso está tomando muito tempo de mim :( . Se você tiver tempo, por favor, faça isso.

Além disso, construir a extensão cffi com chamadas de kernel personalizadas é bastante complicado, porque sempre é preciso criar uma biblioteca extra compilada com nvcc, que é então vinculada a um wrapper cffi. Acho que não tem outro jeito. Pode-se usar cffi no modo ABI, mas o site diz que "O modo API compila um wrapper CPython C que invoca diretamente a função de destino. É, comparativamente, massivamente mais rápido (e funciona melhor do que o libffi)."

@PhilippPelz talvez reinterpret_cast possa ser uma solução? Eu acho que deve ser alterado para cuComplex e usar reinterpret_cast em THPP. Vou tentar primeiro...

Sim, acho que não há outra maneira senão reinterpret_cast se você quiser que o THPP seja construído também sem o cuda instalado.

@PhilippPelz Gostaria de ajudar. Existe alguma lista de tarefas em algum lugar?

THNN e THCUNN precisam ser habilitados para tipos complexos. Você pode coordenar com @roger-luo? Além disso, se pretendemos a integração com o mestre, os testes de unidade precisam ser escritos para todos os métodos complexos.

@elbamos A maior parte do trabalho em THNN será sobre a implementação de novos métodos complexos de retropropagação para cada camada existente. Há um WIP PR na bifurcação de Philipp. Listei algumas referências.

@apaszke @soumith @PhilippPelz E há duas perguntas:

  • alguém sabe por que há outro GenerateXXXTypes.h arquivo em THS ? Parece o mesmo com aqueles em TH .

  • Para que serve o seguinte código em byte_order.cpp ?

void THP_decodeFloatBuffer(float* dst, const uint8_t* src, THPByteOrder order, size_t len)
{
  for (size_t i = 0; i < len; i++) {
    union { uint32_t x; float f; };
    x = (order == THP_BIG_ENDIAN ? decodeUInt32BE(src) : decodeUInt32LE(src));
    dst[i] = f;
    src += sizeof(float);
  }
}

void THP_decodeDoubleBuffer(double* dst, const uint8_t* src, THPByteOrder order, size_t len)
{
  for (size_t i = 0; i < len; i++) {
    union { uint64_t x; double d; };
    x = (order == THP_BIG_ENDIAN ? decodeUInt64BE(src) : decodeUInt64LE(src));
    dst[i] = d;
    src += sizeof(double);
  }
}

Alguma sugestão sobre a implementação de sua versão complexa relacionada? Não tenho certeza se a implementação a seguir está correta ...

void THP_decodeZFloatBuffer(std::complex<float>* dst, const uint8_t* src, THPByteOrder order, size_t len)
{
  for (size_t i = 0; i < len; i++) {
    union { uint64_t x; std::complex<float> cf;};
    x = (order == THP_BIG_ENDIAN ? decodeUInt64BE(src) : decodeUInt64LE(src));
    dst[i] = cf;
    src += sizeof(std::complex<float>);
  }
}

void THP_decodeDoubleBuffer(std::complex<double>* dst, const uint8_t* src, THPByteOrder order, size_t len)
{
  for (size_t i = 0; i < len; i++) {
    union { uint128_t x; std::complex<double> df;};
    x = (order == THP_BIG_ENDIAN ? decodeUInt128BE(src) : decodeUInt128LE(src));
    dst[i] = df;
    src += sizeof(std::complex<double>);
  }
}

decodeUInt128XE anterior é declarado como

static inline uint128_t decodeUInt128LE(const uint8_t *data) {
  return (((uint128_t)data[ 0])<<  0) | (((uint128_t)data[ 1])<<  8)|
         (((uint128_t)data[ 2])<< 16) | (((uint128_t)data[ 3])<< 24)|
         (((uint128_t)data[ 4])<< 32) | (((uint128_t)data[ 5])<< 40)|
         (((uint128_t)data[ 6])<< 48) | (((uint128_t)data[ 7])<< 56)|
         (((uint128_t)data[ 8])<< 64) | (((uint128_t)data[ 9])<< 72)|
         (((uint128_t)data[10])<< 80) | (((uint128_t)data[11])<< 88)|
         (((uint128_t)data[12])<< 96) | (((uint128_t)data[13])<<104)|
         (((uint128_t)data[14])<<112) | (((uint128_t)data[15])<<120);
}

static inline uint128_t decodeUInt128BE(const uint8_t *data) {
  return (((uint128_t)data[15])<<  0) | (((uint128_t)data[14])<<  8)|
         (((uint128_t)data[13])<< 16) | (((uint128_t)data[12])<< 24)|
         (((uint128_t)data[11])<< 32) | (((uint128_t)data[10])<< 40)|
         (((uint128_t)data[ 9])<< 48) | (((uint128_t)data[ 8])<< 56)|
         (((uint128_t)data[ 7])<< 64) | (((uint128_t)data[ 6])<< 72)|
         (((uint128_t)data[ 5])<< 80) | (((uint128_t)data[ 4])<< 88)|
         (((uint128_t)data[ 3])<< 96) | (((uint128_t)data[ 2])<<104)|
         (((uint128_t)data[ 1])<<112) | (((uint128_t)data[ 0])<<120);
}

Atualmente estou usando std::complex<T> em vez de T _Complex em THPP . Não tenho certeza se isso pode ser usado pelo Python ainda. Ou apenas o tipo c T _Complex é utilizável para python. Então aqui o tipo de dst é std::complex<T> .

E se estou correto para esta implementação, provavelmente precisamos de uma implementação uint128_t , como https://github.com/calccrypto/uint128_t ? Como parece que nem todos os compiladores suportam inteiros de 128 bits (o gcc tem um int128_t e um uint128_t).

@PhilippPelz notei que seu fork não tem problemas ativados - qual é o status do seu projeto? estou um pouco chateado que tensores complexos não estão no roteiro para pytorch

@el3ment Eu adicionei um backend complexo para CPU https://github.com/pytorch/pytorch/pull/4899 Mas ainda não foi revisado ... E não recebi nenhum comentário para meu PR, então passei a usar a linguagem de programação Julia recentemente...

Enviei um email para @PhilippPelz da última vez, acho que o repositório dele ainda está na v0.1 e ele está ocupado com a tese até setembro? E eu estava trabalhando no novo backend CUDA da v0.3, mas não tenho tempo para terminar todas essas ligações sozinho. As funções map/reduce são diferentes da v0.1 com algumas otimizações, mas não podem ser convertidas trivialmente para suportar números complexos. Ficarei feliz se alguém estiver disposto a ajudar...

Estou disposto a ajudar.

Em 10 de abril de 2018, às 22h52, Rogerluo [email protected] escreveu:

@el3ment Eu adicionei um back-end complexo para CPU #4899

Enviei um email para @PhilippPelz da última vez, acho que o repositório dele ainda está na v0.1 e ele está ocupado com a tese até setembro? E eu estava trabalhando no novo backend CUDA da v0.3, mas não tenho tempo para terminar todas essas ligações sozinho. As funções map/reduce são diferentes da v0.1 com algumas otimizações, mas não podem ser convertidas trivialmente para suportar números complexos. Ficarei feliz se alguém estiver disposto a ajudar...


Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub ou silencie a conversa.

@elbamos legal, parece que a equipe pytorch prefere uma implementação separada. Vou atualizar meu fork mais tarde para as outras partes mais tarde. Mas eu realmente não tenho tempo para isso e acho que devemos começar a trabalhar nisso quando houver um plano da equipe do pytorch, porque isso seria uma grande extensão para o pytorch.

Oi, meu código está em algum commit após a v0.2

Eu tinha visto que havia uma refatoração bem grande movendo todo o código do tensor para o Aten. Isso significa que não é possível mesclar facilmente meu fork na versão atual e pode haver mais trabalho envolvido.

Ainda estou escrevendo meu Ph.D., mas estava planejando esperar pelo 0.4 de qualquer maneira até que a mesclagem de Variável e Tensor seja lançada. Temo que possa haver muita refatoração acontecendo para alcançá-lo se alguém fizer isso mais cedo.

@elbamos , se você quiser, pode começar a adicionar coisas ao meu fork, eu farei o merge. No seu lugar, eu apenas implementaria o que você precisa para qualquer projeto que esteja fazendo. TH(CU)NN é uma interface muito grande e seria uma grande carga de trabalho.

@el3ment Não tenho tempo para trabalhar nos problemas dos outros. No entanto, vou mesclar coisas se você precisar implementar algo que não está lá.

Se você quer apenas algo que funcione com números complexos prontos para uso, eu recomendo o tensorflow.

Também ajudarei se houver problemas de compilação.

Se eu continuar com o postdoc, em algum momento portarei todas essas coisas para a versão atual. É realmente triste que o Facebook não queira apoiar isso. :((

@PhilippPelz Concordo, é muito triste e, na verdade, o tensorflow não suporta todos os operadores da física quântica ... comecei a usar Julia e abandonei o python.

@Roger-luo interessante, você está usando um pacote julia específico ou é todo código auto-escrito?

@PhilippPelz Estou desenvolvendo um kit de ferramentas quântico de muitos corpos em Julia (desde que o PyTorch PR), inclui uma implementação de rede neural complexa/real com base em alguns artigos anteriores sobre rede neural complexa, e descobri que é tão fácil desenvolver com Julia metaprogramação. No momento, acabei de colocá-lo em QMTK.jl , ele ainda está em andamento e não terminei tudo o que quero. O PyTorch me inspira muito, mas sinto muito pelo suporte complexo...

Mas eu tenho planos de separá-lo para um único pacote de rede neural no futuro (só não quero manter vários repositórios no momento). E haverá mais pessoas a aderir ao desenvolvimento do Instituto de Física, CAS. Aceitarei PRs após sua primeira versão marcada (que será em algumas semanas).

Você pode assisti-lo se estiver interessado em seu desenvolvimento.

Se a equipe do PyTorch ainda tiver planos para suporte complexo no futuro, estarei disposto a ajudar.

Legal, vou ficar de olho!

Olá pessoal, desculpe por não termos respondido a esse problema desde que foi aberto.

Aqui estão dois fatos:

  1. Concordamos absolutamente que o PyTorch precisa de suporte complexo e
  2. Não temos mão de obra para preencher adequadamente a cauda longa que todas as operações complexas precisariam. (Para evidência disso, observe o suporte esparso, que está no mestre e está mancando.)

Desde que esse problema foi aberto em 2017, algumas coisas importantes mudaram que podem tornar a implementação de suporte complexo um pouco mais simples. A primeira é que agora temos Aten, uma biblioteca C++ ergonômica para manipulação de tensores. Isso significa que você não precisa copiar e colar trechos gigantes de código TH/THC e esperar que tenha acertado toda a contagem manual de referências, você pode escrever código C++ como se fosse Python e ele será executado rapidamente. A segunda é que estamos trabalhando em uma nova versão do Aten, chamada C10, que é muito mais séria em ter backends abertos do que o Aten (que é uma coisa fechada), o que deve facilitar o trabalho em suporte complexo, já que não t implica realmente bifurcar o PyTorch, apenas adicionando um novo diretório de código.

Então, @Roger-luo e @PhilippPelz , adoraríamos ter sua ajuda para tornar o back-end complexo uma realidade, mas gostaríamos muito de descobrir uma maneira de fazer isso que nos ajude a mantê-lo de forma sustentável no futuro. Deixe-nos saber o que você pensa.

@ezyang Se você não tiver mão de obra, eu poderia tentar manter a parte complexa do tensor no futuro, acabei de começar meu doutorado (e este é meu ano sabático na verdade) e, portanto, não terei o problema de escrever minha tese em últimos anos, pelo menos. Mas eu realmente não posso continuar contribuindo sem qualquer feedback da equipe pytorch. Eu acho que deveria haver um roteiro para essa grande extensão. E podemos adicionar suporte complexo sem problemas para que seus funcionários não precisem revisar um grande PR e isso facilitará os esforços dos desenvolvedores no rastreamento do branch master.

Em primeiro lugar, acho que o principal problema sobre suporte complexo seria a parte CUDA. É muito fácil suportar a parte da CPU com Aten ou qualquer outra biblioteca, posso reescrever a parte da CPU em apenas alguns dias se houver algum feedback. Existem alguns problemas que eu poderia me preocupar com a parte CUDA, e acho que isso pode levar a duas abordagens diferentes:

  1. Use float2 , etc. para simular um único valor complexo como cuComplex na parte CUDA.
  2. Use FloatTensor e DoubleTensor existentes para simular um tensor complexo na parte C++ do Aten.

A razão para a segunda abordagem é porque em THC , pytorch usa alguns truques para acelerar operações de mapeamento/redução e não é adequado para cuComplex trivialmente porque cuComplex é na verdade float2 , mas as funções __shfl_xxx não suportam nativamente float2 . Não tenho certeza de como simular eficientemente essa função para float2 no momento.

A segunda abordagem seria mais fácil porque agora não precisamos nos preocupar com o hardware e podemos fazer nossa nova extensão complexa funcionar em dispositivos antigos muito mais facilmente. No entanto, isso pode causar alguma sobrecarga devido ao endereço de memória contíguo.

Além disso, descobri que para integrar números complexos no Aten, podemos ter que lidar com quatro tipos diferentes que são realmente os mesmos em hardware: std::complex , thrust::complex , cuComplex , float2 que pode ser perigoso às vezes. (na verdade, eu encontrei esse problema no ano passado, e reinterpreter_cast foi a solução).

Eu pessoalmente preferiria escrever tudo mais nativo.

E acho que provavelmente precisamos de um cronograma ou roteiro, e podemos pegar cada pequena parte e trabalhar juntos, para que eu não precise rastrear o mestre, o que é totalmente impossível ...

houve um ChangeLog quando eu estava tentando implementar o backend da CPU, classifiquei as funções que precisam ser modificadas para números complexos no log. Poderíamos escrever um roteiro baseado neste log.

Além disso, como meu visto acabou de ser rejeitado (pela Austrália), eu tenho que começar um ano sabático, se você precisar de alguém para continuar trabalhando nisso, eu poderia me candidatar a um estágio.

Eu pensei muito sobre isso no último dia. É um pouco triste que não pudemos mesclar o esforço de Roger como está, mas pensei comigo mesmo

"como podemos construir um suporte tensor complexo, mantendo baixas despesas gerais de manutenção?"

Isto é o que estou apresentando como um plano eficaz a partir do objetivo acima:

  • Os tensores complexos não devem ser um novo tipo de tensor fundamental, como os tensores sparse . Adicionar um tipo fundamental causa muita sobrecarga de manutenção e mudanças transversais. A sobrecarga de manutenção não é sobre "quem mantém os bits complexos?", mas mais sobre "agora todos os desenvolvedores de núcleo devem estar cientes desse tipo complexo ao fazer qualquer alteração fundamental, qualquer alteração Aten, etc."

    • Em vez disso, eles devem sempre ser [Tensor Shape x 2] ou [2 x TensorShape], ou seja, o tensor deve ter uma dimensão extra com tamanho 2.

  • Os tensores complexos devem ser um pequeno arquivo/pasta de ~2k linhas de C++ simples que são construídos sobre a API do Tensor Aten.

    • Por exemplo, como sugere https://github.com/pytorch/pytorch/issues/6514 , a multiplicação complexa deve ser implementada como torch.stack([real1 * real2 - imag1 * imag2, real1 * imag2 + imag1 * real2], dim = -1) onde real1 = input1[:, :, :, ..., 0]

    • Isso prejudica o desempenho: sim, não teremos tanto desempenho como se inline tudo. No entanto, a pergunta é: "por quanto?". Acho que devemos buscar um desempenho 20% menor em troca de um suporte complexo saudável e completo + mantido.

    • As funções complexas mais usadas podem começar a obter kernels dedicados, de modo que, onde o desempenho está tendo mais de 20% de impacto em uma função usada com frequência, nós intervimos.

Tem que ser [Tensor Shape x 2] já que BLAS, cublas e MAGMA esperam seus próprios tipos complexos que são compatíveis com byte para float2. Além disso, as chamadas blas, cublas e magma não podem ser tratadas no nível do python.
Eu não acho que será apenas 20% para multiplicação complexa, você não tem 4 operações de cópia completas em cima dos cálculos para a parte real e imag?
De qualquer forma, eu ainda ficaria feliz se não precisasse mesclar as alterações do mestre continuamente.

Concordo com @PhilippPelz , podemos perder muito desempenho, pois perderemos o suporte complexo do BLAS, cublas e MAGMA. Mas eu não tenho certeza sobre isso. No entanto, para ser claro, o tensor complexo é algo completamente diferente do tensor esparso , a maioria das bibliotecas como scipy.sparse e SparseArrays de Julia tratam o array esparso como uma composição de arrays multidimensionais fundamentais. Mas ninguém trata uma matriz multidimensional com tipo complexo por duas matrizes reais compostas ... (ninguém aqui quero dizer tensorflow, arrayfire, numpy e Julia). Embora no MXNet, o FFT seja realizado por uma composição de dois tensores reais, na verdade, eles não suportam complexos ... Parece que o tensorflow implementou um DataType como um wrapper em torno de diferentes tipos de rede, incluindo complex64 e complex128 veja tipos.proto

Sobre a perda de desempenho

Em primeiro lugar, as funções elementares (funções chamadas map/reduce) não terão grande perda de desempenho (pelo menos, a memória para essas operações será contígua). Mas acho que devemos tentar fazer o benchmark de algumas funções BLAS primeiro, para ver se uma composição de FloatTensor tem desempenho semelhante com Complex64Tensor na GPU, e quanto perderemos no desempenho com um projeto de implementação, como:

  • gemm
  • gemv

Um tensor complexo composto seria algo parecido (ou apenas use shared_ptr ):

class ComplexTensor {
    FloatTensor *real;
    FloatTensor *imag;
};

No entanto, como mencionei na desvantagem da primeira abordagem, funções como __shfl_xxx também parecem um obstáculo se quisermos fazer isso de forma mais nativa.

atualmente torch.fft retorna um único tensor flutuante de forma [dim1, ..., dimN, 2]

@ezyang qual é o prazo para o lançamento do C10? Isso soa como um ponto muito razoável para começar a dar suporte ao complexo no branch master.

@PhilippPelz Definitivamente não para 0.4. Estamos mirando internamente em junho, espero que não demore muito para esperar.

@ezyang você mencionou junho, você conseguiu adicionar suporte para números complexos ao PyTorch?

Acho que ele quis dizer C10, não suporte complexo. C10 vai facilitar a adição de complexos. Foi assim que eu entendi.

Sim, o C10 terá registro aberto de ambos os tipos e funções de Tensor. Portanto, adicionar um tipo complexo como um pacote separado será muito mais fácil.

Existe algum ETA em números complexos? Será que "muito mais fácil" significa "provavelmente será feito rapidamente"?

@themightyoarfish muito mais fácil, quero dizer que não seremos bloqueados no que pode ser enviado para o pytorch master. Não definimos um ETA. Vou avaliar o trabalho assim que abrirmos o registro no PyTorch.

@soumith você ainda precisa de pessoas para trabalhar nisso (número complexo)? A equipe do PyTorch suportará números complexos? Posso passar algum tempo trabalhando nisso, se você quiser, em setembro, pois manterei o QuCumber (ele usará muito o número complexo)

@Roger-luo sim. Eu queria entrar em contato com você assim que tivermos o registro aberto disponível no back-end do PyTorch e pudermos resolver os detalhes.
@ezyang teremos inscrições abertas até setembro?

@soumith Cool, ao seu serviço.

Nós podemos fazer isso acontecer. (Não teremos o novo sistema "completo" em vigor, mas desde que configuremos as coisas para que seja refatorável, podemos continuar movendo-o à medida que novos desenvolvimentos acontecem. Será um bom caso de teste para o novo sistema aberto registro. Posso garantir que isso aconteça.)

@ezyang alguma nota até agora? Eu poderia lê-lo antes de trabalhar nele. Parece que as coisas mudaram muito desde a última vez.

@Roger-luo @PhilippPelz Também gostaria de ajudá-lo com a implementação de tensores complexos. Eu também preciso dele para minhas investigações de doutorado.

@alexgomezalanis talvez pudéssemos ter um canal para discutir no slack, acabei de criar uma chamada de canal #complex-numbers . Mas não começarei a trabalhar nele até setembro (ainda preciso trabalhar em alguns dos meus códigos Julia...)

BTW, parece mudou muito desde a última vez. Vou usar algum tempo para recuperar o atraso antes de colocar minhas mãos nele.

@alexgomezalanis não consigo. você precisa ingressar no espaço de trabalho do pytorch no slack primeiro. Não consigo te achar. Por favor, envie um e-mail para o endereço: [email protected] para receber um convite.

@Roger-luo @alexgomezalanis Ótimo ver a vida novamente na complexa questão do tensor. Posso me oferecer para me envolver também, mas, na realidade, isso não acontecerá até o final de setembro / início de outubro. Quanto a alguns comentaristas sobre esse assunto, o suporte a tensores complexos seria muito útil para meu projeto de doutorado.

Eu também estava tentando salvar minha pesquisa no ano passado 😏… mas agora eu só quero trazer meu antigo código 1w+ loc de volta à vida. 🤣 vamos bater um papo no slack!

:) Sim, vamos conversar no slack. Acabei de encontrar o convite na pasta de correio.

O plugin de trabalho em andamento (para CPU apenas em curto prazo) está aqui: https://github.com/Roger-luo/pytorch-complex

Por favor, sinta-se livre para me dar problema e PR.

Publiquei as notas sobre como a implementação complexa será realizada no início desta edição.

Recentemente, comecei a usar o PyTorch e adoro-o - é muito mais agradável de usar do que o TensorFlow. No entanto, o suporte a tensores complexos é bastante crítico para minha pesquisa (redes neurais ópticas). Isso ainda está sendo trabalhado ativamente? Em caso afirmativo, alguém conhece um período de tempo (solto) para suporte a tensores complexos?

Eu ficaria feliz em ajudar a trabalhar nisso onde eu puder, mas sou relativamente novo no PyTorch, então ainda não tenho uma boa ideia de quão grande é esse recurso. Alguns de meus colegas de laboratório também expressaram grande interesse no suporte a tensores complexos (em física, adicionar isso pode tornar o Torch quase um substituto acelerado por GPU para NumPy) e pode estar disposto a ajudar também se isso significar obter suporte complexo no futuro próximo.

Olá @bencbartlett

Ainda estou tentando trabalhar devagar.... mas atualmente sou apenas um estudante também (com uma situação bastante instável), o que significa que não posso trabalhar nisso em tempo integral, mas apenas nas horas vagas. (Eu implemento meu código relacionado à pesquisa em Julia do ano passado, o que significa que apenas nosso pacote legado precisa de um melhor suporte a números complexos do torch.).

Se o número complexo é crucial para você e é urgente tê-lo na tocha, sugiro que tente isso:

https://github.com/PIQuIL/QuCumber/blob/master/qucumber/utils/cplx.py

É super lento... mas pelo menos funciona. Ou eu tinha uma versão C no velho estilo TH.

Este não será um projeto pequeno que pode ser feito em poucos dias. Portanto, não posso garantir nenhum prazo específico para um suporte funcional completo com valor complexo em CPU ou CUDA.

Eu adoraria ajudá-lo a trabalhar comigo sobre isso no entanto. Eu sugiro que você comece tentando resolver os problemas que postei no repositório de extensões. E sinta-se à vontade para me perguntar através do slack ou e-mail ou problema se tiver dúvidas (já que ainda não há muitos documentos).

Ainda não tenho acesso ao PyTorch Slack, infelizmente. (Enviei e-mail duas vezes pedindo um convite, mas não obtive retorno.) Alguém poderia me convidar? ([email protected])

@Roger-luo Definitivamente vou dar uma olhada no seu fork, mas não posso prometer que vou ajudar muito - meu C++ está enferrujado e, como você apontou, é difícil encontrar tempo para trabalhar nisso como um estudante. Os utilitários QuCumber são bons, mas infelizmente eles não seriam muito úteis para mim: até que tensores complexos sejam suportados por GPU ou sejam suportados por autograd e torch.nn, eles não fornecem muita utilidade acima do que o NumPy pode oferecer.

@soumith @ezyang Seria ótimo receber mais atenção sobre isso da equipe PyTorch! O suporte complexo parece ser um recurso importante para uma biblioteca geral de tensores, é praticamente essencial na física e, especificamente no ML, nos últimos anos, tem havido um interesse crescente em modelos de valor complexo.

A abordagem do @bencbartlett QuCumber pode ser usada em GPU com AD ... é super lento ... quero dizer, se você quiser apenas esse AD, poderá usá-lo.

Sim, francamente falando, estou usando uma versão ligeiramente modificada de https://github.com/FluxML/Flux.jl e alguns meus próprios pacotes em Julia para pesquisa (eu preciso de AD complexo em GPU com tensores em alguma situação também ). O pacote de AD source2source Zygote.jl pode fazer AD em tensores complexos, mas está em um estágio muito inicial que pode ter falhas de segmento. O ecossistema ainda não é tão estável em comparação com a tocha, às vezes tenho que hackear um pouco essas implementações para uso próprio... Mas basicamente funciona para o que preciso para pesquisa em física quântica. Eu posso ter tensores complexos na GPU também.

Eu não acho que o suporte de valor complexo para torch.nn seja necessário, talvez precisemos apenas adicionar algumas definições para autograd uma vez que o tensor complexo é funcional, porque coisas como camadas lineares podem permanecer as mesmas . E alguma função de ativação pode não ter uma expansão padrão no espaço de Hilbert ... (Você pode verificar a postagem do blog do meu colaborador @GiggleLiu )

Para a extensão pytorch-complex, não tenho certeza de quando podemos obter suporte total com AD na GPU ... isso ainda parece muito longe para mim. Eu diria que a implementação da CPU passará por algum período que requer patches na árvore principal (por exemplo, promoções de tipo, suporte simd, etc.), isso também pode estar relacionado à próxima implementação do ATen em C++ e se livrar do TH, etc., e então poderemos adicionar operadores para tensores complexos mais rapidamente.

Posso me candidatar a estágios na primavera (sobre os quais acabei de perguntar a @ezyang ). Então, talvez eu possa trabalhar nisso em tempo integral por vários meses antes de começar meu doutorado. Vamos ver.

Enquanto isso, implementei minha própria versão da multiplicação complexa. No entanto, quando faço o perfil, ocorre que uma quantidade substancial de tempo vai para: torch._C_._cuda_isDriverSufficient

image

Tens alguma ideia do porquê? Se você souber de uma melhor implementação da multiplicação complexa, por favor me avise. De alguma forma, minha versão (mesmo que otimizada para o número de multiplicações: 3 em vez de 4) parece ser relativamente lenta, por exemplo, irfft do tensor out é 10X mais rápido que minha multiplicação por elementos. A multiplicação complexa é suportada no nível C++ do PyTorch?

def complex_mul(x, y, out):
    uavc = x[..., 0] * (y[..., 0] + y[..., 1])
    out[..., 0] = uavc - (x[..., 0] + x[..., 1]) * y[..., 1]
    out[..., 1] = (x[..., 1] - x[..., 0]) * y[..., 0] + uavc
def test_complex_mul_out_tensor(self):
        N, C, H, W, I = 128, 3, 32, 32, 2
        K = 16  # number of filter banks
        repetitions = 1000
        dtype = torch.float
        if torch.cuda.is_available():
            device = torch.device("cuda")
        else:
            device = torch.device("cpu")
        x = torch.randn(N, 1, C, H, W, I, dtype=dtype, device=device)
        y = torch.randn(K, C, H, W, I, dtype=dtype, device=device)
        start_mul_time = time.time()
        out = torch.empty(N, K, C, H, W, I, dtype=dtype, device=device)
        for _ in range(repetitions):
            complex_mul(x, y, out)
        print("multiplication time: ", time.time() - start_mul_time)

Estamos tentando apoiá-lo em C++. veja o post no topo. Se você pode compilar a extensão, ela deve funcionar para multiplicação escalar pelo menos no momento....

Sua implementação é semelhante ao que temos no QuCumber. Ele pode chamar muitos threads de GPU extras se você não chamar o kernel cuda correto para o número complexo. E você pode perder o SIMD se não tiver back-end C++ como suporte em Python.

Eu sugiro que você execute nvprof para obter mais detalhes.

@Roger-luo @apaszke @soumith Obrigado por este tópico btw. Eu implementei um tensor complexo básico hackeado de subclassing torch.Tensor.

Trato a primeira metade como real, a segunda como imaginária e implementei minhas próprias operações aritméticas básicas e algumas outras que preciso para minha pesquisa.

Eu verifiquei no Tensorflow e numpy. Os gradientes e todas as operações que implementei correspondem às suas saídas!

É apenas um resquício até que o PT suporte totalmente tensores complexos.

Recursos:

  1. Testes implementados.
  2. Pypi suportado (ou seja: pip install)
pip install pytorch-complex-tensor

https://github.com/williamFalcon/pytorch-complex-tensor

Obrigado @williamFalcon !

Alguma atualização dessa? Apenas imaginando se haverá um plano para integrar o suporte a tipos complexos no pytorch.

Olá, @whmrtm

@ezyang está trabalhando em https://github.com/Roger-luo/pytorch-complex/issues/4 Ou quem estiver interessado nisso pode nos ajudar a executá-lo. Este problema resolverá alguns problemas básicos de transmissão (então você poderá usar muitas funções depois que esta for resolvida). Por favor, sinta-se à vontade para fazer qualquer PR ou me pedir para adicioná-lo como colaborador.

Não poderei trabalhar em nada até o verão, tenho que terminar um novo lançamento para nosso próprio pacote.

Olá, @whmrtm

@ezyang está trabalhando em Roger-luo/pytorch-complex#4 Ou quem estiver interessado nisso pode nos ajudar a executá-lo. Este problema resolverá alguns problemas básicos de transmissão (então você poderá usar muitas funções depois que esta for resolvida). Por favor, sinta-se à vontade para fazer qualquer PR ou me pedir para adicioná-lo como colaborador.

Não poderei trabalhar em nada até o verão, tenho que terminar um novo lançamento para nosso próprio pacote.

Obrigado pela atualização, vou ver o que posso fazer.

Olá @Roger-luo

Posso acessar o canal de folga relacionado ao tópico de suporte a tensores complexos ([email protected])? Mandei um e-mail pedindo um convite, mas nada aconteceu ainda. Agora estou tentando descobrir pontos onde começar a contribuir para este problema. Acho que https://github.com/Roger-luo/pytorch-complex/issues/4 é um ponto de entrada atual agora?

@beconstant sim, esse é o ponto de partida, isso deve fazer alguma função de transmissão funcionar, mas não sei por que lança erro de promoção de tipo no cuda, estava funcionando na CPU. (Embora não pretendamos oferecer suporte ao cuda em primeiro lugar, isso causaria falha na compilação)

Não consigo enviar um e-mail de convite (não tenho acesso). Eu acho que você deve seguir o guia oficial do pytorch para participar do slack. Mas sempre podemos discutir na questão/PR.

@Roger-luo ok, entendi :)

Deixe-me saber se vocês precisam de alguma ajuda. Vou começar construindo a versão pytorch especificada. Algum progresso em pytorch-complex/issues/4 ?

Deixe-me saber se vocês precisam de alguma ajuda. Vou começar construindo a versão pytorch especificada. Algum progresso em pytorch-complex/issues/4 ?

@dylanbespalko Oi, preciso urgentemente de pytorch implementado na versão de valor complexo.
Muito obrigado por suas contribuições.

Atenciosamente,
Zelar209

Olá @Zellar209 ,

Estou tendo a sensação de que @ezyang está trabalhando duro em um dos maiores problemas ( pytorch-complex/issues/4 ). Eu tenho um sistema AMD agora e um sistema Nvidia em 3 semanas que posso usar para aumentar o suporte da GPU.

Eu acho que o problema é apenas sobre o tipo original de mudança de promoção quebra CUDA, desde que esse PR seja resolvido, pelo menos alguns operadores funcionam na CPU, ainda não temos suporte CUDA ...

IMHO Acho que devemos nos concentrar na CPU e fazer as coisas funcionarem primeiro, depois considerar a GPU mais tarde.

O suporte apenas à CPU é bom. Este tipo de problema de promoção ( pytorch-complex/issues/4 está sendo tratado internamente pelo fb? Tudo bem trabalhar nele externamente?

Olá @dylanbespalko; Eu disse ao @Roger-luo que ia investigar (porque provavelmente estava em melhor posição para descobrir qual é o problema), mas ainda não tive tempo de analisar. Se você quiser dar uma olhada para descobrir como resolver o problema, eu ficaria feliz em aconselhar.

Olá @Zellar209 ,

Estou tendo a sensação de que @ezyang está trabalhando duro em um dos maiores problemas ( pytorch-complex/issues/4 ). Eu tenho um sistema AMD agora e um sistema Nvidia em 3 semanas que posso usar para aumentar o suporte da GPU.

Sim, não preciso de nenhuma GPU agora, estou usando o sistema MAC. Mas eu tive alguns erros ao construir este projeto.

Oi @Zellar209 , você poderia postar o que você obtém no problema do pytorch-complex? Acho que há algo errado com o novo Xcode do Mac, o que dificulta a construção. Mas as pessoas precisarão de mais algumas mensagens de erro para descobrir o porquê.

Perguntei sobre o SO e a msg de erro, mas você não respondeu...

Olá @dylanbespalko; Eu disse ao @Roger-luo que ia investigar (porque provavelmente estava em melhor posição para descobrir qual é o problema), mas ainda não tive tempo de analisar. Se você quiser dar uma olhada para descobrir como resolver o problema, eu ficaria feliz em aconselhar.

Obrigado pela sua resposta antecipada.

1. Quando executo "python setup.py install" usando gcc (padrão), recebo erros como este:

construindo a extensão 'torch_complex.cpp'
gcc -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I/anaconda3/include -arch x86_64 -I/anaconda3/include -arch x86_64 -I/ anaconda3/lib/python3.6/site-packages/torch/include -I/anaconda3/lib/python3.6/site-packages/torch/include/torch/csrc/api/include -I/anaconda3/lib/python3. 6/site-packages/torch/include/TH -I/anaconda3/lib/python3.6/site-packages/torch/include/THC -I/anaconda3/include/python3.6m -c src/module.cpp -o build/temp.macosx-10.7-x86_64-3.6/src/module.o -g -stdlib=libc++ -std=c++11 -DTORCH_API_INCLUDE_EXTENSION_H -DTORCH_EXTENSION_NAME=cpp
gcc: erro: opção de linha de comando não reconhecida '-stdlib=libc++'

erro: o comando 'gcc' falhou com o status de saída 1

2. Quando uso clang para compilar, os erros são:

No arquivo incluído em src/module. cpp:2 :
No arquivo incluído em src/CPUComplexType.h:60:
src/CPUComplexTypeImpl.h:102:105: aviso: 'IntList' está obsoleto [-Wdeprecated-declarations]
Tensor & CPUComplexType::set_(Tensor & self, Storage source, int64_t storage_offset, IntList size, IntList strides) const {
^
/anaconda3/lib/python3.6/site-packages/torch/include/c10/util/ArrayRef.h:273:7: nota: 'IntList' foi explicitamente marcado como obsoleto aqui
usando IntList C10_DEPRECATED_USING = ArrayRef;
^
No arquivo incluído em src/module. cpp:2 :
No arquivo incluído em src/CPUComplexType.h:60:
src/CPUComplexTypeImpl.h:105:76: erro: nenhum membro chamado 'scalarTypeToDataType' no namespace 'at'
auto source_ = selected_storage(source,"source",2, DeviceType::CPU, at::scalarTypeToDataType(CPUComplexTypeInfo::scalar_type));
~~~~^
7 avisos e 2 erros gerados.

erro: o comando 'clang' falhou com o status de saída 1

Eu não posso corrigi-lo. Eu realmente espero que você possa me ajudar!

Ei pessoal,

Obrigado pelo seu feedback! Acho que posso passar a semana analisando isso. Até agora eu compilei o pytorch-complex do @Roger-luo da seguinte forma:

@Zellar209 : Anexei minhas variáveis ​​de ambiente em execução no macOS 10.13.

  1. Exclua a distribuição pytorch existente da seguinte maneira
    conda desinstalar pytorch
    tocha de desinstalação pip
    pip uninstall torch # execute este comando duas vezes
    python setup.py limpo
    Exclua a pasta torch na pasta python site-packages, se existir.
    Renomeie (ou exclua) a pasta de origem pytorch anterior (algo estava se referindo a ela).

  2. Instale a revisão do PyTorch 6cb593b88cb0c411690b4957850058329526d87b.

    git clone [email protected]:pytorch/pytorch.git
    git checkout 6cb593b88cb0c411690b4957850058329526d87b
    git submodule update --init —recursive
    export CMAKE_PREFIX_PATH=${CONDA_PREFIX:-"$(dirname $(which conda))/../“}
    MACOSX_DEPLOYMENT_TARGET=10.13 CC=clang CXX=clang++ python setup.py develop
    python
>>> import torch
  1. Instalar pytorch-complex
    python setup.py install
    python setup.py build
    python setup.py test
    # ERROR: test (unittest.loader._FailedTest)
    # ERROR: test_scalar_binary_op (tests.test_tensor.TestComplexTensor)
  1. Criar um tensor complexo
   from torch_complex import torch
   a = torch.ones(3, dtype=torch.complex128)
   a*a  
   RuntimeError: promoteTypes with complex numbers is not handled yet; figure out what the correct rules should be

@ezyang , @Roger-luo:

Tudo para promoção de tipo para operações de tensor parece ser feito em c10/core/ScalarType.h
Encontrei o erro AT_ERROR("promoteTypes with complex numbers is not handled yet; figure out what the correct rules should be”);
Parece que eu tenho que adicionar uma entrada para c8 e c16 dentro desta tabela.
Isso tem alguma coisa a ver com 9515 ? Eu acho que isso é apenas para chamar funções numpy.
É um bom lugar para começar?

9515 não está relacionado. No entanto, corrigir esse caminho de código em ScalarType.h é um bom ponto de partida.

Eu consertei o caminho de código em ScalarType.h
BinaryOps (add, sub, mul, div) funcionando, mas apenas se ambos os argumentos forem tensores.
Alguns outros problemas estranhos, mas eu preciso olhar um pouco mais.

@dylanbespalko Adicionei promoções de tipo aqui: https://github.com/pytorch/pytorch/pull/11641

Você poderia simplesmente copiar isso, mas o problema é que isso quebra o CUDA de alguma forma.

IIRC, houve um erro de conexão devido à versão do gcc. Eu tive algumas soluções lá.

Ah, obrigado @Roger-luo. Eu estava olhando os comentários de #11641 . Vou fazer um trabalho melhor de copiar o código amanhã.

Como posso saber quando quebrei o CUDA quando não tenho um dispositivo CUDA? Estou assumindo que o CI vai me dizer?

Sim, assim que você enviar um PR, ele lhe dirá qual deles está quebrado. E se tudo simplesmente passar, então poderíamos simplesmente mesclar isso e fazer as coisas funcionarem.

Ok, então vou começar a enviar PRs para que eu saiba quando isso acontecer.

@dylanbespalko Oi, ainda parece haver alguns erros no seu ambiente?
Se resolver, compartilhe conosco. Muito obrigado.

Ei pessoal,

Tentei fazer vários PRs depois de copiar vários commits do @Roger-luo. Infelizmente, não tenho uma GPU CUDA no momento e as máquinas CI com CUDA não estão inicializando. Não posso recriar a falha do teste CUDA agora, então voltarei a isso em algumas semanas, quando puder executar localmente nessa GPU. Parece promissor, pelo menos.

@ezyang , @Roger-luo

Eu dei uma olhada no PR #11641 de Roger:

  • Ele é construído e executado na minha máquina CUDA 9.0
  • Ele falha ao construir em máquinas CI que estão executando o CUDA 9.0

Também dei uma olhada em alguns dos desenvolvimentos recentes do PyTorch:

  • Uma apresentação de @ezyang descrevendo como escrever uma extensão C++/CUDA que pode definir um device/layout/dtype personalizado .

    • Um PR #21964 mais recente que "remove o ComplexHooksInterface", mas define uma extensão C++ de número complexo localizada em pytorch/test/cpp_extensions/complex_registration_extension.cpp

Parece-me que um novo recurso de extensão "fora da árvore" está sendo desenvolvido, o que me permitiria investigar o suporte a números complexos sem quebrar o resto do pytorch. Meu objetivo é:

  1. Defina o suporte de CPU complexo sem AVX.
  2. Defina o suporte CUDA complexo usando o Thrust.

@ezyang
Você pode fornecer um cronograma esperado para esta extensão de dispositivo/layout/dtype fora da árvore que você apresentou? Podemos esperar esse recurso nos próximos 3 meses?

@ezyang

Você consegue mesclar o suporte a números complexos na CPU sem suporte a AVX/SSE? Pretendo enviar o seguinte em solicitações de mesclagem separadas:

  • [ ] Adicionado suporte complexo de kernels CPU BinaryOp
  • [ ] Adicionado suporte complexo de CPU TensorFactories
  • [ ] Adicionado suporte complexo de CPU FillKernels
  • [ ] Adicionado suporte complexo de kernels de intervalo de CPU
  • [ ] Adicionado suporte complexo de kernels unários de CPU
  • [ ] Adicionado suporte complexo de kernels CPU Compare
  • [ ] Adicionado suporte complexo de kernels CPU TensorCompare
  • [ ] Adicionado suporte complexo de kernels de CPU ReduceOp
  • [ ] Adicionado suporte complexo de kernels CPU PointwiseOps
  • [ ] Adicionado suporte complexo de kernels de aprendizado de CPU
  • [ ] Adicionado suporte complexo de kernels CPU LinearAlgebraOps
  • [ ] Adicionado suporte complexo de kernels de CPU SpectralOps

Eu pretendo testar isso no processador Intel / Arm nos próximos dias.

@ezyang ,

Estou analisando operações como fft() e var() onde a implementação do número complexo deve converter os dados do tensor em um tensor duplo de forma: (complex_shape, 2) . Isso não funciona com nenhum método tensor existente:

  1. 'tensor.to(torch.float64): mantém apenas a parte real, e retorna um tensor com a mesma forma.
  2. 'tensor.view(new_shape): a nova forma deve ter o mesmo número de elementos.

Obviamente eu posso fazer algo ineficiente como:

def to_float(tensor):
    return th.stack((tensor.real().type(th.float64), tensor.imag().type(th.float64)), -1)

def to_complex(tensor):
    tensor = tensor.type(th.complex128) 
    return tensor[..., 0] + 1j*tensor[..., 1]

Obviamente isso é criar cópias, quando tudo que eu preciso é static_cast<double> e mudar a forma do tensor para (old_shape, 2) . Você tem alguma sugestão de como fazer isso?

Além disso, existe um hack no numpy que permite fazer isso:

a = np.array([1 + 1j], dtype=np.complex128)
a.dtype = np.float64  ## This works

a = torch.tensor([1 + 1j], dtype=torch.complex128)
a.dtype = torch.float64  ## This does not work

A capacidade de definir dtype realmente funciona nessa situação, mas pode ser imprevisível.

Algumas informações adicionais sobre a interpretação de um número complexo como uma matriz de comprimento 2 de números reais. O seguinte é válido em C++11.

Para qualquer ponteiro para um elemento de um array de números complexos p e qualquer índice de array válido i, reinterpret_cast(p)[2 i] é a parte real do número complexo p[i], e reinterpret_cast(p)[2 i + 1] é a parte imaginária do número complexo p[i]. (Desde C++11)

Eu acho que isso significa que é possível converter um complex_tensor em um real_tensor com forma (complex_shape, 2) e, em seguida, executar uma operação sem chamar real() e imag() que alocaram nova memória.

@dylanbespalko Eu tinha medo de quando você perguntava sobre isso :) A garantia std::complex significa que, se você tiver o ponteiro de dados std::complex<float>* , poderá convertê-lo com segurança em float* (murmúrio de alias estrito) e, em seguida, passe-o para qualquer coisa que você esteja usando. Se você só precisa implementar fft/var onde você pode passar esse representante de baixo nível, isso será mais fácil.

No entanto, se você precisar revisar literalmente um tensor complexo como um tensor flutuante, estamos em apuros, porque não há precedente para isso no PyTorch hoje. O dtype de armazenamento sempre concordou com o dtype do Tensor. Portanto, se você fizer um armazenamento complexo, não há como revisá-lo como um armazenamento flutuante.

Um pensamento que tive é que talvez devêssemos relaxar essa invariante. A ideia é:

  1. Sempre alocamos armazenamentos como o tipo "não vetorizado" em questão. Então para um complexoalocamos um tensor float.
  2. O tensor dtype pode discordar do storage dtype, mas apenas como uma variante vetorizada do tipo subjacente

Não tenho certeza de quanto código teríamos que mudar para fazer essa invariante acontecer.

@ezyang ,

Sim, isso era inevitável...

Se você só precisa implementar fft/var onde você pode passar esse representante de baixo nível, isso será mais fácil.

Sim, isso é possível em muitos casos. Você é capaz de fornecer um trecho de código de como interpretar os dados do tensor como um std::vector?

No entanto, se você precisar revisar literalmente um tensor complexo como um tensor flutuante,....

Eu imagino que é raro ver um tensor usando outro dtype. Eu implementei um método set_dtype() para Tensor , mas recebi alguns erros. Eu também não atualizei os passos para refletir as mudanças na forma. Não sei por que definir dtype funciona em numpy (é uma coincidência?), No entanto, quando você carrega dados para um conversor digital-analógico (DAC), geralmente espera que os dados reais/imaginários sejam intercalados. Talvez isso motive a necessidade de desacoplar o tensor dtype do armazenamento dtype como você sugeriu.

Vou evitar fazer isso por enquanto. Tenho certeza de que existem outros gargalos de desempenho para mim.

Sim, isso é possível em muitos casos. Você é capaz de fornecer um trecho de código de como interpretar os dados do tensor como um std::vector?

Não é exatamente um std::vector, mas estou imaginando algo assim:

Tensor complex_tensor;
assert(complex_tensor.is_contiguous());
std::complex<float>* cp = complex_tensor.data_ptr<std::complex<float>>();
float* fp = reinterpret_cast<float*>(cp);
auto num_floats = complex_tensor.numel() * 2;

Implementei um método set_dtype() para o Tensor, mas recebi alguns erros. Eu também não atualizei os passos para refletir as mudanças na forma.

Sim, isso provavelmente é uma má ideia se você também não corrigir os passos. Também não sou um grande fã de tensores transmutando em outros dtypes; melhor fazer tudo fora do lugar :)

no entanto, quando você carrega dados para um conversor digital-analógico (DAC), ele geralmente espera que os dados reais/imaginários sejam intercalados. Talvez isso motive a necessidade de desacoplar o tensor dtype do armazenamento dtype como você sugeriu.

Sim, em última análise, esta é a coisa certa a fazer, mas concordo que é mais fácil não fazer isso agora.

@ezyang ,

Estou começando a mexer com o suporte CUDA de número complexo.

Existem duas opções binárias compatíveis:

  1. cuComplex : Suporte muito básico para adicionar, sub, mul, div, real, imag.
  2. thrust::complex : substituição de std::complex que suporta alocação de memória de host e dispositivo.

O container thrust::complex parece ser o caminho a seguir. A API Thrust::Complex sugere que os contêineres thrust::complex<T> podem ser alocados na memória do host e do dispositivo, enquanto o std::complex<T> só pode ser alocado na memória do host:

__host__ __device__     thrust::complex< T >::complex (const complex< T > &z)  //thrust container
__host__    thrust::complex< T >::complex (const std::complex< T > &z) //stl container.
  1. Isso está sugerindo que AT_DISPATCH_COMPLEX_TYPES deve definir using scalar_t = thrust::complex<double> em vez de using scalar_t = std::complex<double> ?

  2. Como o Pytorch chama automaticamente equivalentes CUDA de std::log para tipos de dados reais? Como eu sei que existe um equivalente CUDA de um kernel matemático?

  1. Eu acho que a dificuldade de usar thrust::complex<double> universalmente para CPU e CUDA é que nós não construímos contra o impulso se você fizer apenas uma compilação de CPU. Eu acho que há um monte de opções; podemos rolar nosso próprio tipo complexo (semelhante à forma como rolamos nosso próprio meio tipo), ou você pode apenas reinterpretar o seu caminho para a vitória, porque std::complex<> é definido para ter um layout binário específico. Depende de você, mas apenas reinterpretar a conversão entre os tipos parece mais fácil por enquanto.
  2. Temos sobrecargas matemáticas no THCNumerics.cuh, isso responde à sua pergunta?

@iotamudelta levantou um problema com a conformidade com C++11 em #29547

std::real é apenas constexpr do C++ 14

Se eu entendi corretamente o std::real() precisa ser um constexpr para que o compilador hcc possa compilar a instrução para __device__ .

Soluções possíveis:

  1. Encontre outro método ou função para converter complex<double> em double :
  1. Encontre uma maneira de envolver a função:

    • A maioria das chamadas para std::real são feitas em aten/src/ATen/native/cpu/zmath.h . Exemplo: substitua inline por constexpr :

      inline VALUE_TYPE real_impl (SCALAR_TYPE z) ->
      constexpr VALUE_TYPE real_impl (SCALAR_TYPE z)

      inline std::complex<float> real_impl <std::complex<float>> (std::complex<float> z) -> constexpr std::complex<float> real_impl <std::complex<float>> (std::complex<float> z)

      inline std::complex<float> real_impl <std::complex<double>> (std::complex<float> z) -> constexpr std::complex<float> real_impl <std::complex<double>> (std::complex<float> z)

Isso não será compilado porque ainda há uma chamada aninhada para std::real() que não é um constexpr .

3. Se eu usar std::complex::real() em vez de std::real() isso parece ser compatível com C++11.

  1. Acho que você está dizendo que não importa o que eu faça esse código é UB até C++14. Existe alguma outra maneira de converter std::complex<double> para double que atenda às suas necessidades?

@iotamudelta , @bddppq , @ezyang ,

Adicionei suporte para UnaryOps e BinaryOps complexos no CUDA thrust::complex API, mas preciso fazer algumas perguntas antes de enviá-lo.

Eu defini uma função de modelo que permite usar tipos de dados thrust::complex ao lidar com números complexos.
aten/src/ATen/native/cuda/zmath.cuh

#pragma once

#include <complex>
#include <thrust/complex.h>

namespace at { namespace native {
namespace {

template <typename TYPE>
struct ztype_cuda {
  using value_t = TYPE; // Complex template type
  using thrust_t = TYPE; // Equivalent thrust type
};

template <>
struct ztype_cuda<std::complex<float>> {
  using value_t = float;
  using thrust_t = thrust::complex<float>;
};

template <>
struct ztype_cuda<std::complex<double>> {
  using value_t = double;
  using thrust_t = thrust::complex<double>;
};

} // end namespace
}} //end at::native

Então em aten/src/ATen/native/cuda/BinaryOpsKernel.cu
Substituir:

void add_kernel_cuda(TensorIterator& iter, Scalar alpha_scalar) {
  AT_DISPATCH_ALL_TYPES_AND2(kHalf, kBool, iter.common_dtype(), "add_cuda/sub_cuda", [&]() {
    auto alpha = alpha_scalar.to<scalar_t>();
    gpu_kernel_with_scalars(iter, [alpha]GPU_LAMBDA(scalar_t a, scalar_t b) -> scalar_t {
      return a + alpha * b;
    });
  });
}

Com:

void add_kernel_cuda(TensorIterator& iter, Scalar alpha_scalar) {
  AT_DISPATCH_ALL_TYPES_AND_COMPLEX_AND2(kHalf, kBool, iter.dtype(), "add_cuda/sub_cuda", [&]() {
    using thrust_t = typename ztype_cuda<scalar_t>::thrust_t;
    auto alpha = thrust_t(alpha_scalar.to<scalar_t>());
    gpu_kernel_with_scalars(iter, [alpha]GPU_LAMBDA(thrust_t a, thrust_t b) -> thrust_t {
      return a + alpha * b;
    });
  });
}

Perguntas

  1. @ezyang : Para números não complexos, scalar_t e thrust_t são do mesmo tipo. Talvez eu possa substituir o nome da variável thrust_t por algo mais amigável para números não complexos, como scalar_t_c ?
  2. A biblioteca de impulso parece amplamente referenciada no código:
    a) @bddppq : Existe algum motivo para eu usar cuComplex em vez de thrust::complex ?
    b) @iotamudelta : o hip-thrust foi removido no ROCm2.7. Devo usar hip_complex em vez disso?
    thrust::complex parece suportar mais funcionalidades do que cuComplex .

Por favor, deixe-me saber o que você pensa.

@iotamudelta

Atualizei a discussão sobre std::real(). Você pode confirmar que std::complex::real() resolveria o problema.

Olá @dylanbespalko ,

Eu acho que o @iotamudelta está reclamando é que cast_and_store para tipos complexos está faltando um C10_HOST_DEVICE , isso seria um UB se esse caminho de código fosse executado na GPU.

Atualmente, esse utilitário de conversão dinâmica é usado apenas no GPU TensorIterator e só é usado quando há promoção de tipo. Pelo motivo desse complexo não ter suporte na GPU atualmente, cast_and_store para tipos complexos agora não tem o qualificador C10_HOST_DEVICE e usa std::real que é totalmente aceitável para um host- única função. Não há UB aqui porque não é usado e não há nada com que você precise se preocupar.

Mas como você deseja adicionar suporte de complexo à GPU, e complexo é suportado pela promoção de tipo, como podemos ver em https://github.com/pytorch/pytorch/blob/master/c10/core/ScalarType.h#L398 - L420, você precisa ter muito cuidado neste caminho de código e há algumas modificações que você pode precisar fazer para que funcione:

Claro, você precisa adicionar C10_HOST_DEVICE como @iotamudelta está fazendo em https://github.com/pytorch/pytorch/pull/29547 , mas isso não é suficiente, porque simplesmente adicionar C10_HOST_DEVICE sem outras alterações ainda é UB no C++ 11 como mencionado por @iotamudelta , uma boa solução pode ser o que você mencionou: use std::complex::real() para substituir o std::real .

Mas além disso, se você olhar para o arquivo https://github.com/pytorch/pytorch/blob/master/c10/util/TypeCast.h , você verá dentro fetch_and_cast , há algo como:

#ifndef C10_HOST_DEVICE
    AT_FORALL_COMPLEX_TYPES(FETCH_AND_CAST_COMPLEX_CASE)
#endif

Este caminho de código está desabilitado na GPU. Você precisa habilitá-lo e fazê-lo funcionar.

Além disso, não vi nenhuma conversão entre complex<float> e complex<double> dentro fetch_and_cast e cast_and_store . Você também pode precisar adicionar a conversão para isso. Certifique-se de testar completamente a cobertura dessas funções de todos os dtypes.

cc: @ezyang e @bddppq

Também @dylanbespalko , por favor me envie uma cópia se você estiver fazendo alguma alteração em TypeCast.h em seu PR.

OK, eu tenho algumas pequenas coisas para consertar com torch.real() e torch.imag() no ARM, então vou consertar TypeCast.h e algumas outras enquanto estou nisso. Vou cc vocês no PR.

Drive by comment: @smessmer está nos movendo para C++ 14, ponto em que não será UB. Como isso está chegando em breve, se o UB não estiver causando problemas reais, eu não me preocuparia muito com isso.

@ezyang : Bom saber. A maioria das coisas de terceiros como Eigen ainda chama std::real() muito liberalmente.

Para números não complexos, scalar_t e thrust_t são do mesmo tipo. Talvez eu possa substituir o nome da variável thrust_t por algo mais amigável para números não complexos, como scalar_t_c?

Não tenho muita certeza, mas scalar_t_c parece um pouco menos claro do que thrust_t (o que significa c afinal?) Os tipos em questão aqui parecem bastante específicos, então parece melhor usar um nome que fale diretamente sobre a intenção.

Ok, vou ficar com thrust_t . Se alguém mergulhar em ztype_cuda<>() , eles devem descobrir instantaneamente que scalar_t é thrust_t para tipos não complexos.

Olá a todos! Parece que um bom progresso está sendo feito para adicionar suporte complexo ao pytorch! Obrigado @dylanbespalko por tomar a iniciativa e adicionar suporte CUDA também! De alto nível, estou interessado em saber qual é o progresso atual no suporte complexo? Estou principalmente interessado em uma linha do tempo aproximada para ter suporte CUDA para adicionar e multiplicar tensores complexos (operações binárias). Obrigado!

Olá @sunilkpai ,

Eu tenho um PR aberto que deve suportar as operações binárias e unárias em CUDA: #30295.

Mais um problema é com a propagação para trás. Eu acho que a derivada do complexo abs() é definida de forma diferente dos números reais. Não tenho certeza do que fazer sobre isso, mas os derivativos são definidos em tools/autograd/derivatives.yaml

Eu acho que para números complexos /dz abs(z) = z/abs(z) . Isso também pode ser usado para números reais, mas provavelmente será mais lento que sgn(z)

@dylanbespalko Talvez as tabelas 4.1, 4.2 e 4.3 do meu Relatório https://arxiv.org/pdf/1701.00392.pdf possam ajudá-lo a definir as derivadas.

Para as derivadas complexas (cálculo de wirtinger), existem duas opções.
Calculando a derivada wrt z ou z conjugado.
Eu pessoalmente gosto mais do conjugado wrt z derivado.
Parece mais natural para operações de matriz e a atualização do gradiente não precisa de um conjugado.
A definição deles é:

  • derivativo wrt z para z = x + jy : dJ/dz = dJ/dx -j dJ/dy
  • derivativo wrt z.conj para z = x + jy : dJ/dz.conj = dJ/dx + j dJ/dy

Do seu comentário, minha suposição é que você calcula a derivada wrt z no momento.
Neste caso a derivada é d abs(z) / d z = z.conj / abs(z) . Quando você pega a outra definição, pode seguir a sugestão do @Randl .

Deixe-me saber se eu deveria explicar mais. Eu também tenho algumas implementações numpy para as derivadas complexas.

Uma outra operação que seria útil (especialmente para projetos no espaço da física que requerem suporte a números complexos) é um manipulador para o operador exp() . No tensorflow, temos tf.exp(x + iy) = tf.exp(x) * (tf.cos(y) + 1j * tf.sin(y)) . Isso também é simples de implementar em pytorch?

@sunilkpai , @boeddeker , @Randl ,

Obrigado pelo relatório sobre as derivadas complexas. Vou tentar seguir isso e voltarei na próxima semana. Eu pensei em adicionar alguns links aqui e descrever o status do projeto.

O status de números complexos não é oficialmente suportado e deve ser adicionado via extensão PyTorch:

Cada extensão contém duas coisas:

  • Um .cpp que contém qualquer registro de kernel matemático necessário.
  • Uma pasta test/ que contém versões muito simplificadas dos scripts de teste pytorch.
    Procure nos scripts de teste para ver quais kernels são suportados (e por que outros não são).

Por que não consigo imprimir um tensor complexo no console?

  • O objeto python do Tensor tem uma formatação de impressão bonita que chama algumas funções que não são suportadas.

    • Você pode modificar o conteúdo de tensor.py para ignorar a formatação de impressão.

    • Ou você pode simplesmente converter tensores Pytorch em matrizes Numpy e depois imprimir.

Status atual do projeto:

  • A cobertura da CPU é muito boa.

    • Os Kernels são implementados dentro do PyTorch em 'aten/src/ATen/native/cpu/ </li> <li>Complex number specific code is under 'aten/src/ATen/native/cpu/zmath.h

    • A aceleração Intel AVX256 está em 'aten/src/ATen/cpu/vec256/`



      • @sunilkpai : Eu não conhecia a otimização do exp. Esta é a pasta onde você adiciona isso.


      • Deixe-me saber se você se sente à vontade para fazer a alteração.



  • A cobertura da GPU é limitada a operações binárias e unárias:

    • Os Kernels são implementados dentro do PyTorch em 'aten/src/ATen/native/cuda/* </li> <li>Complex number specific code is under 'aten/src/ATen/native/cuda/zmath.cuh

    • Os tipos de dados thrust::complex<T> são usados ​​e incluem os kernels otimizados.

Desenvolvimento atual:

  • Aguardando que os kernels TH baseados em C sejam portados para a pasta C++ ATen.

    • A função rand() é necessária para portar os casos de teste para os testes internos do pytorch.

    • Algumas operações de indexação não são portadas no momento.

    • Existem atualmente 168/1300 kernels matemáticos (abaixo de 230 em outubro) que precisam ser portados de TH para Aten.

  • Tentarei adicionar suporte a números complexos à medida que esses kernels se tornarem disponíveis no Aten.

--

PARA SUA INFORMAÇÃO. Em relação às derivadas complexas, tivemos uma longa discussão em Julia e sua implementação agora está em ChainRules (veja também: http://www.juliadiff.org/ChainRules.jl/dev/api.html#ChainRulesCore.Wirtinger ) e Zygote agora . Geralmente, as pessoas só precisam
\partial L/\partial adjoint(z) como o gradiente (por definição é a direção de diminuição mais rápida), mas a derivada é diferente como \partial L/\partial z , uma interface extra deve ser adicionada, se quisermos um suporte completo para o número complexo AD . Para as regras detalhadas, você pode verificar o que está implementado em ChainRules ou Zygote/lib (já que existem apenas regras genéricas, não há regras separadas para números complexos para a maioria dos operadores, passe para trás para coisas como matmul são escritos em definição genérica, por exemplo adjoint(A) * B )

Por que não consigo imprimir um tensor complexo no console?
O objeto python do Tensor tem uma formatação de impressão bonita que chama algumas funções que não são suportadas.
Você pode modificar o conteúdo de tensor.py para ignorar a formatação de impressão.
Ou você pode simplesmente converter tensores Pytorch em matrizes Numpy e depois imprimir.

Acho que consertei pelo menos parte da impressão em https://github.com/Roger-luo/pytorch-complex para depuração etc. em primeiro lugar, não tenho certeza se isso ajudaria, pois o mestre mudou muito no passado ano. Você pode apenas tomá-lo se for útil, não vou mais trabalhar nisso.

@dylanbespalko Sou relativamente inexperiente com os internos do pytorch, embora tenha começado a aprender! Eu poderia tentar essa alteração, embora com base no que vejo em aten/src/ATen/cpu/vec256/* , não tenho certeza se é necessário, pois o comportamento padrão de std::exp(std::complex) é exatamente o que mencionei no meu comentário anterior: veja notas de https://en.cppreference.com/w/cpp/numeric/complex/exp . Também não tenho certeza de como isso se traduz na implementação dessas operações em CUDA (que atualmente parece limitada a real, imag, conj e angle?).

@sunilkpai ,

Eu adicionei o suporte AVX para exp() usando a equação fornecida.

Também notei que algumas coisas estavam quebradas devido a algumas mudanças recentes no PyTorch. Eu consertei isso em # 30871.

@dylanbespalko

Existe um cronograma para a portabilidade de TH para ATen?
Existe uma maneira que eu possa contribuir, dado o fato de que eu não sou bem versado com o funcionamento interno do pytorch?

Eu encontrei uma fórmula para a retropropagação do complexo svd no arxiv e poderia implementar isso, se você me mostrar onde

Obrigado pelo seu trabalho!

@Jakob-Unfried

https://github.com/pytorch/pytorch/wiki/TH-to-ATen-porting-guide

Os kernels TH são implementados em C e há pouco interesse em adicionar suporte complexo devido a todos os problemas inerentes de contagem de referência. Você pode acompanhar o progresso em aten/src/ATen/native/native_functions.yaml onde cada kernel está registrado:

Procure por legacy::cpu::_th e divida esse número por 3 para o número de kernels TH antigos.
Procure por legacy::cpu::_thnn e divida esse número por 3 para o número de kernels de rede neural TH antigos.

Cada kernel é normalmente registrado de 3 maneiras diferentes:
1. Kernel Regular y = add(a, b)
2. Kernel no local a = add_(a, b)
3. Saída do Kernel add_out(a, b, out=y)
A implementação real está sempre no Kernel de Saída e os outros 2 chamam essa função.

Os kernels nn tendem a ser mais fáceis de portar porque têm menos kernels dependentes. Portanto, se você puder portar os kernels na ordem inversa de como eles foram implementados, você fará menos trabalho geral.

Verificando o problema de rastreamento de portabilidade https://github.com/pytorch/pytorch/issues/24507 , também cc @VitalyFedyunin

Aqui está uma atualização de status no suporte a números complexos, conforme solicitado em #32437. Estou de volta a trabalhar no suporte relacionado à CPU hoje.

Suporte Autograd

  • Eu não tive muito tempo para isso.
  • angle() , real() , imag() , conj() foram todos implementados.
  • abs() exigirá uma implementação separada para números complexos. (veja as notas de @boeddeker e @Randl acima)

Suporte de hardware

O suporte a números complexos está atualmente implementado fora da árvore. Aqui está o que isso significa:

Código na árvore

  • As operações matemáticas são realmente implementadas na árvore (dentro do código-fonte do PyTorch).
  • Nenhum dos testes Pytorch na árvore valida o suporte a números complexos (portanto, as coisas tendem a quebrar).
  • PyTorch está migrando de TH para Aten (#24507).
    - Os kernels matemáticos implementados no TH não suportam números complexos.
    - Apenas kernels implementados no Aten podem suportar números complexos.
  • Você precisa instalar uma extensão PyTorch para habilitar o dtype complexo.

Código fora da árvore

  • Várias extensões PyTorch são implementadas e podem ser facilmente internalizadas no futuro:
  • Cada extensão tem quatro arquivos de importância:

    • setup.py: construa e instale a extensão pytorch.

    • [CPU/CUDA/FPGA]ComplexType.cpp: registro do kernel matemático semelhante a CPUType.cpp ou CUDAType.cpp

    • test/test_torch.py: Casos de teste muito feios que indicam quais kernels estão funcionando, limitados pelo suporte Aten.

    • test/test_autograd.py: Testando a funcionalidade do autograd.

Extensões do PyTorch fora da árvore

  1. cpu_strided_complex
    - [x] CopyKernel
    - [ ] TensorFactories (th_random, th_uniform, th_normal)
    - [x] RangeFactories
    - [x] BinaryOpKernals
    - [x] UnaryOpKernels
    - [x] CompareOpKernels
    - [x] PowKernels
    - [x] ReduceOpKernels (th_min, th_max, algumas normas não computam conjugado complexo)
    - [ ] IndexOpKernels (th_masked_select_bool, th_set, th_gather, th_cat)
    - [x] PointwiseOps
    - [x] Operações de Lerp
    - [ ] BlasOps (th_mv, th_mm, th_fmod, th_eig)
    - [ ] LinpackOps (usa Blas)
    - [ ] SpectralOps (suportado, mas precisa de trabalho)

    1. cuda_strided_complex



      • [x] CopyKernel


      • [ ] TensorFactories (veja problemas de CPU)


      • [x] BinaryOpKernals


      • [x] UnaryOpKernels (Todo: add angle, real, imag, conj)


      • [ ] CompareOpKernels (Todo)


      • [ ] ReduceOpKernels (mensagens de erro sobre WARP_SIZE)


      • A GPU se torna difícil além dos cálculos pontuais, no entanto, funções adicionais podem ser suportadas



  2. vitis_strided_complex

    • Xilinx Vitis é uma plataforma de síntese FPGA de alto nível que suporta servidores e dispositivos embarcados.

    • Lançado em outubro de 2019 (provavelmente suporte limitado para dispositivos).

    • Combina SDAccel (servidor) com VIvado HLS (incorporado).

    • [ ] BinaryOpKernals (final de janeiro)

    • [ ] UnaryOpKernels (final de janeiro)

    • [ ] ReduceOpKernels (final de fevereiro).

    • Objetos vetorizados adicionados recentemente ao FPGA suportam semelhante à classe de modelo Vec256 PyTorch

    • Vec256 foi como o suporte complexo foi adicionado à CPU e parece ser a maneira mais natural de implementar espaços tensores $C$ ou $R^N$

Mais atualizações para este problema: https://github.com/pytorch/pytorch/issues/33152

Isso pode ou não merecer um problema separado, mas eu gostaria de ver e acho que é praticamente mais importante atualmente ter na documentação algo que explique 'como o pytorch funciona com números complexos agora'. aka pode fazer adição, multiplicação, algum tipo de norma, não pode ter pesos complexos, etc. tudo isso pode ser resumido por algumas linhas de documentação explicando qual é o comportamento atual pretendido de alto nível.

Isso pode ou não merecer um problema separado, mas eu gostaria de ver e acho que é praticamente mais importante atualmente ter na documentação algo que explique 'como o pytorch funciona com números complexos agora'. aka pode fazer adição, multiplicação, algum tipo de norma, não pode ter pesos complexos, etc. tudo isso pode ser resumido por algumas linhas de documentação explicando qual é o comportamento atual pretendido de alto nível.

Oi @redwrasse obrigado pelo feedback! atualmente temos uma nota para números complexos que fala sobre alguns fundamentos da tocha e funções complexas suportadas por tensores complexos no mestre
(a maioria está incluída na versão 1.6) https://pytorch.org/docs/master/complex_numbers.html?highlight=complex. Você pode compartilhar quais outras funções você está interessado? feliz em falar mais sobre nosso suporte atual e qual é o plano para os próximos lançamentos.

Isso pode ou não merecer um problema separado, mas eu gostaria de ver e acho que é praticamente mais importante atualmente ter na documentação algo que explique 'como o pytorch funciona com números complexos agora'. aka pode fazer adição, multiplicação, algum tipo de norma, não pode ter pesos complexos, etc. tudo isso pode ser resumido por algumas linhas de documentação explicando qual é o comportamento atual pretendido de alto nível.

Oi @redwrasse obrigado pelo feedback! atualmente temos uma nota para números complexos que fala sobre alguns fundamentos da tocha e funções complexas suportadas por tensores complexos no mestre
(a maioria está incluída na versão 1.6) https://pytorch.org/docs/master/complex_numbers.html?highlight=complex. Você pode compartilhar quais outras funções você está interessado? feliz em falar mais sobre nosso suporte atual e qual é o plano para os próximos lançamentos.

Obrigado @anjali411 , é ótimo ver esta documentação, eu não sabia disso anteriormente. Eu acho que o que é necessário é a frente e o centro de algumas linhas 'estado atual de suporte para redes neurais complexas', mas deixe-me passar por isso ...

Pessoas interessadas em autograd complexo, você pode estar interessado em https://github.com/pytorch/pytorch/issues/41857 , que aborda qual convenção o PyTorch seguirá (JAX ou TF).

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

kdexd picture kdexd  ·  3Comentários

szagoruyko picture szagoruyko  ·  3Comentários

eliabruni picture eliabruni  ·  3Comentários

soumith picture soumith  ·  3Comentários

mishraswapnil picture mishraswapnil  ·  3Comentários