[PYTHON] Dinge, die Sie bei der Stapelvorhersage mit der GCP ML Engine beachten sollten

Was ist in diesem Artikel zu tun?

Wie im folgenden offiziellen Dokument gezeigt, wird bei der Durchführung der Vorhersage mit Charge eine verteilte Verarbeitung auf der Seite der ML-Engine durchgeführt, und die Reihenfolge der Eingabe und Ausgabe stimmt nicht überein. Sie müssen also einen sogenannten ** Instanzschlüssel ** verwenden, um die Ein- und Ausgänge eindeutig zu machen.

Mit anderen Worten, es ist notwendig, den Instanzschlüssel explizit als Eingabe zu schreiben, aber bei der Verarbeitung der Vorhersage muss er so implementiert werden, dass er zusammen mit dem vorhergesagten Wert ausgegeben wird, ohne etwas zu tun. Ich habe nicht sorgfältig geschrieben, wie man es in das offizielle Dokument umsetzt, und ich hatte nicht viel japanische Literatur, deshalb werde ich es in Qiita veröffentlichen, einschließlich eines Memorandums.

AI Platform verwendet verteilte Verarbeitung, um Stapelvorhersagejobs auszuführen. Das heißt, die Daten werden auf einen beliebigen Cluster virtueller Maschinen verteilt und in einer unvorhersehbaren Reihenfolge verarbeitet. Sie müssen einen Instanzschlüssel definiert haben, damit Sie die zurückgegebenen Vorhersagen mit der Eingabeinstanz abgleichen können. Der Instanzschlüssel ist ein Wert, den jede Instanz hat und der für eine Reihe von Dateninstanzen eindeutig ist. Der einfachste Schlüssel ist die Indexnummer.

https://cloud.google.com/ml-engine/docs/prediction-overview?hl=ja#instance_keys

Zielgruppe

Sprache und Rahmen

Annahme

Ich habe zwei Implementierungsmethoden ausprobiert.

  1. Schließen Sie den Schätzer mit der Funktion forward_features ein und übergeben Sie den Spaltennamen als Instanzschlüssel als Zeichenfolge an das Argument (wahrscheinlich ist diese Methode eine einfache Methode).
  2. Wie Sie den vorhergesagten Wert und die Ausgabe des Instanzschlüssels aus dem Modell zusammenfassen, um die endgültige Ausgabe zu erhalten

Dieses Mal gehen wir davon aus, dass die Bewertung aus userId und movieId unter Verwendung des MovieLens-Datasets (Bewertung.csv) vorhergesagt wird. Verwenden Sie für den Indexschlüssel die Indexnummer der Daten, wie im offiziellen Dokument beschrieben.

userId movieId rating key
1 1 1.5 1
1 2 2.5 2
2 1 3.5 3
2 2 4.5 4

Methode 1: Umschließen Sie den Schätzer mit der Funktion forward_features

Erstens [forward_features function] Schauen Sie sich die Beschreibung an (https://github.com/tensorflow/tensorflow/blob/r1.8/tensorflow/contrib/estimator/python/estimator/extenders.py#L143). Ich schreibe über Batch Prediction. (Wie eingangs erwähnt, gibt es auch eine Erklärung, dass die Ausgabereihenfolge nicht garantiert ist, sodass eine erneute Verbindung mit der Eingabetaste erforderlich ist.)

def forward_features(estimator, keys=None):
  """Forward features to predictions dictionary.

  In some cases, user wants to see some of the features in estimators prediction
  output. As an example, consider a batch prediction service: The service simply
  runs inference on the users graph and returns the results. Keys are essential
  because there is no order guarantee on the outputs so they need to be rejoined
  to the inputs via keys or transclusion of the inputs in the outputs.

Das Modell, das ich dieses Mal geschrieben habe, ist ein einfaches Modell wie folgt. Wie Sie der Abbildung entnehmen können, ist der Instanzschlüssel der Eingabeebene des Modells mit keinem Knoten verbunden. Bei der Implementierung von forward_features wird jedoch der Instanzschlüssel in die Ausgabe des Schätzers aufgenommen, sodass ich denke, dass er dort verbunden wird. (Wahrscheinlich hier) Bei der Implementierung des Modells ist es nicht besonders schwierig, nur den Schlüssel explizit zu schreiben.

スクリーンショット 2019-12-18 9.25.30.png

MAX_MOVIES=100000
MAX_USERS=100000
DIM_EMBEDDING=10

def get_model():
    key = tf.keras.layers.Input(shape=(), name='key', dtype='int32')
    
    w_inputs = tf.keras.layers.Input(shape=(1,), dtype='int32', name='movieId')
    w = tf.keras.layers.Embedding(MAX_MOVIES, DIM_EMBEDDING, name='movie')(w_inputs)
    
    u_inputs = tf.keras.layers.Input(shape=(1,), dtype='int32', name='userId')
    u = tf.keras.layers.Embedding(MAX_USERS, DIM_EMBEDDING, name='user')(u_inputs)
    
    o = tf.keras.layers.Multiply()([w, u])
    o = tf.keras.layers.Dropout(rate=0.5)(o)
    o = tf.keras.layers.Flatten()(o)
    o = tf.keras.layers.Dense(10, activation='relu')(o)
    o = tf.keras.layers.Dense(1, name='predictions')(o)
        
    model = tf.keras.Model(inputs=[w_inputs, u_inputs, key], outputs=o)
    model.summary()
    return model

Die Funktion "forward_features" wird in der Hauptfunktion ("train_and_evaluate") verwendet, die das Modell kompiliert / einen Schätzer aus dem Modell erstellt.

def train_and_evaluate(outdir, train_step):
    tf.logging.set_verbosity(v=tf.logging.INFO)
    model = get_model()
    model.compile(optimizer='adam', loss="mae", metrics=["mae"])

    estimator = tf.keras.estimator.model_to_estimator(keras_model = model,
                                                     model_dir = outdir,
                                                     config = tf.estimator.RunConfig(save_checkpoints_secs=100))

    train_spec = tf.estimator.TrainSpec(input_fn=lambda: read_dataset(filename='train.csv', 
                                                                      mode=tf.estimator.ModeKeys.TRAIN),
                                       max_steps=train_step)
    
    exporter = tf.estimator.LatestExporter(name='exporter',
                                          serving_input_receiver_fn=serving_input_fn)
    
    #Forward Estimator hier_Eingehüllt in Funktionen
    estimator = tf.contrib.estimator.forward_features(estimator, 'key')
    
    eval_spec = tf.estimator.EvalSpec(input_fn=lambda: read_dataset(filename='test.csv',
                                                                   mode=tf.estimator.ModeKeys.EVAL),
                                     exporters=exporter,
                                     steps=None,
                                     throttle_secs=15)
    
    tf.estimator.train_and_evaluate(estimator, train_spec, eval_spec)

Der vorhergesagte Wert ist seltsam, weil ich im Training nicht viele Daten eingegeben habe. Sie können sehen, dass der Instanzschlüssel so zurückgegeben wird, wie er mit dem vorhergesagten Wert ist. スクリーンショット 2019-12-18 9.27.22.png

Es gibt eine Beschreibung in dieser Ausgabe, aber im Tensorflow 2-System ist der Contrib.estimator, zu dem forward_features gehört, in der Ausgabe veraltet Möglicherweise müssen Sie Ihre eigene Funktion feature_forward wie beschrieben definieren.

Methode 2: Konzentrieren Sie den vom Diagramm und dem Instanzschlüssel ausgegebenen Wert

Wie in der folgenden Abbildung gezeigt, ist der Wert, der von der letzten Dichte ausgegeben wird, der vorhergesagte Wert, aber der Instanzschlüssel ist unverändert und wird als endgültige Ausgabe verwendet. Da der Instanzschlüssel als Skalarwert eingeht, wird er auch umgeformt, um ihn zu formen. Auf diese Weise ist es möglich, den Instanzschlüssel ohne Verarbeitung auszugeben.

スクリーンショット 2019-12-17 13.48.02.png

MAX_MOVIES=100000
MAX_USERS=100000
DIM_EMBEDDING=10

def get_model():
    key_raw = tf.keras.layers.Input(shape=(), name='key', dtype='int32')
    key = tf.keras.layers.Reshape((1,), input_shape=(), dtype='int32')(key_raw)
    
    w_inputs = tf.keras.layers.Input(shape=(1,), dtype='int32', name='movieId')
    w = tf.keras.layers.Embedding(MAX_MOVIES, DIM_EMBEDDING, name='movie')(w_inputs)
    
    u_inputs = tf.keras.layers.Input(shape=(1,), dtype='int32', name='userId')
    u = tf.keras.layers.Embedding(MAX_USERS, DIM_EMBEDDING, name='user')(u_inputs)
    
    o = tf.keras.layers.Multiply()([w, u])
    o = tf.keras.layers.Dropout(rate=0.5)(o)
    o = tf.keras.layers.Flatten()(o)
    o = tf.keras.layers.Dense(10, activation='relu')(o)
    o = tf.keras.layers.Dense(1, name='predictions')(o)
    
    #Hier konzentrieren wir uns auf die Vorhersage und den Instanzschlüssel
    #Da der Instanzschlüssel vom Typ int ist, lasse ich ihn zwangsweise schweben, um dem Typ zu entsprechen
    pred = tf.keras.layers.Concatenate()([o, tf.cast(key, tf.float32)])
    
    model = tf.keras.Model(inputs=[w_inputs, u_inputs, key_raw], outputs=pred)
    model.summary()
    return model

Bei dieser Methode müssen Sie jedoch eine benutzerdefinierte Verlustfunktion schreiben, da der Instanzschlüssel bei der Berechnung des Verlusts berücksichtigt wird. Ich denke nicht, dass es so schwierig ist, weil Sie nur den Wert der Vorhersage in der Funktion wie unten gezeigt erhalten müssen.

def my_rmse(y_true, y_pred):
    return tf.keras.backend.sqrt(tf.keras.backend.mean(
        tf.keras.backend.square(y_pred[1][0] - y_true))) # y_pred[1][0]Um nur Vorhersage mit zu bekommen

In Bezug auf andere Implementierungen wurden keine weiteren Änderungen vorgenommen. Wenn Sie die Vorhersage wie unten gezeigt versuchen, wird sie wie folgt ausgegeben.

スクリーンショット 2019-12-18 9.02.56.png

Zusammenfassung

Ich habe diesmal zwei Methoden ausprobiert, aber der Unterschied besteht darin, dass es fast keinen Unterschied im Verarbeitungsinhalt gibt, je nachdem, ob Sie die auf der Tensorflow-Seite vorbereitete Funktion (forward_features) verwenden oder die Diagrammstruktur selbst schreiben. Ich werde. (Ersteres wird natürlich empfohlen) Ich hatte nicht viel japanische Literatur über Batch Prediction auf ML Engine, also hoffe ich, dass es denen hilft, die Probleme mit der gleichen Sache haben.

Recommended Posts

Dinge, die Sie bei der Stapelvorhersage mit der GCP ML Engine beachten sollten
Beachten Sie Folgendes, wenn Sie Keras auf Ihrem Mac bereitstellen
Dinge, die Sie bei der Entwicklung von Crawlern in Python beachten sollten
Dinge, die Sie beim Kopieren von Python-Listen beachten sollten
Dinge, die Sie bei der Verarbeitung von Zeichenfolgen in Python2 beachten sollten
Dinge, die Sie bei der Verarbeitung von Zeichenfolgen in Python 3 beachten sollten
Vorsichtsmaßnahmen bei der Verwendung von Python mit AtCoder
Dinge, die Sie bei der Verwendung von CGI mit Python beachten sollten.
Beachten Sie Folgendes, wenn Sie mit ndarray einen Zeilenvektor in einen Spaltenvektor konvertieren
Dinge, die Sie bei der Verwendung von Python beachten sollten, wenn Sie MATLAB verwenden
Beachten Sie Folgendes, wenn Sie automatisierte Tools für die Werkstatt in Python erstellen
Erstellen Sie die Keras AI Prediction Engine in 1 Stunde mit GCP
Beachten Sie beim Initialisieren einer Liste in Python