Bestimmen der Reife einer Wassermelone mithilfe von Keras: ein vollständiger Zyklus von einer Idee bis zu einem Programm bei Google Play

Wie alles begann


Alles begann mit Apple Market - ich fand heraus, dass sie ein Programm haben, um die Reife einer Wassermelone zu bestimmen. Das Programm ... ist komisch. Was ist zumindest das Angebot wert, nicht mit den Fingerknöcheln an eine Wassermelone zu klopfen, sondern ... telefonisch! Trotzdem wollte ich diesen Erfolg auf einer bekannteren Android-Plattform wiederholen.

Werkzeugauswahl


Unser Problem wird auf verschiedene Weise gelöst, und um ehrlich zu sein, musste ich erhebliche Anstrengungen unternehmen, um nicht den "einfachen" Weg zu gehen. Nehmen Sie also Fourier-Transformationen, Wavelets und einen Signaleditor. Ich wollte jedoch Erfahrungen mit neuronalen Netzen sammeln, also lassen Sie die Netze Daten analysieren.

Keras, das Google-Add-On für TensorFlow und Theano, wurde als Bibliothek zum Erstellen und Trainieren neuronaler Netze ausgewählt. Wenn Sie gerade erst mit Deep-Learning-Netzwerken beginnen, sollten Sie im Allgemeinen kein Tool finden. Einerseits ist Keras ein leistungsstarkes Tool, das für Geschwindigkeit, Speicher und Hardware optimiert ist (ja, es kann auf Grafikkarten und deren Clustern verwendet werden). Auf der anderen Seite ist alles, was vor dem Benutzer "verborgen" werden kann, dort verborgen, so dass Sie Ihr Gehirn nicht über das Andocken von Schichten eines neuronalen Netzwerks zermürben müssen. Sehr bequem.

Da Keras und neuronale Netze im Allgemeinen Kenntnisse in Python erfordern - diese Sprache, wie eine umwickelte Schlange ... Entschuldigung, Pent. Kurz gesagt, Sie sollten sich nicht in modernes Deep Learning ohne Python einmischen. Glücklicherweise kann Python in extremen Fällen in zwei Wochen - in einem Monat - studiert werden.

Sie werden einige weitere Bibliotheken für Python benötigen, aber dies sind Kleinigkeiten - ich meine, wenn Sie sich selbst mit Python befasst haben. Es erfordert eine (sehr oberflächliche) Kenntnis von NumPy, PyPlot und möglicherweise einigen Bibliotheken, aus denen wir buchstäblich einige Funktionen übernehmen. Nicht schwer. Die Wahrheit ist.

Abschließend stelle ich fest, dass wir die oben genannten Grafikkartencluster nicht benötigen - unsere Aufgabe wird normalerweise mit Hilfe einer Computer-CPU gelöst - langsam, aber nicht kritisch langsam.

Arbeitsplan


Zuerst müssen Sie ein neuronales Netzwerk erstellen - unter Python und Keras unter Ubuntu. Sie können - auf dem Emulator Ubunta. Sie können - für Windows, aber die zusätzliche Zeit reicht aus, um das erwähnte Ubuntu zu studieren und dann darunter zu arbeiten.

Der nächste Schritt ist das Schreiben eines Programms. Ich habe vor, dies in Java unter Android zu tun. Dies wird ein Prototyp des Programms sein, in dem Sinne, dass es eine Benutzeroberfläche haben wird, aber es gibt noch kein neuronales Netzwerk.

Was bedeutet es, "Schnuller" zu schreiben? Aber hier ist die Sache: Jede Aufgabe im Zusammenhang mit der Datenanalyse beruht früher oder später auf der Suche nach Daten - für die Schulung unseres Programms. Wie viele Wassermelonen sollten tatsächlich gezapft und verkostet werden, damit das neuronale Netzwerk auf diesen Daten ein zuverlässiges Modell aufbauen kann? Hundert? Mehr?

Hier hilft uns unser Programm: Laden Sie es auf Google Play hoch, verteilen Sie es (okay, auferlegen, Arme drehen) an alle Freunde, die nicht das Glück haben, ein Telefon mit Android zu haben, und Daten, ein winziger Stream, beginnen zu fließen ... und übrigens, wo?

Der nächste Schritt besteht darin, ein Serverprogramm zu schreiben, das Daten von unserem Android-Client empfängt. Richtig, dieses Serverprogramm ist sehr einfach, ich habe alles in ungefähr zwanzig Minuten erledigt. Dies ist jedoch eine separate Phase.

Endlich genug Daten. Wir trainieren ein neuronales Netzwerk.

Wir portieren das neuronale Netzwerk in Java und veröffentlichen ein Update für unser Programm.

Gewinn Obwohl nicht. Das Programm war kostenlos. Nur Erfahrung und ausgestopfte Beulen.

Erstellen eines neuronalen Netzwerks


Die Arbeit mit Audio, das natürlich auf eine Wassermelone tippt, ist entweder ein wiederkehrendes neuronales Netzwerk oder das sogenannte eindimensionale evolutionäre Netzwerk. Darüber hinaus waren in den letzten Jahren evolutionäre Netzwerke eindeutig führend und verdrängten wiederkehrende. Die Idee eines Faltungsnetzwerks ist, dass das Fenster über das Datenarray gleitet - das Diagramm „Schallintensität - Zeit“ - und anstatt Hunderttausende von Samples zu analysieren, arbeiten wir nur mit dem, was in das Fenster gelangt. Die folgenden Ebenen kombinieren und analysieren die Ergebnisse dieser Ebene.

Stellen Sie sich zur Verdeutlichung vor, Sie müssten eine Möwe auf einem Foto einer Seelandschaft finden. Sie scannen ein Bild - das „Fenster“ Ihrer Aufmerksamkeit bewegt sich auf der Suche nach einem weißen Häkchen entlang imaginärer Zeilen und Spalten. So funktioniert ein 2D-Faltungsnetzwerk, während ein eindimensionales Netzwerk entlang einer Koordinate scannt - dies ist die beste Wahl, wenn es sich um ein Audiosignal handelt.

Ich stelle jedoch fest, dass es nicht notwendig ist, sich auf 1D-Netzwerke zu konzentrieren. Als Übung habe ich den Ton aufgezeichnet und die resultierende Bitmap als Bild analysiert - unter Verwendung eines 2D-Faltungsnetzwerks. Zu meiner Überraschung war das Ergebnis nicht schlechter als bei der Analyse von „eindimensionalen“ Rohdaten.

Das verwendete Netzwerk hatte folgende Struktur:

model = Sequential() model.add(Conv1D(filters=32, kernel_size=512, strides=3, padding='valid', use_bias=False, input_shape=(nSampleSize, 1), name='c1d', activation='relu')) model.add(Activation('relu', input_shape=(nSampleSize, 1))) model.add(MaxPooling1D(pool_size=(2))) model.add(Conv1D(32, (3))) model.add(Activation('relu')) model.add(MaxPooling1D(pool_size=(2))) model.add(Conv1D(64, (3))) model.add(Activation('relu')) model.add(MaxPooling1D(pool_size=(2))) model.add(Flatten()) model.add(Dense(64)) model.add(Activation('relu')) model.add(Dropout(0.5)) model.add(Dense(nNumOfOutputs)) #1)) model.add(Activation('sigmoid')) model.compile(loss='mean_squared_error', optimizer='adam', metrics=['accuracy']) 

Dieses Netzwerk hat zwei Ausgabewerte (es sagt zwei Werte voraus): Süße und Reife. Die Süße ist 0 (ungesüßt), 1 (normal) und 2 (ausgezeichnet), und die Reife ist 0 zu hart, 1 ist das, was Sie brauchen, und 2 ist überreif, wie Watte mit Sand.

Die Noten für das Testmuster werden von der Person genau wie festgelegt - wir werden im Abschnitt über das Programm für Android sprechen. Die Aufgabe des neuronalen Netzwerks besteht darin, vorherzusagen, welche Bewertung eine Person für eine bestimmte Wassermelone geben wird (gemäß einem Hahn).

Ein Programm schreiben


Ich habe bereits erwähnt, dass das Programm in zwei Versionen herauskommen sollte. Die erste, vorläufige, warnt die Benutzerin ehrlich, dass ihre Vorhersagen völliger Unsinn sind. Der Benutzer kann jedoch einen Schlag auf eine Wassermelone aufzeichnen, den Geschmack dieser Wassermelone bewerten und über das Internet an den Autor des Programms senden. Das heißt, die erste Version sammelt einfach Daten.

Hier ist die Seite des Programms bei Google Play. Natürlich ist das Programm kostenlos.

Was macht sie:

1. Drücken Sie die Taste mit dem Mikrofon und die Aufnahme beginnt. Sie haben fünf Sekunden Zeit, um die Wassermelone dreimal zu treffen - klopfen-klopfen-klopfen. Ein Knopf mit einer Wassermelone macht eine "Vorhersage", und wir berühren sie noch nicht.

Hinweis - Wenn Google eine alte Version hat, werden Aufzeichnung und Vorhersage in einer Schaltfläche mit einer Wassermelone kombiniert, es gibt jedoch keine Schaltfläche mit einem Mikrofon.

Bild

2. Die gespeicherte Datei ist temporär und wird beim nächsten Drücken der Aufnahmetaste überschrieben. Auf diese Weise können Sie das Klopfen wiederholen, wenn jemand Arm in Arm spricht (Sie können sich nicht vorstellen, wie schwierig es ist, andere für fünf Sekunden zum Schweigen zu bringen!) Oder das Wasser ist laut - das Geschirr klingelt - der Nachbar bohrt ...

Aber jetzt wird die Wassermelone ausgewählt und gekauft. Sie haben es nach Hause gebracht, einen Ton aufgenommen und geschnitten. Jetzt können Sie den Geschmack bewerten. Wählen Sie die Registerkarte Speichern.

Auf dieser Registerkarte sehen wir zwei Kombinationsfelder für die Einstufung - Süße und Reife (Süße und Reife, Arbeiten an der Übersetzung sind im Gange). Markieren Sie - klicken Sie auf Speichern.

Achtung! Speichern kann nur einmal angeklickt werden. Setzen Sie also zuerst ein Zeichen. Auf Knopfdruck wird die Audiodatei umbenannt und bei der nächsten Aufnahme nicht mehr gelöscht.

Bild

3. Nachdem Sie ein Dutzend Wassermelonen aufgezeichnet (und daher gegessen) hatten, kehrten Sie aus der Hütte zurück, in der Sie kein Internet hatten. Jetzt ist das Internet. Öffnen Sie die Registerkarte Senden und drücken Sie die Taste. Das Paket (mit einem Dutzend Wassermelonen) geht an den Server des Entwicklers.

Bild

Serverprogramm schreiben


Hier ist alles einfach, daher sollte ich den vollständigen Code für dieses Skript besser auslegen. Das Programm „fängt“ Dateien, gibt ihnen eindeutige Namen und legt sie in einem Verzeichnis ab, auf das nur der Websitebesitzer zugreifen kann.

 <?php if (is_uploaded_file($_FILES['file']['tmp_name'])) { $uploads_dir = './melonaire/'; $tmp_name = $_FILES['file']['tmp_name']; $pic_name = $_FILES['file']['name']; $filename = md5(date('Ymd H:i:s:u')); move_uploaded_file($tmp_name, $uploads_dir.$filename); } else { echo "File not uploaded successfully."; } ?> 

Neuronales Netzwerktraining


Die Daten sind in Training und Test unterteilt, 70 bzw. 30 Prozent. Neuronales Netz - konvergiert. Für Anfänger gibt es hier jedoch keine Überraschungen: Vergessen Sie nicht, die Eingabedaten zu normalisieren, da Sie dadurch viele Nerven sparen. So etwas in der Art:

 for file_name in os.listdir(path): nSweetness, nRipeness, arr_loaded = loadData(file_name) arr_data.append(arr_loaded / max(abs(arr_loaded))) # 2 stands for num. of inputs of a combo box - 1 arr_labels.append([nSweetness / 2.0, nRipeness / 2.0]) 

Portierung eines neuronalen Netzwerks


Es gibt verschiedene Möglichkeiten, ein Netzwerk von einer Python-Umgebung nach Java zu portieren. In letzter Zeit hat Google diesen Vorgang vereinfacht. Wenn Sie also die Lehrbücher lesen, stellen Sie sicher, dass sie nicht veraltet sind. So habe ich es gemacht:

 from keras.models import Model from keras.models import load_model from keras.layers import * import os import sys import tensorflow as tf # ------------------- 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() # ------------------- def get_script_path(): return os.path.dirname(os.path.realpath(sys.argv[0])) # ------------------- 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, 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(get_script_path() + "/models/model.h5") #keras_to_tensorflow(model, output_dir=get_script_path() + "/models/model.h5", # model_name=get_script_path() + "/models/converted.pb") print_graph_nodes(get_script_path() + "/models/converted.pb") 

Beachten Sie die letzte Zeile: Im Java-Code müssen Sie die Eingabe- und Ausgabenamen des Netzwerks angeben. Dieser "Druck" druckt sie nur.

Also legen wir die empfangene Datei coordted.pb in das Assets-Verzeichnis des Projekts in Android Studio, verbinden die Tensorflowinference-Schnittstellenbibliothek (siehe hier oder besser hier ) und fertig.

Das ist alles. Als ich das zum ersten Mal tat, erwartete ich, dass es schwierig werden würde, aber ... es funktionierte beim ersten Versuch.

So sieht ein neuronaler Netzwerkaufruf aus Java-Code aus:

  protected Void doInBackground(Void... params) { try { //Pass input into the tensorflow tf.feed(INPUT_NAME, m_arrInput, 1, // batch ? m_arrInput.length, 1); // channels ? //compute predictions tf.run(new String[]{OUTPUT_NAME}); //copy the output into the PREDICTIONS array tf.fetch(OUTPUT_NAME, m_arrPrediction); } catch (Exception e) { e.getMessage(); } return null; } 

Hier ist m_arrInput ein Array mit zwei Elementen, die - yes! - unsere Vorhersage, normalisiert von null auf eins.

Fazit


Hier soll man sich anscheinend für die Aufmerksamkeit bedanken und die Hoffnung zum Ausdruck bringen, dass es interessant war. Stattdessen stelle ich fest, dass Google die erste Version des Programms ist. Der zweite ist vollständig fertig, aber nicht genügend Daten. Wenn Sie also Wassermelonen mögen, stellen Sie bitte ein Programm auf Ihr Android. Je mehr Daten Sie senden, desto besser funktioniert die zweite Version ...

Natürlich wird es kostenlos sein.

Viel Glück und ja: Danke fürs Zuschauen. Ich hoffe es war interessant.

Wichtiges Update: Eine neue Version mit verbesserter Analyse wurde veröffentlicht. Vielen Dank an alle, die die Wassermelonen geschickt haben, und bitte senden Sie mehr!

Source: https://habr.com/ru/post/de424099/


All Articles