Veja no TensorFlow.org | Executar no Google Colab | Ver fonte no GitHub | Baixar caderno |
Este tutorial demonstra como classificar dados estruturados, como dados tabulares, usando uma versão simplificada do conjunto de dados PetFinder de uma competição Kaggle armazenada em um arquivo CSV.
Você usará o Keras para definir o modelo e as camadas de pré-processamento do Keras como uma ponte para mapear as colunas em um arquivo CSV para os recursos usados para treinar o modelo. O objetivo é prever se um animal de estimação será adotado.
Este tutorial contém código completo para:
- Carregando um arquivo CSV em um DataFrame usando pandas .
- Construindo um pipeline de entrada para agrupar e embaralhar as linhas usando
tf.data
. (Visite tf.data: criar pipelines de entrada do TensorFlow para obter mais detalhes.) - Mapeamento de colunas no arquivo CSV para recursos usados para treinar o modelo com as camadas de pré-processamento Keras.
- Construindo, treinando e avaliando um modelo usando os métodos integrados do Keras.
O miniconjunto de dados PetFinder.my
Existem milhares de linhas no arquivo de conjunto de dados CSV do PetFinder.my mini, onde cada linha descreve um animal de estimação (um cachorro ou um gato) e cada coluna descreve um atributo, como idade, raça, cor e assim por diante.
No resumo do conjunto de dados abaixo, observe que há principalmente colunas numéricas e categóricas. Neste tutorial, você estará lidando apenas com esses dois tipos de recursos, descartando Description
(um recurso de texto livre) e AdoptionSpeed
(um recurso de classificação) durante o pré-processamento de dados.
Coluna | Descrição do animal de estimação | Tipo de recurso | Tipo de dados |
---|---|---|---|
Type | Tipo de animal ( Dog , Cat ) | Categórico | Corda |
Age | Era | Numérico | inteiro |
Breed1 | Raça primária | Categórico | Corda |
Color1 | Cor 1 | Categórico | Corda |
Color2 | Cor 2 | Categórico | Corda |
MaturitySize | Tamanho na maturidade | Categórico | Corda |
FurLength | Comprimento do pelo | Categórico | Corda |
Vaccinated | O animal de estimação foi vacinado | Categórico | Corda |
Sterilized | O animal de estimação foi esterilizado | Categórico | Corda |
Health | Condição de saúde | Categórico | Corda |
Fee | Taxa de adoção | Numérico | inteiro |
Description | Redação de perfil | Texto | Corda |
PhotoAmt | Total de fotos enviadas | Numérico | inteiro |
AdoptionSpeed | Velocidade categórica de adoção | Classificação | inteiro |
Importar TensorFlow e outras bibliotecas
import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow.keras import layers
tf.__version__
'2.8.0-rc1'
Carregue o conjunto de dados e leia-o em um DataFrame pandas
pandas é uma biblioteca Python com muitos utilitários úteis para carregar e trabalhar com dados estruturados. Use tf.keras.utils.get_file
para baixar e extrair o arquivo CSV com o mini conjunto de dados PetFinder.my e carregue-o em um DataFrame com 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
Inspecione o conjunto de dados verificando as cinco primeiras linhas do DataFrame:
dataframe.head()
Criar uma variável de destino
A tarefa original na competição PetFinder.my Adoption Prediction do Kaggle era prever a velocidade com que um animal de estimação seria adotado (por exemplo, na primeira semana, no primeiro mês, nos primeiros três meses e assim por diante).
Neste tutorial, você simplificará a tarefa transformando-a em um problema de classificação binária, onde você simplesmente terá que prever se um animal de estimação foi adotado ou não.
Após modificar a coluna AdoptionSpeed
, 0
indicará que o animal não foi adotado e 1
indicará que foi.
# 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 o DataFrame em conjuntos de treinamento, validação e teste
O conjunto de dados está em um único DataFrame de pandas. Divida-o em conjuntos de treinamento, validação e teste usando, por exemplo, uma proporção 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
Crie um pipeline de entrada usando tf.data
Em seguida, crie uma função de utilitário que converta cada DataFrame de treinamento, validação e conjunto de teste em um tf.data.Dataset
e, em seguida, embaralhe e agrupa os dados.
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
Agora, use a função recém-criada ( df_to_dataset
) para verificar o formato dos dados que a função auxiliar do pipeline de entrada retorna chamando-a nos dados de treinamento e use um tamanho de lote pequeno para manter a saída legível:
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)
Como a saída demonstra, o conjunto de treinamento retorna um dicionário de nomes de coluna (do DataFrame) que mapeia para valores de coluna de linhas.
Aplique as camadas de pré-processamento Keras
As camadas de pré-processamento Keras permitem que você crie pipelines de processamento de entrada nativos do Keras, que podem ser usados como código de pré-processamento independente em fluxos de trabalho não Keras, combinados diretamente com modelos Keras e exportados como parte de um Keras SavedModel.
Neste tutorial, você usará as quatro camadas de pré-processamento a seguir para demonstrar como realizar o pré-processamento, a codificação de dados estruturados e a engenharia de recursos:
-
tf.keras.layers.Normalization
: Executa a normalização de recursos de entrada. -
tf.keras.layers.CategoryEncoding
: Transforma recursos categóricos inteiros em representações densas one-hot, multi-hot ou tf-idf . -
tf.keras.layers.StringLookup
: Transforma valores categóricos de string em índices inteiros. -
tf.keras.layers.IntegerLookup
: Transforma valores categóricos inteiros em índices inteiros.
Você pode aprender mais sobre as camadas disponíveis no guia Trabalhando com camadas de pré-processamento .
- Para recursos numéricos do mini conjunto de dados PetFinder.my, você usará uma camada
tf.keras.layers.Normalization
para padronizar a distribuição dos dados. - Para recursos categóricos , como pet
Type
s (cadeiasDog
eCat
), você os transformará em tensores codificados multi-hot comtf.keras.layers.CategoryEncoding
.
Colunas numéricas
Para cada recurso numérico no miniconjunto de dados PetFinder.my, você usará uma camada tf.keras.layers.Normalization
para padronizar a distribuição dos dados.
Defina uma nova função de utilitário que retorna uma camada que aplica a normalização de recursos a recursos numéricos usando essa camada de pré-processamento 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
Em seguida, teste a nova função chamando-a no total de recursos de fotos de animais de estimação enviados 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.8272058 ], [-0.19125296], [ 1.3986291 ], [-0.19125296], [-0.50922936]], dtype=float32)>
Colunas categóricas
Type
de animais de estimação no conjunto de dados são representados como strings — Dog
s e Cat
s — que precisam ser codificados multi-hot antes de serem inseridos no modelo. O recurso Age
Defina outra nova função de utilitário que retorne uma camada que mapeie valores de um vocabulário para índices inteiros e multi-hot codifica os recursos usando o pré-processamento tf.keras.layers.StringLookup
, tf.keras.layers.IntegerLookup
e tf.keras.CategoryEncoding
camadas:
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))
Teste a função get_category_encoding_layer
chamando-a em recursos pet 'Type'
para transformá-los em tensores codificados 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)>
Repita o processo nos recursos 'Age'
do animal de estimação:
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)>
Pré-processar recursos selecionados para treinar o modelo
Você aprendeu como usar vários tipos de camadas de pré-processamento Keras. A seguir, você irá:
- Aplique as funções de utilitário de pré-processamento definidas anteriormente em 13 recursos numéricos e categóricos do mini conjunto de dados PetFinder.my.
- Adicione todas as entradas de recursos a uma lista.
Como mencionado no início, para treinar o modelo, você usará o mini conjunto de dados do PetFinder.my numérico ( 'PhotoAmt'
, 'Fee'
) e categórico ( 'Age'
, 'Type'
, 'Color1'
, 'Color2 'Color2'
, 'Gender'
, 'MaturitySize'
, 'FurLength'
, 'Vaccinated'
, 'Sterilized'
, 'Health'
, 'Breed1'
).
Anteriormente, você usou um tamanho de lote pequeno para demonstrar o pipeline de entrada. Vamos agora criar um novo pipeline de entrada com um tamanho de lote maior 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.
Normalize os recursos numéricos (o número de fotos de animais de estimação e a taxa de adoção) e adicione-os a uma lista de entradas chamada 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)
Transforme os valores categóricos inteiros do conjunto de dados (a idade do animal de estimação) em índices inteiros, execute a codificação multi-hot e adicione as entradas de recursos 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 a mesma etapa para os valores categóricos de 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(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)
Criar, compilar e treinar o modelo
A próxima etapa é criar um modelo usando a API funcional Keras . Para a primeira camada em seu modelo, mescle a lista de entradas de recursos encoded_features
—em um vetor via concatenação com 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)
Configure o modelo com Keras Model.compile
:
model.compile(optimizer='adam',
loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
metrics=["accuracy"])
Vamos visualizar o gráfico de conectividade:
# Use `rankdir='LR'` to make the graph horizontal.
tf.keras.utils.plot_model(model, show_shapes=True, rankdir="LR")
Em seguida, treine e teste o 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 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
Realizar inferência
O modelo que você desenvolveu agora pode classificar uma linha de um arquivo CSV diretamente depois de incluir as camadas de pré-processamento dentro do próprio modelo.
Agora você pode salvar e recarregar o modelo Keras com Model.save
e Model.load_model
antes de realizar a inferência em novos dados:
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
Para obter uma previsão para uma nova amostra, basta chamar o método Keras Model.predict
. Há apenas duas coisas que você precisa fazer:
- Envolva escalares em uma lista para ter uma dimensão de lote (os
Model
processam apenas lotes de dados, não amostras únicas). - Chame
tf.convert_to_tensor
em cada recurso.
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.
Próximos passos
Para saber mais sobre como classificar dados estruturados, tente trabalhar com outros conjuntos de dados. Para melhorar a precisão durante o treinamento e teste de seus modelos, pense cuidadosamente sobre quais recursos incluir em seu modelo e como eles devem ser representados.
Abaixo estão algumas sugestões para conjuntos de dados:
- Conjuntos de dados do TensorFlow: MovieLens : um conjunto de classificações de filmes de um serviço de recomendação de filmes.
- Conjuntos de dados do TensorFlow: Qualidade do vinho : Dois conjuntos de dados relacionados com as variantes tinto e branco do vinho português "Vinho Verde". Você também pode encontrar o conjunto de dados de Qualidade do Vinho Tinto no Kaggle .
- Kaggle: arXiv Conjunto de dados: Um corpus de 1,7 milhão de artigos acadêmicos do arXiv, abrangendo física, ciência da computação, matemática, estatística, engenharia elétrica, biologia quantitativa e economia.