[PYTHON] Points à garder à l'esprit lors de la prédiction par lots avec GCP ML Engine

Que faire dans cet article

Comme indiqué dans le document officiel ci-dessous, lors de l'exécution de la prédiction avec Batch, le traitement distribué est effectué du côté de ML Engine et l'ordre d'entrée et de sortie ne correspond pas. Vous devez donc utiliser quelque chose appelé une ** clé d'instance ** pour rendre les entrées et les sorties uniques.

En d'autres termes, il est nécessaire d'écrire explicitement la clé d'instance en entrée, mais dans le traitement de Prediction, elle doit être implémentée de sorte qu'elle soit sortie avec la valeur prédite sans rien faire. Je n'ai pas écrit soigneusement comment l'implémenter dans le document officiel, et je n'avais pas beaucoup de littérature japonaise, donc je la posterai sur qiita avec un mémorandum.

AI Platform utilise le traitement distribué pour exécuter des tâches de prédiction par lots. Autrement dit, les données sont distribuées sur n'importe quel cluster de machines virtuelles et traitées dans un ordre imprévisible. Vous devez avoir une clé d'instance définie pour pouvoir faire correspondre les prédictions renvoyées avec l'instance d'entrée. La clé d'instance est une valeur que chaque instance possède et est unique dans un ensemble d'instances de données. La clé la plus simple est le numéro d'index.

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

Public cible

Langage et cadre

supposition

J'ai essayé deux méthodes de mise en œuvre.

  1. Enveloppez l'estimateur avec la fonction forward_features et passez le nom de la colonne comme clé d'instance sous forme de chaîne de caractères à l'argument (probablement cette méthode est une méthode simple)
  2. Comment concater la valeur prédite et la sortie de clé d'instance du modèle pour créer la sortie finale

Cette fois, nous partirons de l'hypothèse que l'évaluation est prédite à partir de userId et movieId en utilisant l'ensemble de données MovieLens (rating.csv). Pour la clé d'index, utilisez le numéro d'index des données tel que décrit dans le document officiel.

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

Méthode 1: Enveloppez l'estimateur avec la fonction forward_features

Premièrement, [fonction forward_features] Jetez un œil à la description (https://github.com/tensorflow/tensorflow/blob/r1.8/tensorflow/contrib/estimator/python/estimator/extenders.py#L143). J'écris sur Batch Prediction. (Comme mentionné au début, il existe également une déclaration indiquant que l'ordre de sortie n'est pas garanti, vous devez donc vous connecter à l'aide de la clé d'entrée.)

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.

Le modèle que j'ai écrit cette fois est un modèle simple comme suit. Comme vous pouvez le voir sur la figure, la clé d'instance de la couche d'entrée du modèle n'est connectée à aucun nœud. Cependant, dans l'implémentation de forward_features, le processus d'inclusion de la clé d'instance dans la sortie de l'estimateur est terminé, donc je pense qu'il y sera connecté. (Probablement ici) Dans la mise en œuvre du modèle, il n'est pas particulièrement difficile d'écrire la clé de manière explicite.

スクリーンショット 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

La fonction forward_features est utilisée dans la fonction principale ( train_and_evaluate) qui compile le modèle / crée un estimateur à partir du modèle.

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)
    
    #Estimateur avant ici_Emballé dans les fonctionnalités
    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)

La valeur prédite est étrange car je n'ai pas entré beaucoup de données dans la formation. Vous pouvez voir que la clé d'instance est renvoyée telle quelle avec la valeur prédite. スクリーンショット 2019-12-18 9.27.22.png

Il y a une description dans ce problème, mais dans le système tensorflow 2, contrib.estimator auquel appartient forward_features est obsolète, donc dans le problème Vous devrez peut-être définir votre propre fonction feature_forward comme décrit.

Méthode 2: concatez la valeur sortie du graphique et la clé d'instance

Comme le montre la figure ci-dessous, la valeur sortie du dernier Dense est la valeur prédite, mais la clé d'instance est concatée telle quelle et utilisée comme sortie finale. De plus, comme la clé d'instance entre en tant que valeur scalaire, elle est remodelée pour la façonner. En faisant cela, il est possible de sortir la clé d'instance sans aucun traitement.

スクリーンショット 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)
    
    #Ici, nous concilions la prédiction et la clé d'instance
    #Puisque la clé d'instance est de type int, je la fais flotter de force pour qu'elle corresponde au type
    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

Cependant, avec cette méthode, vous devez écrire une fonction de perte personnalisée car la clé d'instance est incluse lors du calcul de la perte. Je ne pense pas que ce soit si difficile car il suffit d'obtenir la valeur de la prédiction dans la fonction comme indiqué ci-dessous.

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]Pour n'obtenir que des prédictions avec

Aucun autre changement n'a été apporté concernant les autres implémentations. Si vous essayez réellement la prédiction comme indiqué ci-dessous, elle sera sortie comme ceci.

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

Résumé

J'ai essayé deux méthodes cette fois, mais la différence est qu'il n'y a presque aucune différence dans le contenu du traitement, selon que vous utilisez la fonction (forward_features) préparée côté tensorflow ou que vous écrivez la structure du graphique par vous-même. Je vais. (Bien sûr, le premier est recommandé) Je n'avais pas beaucoup de littérature japonaise sur la prédiction par lots sur ML Engine, alors j'espère que cela aidera ceux qui ont des problèmes avec la même chose.

Recommended Posts

Points à garder à l'esprit lors de la prédiction par lots avec GCP ML Engine
Points à garder à l'esprit lors du déploiement de Keras sur votre Mac
Points à garder à l'esprit lors du développement d'un robot d'exploration en Python
Points à garder à l'esprit lors de la copie de listes Python
Points à garder à l'esprit lors du traitement des chaînes en Python2
Points à garder à l'esprit lors du traitement des chaînes en Python 3
Précautions lors de l'utilisation de Python avec AtCoder
Choses à garder à l'esprit lors de l'utilisation de cgi avec python.
Points à garder à l'esprit lors de la conversion d'un vecteur de ligne en vecteur de colonne avec ndarray
Points à garder à l'esprit lors de l'utilisation de Python pour ceux qui utilisent MATLAB
Points à garder à l'esprit lors de la création d'outils automatisés pour l'atelier en Python
Créez le moteur de prédiction Keras AI en 1 heure avec GCP
Choses à noter lors de l'initialisation d'une liste en Python