Neuronale Netzwerke mit Keras auf Rescale mit Hy

hylang 3

Als lange Zeit GNU Emacs Benutzer, ich bin gekommen, um C-x C-e (eval-last-sexp) selbstverständlich. Das heißt, in fast jeder Datei, die ich bearbeite, kann ich überall einen Klammerausdruck einfügen, drücken C-x C-e, und lassen Sie sich ein Ergebnis im Minipuffer anzeigen (oder, wenn Sie in einem Lisp programmieren, im REPL).
Viele andere Sprachen bieten Konsolenschnittstellen oder REPLs, aber diese sind normalerweise separate Funktionen der Sprache und nicht ein angenommen Interaktionsmodus. Ich gebe zu, dass dies eine oberflächliche Beobachtung ist, aber man könnte dies als „skriptzentrierten“ oder „REPL-zentrierten“ Ansatz zur Benutzerinteraktion umformulieren. Stellen Sie sich vor, Sie lernen eine neue Programmiersprache. Ein „skriptzentrierter“ Ansatz würde Ihnen schnell zeigen, wie Sie ein „Hallo-Welt“-Programm von einem Terminal (oder einer IDE) aus ausführen, während ein „REPL-zentrierter“ Ansatz Ihnen schnell zeigen würde, wie Sie in ein REPL wechseln und die erforderlichen Ausdrücke auswerten, um den „Hallo-Welt“-Effekt zu erzielen.
Anders ausgedrückt: Ein „skriptzentrierter“ Ansatz trennt konzeptionell die Bearbeitungs- und Auswertungszyklen, während der „REPL-zentrierte“ Ansatz auf einen einheitlichen Fluss aus Ausdruck, Auswertung und Feedback ausgelegt ist. Jede Methode hat ihre Stärken und Schwächen, aber für Prototyping und Experimente ist das Gefühl, „im Code zu sein“, das durch die Auswertung direkt am Cursor entsteht, kaum zu übertreffen. In Emacs und für Sprachen der Lisp-Familie ist dies im Allgemeinen die erwartete Interaktionsmethode.
Wie können wir das demonstrieren? Nun, mein Kollege Mark habe ein Tutorial geschrieben beim Einrichten eines Keras-Trainingsjobs im Februar. Die Software wurde seitdem aktualisiert, daher erstellen wir eine aktualisierte Version dieses Jobs. Anstelle von reinem Python verwenden wir jedoch Hylang, was im Grunde ein Lisp für den Python-Interpreter.

Vorausgesetzt, Sie haben eine aktuelle Version von Emacs (sagen wir, Version 24 und höher) mit dem Emacs Paketmanager einrichten, möchten Sie installieren er-Mode (M-x package-install RET hy-mode RET), und eines der vielen Lispy-Paren-Pakete, zB paredit, smartparens, lispelig.
In unserer neuen Datei cifar10_cnn.hy, stellen Sie sicher, dass Sie eingeschaltet sind Hy Modus. Dann verwenden M-x inferior-lisp um ein Hy-Repl zu starten! Scrollen Sie nach unten, um eine Videodemonstration der Emacs-Interaktion anzuzeigen.

1. Kümmern wir uns zunächst um die Importe 

1.1 Python

von __future__ importiere print_function von keras.datasets importiere cifar10 von keras.models importiere Sequential von keras.layers.core importiere Dense, Dropout, Aktivierung, Flatten von keras.layers.convolutional importiere Convolution2D, MaxPooling2D von keras.optimizers importiere SGD, Adadelta, Adagrad von keras.utils importiere np_utils, generic_utils von six.moves importiere range

1.2 Umschreiben in hy:

(importieren Sie [__future__ [print_function]] [keras.datasets [cifar10]] [keras.models [Sequential]] [keras.layers.core [Dense Dropout Activation Flatten]] [keras.layers.convolutional [Convolution2D MaxPooling2D]] [keras.optimizers [SGD Adadelta Adagrad]] [keras.utils [np_utils generic_utils]] [six.moves [range]] [numpy :as np])

51 Wörter zu 39. Nicht schlecht für die Prägnanz!

2. Dann schreiben wir die Konstanten neu

2.1 Python

batch_size = 32 nb_classes = 10 nb_epoch = 100 # Eingabebildabmessungen img_rows, img_cols = 32, 32 # die CIFAR10-Bilder sind RGB img_channels = 3

2.2 Hy

(def batch_size 32 nb_classes 10 nb_epoch 100 ;; Eingabebildabmessungen img_rows 32 img_cols 32 ;; die CIFAR10-Bilder sind RGB img_channels 3)

Hylang lässt sich inspirieren von Clojure, erlaubt aber im Gegensatz zu Clojure mehrere Variablen def-s standardmäßig. In diesem Fall ist es ziemlich praktisch.

3. Die Funktionen

Note that the input_shape Die Argumentreihenfolge hat sich seit der vorherigen Version geändert von (channels, rows, columns) zu (rows, columns, channels)

3.1 Python

def load_dataset(): # die Daten, gemischt und aufgeteilt zwischen Trainings- und Testsätzen (X_train, y_train), (X_test, y_test) = cifar10.load_data() print('X_train shape:', X_train.shape) print(X_train.shape[0], 'train samples') print(X_test.shape[0], 'test samples') # Klassenvektoren in binäre Klassenmatrizen umwandeln Y_train = np_utils.to_categorical(y_train, nb_classes) Y_test = np_utils.to_categorical(y_test, nb_classes) X_train = X_train.astype('float32') X_test = X_test.astype('float32') X_train /= 255 X_test /= 255 return X_train, Y_train, X_test, Y_test def make_network(): Modell = Sequential() model.add(Convolution2D(32, 3, 3, border_mode='same', input_shape=(img_rows, img_cols, img_channels))) model.add(Aktivierung('relu')) model.add(Convolution2D(32, 3, 3)) model.add(Aktivierung('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25)) model.add(Convolution2D(64, 3, 3, border_mode='same')) model.add(Aktivierung('relu')) model.add(Convolution2D(64, 3, 3)) model.add(Aktivierung('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25)) model.add(Flatten()) model.add(Dense(512)) model.add(Aktivierung('relu')) model.add(Dropout(0.5)) model.add(Dense(nb_classes)) model.add(Aktivierung('softmax')) return model def train_model(model, X_train, Y_train, X_test, Y_test): sgd = SGD(lr=0.01, Zerfall=1e-6, Impuls=0.9, Nesterov=Wahr) model.compile(Verlust='kategoriale_Kreuzentropie', Optimierer=sgd) model.fit(X_train, Y_train, nb_epoch=nb_epoch, Batchgröße=Batchgröße, Validierungsaufteilung=0.1, Genauigkeit anzeigen=Wahr, ausführlich=1) print('Testen...') res = model.evaluate(X_test, Y_test, batch_size=batch_size, ausführlich=1, show_accuracy=True) drucken('Testgenauigkeit: {0}'.format(res[1])) def save_model(model): model_json = model.to_json() öffnen('cifar10_architecture.json', 'w').schreiben(model_json) model.save_weights('cifar10_weights.h5', überschreiben=True)

3.2 Hy

Im folgenden Code hätten wir die Variable Destrukturierung für TRAIN und TEST mit einem einzigen Schritt wie folgt:
(let [ [[X-train y-train] [X-test y-test]] (cifar10.load_data) ] )

 

(defn load-dataset [] ;; die Daten, gemischt und zwischen Trainings- und Testsätzen aufgeteilt (let [[TRAIN TEST] (cifar10.load_data) [X-train y-train] TRAIN [X-test y-test] TEST ;; Klassenvektoren in binäre Klassenmatrizen umwandeln Y-train (np_utils.to_categorical y-train nb_classes) Y-test (np_utils.to_categorical y-test nb_classes)] (print "OK") (print "X_train shape: " X-train.shape) (print (get X-train.shape 0) "train samples") (print (get X-test.shape 0) "test samples") ;; hy Tupelnotation (, X-train Y-train X-test Y-test))) (defn make-network [] (doto (Sequential) (.add (Convolution2D 32 3 3 :border_mode "same" :input_shape (, img_rows img_cols img_channels))) (.add (Aktivierung "relu")) (.add (Convolution2D 32 3 3)) (.add (Aktivierung "relu")) (.add (MaxPooling2D :pool_size (, 2 2))) (.add (Dropout 0.25)) (.add (Convolution2D 64 3 3 :border_mode "same")) (.add (Aktivierung "relu")) (.add (Convolution2D 64 3 3)) (.add (Aktivierung "relu")) (.add (MaxPooling2D :pool_size (, 2 2))) (.add (Dropout 0.25)) (.add (Flatten)) (.add (Dense 512)) (.add (Aktivierung "relu")) (.add (Dropout 0.5)) (.add (Dichte nb_classes)) (.add (Aktivierung "softmax")))) (defn train-model [Modell X-Train Y-Train X-Test Y-Test] (let [sgd (SGD :lr 0.01 :Zerfall 1e-6 :Momentum 0.9 :nesterov true)] (doto model (.compile :Verlust "kategoriale Kreuzentropie" :Optimierer sgd) (.fit X-Train Y-Train :nb_Epoche nb_Epoche :Batchgröße Batchgröße :Validierungsaufteilung 0.1 :Genauigkeit anzeigen true :ausführlich 1))) (print "Testen...") (let [res (Modell.evaluate X-Test Y-Test :Batchgröße Batchgröße :ausführlich 1 :Genauigkeit anzeigen true)] (-> "Testgenauigkeit {}" (.format (get res 1)) (drucken)))) (defn save-model [Modell] (mit [ofile (öffnen Sie "cifar10_architecture.json" "w")] (ofile.write (model.to_json))) (model.save_weights "cifar10_weights.h5" :überschreiben Sie true))

Beachten Sie, wie die Verwendung doto hier vereinfacht die wiederholte Zuweisung erheblich. Da Ausdrücke die endgültige Form in ihnen auswerten, die durch doto, unser Modellaufbau in make-network erfordert nicht einmal einen Variablennamen.
Hylang unterstützt auch die praktischen Threading-Makros (->) a la Clojure, wodurch es einfach ist, Anweisungen miteinander zu verketten; in diesem Beispiel fädeln wir einfach die Formatzeichenfolge durch die .format Funktion, und drucken Sie es dann aus.

4. Der Hauptführungsblock

4.1 Python

wenn __name__ == '__main__': X_train, Y_train, X_test, Y_test = load_dataset() model = make_network() train_model(model, X_train, Y_train, X_test, Y_test) save_model(model)

4.2 Hy

(when (= --name-- "__main__") ;; zur Reproduzierbarkeit hinzugefügt (np.random.seed 1) (let [[X-train Y-train X-test Y-test] (load-dataset)] (doto (make-network) (train-model X-train Y-train X-test Y-test) (save-model))))

5. Ein kurzes Video

In diesem kurzen Video können Sie sehen, wie man das resultierende hylang Datei in Emacs und führen Sie es durch die hy REPL, Auswertung der Aussage auf Punkt (die angezeigt wird als ^X ^E im Tasten-Overlay) und ansonsten zwischen REPL und Editierpuffer hin- und herwechseln.
Gegen Ende können Sie sehen, wie ich das verpasst habe numpy Import, fügte den Import zum (import ...) Formular und wertete das gesamte Importformular neu aus. Ich bewegte den Cursor an das Ende des Formulars und verwendete eval-last-sexpum den Ausdruck auszuwerten, hätte aber auch Ctrl Alt x or lisp-eval-defun, wodurch der Ausdruck der obersten Ebene um den Cursor herum ausgewertet wird.
Da load-dataset und make-network keine Argumente annehmen, ist es praktisch, die Funktionskörper in eine let or doto Ausdruck (oder unten stehende Formular), wiederholtes Auswerten des Blocks am Punkt, Überprüfen der REPL-Ausgabe und, wenn zufrieden, Umschließen des let Block in einen defn Form.

6. Ausführen auf der Plattform

Das Video stoppt direkt nach dem eigentlichen Modelltraining, da mein Computer keine gute GPU hat und das Training sehr lange dauern würde. Stattdessen installieren wir es zurück auf der Rescale-Plattform, um es abzuschließen. Zuerst installieren wir die hy Compiler durch Ausführen

 

pip install git+https://github.com/hylang/hy.git

dann einfach anrufen hy cifar10_cnn.hy um die Ausgabe des vorherigen Beispiels von Mark zu replizieren.
(Beachten Sie, dass wir in diesem Beispiel die neueste Version (Version 0.11.0, Commit 0abc218) von Hylang direkt von GitHub ausführen.) Wenn Sie Hy mit pip install hy Möglicherweise wird eine ältere Zuordnung verwendet. let/with Syntax.
Ein lauffähiges Beispiel finden Sie werden auf dieser Seite erläutert. Darüber hinaus finden Sie eine greifbare Version dieses Beitrags auf github.

7. Entschuldigen Sie das Wortspiel

Aber ist es Zeit für hy? Wie Sie sehen, hat die REPL-Integration in Emacs ihre Tücken. Das Debuggen von Fehlern aus Deep Stack Traces ist aufgrund der geringeren Unterstützung durch ausgereifte Debugging-Tools etwas anspruchsvoller. Wenn Sie jedoch gerne mit Lisps arbeiten und mit dem Python-Ökosystem arbeiten möchten oder müssen, ist hy ein funktionales, leistungsstarkes und angenehmes Tool für Webentwicklung, maschinelles Lernen oder einfaches Textparsing. Habe ich erwähnt, dass Sie sogar kombinieren können? hy Dateien und py Dateien?