ช่วยปกป้อง Great Barrier Reef กับ TensorFlow บน Kaggle เข้าร่วมท้าทาย

โหลด DataFrame แพนด้า

ดูบน TensorFlow.org ทำงานใน Google Colab ดูแหล่งที่มาบน GitHub ดาวน์โหลดโน๊ตบุ๊ค

กวดวิชานี้มีตัวอย่างของวิธีการโหลด หมีแพนด้า DataFrames เข้า TensorFlow

คุณจะใช้ขนาดเล็ก ชุดข้อมูลที่เป็นโรคหัวใจ ให้โดย UCI เครื่องเรียนรู้ Repository CSV มีหลายร้อยแถว แต่ละแถวอธิบายผู้ป่วย และแต่ละคอลัมน์อธิบายแอตทริบิวต์ คุณจะใช้ข้อมูลนี้เพื่อทำนายว่าผู้ป่วยเป็นโรคหัวใจหรือไม่ ซึ่งเป็นงานการจำแนกเลขฐานสอง

อ่านข้อมูลโดยใช้แพนด้า

import pandas as pd
import tensorflow as tf

SHUFFLE_BUFFER = 500
BATCH_SIZE = 2

ดาวน์โหลดไฟล์ CSV ที่มีชุดข้อมูลโรคหัวใจ:

csv_file = tf.keras.utils.get_file('heart.csv', 'https://storage.googleapis.com/download.tensorflow.org/data/heart.csv')
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/heart.csv
16384/13273 [=====================================] - 0s 0us/step
24576/13273 [=======================================================] - 0s 0us/step

อ่านไฟล์ CSV โดยใช้แพนด้า:

df = pd.read_csv(csv_file)

นี่คือลักษณะของข้อมูล:

df.head()
df.dtypes
age           int64
sex           int64
cp            int64
trestbps      int64
chol          int64
fbs           int64
restecg       int64
thalach       int64
exang         int64
oldpeak     float64
slope         int64
ca            int64
thal         object
target        int64
dtype: object

คุณจะสร้างแบบจำลองในการทำนายฉลากที่มีอยู่ใน target คอลัมน์

target = df.pop('target')

DataFrame เป็นอาร์เรย์

หากข้อมูลของคุณมีประเภทข้อมูลเครื่องแบบหรือ dtype ก็ใช้เป็นไปได้หมีแพนด้า DataFrame ทุกที่ที่คุณสามารถใช้อาร์เรย์ NumPy งานนี้เพราะ pandas.DataFrame ระดับสนับสนุน __array__ โปรโตคอลและ TensorFlow ของ tf.convert_to_tensor ฟังก์ชั่นรับวัตถุที่สนับสนุนโปรโตคอล

นำคุณสมบัติตัวเลขจากชุดข้อมูล (ข้ามคุณสมบัติหมวดหมู่ไปก่อน):

numeric_feature_names = ['age', 'thalach', 'trestbps',  'chol', 'oldpeak']
numeric_features = df[numeric_feature_names]
numeric_features.head()

DataFrame สามารถแปลงเป็นอาร์เรย์ NumPy ใช้ DataFrame.values ทรัพย์สินหรือ numpy.array(df) เพื่อแปลงเป็นเมตริกซ์ใช้ tf.convert_to_tensor :

tf.convert_to_tensor(numeric_features)
<tf.Tensor: shape=(303, 5), dtype=float64, numpy=
array([[ 63. , 150. , 145. , 233. ,   2.3],
       [ 67. , 108. , 160. , 286. ,   1.5],
       [ 67. , 129. , 120. , 229. ,   2.6],
       ...,
       [ 65. , 127. , 135. , 254. ,   2.8],
       [ 48. , 150. , 130. , 256. ,   0. ],
       [ 63. , 154. , 150. , 407. ,   4. ]])>

โดยทั่วไปถ้าวัตถุสามารถแปลงเป็นเมตริกซ์ที่มี tf.convert_to_tensor มันสามารถส่งผ่านไปทุกที่ที่คุณสามารถผ่าน tf.Tensor

ด้วย Model.fit

DataFrame ตีความเป็นเมตริกซ์เดียวสามารถนำมาใช้โดยตรงเป็นอาร์กิวเมนต์ที่ Model.fit วิธี

ด้านล่างนี้คือตัวอย่างการฝึกโมเดลเกี่ยวกับคุณสมบัติตัวเลขของชุดข้อมูล

ขั้นตอนแรกคือการปรับช่วงอินพุตให้เป็นมาตรฐาน ใช้ tf.keras.layers.Normalization ชั้นที่

ในการตั้งชั้นของค่าเฉลี่ยและค่าเบี่ยงเบนมาตรฐานก่อนที่จะใช้มันให้แน่ใจว่าจะเรียก Normalization.adapt วิธีการ:

normalizer = tf.keras.layers.Normalization(axis=-1)
normalizer.adapt(numeric_features)

เรียกเลเยอร์ในสามแถวแรกของ DataFrame เพื่อแสดงตัวอย่างผลลัพธ์จากเลเยอร์นี้:

normalizer(numeric_features.iloc[:3])
<tf.Tensor: shape=(3, 5), dtype=float32, numpy=
array([[ 0.93383914,  0.03480718,  0.74578077, -0.26008663,  1.0680453 ],
       [ 1.3782105 , -1.7806165 ,  1.5923285 ,  0.7573877 ,  0.38022864],
       [ 1.3782105 , -0.87290466, -0.6651321 , -0.33687714,  1.3259765 ]],
      dtype=float32)>

ใช้เลเยอร์การทำให้เป็นมาตรฐานเป็นเลเยอร์แรกของโมเดลอย่างง่าย:

def get_basic_model():
  model = tf.keras.Sequential([
    normalizer,
    tf.keras.layers.Dense(10, activation='relu'),
    tf.keras.layers.Dense(10, activation='relu'),
    tf.keras.layers.Dense(1)
  ])

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

เมื่อคุณผ่าน DataFrame เป็น x อาร์กิวเมนต์ Model.fit , Keras ถือว่าเป็น DataFrame มันจะอาร์เรย์ NumPy:

model = get_basic_model()
model.fit(numeric_features, target, epochs=15, batch_size=BATCH_SIZE)
Epoch 1/15
152/152 [==============================] - 1s 2ms/step - loss: 0.6405 - accuracy: 0.7789
Epoch 2/15
152/152 [==============================] - 0s 2ms/step - loss: 0.5510 - accuracy: 0.7426
Epoch 3/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4935 - accuracy: 0.7459
Epoch 4/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4649 - accuracy: 0.7558
Epoch 5/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4492 - accuracy: 0.7624
Epoch 6/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4404 - accuracy: 0.7624
Epoch 7/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4350 - accuracy: 0.7789
Epoch 8/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4307 - accuracy: 0.7888
Epoch 9/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4291 - accuracy: 0.7756
Epoch 10/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4262 - accuracy: 0.7822
Epoch 11/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4242 - accuracy: 0.7855
Epoch 12/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4227 - accuracy: 0.7789
Epoch 13/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4229 - accuracy: 0.7987
Epoch 14/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4207 - accuracy: 0.7954
Epoch 15/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4212 - accuracy: 0.7822
<keras.callbacks.History at 0x7f52dc52b8d0>

ด้วย tf.data

หากคุณต้องการใช้ tf.data แปลงเพื่อ DataFrame ของเครื่องแบบ dtype ที่ Dataset.from_tensor_slices วิธีการจะสร้างชุดข้อมูลที่ iterates มากกว่าแถวของ DataFrame ที่ แต่ละแถวเริ่มต้นเป็นเวกเตอร์ของค่า ในการฝึกอบรมรุ่นที่คุณจะต้อง (inputs, labels) คู่เพื่อให้ผ่าน (features, labels) และ Dataset.from_tensor_slices จะกลับมาคู่จำเป็นชิ้น:

numeric_dataset = tf.data.Dataset.from_tensor_slices((numeric_features, target))

for row in numeric_dataset.take(3):
  print(row)
(<tf.Tensor: shape=(5,), dtype=float64, numpy=array([ 63. , 150. , 145. , 233. ,   2.3])>, <tf.Tensor: shape=(), dtype=int64, numpy=0>)
(<tf.Tensor: shape=(5,), dtype=float64, numpy=array([ 67. , 108. , 160. , 286. ,   1.5])>, <tf.Tensor: shape=(), dtype=int64, numpy=1>)
(<tf.Tensor: shape=(5,), dtype=float64, numpy=array([ 67. , 129. , 120. , 229. ,   2.6])>, <tf.Tensor: shape=(), dtype=int64, numpy=0>)
numeric_batches = numeric_dataset.shuffle(1000).batch(BATCH_SIZE)

model = get_basic_model()
model.fit(numeric_batches, epochs=15)
Epoch 1/15
152/152 [==============================] - 1s 2ms/step - loss: 0.6827 - accuracy: 0.7393
Epoch 2/15
152/152 [==============================] - 0s 2ms/step - loss: 0.6239 - accuracy: 0.7327
Epoch 3/15
152/152 [==============================] - 0s 2ms/step - loss: 0.5740 - accuracy: 0.7327
Epoch 4/15
152/152 [==============================] - 0s 2ms/step - loss: 0.5316 - accuracy: 0.7360
Epoch 5/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4957 - accuracy: 0.7426
Epoch 6/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4726 - accuracy: 0.7591
Epoch 7/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4569 - accuracy: 0.7822
Epoch 8/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4482 - accuracy: 0.7723
Epoch 9/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4417 - accuracy: 0.7855
Epoch 10/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4379 - accuracy: 0.7855
Epoch 11/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4356 - accuracy: 0.7888
Epoch 12/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4326 - accuracy: 0.7888
Epoch 13/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4308 - accuracy: 0.7855
Epoch 14/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4288 - accuracy: 0.8020
Epoch 15/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4267 - accuracy: 0.7888
<keras.callbacks.History at 0x7f52dc35db10>

DataFrame เป็นพจนานุกรม

เมื่อคุณเริ่มจัดการกับข้อมูลที่ต่างกัน จะไม่สามารถจัดการกับ DataFrame ราวกับว่ามันเป็นอาร์เรย์เดียวได้อีกต่อไป เทนเซอร์ TensorFlow จำเป็นต้องให้ทุกคนมีองค์ประกอบเดียวกัน dtype

ดังนั้น ในกรณีนี้ คุณต้องเริ่มมองว่ามันเป็นพจนานุกรมของคอลัมน์ โดยที่แต่ละคอลัมน์มี dtype เหมือนกัน DataFrame นั้นเหมือนกับพจนานุกรมของอาร์เรย์ ดังนั้นโดยทั่วไปสิ่งที่คุณต้องทำคือส่ง DataFrame ไปยัง Python dict TensorFlow APIs ที่สำคัญจำนวนมากรองรับพจนานุกรม (ซ้อนกัน-) ของอาร์เรย์เป็นอินพุต

tf.data ท่อป้อนข้อมูลการจัดการนี้ค่อนข้างดี ทั้งหมด tf.data การดำเนินงานจัดการพจนานุกรมและ tuples โดยอัตโนมัติ ดังนั้นเพื่อให้ชุดของพจนานุกรมตัวอย่างจาก DataFrame เพียงทิ้งให้ Dict ก่อนหั่นกับ Dataset.from_tensor_slices :

numeric_dict_ds = tf.data.Dataset.from_tensor_slices((dict(numeric_features), target))

นี่คือตัวอย่างสามตัวอย่างแรกจากชุดข้อมูลนั้น:

for row in numeric_dict_ds.take(3):
  print(row)
({'age': <tf.Tensor: shape=(), dtype=int64, numpy=63>, 'thalach': <tf.Tensor: shape=(), dtype=int64, numpy=150>, 'trestbps': <tf.Tensor: shape=(), dtype=int64, numpy=145>, 'chol': <tf.Tensor: shape=(), dtype=int64, numpy=233>, 'oldpeak': <tf.Tensor: shape=(), dtype=float64, numpy=2.3>}, <tf.Tensor: shape=(), dtype=int64, numpy=0>)
({'age': <tf.Tensor: shape=(), dtype=int64, numpy=67>, 'thalach': <tf.Tensor: shape=(), dtype=int64, numpy=108>, 'trestbps': <tf.Tensor: shape=(), dtype=int64, numpy=160>, 'chol': <tf.Tensor: shape=(), dtype=int64, numpy=286>, 'oldpeak': <tf.Tensor: shape=(), dtype=float64, numpy=1.5>}, <tf.Tensor: shape=(), dtype=int64, numpy=1>)
({'age': <tf.Tensor: shape=(), dtype=int64, numpy=67>, 'thalach': <tf.Tensor: shape=(), dtype=int64, numpy=129>, 'trestbps': <tf.Tensor: shape=(), dtype=int64, numpy=120>, 'chol': <tf.Tensor: shape=(), dtype=int64, numpy=229>, 'oldpeak': <tf.Tensor: shape=(), dtype=float64, numpy=2.6>}, <tf.Tensor: shape=(), dtype=int64, numpy=0>)

พจนานุกรมที่มี Keras

โดยปกติ โมเดลและเลเยอร์ของ Keras คาดหวังเทนเซอร์อินพุตเดียว แต่คลาสเหล่านี้สามารถรับและส่งคืนโครงสร้างที่ซ้อนกันของพจนานุกรม ทูเพิล และเทนเซอร์ โครงสร้างเหล่านี้เป็นที่รู้จักกันในนาม "รัง" (หมายถึง tf.nest โมดูลสำหรับรายละเอียด)

มีสองวิธีที่เทียบเท่ากันที่คุณสามารถเขียนโมเดล keras ที่ยอมรับพจนานุกรมเป็นอินพุต

1. Model-subclass style

คุณเขียน subclass ของ tf.keras.Model (หรือ tf.keras.Layer ) คุณจัดการอินพุตโดยตรงและสร้างผลลัพธ์:

def stack_dict(inputs, fun=tf.stack):
    values = []
    for key in sorted(inputs.keys()):
      values.append(tf.cast(inputs[key], tf.float32))

    return fun(values, axis=-1)

โมเดลนี้สามารถรับพจนานุกรมของคอลัมน์หรือชุดข้อมูลขององค์ประกอบพจนานุกรมสำหรับการฝึกอบรมได้:

model.fit(dict(numeric_features), target, epochs=5, batch_size=BATCH_SIZE)
Epoch 1/5
152/152 [==============================] - 2s 16ms/step - loss: 0.5968 - accuracy: 0.7261
Epoch 2/5
152/152 [==============================] - 2s 15ms/step - loss: 0.5182 - accuracy: 0.7261
Epoch 3/5
152/152 [==============================] - 2s 15ms/step - loss: 0.4738 - accuracy: 0.7360
Epoch 4/5
152/152 [==============================] - 2s 15ms/step - loss: 0.4515 - accuracy: 0.7525
Epoch 5/5
152/152 [==============================] - 2s 15ms/step - loss: 0.4405 - accuracy: 0.7756
<keras.callbacks.History at 0x7f52dc165990>
numeric_dict_batches = numeric_dict_ds.shuffle(SHUFFLE_BUFFER).batch(BATCH_SIZE)
model.fit(numeric_dict_batches, epochs=5)
Epoch 1/5
152/152 [==============================] - 3s 17ms/step - loss: 0.4345 - accuracy: 0.7789
Epoch 2/5
152/152 [==============================] - 2s 15ms/step - loss: 0.4298 - accuracy: 0.7822
Epoch 3/5
152/152 [==============================] - 2s 15ms/step - loss: 0.4273 - accuracy: 0.7789
Epoch 4/5
152/152 [==============================] - 2s 15ms/step - loss: 0.4246 - accuracy: 0.7855
Epoch 5/5
152/152 [==============================] - 2s 15ms/step - loss: 0.4225 - accuracy: 0.7921
<keras.callbacks.History at 0x7f52dc0d4690>

ต่อไปนี้เป็นคำทำนายสำหรับสามตัวอย่างแรก:

model.predict(dict(numeric_features.iloc[:3]))
array([[[ 0.14884435]],

       [[ 0.37460226]],

       [[-0.08134247]]], dtype=float32)

2. สไตล์การทำงานของ Keras

inputs = {}
for name, column in numeric_features.items():
  inputs[name] = tf.keras.Input(
      shape=(1,), name=name, dtype=tf.float32)

inputs
{'age': <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'age')>,
 'thalach': <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'thalach')>,
 'trestbps': <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'trestbps')>,
 'chol': <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'chol')>,
 'oldpeak': <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'oldpeak')>}
x = stack_dict(inputs, fun=tf.concat)

normalizer = tf.keras.layers.Normalization(axis=-1)
normalizer.adapt(stack_dict(dict(numeric_features)))

x = normalizer(x)
x = tf.keras.layers.Dense(10, activation='relu')(x)
x = tf.keras.layers.Dense(10, activation='relu')(x)
x = tf.keras.layers.Dense(1)(x)

model = tf.keras.Model(inputs, x)

model.compile(optimizer='adam',
              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=['accuracy'],
              run_eagerly=True)
tf.keras.utils.plot_model(model, rankdir="LR", show_shapes=True)

png

คุณสามารถฝึกโมเดลฟังก์ชันได้เช่นเดียวกับคลาสย่อยของโมเดล:

model.fit(dict(numeric_features), target, epochs=5, batch_size=BATCH_SIZE)
Epoch 1/5
152/152 [==============================] - 2s 14ms/step - loss: 0.7151 - accuracy: 0.7030
Epoch 2/5
152/152 [==============================] - 2s 14ms/step - loss: 0.5883 - accuracy: 0.7360
Epoch 3/5
152/152 [==============================] - 2s 14ms/step - loss: 0.5205 - accuracy: 0.7360
Epoch 4/5
152/152 [==============================] - 2s 15ms/step - loss: 0.4838 - accuracy: 0.7492
Epoch 5/5
152/152 [==============================] - 2s 15ms/step - loss: 0.4622 - accuracy: 0.7492
<keras.callbacks.History at 0x7f52bc7b2690>
numeric_dict_batches = numeric_dict_ds.shuffle(SHUFFLE_BUFFER).batch(BATCH_SIZE)
model.fit(numeric_dict_batches, epochs=5)
Epoch 1/5
152/152 [==============================] - 2s 14ms/step - loss: 0.4487 - accuracy: 0.7723
Epoch 2/5
152/152 [==============================] - 2s 14ms/step - loss: 0.4392 - accuracy: 0.7789
Epoch 3/5
152/152 [==============================] - 2s 14ms/step - loss: 0.4339 - accuracy: 0.7789
Epoch 4/5
152/152 [==============================] - 2s 14ms/step - loss: 0.4303 - accuracy: 0.7789
Epoch 5/5
152/152 [==============================] - 2s 14ms/step - loss: 0.4269 - accuracy: 0.7855
<keras.callbacks.History at 0x7f52dc0d4910>

ตัวอย่างเต็ม

มันคุณผ่าน heterogenous DataFrame เพื่อ Keras แต่ละคอลัมน์อาจต้องประมวลผลเบื้องต้นที่ไม่ซ้ำกัน คุณสามารถประมวลผลล่วงหน้านี้ได้โดยตรงใน DataFrame แต่เพื่อให้โมเดลทำงานได้อย่างถูกต้อง อินพุตจะต้องได้รับการประมวลผลล่วงหน้าในลักษณะเดียวกันเสมอ ดังนั้น วิธีที่ดีที่สุดคือการสร้างการประมวลผลล่วงหน้าในแบบจำลอง Keras ชั้น preprocessing ครอบคลุมงานทั่วไปจำนวนมาก

สร้างหัวประมวลผลล่วงหน้า

ในชุดข้อมูลนี้ คุณลักษณะ "จำนวนเต็ม" บางอย่างในข้อมูลดิบเป็นดัชนีตามหมวดหมู่จริงๆ ดัชนีเหล่านี้ไม่ได้มีคำสั่งให้ค่าตัวเลขจริงๆ (หมายถึง คำอธิบายชุดข้อมูล สำหรับรายละเอียด) เนื่องจากสิ่งเหล่านี้ไม่เป็นระเบียบจึงไม่เหมาะสมที่จะป้อนโดยตรงไปยังแบบจำลอง โมเดลจะตีความว่าพวกเขาได้รับคำสั่ง หากต้องการใช้อินพุตเหล่านี้ คุณจะต้องเข้ารหัสเป็นเวกเตอร์แบบร้อนครั้งเดียวหรือเวกเตอร์แบบฝัง เช่นเดียวกับคุณลักษณะการจัดหมวดหมู่สตริง

ในทางกลับกัน คุณสมบัติไบนารีไม่จำเป็นต้องเข้ารหัสหรือทำให้เป็นมาตรฐาน

เริ่มต้นด้วยการสร้างรายการคุณลักษณะที่จัดอยู่ในแต่ละกลุ่ม:

binary_feature_names = ['sex', 'fbs', 'exang']
categorical_feature_names = ['cp', 'restecg', 'slope', 'thal', 'ca']

ขั้นตอนต่อไปคือการสร้างแบบจำลองการประมวลผลล่วงหน้าที่จะใช้การประมวลผลล่วงหน้าที่เหมาะสมกับแต่ละรายการกับอินพุตแต่ละรายการและเชื่อมโยงผลลัพธ์เข้าด้วยกัน

ในส่วนนี้จะใช้ Keras หน้าที่ API ในการดำเนินการ preprocessing คุณเริ่มต้นด้วยการสร้างหนึ่ง tf.keras.Input สำหรับคอลัมน์ของ dataframe แต่ละ:

inputs = {}
for name, column in df.items():
  if type(column[0]) == str:
    dtype = tf.string
  elif (name in categorical_feature_names or
        name in binary_feature_names):
    dtype = tf.int64
  else:
    dtype = tf.float32

  inputs[name] = tf.keras.Input(shape=(), name=name, dtype=dtype)
inputs
{'age': <KerasTensor: shape=(None,) dtype=float32 (created by layer 'age')>,
 'sex': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'sex')>,
 'cp': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'cp')>,
 'trestbps': <KerasTensor: shape=(None,) dtype=float32 (created by layer 'trestbps')>,
 'chol': <KerasTensor: shape=(None,) dtype=float32 (created by layer 'chol')>,
 'fbs': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'fbs')>,
 'restecg': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'restecg')>,
 'thalach': <KerasTensor: shape=(None,) dtype=float32 (created by layer 'thalach')>,
 'exang': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'exang')>,
 'oldpeak': <KerasTensor: shape=(None,) dtype=float32 (created by layer 'oldpeak')>,
 'slope': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'slope')>,
 'ca': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'ca')>,
 'thal': <KerasTensor: shape=(None,) dtype=string (created by layer 'thal')>}

สำหรับแต่ละอินพุต คุณจะต้องใช้การแปลงบางส่วนโดยใช้เลเยอร์ Keras และ TensorFlow ops คุณลักษณะแต่ละคนเริ่มเป็นชุดของสเกลาร์ (ที่ shape=(batch,) ) เอาท์พุทสำหรับแต่ละควรจะเป็นชุดของ tf.float32 เวกเตอร์ ( shape=(batch, n) ) ขั้นตอนสุดท้ายจะเชื่อมเวกเตอร์เหล่านั้นเข้าด้วยกัน

อินพุตไบนารี

เนื่องจากปัจจัยการผลิตไบนารีไม่จำเป็นต้องประมวลผลเบื้องต้นใด ๆ เพียงแค่เพิ่มแกนเวกเตอร์โยนให้แก่ float32 และเพิ่มลงในรายการของปัจจัยการผลิต preprocessed นี้:

preprocessed = []

for name in binary_feature_names:
  inp = inputs[name]
  inp = inp[:, tf.newaxis]
  float_value = tf.cast(inp, tf.float32)
  preprocessed.append(float_value)

preprocessed
[<KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'tf.cast_5')>,
 <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'tf.cast_6')>,
 <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'tf.cast_7')>]

อินพุตตัวเลข

เช่นเดียวกับในส่วนก่อนหน้านี้คุณจะต้องการที่จะเรียกใช้ปัจจัยการผลิตที่เป็นตัวเลขเหล่านี้ผ่าน tf.keras.layers.Normalization ชั้นก่อนที่จะใช้พวกเขา ความแตกต่างคือคราวนี้พวกเขากำลังป้อนข้อมูลเป็น dict โค้ดข้างล่างนี้เก็บรวบรวมคุณสมบัติเป็นตัวเลขจาก DataFrame, กองพวกเขาร่วมกันและส่งผ่านไปยังผู้ Normalization.adapt วิธี

normalizer = tf.keras.layers.Normalization(axis=-1)
normalizer.adapt(stack_dict(dict(numeric_features)))

โค้ดด้านล่างจะซ้อนคุณสมบัติตัวเลขและเรียกใช้ผ่านเลเยอร์การทำให้เป็นมาตรฐาน

numeric_inputs = {}
for name in numeric_feature_names:
  numeric_inputs[name]=inputs[name]

numeric_inputs = stack_dict(numeric_inputs)
numeric_normalized = normalizer(numeric_inputs)

preprocessed.append(numeric_normalized)

preprocessed
[<KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'tf.cast_5')>,
 <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'tf.cast_6')>,
 <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'tf.cast_7')>,
 <KerasTensor: shape=(None, 5) dtype=float32 (created by layer 'normalization_3')>]

คุณสมบัติหมวดหมู่

ในการใช้คุณสมบัติตามหมวดหมู่ ก่อนอื่นคุณต้องเข้ารหัสให้เป็นเวกเตอร์ไบนารีหรือการฝัง เนื่องจากคุณสมบัติเหล่านี้เพียง แต่มีขนาดเล็กจำนวนมากของประเภทแปลงปัจจัยการผลิตโดยตรงกับเวกเตอร์หนึ่งร้อนใช้ output_mode='one_hot' ตัวเลือกที่ได้รับการสนับสนุน byy ทั้ง tf.keras.layers.StringLookup และ tf.keras.layers.IntegerLookup ชั้น

นี่คือตัวอย่างการทำงานของเลเยอร์เหล่านี้:

vocab = ['a','b','c']
lookup = tf.keras.layers.StringLookup(vocabulary=vocab, output_mode='one_hot')
lookup(['c','a','a','b','zzz'])
<tf.Tensor: shape=(5, 4), dtype=float32, numpy=
array([[0., 0., 0., 1.],
       [0., 1., 0., 0.],
       [0., 1., 0., 0.],
       [0., 0., 1., 0.],
       [1., 0., 0., 0.]], dtype=float32)>
vocab = [1,4,7,99]
lookup = tf.keras.layers.IntegerLookup(vocabulary=vocab, output_mode='one_hot')

lookup([-1,4,1])
<tf.Tensor: shape=(3, 5), dtype=float32, numpy=
array([[1., 0., 0., 0., 0.],
       [0., 0., 1., 0., 0.],
       [0., 1., 0., 0., 0.]], dtype=float32)>

ในการกำหนดคำศัพท์สำหรับอินพุตแต่ละรายการ ให้สร้างเลเยอร์เพื่อแปลงคำศัพท์นั้นเป็นเวกเตอร์ยอดนิยม:

for name in categorical_feature_names:
  vocab = sorted(set(df[name]))
  print(f'name: {name}')
  print(f'vocab: {vocab}\n')

  if type(vocab[0]) is str:
    lookup = tf.keras.layers.StringLookup(vocabulary=vocab, output_mode='one_hot')
  else:
    lookup = tf.keras.layers.IntegerLookup(vocabulary=vocab, output_mode='one_hot')

  x = inputs[name][:, tf.newaxis]
  x = lookup(x)
  preprocessed.append(x)
name: cp
vocab: [0, 1, 2, 3, 4]

name: restecg
vocab: [0, 1, 2]

name: slope
vocab: [1, 2, 3]

name: thal
vocab: ['1', '2', 'fixed', 'normal', 'reversible']

name: ca
vocab: [0, 1, 2, 3]

ประกอบหัวประมวลผลล่วงหน้า

ณ จุดนี้ preprocessed เป็นเพียงรายการหลามทุกผล preprocessing แต่ละผลมีรูปร่างของ (batch_size, depth) :

preprocessed
[<KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'tf.cast_5')>,
 <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'tf.cast_6')>,
 <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'tf.cast_7')>,
 <KerasTensor: shape=(None, 5) dtype=float32 (created by layer 'normalization_3')>,
 <KerasTensor: shape=(None, 6) dtype=float32 (created by layer 'integer_lookup_1')>,
 <KerasTensor: shape=(None, 4) dtype=float32 (created by layer 'integer_lookup_2')>,
 <KerasTensor: shape=(None, 4) dtype=float32 (created by layer 'integer_lookup_3')>,
 <KerasTensor: shape=(None, 6) dtype=float32 (created by layer 'string_lookup_1')>,
 <KerasTensor: shape=(None, 5) dtype=float32 (created by layer 'integer_lookup_4')>]

Concatenate คุณลักษณะทั้งหมด preprocessed ไปตาม depth แกนเพื่อให้แต่ละพจนานุกรมตัวอย่างจะถูกแปลงเป็นเวกเตอร์เดียว เวกเตอร์ประกอบด้วยคุณสมบัติการจัดหมวดหมู่ คุณสมบัติตัวเลข และคุณสมบัติด่วนหมวดหมู่:

preprocesssed_result = tf.concat(preprocessed, axis=-1)
preprocesssed_result
<KerasTensor: shape=(None, 33) dtype=float32 (created by layer 'tf.concat_1')>

ตอนนี้สร้างแบบจำลองจากการคำนวณนั้นเพื่อให้สามารถนำกลับมาใช้ใหม่ได้:

preprocessor = tf.keras.Model(inputs, preprocesssed_result)
tf.keras.utils.plot_model(preprocessor, rankdir="LR", show_shapes=True)

png

ในการทดสอบ preprocessor ใช้ DataFrame.iloc เข้าถึงหั่นตัวอย่างแรกจาก DataFrame จากนั้นแปลงเป็นพจนานุกรมและส่งพจนานุกรมไปยังตัวประมวลผลล่วงหน้า ผลลัพธ์ที่ได้คือเวกเตอร์เดียวที่มีคุณลักษณะไบนารี คุณลักษณะที่เป็นตัวเลขปกติ และคุณลักษณะการจัดหมวดหมู่ที่ร้อนแรง ตามลำดับ:

preprocessor(dict(df.iloc[:1]))
<tf.Tensor: shape=(1, 33), dtype=float32, numpy=
array([[ 1.        ,  1.        ,  0.        ,  0.93383914, -0.26008663,
         1.0680453 ,  0.03480718,  0.74578077,  0.        ,  0.        ,

         1.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  1.        ,  0.        ,  0.        ,
         0.        ,  1.        ,  0.        ,  0.        ,  0.        ,
         1.        ,  0.        ,  0.        ,  0.        ,  1.        ,
         0.        ,  0.        ,  0.        ]], dtype=float32)>

สร้างและฝึกโมเดล

ตอนนี้สร้างตัวหลักของโมเดล ใช้การกำหนดค่าเช่นเดียวกับในตัวอย่างก่อนหน้านี้: คู่ของ Dense แก้ไขเชิงเส้นชั้นและ Dense(1) ชั้นเอาท์พุทสำหรับการจัดหมวดหมู่

body = tf.keras.Sequential([
  tf.keras.layers.Dense(10, activation='relu'),
  tf.keras.layers.Dense(10, activation='relu'),
  tf.keras.layers.Dense(1)
])

ตอนนี้นำทั้งสองส่วนมารวมกันโดยใช้ Keras functional API

inputs
{'age': <KerasTensor: shape=(None,) dtype=float32 (created by layer 'age')>,
 'sex': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'sex')>,
 'cp': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'cp')>,
 'trestbps': <KerasTensor: shape=(None,) dtype=float32 (created by layer 'trestbps')>,
 'chol': <KerasTensor: shape=(None,) dtype=float32 (created by layer 'chol')>,
 'fbs': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'fbs')>,
 'restecg': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'restecg')>,
 'thalach': <KerasTensor: shape=(None,) dtype=float32 (created by layer 'thalach')>,
 'exang': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'exang')>,
 'oldpeak': <KerasTensor: shape=(None,) dtype=float32 (created by layer 'oldpeak')>,
 'slope': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'slope')>,
 'ca': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'ca')>,
 'thal': <KerasTensor: shape=(None,) dtype=string (created by layer 'thal')>}
x = preprocessor(inputs)
x
<KerasTensor: shape=(None, 33) dtype=float32 (created by layer 'model_1')>
result = body(x)
result
<KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'sequential_3')>
model = tf.keras.Model(inputs, result)

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

โมเดลนี้คาดว่าจะมีพจนานุกรมของอินพุต วิธีที่ง่ายที่สุดที่จะผ่านมันข้อมูลคือการแปลง DataFrame เพื่อ Dict และผ่าน Dict ที่เป็น x อาร์กิวเมนต์ Model.fit :

history = model.fit(dict(df), target, epochs=5, batch_size=BATCH_SIZE)
Epoch 1/5
152/152 [==============================] - 1s 4ms/step - loss: 0.5340 - accuracy: 0.7558
Epoch 2/5
152/152 [==============================] - 1s 4ms/step - loss: 0.4038 - accuracy: 0.7789
Epoch 3/5
152/152 [==============================] - 1s 4ms/step - loss: 0.3515 - accuracy: 0.8218
Epoch 4/5
152/152 [==============================] - 1s 4ms/step - loss: 0.3262 - accuracy: 0.8482
Epoch 5/5
152/152 [==============================] - 1s 4ms/step - loss: 0.3087 - accuracy: 0.8680

ใช้ tf.data งานเช่นกัน:

ds = tf.data.Dataset.from_tensor_slices((
    dict(df),
    target
))

ds = ds.batch(BATCH_SIZE)
import pprint

for x, y in ds.take(1):
  pprint.pprint(x)
  print()
  print(y)
{'age': <tf.Tensor: shape=(2,), dtype=int64, numpy=array([63, 67])>,
 'ca': <tf.Tensor: shape=(2,), dtype=int64, numpy=array([0, 3])>,
 'chol': <tf.Tensor: shape=(2,), dtype=int64, numpy=array([233, 286])>,
 'cp': <tf.Tensor: shape=(2,), dtype=int64, numpy=array([1, 4])>,
 'exang': <tf.Tensor: shape=(2,), dtype=int64, numpy=array([0, 1])>,
 'fbs': <tf.Tensor: shape=(2,), dtype=int64, numpy=array([1, 0])>,
 'oldpeak': <tf.Tensor: shape=(2,), dtype=float64, numpy=array([2.3, 1.5])>,
 'restecg': <tf.Tensor: shape=(2,), dtype=int64, numpy=array([2, 2])>,
 'sex': <tf.Tensor: shape=(2,), dtype=int64, numpy=array([1, 1])>,
 'slope': <tf.Tensor: shape=(2,), dtype=int64, numpy=array([3, 2])>,
 'thal': <tf.Tensor: shape=(2,), dtype=string, numpy=array([b'fixed', b'normal'], dtype=object)>,
 'thalach': <tf.Tensor: shape=(2,), dtype=int64, numpy=array([150, 108])>,
 'trestbps': <tf.Tensor: shape=(2,), dtype=int64, numpy=array([145, 160])>}

tf.Tensor([0 1], shape=(2,), dtype=int64)
history = model.fit(ds, epochs=5)
Epoch 1/5
152/152 [==============================] - 1s 4ms/step - loss: 0.2982 - accuracy: 0.8581
Epoch 2/5
152/152 [==============================] - 1s 5ms/step - loss: 0.2898 - accuracy: 0.8647
Epoch 3/5
152/152 [==============================] - 1s 5ms/step - loss: 0.2831 - accuracy: 0.8680
Epoch 4/5
152/152 [==============================] - 1s 5ms/step - loss: 0.2772 - accuracy: 0.8680
Epoch 5/5
152/152 [==============================] - 1s 4ms/step - loss: 0.2720 - accuracy: 0.8680