Visualizza su TensorFlow.org | Esegui in Google Colab | Visualizza l'origine su GitHub | Scarica quaderno |
Questo tutorial mostra come classificare i dati strutturati, come i dati tabulari, utilizzando una versione semplificata del set di dati PetFinder da una competizione Kaggle archiviata in un file CSV.
Utilizzerai Keras per definire il modello e i livelli di preelaborazione Keras come ponte per mappare dalle colonne in un file CSV alle funzioni utilizzate per addestrare il modello. L'obiettivo è prevedere se un animale domestico verrà adottato.
Questo tutorial contiene il codice completo per:
- Caricamento di un file CSV in un DataFrame utilizzando Pandas .
- Creazione di una pipeline di input per eseguire in batch e mescolare le righe utilizzando
tf.data
. (Visita tf.data: Build pipeline di input TensorFlow per maggiori dettagli.) - Mappatura dalle colonne nel file CSV alle funzionalità utilizzate per addestrare il modello con i livelli di preelaborazione Keras.
- Costruire, addestrare e valutare un modello utilizzando i metodi integrati di Keras.
Il mini set di dati PetFinder.my
Ci sono diverse migliaia di righe nel file del set di dati CSV di PetFinder.my mini, in cui ogni riga descrive un animale domestico (un cane o un gatto) e ogni colonna descrive un attributo, come età, razza, colore e così via.
Nel riepilogo del set di dati riportato di seguito, si noti che sono presenti principalmente colonne numeriche e categoriali. In questo tutorial, ti occuperai solo di questi due tipi di funzionalità, rilasciando Description
(una funzionalità di testo libero) e AdoptionSpeed
(una funzionalità di classificazione) durante la preelaborazione dei dati.
Colonna | Descrizione dell'animale domestico | Tipo di caratteristica | Tipo di dati |
---|---|---|---|
Type | Tipo di animale ( Dog , Cat ) | Categorico | Corda |
Age | Età | Numerico | Numero intero |
Breed1 | Razza primaria | Categorico | Corda |
Color1 | Colore 1 | Categorico | Corda |
Color2 | Colore 2 | Categorico | Corda |
MaturitySize | Taglia a maturità | Categorico | Corda |
FurLength | Lunghezza della pelliccia | Categorico | Corda |
Vaccinated | L'animale è stato vaccinato | Categorico | Corda |
Sterilized | L'animale è stato sterilizzato | Categorico | Corda |
Health | Condizione di salute | Categorico | Corda |
Fee | Tassa di adozione | Numerico | Numero intero |
Description | Redazione del profilo | Testo | Corda |
PhotoAmt | Totale foto caricate | Numerico | Numero intero |
AdoptionSpeed | Velocità categoriale di adozione | Classificazione | Numero intero |
Importa TensorFlow e altre librerie
import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow.keras import layers
tf.__version__
'2.8.0-rc1'
Carica il set di dati e leggilo in un DataFrame panda
pandas è una libreria Python con molte utili utilità per caricare e lavorare con dati strutturati. Usa tf.keras.utils.get_file
per scaricare ed estrarre il file CSV con il mini set di dati PetFinder.my e caricarlo in un DataFrame 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
Ispeziona il set di dati controllando le prime cinque righe di DataFrame:
dataframe.head()
Crea una variabile di destinazione
Il compito originale del concorso PetFinder.my Adoption Prediction di Kaggle era di prevedere la velocità con cui un animale domestico verrà adottato (ad es. nella prima settimana, nel primo mese, nei primi tre mesi e così via).
In questo tutorial, semplificherai il compito trasformandolo in un problema di classificazione binaria, in cui devi semplicemente prevedere se un animale domestico è stato adottato o meno.
Dopo aver modificato la colonna AdoptionSpeed
, 0
indicherà che l'animale non è stato adottato e 1
indicherà che lo 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'])
Suddividi il DataFrame in set di training, convalida e test
Il set di dati è in un singolo DataFrame panda. Suddividilo in set di addestramento, convalida e test utilizzando, ad esempio, un rapporto 80:10:10, rispettivamente:
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 pipeline di input usando tf.data
Quindi, crea una funzione di utilità che converte ogni set di dati di training, convalida e test DataFrame in un tf.data.Dataset
, quindi mescola e raggruppa i dati in batch.
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
Ora, usa la funzione appena creata ( df_to_dataset
) per controllare il formato dei dati che la funzione di supporto della pipeline di input restituisce chiamandola sui dati di addestramento e usa una piccola dimensione batch per mantenere leggibile l'output:
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( [[84] [ 1] [ 5] [ 1] [12]], shape=(5, 1), dtype=int64) A batch of targets: tf.Tensor([1 1 0 1 0], shape=(5,), dtype=int64)
Come dimostra l'output, il set di addestramento restituisce un dizionario di nomi di colonna (da DataFrame) che esegue il mapping ai valori di colonna dalle righe.
Applicare i livelli di preelaborazione Keras
I livelli di preelaborazione Keras consentono di creare pipeline di elaborazione dell'input Keras native, che possono essere utilizzate come codice di preelaborazione indipendente nei flussi di lavoro non Keras, combinate direttamente con i modelli Keras ed esportate come parte di un Keras SavedModel.
In questo tutorial, utilizzerai i seguenti quattro livelli di preelaborazione per dimostrare come eseguire la preelaborazione, la codifica dei dati strutturati e l'ingegneria delle funzionalità:
-
tf.keras.layers.Normalization
: esegue la normalizzazione delle funzionalità di input. -
tf.keras.layers.CategoryEncoding
: trasforma le caratteristiche categoriali intere in rappresentazioni one-hot, multi-hot o tf-idf dense. -
tf.keras.layers.StringLookup
: trasforma i valori categoriali delle stringhe in indici interi. -
tf.keras.layers.IntegerLookup
: trasforma i valori categoriali interi in indici interi.
Puoi saperne di più sui livelli disponibili nella guida Lavorare con i livelli di preelaborazione .
- Per le funzionalità numeriche del mini set di dati PetFinder.my, utilizzerai un livello
tf.keras.layers.Normalization
per standardizzare la distribuzione dei dati. - Per le caratteristiche categoriali , come pet
Type
s (stringheDog
eCat
), le trasformerai in tensori codificati multi-hot contf.keras.layers.CategoryEncoding
.
Colonne numeriche
Per ogni caratteristica numerica nel mini set di dati PetFinder.my, utilizzerai un livello tf.keras.layers.Normalization
per standardizzare la distribuzione dei dati.
Definire una nuova funzione di utilità che restituisce un livello che applica la normalizzazione in base alle caratteristiche alle caratteristiche numeriche utilizzando quel livello di preelaborazione 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
Quindi, testa la nuova funzione chiamandola sulle funzionalità totali delle foto degli animali caricate per normalizzare '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.8272058 ], [-0.19125296], [ 1.3986291 ], [-0.19125296], [-0.50922936]], dtype=float32)>
Colonne categoriali
Type
di animali domestici nel set di dati sono rappresentati come stringhe, Dog
s e Cat
s, che devono essere codificate multi-hot prima di essere inserite nel modello. La funzione Age
Definire un'altra nuova funzione di utilità che restituisce un livello che mappa i valori da un vocabolario a indici interi e codifica multi-hot le funzionalità utilizzando la tf.keras.layers.StringLookup
, tf.keras.layers.IntegerLookup
e tf.keras.CategoryEncoding
strati:
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))
Testare la funzione get_category_encoding_layer
chiamandola sulle funzionalità pet 'Type'
per trasformarle in tensori codificati multi-hot:
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., 1., 0.], [0., 1., 0.], [0., 1., 0.], [0., 1., 0.]], dtype=float32)>
Ripeti il processo sulle caratteristiche 'Age'
dell'animale domestico:
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([[1., 0., 0., 0., 0.], [0., 0., 0., 1., 0.], [1., 0., 0., 0., 0.], [0., 0., 0., 1., 0.], [1., 0., 0., 0., 0.]], dtype=float32)>
Preelabora le funzioni selezionate su cui addestrare il modello
Hai imparato come utilizzare diversi tipi di livelli di preelaborazione Keras. Successivamente, dovrai:
- Applicare le funzioni di utilità di preelaborazione definite in precedenza su 13 funzioni numeriche e categoriali dal mini set di dati PetFinder.my.
- Aggiungi tutti gli input di funzionalità a un elenco.
Come accennato all'inizio, per addestrare il modello, utilizzerai il mini set di dati PetFinder.my numerico ( 'PhotoAmt'
, 'Fee'
) e categoriale ( 'Age'
, 'Type'
, 'Color1'
, 'Color2'
, 'Gender'
Caratteristiche di 'Gender'
, 'MaturitySize'
, 'FurLength'
, 'Vaccinated'
, 'Sterilized'
, 'Health'
, 'Breed1'
).
In precedenza, hai usato una piccola dimensione batch per dimostrare la pipeline di input. Creiamo ora una nuova pipeline di input con una dimensione batch maggiore di 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.
Normalizza le caratteristiche numeriche (il numero di foto degli animali domestici e la quota di adozione) e aggiungile a un elenco di input chiamato 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)
Trasforma i valori categoriali interi dal set di dati (l'età degli animali domestici) in indici interi, esegui la codifica multi-hot e aggiungi gli input delle funzionalità risultanti 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)
Ripetere lo stesso passaggio per i valori categoriali della stringa:
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)
Crea, compila e addestra il modello
Il passaggio successivo consiste nel creare un modello utilizzando l' API funzionale Keras . Per il primo livello nel tuo modello, unisci l'elenco di input di funzionalità - encoded_features
- in un vettore tramite concatenazione 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)
Configura il modello con Keras Model.compile
:
model.compile(optimizer='adam',
loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
metrics=["accuracy"])
Visualizziamo il grafico della connettività:
# Use `rankdir='LR'` to make the graph horizontal.
tf.keras.utils.plot_model(model, show_shapes=True, rankdir="LR")
Quindi, addestra e testa il modello:
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 19ms/step - loss: 0.6524 - accuracy: 0.5034 - val_loss: 0.5887 - val_accuracy: 0.6941 Epoch 2/10 37/37 [==============================] - 0s 8ms/step - loss: 0.5906 - accuracy: 0.6648 - val_loss: 0.5627 - val_accuracy: 0.7218 Epoch 3/10 37/37 [==============================] - 0s 8ms/step - loss: 0.5697 - accuracy: 0.6924 - val_loss: 0.5463 - val_accuracy: 0.7504 Epoch 4/10 37/37 [==============================] - 0s 8ms/step - loss: 0.5558 - accuracy: 0.6978 - val_loss: 0.5346 - val_accuracy: 0.7504 Epoch 5/10 37/37 [==============================] - 0s 8ms/step - loss: 0.5502 - accuracy: 0.7105 - val_loss: 0.5272 - val_accuracy: 0.7487 Epoch 6/10 37/37 [==============================] - 0s 8ms/step - loss: 0.5415 - accuracy: 0.7123 - val_loss: 0.5210 - val_accuracy: 0.7608 Epoch 7/10 37/37 [==============================] - 0s 8ms/step - loss: 0.5354 - accuracy: 0.7171 - val_loss: 0.5152 - val_accuracy: 0.7435 Epoch 8/10 37/37 [==============================] - 0s 8ms/step - loss: 0.5301 - accuracy: 0.7214 - val_loss: 0.5113 - val_accuracy: 0.7513 Epoch 9/10 37/37 [==============================] - 0s 8ms/step - loss: 0.5286 - accuracy: 0.7189 - val_loss: 0.5087 - val_accuracy: 0.7574 Epoch 10/10 37/37 [==============================] - 0s 8ms/step - loss: 0.5252 - accuracy: 0.7260 - val_loss: 0.5058 - val_accuracy: 0.7539 <keras.callbacks.History at 0x7f5f9fa91c50>
loss, accuracy = model.evaluate(test_ds)
print("Accuracy", accuracy)
5/5 [==============================] - 0s 6ms/step - loss: 0.5012 - accuracy: 0.7626 Accuracy 0.762565016746521
Eseguire l'inferenza
Il modello che hai sviluppato ora può classificare una riga da un file CSV direttamente dopo aver incluso i livelli di preelaborazione all'interno del modello stesso.
Ora puoi salvare e ricaricare il modello Keras con Model.save
e Model.load_model
prima di eseguire l'inferenza sui nuovi dati:
model.save('my_pet_classifier')
reloaded_model = tf.keras.models.load_model('my_pet_classifier')
2022-01-26 06:20:08.013613: 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
Per ottenere una previsione per un nuovo campione, puoi semplicemente chiamare il metodo Keras Model.predict
. Ci sono solo due cose che devi fare:
- Avvolgere gli scalari in un elenco in modo da avere una dimensione batch (il
Model
elabora solo batch di dati, non singoli campioni). - Chiama
tf.convert_to_tensor
su ciascuna funzione.
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 77.7 percent probability of getting adopted.
Prossimi passi
Per ulteriori informazioni sulla classificazione dei dati strutturati, prova a lavorare con altri set di dati. Per migliorare la precisione durante l'addestramento e il test dei tuoi modelli, pensa attentamente a quali funzionalità includere nel tuo modello e come dovrebbero essere rappresentate.
Di seguito sono riportati alcuni suggerimenti per i set di dati:
- Set di dati TensorFlow: MovieLens : un insieme di valutazioni di film da un servizio di consigli sui film.
- Set di dati TensorFlow: Qualità del vino : due set di dati relativi alle varianti rosse e bianche del vino portoghese "Vinho Verde". Puoi anche trovare il set di dati sulla qualità del vino rosso su Kaggle .
- Kaggle: arXiv Dataset : un corpus di 1,7 milioni di articoli accademici di arXiv, che coprono fisica, informatica, matematica, statistica, ingegneria elettrica, biologia quantitativa ed economia.