Com o recente progresso das redes neurais em geral e o reconhecimento de imagens em particular, pode parecer que criar um aplicativo baseado em NN para reconhecimento de imagens seja uma operação simples de rotina. Bem, até certo ponto, é verdade: se você pode imaginar uma aplicação de reconhecimento de imagem, provavelmente alguém já fez algo semelhante. Tudo que você precisa fazer é pesquisar no Google e repetir.
No entanto, ainda existem inúmeros pequenos detalhes de que ... eles não são insolúveis, não. Eles simplesmente levam muito do seu tempo, especialmente se você é iniciante. O que seria de ajuda é um projeto passo a passo, feito bem na sua frente, do começo ao fim. Um projeto que não contém "esta parte é óbvia, então vamos ignorá-la". Bem, quase :)
Neste tutorial, examinaremos um identificador de raça de cachorro: criaremos e ensinaremos uma rede neural, depois a portaremos para Java para Android e publicaremos no Google Play.
Para aqueles que desejam ver um resultado final, aqui está o link para o
NeuroDog App no Google Play.
Site com minha robótica:
robotics.snowcron.com .
Site com:
Guia do usuário do NeuroDog .
Aqui está uma captura de tela do programa:

Uma visão geral
Vamos usar a biblioteca do Keras: Google para trabalhar com redes neurais. É de alto nível, o que significa que a curva de aprendizado será acentuada, definitivamente mais rápida do que com outras bibliotecas que eu conheço. Familiarize-se com ele: existem muitos tutoriais online de alta qualidade.
Usaremos CNNs - Redes Neurais Convolucionais. CNNs (e redes mais avançadas baseadas nelas) são de fato padrão no reconhecimento de imagens. Entretanto, ensinar alguém adequadamente pode se tornar uma tarefa formidável: estrutura da rede, parâmetros de aprendizado (todas essas taxas de aprendizado, momentos, L1 e L2 e assim por diante) devem ser cuidadosamente ajustados e, como a tarefa exige muitos recursos computacionais, não pode simplesmente tentar todas as combinações possíveis.
Essa é uma das poucas razões pelas quais, na maioria dos casos, preferimos usar o "transferir conhecimento" para a chamada abordagem "baunilha". O Transfer Knowlege usa uma rede neural treinada por outra pessoa (pense no Google) para alguma outra tarefa. Em seguida, removemos as últimas camadas, adicionamos camadas próprias ... e isso faz milagres.
Pode parecer estranho: pegamos a rede do Google treinada para reconhecer gatos, flores e móveis e agora identifica raça de cães! Para entender como funciona, vamos dar uma olhada no funcionamento das redes neurais profundas, incluindo as usadas para reconhecimento de imagem.
Nós alimentamos uma imagem como entrada. A primeira camada de uma rede analisa a imagem em busca de padrões simples, como "linha horizontal curta", "um arco" e assim por diante. A próxima camada pega esses padrões (e onde eles estão localizados na imagem) e produz padrões de nível superior, como "pele", "canto do olho" etc. No final, temos um quebra-cabeça que pode ser combinado à descrição de um cachorro: pêlo, dois olhos, perna humana na boca e assim por diante.
Agora, tudo isso foi feito por um conjunto de camadas pré-treinadas que recebemos (do Google ou de outro grande jogador). Finalmente, adicionamos nossas próprias camadas e ensinamos a trabalhar com esses padrões para reconhecer raças de cães. Parece lógico.
Para resumir, neste tutorial, criaremos a CNN “vanilla” e algumas redes de “transfer learning” de diferentes tipos. Quanto ao "baunilha": vou usá-lo apenas como um exemplo de como isso pode ser feito, mas não vou ajustá-lo, pois as redes "pré-treinadas" são muito mais fáceis de usar. O Keras vem com poucas redes pré-treinadas, vou escolher algumas configurações e compará-las.
Como queremos que nossa Rede Neural reconheça raças de cães, precisamos "mostrar" amostras de imagens de diferentes raças. Felizmente, há um
grande conjunto de dados criado para uma tarefa semelhante (
original aqui ). Neste artigo, vou usar a
versão do KaggleEntão eu vou portar o "vencedor" para o Android. Portar o Keras NN para o Android é relativamente fácil, e seguiremos todas as etapas necessárias.
Em seguida, publicaremos no Google Play. Como seria de esperar, o Google não cooperará, portanto, serão necessários poucos truques adicionais. Por exemplo, nossa rede neural excede o tamanho permitido do APK do Android: teremos que usar o pacote. Além disso, o Google não mostrará nosso aplicativo nos resultados de pesquisa, a menos que façamos certas coisas mágicas.
No final, teremos um aplicativo Android "comercial" totalmente funcional (entre aspas, pois é gratuito, embora esteja pronto para o mercado) com Android NN.
Ambiente de desenvolvimento
Existem algumas abordagens diferentes para a programação do Keras, dependendo do sistema operacional usado (o Ubuntu é recomendado), a placa de vídeo que você possui (ou não) e assim por diante. Não há nada de errado em configurar o ambiente de desenvolvimento no computador local e instalar todas as bibliotecas necessárias e assim por diante. Exceto ... existe uma maneira mais fácil.
Primeiro, a instalação e configuração de várias ferramentas de desenvolvimento leva tempo e você terá que gastar tempo novamente, quando novas versões estiverem disponíveis. Segundo, o treinamento de redes neurais requer muita energia computacional. Você pode acelerar o seu computador usando a GPU ... no momento em que este artigo foi escrito, uma GPU de topo para cálculos relacionados à NN custa entre 2000 e 7000 dólares. E a configuração também leva tempo.
Então, vamos usar uma abordagem diferente. Veja, o Google permite que as pessoas usem suas GPUs gratuitamente para cálculos relacionados a NN; ele também criou um ambiente totalmente configurado; todos juntos é chamado Google Colab. O serviço concede acesso a um Notebook Jupiter com Python, Keras e várias bibliotecas adicionais já instaladas. Tudo o que você precisa fazer é obter uma conta do Google (obter uma conta do Gmail e você terá acesso a tudo o mais) e é isso.
No momento da redação deste artigo, a Colab pode ser acessada
por este link , mas pode mudar. Basta pesquisar no Google Colab.
Um problema óbvio com a Colab é que é um serviço WEB. Como você acessará SEUS arquivos a partir dele? Salvando redes neurais após a conclusão do treinamento, carregando dados específicos para sua tarefa e assim por diante?
Existem poucas (no momento em que escrevo - três) abordagens diferentes; vamos usar o que acredito ser o melhor: usar o Google Drive.
O Google Drive é um armazenamento em nuvem que funciona praticamente como um disco rígido e pode ser mapeado para o Google Colab (veja o código abaixo). Então você trabalha com ele como faria com um disco rígido local. Por exemplo, se você deseja acessar fotos de cães da Rede Neural criada em Colab, é necessário fazer o upload dessas fotos no Google Drive, só isso.
Criando e treinando o NN
Abaixo, vou percorrer o código Python, um bloco de código do Jupiter Notebook após o outro. Você pode copiar esse código para o seu notebook e executá-lo, pois os blocos podem ser executados independentemente um do outro.
Inicialização
Primeiro de tudo, vamos montar o Google Drive. Apenas duas linhas de código. Esse código precisa ser executado apenas uma vez por sessão da Colab (digamos, uma vez a cada seis horas de trabalho). Se você executá-lo pela segunda vez, ele será ignorado, pois a unidade já está montada.
from google.colab import drive drive.mount('/content/drive/')
A primeira vez que você será solicitado a confirmar a montagem - nada complicado aqui. É assim:
>>> Go to this URL in a browser: ... >>> Enter your authorization code: >>> ·········· >>> Mounted at /content/drive/
Um padrão bastante
inclui seção; provavelmente algumas das inclusões não são necessárias. Além disso, como vou testar diferentes configurações de NN, você terá que comentar / descomentar algumas delas para um tipo específico de NN: por exemplo, para usar o InceptionV3 tipo NN, descomentar InceptionV3 e comentar, por exemplo, ResNet50. Ou não: você pode manter esses itens descomentados, ele usará mais memória, mas é tudo.
import datetime as dt import pandas as pd import seaborn as sns import matplotlib.pyplot as plt from tqdm import tqdm import cv2 import numpy as np import os import sys import random import warnings from sklearn.model_selection import train_test_split import keras from keras import backend as K from keras import regularizers from keras.models import Sequential from keras.models import Model from keras.layers import Dense, Dropout, Activation from keras.layers import Flatten, Conv2D from keras.layers import MaxPooling2D from keras.layers import BatchNormalization, Input from keras.layers import Dropout, GlobalAveragePooling2D from keras.callbacks import Callback, EarlyStopping from keras.callbacks import ReduceLROnPlateau from keras.callbacks import ModelCheckpoint import shutil from keras.applications.vgg16 import preprocess_input from keras.preprocessing import image from keras.preprocessing.image import ImageDataGenerator from keras.models import load_model from keras.applications.resnet50 import ResNet50 from keras.applications.resnet50 import preprocess_input from keras.applications.resnet50 import decode_predictions from keras.applications import inception_v3 from keras.applications.inception_v3 import InceptionV3 from keras.applications.inception_v3 import preprocess_input as inception_v3_preprocessor from keras.applications.mobilenetv2 import MobileNetV2 from keras.applications.nasnet import NASNetMobile
No Google Drive, vamos criar uma pasta para nossos arquivos. A segunda linha exibe seu conteúdo:
working_path = "/content/drive/My Drive/DeepDogBreed/data/" !ls "/content/drive/My Drive/DeepDogBreed/data" >>> all_images labels.csv models test train valid
Como você pode ver, fotos de cães (aquelas copiadas do conjunto de dados de Stanford (veja acima) para o Google Drive, são armazenadas inicialmente na pasta
all_images . Mais tarde, vamos copiá-las para
treinar, validar e
testar pastas. Vamos salvar modelos treinados na pasta
models . Quanto ao arquivo labels.csv, ele faz parte de um conjunto de dados, mapeia os arquivos de imagem para raças de cães.
Existem muitos testes que você pode executar para descobrir o que você tem; vamos executar apenas um:
Ok, a GPU está conectada. Caso contrário, encontre-o nas configurações do Jupiter Notebook e ligue-o.
Agora precisamos declarar algumas constantes que vamos usar, como o tamanho de uma imagem que a Rede Neural deve esperar e assim por diante. Observe que usamos uma imagem de 256x256, pois ela é grande o suficiente de um lado e cabe na memória do outro. No entanto, alguns tipos de redes neurais que estamos prestes a usar esperam uma imagem de 224x224. Para lidar com isso, quando necessário, comente o tamanho da imagem antiga e remova o comentário de uma nova.
A mesma abordagem (comentar um - descomentar o outro) se aplica aos nomes dos modelos que salvamos, simplesmente porque não queremos sobrescrever o resultado de um teste anterior quando tentamos uma nova configuração.
warnings.filterwarnings("ignore") os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' np.random.seed(7) start = dt.datetime.now() BATCH_SIZE = 16 EPOCHS = 15 TESTING_SPLIT=0.3
Carregando dados
Primeiro, vamos carregar o arquivo
labels.csv e dividir seu conteúdo em partes de treinamento e validação. Observe que ainda não há uma parte de teste, como vou trapacear um pouco, a fim de obter mais dados para o treinamento.
labels = pd.read_csv(working_path + 'labels.csv') print(labels.head()) train_ids, valid_ids = train_test_split(labels, test_size = TESTING_SPLIT) print(len(train_ids), 'train ids', len(valid_ids), 'validation ids') print('Total', len(labels), 'testing images') >>> id breed >>> 0 000bec180eb18c7604dcecc8fe0dba07 boston_bull >>> 1 001513dfcb2ffafc82cccf4d8bbaba97 dingo >>> 2 001cdf01b096e06d78e9e5112d419397 pekinese >>> 3 00214f311d5d2247d5dfe4fe24b2303d bluetick >>> 4 0021f9ceb3235effd7fcde7f7538ed62 golden_retriever >>> 7155 train ids 3067 validation ids >>> Total 10222 testing images
A seguir, precisamos copiar os arquivos de imagem reais para pastas de treinamento / validação / teste, de acordo com a matriz de nomes de arquivos que passamos. A função a seguir copia arquivos com nomes fornecidos para uma pasta especificada.
def copyFileSet(strDirFrom, strDirTo, arrFileNames): arrBreeds = np.asarray(arrFileNames['breed']) arrFileNames = np.asarray(arrFileNames['id']) if not os.path.exists(strDirTo): os.makedirs(strDirTo) for i in tqdm(range(len(arrFileNames))): strFileNameFrom = strDirFrom + arrFileNames[i] + ".jpg" strFileNameTo = strDirTo + arrBreeds[i] + "/" + arrFileNames[i] + ".jpg" if not os.path.exists(strDirTo + arrBreeds[i] + "/"): os.makedirs(strDirTo + arrBreeds[i] + "/")
Como você pode ver, copiamos apenas um arquivo para cada raça de cães em uma pasta de
teste . À medida que copiamos os arquivos, também criamos subpastas - uma subpasta por cada raça de cães. As imagens de cada raça em particular são copiadas em sua subpasta.
O motivo é que o Keras pode trabalhar com uma estrutura de diretórios organizada dessa maneira, carregando os arquivos de imagem conforme necessário, economizando memória. Seria uma péssima idéia carregar todas as 15.000 imagens na memória de uma só vez.
Chamar essa função toda vez que executamos nosso código seria um exagero: as imagens já foram copiadas, por que devemos copiá-las novamente. Portanto, comente após o primeiro uso:
Além disso, precisamos da lista de raças de cães:
breeds = np.unique(labels['breed']) map_characters = {}
Processando imagens
Vamos usar o recurso do Keras chamado ImageDataGenerators. ImageDataGenerator pode processar uma imagem, redimensioná-la, girar e assim por diante. Ele também pode ter uma função de
processamento que faz manipulações de imagem personalizadas.
def preprocess(img): img = cv2.resize(img, (IMAGE_SIZE, IMAGE_SIZE), interpolation = cv2.INTER_AREA)
Observe a seguinte linha:
Podemos realizar a normalização (ajustando o intervalo de 0-255 do canal de imagem a 0-1) no próprio ImageDataGenerator. Então, por que precisaríamos de pré-processador? Como exemplo, forneci a função de
desfoque (comentada): essa é uma manipulação de imagem personalizada. Você pode usar qualquer coisa, desde nitidez a HDR aqui.
Vamos usar dois ImageDataGenerators diferentes, um para treinamento e outro para validação. A diferença é que precisamos de rotações e zoom para treinamento, para tornar as imagens mais "diversas", mas não precisamos delas para validação (não nesta tarefa).
train_datagen = ImageDataGenerator( preprocessing_function=preprocess,
Criando rede neural
Como foi mencionado acima, vamos criar alguns tipos de redes neurais. Cada vez que usamos uma função diferente, diferentes incluem biblioteca e, em alguns casos, diferentes tamanhos de imagem. Portanto, para alternar de um tipo de rede neural para outro, é necessário comentar / descomentar o código correspondente.
Primeiro, vamos criar a CNN "vanilla". O desempenho é fraco, pois não o otimizei, mas pelo menos fornece uma estrutura que você pode usar para criar sua própria rede (geralmente, é uma má idéia, pois existem redes pré-treinadas disponíveis).
def createModelVanilla(): model = Sequential()
Quando criamos a Rede Neural usando o
aprendizado por transferência , o procedimento muda:
def createModelMobileNetV2():
A criação de outros tipos de NNs pré-treinados é muito semelhante:
def createModelResNet50(): base_model = ResNet50(weights='imagenet', include_top=False, pooling='avg', input_shape=(IMAGE_SIZE, IMAGE_SIZE, 3)) x = base_model.output x = Dense(512)(x) x = Activation('relu')(x) x = Dropout(0.5)(x) predictions = Dense(NUM_CLASSES, activation='softmax')(x) model = Model(inputs=base_model.input, outputs=predictions)
Atenção: o vencedor! Este NN demonstrou os melhores resultados:
def createModelInceptionV3():
Mais um:
def createModelNASNetMobile():
Diferentes tipos de NNs são usados em diferentes situações. Além dos problemas de precisão, os dimensionadores (o NN móvel é 5 vezes menor que o do início) e a velocidade (se precisarmos de análise em tempo real de um fluxo de vídeo, talvez seja necessário sacrificar a precisão).
Treinando a rede neural
Antes de tudo, estamos
experimentando , portanto, precisamos poder excluir as NNs salvas anteriormente, mas que não precisam mais. A seguinte função exclui NN se o arquivo existir:
A maneira como criamos e excluímos NNs é simples. Primeiro, excluímos. Agora, se você não quiser chamar
delete , lembre-se de que o Jupiter Notebook tem uma função de "seleção de execução" - selecione apenas o que você precisa e execute-o.
Em seguida, criamos o NN se o arquivo não existir ou o
carregamos se o arquivo existir: é claro, não podemos chamar "delete" e esperar que o NN exista; portanto, para usar a rede salva anteriormente, não chame
delete .
Em outras palavras, podemos criar um novo NN ou usar um já existente, dependendo do que estamos experimentando no momento. Um cenário simples: treinamos o NN e partimos para férias. O Google efetuou o logout, portanto, precisamos recarregar o NN: comente a parte "delete" e remova o comentário da parte "load".
deleteSavedNet(working_path + strModelFileName)
Os pontos de verificação são muito importantes ao ensinar as NNs. Você pode criar uma matriz de funções a serem chamadas no final de cada época de treinamento; por exemplo, você pode salvar o NN se apresentar resultados melhores que o último salvo.
checkpoint = ModelCheckpoint(working_path + strModelFileName, monitor='val_acc', verbose=1, save_best_only=True, mode='auto', save_weights_only=False) callbacks_list = [ checkpoint ]
Por fim, ensinaremos nosso NN usando o conjunto de treinamento:
Aqui estão os gráficos de precisão e perda para o vencedor NN:


Como você pode ver, a rede aprende bem.
Testando a rede neural
Após a fase de treinamento estar concluída, precisamos realizar testes; Para isso, o NN recebe imagens que nunca viu. Lembre-se, deixamos de lado uma imagem para cada espécie de cão.
Exportando NN para Java
Primeiro, precisamos carregar o NN. O motivo é que exportar é um bloco de código separado; portanto, é provável que o executemos separadamente, sem treinar novamente o NN. Ao usar meu código, você realmente não se importa, mas se você desenvolvesse seu próprio desenvolvimento, tentaria evitar treinar novamente
a mesma rede uma vez após a outra.
Pelo mesmo motivo - este é um bloco de código separado - estamos usando inclusões adicionais aqui. Nada nos impede de subir, é claro:
from keras.models import Model from keras.models import load_model from keras.layers import * import os import sys import tensorflow as tf
Um pequeno teste, apenas para garantir que carregamos tudo certo:
img = image.load_img(working_path + "test/affenpinscher.jpg")

A seguir, precisamos obter nomes das camadas de entrada e saída da nossa rede (a menos que tenhamos usado o parâmetro "name" ao criar a rede, o que não fizemos).
model.summary() >>> Layer (type) >>> ====================== >>> input_7 (InputLayer) >>> ______________________ >>> conv2d_283 (Conv2D) >>> ______________________ >>> ... >>> dense_14 (Dense) >>> ====================== >>> Total params: 22,913,432 >>> Trainable params: 1,110,648 >>> Non-trainable params: 21,802,784
Vamos usar os nomes da camada de entrada e saída posteriormente, ao importar o NN no aplicativo Java Android.
Também podemos usar o seguinte código para obter essas informações:
def print_graph_nodes(filename): g = tf.GraphDef() g.ParseFromString(open(filename, 'rb').read()) print() print(filename) print("=======================INPUT===================") print([n for n in g.node if n.name.find('input') != -1]) print("=======================OUTPUT==================") print([n for n in g.node if n.name.find('output') != -1]) print("===================KERAS_LEARNING==============") print([n for n in g.node if n.name.find('keras_learning_phase') != -1]) print("===============================================") print()
No entanto, a primeira abordagem é preferida.
A função a seguir exporta o Keras Neural Network para o formato
pb , que usaremos no Android.
def keras_to_tensorflow(keras_model, output_dir, model_name,out_prefix="output_", log_tensorboard=True): if os.path.exists(output_dir) == False: os.mkdir(output_dir) out_nodes = [] for i in range(len(keras_model.outputs)): out_nodes.append(out_prefix + str(i + 1)) tf.identity(keras_model.output[i], out_prefix + str(i + 1)) sess = K.get_session() from tensorflow.python.framework import graph_util from tensorflow.python.framework graph_io init_graph = sess.graph.as_graph_def() main_graph = graph_util.convert_variables_to_constants( sess, init_graph, out_nodes) graph_io.write_graph(main_graph, output_dir, name=model_name, as_text=False) if log_tensorboard: from tensorflow.python.tools import import_pb_to_tensorboard import_pb_to_tensorboard.import_to_tensorboard( os.path.join(output_dir, model_name), output_dir)
Vamos usar essas funções para criar um NN exportes:
model = load_model(working_path + strModelFileName) keras_to_tensorflow(model, output_dir=working_path + strModelFileName, model_name=working_path + "models/dogs.pb") print_graph_nodes(working_path + "models/dogs.pb")
A última linha imprime a estrutura do nosso NN.
Criando um aplicativo Android com NN
Exportando NN para o aplicativo Android. está bem formalizado e não deve apresentar dificuldades. Há, como sempre, mais de uma maneira de fazê-lo; vamos usar os mais populares (pelo menos no momento).
Primeiro de tudo, use o Android Studio para criar um novo projeto. Vamos cortar um pouco os cantos, para que ele contenha apenas uma única atividade.

Como você pode ver, adicionamos a pasta "assets" e copiamos nosso arquivo de rede neural lá.
Arquivo Gradle
Há algumas mudanças que precisamos fazer para classificar os arquivos. Primeiro, precisamos importar a biblioteca
tensorflow-android . É usado para manipular o Tensorflow (e Keras, de acordo) do Java:

Como um detalhe "difícil de encontrar" adicional, observe as versões:
versionCode e
versionName . Enquanto trabalha no seu aplicativo, você precisa fazer o upload de novas versões para o Google Play. Sem atualizar versões (algo como 1 -> 2 -> 3 ...), você não poderá fazer isso.
Manifesto
Primeiro de tudo, nosso aplicativo. vai ser "pesado" - uma rede neural de 100 Mb cabe facilmente na memória dos telefones modernos, mas abrir uma instância separada sempre que o usuário "compartilha" uma imagem do Facebook definitivamente não é uma boa idéia.
Portanto, garantiremos que haja apenas uma instância do nosso aplicativo:
<activity android:name=".MainActivity" android:launchMode="singleTask">
Ao adicionar
android: launchMode = "singleTask" a MainActivity, pedimos ao Android para abrir um aplicativo existente, em vez de iniciar outra instância.
Então nos certificamos de nosso aplicativo. aparece em uma lista de aplicativos capazes de lidar
com imagens
compartilhadas :
<intent-filter> <action android:name="android.intent.action.SEND" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="image/*" /> </intent-filter>
Por fim, precisamos solicitar recursos e permissões, para que o aplicativo possa acessar a funcionalidade do sistema necessária:
<uses-feature android:name="android.hardware.camera" android:required="true" /> <uses-permission android:name= "android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" tools:node="remove" />
Se você está familiarizado com a programação do Android, esta parte não deve gerar dúvidas.
Layout do aplicativo.
Vamos criar dois layouts, um para o modo retrato e outro para o modo paisagem. Aqui está o
layout Retrato .
O que temos aqui: uma visão ampla para mostrar uma imagem, uma lista bastante irritante de comerciais (mostrada quando o botão "bone" é pressionado), botões "Help", botões para carregar uma imagem do File / Gallery e da Camera e finalmente, um botão (processo inicialmente oculto) "Process".

Na própria atividade, implementaremos alguma lógica que mostra / oculta e ativa / desativa os botões, dependendo do estado do aplicativo.
Atividade principal
A atividade estende uma atividade padrão do Android:
public class MainActivity extends Activity
Vamos dar uma olhada no código responsável pelas operações NN.
Primeiro de tudo, o NN aceita um bitmap. Originalmente, é um bitmap grande do arquivo ou da câmera (m_bitmap), depois o transformamos em um bitmap padrão de 256x256 (m_bitmapForNn). Também mantemos as dimensões da imagem (256) em uma constante:
static Bitmap m_bitmap = null; static Bitmap m_bitmapForNn = null; private int m_nImageSize = 256;
Precisamos dizer ao NN quais são os nomes para as camadas de entrada e saída; se você consultar a lista acima, verá que os nomes são (no nosso caso! o seu caso pode ser diferente!):
private String INPUT_NAME = "input_7_1"; private String OUTPUT_NAME = "output_1";
Em seguida, declaramos a variável para conter o objeto TensofFlow. Além disso, armazenamos o caminho para o arquivo NN nos ativos:
private TensorFlowInferenceInterface tf;
string privada MODEL_PATH =
"arquivo: ///android_asset/dogs.pb";
Raças de cães, para apresentar ao usuário uma informação significativa, em vez de índices na matriz:
private String[] m_arrBreedsArray;
Inicialmente, carregamos um bitmap. No entanto, o próprio NN espera uma matriz de valores RGB, e sua saída é uma matriz de probabilidades da imagem apresentada ser uma raça específica. Portanto, precisamos adicionar mais duas matrizes (observe que 120 é o número de raças em nosso conjunto de dados de treinamento):
private float[] m_arrPrediction = new float[120]; private float[] m_arrInput = null;
Carregue a biblioteca de inferência tensorflow
static { System.loadLibrary("tensorflow_inference"); }
Como a operação da NN é longa, precisamos executá-la em um thread separado, caso contrário, há uma boa chance de acessar o aplicativo "system". aviso de não responder ", para não mencionar estragar a experiência do usuário.
class PredictionTask extends AsyncTask<Void, Void, Void> { @Override protected void onPreExecute() { super.onPreExecute(); }
No onCreate () do MainActivity, precisamos adicionar o onClickListener para o botão "Process": m_btn_process.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { processImage(); } });
O que processImage () faz é simplesmente chamar o thread que vimos acima: private void processImage() { try { enableControls(false);
Detalhes Adicionais
Não vamos discutir o código relacionado à interface do usuário neste tutorial, pois é trivial e definitivamente não faz parte da tarefa "portando NN". No entanto, há poucas coisas que devem ser esclarecidas.Quando prevemos nosso aplicativo. ao iniciar várias instâncias, evitamos, ao mesmo tempo, um fluxo normal de controle: se você compartilha uma imagem do Facebook e depois outra, o aplicativo não será reiniciado. Isso significa que a maneira "tradicional" de manipular dados compartilhados, capturando-os no onCreate, não é suficiente no nosso caso, pois o onCreate não é chamado em um cenário que acabamos de criar.Aqui está uma maneira de lidar com a situação:1. No onCreate de MainActivity, chame a função onSharedIntent: protected void onCreate( Bundle savedInstanceState) { super.onCreate(savedInstanceState); .... onSharedIntent(); ....
Além disso, adicione um manipulador para onNewIntent: @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); onSharedIntent(); }
A própria função onSharedIntent: private void onSharedIntent() { Intent receivedIntent = getIntent(); String receivedAction = receivedIntent.getAction(); String receivedType = receivedIntent.getType(); if (receivedAction.equals(Intent.ACTION_SEND)) {
Agora, lidamos com a imagem compartilhada do onCreate (se o aplicativo acabou de ser iniciado) ou do onNewIntent se uma instância foi encontrada na memória.Boa sorte Se você gosta deste artigo, "gostei" dele nas redes sociais, também existem botões sociais no próprio site .