Wie würde man am besten eine Vorverarbeitungsschicht hinzufügen (z. B. subtrahieren und dividieren) in ein keras (v2.0.5) -Modell, so dass das Modell vollständig eigenständig ist Bereitstellung (möglicherweise in einer C++ - Umgebung). Ich habe versucht:Hinzufügen einer Vorverarbeitungsschicht zum Keras-Modell und Festlegen der Tensorwerte
def getmodel():
model = Sequential()
mean_tensor = K.placeholder(shape=(1,1,3), name="mean_tensor")
std_tensor = K.placeholder(shape=(1,1,3), name="std_tensor")
preproc_layer = Lambda(lambda x: (x - mean_tensor)/(std_tensor + K.epsilon()),
input_shape=im_shape)
model.add(preproc_layer)
# Build the remaining model, perhaps set weights,
...
return model
Dann woanders setzen Sie die mittlere/Std auf dem Modell. Ich fand die set_value Funktion versucht, so die folgenden:
m = getmodel()
mean, std = get_mean_std(..)
graph = K.get_session().graph
mean_tensor = graph.get_tensor_by_name("mean_tensor:0")
std_tensor = graph.get_tensor_by_name("std_tensor:0")
K.set_value(mean_tensor, mean)
K.set_value(std_tensor, std)
jedoch die set_value
nicht mit
AttributeError: 'Tensor' object has no attribute 'assign'
So set_value
nicht funktioniert (die begrenzten) docs vorschlagen würde. Was wäre der richtige Weg, dies zu tun? Holen Sie sich die TF-Sitzung, wickeln Sie den gesamten Trainingscode in eine with (session)
und verwenden Sie feed_dict? Ich hätte gedacht, dass es einen nativen keras Weg geben würde, Tensor-Werte zu setzen.
Statt einen Platzhalter verwenden Ich habe versucht, den Mittelwert/std auf Modellbau Einstellung entweder K.variable
oder K.constant
:
mean_tensor = K.variable(mean, name="mean_tensor")
std_tensor = K.variable(std, name="std_tensor")
Dies vermeidet set_value
Probleme. Obwohl ich merke, dass es funktioniert, wenn ich versuche, dieses Modell zu trainieren (was ich weiß, ist nicht besonders effizient, da Sie die Normalisierung für jedes Bild wiederholen), aber am Ende der ersten Epoche versagt der ModelCheckpoint Handler mit einem sehr tiefen Stapel Spur:
...
File "/Users/dgorissen/Library/Python/2.7/lib/python/site-packages/keras/models.py", line 102, in save_model
'config': model.get_config()
File "/Users/dgorissen/Library/Python/2.7/lib/python/site-packages/keras/models.py", line 1193, in get_config
return copy.deepcopy(config)
File "/usr/local/Cellar/python/2.7.12_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 163, in deepcopy
y = copier(x, memo)
...
File "/usr/local/Cellar/python/2.7.12_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 190, in deepcopy
y = _reconstruct(x, rv, 1, memo)
File "/usr/local/Cellar/python/2.7.12_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 343, in _reconstruct
y.__dict__.update(state)
AttributeError: 'NoneType' object has no attribute 'update'
Update 1:
ich habe auch versucht, einen anderen Ansatz. Trainieren eines Modells als normal, dann schreibe gerade ein zweites Modell, das die Vorverarbeitung tut:
# Regular model, trained as usual
model = ...
# Preprocessing model
preproc_model = Sequential()
mean_tensor = K.constant(mean, name="mean_tensor")
std_tensor = K.constant(std, name="std_tensor")
preproc_layer = Lambda(lambda x: (x - mean_tensor)/(std_tensor + K.epsilon()),
input_shape=im_shape, name="normalisation")
preproc_model.add(preproc_layer)
# Prepend the preprocessing model to the regular model
full_model = Model(inputs=[preproc_model.input],
outputs=[model(preproc_model.output)])
# Save the complete model to disk
full_model.save('full_model.hdf5')
Dies scheint bis zum save()
Aufruf zu arbeiten, die wie oben mit der gleichen tiefen Stack-Trace ausfällt. Vielleicht ist die Lambda
Schicht das Problem, aber juding von this issue die es scheint, sollte es ordnungsgemäß serialisieren.
Also insgesamt, wie ich eine Normalisierungsschicht an ein Keras-Modell anhängen, ohne die Fähigkeit zu serialisieren (und zu PB exportieren)?
Ich bin sicher, Sie können es funktionieren, indem Sie direkt auf TF (z. B. this thread oder tf.Transform), aber hätte gedacht, dass es in keras direkt möglich wäre.
Update 2:
So fand ich, dass der tiefe Stack-Trace, indem Sie
def foo(x):
bar = K.variable(baz, name="baz")
return x - bar
So definieren bar
innerhalb der Funktion anstelle von außen Rahmen der Erfassung vermieden werden könnte.
Ich habe dann gefunden, ich könnte auf der Festplatte speichern, konnte aber nicht von der Festplatte geladen werden. Es gibt eine Reihe von GitHub-Problemen.Ich habe die in #5396 angegebene Problemumgehung verwendet, um alle Variablen als Argumente zu übergeben, dies erlaubte mir dann zu speichern und zu laden.
Ich dachte, ich war fast da, ich fuhr mit meinem Ansatz von Update 1 über das Stapeln eines Vorverarbeitungsmodells vor einem trainierten Modell. Dies führte dann zu Model is not compiled
Fehlern. Arbeitete um diejenigen, aber am Ende habe ich es nie geschafft, die folgende Arbeit zu bekommen:
- Erstellen und trainieren ein Modell
- Speichern auf der Festplatte
- laden es, prepend eine Vorverarbeitung Modell
- Export der Modell auf der Festplatte als eine gefrorene pb Datei
- Legen sie das gefrorene pb von der Festplatte
- Wenden sie es auf einigen unsichtbaren Daten gestapelt
Ich habe es zu dem Punkt, wo es keine Fehler gab, aber konnte nicht die Normalisierung Tensoren durch die gefrorenen pb zu verbreiten. Nachdem zu viel Zeit auf diese verbrachte ich gab dann auf und wechselte zu dem etwas weniger elegant Ansatz:
- ein Modell bauen mit der Vorverarbeitung in dem Modell von Anfang an, sondern auf einen No-op (Mittelwert = 0, std = 1)
- Trainieren Sie das Modell, erstellen Sie ein identisches Modell, aber diesmal mit den richtigen Werten für mean/std.
- Übertragen Sie die Gewichte
- Export und das Modell
All diese nun vollständig funktioniert wie erwartet pb einzufrieren. Kleiner Aufwand für das Training, aber für mich vernachlässigbar.
Noch nicht herausgefunden, wie man den Wert einer Tensor-Variable in keras setzen würde (ohne die Ausnahme assign
zu erhöhen), aber kann jetzt ohne es tun.
Wird @ Daniels Antwort akzeptieren, da sie mich in die richtige Richtung gebracht hat.
Verwandte Frage:
Wenn die Operation fest ist (nichts zu lernen) und sich vor der ersten Schicht befindet, sollten Sie die Operation möglicherweise direkt in den Eingabedaten ausführen, bevor Sie die Daten Ihrem Modell übergeben. Das würde Ihnen ersparen, wenn Sie während des Trainings zusätzliche unnötige Berechnungen durchführen müssen. –
Haben 'mean_tensor' und' std_tensor' dieselbe "Batchgröße" wie X? Dies kann die Antwort erheblich ändern ... –
@Daniel Dies ist ein leicht vereinfachtes Szenario. Ich ignoriere jetzt den Overhead für das Training, aber Sie könnten sich vorstellen, diese Schicht auf ein Modell zu kleben, das in Produktion geht, und Sie würden auf das gleiche Problem stoßen. Es gibt keine Formabweichungsfehler, wenn ich die Tensoren als Konstanten definiere. Ansonsten bekomme ich den no attribute error wie beschrieben. – dgorissen