Pomoc chronić Wielkiej Rafy Koralowej z TensorFlow na Kaggle Dołącz Wyzwanie

Klasyfikuj uporządkowane dane za pomocą warstw przetwarzania wstępnego Keras

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

Ten poradnik pokazuje, jak sklasyfikować ustrukturyzowanych danych, takich jak dane tabelaryczne, stosując uproszczoną wersję zbiorze PetFinder od konkurencji Kaggle przechowywane w pliku CSV.

Będziesz korzystać Keras zdefiniowanie modelu i Keras przerób warstw jako pomost do mapy z kolumn w pliku CSV do funkcji używanych do pociągu modelu. Celem jest przewidzenie, czy zwierzę zostanie adoptowane.

Ten samouczek zawiera kompletny kod dla:

  • Ładowanie pliku CSV do DataFrame wykorzystaniem pandy .
  • Budowy rurociągu wejściowe do partii i przetasować wiersze używając tf.data . (Wizyta tf.data: Budowa rurociągów wejściowe TensorFlow więcej szczegółów.)
  • Mapowanie z kolumn w pliku CSV do funkcji używanych do trenowania modelu za pomocą warstw przetwarzania wstępnego Keras.
  • Budowanie, trenowanie i ocena modelu przy użyciu wbudowanych metod Keras.

Minizestaw danych PetFinder.my

Istnieje kilka tysięcy wierszy w pliku danych CSV PetFinder.my mini, gdzie każdy wiersz opisuje zwierzaka (psa lub kota), a każda kolumna opisuje atrybut, taki jak wiek, rasa, kolor i tak dalej.

Zwróć uwagę, że w poniższym podsumowaniu zbioru danych znajdują się głównie kolumny liczbowe i kategorialne. W tym ćwiczeniu będziesz mieć do czynienia tylko z tymi dwoma rodzajami fabularnych, upuszczając Description (bezpłatna funkcja text) oraz AdoptionSpeed (funkcja klasyfikacja) podczas wstępnego przetwarzania danych.

Kolumna Opis zwierzaka Typ funkcji Typ danych
Type Typ zwierzęcia ( Dog , Cat ) Kategoryczny Strunowy
Age Wiek Liczbowy Liczba całkowita
Breed1 Rasa podstawowa Kategoryczny Strunowy
Color1 Kolor 1 Kategoryczny Strunowy
Color2 Kolor 2 Kategoryczny Strunowy
MaturitySize Rozmiar w terminie dojrzałości Kategoryczny Strunowy
FurLength Długość futra Kategoryczny Strunowy
Vaccinated Zwierzę zostało zaszczepione Kategoryczny Strunowy
Sterilized Zwierzę zostało wysterylizowane Kategoryczny Strunowy
Health Stan zdrowia Kategoryczny Strunowy
Fee Opłata adopcyjna Liczbowy Liczba całkowita
Description Zapis profilu Tekst Strunowy
PhotoAmt Wszystkie przesłane zdjęcia Liczbowy Liczba całkowita
AdoptionSpeed Kategoryczna szybkość adopcji Klasyfikacja Liczba całkowita

Importuj TensorFlow i inne biblioteki

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

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

Załaduj zbiór danych i wczytaj go do pandy DataFrame

pandy to biblioteka Pythona z wielu pomocnych narzędzi do załadunku i pracy z danymi strukturyzowanych. Zastosowanie tf.keras.utils.get_file pobrać i rozpakować plik CSV ze zbioru danych PetFinder.my mini i załadować go do DataFrame z 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

Sprawdź zestaw danych, sprawdzając pierwsze pięć wierszy DataFrame:

dataframe.head()

Utwórz zmienną docelową

Oryginalny zadaniem w Kaggle za PetFinder.my konkurencji Przyjęcie Prediction było przewidzieć prędkość, przy której zostanie przyjęty dla zwierząt (na przykład w pierwszym tygodniu, pierwszy miesiąc, pierwsze trzy miesiące, i tak dalej).

W tym samouczku uprościsz zadanie, przekształcając je w binarny problem klasyfikacji, w którym musisz po prostu przewidzieć, czy zwierzę zostało adoptowane, czy nie.

Po zmodyfikowaniu AdoptionSpeed kolumnę 0 wskaże zwierzę nie zostało przyjęte, a 1 wskazuje, że był.

# 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'])

Podziel DataFrame na zestawy treningowe, walidacyjne i testowe

Zestaw danych znajduje się w pojedynczej pandzie DataFrame. Podziel go na zestawy treningowe, walidacyjne i testowe, stosując na przykład stosunek 80:10:10, odpowiednio:

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

Utwórz potok wejściowy za pomocą tf.data

Następnie należy utworzyć funkcję użytkową, który przekształca każdy szkolenia Walidacja oraz badanie określone DataFrame w tf.data.Dataset , następnie tasuje i porcje danych.

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

Teraz można użyć nowo utworzoną funkcję ( df_to_dataset ), aby sprawdzić format danych wejściowych funkcja zwraca rurociąg pomocnicze nazywając go na danych treningowych i użyj małej wielkości wsadu, aby utrzymać produkcję czytelny:

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)

Jak pokazują dane wyjściowe, zestaw uczący zwraca słownik nazw kolumn (z DataFrame), które mapują wartości kolumn z wierszy.

Zastosuj warstwy obróbki wstępnej Keras

Warstwy przetwarzania wstępnego Keras umożliwiają tworzenie natywnych potoków przetwarzania danych wejściowych Keras, które mogą być używane jako niezależny kod przetwarzania wstępnego w przepływach pracy innych niż Keras, połączone bezpośrednio z modelami Keras i eksportowane jako część Keras SavedModel.

W tym samouczku użyjesz następujących czterech warstw przetwarzania wstępnego, aby zademonstrować, jak wykonać przetwarzanie wstępne, kodowanie danych strukturalnych i inżynierię funkcji:

Możesz dowiedzieć się więcej na temat dostępnych warstw w Praca z przerób warstw przewodnika.

  • Dla funkcji liczbowych na zbiorze PetFinder.my mini, można użyć tf.keras.layers.Normalization warstwę standaryzacja dystrybucji danych.
  • Dla kategorycznych funkcji, takich jak zwierzę Type S ( Dog i Cat strings), można przekształcić je do wielu gorących zakodowanych tensorów z tf.keras.layers.CategoryEncoding .

Kolumny numeryczne

Dla każdej funkcji numerycznych w zbiorze PetFinder.my mini, można użyć tf.keras.layers.Normalization warstwę standaryzacja dystrybucji danych.

Zdefiniuj nową funkcję narzędziową, która zwraca warstwę, która stosuje normalizację cech do cech numerycznych przy użyciu tej warstwy przetwarzania wstępnego 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

Następnie przetestować nową funkcję, nazywając ją na całkowity upload zdjęcie zwierzaka wyposażony znormalizować '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)>

Kolumny kategorialne

Pet Type s w zbiorze danych są reprezentowane strings- Dog s i Cat s-które muszą być multi-gorący zakodowane przed wprowadzeniem do modelu. Age cecha

Określić kolejną nową funkcję użytkową, która zwraca warstwę, która odwzorowuje wartości od słownika indeksów całkowitej oraz wiele gorących koduje FUNKCJE tf.keras.layers.StringLookup , tf.keras.layers.IntegerLookup i tf.keras.CategoryEncoding przerób warstwy:

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))

Przetestować get_category_encoding_layer funkcję nazywając go PET 'Type' dysponuje, aby włączyć je do wielu gorących zakodowanych tensorów:

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)>

Powtórz ten proces na zwierzę 'Age' funkcje:

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)>

Wstępnie przetwórz wybrane funkcje, aby trenować model

Nauczyłeś się korzystać z kilku rodzajów warstw przetwarzania wstępnego Keras. Następnie będziesz:

  • Zastosuj zdefiniowane wcześniej funkcje narzędziowe do przetwarzania wstępnego na 13 numerycznych i kategorycznych funkcjach z mini zbioru danych PetFinder.my.
  • Dodaj wszystkie dane wejściowe funkcji do listy.

Jak wspomniano na początku, do pociągu modelu, można użyć numerycznego PetFinder.my mini danej jednostki ( 'PhotoAmt' , 'Fee' ) i kategoryczne ( 'Age' , 'Type' , 'Color1' , 'Color2' , 'Gender' , 'MaturitySize' , 'FurLength' , 'Vaccinated' , 'Sterilized' , 'Health' , 'Breed1' ) funkcje.

Wcześniej użyłeś małego rozmiaru partii, aby zademonstrować potok wejściowy. Utwórzmy teraz nowy potok wejściowy z większym rozmiarem partii 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.

Normalizować funkcje numeryczne (liczba zdjęć domowych i opłaty przyjęcie), i dodać je do jednej listy wejść zwanych 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)

Włączyć liczb całkowitych kategoryczne z zestawu danych (wiek PET) w indeksach całkowitą wykonać wiele gorącej kodowania i dodać sygnały wejściowe funkcji do 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)

Powtórz ten sam krok dla wartości kategorycznych ciągu:

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)

Twórz, kompiluj i trenuj model

Następnym krokiem jest stworzenie modelu przy użyciu API Functional Keras . Dla pierwszej warstwy w modelu, łączenie listę funkcji WEJÂCIA encoded_features -into jednego wektora poprzez łączenie z 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)

Skonfigurować model z Keras Model.compile :

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

Zwizualizujmy wykres łączności:

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

png

Następnie przeszkol i przetestuj model:

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

Wykonaj wnioskowanie

Opracowany model może teraz klasyfikować wiersz z pliku CSV bezpośrednio po dołączeniu warstw przetwarzania wstępnego do samego modelu.

Można teraz zapisać i odświeżyć model Keras z Model.save i Model.load_model przed wykonaniem wnioskowanie na nowych danych:

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

Aby uzyskać prognozy dla nowej próbki, można po prostu zadzwonić do Keras Model.predict metody. Musisz zrobić tylko dwie rzeczy:

  1. Wrap skalary na listę, tak aby mieć wymiar wsadowego ( Model jedynej partii danych procesowych, a nie pojedynczych próbek).
  2. Zadzwoń tf.convert_to_tensor na każdej funkcji.
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.

Następne kroki

Aby dowiedzieć się więcej o klasyfikowaniu uporządkowanych danych, spróbuj pracować z innymi zbiorami danych. Aby poprawić dokładność podczas uczenia i testowania modeli, zastanów się dokładnie, które funkcje należy uwzględnić w modelu i jak powinny być reprezentowane.

Poniżej znajduje się kilka sugestii dotyczących zbiorów danych: