Lançamento da plataforma Elbrus para redes neurais do PuzzleLib

IA em ferro doméstico


Falamos sobre como portamos nossa estrutura para redes neurais e sistema de reconhecimento de rosto para os processadores russos Elbrus.

imagem

Foi uma tarefa interessante: na primavera de 2019, conversamos sobre isso no escritório da Yandex na grande reunião sobre Elbrus, agora estamos compartilhando com Habr.

Resumidamente - o que é Elbrus


Este é um processador russo com arquitetura própria, desenvolvido no MCST . Maxim Gorshenin fala bem sobre ele em seu canal: www.youtube.com/watch?v=H8eBgJ58EPY

Resumidamente - o que é o PuzzleLib


Esta é a nossa plataforma para redes neurais, que desenvolvemos e usamos desde 2015. Análogo do Google TensorFlow e Facebook PyTorch. Curiosamente, o PuzzleLib suporta não apenas os processadores NVIDIA e Intel, mas também as placas de vídeo AMD.

Embora tenhamos uma pequena biblioteca (o TensorFlow tem cerca de 2 milhões de linhas, temos 100 mil), somos melhores em velocidade - um pouco, mas melhor =)

Ainda não estamos em código aberto, a biblioteca é usada para nossos projetos. A biblioteca está completa: suporta o estágio de treinamento e o estágio de inferência das redes neurais. Você pode criar redes neurais convolucionais e recorrentes; também existe uma interface para a criação de gráficos arbitrários de cálculos.

O PuzzleLib tem


  • Módulos para montagem de redes neurais (Ativação (Sigmoid, Tanh, ReLU, ELU, LeakyReLU, SoftMaxPlus), AvgPool (1D, 2D, 3D), BatchNorm (1D, 2D, 3D, ND), Conv (1D, 2D, 3D, ND) , CrossMapLRN, Deconv (1D, 2D, 3D, ND), Dropout (1D, 2D) etc.)
  • Otimizadores (AdaDelta, AdaGrad, Adam, Hooks, LBFGS, MomentumSGD, NesterovSGD, RMSProp, etc.)
  • Redes neurais prontas para uso (Resnet, Inception, YOLO, U-Net etc.)

Estes são os familiares, familiares a todos os envolvidos em redes neurais, blocos para projetistas de redes neurais (já que quaisquer estruturas são construtoras que consistem em blocos e algoritmos típicos de computação).

Tivemos uma ideia de lançar nossa biblioteca sobre arquitetura Elbrus.


Por que queremos apoiar o Elbrus?


  1. Este é o único processador russo, eu queria entender como as coisas estão indo, como é fácil trabalhar com ele.
  2. Achamos que seria interessante para as organizações estatais que o software russo que estamos desenvolvendo funcione no hardware russo.
  3. E, é claro, estávamos apenas interessados, porque Elbrus é um processador VLIW , ou seja, um processador com instruções longas, e não existem processadores de uso geral completos no mundo.

Tudo começou com o fato de termos nos encontrado com o MCST, conversado e emprestado o computador Elbrus 401 para desenvolvimento.

O que eu gostei : O Linux é executado no Elbrus, existe um python neste Linux e não funciona no modo de emulação - é um python nativo de pleno direito, montado para o Elbrus. Há também um pacote de bibliotecas python padrão, por exemplo, numpy, que todos os desenvolvedores adoram.

Havia algumas tarefas para as quais tivemos que coletar adicionalmente bibliotecas: por exemplo, no PuzzleLib, usamos o formato hdf para armazenar os pesos das redes neurais e, consequentemente, tivemos que construir as bibliotecas libhdf e h5py usando o compilador lcc. Mas não tivemos problemas de montagem.

A biblioteca de visão computacional OpenCV também já foi compilada, mas não havia ligação para o python - nós a construímos separadamente.

A famosa biblioteca dlib também é bastante fácil de compilar. Havia apenas pequenas dificuldades: alguns arquivos desse projeto de código aberto não tinham um bom marcador para determinar o utf-8, o que perturbou o lexer lcc. Na verdade, havia simplesmente um formato de arquivo incorreto, que precisava ser corrigido na fonte.

Decidimos começar o reconhecimento de rosto primeiro. Este é um caso de uso compreensível para muitos, onde essa tecnologia é usada. O PuzzleLib, como outras bibliotecas, possui uma parte de back-end bastante grande, ou seja, uma base de código específica para diferentes arquiteturas de processador.

Nossos back-end:

  • CUDA (NVIDIA)
  • Open CL + MI Open (AMD)
  • mlkDNN (Intel)
  • CPU (numpy)

Na Elbrus, lançamos um back-end numpy, que era muito simples, porque a plataforma requer um mínimo de tudo:

Plataforma -> compilador c90 -> python -> numpy

Temos uma biblioteca sem fatores complicadores (por exemplo, sem sistemas especiais de montagem) - além do fato de precisarmos coletar determinados aglutinantes. Fizemos os testes, tudo funciona - tanto em redes convolucionais quanto em recorrentes. O reconhecimento facial que lançamos é bastante simples, com base no Inception-ResNet.

Primeiros resultados do trabalho

No Intel Core i7 7700, o tempo de processamento de uma imagem era de 0,1 segundos, e aqui - 15. Era necessário otimizar.

Obviamente, esperar que o entorpecido funcionasse bem rapidamente seria errado.

Como otimizamos a computação


Medimos a velocidade de inferência através do criador de perfil python e descobrimos que quase todo o tempo era gasto multiplicando matrizes em numpy. Para a amostra, eles escreveram a multiplicação manual mais simples da matriz, e ela já se mostrou mais rápida, embora não estivesse claro o porquê.

Parece que numpy.dot deveria ter sido escrito um pouco menos ingênuo do que uma multiplicação tão simples. No entanto, convencemos, verificamos - o resultado foi mais rápido (12 segundos por quadro em vez de 15).

Em seguida, aprendemos sobre a biblioteca de álgebra linear EML, que está sendo desenvolvida no ICST, e substituímos as chamadas np.dot por cblas_sgemm. Tornou-se 10 vezes mais rápido (1,5 segundos) - ficamos muito satisfeitos.

Isso foi seguido por várias otimizações passo a passo. Como executamos apenas o reconhecimento de faces, e geralmente não dados arbitrários, decidimos aprimorar nossas operações apenas sob tensores 4d e transformar o Fusion - após o qual o tempo de processamento diminuiu 2 vezes - para 0,75 segundos.

Explicação: Fusion é quando várias operações são combinadas em uma, por exemplo, convolução, normalização e ativação. Em vez de fazer um passe em três ciclos, um passe é feito.

Essas bibliotecas estão disponíveis na NVIDIA ( TensorRT ). Um gráfico computacional é carregado nele e a biblioteca produz um gráfico otimizado e acelerado, em particular devido ao fato de poder recolher as operações em um. A Intel também possui uma similar (nGraph e OpenVINO ).

Vimos então que, como havia muitas convoluções 1x1 no Inception-ResNet, tínhamos cópia extra de dados. Decidimos nos especializar no fato de trabalharmos em lotes de 1 foto (ou seja, não processamos 100 fotos em lotes, mas fornecemos o modo de streaming) - existem casos de uso em que você não precisa trabalhar com arquivos, mas com um fluxo (por exemplo, para vigilância por vídeo ou ACS). Criamos uma passagem especializada sem im2col (removemos cópias grandes) - tornou-se 0,45 segundos.

Então olhamos novamente para o criador de perfil, tínhamos tudo da mesma maneira - embora todos os estágios tenham diminuído no tempo, ainda passamos 80% do tempo gasto no cálculo de blocos de inferência convolucionais.
Percebemos que precisávamos paralelizar gemm (multiplicação da matriz geral). Esse gemm, que em EML, acabou por ser de thread único. Assim, tivemos que escrever gemm multi-threaded. A idéia é a seguinte: uma matriz grande é dividida em sub-blocos e, em seguida, há uma multiplicação dessas pequenas matrizes. Nós escrevemos um gemm com o OpenMP, mas não funcionou, os erros travaram. Pegamos um pool manual de threads, a paralelização deu 0,33 segundos por quadro.

Em seguida, recebemos acesso remoto a um servidor mais poderoso com o Elbrus 8C , cuja velocidade aumentou para 0,2 segundos por quadro.

O vídeo a seguir mostra o trabalho do suporte de demonstração com reconhecimento de rosto em um computador Elbrus 401-PC com um processador Elbrus 4C:


Conclusões e planos futuros


  • Trabalhamos não apenas com reconhecimento de rosto, mas em princípio uma estrutura de rede neural, para que possamos coletar qualquer detector, classificador e executá-lo no Elbrus.
  • Reunimos um stand de demonstração com a Web-UI para demonstrar o reconhecimento facial no PuzzleLib.
  • O reconhecimento de rosto no Elbrus já é rápido o suficiente para tarefas práticas, e você pode acelerá-lo, se necessário.
  • Você pode trabalhar com Elbrus. Costumávamos trabalhar com processadores exóticos - por exemplo, com processadores russos tensores ainda em desenvolvimento, com placas de vídeo AMD e seus softwares. Tudo não é tão bom e simples lá. Ou seja, se usarmos a biblioteca MI Open da AMD, essa é uma biblioteca muito mal escrita, na qual nem todas as combinações de passada, preenchimento e tamanho de filtro levam a cálculos bem-sucedidos. A qualidade das ferramentas da Elbrus é boa - se você tem um projeto em Python, C ou C ++, executá-lo no Elbrus não é nada difícil.
  • Também é importante notar que o trabalho de otimização passo a passo sobre o qual falamos não é operações específicas para trabalhar na Elbrus. Essas são operações padrão do processador multinúcleo. Em nossa opinião, este é um bom sinal de que o processador pode ser operado como um processador normal da Intel / NVIDIA.

Planos:


  • Como o Elbrus tem uma peculiaridade em ser um processador VLIW, algumas otimizações específicas do Elbrus podem ser realizadas.
  • Faça a quantização (trabalhando com int8 em vez de float32), que economiza memória e aumenta a velocidade. Portanto, nesse caso, é claro, pode haver uma diminuição na qualidade dos cálculos - mas isso pode não acontecer. Percebemos os dois casos na prática.

Planejamos entender melhor, explorar os recursos do processador VLIW. De fato, por enquanto, apenas confiamos no compilador, pois, se escrevermos um bom código, o compilador o otimiza bem, porque conhece os recursos do Elbrus.

Em geral, foi interessante, vamos entender mais. Isso não levou muito tempo - todas as operações de transferência levaram um total de uma semana.

Em janeiro de 2020, planejamos colocar o PuzzleLib em código aberto, escreveremos mais sobre isso aqui =)
Obrigado pela atenção!

Source: https://habr.com/ru/post/pt469033/


All Articles