Caffe2 - Guia rápido
Nos últimos dois anos, o Deep Learning se tornou uma grande tendência no aprendizado de máquina. Foi aplicado com sucesso para resolver problemas anteriormente insolúveis em Vision, Speech Recognition and Natural Language Processing(PNL). Existem muitos outros domínios nos quais o Deep Learning está sendo aplicado e mostrou sua utilidade.
Caffe (Convolutional Architecture for Fast Feature Embedding) é uma estrutura de aprendizagem profunda desenvolvida em Berkeley Vision and Learning Center (BVLC). O projeto Caffe foi criado por Yangqing Jia durante seu doutorado. na Universidade da Califórnia - Berkeley. O Caffe oferece uma maneira fácil de experimentar o aprendizado profundo. Ele é escrito em C ++ e fornece ligações paraPython e Matlab.
Ele suporta muitos tipos diferentes de arquiteturas de aprendizado profundo, como CNN (Rede Neural Convolucional), LSTM(Memória de longo prazo) e FC (totalmente conectado). Ele oferece suporte a GPU e, portanto, é ideal para ambientes de produção envolvendo redes neurais profundas. Ele também suporta bibliotecas de kernel baseadas em CPU, comoNVIDIA, Biblioteca CUDA Deep Neural Network (cuDNN) e Intel Math Kernel Library (Intel MKL).
Em abril de 2017, a empresa americana de serviços de rede social Facebook anunciou o Caffe2, que agora inclui RNN (Redes Neurais Recorrentes) e, em março de 2018, o Caffe2 foi fundido com o PyTorch. Os criadores do Caffe2 e membros da comunidade criaram modelos para resolver vários problemas. Esses modelos estão disponíveis ao público como modelos pré-treinados. Caffe2 ajuda os criadores a usar esses modelos e criar sua própria rede para fazer previsões no conjunto de dados.
Antes de entrarmos nos detalhes do Caffe2, vamos entender a diferença entre machine learning e deep learning. Isso é necessário para entender como os modelos são criados e usados no Caffe2.
Aprendizado de máquina x aprendizado profundo
Em qualquer algoritmo de aprendizado de máquina, seja ele tradicional ou de aprendizado profundo, a seleção de recursos no conjunto de dados desempenha um papel extremamente importante na obtenção da precisão de predição desejada. Em técnicas tradicionais de aprendizado de máquina, ofeature selectioné feito principalmente por inspeção humana, julgamento e profundo conhecimento do domínio. Às vezes, você pode buscar a ajuda de alguns algoritmos testados para seleção de recursos.
O fluxo de aprendizado de máquina tradicional é ilustrado na figura abaixo -
No aprendizado profundo, a seleção de recursos é automática e faz parte do próprio algoritmo de aprendizado profundo. Isso é mostrado na figura abaixo -
Em algoritmos de aprendizado profundo, feature engineeringé feito automaticamente. Geralmente, a engenharia de recursos é demorada e requer um bom conhecimento no domínio. Para implementar a extração automática de recursos, os algoritmos de aprendizado profundo geralmente pedem uma grande quantidade de dados, portanto, se você tiver apenas milhares e dezenas de milhares de pontos de dados, a técnica de aprendizado profundo pode falhar em fornecer resultados satisfatórios.
Com dados maiores, os algoritmos de aprendizado profundo produzem melhores resultados em comparação com os algoritmos de ML tradicionais com uma vantagem adicional de menos ou nenhuma engenharia de recursos.
Agora, como você tem alguns insights sobre aprendizado profundo, vamos ter uma visão geral do que é o Caffe.
Treinando uma CNN
Vamos aprender o processo de treinamento de uma CNN para classificação de imagens. O processo consiste nas seguintes etapas -
Data Preparation- Nesta etapa, recortamos as imagens no centro e as redimensionamos para que todas as imagens para treinamento e teste tenham o mesmo tamanho. Isso geralmente é feito executando um pequeno script Python nos dados da imagem.
Model Definition- Nesta etapa, definimos uma arquitetura CNN. A configuração é armazenada em.pb (protobuf)Arquivo. Uma arquitetura típica de CNN é mostrada na figura abaixo.
Solver Definition- Definimos o arquivo de configuração do solver. O Solver faz a otimização do modelo.
Model Training- Usamos o utilitário Caffe embutido para treinar o modelo. O treinamento pode levar uma quantidade considerável de tempo e uso da CPU. Após a conclusão do treinamento, o Caffe armazena o modelo em um arquivo, que pode ser usado posteriormente em dados de teste e implantação final para previsões.
O que há de novo no Caffe2
No Caffe2, você encontrará muitos modelos pré-treinados prontos para uso e também aproveitará as contribuições da comunidade de novos modelos e algoritmos com bastante frequência. Os modelos que você cria podem escalar facilmente usando o poder da GPU na nuvem e também podem ser reduzidos ao uso de massas no celular com suas bibliotecas de plataforma cruzada.
As melhorias feitas no Caffe2 em relação ao Caffe podem ser resumidas da seguinte forma -
- Implantação móvel
- Novo suporte de hardware
- Suporte para treinamento distribuído em larga escala
- Computação quantizada
- Stress testado no Facebook
Demonstração de modelo pré-treinado
O site do Berkeley Vision and Learning Center (BVLC) fornece demonstrações de suas redes pré-treinadas. Uma rede para classificação de imagens está disponível no link aqui indicadohttps://caffe2.ai/docs/learn-more#null__caffe-neural-network-for-image-classification e é retratado na imagem abaixo.
Na captura de tela, a imagem de um cachorro é classificada e rotulada com sua precisão de previsão. Também diz que demorou apenas0.068 secondspara classificar a imagem. Você pode tentar uma imagem de sua escolha especificando o URL da imagem ou enviando a própria imagem nas opções fornecidas na parte inferior da tela.
Agora que você tem informações suficientes sobre os recursos do Caffe2, é hora de experimentar o Caffe2 por conta própria. Para usar os modelos pré-treinados ou para desenvolver seus modelos em seu próprio código Python, você deve primeiro instalar o Caffe2 em sua máquina.
Na página de instalação do site Caffe2 que está disponível no link https://caffe2.ai/docs/getting-started.html você veria o seguinte para selecionar sua plataforma e tipo de instalação.
Como você pode ver na imagem acima, Caffe2 suporta várias plataformas populares, incluindo as móveis.
Agora, vamos entender as etapas para MacOS installation no qual todos os projetos neste tutorial são testados.
Instalação MacOS
A instalação pode ser de quatro tipos, conforme indicado abaixo -
- Binários pré-construídos
- Construir a partir da fonte
- Imagens Docker
- Cloud
Dependendo de sua preferência, selecione qualquer uma das opções acima como seu tipo de instalação. As instruções fornecidas aqui são de acordo com o local de instalação do Caffe2 parapre-built binaries. Ele usa o Anaconda paraJupyter environment. Execute o seguinte comando no prompt do console
pip install torch_nightly -f
https://download.pytorch.org/whl/nightly/cpu/torch_nightly.html
Além do acima, você precisará de algumas bibliotecas de terceiros, que são instaladas usando os seguintes comandos -
conda install -c anaconda setuptools
conda install -c conda-forge graphviz
conda install -c conda-forge hypothesis
conda install -c conda-forge ipython
conda install -c conda-forge jupyter
conda install -c conda-forge matplotlib
conda install -c anaconda notebook
conda install -c anaconda pydot
conda install -c conda-forge python-nvd3
conda install -c anaconda pyyaml
conda install -c anaconda requests
conda install -c anaconda scikit-image
conda install -c anaconda scipy
Alguns dos tutoriais no site Caffe2 também exigem a instalação de zeromq, que é instalado usando o seguinte comando -
conda install -c anaconda zeromq
Instalação Windows / Linux
Execute o seguinte comando no prompt do console -
conda install -c pytorch pytorch-nightly-cpu
Como você deve ter notado, você precisaria do Anaconda para usar a instalação acima. Você precisará instalar os pacotes adicionais conforme especificado noMacOS installation.
Instalação de teste
Para testar sua instalação, um pequeno script Python é fornecido abaixo, que você pode cortar e colar em seu projeto Juypter e executar.
from caffe2.python import workspace
import numpy as np
print ("Creating random data")
data = np.random.rand(3, 2)
print(data)
print ("Adding data to workspace ...")
workspace.FeedBlob("mydata", data)
print ("Retrieving data from workspace")
mydata = workspace.FetchBlob("mydata")
print(mydata)
Ao executar o código acima, você verá a seguinte saída -
Creating random data
[[0.06152718 0.86448082]
[0.36409966 0.52786113]
[0.65780886 0.67101053]]
Adding data to workspace ...
Retrieving data from workspace
[[0.06152718 0.86448082]
[0.36409966 0.52786113]
[0.65780886 0.67101053]]
A captura de tela da página de teste de instalação é mostrada aqui para sua referência rápida -
Agora que você instalou o Caffe2 em sua máquina, prossiga para instalar os aplicativos do tutorial.
Instalação Tutorial
Baixe a fonte dos tutoriais usando o seguinte comando em seu console -
git clone --recursive https://github.com/caffe2/tutorials caffe2_tutorials
Depois que o download for concluído, você encontrará vários projetos Python no caffe2_tutorialspasta em seu diretório de instalação. A captura de tela desta pasta é fornecida para sua leitura rápida.
/Users/yourusername/caffe2_tutorials
Você pode abrir alguns desses tutoriais para ver o que Caffe2 codeparece. Os próximos dois projetos descritos neste tutorial são amplamente baseados nos exemplos mostrados acima.
Agora é hora de fazermos nossa própria codificação Python. Vamos entender, como usar um modelo pré-treinado do Caffe2. Posteriormente, você aprenderá a criar sua própria rede neural trivial para treinamento em seu próprio conjunto de dados.
Antes de aprender a usar um modelo pré-treinado em seu aplicativo Python, vamos primeiro verificar se os modelos estão instalados em sua máquina e são acessíveis por meio do código Python.
Quando você instala o Caffe2, os modelos pré-treinados são copiados na pasta de instalação. Na máquina com instalação do Anaconda, esses modelos estão disponíveis na pasta a seguir.
anaconda3/lib/python3.7/site-packages/caffe2/python/models
Verifique a pasta de instalação em sua máquina para a presença desses modelos. Você pode tentar carregar esses modelos da pasta de instalação com o seguinte script Python curto -
CAFFE_MODELS = os.path.expanduser("/anaconda3/lib/python3.7/site-packages/caffe2/python/models")
INIT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'init_net.pb')
PREDICT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'predict_net.pb')
print(INIT_NET)
print(PREDICT_NET)
Quando o script for executado com sucesso, você verá a seguinte saída -
/anaconda3/lib/python3.7/site-packages/caffe2/python/models/squeezenet/init_net.pb
/anaconda3/lib/python3.7/site-packages/caffe2/python/models/squeezenet/predict_net.pb
Isso confirma que o squeezenet módulo está instalado em sua máquina e está acessível para seu código.
Agora, você está pronto para escrever seu próprio código Python para classificação de imagens usando Caffe2 squeezenet módulo pré-treinado.
Nesta lição, você aprenderá a usar um modelo pré-treinado para detectar objetos em uma determinada imagem. Você vai usarsqueezenet Módulo pré-treinado que detecta e classifica os objetos em uma determinada imagem com grande precisão.
Abra um novo Juypter notebook e siga as etapas para desenvolver este aplicativo de classificação de imagens.
Importando Bibliotecas
Primeiro, importamos os pacotes necessários usando o código abaixo -
from caffe2.proto import caffe2_pb2
from caffe2.python import core, workspace, models
import numpy as np
import skimage.io
import skimage.transform
from matplotlib import pyplot
import os
import urllib.request as urllib2
import operator
Em seguida, configuramos alguns variables -
INPUT_IMAGE_SIZE = 227
mean = 128
As imagens usadas para o treinamento obviamente serão de tamanhos variados. Todas essas imagens devem ser convertidas em um tamanho fixo para um treinamento preciso. Da mesma forma, as imagens de teste e a imagem que se deseja prever no ambiente de produção também devem ser convertidas para o tamanho igual ao utilizado durante o treinamento. Assim, criamos uma variável acima chamadaINPUT_IMAGE_SIZE tendo valor 227. Portanto, vamos converter todas as nossas imagens para o tamanho227x227 antes de usá-lo em nosso classificador.
Também declaramos uma variável chamada mean tendo valor 128, que é usado posteriormente para melhorar os resultados da classificação.
A seguir, desenvolveremos duas funções para o processamento da imagem.
Processamento de imagem
O processamento da imagem consiste em duas etapas. O primeiro é redimensionar a imagem e o segundo é recortar a imagem centralmente. Para essas duas etapas, escreveremos duas funções para redimensionar e recortar.
Redimensionamento de imagem
Primeiro, vamos escrever uma função para redimensionar a imagem. Como dissemos antes, vamos redimensionar a imagem para227x227. Então, vamos definir a funçãoresize como segue -
def resize(img, input_height, input_width):
Obtemos a proporção da imagem dividindo a largura pela altura.
original_aspect = img.shape[1]/float(img.shape[0])
Se a relação de aspecto for maior que 1, indica que a imagem é ampla, ou seja, está no modo paisagem. Agora ajustamos a altura da imagem e retornamos a imagem redimensionada usando o seguinte código -
if(original_aspect>1):
new_height = int(original_aspect * input_height)
return skimage.transform.resize(img, (input_width,
new_height), mode='constant', anti_aliasing=True, anti_aliasing_sigma=None)
Se a proporção for less than 1, indica o portrait mode. Agora ajustamos a largura usando o seguinte código -
if(original_aspect<1):
new_width = int(input_width/original_aspect)
return skimage.transform.resize(img, (new_width,
input_height), mode='constant', anti_aliasing=True, anti_aliasing_sigma=None)
Se a proporção da imagem for igual 1, não fazemos ajustes de altura / largura.
if(original_aspect == 1):
return skimage.transform.resize(img, (input_width,
input_height), mode='constant', anti_aliasing=True, anti_aliasing_sigma=None)
O código de função completo é fornecido abaixo para sua referência rápida -
def resize(img, input_height, input_width):
original_aspect = img.shape[1]/float(img.shape[0])
if(original_aspect>1):
new_height = int(original_aspect * input_height)
return skimage.transform.resize(img, (input_width,
new_height), mode='constant', anti_aliasing=True, anti_aliasing_sigma=None)
if(original_aspect<1):
new_width = int(input_width/original_aspect)
return skimage.transform.resize(img, (new_width,
input_height), mode='constant', anti_aliasing=True, anti_aliasing_sigma=None)
if(original_aspect == 1):
return skimage.transform.resize(img, (input_width,
input_height), mode='constant', anti_aliasing=True, anti_aliasing_sigma=None)
Agora escreveremos uma função para cortar a imagem em torno de seu centro.
Corte de imagem
Nós declaramos o crop_image funcionar da seguinte forma -
def crop_image(img,cropx,cropy):
Extraímos as dimensões da imagem usando a seguinte declaração -
y,x,c = img.shape
Criamos um novo ponto de partida para a imagem usando as duas linhas de código a seguir -
startx = x//2-(cropx//2)
starty = y//2-(cropy//2)
Finalmente, retornamos a imagem cortada criando um objeto de imagem com as novas dimensões -
return img[starty:starty+cropy,startx:startx+cropx]
Todo o código da função é fornecido abaixo para sua referência rápida -
def crop_image(img,cropx,cropy):
y,x,c = img.shape
startx = x//2-(cropx//2)
starty = y//2-(cropy//2)
return img[starty:starty+cropy,startx:startx+cropx]
Agora, vamos escrever o código para testar essas funções.
Processando imagem
Em primeiro lugar, copie um arquivo de imagem em images subpasta dentro do diretório do projeto. tree.jpgo arquivo é copiado no projeto. O seguinte código Python carrega a imagem e a exibe no console -
img = skimage.img_as_float(skimage.io.imread("images/tree.jpg")).astype(np.float32)
print("Original Image Shape: " , img.shape)
pyplot.figure()
pyplot.imshow(img)
pyplot.title('Original image')
O resultado é o seguinte -
Observe que o tamanho da imagem original é 600 x 960. Precisamos redimensionar isso para nossa especificação de227 x 227. Chamando nosso definido anteriormenteresizefunção faz esse trabalho.
img = resize(img, INPUT_IMAGE_SIZE, INPUT_IMAGE_SIZE)
print("Image Shape after resizing: " , img.shape)
pyplot.figure()
pyplot.imshow(img)
pyplot.title('Resized image')
O resultado é o seguinte -
Observe que agora o tamanho da imagem é 227 x 363. Precisamos cortar isso para227 x 227para o feed final do nosso algoritmo. Chamamos a função de corte previamente definida para este propósito.
img = crop_image(img, INPUT_IMAGE_SIZE, INPUT_IMAGE_SIZE)
print("Image Shape after cropping: " , img.shape)
pyplot.figure()
pyplot.imshow(img)
pyplot.title('Center Cropped')
Abaixo mencionado está a saída do código -
Neste ponto, a imagem está do tamanho 227 x 227e está pronto para processamento posterior. Agora trocamos os eixos da imagem para extrair as três cores em três zonas diferentes.
img = img.swapaxes(1, 2).swapaxes(0, 1)
print("CHW Image Shape: " , img.shape)
A seguir está o resultado -
CHW Image Shape: (3, 227, 227)
Observe que o último eixo agora se tornou a primeira dimensão na matriz. Vamos agora representar os três canais usando o seguinte código -
pyplot.figure()
for i in range(3):
pyplot.subplot(1, 3, i+1)
pyplot.imshow(img[i])
pyplot.axis('off')
pyplot.title('RGB channel %d' % (i+1))
O resultado é declarado abaixo -
Finalmente, fazemos algum processamento adicional na imagem, como a conversão Red Green Blue para Blue Green Red (RGB to BGR), removendo a média para melhores resultados e adicionando eixo de tamanho de lote usando as seguintes três linhas de código -
# convert RGB --> BGR
img = img[(2, 1, 0), :, :]
# remove mean
img = img * 255 - mean
# add batch size axis
img = img[np.newaxis, :, :, :].astype(np.float32)
Neste ponto, sua imagem está em NCHW formate está pronto para alimentar nossa rede. A seguir, carregaremos nossos arquivos de modelo pré-treinados e alimentaremos a imagem acima para previsão.
Previsão de objetos em imagem processada
Primeiro configuramos os caminhos para o init e predict redes definidas nos modelos pré-treinados da Caffe.
Configurando caminhos de arquivo de modelo
Lembre-se de nossa discussão anterior, todos os modelos pré-treinados são instalados no modelspasta. Configuramos o caminho para esta pasta da seguinte maneira -
CAFFE_MODELS = os.path.expanduser("/anaconda3/lib/python3.7/site-packages/caffe2/python/models")
Nós montamos o caminho para o init_net arquivo protobuf do squeezenet modelo da seguinte forma -
INIT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'init_net.pb')
Da mesma forma, configuramos o caminho para o predict_net protobuf da seguinte forma -
PREDICT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'predict_net.pb')
Imprimimos os dois caminhos para fins de diagnóstico -
print(INIT_NET)
print(PREDICT_NET)
O código acima, junto com a saída, é fornecido aqui para sua referência rápida -
CAFFE_MODELS = os.path.expanduser("/anaconda3/lib/python3.7/site-packages/caffe2/python/models")
INIT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'init_net.pb')
PREDICT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'predict_net.pb')
print(INIT_NET)
print(PREDICT_NET)
O resultado é mencionado abaixo -
/anaconda3/lib/python3.7/site-packages/caffe2/python/models/squeezenet/init_net.pb
/anaconda3/lib/python3.7/site-packages/caffe2/python/models/squeezenet/predict_net.pb
A seguir, criaremos um preditor.
Criando Predictor
Lemos os arquivos de modelo usando as duas declarações a seguir -
with open(INIT_NET, "rb") as f:
init_net = f.read()
with open(PREDICT_NET, "rb") as f:
predict_net = f.read()
O preditor é criado passando ponteiros para os dois arquivos como parâmetros para o Predictor função.
p = workspace.Predictor(init_net, predict_net)
o pobject é o preditor, que é usado para predizer os objetos em qualquer imagem. Observe que cada imagem de entrada deve estar no formato NCHW como o que fizemos anteriormente para nossotree.jpg Arquivo.
Objetos de previsão
Prever os objetos em uma determinada imagem é trivial - basta executar uma única linha de comando. Nós chamamosrun método no predictor objeto para a detecção de um objeto em uma determinada imagem.
results = p.run({'data': img})
Os resultados da previsão agora estão disponíveis no results objeto, que convertemos em uma matriz para nossa legibilidade.
results = np.asarray(results)
Imprima as dimensões da matriz para sua compreensão usando a seguinte declaração -
print("results shape: ", results.shape)
O resultado é mostrado abaixo -
results shape: (1, 1, 1000, 1, 1)
Vamos agora remover o eixo desnecessário -
preds = np.squeeze(results)
A predicação superior agora pode ser recuperada tomando o max valor no preds array.
curr_pred, curr_conf = max(enumerate(preds), key=operator.itemgetter(1))
print("Prediction: ", curr_pred)
print("Confidence: ", curr_conf)
O resultado é o seguinte -
Prediction: 984
Confidence: 0.89235985
Como você pode ver, o modelo previu um objeto com um valor de índice 984 com 89%confiança. O índice de 984 não faz muito sentido para nós na compreensão do tipo de objeto detectado. Precisamos obter o nome stringificado para o objeto usando seu valor de índice. Os tipos de objetos que o modelo reconhece junto com seus valores de índice correspondentes estão disponíveis em um repositório github.
Agora, veremos como recuperar o nome do nosso objeto com valor de índice de 984.
Resultado de Stringificação
Criamos um objeto de URL para o repositório github da seguinte maneira -
codes = "https://gist.githubusercontent.com/aaronmarkham/cd3a6b6ac0
71eca6f7b4a6e40e6038aa/raw/9edb4038a37da6b5a44c3b5bc52e448ff09bfe5b/alexnet_codes"
Lemos o conteúdo do URL -
response = urllib2.urlopen(codes)
A resposta conterá uma lista de todos os códigos e suas descrições. Algumas linhas da resposta são mostradas abaixo para sua compreensão do que ela contém -
5: 'electric ray, crampfish, numbfish, torpedo',
6: 'stingray',
7: 'cock',
8: 'hen',
9: 'ostrich, Struthio camelus',
10: 'brambling, Fringilla montifringilla',
Agora iteramos todo o array para localizar nosso código desejado de 984 usando um for loop da seguinte forma -
for line in response:
mystring = line.decode('ascii')
code, result = mystring.partition(":")[::2]
code = code.strip()
result = result.replace("'", "")
if (code == str(curr_pred)):
name = result.split(",")[0][1:]
print("Model predicts", name, "with", curr_conf, "confidence")
Ao executar o código, você verá a seguinte saída -
Model predicts rapeseed with 0.89235985 confidence
Agora você pode experimentar o modelo em outra imagem.
Previsão de uma imagem diferente
Para prever outra imagem, basta copiar o arquivo de imagem para o imagespasta do diretório do seu projeto. Este é o diretório no qual nossotree.jpgarquivo é armazenado. Altere o nome do arquivo de imagem no código. Apenas uma alteração é necessária conforme mostrado abaixo
img = skimage.img_as_float(skimage.io.imread("images/pretzel.jpg")).astype(np.float32)
A imagem original e o resultado da previsão são mostrados abaixo -
O resultado é mencionado abaixo -
Model predicts pretzel with 0.99999976 confidence
Como você pode ver, o modelo pré-treinado é capaz de detectar objetos em uma determinada imagem com grande precisão.
Full Source
O código-fonte completo do código acima que usa um modelo pré-treinado para detecção de objetos em uma determinada imagem é mencionado aqui para sua referência rápida -
def crop_image(img,cropx,cropy):
y,x,c = img.shape
startx = x//2-(cropx//2)
starty = y//2-(cropy//2)
return img[starty:starty+cropy,startx:startx+cropx]
img = skimage.img_as_float(skimage.io.imread("images/pretzel.jpg")).astype(np.float32)
print("Original Image Shape: " , img.shape)
pyplot.figure()
pyplot.imshow(img)
pyplot.title('Original image')
img = resize(img, INPUT_IMAGE_SIZE, INPUT_IMAGE_SIZE)
print("Image Shape after resizing: " , img.shape)
pyplot.figure()
pyplot.imshow(img)
pyplot.title('Resized image')
img = crop_image(img, INPUT_IMAGE_SIZE, INPUT_IMAGE_SIZE)
print("Image Shape after cropping: " , img.shape)
pyplot.figure()
pyplot.imshow(img)
pyplot.title('Center Cropped')
img = img.swapaxes(1, 2).swapaxes(0, 1)
print("CHW Image Shape: " , img.shape)
pyplot.figure()
for i in range(3):
pyplot.subplot(1, 3, i+1)
pyplot.imshow(img[i])
pyplot.axis('off')
pyplot.title('RGB channel %d' % (i+1))
# convert RGB --> BGR
img = img[(2, 1, 0), :, :]
# remove mean
img = img * 255 - mean
# add batch size axis
img = img[np.newaxis, :, :, :].astype(np.float32)
CAFFE_MODELS = os.path.expanduser("/anaconda3/lib/python3.7/site-packages/caffe2/python/models")
INIT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'init_net.pb')
PREDICT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'predict_net.pb')
print(INIT_NET)
print(PREDICT_NET)
with open(INIT_NET, "rb") as f:
init_net = f.read()
with open(PREDICT_NET, "rb") as f:
predict_net = f.read()
p = workspace.Predictor(init_net, predict_net)
results = p.run({'data': img})
results = np.asarray(results)
print("results shape: ", results.shape)
preds = np.squeeze(results)
curr_pred, curr_conf = max(enumerate(preds), key=operator.itemgetter(1))
print("Prediction: ", curr_pred)
print("Confidence: ", curr_conf)
codes = "https://gist.githubusercontent.com/aaronmarkham/cd3a6b6ac071eca6f7b4a6e40e6038aa/raw/9edb4038a37da6b5a44c3b5bc52e448ff09bfe5b/alexnet_codes"
response = urllib2.urlopen(codes)
for line in response:
mystring = line.decode('ascii')
code, result = mystring.partition(":")[::2]
code = code.strip()
result = result.replace("'", "")
if (code == str(curr_pred)):
name = result.split(",")[0][1:]
print("Model predicts", name, "with", curr_conf, "confidence")
A esta altura, você já sabe como usar um modelo pré-treinado para fazer as previsões em seu conjunto de dados.
O que vem a seguir é aprender como definir seu neural network (NN) arquiteturas em Caffe2e treine-os em seu conjunto de dados. Agora aprenderemos como criar um NN de camada única trivial.
Nesta lição, você aprenderá a definir um single layer neural network (NN)no Caffe2 e execute-o em um conjunto de dados gerado aleatoriamente. Escreveremos código para representar graficamente a arquitetura da rede, imprimir a entrada, a saída, os pesos e os valores de polarização. Para entender esta lição, você deve estar familiarizado comneural network architectures, Está terms e mathematics usado neles.
Arquitetura de rede
Vamos considerar que queremos construir uma única camada NN como mostrado na figura abaixo -
Matematicamente, esta rede é representada pelo seguinte código Python -
Y = X * W^T + b
Onde X, W, b são tensores e Yé a saída. Vamos preencher todos os três tensores com alguns dados aleatórios, executar a rede e examinar oYresultado. Para definir a rede e os tensores, Caffe2 fornece váriosOperator funções.
Operadores Caffe2
No Caffe2, Operatoré a unidade básica de computação. The Caffe2Operator é representado da seguinte forma.
Caffe2 fornece uma lista exaustiva de operadores. Para a rede que estamos projetando atualmente, usaremos o operador chamado FC, que calcula o resultado da passagem de um vetor de entradaX em uma rede totalmente conectada com uma matriz de peso bidimensional W e um vetor de polarização unidimensional b. Em outras palavras, ele calcula a seguinte equação matemática
Y = X * W^T + b
Onde X tem dimensões (M x k), W tem dimensões (n x k) e b é (1 x n). A saídaY será de dimensão (M x n), Onde M é o tamanho do lote.
Para os vetores X e W, vamos usar o GaussianFilloperador para criar alguns dados aleatórios. Para gerar valores de polarizaçãob, nós vamos usar ConstantFill operador.
Vamos agora definir nossa rede.
Criando Rede
Em primeiro lugar, importe os pacotes necessários -
from caffe2.python import core, workspace
Em seguida, defina a rede chamando core.Net como segue -
net = core.Net("SingleLayerFC")
O nome da rede é especificado como SingleLayerFC. Nesse ponto, o objeto de rede denominado net é criado. Ele não contém nenhuma camada até o momento.
Criação de tensores
Vamos agora criar os três vetores exigidos por nossa rede. Primeiro, criaremos o tensor X chamandoGaussianFill operador da seguinte forma -
X = net.GaussianFill([], ["X"], mean=0.0, std=1.0, shape=[2, 3], run_once=0)
o X vetor tem dimensões 2 x 3 com o valor médio dos dados de 0,0 e desvio padrão de 1.0.
Da mesma forma, nós criamos W tensor da seguinte forma -
W = net.GaussianFill([], ["W"], mean=0.0, std=1.0, shape=[5, 3], run_once=0)
o W vetor é do tamanho 5 x 3.
Finalmente, criamos viés b matriz de tamanho 5.
b = net.ConstantFill([], ["b"], shape=[5,], value=1.0, run_once=0)
Agora, vem a parte mais importante do código, que é definir a própria rede.
Definindo Rede
Definimos a rede na seguinte instrução Python -
Y = X.FC([W, b], ["Y"])
Nós chamamos FC operador nos dados de entrada X. Os pesos são especificados emWe viés em b. A saída éY. Como alternativa, você pode criar a rede usando a seguinte instrução Python, que é mais detalhada.
Y = net.FC([X, W, b], ["Y"])
Nesse ponto, a rede é simplesmente criada. Até que executemos a rede pelo menos uma vez, ela não conterá nenhum dado. Antes de executar a rede, examinaremos sua arquitetura.
Arquitetura de rede de impressão
Caffe2 define a arquitetura de rede em um arquivo JSON, que pode ser examinado chamando o método Proto no net objeto.
print (net.Proto())
Isso produz a seguinte saída -
name: "SingleLayerFC"
op {
output: "X"
name: ""
type: "GaussianFill"
arg {
name: "mean"
f: 0.0
}
arg {
name: "std"
f: 1.0
}
arg {
name: "shape"
ints: 2
ints: 3
}
arg {
name: "run_once"
i: 0
}
}
op {
output: "W"
name: ""
type: "GaussianFill"
arg {
name: "mean"
f: 0.0
}
arg {
name: "std"
f: 1.0
}
arg {
name: "shape"
ints: 5
ints: 3
}
arg {
name: "run_once"
i: 0
}
}
op {
output: "b"
name: ""
type: "ConstantFill"
arg {
name: "shape"
ints: 5
}
arg {
name: "value"
f: 1.0
}
arg {
name: "run_once"
i: 0
}
}
op {
input: "X"
input: "W"
input: "b"
output: "Y"
name: ""
type: "FC"
}
Como você pode ver na lista acima, primeiro define os operadores X, W e b. Vamos examinar a definição deWcomo um exemplo. O tipo deW é especificado como GausianFill. omean é definido como flutuante 0.0, o desvio padrão é definido como flutuante 1.0, e as shape é 5 x 3.
op {
output: "W"
name: "" type: "GaussianFill"
arg {
name: "mean"
f: 0.0
}
arg {
name: "std"
f: 1.0
}
arg {
name: "shape"
ints: 5
ints: 3
}
...
}
Examine as definições de X e bpara seu próprio entendimento. Finalmente, vamos dar uma olhada na definição de nossa rede de camada única, que é reproduzida aqui
op {
input: "X"
input: "W"
input: "b"
output: "Y"
name: ""
type: "FC"
}
Aqui, o tipo de rede é FC (Totalmente conectado) com X, W, b como entradas e Yé a saída. Essa definição de rede é muito detalhada e, para redes grandes, será tedioso examinar seu conteúdo. Felizmente, Caffe2 fornece uma representação gráfica para as redes criadas.
Representação Gráfica da Rede
Para obter a representação gráfica da rede, execute o seguinte trecho de código, que é essencialmente apenas duas linhas de código Python.
from caffe2.python import net_drawer
from IPython import display
graph = net_drawer.GetPydotGraph(net, rankdir="LR")
display.Image(graph.create_png(), width=800)
Ao executar o código, você verá a seguinte saída -
Para grandes redes, a representação gráfica torna-se extremamente útil na visualização e depuração de erros de definição de rede.
Finalmente, é hora de operar a rede.
Rede em execução
Você administra a rede chamando o RunNetOnce método no workspace objeto -
workspace.RunNetOnce(net)
Depois que a rede é executada uma vez, todos os nossos dados que são gerados aleatoriamente seriam criados, alimentados na rede e a saída seria criada. Os tensores que são criados após a execução da rede são chamadosblobsem Caffe2. O espaço de trabalho consiste noblobsvocê cria e armazena na memória. Isso é bastante semelhante ao Matlab.
Depois de executar a rede, você pode examinar o blobs que o espaço de trabalho contém usando o seguinte print comando
print("Blobs in the workspace: {}".format(workspace.Blobs()))
Você verá a seguinte saída -
Blobs in the workspace: ['W', 'X', 'Y', 'b']
Observe que o espaço de trabalho consiste em três blobs de entrada - X, W e b. Ele também contém o blob de saída chamadoY. Vamos agora examinar o conteúdo desses blobs.
for name in workspace.Blobs():
print("{}:\n{}".format(name, workspace.FetchBlob(name)))
Você verá a seguinte saída -
W:
[[ 1.0426593 0.15479846 0.25635982]
[-2.2461145 1.4581774 0.16827184]
[-0.12009818 0.30771437 0.00791338]
[ 1.2274994 -0.903331 -0.68799865]
[ 0.30834186 -0.53060573 0.88776857]]
X:
[[ 1.6588869e+00 1.5279824e+00 1.1889904e+00]
[ 6.7048723e-01 -9.7490678e-04 2.5114202e-01]]
Y:
[[ 3.2709925 -0.297907 1.2803618 0.837985 1.7562964]
[ 1.7633215 -0.4651525 0.9211631 1.6511179 1.4302125]]
b:
[1. 1. 1. 1. 1.]
Observe que os dados em sua máquina ou na verdade em cada execução da rede seriam diferentes, pois todas as entradas são criadas aleatoriamente. Agora você definiu com êxito uma rede e a executou em seu computador.
Na lição anterior, você aprendeu a criar uma rede trivial e aprendeu como executá-la e examinar sua saída. O processo de criação de redes complexas é semelhante ao processo descrito acima. Caffe2 fornece um grande conjunto de operadores para a criação de arquiteturas complexas. Recomendamos que você examine a documentação do Caffe2 para obter uma lista de operadores. Depois de estudar o propósito de vários operadores, você estaria em condições de criar redes complexas e treiná-los. Para treinar a rede, Caffe2 oferece váriospredefined computation units- são os operadores. Você precisará selecionar os operadores apropriados para treinar sua rede para o tipo de problema que está tentando resolver.
Depois que uma rede for treinada para sua satisfação, você pode armazená-la em um arquivo de modelo semelhante aos arquivos de modelo pré-treinados usados anteriormente. Esses modelos treinados podem contribuir para o repositório Caffe2 para o benefício de outros usuários. Ou você pode simplesmente colocar o modelo treinado para seu próprio uso de produção privada.
Resumo
Caffe2, que é uma estrutura de aprendizado profundo, permite que você experimente vários tipos de redes neurais para prever seus dados. O site Caffe2 oferece muitos modelos pré-treinados. Você aprendeu a usar um dos modelos pré-treinados para classificar objetos em uma determinada imagem. Você também aprendeu a definir uma arquitetura de rede neural de sua escolha. Essas redes personalizadas podem ser treinadas usando muitos operadores predefinidos no Caffe. Um modelo treinado é armazenado em um arquivo que pode ser levado para um ambiente de produção.