Google I / O là một kết quả hoàn hảo! Cập nhật các phiên TensorFlow Xem phiên

Tải DataFrame gấu trúc

Xem trên TensorFlow.org Chạy trong Google Colab Xem nguồn trên GitHub Tải xuống sổ ghi chép

Hướng dẫn này cung cấp các ví dụ về cách tải DataFrames của gấu trúc vào TensorFlow.

Bạn sẽ sử dụng một tập dữ liệu nhỏ về bệnh tim do Kho lưu trữ Máy học UCI cung cấp. Có vài trăm hàng trong CSV. Mỗi hàng mô tả một bệnh nhân và mỗi cột mô tả một thuộc tính. Bạn sẽ sử dụng thông tin này để dự đoán liệu một bệnh nhân có bị bệnh tim hay không, đây là một nhiệm vụ phân loại nhị phân.

Đọc dữ liệu bằng gấu trúc

import pandas as pd
import tensorflow as tf

SHUFFLE_BUFFER = 500
BATCH_SIZE = 2

Tải xuống tệp CSV chứa tập dữ liệu bệnh tim:

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

Đọc tệp CSV bằng cách sử dụng gấu trúc:

df = pd.read_csv(csv_file)

Dữ liệu trông như thế này:

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

Bạn sẽ xây dựng các mô hình để dự đoán nhãn chứa trong cột target .

target = df.pop('target')

DataFrame dưới dạng một mảng

Nếu dữ liệu của bạn có kiểu dữ liệu hoặc loại dữ liệu thống nhất, bạn có thể sử dụng dtype gấu trúc ở bất kỳ đâu bạn có thể sử dụng mảng NumPy. Điều này hoạt động vì lớp pandas.DataFrame hỗ trợ giao thức __array__ và hàm tf.convert_to_tensor của TensorFlow chấp nhận các đối tượng hỗ trợ giao thức.

Lấy các tính năng số từ tập dữ liệu (bỏ qua các tính năng phân loại ngay bây giờ):

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

DataFrame có thể được chuyển đổi thành mảng NumPy bằng cách sử dụng thuộc tính DataFrame.values hoặc numpy.array(df) . Để chuyển đổi nó thành tensor, hãy sử dụng 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. ]])>

Nói chung, nếu một đối tượng có thể được chuyển đổi thành tensor với tf.convert_to_tensor , nó có thể được chuyển ở bất kỳ đâu bạn có thể chuyển qua tf.Tensor .

Với Model.fit

DataFrame, được hiểu là một tensor đơn, có thể được sử dụng trực tiếp làm đối số cho phương thức Model.fit .

Dưới đây là một ví dụ về đào tạo một mô hình về các tính năng số của tập dữ liệu.

Bước đầu tiên là chuẩn hóa các phạm vi đầu vào. Sử dụng lớp tf.keras.layers.Normalization cho điều đó.

Để đặt giá trị trung bình và độ lệch chuẩn của lớp trước khi chạy, hãy nhớ gọi phương thức Normalization.adapt :

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

Gọi lớp trên ba hàng đầu tiên của DataFrame để trực quan hóa ví dụ về kết quả từ lớp này:

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

Sử dụng lớp chuẩn hóa làm lớp đầu tiên của một mô hình đơn giản:

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

Khi bạn chuyển DataFrame làm đối số x cho Model.fit , Keras xử lý DataFrame giống như một mảng 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.6839 - accuracy: 0.7690
Epoch 2/15
152/152 [==============================] - 0s 2ms/step - loss: 0.5789 - accuracy: 0.7789
Epoch 3/15
152/152 [==============================] - 0s 2ms/step - loss: 0.5195 - accuracy: 0.7723
Epoch 4/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4814 - accuracy: 0.7855
Epoch 5/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4566 - accuracy: 0.7789
Epoch 6/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4427 - accuracy: 0.7888
Epoch 7/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4342 - accuracy: 0.7921
Epoch 8/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4290 - accuracy: 0.7855
Epoch 9/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4240 - accuracy: 0.7987
Epoch 10/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4232 - accuracy: 0.7987
Epoch 11/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4208 - accuracy: 0.7987
Epoch 12/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4186 - accuracy: 0.7954
Epoch 13/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4172 - accuracy: 0.8020
Epoch 14/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4156 - accuracy: 0.8020
Epoch 15/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4138 - accuracy: 0.8020
<keras.callbacks.History at 0x7f1ddc27b110>

Với tf.data

Nếu bạn muốn áp dụng các phép biến đổi tf.data cho DataFrame của một loại dtype đồng nhất, phương thức Dataset.from_tensor_slices sẽ tạo một tập dữ liệu lặp qua các hàng của DataFrame. Mỗi hàng ban đầu là một vectơ giá trị. Để đào tạo một mô hình, bạn cần các cặp (inputs, labels) , vì vậy truyền (features, labels)Dataset.from_tensor_slices sẽ trả về các cặp lát cắt cần thiết:

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.7677 - accuracy: 0.6865
Epoch 2/15
152/152 [==============================] - 0s 2ms/step - loss: 0.6319 - accuracy: 0.7591
Epoch 3/15
152/152 [==============================] - 0s 2ms/step - loss: 0.5717 - accuracy: 0.7459
Epoch 4/15
152/152 [==============================] - 0s 2ms/step - loss: 0.5228 - accuracy: 0.7558
Epoch 5/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4820 - accuracy: 0.7624
Epoch 6/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4584 - accuracy: 0.7657
Epoch 7/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4454 - accuracy: 0.7657
Epoch 8/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4379 - accuracy: 0.7789
Epoch 9/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4324 - accuracy: 0.7789
Epoch 10/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4282 - accuracy: 0.7756
Epoch 11/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4273 - accuracy: 0.7789
Epoch 12/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4268 - accuracy: 0.7756
Epoch 13/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4248 - accuracy: 0.7789
Epoch 14/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4235 - accuracy: 0.7855
Epoch 15/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4223 - accuracy: 0.7888
<keras.callbacks.History at 0x7f1ddc406510>

DataFrame như một từ điển

Khi bạn bắt đầu xử lý dữ liệu không đồng nhất, bạn không thể xử lý DataFrame như thể nó là một mảng duy nhất. TensorFlow tensors yêu cầu tất cả các phần tử có cùng một dtype .

Vì vậy, trong trường hợp này, bạn cần bắt đầu coi nó như một từ điển của các cột, trong đó mỗi cột có một kiểu đồng nhất. DataFrame rất giống một từ điển của các mảng, vì vậy thông thường tất cả những gì bạn cần làm là truyền DataFrame sang một câu lệnh Python. Nhiều API TensorFlow quan trọng hỗ trợ từ điển (lồng nhau-) của các mảng làm đầu vào.

Đường ống đầu vào tf.data xử lý điều này khá tốt. Tất cả các thao tác tf.data động xử lý từ điển và bộ giá trị. Vì vậy, để tạo tập dữ liệu gồm các ví dụ từ điển từ DataFrame, chỉ cần truyền nó thành một lệnh trước khi cắt nó bằng Dataset.from_tensor_slices :

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

Dưới đây là ba ví dụ đầu tiên từ tập dữ liệu đó:

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

Từ điển với Keras

Thông thường, các mô hình và lớp Keras mong đợi một tensor đầu vào duy nhất, nhưng các lớp này có thể chấp nhận và trả về các cấu trúc lồng nhau của từ điển, bộ giá trị và tensor. Những cấu trúc này được gọi là "tổ" (tham khảo mô-đun tf.nest để biết thêm chi tiết).

Có hai cách tương đương để bạn có thể viết một mô hình keras chấp nhận một từ điển làm đầu vào.

1. Kiểu mẫu-lớp con

Bạn viết một lớp con của tf.keras.Model (hoặc tf.keras.Layer ). Bạn trực tiếp xử lý các đầu vào và tạo ra các đầu ra:

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)

Mô hình này có thể chấp nhận một từ điển các cột hoặc một tập dữ liệu gồm các phần tử từ điển để đào tạo:

model.fit(dict(numeric_features), target, epochs=5, batch_size=BATCH_SIZE)
Epoch 1/5
152/152 [==============================] - 3s 17ms/step - loss: 0.6736 - accuracy: 0.7063
Epoch 2/5
152/152 [==============================] - 3s 17ms/step - loss: 0.5577 - accuracy: 0.7294
Epoch 3/5
152/152 [==============================] - 2s 16ms/step - loss: 0.4869 - accuracy: 0.7591
Epoch 4/5
152/152 [==============================] - 2s 16ms/step - loss: 0.4525 - accuracy: 0.7690
Epoch 5/5
152/152 [==============================] - 2s 16ms/step - loss: 0.4403 - accuracy: 0.7624
<keras.callbacks.History at 0x7f1de4fa9390>
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 15ms/step - loss: 0.4328 - accuracy: 0.7756
Epoch 2/5
152/152 [==============================] - 2s 14ms/step - loss: 0.4297 - accuracy: 0.7888
Epoch 3/5
152/152 [==============================] - 2s 15ms/step - loss: 0.4270 - accuracy: 0.7888
Epoch 4/5
152/152 [==============================] - 2s 15ms/step - loss: 0.4245 - accuracy: 0.8020
Epoch 5/5
152/152 [==============================] - 2s 15ms/step - loss: 0.4240 - accuracy: 0.7921
<keras.callbacks.History at 0x7f1ddc0dba90>

Dưới đây là dự đoán cho ba ví dụ đầu tiên:

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

       [[0.60601974]],

       [[0.03647463]]], dtype=float32)

2. Phong cách chức năng 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

Bạn có thể huấn luyện mô hình chức năng theo cách giống như lớp con của mô hình:

model.fit(dict(numeric_features), target, epochs=5, batch_size=BATCH_SIZE)
Epoch 1/5
152/152 [==============================] - 2s 15ms/step - loss: 0.6529 - accuracy: 0.7492
Epoch 2/5
152/152 [==============================] - 2s 15ms/step - loss: 0.5448 - accuracy: 0.7624
Epoch 3/5
152/152 [==============================] - 2s 15ms/step - loss: 0.4935 - accuracy: 0.7756
Epoch 4/5
152/152 [==============================] - 2s 15ms/step - loss: 0.4650 - accuracy: 0.7789
Epoch 5/5
152/152 [==============================] - 2s 15ms/step - loss: 0.4486 - accuracy: 0.7855
<keras.callbacks.History at 0x7f1ddc0d0f90>
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 15ms/step - loss: 0.4398 - accuracy: 0.7855
Epoch 2/5
152/152 [==============================] - 2s 15ms/step - loss: 0.4330 - accuracy: 0.7855
Epoch 3/5
152/152 [==============================] - 2s 16ms/step - loss: 0.4294 - accuracy: 0.7921
Epoch 4/5
152/152 [==============================] - 2s 16ms/step - loss: 0.4271 - accuracy: 0.7888
Epoch 5/5
152/152 [==============================] - 2s 16ms/step - loss: 0.4231 - accuracy: 0.7855
<keras.callbacks.History at 0x7f1d7c5d5d10>

Đầy đủ ví dụ

Đó là bạn đang chuyển một DataFrame không đồng nhất tới Keras, mỗi cột có thể cần xử lý trước duy nhất. Bạn có thể thực hiện tiền xử lý này trực tiếp trong DataFrame, nhưng để một mô hình hoạt động chính xác, các đầu vào luôn cần được xử lý trước theo cùng một cách. Vì vậy, cách tiếp cận tốt nhất là xây dựng tiền xử lý vào mô hình. Các lớp tiền xử lý của Keras bao gồm nhiều tác vụ phổ biến.

Xây dựng đầu tiền xử lý

Trong tập dữ liệu này, một số tính năng "số nguyên" trong dữ liệu thô thực sự là các chỉ số Categorical. Các chỉ số này không thực sự là các giá trị số được sắp xếp theo thứ tự (tham khảo mô tả tập dữ liệu để biết thêm chi tiết). Bởi vì những thứ này không có thứ tự nên chúng không có quyền sở hữu để cung cấp trực tiếp cho mô hình; mô hình sẽ diễn giải chúng như được đặt hàng. Để sử dụng các đầu vào này, bạn sẽ cần mã hóa chúng, dưới dạng vectơ một nóng hoặc vectơ nhúng. Điều tương tự cũng áp dụng cho các đối tượng phân loại theo chuỗi.

Mặt khác, các tính năng nhị phân thường không cần được mã hóa hoặc chuẩn hóa.

Bắt đầu bằng cách tạo danh sách các tính năng được chia thành từng nhóm:

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

Bước tiếp theo là xây dựng một mô hình tiền xử lý sẽ áp dụng tiền xử lý thích hợp cho từng đầu vào và nối các kết quả.

Phần này sử dụng API chức năng Keras để triển khai tiền xử lý. Bạn bắt đầu bằng cách tạo một tf.keras.Input cho mỗi cột của khung dữ liệu:

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

Đối với mỗi đầu vào, bạn sẽ áp dụng một số phép biến đổi bằng cách sử dụng các lớp Keras và hoạt động TensorFlow. Mỗi tính năng bắt đầu như một loạt các đại lượng vô hướng ( shape=(batch,) ). Đầu ra cho mỗi vectơ phải là một lô vectơ tf.float32 ( shape=(batch, n) ). Bước cuối cùng sẽ nối tất cả các vectơ đó lại với nhau.

Đầu vào nhị phân

Vì các đầu vào nhị phân không cần bất kỳ xử lý trước nào, chỉ cần thêm trục vectơ, truyền chúng thành float32 và thêm chúng vào danh sách các đầu vào được xử lý trước:

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

Đầu vào số

Giống như trong phần trước, bạn sẽ muốn chạy các đầu vào số này thông qua lớp tf.keras.layers.Normalization trước khi sử dụng chúng. Sự khác biệt là lần này chúng được nhập dưới dạng chính tả. Đoạn mã dưới đây thu thập các đặc điểm số từ DataFrame, xếp chúng lại với nhau và chuyển chúng đến phương thức Normalization.adapt .

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

Đoạn mã dưới đây xếp chồng các tính năng số và chạy chúng qua lớp chuẩn hóa.

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

Các tính năng phân loại

Để sử dụng các tính năng phân loại, trước tiên bạn cần mã hóa chúng thành các vectơ nhị phân hoặc các tệp nhúng. Vì các tính năng này chỉ chứa một số lượng nhỏ các danh mục, hãy chuyển đổi đầu vào trực tiếp thành vectơ một nóng bằng cách sử dụng tùy chọn output_mode='one_hot' , được hỗ trợ bởi cả hai lớp tf.keras.layers.StringLookuptf.keras.layers.IntegerLookup .

Đây là một ví dụ về cách các lớp này hoạt động:

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

Để xác định từ vựng cho mỗi đầu vào, hãy tạo một lớp để chuyển đổi từ vựng đó thành vectơ duy nhất:

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]

Lắp ráp đầu tiền xử lý

Tại thời điểm này, preprocessed chỉ là một danh sách Python gồm tất cả các kết quả tiền xử lý, mỗi kết quả có dạng (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')>]

Kết hợp tất cả các đối tượng địa lý đã được xử lý trước dọc theo trục depth , do đó mỗi từ điển-ví dụ được chuyển đổi thành một vectơ duy nhất. Vectơ chứa các đối tượng địa lý phân loại, đối tượng số và các đối tượng địa lý phổ biến:

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

Bây giờ, hãy tạo một mô hình từ phép tính đó để nó có thể được sử dụng lại:

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

png

Để kiểm tra bộ tiền xử lý, hãy sử dụng bộ truy cập DataFrame.iloc để cắt ví dụ đầu tiên từ DataFrame. Sau đó chuyển nó thành từ điển và chuyển từ điển cho bộ tiền xử lý. Kết quả là một vectơ duy nhất chứa các đối tượng nhị phân, đối tượng số được chuẩn hóa và các đối tượng phân loại duy nhất, theo thứ tự đó:

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

Tạo và đào tạo một mô hình

Bây giờ xây dựng phần thân chính của mô hình. Sử dụng cấu hình tương tự như trong ví dụ trước: Một vài lớp tuyến tính được chỉnh lưu Dense và một lớp đầu ra Dense(1) để phân loại.

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

Bây giờ hãy ghép hai phần lại với nhau bằng cách sử dụng API chức năng Keras.

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

Mô hình này mong đợi một từ điển của các đầu vào. Cách đơn giản nhất để chuyển nó dữ liệu là chuyển DataFrame thành một dict và chuyển dict đó làm đối số x cho Model.fit :

history = model.fit(dict(df), target, epochs=5, batch_size=BATCH_SIZE)
Epoch 1/5
152/152 [==============================] - 1s 4ms/step - loss: 0.6911 - accuracy: 0.6997
Epoch 2/5
152/152 [==============================] - 1s 4ms/step - loss: 0.5073 - accuracy: 0.7393
Epoch 3/5
152/152 [==============================] - 1s 4ms/step - loss: 0.4129 - accuracy: 0.7888
Epoch 4/5
152/152 [==============================] - 1s 4ms/step - loss: 0.3663 - accuracy: 0.7921
Epoch 5/5
152/152 [==============================] - 1s 4ms/step - loss: 0.3363 - accuracy: 0.8152

Sử dụng tf.data cũng hoạt động:

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 5ms/step - loss: 0.3150 - accuracy: 0.8284
Epoch 2/5
152/152 [==============================] - 1s 5ms/step - loss: 0.2989 - accuracy: 0.8449
Epoch 3/5
152/152 [==============================] - 1s 5ms/step - loss: 0.2870 - accuracy: 0.8449
Epoch 4/5
152/152 [==============================] - 1s 5ms/step - loss: 0.2782 - accuracy: 0.8482
Epoch 5/5
152/152 [==============================] - 1s 5ms/step - loss: 0.2712 - accuracy: 0.8482