RSVP для вашего местного мероприятия TensorFlow Everywhere сегодня!
Эта страница переведена с помощью Cloud Translation API.
Switch to English

Классифицируйте структурированные данные с помощью слоев предварительной обработки Keras

Посмотреть на TensorFlow.org Запускаем в Google Colab Посмотреть исходный код на GitHub Скачать блокнот

В этом руководстве показано, как классифицировать структурированные данные (например, табличные данные в CSV). Вы будете использовать Keras для определения модели и предварительной обработки слоев в качестве моста для сопоставления столбцов в CSV с функциями, используемыми для обучения модели. Это руководство содержит полный код для:

  • Загрузите файл CSV с помощью Pandas .
  • Создайте входной конвейер для пакетной обработки и перемешивания строк с помощью tf.data .
  • Сопоставьте столбцы в CSV с функциями, используемыми для обучения модели с помощью слоев предварительной обработки Keras.
  • Создайте, обучите и оцените модель с помощью Keras.

Набор данных

Вы будете использовать упрощенную версию набора данных PetFinder. В CSV несколько тысяч строк. Каждая строка описывает домашнее животное, а каждый столбец описывает атрибут. Вы будете использовать эту информацию, чтобы предсказать, будет ли питомец усыновлен.

Ниже приводится описание этого набора данных. Обратите внимание, что есть как числовые, так и категориальные столбцы. Есть столбец с произвольным текстом, который вы не будете использовать в этом руководстве.

Столбец Описание Тип функции Тип данных
Тип Тип животного (Собака, Кошка) Категоричный строка
Возраст Возраст питомца Числовой целое число
Порода1 Основная порода питомца Категоричный строка
Цвет1 Цвет 1 питомца Категоричный строка
Цвет2 Цвет 2 питомца Категоричный строка
Зрелость Размер Размер к погашению Категоричный строка
FurLength Длина меха Категоричный строка
Вакцинированный Животное было вакцинировано Категоричный строка
Стерилизованный Домашнее животное стерилизовано Категоричный строка
Здоровье Состояние здоровья Категоричный строка
Гонорар Плата за усыновление Числовой целое число
Описание Описание профиля для этого питомца Текст строка
PhotoAmt Всего загружено фото для этого питомца Числовой целое число
Скорость принятия Скорость принятия Классификация целое число

Импортировать TensorFlow и другие библиотеки

pip install -q sklearn
import numpy as np
import pandas as pd
import tensorflow as tf

from sklearn.model_selection import train_test_split
from tensorflow.keras import layers
from tensorflow.keras.layers.experimental import preprocessing

Используйте Pandas для создания фрейма данных

Pandas - это библиотека Python со множеством полезных утилит для загрузки и работы со структурированными данными. Вы будете использовать Pandas, чтобы загрузить набор данных из URL-адреса и загрузить его во фрейм данных.

import pathlib

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

dataframe.head()

Создать целевую переменную

Задача конкурса Kaggle - предсказать скорость, с которой животное будет усыновлено (например, в первую неделю, в первый месяц, в первые три месяца и т. Д.). Давайте упростим это для нашего урока. Здесь вы превратите это в задачу двоичной классификации и просто предскажете, было ли животное усыновлено или нет.

После изменения столбца метки 0 будет означать, что домашнее животное не было принято, а 1 будет указывать, что это было.

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

# Drop un-used columns.
dataframe = dataframe.drop(columns=['AdoptionSpeed', 'Description'])

Разделите фрейм данных на обучение, проверку и тестирование

Набор данных, который вы скачали, был одним файлом CSV. Вы разделите это на наборы для обучения, проверки и тестирования.

train, test = train_test_split(dataframe, test_size=0.2)
train, val = train_test_split(train, test_size=0.2)
print(len(train), 'train examples')
print(len(val), 'validation examples')
print(len(test), 'test examples')
7383 train examples
1846 validation examples
2308 test examples

Создайте входной конвейер с помощью tf.data

Затем вы оберните фреймы данных tf.data , чтобы перемешать и группировать данные. Если бы вы работали с очень большим CSV-файлом (настолько большим, что он не помещается в памяти), вы бы использовали tf.data для чтения его напрямую с диска. Это не рассматривается в этом руководстве.

# A utility method to create a tf.data dataset from a Pandas Dataframe
def df_to_dataset(dataframe, shuffle=True, batch_size=32):
  dataframe = dataframe.copy()
  labels = dataframe.pop('target')
  ds = tf.data.Dataset.from_tensor_slices((dict(dataframe), labels))
  if shuffle:
    ds = ds.shuffle(buffer_size=len(dataframe))
  ds = ds.batch(batch_size)
  ds = ds.prefetch(batch_size)
  return ds

Теперь, когда вы создали входной конвейер, давайте вызовем его, чтобы увидеть формат возвращаемых данных. Вы использовали небольшой размер пакета, чтобы вывод был читабельным.

batch_size = 5
train_ds = df_to_dataset(train, batch_size=batch_size)
[(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']
A batch of ages: tf.Tensor([ 2  2 18  2  1], shape=(5,), dtype=int64)
A batch of targets: tf.Tensor([1 1 0 1 1], shape=(5,), dtype=int64)

Вы можете видеть, что набор данных возвращает словарь имен столбцов (из фрейма данных), который сопоставляется со значениями столбцов из строк в фрейме данных.

Продемонстрируйте использование слоев предварительной обработки.

API слоев предварительной обработки Keras позволяет создавать собственные конвейеры обработки ввода для Keras. Вы будете использовать 3 уровня предварительной обработки, чтобы продемонстрировать код предварительной обработки функции.

Вы можете найти список доступных слоев предварительной обработки здесь .

Числовые столбцы

Для каждой числовой функции вы будете использовать слой Normalization (), чтобы убедиться, что среднее значение каждой функции равно 0, а его стандартное отклонение равно 1.

Функция get_normalization_layer возвращает слой, который применяет поэлементную нормализацию к числовым объектам.

def get_normalization_layer(name, dataset):
  # Create a Normalization layer for our feature.
  normalizer = preprocessing.Normalization()

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

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

  return normalizer
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([[ 1.045485  ],
       [-1.1339161 ],
       [-0.19988704],
       [ 0.11145599],
       [ 0.42279902]], dtype=float32)>

Категориальные столбцы

В этом наборе данных Тип представлен в виде строки (например, «Собака» или «Кошка»). Вы не можете подавать струны напрямую в модель. Слой предварительной обработки заботится о представлении строк в виде горячего вектора.

Функция get_category_encoding_layer возвращает слой, который отображает значения из словаря в целочисленные индексы и get_category_encoding_layer кодирует функции.

def get_category_encoding_layer(name, dataset, dtype, max_tokens=None):
  # Create a StringLookup layer which will turn strings into integer indices
  if dtype == 'string':
    index = preprocessing.StringLookup(max_tokens=max_tokens)
  else:
    index = preprocessing.IntegerLookup(max_values=max_tokens)

  # Prepare a Dataset that only yields our 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)

  # Create a Discretization for our integer indices.
  encoder = preprocessing.CategoryEncoding(max_tokens=index.vocab_size())

  # Prepare a Dataset that only yields our feature.
  feature_ds = feature_ds.map(index)

  # Learn the space of possible indices.
  encoder.adapt(feature_ds)

  # Apply one-hot encoding to our indices. The lambda function captures the
  # layer so we can use them, or include them in the functional model later.
  return lambda feature: encoder(index(feature))
type_col = train_features['Type']
layer = get_category_encoding_layer('Type', train_ds, 'string')
layer(type_col)
<tf.Tensor: shape=(5, 4), dtype=float32, numpy=
array([[0., 0., 0., 1.],
       [0., 0., 0., 1.],
       [0., 0., 1., 0.],
       [0., 0., 0., 1.],
       [0., 0., 1., 0.]], dtype=float32)>

Часто вы не хотите вводить число непосредственно в модель, а вместо этого используйте быстрое кодирование этих входных данных. Рассмотрим необработанные данные, которые представляют возраст питомца.

type_col = train_features['Age']
category_encoding_layer = get_category_encoding_layer('Age', train_ds,
                                                      'int64', 5)
category_encoding_layer(type_col)
<tf.Tensor: shape=(5, 5), dtype=float32, numpy=
array([[0., 0., 1., 0., 0.],
       [0., 0., 1., 0., 0.],
       [0., 1., 0., 0., 0.],
       [0., 0., 1., 0., 0.],
       [0., 0., 0., 0., 1.]], dtype=float32)>

Выберите, какие столбцы использовать

Вы видели, как использовать несколько типов слоев предварительной обработки. Теперь вы будете использовать их для обучения модели. Для построения модели вы будете использовать функциональный API Keras. Функциональный API Keras - это способ создания моделей, более гибких, чем API tf.keras.Sequential .

Цель этого руководства - показать вам полный код (например, механику), необходимый для работы со слоями предварительной обработки. Несколько столбцов были выбраны произвольно для обучения нашей модели.

Ранее вы использовали небольшой размер пакета, чтобы продемонстрировать входной конвейер. Теперь давайте создадим новый конвейер ввода с большим размером пакета.

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)
all_inputs = []
encoded_features = []

# Numeric 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)
# Categorical features encoded as integers.
age_col = tf.keras.Input(shape=(1,), name='Age', dtype='int64')
encoding_layer = get_category_encoding_layer('Age', 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)
# Categorical features encoded as string.
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(header, 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)

Создайте, скомпилируйте и обучите модель

Теперь вы можете создать нашу сквозную модель.

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)
model.compile(optimizer='adam',
              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=["accuracy"])

Давайте визуализируем наш график связи:

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

PNG

Обучите модель

model.fit(train_ds, epochs=10, validation_data=val_ds)
Epoch 1/10
29/29 [==============================] - 0s 15ms/step - loss: 0.6088 - accuracy: 0.5924 - val_loss: 0.5623 - val_accuracy: 0.7302
Epoch 2/10
29/29 [==============================] - 0s 6ms/step - loss: 0.5766 - accuracy: 0.6833 - val_loss: 0.5459 - val_accuracy: 0.7356
Epoch 3/10
29/29 [==============================] - 0s 6ms/step - loss: 0.5579 - accuracy: 0.6981 - val_loss: 0.5364 - val_accuracy: 0.7362
Epoch 4/10
29/29 [==============================] - 0s 6ms/step - loss: 0.5467 - accuracy: 0.7127 - val_loss: 0.5287 - val_accuracy: 0.7313
Epoch 5/10
29/29 [==============================] - 0s 6ms/step - loss: 0.5401 - accuracy: 0.7059 - val_loss: 0.5240 - val_accuracy: 0.7329
Epoch 6/10
29/29 [==============================] - 0s 6ms/step - loss: 0.5362 - accuracy: 0.7222 - val_loss: 0.5203 - val_accuracy: 0.7313
Epoch 7/10
29/29 [==============================] - 0s 6ms/step - loss: 0.5290 - accuracy: 0.7189 - val_loss: 0.5172 - val_accuracy: 0.7297
Epoch 8/10
29/29 [==============================] - 0s 6ms/step - loss: 0.5273 - accuracy: 0.7172 - val_loss: 0.5151 - val_accuracy: 0.7286
Epoch 9/10
29/29 [==============================] - 0s 6ms/step - loss: 0.5236 - accuracy: 0.7210 - val_loss: 0.5127 - val_accuracy: 0.7291
Epoch 10/10
29/29 [==============================] - 0s 6ms/step - loss: 0.5200 - accuracy: 0.7219 - val_loss: 0.5112 - val_accuracy: 0.7297

<tensorflow.python.keras.callbacks.History at 0x7f6fc8e61f98>
loss, accuracy = model.evaluate(test_ds)
print("Accuracy", accuracy)
10/10 [==============================] - 0s 4ms/step - loss: 0.5232 - accuracy: 0.7370
Accuracy 0.7370017170906067

Вывод по новым данным

Теперь вы можете сохранить и перезагрузить модель Keras. Следуйте инструкциям здесь для получения дополнительной информации о моделях TensorFlow.

model.save('my_pet_classifier')
reloaded_model = tf.keras.models.load_model('my_pet_classifier')
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Model.state_updates (from tensorflow.python.keras.engine.training) is deprecated and will be removed in a future version.
Instructions for updating:
This property should not be used in TensorFlow 2.0, as updates are applied automatically.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Layer.updates (from tensorflow.python.keras.engine.base_layer) is deprecated and will be removed in a future version.
Instructions for updating:
This property should not be used in TensorFlow 2.0, as updates are applied automatically.
INFO:tensorflow:Assets written to: my_pet_classifier/assets
WARNING:tensorflow:5 out of the last 5 calls to <function recreate_function.<locals>.restored_function_body at 0x7f6fc8b82400> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/tutorials/customization/performance#python_or_tensor_args and https://www.tensorflow.org/api_docs/python/tf/function for  more details.
WARNING:tensorflow:6 out of the last 6 calls to <function recreate_function.<locals>.restored_function_body at 0x7f6fc8b82d08> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/tutorials/customization/performance#python_or_tensor_args and https://www.tensorflow.org/api_docs/python/tf/function for  more details.
WARNING:tensorflow:7 out of the last 7 calls to <function recreate_function.<locals>.restored_function_body at 0x7f6fc8b611e0> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/tutorials/customization/performance#python_or_tensor_args and https://www.tensorflow.org/api_docs/python/tf/function for  more details.
WARNING:tensorflow:8 out of the last 8 calls to <function recreate_function.<locals>.restored_function_body at 0x7f6fc8b857b8> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/tutorials/customization/performance#python_or_tensor_args and https://www.tensorflow.org/api_docs/python/tf/function for  more details.
WARNING:tensorflow:9 out of the last 9 calls to <function recreate_function.<locals>.restored_function_body at 0x7f6f6870b158> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/tutorials/customization/performance#python_or_tensor_args and https://www.tensorflow.org/api_docs/python/tf/function for  more details.
WARNING:tensorflow:10 out of the last 10 calls to <function recreate_function.<locals>.restored_function_body at 0x7f6f6870bd08> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/tutorials/customization/performance#python_or_tensor_args and https://www.tensorflow.org/api_docs/python/tf/function for  more details.
WARNING:tensorflow:11 out of the last 11 calls to <function recreate_function.<locals>.restored_function_body at 0x7f6fc8b6abf8> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/tutorials/customization/performance#python_or_tensor_args and https://www.tensorflow.org/api_docs/python/tf/function for  more details.

Чтобы получить прогноз для нового образца, вы можете просто вызвать model.predict() . Вам нужно сделать всего две вещи:

  1. Оберните скаляры в список, чтобы иметь размерность партии (модели обрабатывают только пакеты данных, а не отдельные выборки)
  2. Вызов convert_to_tensor для каждой функции
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 83.4 percent probability of getting adopted.

Следующие шаги

Лучший способ узнать больше о классификации структурированных данных - это попробовать сами. Вы можете найти другой набор данных для работы и обучить модель классифицировать ее с помощью кода, подобного приведенному выше. Чтобы повысить точность, тщательно подумайте, какие функции включить в вашу модель и как они должны быть представлены.