ML Community Day คือวันที่ 9 พฤศจิกายน! ร่วมกับเราสำหรับการปรับปรุงจาก TensorFlow, JAX และอื่น ๆ เรียนรู้เพิ่มเติม

โหลด 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)
class MyModel(tf.keras.Model):
  def __init__(self):
    # Create all the internal layers in init.
    super().__init__(self)

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

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

  def adapt(self, inputs):
    # Stach the inputs and `adapt` the normalization layer.
    inputs = stack_dict(inputs)
    self.normalizer.adapt(inputs)

  def call(self, inputs):
    # Stack the inputs
    inputs = stack_dict(inputs)
    # Run them through all the layers.
    result = self.seq(inputs)

    return result

model = MyModel()

model.adapt(dict(numeric_features))

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

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

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