Ayuda a proteger la Gran Barrera de Coral con TensorFlow en Kaggle Únete Challenge

Clasifique datos estructurados utilizando capas de preprocesamiento de Keras

Ver en TensorFlow.org Ejecutar en Google Colab Ver fuente en GitHub Descargar cuaderno

Este tutorial muestra cómo clasificar los datos estructurados, como los datos tabulares, utilizando una versión simplificada del conjunto de datos Petfinder de una competición Kaggle almacenada en un archivo CSV.

Que va a utilizar Keras para definir el modelo, y Keras preprocesamiento capas como un puente para mapear de columnas en un archivo CSV a las funciones más utilizadas para entrenar el modelo. El objetivo es predecir si se adoptará una mascota.

Este tutorial contiene código completo para:

  • Carga de un archivo CSV en una trama de datos utilizando los pandas .
  • La construcción de una tubería de entrada al lote y mezclar las filas utilizando tf.data . (Visita tf.data: construir tuberías de entrada TensorFlow para más detalles).
  • Asignación de columnas en el archivo CSV a entidades utilizadas para entrenar el modelo con las capas de preprocesamiento de Keras.
  • Construir, entrenar y evaluar un modelo usando los métodos incorporados de Keras.

El mini conjunto de datos de PetFinder.my

Hay varios miles de filas en el archivo de conjunto de datos CSV de PetFinder.my mini, donde cada fila describe una mascota (un perro o un gato) y cada columna describe un atributo, como la edad, la raza, el color, etc.

En el resumen del conjunto de datos a continuación, observe que la mayoría de las columnas son numéricas y categóricas. En este tutorial, sólo tendrá que lidiar con esos dos tipos de entidades, dejando caer Description (una característica de texto libre) y AdoptionSpeed (una característica de clasificación) durante el pre-procesamiento de datos.

Columna Descripción de la mascota Tipo de característica Tipo de datos
Type Tipo de animal ( Dog , Cat ) Categórico Cuerda
Age La edad Numérico Entero
Breed1 Raza primaria Categórico Cuerda
Color1 Color 1 Categórico Cuerda
Color2 Color 2 Categórico Cuerda
MaturitySize Tamaño en la madurez Categórico Cuerda
FurLength Longitud de la piel Categórico Cuerda
Vaccinated La mascota ha sido vacunada Categórico Cuerda
Sterilized La mascota ha sido esterilizada Categórico Cuerda
Health Estado de salud Categórico Cuerda
Fee Cuota de adopción Numérico Entero
Description Redacción de perfil Texto Cuerda
PhotoAmt Total de fotos cargadas Numérico Entero
AdoptionSpeed Velocidad categórica de adopción Clasificación Entero

Importar TensorFlow y otras bibliotecas

import numpy as np
import pandas as pd
import tensorflow as tf

from tensorflow.keras import layers
tf.__version__
'2.7.0'

Cargue el conjunto de datos y léalo en un DataFrame de pandas

pandas es una biblioteca de Python con muchas utilidades útiles para la carga y que trabajan con datos estructurados. Uso tf.keras.utils.get_file para descargar y extraer el archivo CSV con el PetFinder.my Mini conjunto de datos, y cargarlo en una trama de datos con pandas.read_csv :

dataset_url = 'http://storage.googleapis.com/download.tensorflow.org/data/petfinder-mini.zip'
csv_file = 'datasets/petfinder-mini/petfinder-mini.csv'

tf.keras.utils.get_file('petfinder_mini.zip', dataset_url,
                        extract=True, cache_dir='.')
dataframe = pd.read_csv(csv_file)
Downloading data from http://storage.googleapis.com/download.tensorflow.org/data/petfinder-mini.zip
1671168/1668792 [==============================] - 0s 0us/step
1679360/1668792 [==============================] - 0s 0us/step

Inspeccione el conjunto de datos comprobando las primeras cinco filas del DataFrame:

dataframe.head()

Crea una variable de destino

La tarea original en Kaggle de la competencia Adopción Predicción PetFinder.my fue predecir la velocidad a la que se adoptó una mascota (por ejemplo, en la primera semana, el primer mes, los tres primeros meses, y así sucesivamente).

En este tutorial, simplificará la tarea transformándola en un problema de clasificación binaria, donde simplemente tendrá que predecir si una mascota fue adoptada o no.

Después de modificar el AdoptionSpeed columna, 0 indicará que la mascota no fue aprobado, y 1 indicará que era.

# In the original dataset, `'AdoptionSpeed'` of `4` indicates
# a pet was not adopted.
dataframe['target'] = np.where(dataframe['AdoptionSpeed']==4, 0, 1)

# Drop unused features.
dataframe = dataframe.drop(columns=['AdoptionSpeed', 'Description'])

Divida el DataFrame en conjuntos de entrenamiento, validación y prueba

El conjunto de datos está en un único DataFrame de pandas. Divídalo en conjuntos de entrenamiento, validación y prueba usando, por ejemplo, una proporción de 80:10:10, respectivamente:

train, val, test = np.split(dataframe.sample(frac=1), [int(0.8*len(dataframe)), int(0.9*len(dataframe))])
print(len(train), 'training examples')
print(len(val), 'validation examples')
print(len(test), 'test examples')
9229 training examples
1154 validation examples
1154 test examples

Crea una canalización de entrada usando tf.data

A continuación, crear una función de utilidad que convierte cada conjunto de entrenamiento, validación y prueba en una trama de datos tf.data.Dataset , a continuación, arrastrando los pies y los lotes de datos.

def df_to_dataset(dataframe, shuffle=True, batch_size=32):
  df = dataframe.copy()
  labels = df.pop('target')
  df = {key: value[:,tf.newaxis] for key, value in dataframe.items()}
  ds = tf.data.Dataset.from_tensor_slices((dict(df), labels))
  if shuffle:
    ds = ds.shuffle(buffer_size=len(dataframe))
  ds = ds.batch(batch_size)
  ds = ds.prefetch(batch_size)
  return ds

Ahora, utilice la función de nueva creación ( df_to_dataset ) para comprobar el formato de los datos de las entradas de canalización de ayuda devuelve las llamándolo en los datos de entrenamiento, y el uso de un pequeño tamaño de lote para mantener la salida legible:

batch_size = 5
train_ds = df_to_dataset(train, batch_size=batch_size)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:4: FutureWarning: Support for multi-dimensional indexing (e.g. `obj[:, None]`) is deprecated and will be removed in a future version.  Convert to a numpy array before indexing instead.
  after removing the cwd from sys.path.
[(train_features, label_batch)] = train_ds.take(1)
print('Every feature:', list(train_features.keys()))
print('A batch of ages:', train_features['Age'])
print('A batch of targets:', label_batch )
Every feature: ['Type', 'Age', 'Breed1', 'Gender', 'Color1', 'Color2', 'MaturitySize', 'FurLength', 'Vaccinated', 'Sterilized', 'Health', 'Fee', 'PhotoAmt', 'target']
A batch of ages: tf.Tensor(
[[ 4]
 [ 1]
 [15]
 [ 3]
 [ 1]], shape=(5, 1), dtype=int64)
A batch of targets: tf.Tensor([0 1 1 0 1], shape=(5,), dtype=int64)

Como demuestra el resultado, el conjunto de entrenamiento devuelve un diccionario de nombres de columna (del DataFrame) que se asignan a los valores de columna de las filas.

Aplicar las capas de preprocesamiento de Keras

Las capas de preprocesamiento de Keras le permiten construir pipelines de procesamiento de entrada nativos de Keras, que se pueden usar como código de preprocesamiento independiente en flujos de trabajo que no son de Keras, combinarlos directamente con modelos de Keras y exportarlos como parte de un modelo guardado de Keras.

En este tutorial, utilizará las siguientes cuatro capas de preprocesamiento para demostrar cómo realizar el preprocesamiento, la codificación de datos estructurados y la ingeniería de funciones:

Usted puede aprender más acerca de las capas disponibles en el Trabajo con procesamiento previo capas guía.

  • Para las características numéricas del PetFinder.my Mini conjunto de datos, que va a utilizar un tf.keras.layers.Normalization capa de normalizar la distribución de los datos.
  • Para las características categóricas, como la mascota Type s ( Dog y Cat cuerdas), se transforman a tensores codificados múltiples calientes con tf.keras.layers.CategoryEncoding .

Columnas numéricas

Para cada característica numérica en el PetFinder.my Mini conjunto de datos, que va a utilizar un tf.keras.layers.Normalization capa de normalizar la distribución de los datos.

Defina una nueva función de utilidad que devuelva una capa que aplica la normalización por características a las características numéricas utilizando esa capa de preprocesamiento de Keras:

def get_normalization_layer(name, dataset):
  # Create a Normalization layer for the feature.
  normalizer = layers.Normalization(axis=None)

  # Prepare a Dataset that only yields the feature.
  feature_ds = dataset.map(lambda x, y: x[name])

  # Learn the statistics of the data.
  normalizer.adapt(feature_ds)

  return normalizer

A continuación, probar la nueva función llamándolo sobre el total subido fotografía de la mascota características para normalizar 'PhotoAmt' :

photo_count_col = train_features['PhotoAmt']
layer = get_normalization_layer('PhotoAmt', train_ds)
layer(photo_count_col)
<tf.Tensor: shape=(5, 1), dtype=float32, numpy=
array([[-0.8390221 ],
       [ 2.3774517 ],
       [ 0.12592004],
       [-0.5173747 ],
       [-0.19572733]], dtype=float32)>

Columnas categóricas

Mascotas Type s en el conjunto de datos se representan como strings- Dog s y Cat s-que deben ser codificados de múltiples caliente antes de ser introducido en el modelo. La Age función

Definir otra nueva función de utilidad que devuelve una capa que mapea los valores de un vocabulario para índices enteros y codifica multi-calientes las funciones utilizando el tf.keras.layers.StringLookup , tf.keras.layers.IntegerLookup , y tf.keras.CategoryEncoding preprocesamiento capas:

def get_category_encoding_layer(name, dataset, dtype, max_tokens=None):
  # Create a layer that turns strings into integer indices.
  if dtype == 'string':
    index = layers.StringLookup(max_tokens=max_tokens)
  # Otherwise, create a layer that turns integer values into integer indices.
  else:
    index = layers.IntegerLookup(max_tokens=max_tokens)

  # Prepare a `tf.data.Dataset` that only yields the feature.
  feature_ds = dataset.map(lambda x, y: x[name])

  # Learn the set of possible values and assign them a fixed integer index.
  index.adapt(feature_ds)

  # Encode the integer indices.
  encoder = layers.CategoryEncoding(num_tokens=index.vocabulary_size())

  # Apply multi-hot encoding to the indices. The lambda function captures the
  # layer, so you can use them, or include them in the Keras Functional model later.
  return lambda feature: encoder(index(feature))

Prueba de la get_category_encoding_layer función llamándolo de mascota 'Type' características para convertirlos en los tensores codificados múltiples calientes:

test_type_col = train_features['Type']
test_type_layer = get_category_encoding_layer(name='Type',
                                              dataset=train_ds,
                                              dtype='string')
test_type_layer(test_type_col)
<tf.Tensor: shape=(5, 3), dtype=float32, numpy=
array([[0., 1., 0.],
       [0., 0., 1.],
       [0., 1., 0.],
       [0., 0., 1.],
       [0., 1., 0.]], dtype=float32)>

Repita el proceso en el animal doméstico 'Age' características:

test_age_col = train_features['Age']
test_age_layer = get_category_encoding_layer(name='Age',
                                             dataset=train_ds,
                                             dtype='int64',
                                             max_tokens=5)
test_age_layer(test_age_col)
<tf.Tensor: shape=(5, 5), dtype=float32, numpy=
array([[0., 0., 0., 0., 1.],
       [0., 0., 0., 1., 0.],
       [1., 0., 0., 0., 0.],
       [0., 0., 1., 0., 0.],
       [0., 0., 0., 1., 0.]], dtype=float32)>

Procesar previamente las entidades seleccionadas para entrenar el modelo en

Ha aprendido a utilizar varios tipos de capas de preprocesamiento de Keras. A continuación, harás lo siguiente:

  • Aplique las funciones de utilidad de preprocesamiento definidas anteriormente en 13 características numéricas y categóricas del mini conjunto de datos PetFinder.my.
  • Agregue todas las entradas de funciones a una lista.

Como se mencionó al principio, para entrenar el modelo, que va a utilizar numérica de su PetFinder.my Mini conjunto de datos ( 'PhotoAmt' , 'Fee' ) y categórica ( 'Age' , 'Type' , 'Color1' , 'Color2' , 'Gender' , 'MaturitySize' , 'FurLength' , 'Vaccinated' , 'Sterilized' , 'Health' , 'Breed1' ) cuenta.

Anteriormente, usó un tamaño de lote pequeño para demostrar la canalización de entrada. Creemos ahora una nueva canalización de entrada con un tamaño de lote más grande de 256:

batch_size = 256
train_ds = df_to_dataset(train, batch_size=batch_size)
val_ds = df_to_dataset(val, shuffle=False, batch_size=batch_size)
test_ds = df_to_dataset(test, shuffle=False, batch_size=batch_size)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:4: FutureWarning: Support for multi-dimensional indexing (e.g. `obj[:, None]`) is deprecated and will be removed in a future version.  Convert to a numpy array before indexing instead.
  after removing the cwd from sys.path.

Normalizar las características numéricas (el número de fotos de mascotas y la tasa de adopción), y añadirlos a una lista de entradas de llamadas encoded_features :

all_inputs = []
encoded_features = []

# Numerical features.
for header in ['PhotoAmt', 'Fee']:
  numeric_col = tf.keras.Input(shape=(1,), name=header)
  normalization_layer = get_normalization_layer(header, train_ds)
  encoded_numeric_col = normalization_layer(numeric_col)
  all_inputs.append(numeric_col)
  encoded_features.append(encoded_numeric_col)

A su vez los valores de número entero categóricas del conjunto de datos (la edad del animal doméstico) en índices enteros, realizar la codificación multi-caliente, y añadir las entradas de características resultantes a encoded_features :

age_col = tf.keras.Input(shape=(1,), name='Age', dtype='int64')

encoding_layer = get_category_encoding_layer(name='Age',
                                             dataset=train_ds,
                                             dtype='int64',
                                             max_tokens=5)
encoded_age_col = encoding_layer(age_col)
all_inputs.append(age_col)
encoded_features.append(encoded_age_col)

Repita el mismo paso para los valores categóricos de la cadena:

categorical_cols = ['Type', 'Color1', 'Color2', 'Gender', 'MaturitySize',
                    'FurLength', 'Vaccinated', 'Sterilized', 'Health', 'Breed1']

for header in categorical_cols:
  categorical_col = tf.keras.Input(shape=(1,), name=header, dtype='string')
  encoding_layer = get_category_encoding_layer(name=header,
                                               dataset=train_ds,
                                               dtype='string',
                                               max_tokens=5)
  encoded_categorical_col = encoding_layer(categorical_col)
  all_inputs.append(categorical_col)
  encoded_features.append(encoded_categorical_col)

Cree, compile y entrene el modelo

El siguiente paso es crear un modelo que utiliza la API funcional Keras . Para la primera capa en el modelo, fusionar la lista de función insumos- encoded_features -into un vector mediante la concatenación con tf.keras.layers.concatenate .

all_features = tf.keras.layers.concatenate(encoded_features)
x = tf.keras.layers.Dense(32, activation="relu")(all_features)
x = tf.keras.layers.Dropout(0.5)(x)
output = tf.keras.layers.Dense(1)(x)

model = tf.keras.Model(all_inputs, output)

Configurar el modelo con Keras Model.compile :

model.compile(optimizer='adam',
              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=["accuracy"])

Visualicemos el gráfico de conectividad:

# Use `rankdir='LR'` to make the graph horizontal.
tf.keras.utils.plot_model(model, show_shapes=True, rankdir="LR")

png

A continuación, entrene y pruebe el modelo:

model.fit(train_ds, epochs=10, validation_data=val_ds)
Epoch 1/10
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/keras/engine/functional.py:559: UserWarning: Input dict contained keys ['target'] which did not match any model input. They will be ignored by the model.
  inputs = self._flatten_to_reference_inputs(inputs)
37/37 [==============================] - 2s 18ms/step - loss: 0.6231 - accuracy: 0.5496 - val_loss: 0.5638 - val_accuracy: 0.7409
Epoch 2/10
37/37 [==============================] - 0s 7ms/step - loss: 0.5758 - accuracy: 0.6770 - val_loss: 0.5473 - val_accuracy: 0.7400
Epoch 3/10
37/37 [==============================] - 0s 7ms/step - loss: 0.5544 - accuracy: 0.7043 - val_loss: 0.5377 - val_accuracy: 0.7383
Epoch 4/10
37/37 [==============================] - 0s 8ms/step - loss: 0.5482 - accuracy: 0.7098 - val_loss: 0.5309 - val_accuracy: 0.7348
Epoch 5/10
37/37 [==============================] - 0s 8ms/step - loss: 0.5424 - accuracy: 0.7100 - val_loss: 0.5268 - val_accuracy: 0.7253
Epoch 6/10
37/37 [==============================] - 0s 8ms/step - loss: 0.5336 - accuracy: 0.7130 - val_loss: 0.5221 - val_accuracy: 0.7331
Epoch 7/10
37/37 [==============================] - 0s 7ms/step - loss: 0.5289 - accuracy: 0.7258 - val_loss: 0.5189 - val_accuracy: 0.7357
Epoch 8/10
37/37 [==============================] - 0s 8ms/step - loss: 0.5280 - accuracy: 0.7146 - val_loss: 0.5165 - val_accuracy: 0.7374
Epoch 9/10
37/37 [==============================] - 0s 8ms/step - loss: 0.5221 - accuracy: 0.7264 - val_loss: 0.5142 - val_accuracy: 0.7331
Epoch 10/10
37/37 [==============================] - 0s 7ms/step - loss: 0.5200 - accuracy: 0.7235 - val_loss: 0.5128 - val_accuracy: 0.7357
<keras.callbacks.History at 0x7f1667fe7790>
loss, accuracy = model.evaluate(test_ds)
print("Accuracy", accuracy)
5/5 [==============================] - 0s 6ms/step - loss: 0.5032 - accuracy: 0.7513
Accuracy 0.7512997984886169

Realizar inferencia

El modelo que ha desarrollado ahora puede clasificar una fila de un archivo CSV directamente después de haber incluido las capas de preprocesamiento dentro del propio modelo.

Ahora puede guardar y volver a cargar el modelo Keras con Model.save y Model.load_model antes de realizar inferencia sobre nuevos datos:

model.save('my_pet_classifier')
reloaded_model = tf.keras.models.load_model('my_pet_classifier')
2021-11-06 01:29:25.921254: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
WARNING:absl:Function `_wrapped_model` contains input name(s) PhotoAmt, Fee, Age, Type, Color1, Color2, Gender, MaturitySize, FurLength, Vaccinated, Sterilized, Health, Breed1 with unsupported characters which will be renamed to photoamt, fee, age, type, color1, color2, gender, maturitysize, furlength, vaccinated, sterilized, health, breed1 in the SavedModel.
INFO:tensorflow:Assets written to: my_pet_classifier/assets
INFO:tensorflow:Assets written to: my_pet_classifier/assets

Para obtener una predicción para una nueva muestra, sólo tiene que llamar al Keras Model.predict método. Solo hay dos cosas que debe hacer:

  1. Escalares Wrap en una lista de modo que tienen una dimensión de lote ( Model s sólo lotes de proceso de datos, no muestras individuales).
  2. Llamar tf.convert_to_tensor en cada función.
sample = {
    'Type': 'Cat',
    'Age': 3,
    'Breed1': 'Tabby',
    'Gender': 'Male',
    'Color1': 'Black',
    'Color2': 'White',
    'MaturitySize': 'Small',
    'FurLength': 'Short',
    'Vaccinated': 'No',
    'Sterilized': 'No',
    'Health': 'Healthy',
    'Fee': 100,
    'PhotoAmt': 2,
}

input_dict = {name: tf.convert_to_tensor([value]) for name, value in sample.items()}
predictions = reloaded_model.predict(input_dict)
prob = tf.nn.sigmoid(predictions[0])

print(
    "This particular pet had a %.1f percent probability "
    "of getting adopted." % (100 * prob)
)
This particular pet had a 74.4 percent probability of getting adopted.

Próximos pasos

Para obtener más información sobre la clasificación de datos estructurados, intente trabajar con otros conjuntos de datos. Para mejorar la precisión durante el entrenamiento y la prueba de sus modelos, piense detenidamente qué características incluir en su modelo y cómo deben representarse.

A continuación, se muestran algunas sugerencias para conjuntos de datos: