![]() | ![]() | ![]() | ![]() |
このチュートリアルでは、構造化データ(CSVの表形式データなど)を分類する方法を示します。 Kerasを使用してモデルを定義し、CSVの列からモデルのトレーニングに使用される機能にマップするためのブリッジとしてレイヤーを前処理します。このチュートリアルには、次の完全なコードが含まれています。
- Pandasを使用して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
パンダを使用してデータフレームを作成する
Pandasは、構造化データのロードと操作に役立つ多くのユーティリティを備えた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([ 2 2 18 2 1], shape=(5,), dtype=int64) A batch of targets: tf.Tensor([1 1 0 1 1], shape=(5,), dtype=int64)
データセットが、データフレーム内の行の列値にマップされる(データフレームからの)列名のディクショナリを返すことがわかります。
前処理レイヤーの使用を示します。
Keras前処理レイヤーAPIを使用すると、Kerasネイティブの入力処理パイプラインを構築できます。 3つの前処理レイヤーを使用して、機能の前処理コードを示します。
-
Normalization
-データの機能ごとの正規化。 -
CategoryEncoding
カテゴリエンコーディングレイヤー。 -
StringLookup
文字列を語彙から整数インデックスにマップします。 -
IntegerLookup
ボキャブラリーから整数インデックスに整数をマップします。
利用可能な前処理レイヤーのリストはここにあります。
数値列
数値フィーチャごとに、Normalization()レイヤーを使用して、各フィーチャの平均が0で、標準偏差が1であることを確認します。
get_normalization_layer
関数は、数値特徴に特徴get_normalization_layer
正規化を適用するレイヤーを返します。
def get_normalization_layer(name, dataset):
# Create a Normalization layer for our feature.
normalizer = preprocessing.Normalization()
# 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([[ 1.045485 ], [-1.1339161 ], [-0.19988704], [ 0.11145599], [ 0.42279902]], 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_values=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(max_tokens=index.vocab_size())
# Prepare a Dataset that only yields our feature.
feature_ds = feature_ds.map(index)
# Learn the space of possible indices.
encoder.adapt(feature_ds)
# 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., 0., 1.], [0., 0., 0., 1.], [0., 0., 1., 0.], [0., 0., 0., 1.], [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., 0., 1., 0., 0.], [0., 0., 1., 0., 0.], [0., 1., 0., 0., 0.], [0., 0., 1., 0., 0.], [0., 0., 0., 0., 1.]], dtype=float32)>
使用する列を選択します
いくつかのタイプの前処理レイヤーを使用する方法を見てきました。次に、それらを使用してモデルをトレーニングします。 Keras機能APIを使用してモデルを構築します。 Keras機能APIは、 tf.keras.SequentialAPIよりも柔軟なモデルを作成する方法です。
このチュートリアルの目的は、前処理レイヤーを操作するために必要な完全なコード(メカニックなど)を示すことです。モデルをトレーニングするために、いくつかの列が任意に選択されています。
以前は、入力パイプラインを示すために小さなバッチサイズを使用しました。次に、バッチサイズを大きくした新しい入力パイプラインを作成しましょう。
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")
モデルをトレーニングする
model.fit(train_ds, epochs=10, validation_data=val_ds)
Epoch 1/10 29/29 [==============================] - 0s 15ms/step - loss: 0.6088 - accuracy: 0.5924 - val_loss: 0.5623 - val_accuracy: 0.7302 Epoch 2/10 29/29 [==============================] - 0s 6ms/step - loss: 0.5766 - accuracy: 0.6833 - val_loss: 0.5459 - val_accuracy: 0.7356 Epoch 3/10 29/29 [==============================] - 0s 6ms/step - loss: 0.5579 - accuracy: 0.6981 - val_loss: 0.5364 - val_accuracy: 0.7362 Epoch 4/10 29/29 [==============================] - 0s 6ms/step - loss: 0.5467 - accuracy: 0.7127 - val_loss: 0.5287 - val_accuracy: 0.7313 Epoch 5/10 29/29 [==============================] - 0s 6ms/step - loss: 0.5401 - accuracy: 0.7059 - val_loss: 0.5240 - val_accuracy: 0.7329 Epoch 6/10 29/29 [==============================] - 0s 6ms/step - loss: 0.5362 - accuracy: 0.7222 - val_loss: 0.5203 - val_accuracy: 0.7313 Epoch 7/10 29/29 [==============================] - 0s 6ms/step - loss: 0.5290 - accuracy: 0.7189 - val_loss: 0.5172 - val_accuracy: 0.7297 Epoch 8/10 29/29 [==============================] - 0s 6ms/step - loss: 0.5273 - accuracy: 0.7172 - val_loss: 0.5151 - val_accuracy: 0.7286 Epoch 9/10 29/29 [==============================] - 0s 6ms/step - loss: 0.5236 - accuracy: 0.7210 - val_loss: 0.5127 - val_accuracy: 0.7291 Epoch 10/10 29/29 [==============================] - 0s 6ms/step - loss: 0.5200 - accuracy: 0.7219 - val_loss: 0.5112 - val_accuracy: 0.7297 <tensorflow.python.keras.callbacks.History at 0x7f6fc8e61f98>
loss, accuracy = model.evaluate(test_ds)
print("Accuracy", accuracy)
10/10 [==============================] - 0s 4ms/step - loss: 0.5232 - accuracy: 0.7370 Accuracy 0.7370017170906067
新しいデータの推測
これで、Kerasモデルを保存して再ロードできます。 TensorFlowモデルの詳細については、こちらのチュートリアルに従ってください。
model.save('my_pet_classifier')
reloaded_model = tf.keras.models.load_model('my_pet_classifier')
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Model.state_updates (from tensorflow.python.keras.engine.training) is deprecated and will be removed in a future version. Instructions for updating: This property should not be used in TensorFlow 2.0, as updates are applied automatically. WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Layer.updates (from tensorflow.python.keras.engine.base_layer) is deprecated and will be removed in a future version. Instructions for updating: This property should not be used in TensorFlow 2.0, as updates are applied automatically. INFO:tensorflow:Assets written to: my_pet_classifier/assets WARNING:tensorflow:5 out of the last 5 calls to <function recreate_function.<locals>.restored_function_body at 0x7f6fc8b82400> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/tutorials/customization/performance#python_or_tensor_args and https://www.tensorflow.org/api_docs/python/tf/function for more details. WARNING:tensorflow:6 out of the last 6 calls to <function recreate_function.<locals>.restored_function_body at 0x7f6fc8b82d08> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/tutorials/customization/performance#python_or_tensor_args and https://www.tensorflow.org/api_docs/python/tf/function for more details. WARNING:tensorflow:7 out of the last 7 calls to <function recreate_function.<locals>.restored_function_body at 0x7f6fc8b611e0> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/tutorials/customization/performance#python_or_tensor_args and https://www.tensorflow.org/api_docs/python/tf/function for more details. WARNING:tensorflow:8 out of the last 8 calls to <function recreate_function.<locals>.restored_function_body at 0x7f6fc8b857b8> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/tutorials/customization/performance#python_or_tensor_args and https://www.tensorflow.org/api_docs/python/tf/function for more details. WARNING:tensorflow:9 out of the last 9 calls to <function recreate_function.<locals>.restored_function_body at 0x7f6f6870b158> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/tutorials/customization/performance#python_or_tensor_args and https://www.tensorflow.org/api_docs/python/tf/function for more details. WARNING:tensorflow:10 out of the last 10 calls to <function recreate_function.<locals>.restored_function_body at 0x7f6f6870bd08> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/tutorials/customization/performance#python_or_tensor_args and https://www.tensorflow.org/api_docs/python/tf/function for more details. WARNING:tensorflow:11 out of the last 11 calls to <function recreate_function.<locals>.restored_function_body at 0x7f6fc8b6abf8> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/tutorials/customization/performance#python_or_tensor_args and https://www.tensorflow.org/api_docs/python/tf/function for more details.
新しいサンプルの予測を取得するには、 model.predict()
呼び出すだけです。あなたがする必要があるのは2つだけです:
- バッチディメンションを持つようにスカラーをリストにラップします(モデルはデータのバッチのみを処理し、単一のサンプルは処理しません)
- 各機能で
convert_to_tensor
を呼び出し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 83.4 percent probability of getting adopted.
次のステップ
構造化データの分類についてさらに学ぶための最良の方法は、自分で試すことです。使用する別のデータセットを見つけて、上記のようなコードを使用してモデルを分類するようにトレーニングすることをお勧めします。精度を向上させるには、モデルに含める機能と、それらをどのように表現するかを慎重に検討してください。