Wenn Sie ein Modell mit Core ML Tools konvertieren, möchten Sie möglicherweise Ebenen hinzufügen und Berechnungen dazwischen einfügen oder einen Teil der Ebene ausschneiden. In diesem Artikel wird jedoch erläutert, wie dies funktioniert.
Da Core ML Tools nur wenige Dokumente und wenig Informationen im Internet hat, muss ich sie beim Lesen des Quellcodes nachschlagen, aber ich denke, dass das Bearbeiten von Ebenen ein häufiger Anwendungsfall bei der Konvertierung in Core ML ist. Ich hoffe dieser Artikel hilft Ihnen.
Fügen wir als Modellfall eine Umformung hinzu, um die Ausgabeform des Modells (19) (1,1,19) zu erhalten.
Es ist fast bedeutungslos, weil ich nur Dimensionen hinzufüge, aber ich mache das, weil ich es zu einem einfachen Fall machen möchte.
Das zu verwendende Modell ist eines, das das Ergebnis der Addition von zwei einstelligen Zahlen vorhersagt (klassifiziert). Das Klassifizierungsergebnis besteht aus 19 Sequenzen. Dies liegt daran, dass das Hinzufügen von einstelligen Zahlen insgesamt 19 Arten von Klassifizierungsproblemen von 0 bis 18 ergibt.
In der Abbildung sieht es so aus.
Dieses Modell ist das gleiche wie das im vorherigen Artikel verwendete. Im vorherigen Artikel haben wir die Ausgabe bis zum Labelnamen angegeben, aber dieses Mal werden wir einfach 19 Wahrscheinlichkeiten so ausgeben, wie sie sind.
Fügen wir nun die Ebene "Umformen" hinzu. Arbeiten Sie an Google Colaboratory.
Den vollständigen Code für diese Arbeit finden Sie hier. https://gist.github.com/TokyoYoshida/2fada34313385d63b666253490b5f3f4
** 1. Keras-Modell laden **
Ich werde ein mit Keras hergestelltes Modell verwenden. Der Modellerstellungsteil wird weggelassen, da er im vorherigen Artikel enthalten ist.
notebook
from keras.models import load_model
keras_model = load_model('my_model.h5')
** 2. In CoreML konvertieren **
In CoreML konvertieren. Ich habe diesmal kein Etikett angebracht, also konvertiere ich es einfach so, wie es ist.
notebook
from coremltools.converters import keras as converter
mlmodel = converter.convert(keras_model)
** 3. Mit Builder laden **
Laden Sie es in den Neural Network Builder in den Core ML Tools.
notebook
import coremltools
spec = coremltools.utils.load_spec(coreml_model_path)
builder = coremltools.models.neural_network.NeuralNetworkBuilder(spec=spec)
Lassen Sie uns die Modellinformationen anzeigen. Daraus können Sie ersehen, dass die Ausgabe des Modells als output1 bezeichnet wird und die Form 19 ist.
notebook
spec.description.output
#Ausgabeergebnis
# [name: "output1"
# type {
# multiArrayType {
# shape: 19
# dataType: DOUBLE
# }
# }
# ]
Zeigt Ebeneninformationen an.
notebook
builder.layers
#Ausgabe
# ['dense_4',
# 'dense_4__activation__',
# 'dense_5',
# 'dense_5__activation__',
# 'dense_6',
# 'activation_18']
Das Ziel ist diesmal activity_18, die Ausgabeschicht. Formieren Sie die Ausgabe dieser Ebene neu.
** 4. Rehape-Ebene hinzufügen **
NeuralNetworkBuilder verfügt über eine Methode namens add_reshape, mit der Sie eine Umformebene hinzufügen können.
~~ Es ist wichtig anzumerken, dass ich mit dem Builder dem Builder intuitiv eine Ebene hinzufügen kann, die das ursprüngliche Modell darstellt, aber diese Methode funktioniert nicht. ~~ (Hinzugefügt am 27. Oktober 2020, ich habe festgestellt, dass ich dem Builder eine Ebene hinzufügen kann, die das ursprüngliche Modell darstellt, also werde ich es korrigieren.)
Fügen wir beispielsweise die Umformungsebene so hinzu, wie sie dem zuvor im Builder geladenen Modell entspricht.
notebook
reshape = builder.add_reshape(name='Reshape', input_name='activation_18', output_name='output', target_shape=(1,1,19), mode=0)
Wenn ich dies mit Xcode lese, erhalte ich diesen Fehler.
Xcode-Fehler
There was a problem decoding this CoreML document
validator error: Layer 'Reshape' consumes an input named 'activation_18' which is not present in this network.
Wenn ich versuche, eine CoreML-Inferenz für Python durchzuführen, wird folgende Fehlermeldung angezeigt:
Python-Fehler
RuntimeError: Error compiling model: "Error reading protobuf spec. validator error: Layer 'Reshape' consumes an input named 'activation_18' which is not present in this network.".
Es fiel mir schwer, es im Internet zu finden, aber ich bin mir sicher, dass es Menschen gibt, die es schwer haben, dasselbe zu tun.
Der Grund für diesen Fehler ist, dass ich input_name = 'activity_18'
gesetzt habe. Hier müssen Sie den Namen der Eingabe oder Ausgabe angeben, die im ursprünglichen Modell in "builder.spec.description" angezeigt wird.
~~ Verwenden Sie zur Umgehung dieses Problems NeuralNetworkBuilder, um ein vollständiges Modell mit nur einer Ebene zu erstellen und es dem ursprünglichen Modell hinzuzufügen. ~~ (Korrigiert am 27. Oktober 2020) Wenn das Argument input_name von add_reshape mit dem Argument output_name des ursprünglichen Modells übereinstimmt, können Sie die Ebenen erfolgreich verbinden.
Fügen Sie Ihrem Modell eine Umformebene hinzu. Eingabe gibt die Ausgabe des Originalmodells an, dh "Ausgabe1". Ich hatte das Gefühl, dass dies die Eingabe des neuen Modells "input2" war, aber es scheint, dass die Ausgabe des ursprünglichen Modells und die Eingabe in die Umformebene nicht gut funktionieren. Ausgabe gibt die Ausgabe des neuen Modells "output2" an. target_shape gibt (1,1,19) an, welche Form Sie dieses Mal konvertieren möchten.
notebook
builder.add_reshape(name='Reshape', input_name='output1', output_name='output2', target_shape=(1,1,19), mode=0)
Sie haben jetzt ein Modell mit hinzugefügter Umformung.
Überprüfen Sie die Ebeneninformationen.
notebook
builder.layers
#Ausgabe
# ['dense_4',
# 'dense_4__activation__',
# 'dense_5',
# 'dense_5__activation__',
# 'dense_6',
# 'activation_18',
# 'Reshape']
** 5. Ändern Sie die Ausgabeinformationen des Modells **
Die Umformebene wurde am Ende des Modells hinzugefügt, dies ersetzte jedoch nur die letzte Ebene des Modells, und die Ausgabeinformationen des gesamten Modells haben sich nicht geändert.
Wenn Sie die Ausgabeinformationen als Test überprüfen, können Sie feststellen, dass sie immer noch (19) anstelle der erwarteten Form (1,1,19) sind.
notebook
spec.description.output
# [name: "output1"
# type {
# multiArrayType {
# shape: 19
# dataType: DOUBLE
# }
# }
# ]
Das Ändern der Ausgabeinformationen des Modells ist ebenfalls sehr eigenartig und führt zu einem Fehler, wenn Sie versuchen, sie builder.spec.description.output [0] zuzuweisen. Geben Sie es daher beim Poppen oder Hinzufügen an.
notebook
//Löschen Sie eine Ausgabeinformation. Da diesmal nur eine Ausgabeinformation vorhanden war, verschwinden die Ausgabeinformationen
builder.spec.description.output.pop()
//Fügen Sie eine Ausgabeinformation hinzu
builder.spec.description.output.add()
//Geben Sie Attribute der Ausgabeinformationen an
output = builder.spec.description.output[0]
output.name = "output2"
output.type.multiArrayType.dataType = coremltools.proto.FeatureTypes_pb2.ArrayFeatureType.ArrayDataType.Value('DOUBLE')
//Als Forminformation(1,1,19)Einstellen
output.type.multiArrayType.shape.append(1)
output.type.multiArrayType.shape.append(1)
output.type.multiArrayType.shape.append(19)
(Ergänzung) Im obigen Beispiel wurden die Informationen hinzugefügt, nachdem sie durch Löschen mit pop () und Hinzufügen mit add () bereinigt wurden. Es ist jedoch möglich, nur den Attributwert der ursprünglich vorhandenen Ausgabe direkt neu zu schreiben.
Schreiben Sie die Form beispielsweise wie folgt neu.
Beispiel für das Umschreiben der Form
builder.spec.description.output[0].type.multiArrayType.shape[0] = 100
(Ende der Ergänzung)
Wenn Sie die Ausgabeinformationen überprüfen, können Sie feststellen, dass die Einstellungen erfolgreich sind.
notebook
builder.spec.description.output
# [name: "output2"
# type {
# multiArrayType {
# shape: 1
# shape: 1
# shape: 19
# dataType: DOUBLE
# }
# }
# ]
** 6. Überprüfen Sie das Ausgabeergebnis des Modells mit Jupyter Notebook **
Überprüfen Sie das Ausgabeergebnis des Modells mit Jupyter Notebook, das auf einem Mac ausgeführt wird. Warum Jupyter Notebook auf Mac? Da das Back-End von Google Colaboratory jedoch Linux ist, kann auf CoreML nicht geschlossen werden, und es kann nicht bestätigt werden, ob das Modell ordnungsgemäß funktioniert.
Sie können mit Xcode schließen, aber Xcode kann Ihnen beim Lesen eines seltsamen Modells einen Fehler geben, aber es kann auch den folgenden Fehler beim Erstellen löschen.
Xcode-Fehler
Command CoreMLModelCompile failed with a nonzero exit code
Wenn Sie einen solchen Fehler erhalten, sollten Sie ihn in Jupyter Notebook ausführen, um die Details des Fehlers anzuzeigen.
Starten Sie also Jupyter Notebook.
Hier ist der vollständige Code. https://gist.github.com/TokyoYoshida/632b4c8070aa6c937539e4ae261a2740
Geben Sie [2,3] als Eingabe für das Modell und versuchen Sie, die Inferenz durchzuführen.
JupyterNoteBook
coreml_model_path= "my_model_with_builder.mlmodel"
import coremltools
spec = coremltools.utils.load_spec(coreml_model_path)
builder = coremltools.models.neural_network.NeuralNetworkBuilder(spec=spec)
mlmodel = coremltools.models.MLModel(spec)
mlmodel.predict({'input1': np.array([2.0,3.0])})
# {'output2': array([[[2.56040733e-21, 7.25779588e-15, 1.99342376e-10, 1.11184195e-09,
# 5.92091055e-05, 9.99939799e-01, 9.72097268e-07, 1.13292452e-14,
# 4.43997455e-23, 5.00404492e-33, 0.00000000e+00, 0.00000000e+00,
# 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,
# 0.00000000e+00, 0.00000000e+00, 0.00000000e+00]]])}
Da es sich bei diesem Modell um ein Modell handelt, das zwei Elemente hinzufügt, beträgt die Wahrscheinlichkeit für das fünfte Element fast 1, sodass Sie sehen können, dass es korrekt abgeleitet werden kann.
Da das Ausgabearray "[[[19 Arrays mit Wahrscheinlichkeit]]]" ist, wird auch bestätigt, dass die Form wie beabsichtigt (1,1,19) ist. Ich kann es schaffen
** 7. Überprüfen Sie das Ausgabeergebnis des Modells mit Xcode & App **
Stellen Sie abschließend das Ausgabeergebnis des Modells auf Xcode und überprüfen Sie es mit der Anwendung.
Der vollständige Code ist hier. https://github.com/TokyoYoshida/CoreMLSimpleTest
ViewController.swift
let model = my_model_with_builder()
let inputArray = try! MLMultiArray([2,3])
let inputToModel = my_model_with_builderInput(input1: inputArray)
if let prediction = try? model.prediction(input: inputToModel) {
print(prediction.output2)
try! print(prediction.output2.reshaped(to: [19]))
}
// # Double 1 x 1 x 19 array
// # Double 19 vector
// # [2.422891379885771e-21,7.01752566646674e-15,1.959301054732521e-10,1.089580203839091e-09,5.933549255132675e-05,0.9999396800994873,9.530076567898504e-07,1.087061586308846e-14,4.16250629238845e-23,4.617410135639087e-33,1.401298464324817e-45,1.401298464324817e-45,1.401298464324817e-45,1.401298464324817e-45,1.401298464324817e-45,1.401298464324817e-45,0,0,0]
//
Sie können sehen, dass dies auch wie beabsichtigt ist. Die Wahrscheinlichkeitszahlen können leicht abweichen, aber keine Sorge, dies liegt an der Umschulung des Modells.
Ich habe den Vorgang nicht bestätigt, werde aber auch schreiben, wie die Ebene gelöscht wird.
Löschen Sie die Ebene.
notebook
layers = builder.spec.neuralNetwork.layers
#Holen Sie sich die zweite von der Rückseite der Ebene(activation_18)
item = layers[-2]
#Löschen Sie dieses Element
layers.remove(item)
Wenn Sie sich die Ebeneninformationen ansehen, können Sie sehen, dass sie gelöscht wurden.
notebook
for layer in layers:
print(layer.name)
# dense_4
# dense_4__activation__
# dense_5
# dense_5__activation__
# dense_6
# Reshape
Hinweis veröffentlicht regelmäßig Informationen zur iOS-Entwicklung. Folgen Sie uns daher. https://note.com/tokyoyoshida
Es wird auch auf Twitter gepostet. https://twitter.com/jugemjugemjugem
Recommended Posts