Estimateurs personnalisés de treillis TF

Voir sur TensorFlow.org Exécuter dans Google Colab Voir la source sur GitHub Télécharger le cahier

Aperçu

Vous pouvez utiliser des estimateurs personnalisés pour créer des modèles arbitrairement monotones à l'aide de couches TFL. Ce guide décrit les étapes nécessaires pour créer de tels estimateurs.

Installer

Installation du package TF Lattice :

pip install tensorflow-lattice

Importation des packages requis :

import tensorflow as tf

import logging
import numpy as np
import pandas as pd
import sys
import tensorflow_lattice as tfl
from tensorflow import feature_column as fc

from tensorflow_estimator.python.estimator.canned import optimizers
from tensorflow_estimator.python.estimator.head import binary_class_head
logging.disable(sys.maxsize)

Téléchargement du jeu de données UCI Statlog (Heart) :

csv_file = tf.keras.utils.get_file(
    'heart.csv', 'http://storage.googleapis.com/download.tensorflow.org/data/heart.csv')
df = pd.read_csv(csv_file)
target = df.pop('target')
train_size = int(len(df) * 0.8)
train_x = df[:train_size]
train_y = target[:train_size]
test_x = df[train_size:]
test_y = target[train_size:]
df.head()

Définition des valeurs par défaut utilisées pour la formation dans ce guide :

LEARNING_RATE = 0.1
BATCH_SIZE = 128
NUM_EPOCHS = 1000

Colonnes de fonction

Comme pour tout autre estimateur de TF, les données doivent être transmises à l'estimateur, qui est typiquement via un input_fn et analysés en utilisant FeatureColumns .

# Feature columns.
# - age
# - sex
# - ca        number of major vessels (0-3) colored by flourosopy
# - thal      3 = normal; 6 = fixed defect; 7 = reversable defect
feature_columns = [
    fc.numeric_column('age', default_value=-1),
    fc.categorical_column_with_vocabulary_list('sex', [0, 1]),
    fc.numeric_column('ca'),
    fc.categorical_column_with_vocabulary_list(
        'thal', ['normal', 'fixed', 'reversible']),
]

Notez que les caractéristiques catégoriques ne doivent pas nécessairement être enveloppé par une colonne de fonction dense, puisque tfl.laysers.CategoricalCalibration couche peut directement consommer des indices de la catégorie.

Création de input_fn

Comme pour tout autre estimateur, vous pouvez utiliser input_fn pour alimenter le modèle en données à des fins d'apprentissage et d'évaluation.

train_input_fn = tf.compat.v1.estimator.inputs.pandas_input_fn(
    x=train_x,
    y=train_y,
    shuffle=True,
    batch_size=BATCH_SIZE,
    num_epochs=NUM_EPOCHS,
    num_threads=1)

test_input_fn = tf.compat.v1.estimator.inputs.pandas_input_fn(
    x=test_x,
    y=test_y,
    shuffle=False,
    batch_size=BATCH_SIZE,
    num_epochs=1,
    num_threads=1)

Création de model_fn

Il existe plusieurs façons de créer un estimateur personnalisé. Ici , nous allons construire un model_fn qui appelle un modèle Keras sur les tenseurs d'entrée analysable. Pour analyser les caractéristiques d'entrée, vous pouvez utiliser tf.feature_column.input_layer , tf.keras.layers.DenseFeatures ou tfl.estimators.transform_features . Si vous utilisez ce dernier, vous n'aurez pas besoin d'envelopper les entités catégorielles avec des colonnes d'entités denses, et les tenseurs résultants ne seront pas concaténés, ce qui facilite l'utilisation des entités dans les couches de calibrage.

Pour construire un modèle, vous pouvez mélanger et assortir des couches TFL ou toute autre couche Keras. Ici, nous créons un modèle Keras en treillis calibré à partir de couches TFL et imposons plusieurs contraintes de monotonie. Nous utilisons ensuite le modèle Keras pour créer l'estimateur personnalisé.

def model_fn(features, labels, mode, config):
  """model_fn for the custom estimator."""
  del config
  input_tensors = tfl.estimators.transform_features(features, feature_columns)
  inputs = {
      key: tf.keras.layers.Input(shape=(1,), name=key) for key in input_tensors
  }

  lattice_sizes = [3, 2, 2, 2]
  lattice_monotonicities = ['increasing', 'none', 'increasing', 'increasing']
  lattice_input = tf.keras.layers.Concatenate(axis=1)([
      tfl.layers.PWLCalibration(
          input_keypoints=np.linspace(10, 100, num=8, dtype=np.float32),
          # The output range of the calibrator should be the input range of
          # the following lattice dimension.
          output_min=0.0,
          output_max=lattice_sizes[0] - 1.0,
          monotonicity='increasing',
      )(inputs['age']),
      tfl.layers.CategoricalCalibration(
          # Number of categories including any missing/default category.
          num_buckets=2,
          output_min=0.0,
          output_max=lattice_sizes[1] - 1.0,
      )(inputs['sex']),
      tfl.layers.PWLCalibration(
          input_keypoints=[0.0, 1.0, 2.0, 3.0],
          output_min=0.0,
          output_max=lattice_sizes[0] - 1.0,
          # You can specify TFL regularizers as tuple
          # ('regularizer name', l1, l2).
          kernel_regularizer=('hessian', 0.0, 1e-4),
          monotonicity='increasing',
      )(inputs['ca']),
      tfl.layers.CategoricalCalibration(
          num_buckets=3,
          output_min=0.0,
          output_max=lattice_sizes[1] - 1.0,
          # Categorical monotonicity can be partial order.
          # (i, j) indicates that we must have output(i) <= output(j).
          # Make sure to set the lattice monotonicity to 'increasing' for this
          # dimension.
          monotonicities=[(0, 1), (0, 2)],
      )(inputs['thal']),
  ])
  output = tfl.layers.Lattice(
      lattice_sizes=lattice_sizes, monotonicities=lattice_monotonicities)(
          lattice_input)

  training = (mode == tf.estimator.ModeKeys.TRAIN)
  model = tf.keras.Model(inputs=inputs, outputs=output)
  logits = model(input_tensors, training=training)

  if training:
    optimizer = optimizers.get_optimizer_instance_v2('Adagrad', LEARNING_RATE)
  else:
    optimizer = None

  head = binary_class_head.BinaryClassHead()
  return head.create_estimator_spec(
      features=features,
      mode=mode,
      labels=labels,
      optimizer=optimizer,
      logits=logits,
      trainable_variables=model.trainable_variables,
      update_ops=model.updates)

Formation et estimateur

Utilisation de la model_fn nous pouvons créer et former l'estimateur.

estimator = tf.estimator.Estimator(model_fn=model_fn)
estimator.train(input_fn=train_input_fn)
results = estimator.evaluate(input_fn=test_input_fn)
print('AUC: {}'.format(results['auc']))
2021-09-30 20:51:11.094402: E tensorflow/stream_executor/cuda/cuda_driver.cc:271] failed call to cuInit: CUDA_ERROR_NO_DEVICE: no CUDA-capable device is detected
AUC: 0.5946115255355835