סיווג נתונים מובנים באמצעות שכבות עיבוד מקדים של Keras

הצג באתר TensorFlow.org הפעל בגוגל קולאב צפה במקור ב-GitHub הורד מחברת

מדריך זה מדגים כיצד לסווג נתונים מובנים, כגון נתונים טבלאיים, באמצעות גרסה פשוטה של מערך הנתונים של PetFinder מתחרות Kaggle המאוחסנת בקובץ CSV.

אתה תשתמש ב- Keras כדי להגדיר את המודל, ובשכבות עיבוד מוקדם של Keras כגשר למיפוי מעמודות בקובץ CSV לתכונות המשמשות לאימון המודל. המטרה היא לחזות אם חיית מחמד תאומץ.

מדריך זה מכיל קוד מלא עבור:

  • טעינת קובץ CSV לתוך DataFrame באמצעות פנדות .
  • בניית צינור קלט כדי לקבץ ולערבב את השורות באמצעות tf.data . (בקר ב-tf.data: בניית צינורות קלט של TensorFlow לפרטים נוספים.)
  • מיפוי מעמודות בקובץ ה-CSV לתכונות המשמשות לאימון המודל עם שכבות העיבוד המקדים של Keras.
  • בנייה, הדרכה והערכת מודל בשיטות המובנות של Keras.

מערך הנתונים המיני של PetFinder.my

יש כמה אלפי שורות בקובץ הנתונים CSV של PetFinder.my mini, כאשר כל שורה מתארת ​​חיית מחמד (כלב או חתול) וכל עמודה מתארת ​​תכונה, כגון גיל, גזע, צבע וכן הלאה.

בסיכום מערך הנתונים למטה, שימו לב שיש בעיקר עמודות מספריות וקטגוריות. במדריך זה, אתה תעסוק רק בשני סוגי התכונות הללו, ביטול Description (תכונת טקסט חופשי) ו- AdoptionSpeed (תכונת סיווג) במהלך עיבוד מוקדם של נתונים.

טור תיאור חיית המחמד סוג תכונה סוג מידע
Type סוג בעל חיים ( Dog , Cat ) קָטֵגוֹרִי חוּט
Age גיל מִספָּרִי מספר שלם
Breed1 גזע ראשוני קָטֵגוֹרִי חוּט
Color1 צבע 1 קָטֵגוֹרִי חוּט
Color2 צבע 2 קָטֵגוֹרִי חוּט
MaturitySize גודל בבגרות קָטֵגוֹרִי חוּט
FurLength אורך פרווה קָטֵגוֹרִי חוּט
Vaccinated חיית המחמד חוסנה קָטֵגוֹרִי חוּט
Sterilized חיית המחמד עברה עיקור קָטֵגוֹרִי חוּט
Health מצב בריאותי קָטֵגוֹרִי חוּט
Fee דמי אימוץ מִספָּרִי מספר שלם
Description כתיבת פרופיל טֶקסט חוּט
PhotoAmt סך התמונות שהועלו מִספָּרִי מספר שלם
AdoptionSpeed מהירות אימוץ קטגורית מִיוּן מספר שלם

ייבוא ​​TensorFlow וספריות אחרות

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

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

טען את מערך הנתונים וקרא אותו לתוך DataFrame של pandas

pandas היא ספריית Python עם הרבה כלי עזר מועילים לטעינה ועבודה עם נתונים מובנים. השתמש tf.keras.utils.get_file כדי להוריד ולחלץ את קובץ ה-CSV עם מערך הנתונים המיני של PetFinder.my, ולטעון אותו לתוך DataFrame עם 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

בדוק את מערך הנתונים על ידי בדיקת חמש השורות הראשונות של DataFrame:

dataframe.head()

צור משתנה יעד

המשימה המקורית בתחרות חיזוי אימוץ PetFinder.my של Kaggle הייתה לחזות את המהירות שבה חיית מחמד תאומץ (למשל בשבוע הראשון, החודש הראשון, שלושת החודשים הראשונים וכן הלאה).

במדריך זה תפשט את המשימה על ידי הפיכתה לבעיית סיווג בינארי, שבה אתה פשוט צריך לחזות אם חיית מחמד אומצה או לא.

לאחר שינוי העמודה AdoptionSpeed , 0 יציין שחיית המחמד לא אומצה, ו 1 יציין שכן.

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

פצל את ה-DataFrame למערכות הדרכה, אימות ובדיקות

מערך הנתונים נמצא ב-PandaFrame יחיד. חלקו אותו לקבוצות אימון, אימות ומבחנים תוך שימוש, לדוגמה, ביחס של 80:10:10, בהתאמה:

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

צור צינור קלט באמצעות tf.data

לאחר מכן, צור פונקציית עזר הממירה כל אימון, אימות ו-DataFrame של ערכת מבחנים ל- tf.data.Dataset , ולאחר מכן מערבבת ומקבצת את הנתונים.

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

כעת, השתמש בפונקציה החדשה שנוצרה ( df_to_dataset ) כדי לבדוק את פורמט הנתונים שפונקציית העזר של צינור הקלט מחזירה על ידי קריאה לנתוני האימון, והשתמש בגודל אצווה קטן כדי לשמור על הפלט קריא:

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)

כפי שהפלט מדגים, ערכת ההדרכה מחזירה מילון של שמות עמודות (מה-DataFrame) הממפים ערכי עמודות משורות.

החל את שכבות העיבוד המקדים של Keras

שכבות העיבוד המקדים של Keras מאפשרות לך לבנות צינורות עיבוד קלט מקוריים של Keras, שיכולים לשמש כקוד עיבוד מוקדם עצמאי בזרימות עבודה שאינן של Keras, בשילוב ישירות עם דגמי Keras, ולייצא כחלק מ-Keras SavedModel.

במדריך זה, תשתמש בארבע שכבות העיבוד המקדים הבאות כדי להדגים כיצד לבצע עיבוד מקדים, קידוד נתונים מובנים והנדסת תכונות:

תוכל ללמוד עוד על השכבות הזמינות במדריך עבודה עם שכבות עיבוד מקדים .

  • עבור מאפיינים מספריים של מערך הנתונים המיני של PetFinder.my, תשתמש בשכבת tf.keras.layers.Normalization לסטנדרטיזציה של הפצת הנתונים.
  • עבור תכונות קטגוריות , כגון Type חיות מחמד (מחרוזות Dog Cat ), תמיר אותן לטנזורים מקודדים מרובים-חמים עם tf.keras.layers.CategoryEncoding .

עמודות מספריות

עבור כל תכונה מספרית במערך הנתונים המיני של PetFinder.my, תשתמש בשכבת tf.keras.layers.Normalization לסטנדרטיזציה של הפצת הנתונים.

הגדר פונקציית עזר חדשה שמחזירה שכבה המחילה נורמליזציה מבחינה תכונה על תכונות מספריות באמצעות אותה שכבת עיבוד מקדים של 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

לאחר מכן, בדוק את הפונקציה החדשה על ידי קריאה לכל תכונות תמונת חיית המחמד שהועלו כדי לנרמל '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)>

עמודות קטגוריות

Type חיות מחמד במערך הנתונים מיוצגים כמחרוזות - Dog Cat - אשר צריך להיות מקודד מרובות חם לפני הזנה למודל. תכונת Age

הגדר פונקציית שירות חדשה נוספת המחזירה שכבה אשר ממפה ערכים מאוצר מילים למדדים שלמים ומקודדת את התכונות מרובה-חם באמצעות העיבוד המקדים tf.keras.layers.StringLookup , tf.keras.layers.IntegerLookup ו- tf.keras.CategoryEncoding שכבות:

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

בדוק את הפונקציה get_category_encoding_layer על ידי קריאתה לתכונות 'Type' לחיות מחמד כדי להפוך אותן לטנזורים מקודדים מרובים חמים:

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

חזור על התהליך בתכונות 'Age' חיית המחמד:

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

עבד מראש תכונות נבחרות כדי לאמן את הדגם

למדת כיצד להשתמש במספר סוגים של שכבות עיבוד מקדים של Keras. לאחר מכן, תעשה:

  • החל את פונקציות השירות לעיבוד מוקדם שהוגדרו קודם לכן על 13 תכונות מספריות וקטגוריות ממערך הנתונים המיני של PetFinder.my.
  • הוסף את כל כניסות התכונות לרשימה.

כפי שצוין בהתחלה, כדי להכשיר את המודל, תשתמש במערך הנתונים המיני של PetFinder.my המספריים ( 'PhotoAmt' , 'Fee' ) וקטגוריים ( 'Age' , 'Type' , 'Color1' , 'Color2' , 'Gender' , 'MaturitySize' , 'FurLength' , 'מחוסן 'Vaccinated' , 'Sterilized' , 'Health' , 'Breed1' ).

קודם לכן, השתמשת בגודל אצווה קטן כדי להדגים את צינור הקלט. כעת ניצור צינור קלט חדש עם גודל אצווה גדול יותר של 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.

נרמל את התכונות המספריות (מספר תמונות חיית המחמד ודמי האימוץ), והוסיפו אותן לרשימה אחת של כניסות בשם 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)

הפוך את הערכים הקטגוריים של מספרים שלמים ממערך הנתונים (גיל חיית המחמד) למדדים שלמים, בצע קידוד רב-חם, והוסף את כניסות התכונות המתקבלות ל- 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)

חזור על אותו שלב עבור הערכים הקטגוריים של המחרוזת:

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)

צור, הידור והכשרת המודל

השלב הבא הוא יצירת מודל באמצעות ה- Keras Functional API . עבור השכבה הראשונה במודל שלך, מיזוג את רשימת כניסות התכונות - encoded_features - לוקטור אחד באמצעות שרשור עם 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)

הגדר את הדגם עם Keras Model.compile :

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

בואו נדמיין את גרף הקישוריות:

# Use `rankdir='LR'` 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
/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

בצע מסקנות

המודל שפיתחת יכול כעת לסווג שורה מקובץ CSV ישירות לאחר שכללת את שכבות העיבוד המקדים בתוך המודל עצמו.

כעת אתה יכול לשמור ולטעון מחדש את מודל Keras עם Model.save ו- Model.load_model לפני ביצוע הסקה על נתונים חדשים:

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

כדי לקבל חיזוי למדגם חדש, אתה יכול פשוט לקרוא לשיטת Model.predict . יש רק שני דברים שאתה צריך לעשות:

  1. עטפו סקלרים לרשימה כך שתהיה ממד אצווה ( Model מעבד רק קבוצות של נתונים, לא דוגמאות בודדות).
  2. התקשר tf.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 77.7 percent probability of getting adopted.

הצעדים הבאים

למידע נוסף על סיווג נתונים מובנים, נסה לעבוד עם מערכי נתונים אחרים. כדי לשפר את הדיוק במהלך אימון ובדיקת המודלים שלך, חשוב היטב אילו תכונות לכלול במודל שלך וכיצד יש לייצג אותם.

להלן כמה הצעות למערך נתונים:

  • מערכי נתונים של TensorFlow: MovieLens : קבוצה של דירוגי סרטים משירות המלצות לסרטים.
  • מערכי נתונים של TensorFlow: איכות יין : שני מערכי נתונים הקשורים לגרסאות אדומות ולבנות של היין הפורטוגזי "Vinho Verde". אתה יכול גם למצוא את מערך הנתונים של איכות היין האדום ב- Kaggle .
  • Kaggle: arXiv Dataset: קורפוס של 1.7 מיליון מאמרים אקדמיים מ-arXiv, המכסים פיזיקה, מדעי המחשב, מתמטיקה, סטטיסטיקה, הנדסת חשמל, ביולוגיה כמותית וכלכלה.