Les progrès dans le domaine des réseaux de neurones en général et de la reconnaissance des formes en particulier ont conduit au fait qu'il peut sembler que la création d'une application de réseau de neurones pour travailler avec des images est une tâche de routine. Dans un sens, c'est - si vous avez une idée liée à la reconnaissance des formes, ne doutez pas que quelqu'un a déjà écrit quelque chose comme ça. Il vous suffit de trouver le morceau de code correspondant dans Google et de le «compiler» à partir de l'auteur.
Cependant, il y a encore de nombreux détails qui rendent la tâche moins insoluble que ... ennuyeuse, je dirais. Cela prend trop de temps, surtout si vous êtes un débutant qui a besoin de leadership, étape par étape, d'un projet réalisé sous vos yeux et achevé du début à la fin. Sans l'habituel dans de tels cas, «sauter cette partie évidente» des excuses.
Dans cet article, nous examinerons la tâche de créer un identifiant de race de chien: nous allons créer et former un réseau de neurones, puis le porter sur Java pour Android et le publier sur Google Play.
Si vous voulez voir le résultat final, le voici:
NeuroDog App sur Google Play.
Site Web avec ma robotique (en cours):
robotics.snowcron.com .
Site Web avec le programme lui-même, y compris un guide:
NeuroDog User Guide .
Et voici une capture d'écran du programme:

Énoncé du problème
Nous utiliserons Keras: une bibliothèque Google pour travailler avec les réseaux de neurones. Il s'agit d'une bibliothèque de haut niveau, ce qui signifie qu'elle est plus facile à utiliser que les alternatives que je connais. Si quoi que ce soit - il existe de nombreux manuels sur Keras dans le réseau, de haute qualité.
Nous utiliserons CNN - Convolutional Neural Networks. CNN (et les configurations plus avancées basées sur eux) sont la norme de facto en matière de reconnaissance d'image. Dans le même temps, la formation d'un tel réseau n'est pas toujours facile: vous devez choisir la bonne structure de réseau, les paramètres de formation (tous ces taux d'apprentissage, l'élan, L1 et L2, etc.). La tâche nécessite des ressources informatiques importantes, et donc, pour la résoudre simplement en passant par TOUS les paramètres échouera.
C'est l'une des nombreuses raisons pour lesquelles, dans la plupart des cas, ils utilisent ce que l'on appelle le «transfert de connaissances» au lieu de l'approche dite «vanille». Transfer Knowlege utilise un réseau de neurones formé par quelqu'un avant nous (par exemple, Google) et généralement pour une tâche similaire, mais toujours différente. Nous en prenons les couches initiales, remplaçons les couches finales par notre propre classificateur - et cela fonctionne, et cela fonctionne très bien.
Au début, un tel résultat peut être surprenant: comment se fait-il que nous ayons pris un réseau Google formé pour distinguer les chats des chaises, et qu'il reconnaisse les races de chiens pour nous? Pour comprendre comment cela se produit, vous devez comprendre les principes de base du travail des réseaux de neurones profonds, y compris ceux utilisés pour la reconnaissance des formes.
Nous avons «alimenté» le réseau en image (un tableau de nombres, c'est-à-dire) en entrée. La première couche analyse l'image pour des motifs simples, tels que «ligne horizontale», «arc», etc. La couche suivante reçoit ces motifs en entrée et produit des motifs de second ordre, tels que «fourrure», «coin de l'œil» ... En fin de compte, nous obtenons un puzzle à partir duquel nous pouvons reconstruire le chien: laine, deux yeux et une main humaine en dents.
Tout ce qui précède a été fait à l'aide de couches pré-formées obtenues par nous (par exemple, de Google). Ensuite, nous ajoutons nos couches et leur apprenons à extraire des informations sur la race de ces modèles. Cela semble logique.
Pour résumer, dans cet article, nous allons créer à la fois CNN «vanille» et plusieurs variantes «transfert d'apprentissage» de différents types de réseaux. Quant à «vanilla»: je vais le créer, mais je ne prévois pas de le configurer en sélectionnant des paramètres, car il est beaucoup plus facile de former et de configurer des réseaux «pré-formés».
Puisque nous prévoyons d'enseigner à notre réseau de neurones à reconnaître les races de chiens, nous devons lui «montrer» des échantillons de diverses races. Heureusement, il existe un ensemble de photographies créées
ici pour une tâche similaire (l'
original est ici ).
Ensuite, je prévois de porter le meilleur des réseaux reçus pour Android. Le portage des réseaux Kerasov sur Android est relativement simple, bien formalisé et nous ferons toutes les étapes nécessaires, il ne sera donc pas difficile de reproduire cette partie.
Ensuite, nous publierons tout cela sur Google Play. Naturellement, Google résistera, donc des astuces supplémentaires seront utilisées. Par exemple, la taille de notre application (en raison d'un réseau de neurones volumineux) sera supérieure à la taille autorisée de l'APK Android acceptée par Google Play: nous devrons utiliser des bundles. De plus, Google n'affichera pas notre application dans les résultats de recherche, cela peut être corrigé en enregistrant des balises de recherche dans l'application, ou attendez simplement ... une semaine ou deux.
En conséquence, nous obtenons une application "commerciale" entièrement fonctionnelle (entre guillemets, car elle est présentée gratuitement) pour Android et utilisant des réseaux de neurones.
Environnement de développement
Vous pouvez programmer Keras de différentes manières, en fonction du système d'exploitation que vous utilisez (Ubuntu recommandé), de la présence ou de l'absence d'une carte vidéo, etc. Il n'y a rien de mal dans le développement sur l'ordinateur local (et, par conséquent, sa configuration), sauf que ce n'est pas le moyen le plus simple.
Tout d'abord, l'installation et la configuration d'un grand nombre d'outils et de bibliothèques prennent du temps, puis lorsque de nouvelles versions seront publiées, vous devrez passer du temps à nouveau. Deuxièmement, les réseaux de neurones nécessitent une grande puissance de calcul pour la formation. Vous pouvez accélérer (de 10 fois ou plus) ce processus si vous utilisez un GPU ... au moment de la rédaction de cet article, les meilleurs GPU les plus appropriés pour ce travail coûtaient entre 2000 $ et 7000 $. Et oui, ils doivent également être configurés.
Nous allons donc aller dans l'autre sens. Le fait est que Google permet aux hérissons pauvres comme nous d'utiliser les GPU de leur cluster - gratuitement, pour les calculs liés aux réseaux de neurones, il fournit également un environnement entièrement configuré, tous ensemble, cela s'appelle Google Colab. Le service vous donne accès à Jupiter Notebook avec python, Keras et un grand nombre d'autres bibliothèques déjà configurées. Tout ce que vous avez à faire est d'obtenir un compte Google (obtenez un compte Gmail et cela vous donnera accès à tout le reste).
Pour le moment, Colab peut être embauché
ici , mais connaissant Google, cela peut changer à tout moment. Il suffit de google Google Colab.
Le problème évident avec l'utilisation de Colab est qu'il s'agit d'un service WEB. Comment accédons-nous à nos données? Enregistrer le réseau neuronal après la formation, par exemple, télécharger des données spécifiques à notre tâche, etc.?
Il existe plusieurs (au moment de la rédaction de cet article - trois) différentes manières, nous utilisons celle qui me semble la plus pratique - nous utilisons Google Drive.
Google Drive est un stockage de données basé sur le cloud qui fonctionne un peu comme un disque dur ordinaire, et il peut être mappé sur Google Colab (voir le code ci-dessous). Après cela, vous pouvez travailler avec lui comme vous le feriez avec des fichiers sur un disque local. C'est-à-dire, par exemple, afin d'accéder aux photos de chiens pour former notre réseau de neurones, nous devons les télécharger sur Google Drive, c'est tout.
Création et formation d'un réseau neuronal
Ci-dessous, je donne le code en Python, bloc par bloc (du Jupiter Notebook). Vous pouvez copier ce code dans votre bloc-notes Jupiter et l'exécuter également, bloc par bloc, car les blocs peuvent être exécutés indépendamment (bien sûr, les variables définies dans le premier bloc peuvent être requises à la fin, mais il s'agit d'une dépendance évidente).
Initialisation
Tout d'abord, montons Google Drive. Seulement deux lignes. Ce code ne doit être exécuté qu'une seule fois dans une session Colab (disons une fois toutes les 6 heures). Si vous l'appelez une deuxième fois alors que la session est encore «vivante», elle sera ignorée car le lecteur est déjà monté.
from google.colab import drive drive.mount('/content/drive/')
Au premier démarrage, il vous sera demandé de confirmer vos intentions, il n'y a rien de compliqué. Voici à quoi ça ressemble:
>>> Go to this URL in a browser: ... >>> Enter your authorization code: >>> ·········· >>> Mounted at /content/drive/
Une section d'
inclusion complètement standard; il est possible que certains des fichiers inclus ne soient pas nécessaires, eh bien ... désolé. De plus, comme je vais tester différents réseaux de neurones, vous devrez commenter / décommenter certains des modules inclus pour des types spécifiques de réseaux de neurones: par exemple, pour utiliser InceptionV3 NN, décommenter l'inclusion d'InceptionV3 et commenter, par exemple, ResNet50. Ou pas: tout ce qui change, c'est la taille de la mémoire utilisée, et ce n'est pas très fort.
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
Sur Google Drive, nous créons un dossier pour nos fichiers. La deuxième ligne affiche son contenu:
working_path = "/content/drive/My Drive/DeepDogBreed/data/" !ls "/content/drive/My Drive/DeepDogBreed/data" >>> all_images labels.csv models test train valid
Comme vous pouvez le voir, les photos des chiens (copiées à partir du jeu de données Stanford (voir ci-dessus) sur Google Drive) sont d'abord enregistrées dans le dossier
all_images . Plus tard, nous les copierons dans les répertoires
train, valid et
test . Nous enregistrerons les modèles formés dans le dossier des
modèles . Quant au fichier labels.csv, il fait partie du jeu de données avec photos, il contient un tableau de correspondance des noms des photos et des races de chiens.
Il existe de nombreux tests que vous pouvez exécuter pour comprendre exactement ce que nous avons obtenu pour une utilisation temporaire de Google. Par exemple:
Comme vous pouvez le voir, le GPU est vraiment connecté, et sinon, vous devez trouver et activer cette option dans les paramètres de Jupiter Notebook.
Ensuite, nous devons déclarer certaines constantes, telles que la taille des images, etc. Nous utiliserons des images d'une taille de 256x256 pixels, c'est une image assez grande pour ne pas perdre de détails, et assez petite pour que tout rentre dans la mémoire. Notez, cependant, que certains types de réseaux de neurones que nous utiliserons attendent des images de 224x224 pixels. Dans de tels cas, nous commentons 256 et décommentons 224.
La même approche (commentaire 1 - décommentation) sera appliquée aux noms des modèles que nous enregistrons, tout simplement parce que nous ne voulons pas écraser les fichiers qui peuvent encore être utiles.
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
Chargement des données
Tout d'abord,
téléchargeons le fichier
labels.csv et
divisons- le en parties de formation et de validation. Notez qu'il n'y a pas encore de partie test, car je vais tricher pour obtenir plus de données d'entraînement.
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
Ensuite, copiez les fichiers image dans les dossiers de formation / validation / test, selon les noms de fichiers. La fonction suivante copie les fichiers dont nous transférons les noms dans le dossier spécifié.
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] + "/")
Comme vous pouvez le voir, nous ne copions qu'un fichier pour chaque race de chien comme
test . De plus, lors de la copie, nous créons des sous-dossiers, un pour chaque race. Par conséquent, les photographies sont copiées dans des sous-dossiers par race.
Cela est dû au fait que Keras peut travailler avec un répertoire d'une structure similaire, en chargeant des fichiers image selon les besoins, et pas tous en même temps, ce qui économise de la mémoire. Télécharger les 15 000 images à la fois est une mauvaise idée.
Nous devrons appeler cette fonction une seule fois, car elle copie des images - et n'est plus nécessaire. En conséquence, pour une utilisation future, nous devons le commenter:
Obtenez une liste des races de chiens:
breeds = np.unique(labels['breed']) map_characters = {}
Traitement d'image
Nous allons utiliser la fonctionnalité de bibliothèque Keras appelée ImageDataGenerators. ImageDataGenerator peut traiter l'image, la mettre à l'échelle, la faire pivoter, etc. Il peut également accepter une fonction de
traitement qui peut traiter des images en plus.
def preprocess(img): img = cv2.resize(img, (IMAGE_SIZE, IMAGE_SIZE), interpolation = cv2.INTER_AREA)
Faites attention au code suivant:
Nous pouvons normaliser (sous-données sous la plage 0-1 au lieu du 0-255 d'origine) dans ImageDataGenerator lui-même. Pourquoi alors avons-nous besoin d'un préprocesseur? À titre d'exemple, considérons l'appel flou (commenté, je ne l'utilise pas): il s'agit de la même manipulation d'image personnalisée qui peut être arbitraire. Tout, du contraste au HDR.
Nous utiliserons deux ImageDataGenerators différents, un pour la formation et un pour la validation. La différence est que pour la formation, nous avons besoin de tours et de mise à l'échelle pour augmenter la «variété» de données, mais pour la validation, nous n'en avons pas besoin, du moins pas dans cette tâche.
train_datagen = ImageDataGenerator( preprocessing_function=preprocess,
Création d'un réseau de neurones
Comme déjà mentionné, nous allons créer plusieurs types de réseaux de neurones. Chaque fois, nous appellerons une autre fonction pour créer, inclure d'autres fichiers et parfois déterminer une taille d'image différente. Ainsi, pour basculer entre différents types de réseaux de neurones, nous devons commenter / décommenter le code approprié.
Tout d'abord, créez un CNN «vanille». Cela ne fonctionne pas bien, car j'ai décidé de ne pas perdre de temps à le déboguer, mais au moins cela fournit une base qui peut être développée s'il y a un désir (généralement c'est une mauvaise idée, car les réseaux pré-formés donnent le meilleur résultat).
def createModelVanilla(): model = Sequential()
Lorsque nous créons des réseaux à l'aide de l'
apprentissage par
transfert , la procédure change:
def createModelMobileNetV2():
La création d'autres types de réseaux suit le même schéma:
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)
Attention: gagnant! Ce NN a montré le meilleur résultat:
def createModelInceptionV3():
Un autre:
def createModelNASNetMobile():
Différents types de réseaux de neurones peuvent être utilisés pour différentes tâches. Ainsi, en plus des exigences de précision des prédictions, la taille peut avoir de l'importance (le NN mobile est 5 fois plus petit que Inception) et la vitesse (si nous avons besoin du traitement en temps réel d'un flux vidéo, alors la précision devra être sacrifiée).
Formation au réseau de neurones
Tout d'abord, nous
expérimentons , nous devrions donc pouvoir supprimer les réseaux de neurones que nous avons enregistrés, mais que nous n'utilisons plus. La fonction suivante supprime NN s'il existe:
La façon dont nous créons et supprimons les réseaux de neurones est assez simple et directe. Tout d'abord, supprimez. Lorsque vous appelez
delete (uniquement), il convient de garder à l'esprit que le Jupiter Notebook a une fonction «exécuter la sélection», sélectionnez uniquement ce que vous souhaitez utiliser et exécutez-le.
Ensuite, nous créons un réseau neuronal si son fichier n'existait pas, ou appelons
load s'il existe: bien sûr, nous ne pouvons pas appeler «delete» et nous attendre à ce que NN existe, donc pour utiliser un réseau neuronal enregistré, n'appelez pas
delete .
En d'autres termes, nous pouvons créer un nouveau NN, ou utiliser celui existant, en fonction de la situation et de ce que nous expérimentons actuellement. Un scénario simple: nous avons formé un réseau de neurones, puis sommes partis en vacances. Ils sont revenus et Google a cloué la session, nous devons donc charger celle précédemment enregistrée: commenter «supprimer» et décommenter «charger».
deleteSavedNet(working_path + strModelFileName)
Les points de contrôle sont un élément très important de notre programme. Nous pouvons créer un tableau de fonctions qui devraient être appelées à la fin de chaque ère de formation et le transmettre au point de contrôle. Par exemple, vous pouvez enregistrer un réseau de neurones
s'il affiche des résultats meilleurs que ceux déjà enregistrés.
checkpoint = ModelCheckpoint(working_path + strModelFileName, monitor='val_acc', verbose=1, save_best_only=True, mode='auto', save_weights_only=False) callbacks_list = [ checkpoint ]
Enfin, nous enseignons le réseau neuronal sur l'ensemble d'entraînement:
Les graphiques de précision et de perte pour la meilleure des configurations sont les suivants:


Comme vous pouvez le voir, le réseau neuronal apprend, et pas mal.
Test de réseau neuronal
Une fois la formation terminée, nous devons tester le résultat; pour cela, NN présente des photos qu'elle n'avait jamais vues auparavant - celles que nous avons copiées dans le dossier de test - une pour chaque race de chien.
Exporter un réseau de neurones vers une application Java
Tout d'abord, nous devons organiser le chargement du réseau neuronal à partir du disque. La raison est claire: l'exportation a lieu dans un autre bloc de code, donc nous commencerons probablement l'exportation séparément - lorsque le réseau de neurones sera amené à son état optimal. Autrement dit, immédiatement avant l'exportation, dans le même cycle du programme, nous ne formerons pas le réseau. Si vous utilisez le code affiché ici, il n'y a aucune différence, le réseau optimal a été sélectionné pour vous. Mais si vous apprenez quelque chose par vous-même, alors tout réentraîner avant de sauver est une perte de temps, si auparavant vous avez tout sauvé.
Pour la même raison - pour ne pas sauter par dessus le code - j'inclus ici les fichiers nécessaires à l'exportation. Personne ne vous dérange pour les déplacer au début du programme si votre sens de la beauté l'exige:
from keras.models import Model from keras.models import load_model from keras.layers import * import os import sys import tensorflow as tf
Un petit test après le chargement d'un réseau de neurones, juste pour vous assurer que tout est chargé - fonctionne:
img = image.load_img(working_path + "test/affenpinscher.jpg")

Ensuite, nous devons obtenir les noms des couches d'entrée et de sortie du réseau (que ce soit la fonction de création, nous devons explicitement «nommer» les couches, ce que nous n'avons pas fait).
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
Nous utiliserons les noms des couches d'entrée et de sortie ultérieurement lors de l'importation du réseau neuronal dans une application Java.
Un autre code itinérant sur le réseau pour obtenir ces donné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()
.
Keras Neural Network
pb , , 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)
:
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")
.
Android
Android . , , , ( ) .
, Android Studio . « », — . activity.

, «assets» (, ).
Gradle
. ,
tensorflow-android . , Tensorflow (, , Keras) Java:

:
versionCode versionName . , Google Play. gdadle (, 1 -> 2 -> 3...) , « ».
, «» — 100 Mb Neural Network , instance «» Facebook .
instance :
<activity android:name=".MainActivity" android:launchMode="singleTask">
android:launchMode=«singleTask» MainActivity, Android, () , , instance.
, , - «» :
<intent-filter> <action android:name="android.intent.action.SEND" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="image/*" /> </intent-filter>
, , :
<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" />
Android, .
Layout .
layouts, , .
Portrait layout .
: (view) , (, «»), «Help», File/Gallery , ( ) «Process» .

, enabling/disabling , .
MainActivity
activity (extends) Android Activity:
public class MainActivity extends Activity
, .
, Bitmap. , Bitmap ( ) (m_bitmap), , 256x256 (m_bitmapForNn). (256) :
static Bitmap m_bitmap = null; static Bitmap m_bitmapForNn = null; private int m_nImageSize = 256;
; (. ), , :
private String INPUT_NAME = "input_7_1"; private String OUTPUT_NAME = "output_1";
TensofFlow. , ( assets):
private TensorFlowInferenceInterface tf;
private String MODEL_PATH =
"file:///android_asset/dogs.pb";
, , :
private String[] m_arrBreedsArray;
, Bitmap. , RGB , — , — , . , (, 120 , ):
private float[] m_arrPrediction = new float[120]; private float[] m_arrInput = null;
tensorflow inference library:
static { System.loadLibrary("tensorflow_inference"); }
, , , « », .
class PredictionTask extends AsyncTask<Void, Void, Void> { @Override protected void onPreExecute() { super.onPreExecute(); }
In onCreate() of the MainActivity, we need to add the onClickListener for the «Process» button:
m_btn_process.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { processImage(); } });
processImage() , :
private void processImage() { try { enableControls(false);
UI- , . , .
instances , (flow of control): «» Facebook, , . , «» onCreate , onCreate .
:
1. onCreate MainActivity, onSharedIntent:
protected void onCreate( Bundle savedInstanceState) { super.onCreate(savedInstanceState); .... onSharedIntent(); ....
onNewIntent:
@Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); onSharedIntent(); }
onSharedIntent:
private void onSharedIntent() { Intent receivedIntent = getIntent(); String receivedAction = receivedIntent.getAction(); String receivedType = receivedIntent.getType(); if (receivedAction.equals(Intent.ACTION_SEND)) {
onCreate ( ) onNewIntent ( ).
Bonne chance , , «» , «»
.