Con el progreso reciente en las redes neuronales en general y el reconocimiento de imágenes en particular, podría parecer que crear una aplicación basada en NN para el reconocimiento de imágenes es una operación de rutina simple. Bueno, hasta cierto punto es cierto: si puedes imaginar una aplicación de reconocimiento de imágenes, entonces es muy probable que alguien ya haya hecho algo similar. Todo lo que necesitas hacer es buscarlo en Google y repetir.
Sin embargo, todavía hay innumerables pequeños detalles que ... no son insolubles, no. Simplemente toman demasiado tiempo, especialmente si eres un principiante. Lo que sería de ayuda es un proyecto paso a paso, hecho frente a usted, de principio a fin. Un proyecto que no contiene "esta parte es obvia, así que saltemos" las declaraciones. Bueno, casi :)
En este tutorial veremos un identificador de raza de perro: crearemos y enseñaremos una red neuronal, luego la trasladaremos a Java para Android y la publicaremos en Google Play.
Para aquellos de ustedes que desean ver un resultado final, aquí está el enlace a la
aplicación NeuroDog en Google Play.
Sitio web con mi robótica:
robotics.snowcron.com .
Sitio web con:
Guía del usuario de NeuroDog .
Aquí hay una captura de pantalla del programa:

Una visión general
Vamos a utilizar Keras: la biblioteca de Google para trabajar con redes neuronales. Es de alto nivel, lo que significa que la curva de aprendizaje será empinada, definitivamente más rápida que con otras bibliotecas que conozco. Familiarícese con él: hay muchos tutoriales de alta calidad en línea.
Utilizaremos CNNs - Redes neuronales convolucionales. Las CNN (y las redes más avanzadas basadas en ellas) son el estándar de facto en el reconocimiento de imágenes. Sin embargo, enseñar uno correctamente puede convertirse en una tarea formidable: la estructura de la red, los parámetros de aprendizaje (todas esas tasas de aprendizaje, ímpetu, L1 y L2, etc.) deben ajustarse cuidadosamente, y como la tarea requiere muchos recursos computacionales, nosotros No puede simplemente probar todas las combinaciones posibles.
Esta es una de las pocas razones por las cuales en la mayoría de los casos preferimos usar el "conocimiento de transferencia" al llamado enfoque "vainilla". Transfer Knowlege utiliza una red neuronal entrenada por otra persona (piense en Google) para alguna otra tarea. Luego eliminamos las últimas capas, agregamos capas propias ... y funciona milagros.
Puede sonar extraño: tomamos la red de Google entrenada para reconocer gatos, flores y muebles, ¡y ahora identifica la raza de perros! Para comprender cómo funciona, echemos un vistazo a la forma en que funcionan las redes neuronales profundas, incluidas las utilizadas para el reconocimiento de imágenes.
Le damos una imagen como entrada. La primera capa de una red analiza la imagen en busca de patrones simples, como "línea horizontal corta", "un arco", etc. La siguiente capa toma estos patrones (y dónde están ubicados en la imagen) y produce patrones de nivel superior, como "pelaje", "esquina de un ojo", etc. Al final, tenemos un rompecabezas que se puede combinar en una descripción de un perro: pelaje, dos ojos, pierna humana en la boca, etc.
Ahora, todo esto fue hecho por un conjunto de capas pre-entrenadas que obtuvimos (de Google o de algún otro gran jugador). Finalmente, agregamos nuestras propias capas encima y le enseñamos a trabajar con esos patrones para reconocer las razas de perros. Suena lógico
Para resumir, en este tutorial vamos a crear CNN "vainilla" y un par de redes de "aprendizaje de transferencia" de diferentes tipos. En cuanto a "vainilla": solo lo usaré como un ejemplo de cómo se puede hacer, pero no voy a ajustarlo, ya que las redes "pre-entrenadas" son mucho más fáciles de usar. Keras viene con pocas redes pre-entrenadas, elegiré un par de configuraciones y las compararé.
Como queremos que nuestra red neuronal pueda reconocer las razas de perros, necesitamos "mostrar" imágenes de muestra de diferentes razas. Afortunadamente, hay un
gran conjunto de datos creado para una tarea similar (
original aquí ). En este artículo, voy a usar la
versión de KaggleLuego voy a portar el "ganador" a Android. Portar Keras NN a Android es relativamente fácil, y vamos a recorrer todos los pasos necesarios.
Luego lo publicaremos en Google Play. Como era de esperar, Google no va a cooperar, por lo que se requerirán pocos trucos adicionales. Por ejemplo, nuestra red neuronal supera el tamaño permitido de Android APK: tendremos que usar el paquete. Además, Google no mostrará nuestra aplicación en los resultados de búsqueda, a menos que hagamos ciertas cosas mágicas.
Al final, tendremos una aplicación Android "NN" totalmente comercial (entre comillas, ya que es gratuita pero lista para el mercado).
Entorno de desarrollo
Existen pocos enfoques diferentes para la programación de Keras, según el sistema operativo que use (se recomienda Ubuntu), la tarjeta de video que tenga (o no), etc. No hay nada de malo en configurar el entorno de desarrollo en su computadora local e instalar todas las bibliotecas necesarias, etc. Excepto ... hay una manera más fácil.
Primero, la instalación y configuración de múltiples herramientas de desarrollo lleva tiempo y tendrá que pasar tiempo nuevamente cuando las nuevas versiones estén disponibles. En segundo lugar, entrenar redes neuronales requiere mucha potencia de cálculo. Puede acelerar su computadora utilizando GPU ... en el momento de escribir este artículo, una GPU superior para los cálculos relacionados con NN cuesta 2000 - 7000 dólares. Y configurarlo también lleva tiempo.
Entonces vamos a utilizar un enfoque diferente. Vea, Google permite a las personas usar sus GPU de forma gratuita para los cálculos relacionados con NN, también ha creado un entorno totalmente configurado; todos juntos se llama Google Colab. El servicio le otorga acceso a un Jupiter Notebook con Python, Keras y toneladas de bibliotecas adicionales ya instaladas. Todo lo que necesita hacer es obtener una cuenta de Google (obtenga una cuenta de Gmail, y tendrá acceso a todo lo demás) y eso es todo.
En el momento de escribir este artículo, se puede acceder a Colab
mediante este enlace , pero puede cambiar. Simplemente busque en Google "Google Colab".
Un problema obvio con Colab es que es un servicio WEB. ¿Cómo vas a acceder a TUS archivos desde allí? ¿Guardar redes neuronales después de completar el entrenamiento, cargar datos específicos para su tarea, etc.?
Hay pocos (en el momento de escribir esto: tres) enfoques diferentes; vamos a usar lo que creo que es lo mejor: usar Google Drive.
Google Drive es un almacenamiento en la nube que funciona más o menos como un disco duro, y se puede asignar a Google Colab (consulte el código a continuación). Luego trabajas con él como lo harías con un disco duro local. Entonces, por ejemplo, si desea acceder a fotos de perros desde la Red neuronal que creó en Colab, debe cargar esas fotos en su Google Drive, eso es todo.
Creando y entrenando el NN
A continuación, voy a recorrer el código de Python, un bloque de código de Jupiter Notebook tras otro. Puede copiar ese código en su computadora portátil y ejecutarlo, ya que los bloques se pueden ejecutar independientemente uno del otro.
Inicialización
En primer lugar, montemos Google Drive. Solo dos líneas de código. Ese código debe ejecutarse solo una vez por sesión de Colab (por ejemplo, una vez cada seis horas de trabajo). Si lo ejecuta la segunda vez, se omitirá ya que la unidad ya está montada.
from google.colab import drive drive.mount('/content/drive/')
La primera vez se le pedirá que confirme el montaje, nada complicado aquí. Se ve así:
>>> Go to this URL in a browser: ... >>> Enter your authorization code: >>> ·········· >>> Mounted at /content/drive/
Una bonita sección estándar
incluida ; Lo más probable es que algunas de las inclusiones no sean necesarias. Además, como voy a probar diferentes configuraciones de NN, tendrá que comentar / descomentar algunas de ellas para un tipo particular de NN: por ejemplo, para usar InceptionV3 tipo NN, descomentar InceptionV3 y comentar, por ejemplo, ResNet50. O no: puede mantener esos comentarios sin comentar, usará más memoria, pero eso es todo.
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
En Google Drive, vamos a crear una carpeta para nuestros archivos. La segunda línea muestra su contenido:
working_path = "/content/drive/My Drive/DeepDogBreed/data/" !ls "/content/drive/My Drive/DeepDogBreed/data" >>> all_images labels.csv models test train valid
Como puede ver, las fotos de perros (las copiadas del conjunto de datos de Stanford (ver arriba) a Google Drive) se almacenan inicialmente en la carpeta
all_images . Más adelante las
copiaremos a las carpetas de
entrenamiento, validez y
prueba . Vamos a guardar modelos entrenados en la carpeta de
modelos . En cuanto al archivo labels.csv, es parte de un conjunto de datos, asigna archivos de imagen a razas de perros.
Hay muchas pruebas que puede ejecutar para descubrir qué es lo que tiene, ejecutemos solo una:
Ok, la GPU está conectada. De lo contrario, búsquelo en la configuración de Jupiter Notebook y actívelo.
Ahora necesitamos declarar algunas constantes que vamos a utilizar, como el tamaño de una imagen que la Red Neural debería esperar, etc. Tenga en cuenta que usamos una imagen de 256x256, ya que es lo suficientemente grande en un lado y cabe en la memoria en el otro. Sin embargo, algunos tipos de redes neuronales que estamos a punto de usar esperan una imagen de 224x224. Para manejar esto, cuando sea necesario, comente el tamaño de la imagen anterior y descomente una nueva.
El mismo enfoque (comentario uno - descomentar el otro) se aplica a los nombres de los modelos que guardamos, simplemente porque no queremos sobrescribir el resultado de una prueba anterior cuando intentamos una nueva configuración.
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
Cargando datos
Primero,
carguemos el archivo
labels.csv y dividamos su contenido en partes de capacitación y validación. Tenga en cuenta que todavía no hay una parte de prueba, ya que voy a hacer un poco de trampa, para obtener más datos para el entrenamiento.
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
Lo siguiente, tenemos que copiar los archivos de imagen reales a las carpetas de entrenamiento / validación / prueba, de acuerdo con la matriz de nombres de archivos que pasamos. La siguiente función copia archivos con nombres proporcionados a una carpeta 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 puede ver, solo copiamos un archivo para cada raza de perros a una carpeta de
prueba . A medida que copiamos archivos, también creamos subcarpetas, una subcarpeta por cada raza de perros. Las imágenes para cada raza en particular se copian en su subcarpeta.
La razón es que Keras puede trabajar con una estructura de directorios organizada de esta manera, cargando archivos de imagen según sea necesario, ahorrando memoria. Sería una muy mala idea cargar todas las 15,000 imágenes en la memoria a la vez.
Llamar a esta función cada vez que ejecutamos nuestro código sería una exageración: las imágenes ya están copiadas, ¿por qué deberíamos copiarlas nuevamente? Entonces, coméntalo después del primer uso:
Además, necesitamos una lista de razas de perros:
breeds = np.unique(labels['breed']) map_characters = {}
Procesando imágenes
Vamos a utilizar la característica de Keras llamada ImageDataGenerators. ImageDataGenerator puede procesar una imagen, cambiar su tamaño, rotar, etc. También puede tomar una función de
procesamiento que realiza manipulaciones de imágenes personalizadas.
def preprocess(img): img = cv2.resize(img, (IMAGE_SIZE, IMAGE_SIZE), interpolation = cv2.INTER_AREA)
Tenga en cuenta la siguiente línea:
Podemos realizar la normalización (ajustando el rango de 0-255 del canal de imagen a 0-1) en ImageDataGenerator. Entonces, ¿por qué necesitaríamos un preprocesador? Como ejemplo, he proporcionado la función de
desenfoque (comentado): que es una manipulación de imagen personalizada. Puede usar cualquier cosa, desde afilar hasta HDR aquí.
Vamos a utilizar dos ImageDataGenerators diferentes, uno para capacitación y otro para validación. La diferencia es que necesitamos rotaciones y zoom para el entrenamiento, para que las imágenes sean más "diversas", pero no lo necesitamos para la validación (no en esta tarea).
train_datagen = ImageDataGenerator( preprocessing_function=preprocess,
Crear red neuronal
Como se mencionó anteriormente, vamos a crear algunos tipos de redes neuronales. Cada vez que usamos una función diferente, se incluye una biblioteca diferente y, en algunos casos, diferentes tamaños de imagen. Por lo tanto, para cambiar de un tipo de red neuronal a otra, debe comentar / descomentar el código correspondiente.
Primero, creemos la CNN "vainilla". Funciona mal, ya que no lo he optimizado, pero al menos proporciona un marco que podría usar para crear una red propia (en general, es una mala idea, ya que hay redes previamente capacitadas disponibles).
def createModelVanilla(): model = Sequential()
Cuando creamos una red neuronal usando el
aprendizaje de transferencia , el procedimiento cambia:
def createModelMobileNetV2():
Crear otros tipos de NN pre-entrenados es muy similar:
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)
A la atención de: el ganador! Este NN demostró los mejores resultados:
def createModelInceptionV3():
Uno mas:
def createModelNASNetMobile():
Se utilizan diferentes tipos de NN en diferentes situaciones. Además de los problemas de precisión, el tamaño importa (el NN móvil es 5 veces más pequeño que el inicio uno) y la velocidad (si necesitamos un análisis en tiempo real de una transmisión de video, podríamos tener que sacrificar la precisión).
Entrenando la red neuronal
En primer lugar, estamos
experimentando , por lo que debemos poder eliminar los NN que hemos guardado anteriormente, pero que ya no necesitamos. La siguiente función elimina NN si el archivo existe:
La forma en que creamos y eliminamos NN es sencilla. Primero, lo eliminamos. Ahora, si no desea llamar a
eliminar , solo recuerde que Jupiter Notebook tiene una función de "ejecutar selección": seleccione solo lo que necesita y ejecútelo.
Luego creamos el NN si su archivo no existe o lo
cargamos si el archivo existe: por supuesto, no podemos llamar "eliminar" y luego esperar que exista el NN, por lo que para usar la red previamente guardada, no llame a
eliminar .
En otras palabras, podemos crear un nuevo NN o usar uno existente, dependiendo de lo que estemos experimentando en este momento. Un escenario simple: hemos entrenado a la NN, luego nos fuimos de vacaciones. Google nos desconectó, por lo que debemos volver a cargar el NN: comentar la parte "eliminar" y descomentar la parte "cargar".
deleteSavedNet(working_path + strModelFileName)
Los puntos de control son muy importantes cuando se enseñan las NN. Puede crear una serie de funciones que se llamarán al final de cada época de entrenamiento, por ejemplo, puede guardar el NN si muestra mejores resultados que el último guardado.
checkpoint = ModelCheckpoint(working_path + strModelFileName, monitor='val_acc', verbose=1, save_best_only=True, mode='auto', save_weights_only=False) callbacks_list = [ checkpoint ]
Finalmente, enseñaremos nuestro NN usando el conjunto de entrenamiento:
Aquí hay tablas de precisión y pérdida para el ganador NN:


Como puede ver, la red aprende bien.
Probar la red neuronal
Una vez completada la fase de capacitación, debemos realizar pruebas; para hacerlo, NN se presenta con imágenes que nunca vio. Como recordará, hemos reservado una imagen para cada especie de perro.
Exportando NN a Java
Primero, necesitamos cargar el NN. La razón es que exportar es un bloque de código separado, por lo que es probable que lo ejecutemos por separado, sin volver a entrenar el NN. Cuando usa mi código, realmente no le importa, pero si hiciera su propio desarrollo, trataría de evitar volver a entrenar
la misma red una y otra vez.
Por la misma razón, esto es de alguna manera un bloque de código separado, estamos usando inclusiones adicionales aquí. Nada nos impide subirlos, por supuesto:
from keras.models import Model from keras.models import load_model from keras.layers import * import os import sys import tensorflow as tf
Un poco de prueba, solo para asegurarnos de que hemos cargado todo bien:
img = image.load_img(working_path + "test/affenpinscher.jpg")

Lo siguiente, necesitamos obtener nombres de las capas de entrada y salida de nuestra red (a menos que usemos el parámetro "nombre" al crear la red, lo cual no hicimos).
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
Usaremos nombres de la capa de entrada y salida más adelante, al importar el NN en la aplicación Java de Android.
También podemos usar el siguiente código para obtener esta información:
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()
Sin embargo, se prefiere el primer enfoque.
La siguiente función exporta Keras Neural Network a formato
pb , una que vamos a usar en 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)
Usemos estas funciones para crear un NN exportado:
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")
La última línea imprime la estructura de nuestro NN.
Crear una aplicación de Android con NN
Exportando NN a la aplicación de Android. está bien formalizado y no debe presentar ninguna dificultad. Hay, como siempre, más de una forma de hacerlo; vamos a usar los más populares (al menos por el momento).
En primer lugar, use Android Studio para crear un nuevo proyecto. Vamos a cortar un poco las esquinas, por lo que solo contendrá una sola actividad.

Como puede ver, hemos agregado la carpeta "activos" y copiamos nuestro archivo de red neuronal allí.
Archivo Gradle
Hay un par de cambios que debemos hacer para gradle file. En primer lugar, tenemos que importar la biblioteca
tensorflow-android . Se utiliza para manejar Tensorflow (y Keras, en consecuencia) desde Java:

Como detalle adicional "difícil de encontrar", tenga en cuenta las versiones:
versionCode y
versionName . Mientras trabaja en su aplicación, deberá cargar nuevas versiones a Google Play. Sin actualizar las versiones (algo así como 1 -> 2 -> 3 ...) no podrá hacerlo.
Manifiesto
En primer lugar, nuestra aplicación. va a ser "pesado": una red neuronal de 100 Mb cabe fácilmente en la memoria de los teléfonos modernos, pero abrir una instancia por separado cada vez que el usuario "comparte" una imagen de Facebook definitivamente no es una buena idea.
Así que nos aseguraremos de que solo haya una instancia de nuestra aplicación:
<activity android:name=".MainActivity" android:launchMode="singleTask">
Al agregar
android: launchMode = "singleTask" a MainActivity, le decimos a Android que abra una aplicación existente, en lugar de lanzar otra instancia.
Luego nos aseguramos de nuestra aplicación. aparece en una lista de aplicaciones capaces de manejar imágenes
compartidas :
<intent-filter> <action android:name="android.intent.action.SEND" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="image/*" /> </intent-filter>
Finalmente, necesitamos solicitar características y permisos, para que la aplicación pueda acceder a la funcionalidad del sistema que requiere:
<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" />
Si está familiarizado con la programación de Android, esta parte no debe plantear preguntas.
Diseño de la aplicación.
Vamos a crear dos diseños, uno para el modo vertical y otro para el modo horizontal. Aquí está el
diseño del
retrato .
Lo que tenemos aquí: una vista grande para mostrar una imagen, una lista bastante molesta de comerciales (que se muestra cuando se presiona el botón "hueso"), botones "Ayuda", botones para cargar una imagen desde Archivo / Galería y desde Cámara, y finalmente, un botón (inicialmente oculto) "Proceso".

En la actividad en sí, implementaremos algunos botones lógicos que muestran / ocultan y habilitan / deshabilitan dependiendo del estado de la aplicación.
Actividad principal
La actividad extiende una actividad estándar de Android:
public class MainActivity extends Activity
Echemos un vistazo al código responsable de las operaciones NN.
En primer lugar, NN acepta un mapa de bits. Originalmente es un mapa de bits grande desde un archivo o cámara (m_bitmap), luego lo transformamos en un mapa de bits estándar de 256x256 (m_bitmapForNn). También mantenemos las dimensiones de la imagen (256) en una constante:
static Bitmap m_bitmap = null; static Bitmap m_bitmapForNn = null; private int m_nImageSize = 256;
Necesitamos decirle al NN cuáles son los nombres de las capas de entrada y salida; Si consulta la lista anterior, encontrará que los nombres son (¡en nuestro caso! ¡Su caso puede ser diferente!):
private String INPUT_NAME = "input_7_1"; private String OUTPUT_NAME = "output_1";
Luego declaramos la variable para contener el objeto TensofFlow. Además, almacenamos la ruta al archivo NN en los activos:
private TensorFlowInferenceInterface tf;
Cadena privada MODEL_PATH =
"archivo: ///android_asset/dogs.pb";
Razas de perros, para presentar al usuario una información significativa, en lugar de índices en la matriz:
private String[] m_arrBreedsArray;
Inicialmente, cargamos un mapa de bits. Sin embargo, NN en sí mismo espera un conjunto de valores RGB, y su salida es un conjunto de probabilidades de que la imagen presentada sea una raza particular. Por lo tanto, debemos agregar dos matrices más (tenga en cuenta que 120 es el número de razas en nuestro conjunto de datos de entrenamiento):
private float[] m_arrPrediction = new float[120]; private float[] m_arrInput = null;
Cargue la biblioteca de inferencia de tensorflow
static { System.loadLibrary("tensorflow_inference"); }
Como la operación de NN es larga, necesitamos realizarla en un hilo separado, de lo contrario hay una buena posibilidad de llegar a la aplicación del sistema. advertencia "no responde", sin mencionar que arruina la experiencia del usuario.
class PredictionTask extends AsyncTask<Void, Void, Void> { @Override protected void onPreExecute() { super.onPreExecute(); }
En onCreate () de MainActivity, necesitamos agregar onClickListener para el botón "Proceso": m_btn_process.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { processImage(); } });
Lo que hace processImage () es simplemente llamar al hilo que vimos arriba: private void processImage() { try { enableControls(false);
Detalles adicionales
No vamos a discutir el código relacionado con la interfaz de usuario en este tutorial, ya que es trivial y definitivamente no es parte de la tarea "portar NN". Sin embargo, hay pocas cosas que deberían aclararse.Cuando prevenimos nuestra aplicación. desde el lanzamiento de varias instancias, hemos evitado, al mismo tiempo, un flujo normal de control: si comparte una imagen de Facebook y luego comparte otra, la aplicación no se reiniciará. Significa que la forma "tradicional" de manejar datos compartidos al capturarlos en onCreate no es suficiente en nuestro caso, ya que onCreate no se llama en un escenario que acabamos de crear.Aquí hay una manera de manejar la situación:1. En onCreate of MainActivity, llame a la función onSharedIntent: protected void onCreate( Bundle savedInstanceState) { super.onCreate(savedInstanceState); .... onSharedIntent(); ....
Además, agregue un controlador para onNewIntent: @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); onSharedIntent(); }
La función onSharedIntent en sí misma: private void onSharedIntent() { Intent receivedIntent = getIntent(); String receivedAction = receivedIntent.getAction(); String receivedType = receivedIntent.getType(); if (receivedAction.equals(Intent.ACTION_SEND)) {
Ahora manejamos la imagen compartida desde onCreate (si la aplicación se acaba de iniciar) o desde onNewIntent si se encontró una instancia en la memoria.Buena suerte Si te gusta este artículo, por favor "dale me gusta" en las redes sociales, también hay botones sociales en un sitio en sí.