Testen von Wassermelonen mit neuronalen Netzen: Full Dev. Wechseln Sie vom Prototyping zur App. bei google play

Der anfang


Alles begann, als ich eine App fand. auf dem Apfelmarkt konnte das angeblich die Reife einer Wassermellone bestimmen. Ein Programm war ... seltsam. Denken Sie nur einmal darüber nach: Statt mit den Fingerknöcheln zu klopfen, sollten Sie mit Ihrem iPhone die Wassermellone treffen! Trotzdem habe ich mich entschlossen, diese Funktionalität auf einer Andtoid-Plattform zu wiederholen.

Auswahlwerkzeuge


Es gibt nur wenige Möglichkeiten, das Problem zu lösen, und ich musste gewisse Anstrengungen unternehmen, um ein leichtes Problem zu vermeiden. Das heißt, Fourier-Transformationen, Wavelets und Signaleditor. Ich wollte doch neuronale Netze lernen.

Ich habe Keras als NN-Bibliothek ausgewählt, ein wunderbares Tool von Google, das TensorFlow und Theano umgibt. Wenn Sie ein Anfänger sind, ist dies definitiv das beste Werkzeug. Auf der einen Seite ist Keras ein leistungsfähiges Tool, das durch Geschwindigkeit, Speicher und Hardware optimiert ist (und ja, es funktioniert mit GPUs). Auf der anderen Seite werden alle langweiligen Mitarbeiter vor dem Benutzer verborgen, sodass Sie sich auf die eigentliche Aufgabe konzentrieren können. Sehr praktisch.

Keras und neuronale Netze im Allgemeinen sind normalerweise an Python gebunden, die Sprache, die wie eine Riesenschlange ist ... egal. Auf jeden Fall muss man Python kennen, um in einem Deep Learning-Bereich arbeiten zu können. Glücklicherweise ist es eine einfache Sprache, die sehr schnell gelernt werden kann.

Zusätzlich zu Python benötigen Sie einige zusätzliche Bibliotheken, die Sie jedoch problemlos beherrschen können - auch im Vergleich zu Python. Sie benötigen eine (flache) Erfahrung mit NumPy, PyPlot und möglicherweise einigen anderen Bibliotheken.

Abschließend ist zu erwähnen, dass wir keine GPU-Claster benötigen: Unser Problem kann auf einer einzelnen CPU gelöst werden, langsam, aber nicht kritisch langsam.

Arbeitsplan


Zunächst müssen wir ein neuronales Netzwerk mit Python und Keras in einer Ubuntu-Umgebung erstellen. Man kann es in Windows tun, aber Zeit, die Sie für die Konfiguration aufwenden, sollte ausreichen, um Ubuntu zu lernen.

Der nächste Schritt ist das Schreiben eines Programms. Ich plane es auf Java für Android zu machen. Es wird ein Prototyp sein, was bedeutet, dass es die Benutzeroberfläche haben wird, aber noch kein NN.

Warum müssen wir ein Dummy-Programm schreiben? Hier ist der Trick: Jedes tiefe Lernen braucht Daten, um zu lernen. Wie viele Wassermellons sollte ich testen (in beiden Bedeutungen dieses Wortes), um dem NN ausreichende Datenmengen> Hundert zur Verfügung zu stellen? Mehr?

Hier werden wir das Dummy-Programm verwenden: Ich werde es auf Google Play platzieren, es verschenken (ok, alle meine Freunde zwingen, es zu installieren) und Daten von ihm sammeln ... Wo?

Der nächste Schritt besteht darin, ein serverseitiges Programm zu schreiben, das Daten von unserem Android-Client empfängt. Dies ist eine sehr einfache Aufgabe, ich habe ungefähr zwanzig Minuten gebraucht, um zu schreiben, aber es ist immer noch ein separater Schritt.

Wenn wir genügend Daten haben, können wir das NN unterrichten.

Dann müssen wir den resultierenden NN nach Java portieren und eine neue Version unseres Programms veröffentlichen, um einen "Dummy" zu ersetzen.

Profit Nein, warte. Das Programm ist kostenlos. Nur die Erfahrung.

Nn erstellen


Mit Audiosignalen zu arbeiten, die die Wassermellone definitiv anstoßen, bedeutet entweder wiederkehrende neuronale Netze oder so genannte eindimensionale CNN. Da CNNs einfacher zu verwenden und - für kurze Signale - besser sind, werden wir sie verwenden. Die Idee eines Faltungs-NN besteht darin, ein "Sensorfenster" über ein Array unserer Daten (das ein Audiosignal ist) "zu schieben". Anstatt alle Daten gleichzeitig zu analysieren, suchen wir daher nach lokalen Submustern. Jede folgende Schicht der NN arbeitet mit Mustern, die von der vorherigen Schicht erhalten wurden, und sucht nach Mustern höherer Ebenen.

Stellen Sie sich zur Vereinfachung vor, wir müssten eine Möwe auf dem Foto eines Ozeans ausfindig machen. Wir schieben ein kleines "Fenster" über das Bild und suchen nach einem weißen "Häkchen-ähnlichen" Muster. Nun, das war ein 2D-Faltungsnetzwerk, für das ein eindimensionales Signal benötigt wird. 1D CNN ist eine logische Wahl.

Die NN 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']) 

Dieser NN hat zwei Ausgänge (er sagt zwei Werte voraus: Süße und Reife. Die Süße kann 0 (nicht süß), 1 (normal) und 2 (exzellent) sein. Die Reife kann 0 (zu starr), 1 (gut) sein ) und 2 - zu weich, wie Baumwolle mit Sand.

Um diese Bezeichnungen (Ausgaben) zu erstellen, benötigen wir Daten, die von Menschen aufbereitet wurden. Die Vorgehensweise wird später in einem Kapitel über das Android-Programm erläutert. Das Ziel unserer NN ist es, mithilfe von Audiobeispielen die Schätzungen vorherzusagen, die ein Mensch machen würde.

Programm schreiben


Wie bereits erwähnt, wird es zwei Versionen eines Programms geben: "Dummy" und "Final". Ein Dummy macht zufällige Vorhersagen (und der Benutzer wird gewarnt). Dabei werden Audio-Samples aufgezeichnet und zusammen mit Schätzungen der Benutzer über die tatsächliche Qualität des Wassermellons an unseren Server gesendet. Mit anderen Worten, das Programm sammelt einfach die Daten.

Hier ist eine Seite der endgültigen Version eines Programms, es ist kostenlos.

Was es macht:

1. Wenn die "Mikrofon" -Taste gedrückt wird, beginnt eine Aufnahme. Der Benutzer hat fünf Sekunden Zeit, um dreimal gegen das Wasser zu klopfen. Es ist ziemlich ähnlich wie beim Klopfen an der Tür. Dann können Sie die Taste "Wassermelone" drücken, um die "Vorhersage" zu erhalten.

Bild

2. Die von uns vorgenommene Aufnahme wird als temporäre Datei gespeichert. Mit temporär meine ich, dass es bei der nächsten Aufnahme überschrieben wird. Es erlaubt, das Klopfen zu wiederholen, wenn jemand im Raum spricht (man würde nicht glauben, wie schwierig es ist, Leute für fünf Sekunden ruhig zu machen!), Oder Wasser läuft oder irgendein anderes Geräusch hat Platz.

Ok, sagen wir, die Wassermellone ist gekauft und Sie haben sie nach Hause gebracht. Sie haben eine Aufnahme gemacht, und dann haben Sie sie geschnitten. Jetzt können Sie den Geschmack einschätzen.

Wählen Sie die Registerkarte "Speichern".

Auf dieser Registerkarte befinden sich zwei Auswahlfelder: Süße und Reife. Wählen Sie die Werte aus und klicken Sie auf Speichern.

Wichtig! Sie können nur einmal auf Speichern klicken! Dadurch wird verhindert, dass Benutzer mehrere Schätzungen für dieselbe Wassermellone senden. Dies bedeutet auch, dass Sie die Werte sorgfältig auswählen und erst dann auf Speichern klicken müssen. Nachdem Sie das Ergebnis gespeichert haben, wird eine Audiodatei umbenannt und beim nächsten Aufnehmen nicht gelöscht.

Bild

3. Nachdem Sie die Wassermellons geschätzt (gegessen und gegessen) haben, sind Sie aus dem Dorf zurückgekehrt, in dem Sie uneingeschränkten Zugang zu Wassermellons hatten, aber kein Internet. Jetzt bist du online. Öffnen Sie die Registerkarte Senden und drücken Sie die Taste. Ein Paket mit Informationen zu allen Wassermellons, die Sie noch nicht eingereicht haben, wird an unseren Server gesendet.

Bild

Schreiben des serverseitigen Programms


Es ist wirklich einfach, also veröffentliche ich besser nur den Quellcode. Das Programm "fängt" Dateien ab, weist eindeutige Namen zu und legt sie in einem Ordner ab, auf den 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."; } ?> 

Nn trainieren


Wir teilen die Daten in Training (70%) und Testen (30%) auf. Neuronales Netz konvergiert gut, keine Überraschungen hier. Ein Hinweis für Anfänger: Vergessen Sie nicht, die Eingabedaten zu normalisieren, das spart Ihnen viel Zeit und Nerven. 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 nach Java


Es gibt nur wenige Möglichkeiten, den NN von Python nach Java zu portieren. In letzter Zeit hat Google diesen Vorgang sehr bequem gestaltet. Wenn Sie sich also für das Studium von Lehrbüchern entscheiden, stellen Sie sicher, dass diese 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 benötigen Sie den Namen der Eingabe- und Ausgabeschichten des NN. Die "print" -Anweisung zeigt sie für uns an.

Als nächstes platzieren wir die exportierte Datei im Ordner "assets" des Android Studio-Projekts (Dateiname ist coordted.pb, fragen Sie nicht), fügen die Bibliothek hinzu ( hier , hier oder besser, hier tensorflowinference interface, und ... das war's.

Das war's Als ich es zum ersten Mal tat, erwartete ich Probleme, aber ... alles hat einfach funktioniert.

Hier ist der Aufruf an unser NN aus Java-Code:

  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 "m_arrInput" - ein Array, das zwei Elemente mit unserer Vorhersage (Süße, Reife) im Bereich von 0 bis 1 enthält.

Fazit


Ich glaube, ich soll meinem Publikum für die Aufmerksamkeit danken und die Hoffnung zum Ausdruck bringen, dass es interessant war. Stattdessen wünsche ich Ihnen mehr Süßwasser-Mellons und ich hoffe, Sie schicken mir neue Hörproben, wenn Sie sie essen (Mellons, keine Proben, nicht wahr!)

Das Programm ist natürlich kostenlos.

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


All Articles