Olá pessoal!
Depois de escrever a
primeira parte, que não
era muito séria e nem particularmente útil em termos práticos, minha consciência me engoliu um pouco. E eu decidi terminar o que comecei. Ou seja, escolher a mesma implementação de uma rede neural para rodar no Rasperry Pi Zero W em tempo real (é claro, o máximo possível nesse hardware). Para expulsá-la dos dados da vida real e iluminar os resultados em Habré.
Cuidado Existe um código viável e mais alguns gatos sob o corte do que na primeira parte. Na foto, berço e bacalhau, respectivamente.
Qual rede escolher?
Lembro-me de que, devido à fraqueza do ferro framboesa, a escolha das realizações da rede neural é pequena. Ou seja:
1. SqueezeNet.
2. YOLOv3 minúsculo.
3. MobileNet.
4. ShuffleNet.
Quão correta foi a escolha a favor do SqueezeNet na
primeira parte ? .. Executar cada uma das redes neurais acima mencionadas no seu hardware é um evento bastante longo. Portanto, atormentado por vagas dúvidas, decidi pesquisar no Google se alguém tivesse feito uma pergunta dessas antes de mim. Aconteceu que ele se perguntou e investigou em detalhes. Aqueles que desejam podem consultar a
fonte . Vou me limitar a uma única imagem:

A partir da figura, o tempo de processamento de uma imagem para diferentes modelos treinados no conjunto de dados ImageNet é o mínimo com o SqueezeNet v.1.1. Tomaremos isso como um guia de ação. O YOLOv3 não foi incluído na comparação, mas, tanto quanto me lembro, o YOLO é mais caro que o MobileNet. I.e. também deve ter velocidade inferior ao SqueezeNet.
Implementação da rede selecionada
Os pesos e topologia do SqueezeNet treinados no conjunto de dados ImageNet (estrutura Caffe) podem ser encontrados no
GitHub . Apenas para o caso, baixei as duas versões para que depois pudessem ser comparadas. Por que ImageNet? Esse conjunto de todos os disponíveis tem o número máximo de classes (1000 unid.). Portanto, os resultados da rede neural prometem ser bastante interessantes.
Desta vez, veremos como o Raspberry Zero lida com o reconhecimento de quadros da câmera. Aqui está ele, nosso humilde trabalhador do post de hoje:

Peguei o código-fonte do blog Adrian Rosebrock mencionado na
primeira parte como base do código, a
partir daqui . Mas eu tive que arar significativamente:
1. Substitua seu modelo pelo MobileNetSSD no SqueezeNet.
2. A implementação da Cláusula 1 levou à expansão do número de classes para 1000. Mas, ao mesmo tempo, a função de destacar objetos com quadros multicoloridos (SSD funcional) foi, infelizmente, removida.
3. Para remover a recepção de argumentos pela linha de comando (por algum motivo, essa entrada de parâmetros me incomoda).
4. Remova o método VideoStream e, com ele, a biblioteca imutils amada por Adrian. Inicialmente, o método foi usado para obter o fluxo de vídeo da câmera. Mas com minha câmera conectada ao Raspberry Zero, estupidamente não funcionou, fornecendo algo como "Instruções ilegais".
5. Adicione a taxa de quadros (FPS) à imagem reconhecida, reescreva o cálculo do FPS.
6. Crie quadros salvos para escrever este post.
No raspberry com o Rapbian Stretch OS, Python 3.5.3 e instalado através do pip3, instale o OpenCV 3.4.1, o seguinte foi iniciado e iniciado:
Código aquiimport picamera from picamera.array import PiRGBArray import numpy as np import time from time import sleep import datetime as dt import cv2
Resultados
O código é exibido na tela do monitor conectado ao Raspberry, o próximo quadro reconhecido neste formulário. Na parte superior do quadro, apenas a classe mais provável é exibida.

Portanto, um mouse de computador foi identificado como um mouse com uma probabilidade muito alta. Ao mesmo tempo, as imagens são atualizadas com uma frequência de 0,34 FPS (ou seja, aproximadamente a cada três segundos). É um pouco chato segurar a câmera e esperar que o próximo quadro seja processado, mas você pode viver. A propósito, se você remover o quadro de salvamento no cartão SD, a velocidade de processamento aumentará para 0,37 ... 0,38 FPS. Certamente, existem outras maneiras de dispersar. Vamos esperar e ver, em qualquer caso, deixaremos esta pergunta para os próximos posts.
Separadamente, peço desculpas pelo balanço de branco. O fato é que a câmera de infravermelho com a luz de fundo ligada estava conectada ao Rapberry; portanto, a maioria dos quadros parece estranha. Mas quanto mais valioso cada acerto da rede neural. Obviamente, o balanço de branco no conjunto de treinamento estava mais correto. Além disso, decidi inserir apenas os quadros brutos, para que o leitor os veja da mesma maneira que vêem a rede neural.
Primeiro, vamos comparar o trabalho das versões 1.0 do SqueezeNet (no quadro esquerdo) e 1.1 (no direito):

Pode-se ver que a versão 1.1 funciona duas vezes e quinze vezes mais rápido que 1.0 (0,34 FPS versus 0,15). O ganho de velocidade é palpável. Não vale a pena tirar conclusões sobre a precisão do reconhecimento neste exemplo, pois a precisão depende muito da posição da câmera em relação ao objeto, iluminação, brilho, sombras etc.
Em vista de uma vantagem de velocidade tão significativa v1.1 sobre v.1.0 no futuro, apenas o SqueezeNet v.1.1 foi usado. Para avaliar o desempenho do modelo, apontei a câmera para vários objetos que
estavam à mão e recebi os seguintes quadros na saída:

Um teclado é pior que um mouse. Talvez no conjunto de treinamento, a maioria dos teclados fosse branca.

Um telefone celular é muito bem definido se você ligar a tela. Uma célula com uma tela desligada não conta uma rede neural como célula.

Uma xícara vazia é razoavelmente definida como uma xícara de café. Até agora, tudo está indo muito bem.

As tesouras estão em piores condições: são teimosamente definidas pela rede como um grampo de cabelo. No entanto, entrar na macieira, se não no alvo)
Vamos complicar a tarefa
Vamos tentar colocar algo complicado na rede neural do
porco . Acabei de encontrar um brinquedo infantil caseiro. Acredito que a maioria dos leitores o reconheça como um gato de brinquedo. Eu me pergunto o que será considerado por nossa inteligência artificial rudimentar.

No quadro à esquerda, a luz infravermelha apagou todas as tiras do tecido. Como resultado, o brinquedo foi definido como uma máscara de oxigênio com uma probabilidade bastante decente. Porque não A forma do brinquedo realmente se assemelha a uma máscara de oxigênio.
Na moldura à direita, cobri meus dedos com um destaque de infravermelho, para que as listras aparecessem no brinquedo e o balanço de branco se tornasse mais crível. Na verdade, esse é o único quadro que parece mais ou menos normal neste post. Mas a rede neural tem uma abundância de detalhes na imagem confusa. Ela identificou o brinquedo como um moletom. Devo dizer que isso também não parece um "dedo no céu". Bata se não estiver na "macieira", pelo menos no pomar).
Bem, abordamos sem problemas o clímax de nossa ação. O vencedor de destaque da batalha, consagrado em detalhes no
primeiro post, entra no ringue. E tira facilmente o cérebro da nossa rede neural desde os primeiros quadros.

É curioso que um gato praticamente não mude de posição, mas cada vez que é determinado de forma diferente. E desta perspectiva, é mais parecido com um gambá. Em segundo lugar, é a semelhança com um hamster. Vamos tentar mudar o ângulo.

Sim, se você tirar uma foto de um gato de cima, é determinado corretamente, mas se você mudar um pouco a posição do corpo do gato no quadro, para a rede neural, ele se torna um cachorro - do husky e malamute siberiano (cão de trenó esquimó), respectivamente.

E essa seleção é bonita, pois um cão de raças diferentes é definido em cada quadro separado de um gato. E as raças não se repetem)

A propósito, há poses nas quais as redes neurais se tornam óbvias de que ainda é um gato, não um cachorro. Ou seja, o SqueezeNet v.1.1 ainda conseguiu provar a si mesmo em um objeto tão difícil de analisar. Dado o sucesso da rede neural no reconhecimento de objetos no início do teste e no reconhecimento de um gato como um gato no final, desta vez declaramos um forte empate de combate)
Bem, isso é tudo. Convido todos a experimentar o código proposto em sua framboesa e em qualquer objeto que tenha sido exibido como objetos animados e inanimados. Serei especialmente grato àqueles que medem o FPS no Rapberry Pi B +. Prometo incluir os resultados neste post com referência à pessoa que enviou os dados. Eu acredito que deve sair significativamente mais do que 1 FPS!
Espero que algumas das informações contidas neste post sejam úteis para fins educacionais ou de entretenimento, e alguém possa até ter novas idéias.
Tenham uma boa semana de trabalho! E até breve)

UPD1: No Raspberry Pi 3B +, o script acima funciona com uma frequência de 2 com um pequeno FPS.
UPD2: No RPi 3B + com Movidius NCS, o script é executado em 6 FPS.