Keras前処理レイヤーを使用して構造化データを分類する

TensorFlow.orgで表示 GoogleColabで実行 GitHubでソースを表示 ノートブックをダウンロード

このチュートリアルでは、構造化データ(CSVの表形式データなど)を分類する方法を示します。あなたは使用するKerasをモデルを定義し、前処理層のブリッジとしては、モデルを訓練するために使用される機能をCSVの列からマップすること。このチュートリアルには、次の完全なコードが含まれています。

  • 使用してCSVファイル読み込みパンダを
  • バッチへの入力パイプラインを構築し、使用して行をシャッフルtf.dataを
  • CSVの列から、Keras前処理レイヤーを使用してモデルをトレーニングするために使用される機能にマップします。
  • Kerasを使用してモデルを構築、トレーニング、評価します。

データセット

あなたはPetFinderのの簡易版を使用しますデータセットを。 CSVには数千行あります。各行はペットを説明し、各列は属性を説明します。この情報を使用して、ペットが養子縁組されるかどうかを予測します。

以下は、このデータセットの説明です。数値列とカテゴリ列の両方があることに注意してください。このチュートリアルでは使用しないフリーテキスト列があります。

説明機能タイプデータ・タイプ
タイプ動物の種類(犬、猫)カテゴリカルストリング
ペットの年齢数値整数
品種1ペットの主な品種カテゴリカルストリング
Color1ペットのカラー1カテゴリカルストリング
Color2ペットのカラー2カテゴリカルストリング
MaturitySize成熟時のサイズカテゴリカルストリング
FurLength毛皮の長さカテゴリカルストリング
ワクチン接種ペットはワクチン接種されていますカテゴリカルストリング
滅菌済みペットは滅菌済みカテゴリカルストリング
健康健康状態カテゴリカルストリング
手数料養子縁組費用数値整数
説明このペットのプロフィールの記事文章ストリング
PhotoAmtこのペットのアップロードされた写真の合計数値整数
AdoptionSpeed採用のスピード分類整数

TensorFlowおよびその他のライブラリをインポートします

pip install -q sklearn
import numpy as np
import pandas as pd
import tensorflow as tf

from sklearn.model_selection import train_test_split
from tensorflow.keras import layers
from tensorflow.keras.layers.experimental import preprocessing
tf.__version__
'2.5.0'

パンダを使用してデータフレームを作成する

パンダは、構造化データをロードし、作業のための多くの有用なユーティリティとPythonライブラリです。 Pandasを使用してURLからデータセットをダウンロードし、データフレームにロードします。

import pathlib

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
dataframe.head()

ターゲット変数を作成します

Kaggleコンテストのタスクは、ペットが養子縁組される速度を予測することです(たとえば、最初の週、最初の月、最初の3か月など)。チュートリアルのためにこれを単純化しましょう。ここでは、これをバイナリ分類問題に変換し、ペットが養子縁組されたかどうかを簡単に予測します。

ラベル列を変更した後、0はペットが養子縁組されなかったことを示し、1は養子縁組されたことを示します。

# In the original dataset "4" indicates the pet was not adopted.
dataframe['target'] = np.where(dataframe['AdoptionSpeed']==4, 0, 1)

# Drop un-used columns.
dataframe = dataframe.drop(columns=['AdoptionSpeed', 'Description'])

データフレームをトレーニング、検証、テストに分割します

ダウンロードしたデータセットは単一のCSVファイルでした。これをトレーニング、検証、テストのセットに分割します。

train, test = train_test_split(dataframe, test_size=0.2)
train, val = train_test_split(train, test_size=0.2)
print(len(train), 'train examples')
print(len(val), 'validation examples')
print(len(test), 'test examples')
7383 train examples
1846 validation examples
2308 test examples

tf.dataを使用して入力パイプラインを作成します

次に、あなたがデータフレームをラップしますtf.dataデータをシャッフルし、バッチするためには、。非常に大きなCSVファイル(メモリに収まらないほど大きい)で作業している場合は、tf.dataを使用してディスクから直接読み取ります。これは、このチュートリアルではカバーされていません。

# A utility method to create a tf.data dataset from a Pandas Dataframe
def df_to_dataset(dataframe, shuffle=True, batch_size=32):
  dataframe = dataframe.copy()
  labels = dataframe.pop('target')
  ds = tf.data.Dataset.from_tensor_slices((dict(dataframe), labels))
  if shuffle:
    ds = ds.shuffle(buffer_size=len(dataframe))
  ds = ds.batch(batch_size)
  ds = ds.prefetch(batch_size)
  return ds

入力パイプラインを作成したので、それを呼び出して、返されるデータの形式を確認しましょう。出力を読みやすくするために、小さなバッチサイズを使用しました。

batch_size = 5
train_ds = df_to_dataset(train, batch_size=batch_size)
[(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']
A batch of ages: tf.Tensor([7 3 1 4 2], shape=(5,), dtype=int64)
A batch of targets: tf.Tensor([0 0 1 0 1], shape=(5,), dtype=int64)

データセットが、データフレーム内の行の列値にマップされる(データフレームからの)列名のディクショナリを返すことがわかります。

前処理レイヤーの使用を示します。

Keras前処理レイヤーAPIを使用すると、Kerasネイティブの入力処理パイプラインを構築できます。 3つの前処理レイヤーを使用して、機能の前処理コードを示します。

あなたは、可能な前処理層のリストを見つけることができるここに

数値列

数値機能ごとに、Normalization()レイヤーを使用して、各機能の平均が0で、標準偏差が1であることを確認します。

get_normalization_layer関数は、数値の特徴にfeaturewise正規化を適用する層を返します。

def get_normalization_layer(name, dataset):
  # Create a Normalization layer for our feature.
  normalizer = preprocessing.Normalization(axis=None)

  # Prepare a Dataset that only yields our feature.
  feature_ds = dataset.map(lambda x, y: x[name])

  # Learn the statistics of the data.
  normalizer.adapt(feature_ds)

  return normalizer
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.8334968],
       [-0.8334968],
       [ 1.0716735],
       [-0.8334968],
       [-0.8334968]], dtype=float32)>

カテゴリ列

このデータセットでは、Typeは文字列として表されます(例:「Dog」または「Cat」)。文字列をモデルに直接フィードすることはできません。前処理レイヤーは、文字列をワンホットベクトルとして表現します。

get_category_encoding_layer関数は、整数インデックスとワンホットエンコード機能に語彙の値をマッピングする層を返します。

def get_category_encoding_layer(name, dataset, dtype, max_tokens=None):
  # Create a StringLookup layer which will turn strings into integer indices
  if dtype == 'string':
    index = preprocessing.StringLookup(max_tokens=max_tokens)
  else:
    index = preprocessing.IntegerLookup(max_tokens=max_tokens)

  # Prepare a Dataset that only yields our 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)

  # Create a Discretization for our integer indices.
  encoder = preprocessing.CategoryEncoding(num_tokens=index.vocabulary_size())

  # Apply one-hot encoding to our indices. The lambda function captures the
  # layer so we can use them, or include them in the functional model later.
  return lambda feature: encoder(index(feature))
type_col = train_features['Type']
layer = get_category_encoding_layer('Type', train_ds, 'string')
layer(type_col)
<tf.Tensor: shape=(5, 4), dtype=float32, numpy=
array([[0., 0., 1., 0.],
       [0., 0., 0., 1.],
       [0., 0., 0., 1.],
       [0., 0., 1., 0.],
       [0., 0., 1., 0.]], dtype=float32)>

多くの場合、モデルに直接数値を入力するのではなく、それらの入力のワンホットエンコーディングを使用します。ペットの年齢を表す生データを検討してください。

type_col = train_features['Age']
category_encoding_layer = get_category_encoding_layer('Age', train_ds,
                                                      'int64', 5)
category_encoding_layer(type_col)
<tf.Tensor: shape=(5, 5), dtype=float32, numpy=
array([[0., 1., 0., 0., 0.],
       [0., 0., 0., 1., 0.],
       [0., 0., 0., 0., 1.],
       [0., 1., 0., 0., 0.],
       [0., 0., 1., 0., 0.]], dtype=float32)>

使用する列を選択します

いくつかのタイプの前処理レイヤーを使用する方法を見てきました。次に、それらを使用してモデルをトレーニングします。あなたは使用するKeras機能APIをモデルを構築します。 Keras機能APIは、より柔軟性のあるモデルを作成する方法ですtf.keras.Sequential APIを。

このチュートリアルの目的は、前処理レイヤーを操作するために必要な完全なコード(メカニックなど)を示すことです。モデルをトレーニングするために、いくつかの列が任意に選択されています。

以前は、入力パイプラインを示すために小さなバッチサイズを使用しました。次に、バッチサイズを大きくした新しい入力パイプラインを作成しましょう。

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)
all_inputs = []
encoded_features = []

# Numeric 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)
# Categorical features encoded as integers.
age_col = tf.keras.Input(shape=(1,), name='Age', dtype='int64')
encoding_layer = get_category_encoding_layer('Age', 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 features encoded as 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(header, 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)

モデルを作成、コンパイル、トレーニングします

これで、エンドツーエンドモデルを作成できます。

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)
model.compile(optimizer='adam',
              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=["accuracy"])

接続グラフを視覚化してみましょう。

# rankdir='LR' is used 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
29/29 [==============================] - 2s 19ms/step - loss: 0.6824 - accuracy: 0.4887 - val_loss: 0.5852 - val_accuracy: 0.7134
Epoch 2/10
29/29 [==============================] - 0s 7ms/step - loss: 0.5998 - accuracy: 0.6500 - val_loss: 0.5615 - val_accuracy: 0.7340
Epoch 3/10
29/29 [==============================] - 0s 7ms/step - loss: 0.5775 - accuracy: 0.6676 - val_loss: 0.5489 - val_accuracy: 0.7243
Epoch 4/10
29/29 [==============================] - 0s 7ms/step - loss: 0.5553 - accuracy: 0.6928 - val_loss: 0.5403 - val_accuracy: 0.7264
Epoch 5/10
29/29 [==============================] - 0s 7ms/step - loss: 0.5553 - accuracy: 0.7045 - val_loss: 0.5338 - val_accuracy: 0.7248
Epoch 6/10
29/29 [==============================] - 0s 7ms/step - loss: 0.5417 - accuracy: 0.7058 - val_loss: 0.5290 - val_accuracy: 0.7281
Epoch 7/10
29/29 [==============================] - 0s 7ms/step - loss: 0.5369 - accuracy: 0.7093 - val_loss: 0.5251 - val_accuracy: 0.7302
Epoch 8/10
29/29 [==============================] - 0s 7ms/step - loss: 0.5364 - accuracy: 0.7135 - val_loss: 0.5222 - val_accuracy: 0.7291
Epoch 9/10
29/29 [==============================] - 0s 7ms/step - loss: 0.5296 - accuracy: 0.7154 - val_loss: 0.5198 - val_accuracy: 0.7362
Epoch 10/10
29/29 [==============================] - 0s 7ms/step - loss: 0.5288 - accuracy: 0.7222 - val_loss: 0.5175 - val_accuracy: 0.7313
<tensorflow.python.keras.callbacks.History at 0x7f51e056a510>
loss, accuracy = model.evaluate(test_ds)
print("Accuracy", accuracy)
10/10 [==============================] - 0s 5ms/step - loss: 0.5209 - accuracy: 0.7331
Accuracy 0.7331022620201111

新しいデータに関する推論

これで、Kerasモデルを保存して再ロードできます。チュートリアルに従ってくださいここTensorFlowモデルの詳細については。

model.save('my_pet_classifier')
reloaded_model = tf.keras.models.load_model('my_pet_classifier')
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()あなたがする必要があるのはたった2つのことです:

  1. バッチ次元を持つようにスカラーをリストにラップします(モデルはデータのバッチのみを処理し、単一のサンプルは処理しません)
  2. コール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 86.6 percent probability of getting adopted.

次のステップ

構造化データの分類についてさらに学ぶための最良の方法は、自分で試すことです。使用する別のデータセットを見つけ、上記のようなコードを使用してモデルをトレーニングして分類することをお勧めします。精度を向上させるには、モデルに含める機能と、それらをどのように表現するかを慎重に検討してください。