Klasifikasikan data terstruktur menggunakan lapisan prapemrosesan Keras

Lihat di TensorFlow.org Jalankan di Google Colab Lihat sumber di GitHub Unduh buku catatan

Tutorial ini menunjukkan cara mengklasifikasikan data terstruktur, seperti data tabular, menggunakan versi sederhana dari kumpulan data PetFinder dari kompetisi Kaggle yang disimpan dalam file CSV.

Anda akan menggunakan Keras untuk mendefinisikan model, dan lapisan prapemrosesan Keras sebagai jembatan untuk memetakan dari kolom dalam file CSV ke fitur yang digunakan untuk melatih model. Tujuannya adalah untuk memprediksi apakah hewan peliharaan akan diadopsi.

Tutorial ini berisi kode lengkap untuk:

  • Memuat file CSV ke dalam DataFrame menggunakan pandas .
  • Membangun pipa input untuk mengelompokkan dan mengacak baris menggunakan tf.data . (Kunjungi tf.data: Membangun pipeline input TensorFlow untuk detail selengkapnya.)
  • Pemetaan dari kolom dalam file CSV ke fitur yang digunakan untuk melatih model dengan lapisan prapemrosesan Keras.
  • Membangun, melatih, dan mengevaluasi model menggunakan metode bawaan Keras.

Kumpulan data mini PetFinder.my

Ada beberapa ribu baris dalam file dataset CSV PetFinder.my mini, di mana setiap baris menggambarkan hewan peliharaan (anjing atau kucing) dan setiap kolom menggambarkan atribut, seperti usia, jenis, warna, dan sebagainya.

Dalam ringkasan dataset di bawah ini, perhatikan sebagian besar kolom numerik dan kategoris. Dalam tutorial ini, Anda hanya akan berurusan dengan dua jenis fitur tersebut, menjatuhkan Description (fitur teks gratis) dan AdoptionSpeed (fitur klasifikasi) selama prapemrosesan data.

Kolom Deskripsi hewan peliharaan Jenis fitur Tipe data
Type Jenis hewan ( Dog , Cat ) kategoris Rangkaian
Age Usia numerik Bilangan bulat
Breed1 Trah primer kategoris Rangkaian
Color1 Warna 1 kategoris Rangkaian
Color2 Warna 2 kategoris Rangkaian
MaturitySize Ukuran saat jatuh tempo kategoris Rangkaian
FurLength panjang bulu kategoris Rangkaian
Vaccinated Hewan peliharaan telah divaksinasi kategoris Rangkaian
Sterilized Hewan peliharaan telah disterilkan kategoris Rangkaian
Health Kondisi kesehatan kategoris Rangkaian
Fee Biaya adopsi numerik Bilangan bulat
Description penulisan profil Teks Rangkaian
PhotoAmt Jumlah foto yang diunggah numerik Bilangan bulat
AdoptionSpeed Kecepatan adopsi kategoris Klasifikasi Bilangan bulat

Impor TensorFlow dan perpustakaan lainnya

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

from tensorflow.keras import layers
tf.__version__
'2.8.0-rc1'

Muat dataset dan baca ke dalam pandas DataFrame

pandas adalah pustaka Python dengan banyak utilitas bermanfaat untuk memuat dan bekerja dengan data terstruktur. Gunakan tf.keras.utils.get_file untuk mengunduh dan mengekstrak file CSV dengan dataset mini PetFinder.my, dan memuatnya ke dalam DataFrame dengan 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

Periksa kumpulan data dengan memeriksa lima baris pertama DataFrame:

dataframe.head()

Buat variabel target

Tugas awal dalam kompetisi Prediksi Adopsi PetFinder.my Kaggle adalah memprediksi kecepatan adopsi hewan peliharaan (misalnya di minggu pertama, bulan pertama, tiga bulan pertama, dan seterusnya).

Dalam tutorial ini, Anda akan menyederhanakan tugas dengan mengubahnya menjadi masalah klasifikasi biner, di mana Anda hanya perlu memprediksi apakah hewan peliharaan diadopsi atau tidak.

Setelah memodifikasi kolom AdoptionSpeed , 0 akan menunjukkan hewan peliharaan tidak diadopsi, dan 1 akan menunjukkan itu.

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

Pisahkan DataFrame menjadi set pelatihan, validasi, dan pengujian

Dataset ada dalam satu DataFrame panda. Bagi menjadi pelatihan, validasi, dan set pengujian menggunakan, misalnya, rasio 80:10:10, masing-masing:

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

Buat saluran input menggunakan tf.data

Selanjutnya, buat fungsi utilitas yang mengubah setiap pelatihan, validasi, dan kumpulan uji DataFrame menjadi tf.data.Dataset , lalu mengacak dan mengelompokkan data.

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

Sekarang, gunakan fungsi yang baru dibuat ( df_to_dataset ) untuk memeriksa format data yang dikembalikan oleh fungsi pembantu pipa input dengan memanggilnya pada data pelatihan, dan gunakan ukuran batch kecil agar output tetap dapat dibaca:

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)

Seperti yang ditunjukkan oleh output, set pelatihan mengembalikan kamus nama kolom (dari DataFrame) yang memetakan ke nilai kolom dari baris.

Terapkan lapisan pra-pemrosesan Keras

Lapisan prapemrosesan Keras memungkinkan Anda membangun saluran pemrosesan input asli Keras, yang dapat digunakan sebagai kode prapemrosesan independen dalam alur kerja non-Keras, digabungkan langsung dengan model Keras, dan diekspor sebagai bagian dari Keras SavedModel.

Dalam tutorial ini, Anda akan menggunakan empat lapisan prapemrosesan berikut untuk mendemonstrasikan cara melakukan prapemrosesan, penyandian data terstruktur, dan rekayasa fitur:

Anda dapat mempelajari lebih lanjut tentang lapisan yang tersedia di panduan Bekerja dengan lapisan prapemrosesan .

  • Untuk fitur numerik dari dataset mini PetFinder.my, Anda akan menggunakan lapisan tf.keras.layers.Normalization untuk menstandardisasi distribusi data.
  • Untuk fitur kategoris , seperti pet Type s ( String Dog dan Cat ), Anda akan mengubahnya menjadi tensor yang disandikan multi-panas dengan tf.keras.layers.CategoryEncoding .

Kolom numerik

Untuk setiap fitur numerik di dataset mini PetFinder.my, Anda akan menggunakan lapisan tf.keras.layers.Normalization untuk menstandardisasi distribusi data.

Tentukan fungsi utilitas baru yang mengembalikan lapisan yang menerapkan normalisasi fitur ke fitur numerik menggunakan lapisan prapemrosesan Keras itu:

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

Selanjutnya, uji fungsi baru dengan memanggilnya pada total fitur foto hewan peliharaan yang diunggah untuk menormalkan '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)>

Kolom kategoris

Pet Type s dalam dataset direpresentasikan sebagai string— Dog s dan Cat s—yang perlu di-encode multi-hot sebelum dimasukkan ke dalam model. Fitur Age

Tetapkan fungsi utilitas baru lainnya yang mengembalikan lapisan yang memetakan nilai dari kosakata ke indeks bilangan bulat dan mengkodekan fitur multi-hot menggunakan tf.keras.layers.StringLookup , tf.keras.layers.IntegerLookup , dan tf.keras.CategoryEncoding prapemrosesan lapisan:

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

Uji fungsi get_category_encoding_layer dengan memanggilnya pada fitur pet 'Type' untuk mengubahnya menjadi tensor yang disandikan multi-panas:

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

Ulangi proses pada fitur 'Age' hewan peliharaan:

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

Praproses fitur yang dipilih untuk melatih model pada

Anda telah mempelajari cara menggunakan beberapa jenis lapisan prapemrosesan Keras. Selanjutnya, Anda akan:

  • Terapkan fungsi utilitas prapemrosesan yang ditentukan sebelumnya pada 13 fitur numerik dan kategoris dari kumpulan data mini PetFinder.my.
  • Tambahkan semua input fitur ke daftar.

Seperti yang disebutkan di awal, untuk melatih model, Anda akan menggunakan dataset mini PetFinder.my numerik ( 'PhotoAmt' , 'Fee' ) dan categorical ( 'Age' , 'Type' , 'Color1' , 'Color2' , 'Gender' , 'Ukuran 'MaturitySize' , 'FurLength' , 'Vaccinated' , 'Disterilkan 'Sterilized' , 'Health' , 'Breed1' ) fitur.

Sebelumnya, Anda menggunakan ukuran batch kecil untuk mendemonstrasikan saluran input. Sekarang mari kita buat pipeline input baru dengan ukuran batch 256 yang lebih besar:

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.

Normalisasi fitur numerik (jumlah foto hewan peliharaan dan biaya adopsi), dan tambahkan ke satu daftar input yang disebut 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)

Ubah nilai kategorikal bilangan bulat dari kumpulan data (usia hewan peliharaan) menjadi indeks bilangan bulat, lakukan penyandian multi-panas, dan tambahkan input fitur yang dihasilkan ke 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)

Ulangi langkah yang sama untuk nilai kategorikal 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)

Buat, kompilasi, dan latih model

Langkah selanjutnya adalah membuat model menggunakan Keras Functional API . Untuk lapisan pertama dalam model Anda, gabungkan daftar input fitur— encoded_features —ke dalam satu vektor melalui penggabungan dengan 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)

Konfigurasi model dengan Keras Model.compile :

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

Mari kita visualisasikan grafik konektivitas:

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

png

Selanjutnya, latih dan uji 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 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

Lakukan inferensi

Model yang telah Anda kembangkan sekarang dapat mengklasifikasikan baris dari file CSV secara langsung setelah Anda menyertakan lapisan prapemrosesan di dalam model itu sendiri.

Anda sekarang dapat menyimpan dan memuat ulang model Keras dengan Model.save dan Model.load_model sebelum melakukan inferensi pada data baru:

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

Untuk mendapatkan prediksi sampel baru, Anda cukup memanggil metode Keras Model.predict . Hanya ada dua hal yang perlu Anda lakukan:

  1. Bungkus skalar ke dalam daftar sehingga memiliki dimensi batch ( Model hanya memproses kumpulan data, bukan sampel tunggal).
  2. Panggil tf.convert_to_tensor pada setiap fitur.
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.

Langkah selanjutnya

Untuk mempelajari lebih lanjut tentang mengklasifikasikan data terstruktur, coba gunakan set data lain. Untuk meningkatkan akurasi selama pelatihan dan pengujian model Anda, pikirkan baik-baik fitur mana yang akan disertakan dalam model Anda dan bagaimana fitur tersebut harus ditampilkan.

Di bawah ini adalah beberapa saran untuk kumpulan data: