Google I / O powraca w dniach 18-20 maja! Zarezerwuj miejsce i stwórz swój harmonogram Zarejestruj się teraz

Niestandardowe estymatory TF Lattice

Zobacz na TensorFlow.org Uruchom w Google Colab Wyświetl źródło w serwisie GitHub Pobierz notatnik

Przegląd

Za pomocą niestandardowych estymatorów można tworzyć dowolnie monotoniczne modele przy użyciu warstw TFL. Ten przewodnik przedstawia kroki potrzebne do stworzenia takich estymatorów.

Ustawiać

Instalowanie pakietu TF Lattice:

pip install -q tensorflow-lattice

Importowanie wymaganych pakietów:

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)

Pobieranie zestawu danych 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()

Ustawianie wartości domyślnych używanych do treningu w tym przewodniku:

LEARNING_RATE = 0.1
BATCH_SIZE = 128
NUM_EPOCHS = 1000

Kolumny funkcji

Podobnie jak w przypadku każdego innego estymatora TF, dane muszą zostać przekazane do estymatora, który zwykle jest wykonywany przez parametr input_fn i analizowany przy użyciu 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']),
]

Należy zauważyć, że cechy kategorialne nie muszą być opakowane gęstą kolumną cech, ponieważ warstwa tfl.laysers.CategoricalCalibration może bezpośrednio zużywać indeksy kategorii.

Tworzę input_fn

Podobnie jak w przypadku każdego innego estymatora, możesz użyć input_fn, aby przesłać dane do modelu w celu uczenia i oceny.

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)

Tworzę model_fn

Istnieje kilka sposobów tworzenia niestandardowego estymatora. Tutaj skonstruujemy model_fn który model_fn model Keras na przeanalizowanych model_fn wejściowych. Aby przeanalizować funkcje wejściowe, możesz użyć tf.feature_column.input_layer , tf.keras.layers.DenseFeatures lub tfl.estimators.transform_features . Jeśli użyjesz tego drugiego, nie będziesz musiał zawijać elementów kategorialnych gęstymi kolumnami cech, a wynikowe tensory nie będą łączone, co ułatwia korzystanie z elementów w warstwach kalibracji.

Aby zbudować model, możesz mieszać i dopasowywać warstwy TFL lub dowolne inne warstwy Keras. Tutaj tworzymy skalibrowany model sieciowy Keras z warstw TFL i nakładamy kilka ograniczeń monotoniczności. Następnie używamy modelu Keras do tworzenia niestandardowego estymatora.

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)

Szkolenie i estymator

Korzystając z model_fn możemy stworzyć i wyszkolić estymator.

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']))
AUC: 0.6416040062904358