Catat tanggalnya! Google I / O mengembalikan 18-20 Mei Daftar sekarang
Halaman ini diterjemahkan oleh Cloud Translation API.
Switch to English

Muat data CSV

Lihat di TensorFlow.org Jalankan di Google Colab Lihat sumber di GitHubUnduh buku catatan

Tutorial ini memberikan contoh cara menggunakan data CSV dengan TensorFlow.

Ada dua bagian utama untuk ini:

  1. Memuat data dari disk
  2. Pra-pemrosesan menjadi bentuk yang sesuai untuk pelatihan.

Tutorial ini berfokus pada pemuatan, dan memberikan beberapa contoh cepat pemrosesan awal. Untuk tutorial yang berfokus pada aspek preprocessing, lihat panduan dan tutorial lapisan preprocessing .

Mendirikan

import pandas as pd
import numpy as np

# Make numpy values easier to read.
np.set_printoptions(precision=3, suppress=True)

import tensorflow as tf
from tensorflow.keras import layers
from tensorflow.keras.layers.experimental import preprocessing

Dalam data memori

Untuk set data CSV kecil, cara termudah untuk melatih model TensorFlow adalah dengan memuatnya ke dalam memori sebagai pandas Dataframe atau array NumPy.

Contoh yang relatif sederhana adalah dataset abalone .

  • Datasetnya kecil.
  • Semua fitur masukan adalah nilai floating point rentang terbatas.

Berikut adalah cara mengunduh data ke dalam Pandas DataFrame :

abalone_train = pd.read_csv(
    "https://storage.googleapis.com/download.tensorflow.org/data/abalone_train.csv",
    names=["Length", "Diameter", "Height", "Whole weight", "Shucked weight",
           "Viscera weight", "Shell weight", "Age"])

abalone_train.head()

Dataset tersebut berisi satu set pengukuran abalone , sejenis siput laut.

cangkang abalon

“Abalone shell” (oleh Nicki Dugan Pogue , CC BY-SA 2.0)

Tugas nominal untuk kumpulan data ini adalah memprediksi usia dari pengukuran lain, jadi pisahkan fitur dan label untuk pelatihan:

abalone_features = abalone_train.copy()
abalone_labels = abalone_features.pop('Age')

Untuk kumpulan data ini, Anda akan memperlakukan semua fitur secara identik. Kemas fitur ke dalam satu array NumPy .:

abalone_features = np.array(abalone_features)
abalone_features
array([[0.435, 0.335, 0.11 , ..., 0.136, 0.077, 0.097],
       [0.585, 0.45 , 0.125, ..., 0.354, 0.207, 0.225],
       [0.655, 0.51 , 0.16 , ..., 0.396, 0.282, 0.37 ],
       ...,
       [0.53 , 0.42 , 0.13 , ..., 0.374, 0.167, 0.249],
       [0.395, 0.315, 0.105, ..., 0.118, 0.091, 0.119],
       [0.45 , 0.355, 0.12 , ..., 0.115, 0.067, 0.16 ]])

Selanjutnya membuat model regresi memprediksi umur. Karena hanya ada satu input tensor, model keras.Sequential sudah cukup di sini.

abalone_model = tf.keras.Sequential([
  layers.Dense(64),
  layers.Dense(1)
])

abalone_model.compile(loss = tf.losses.MeanSquaredError(),
                      optimizer = tf.optimizers.Adam())

Untuk melatih model itu, teruskan fitur dan label ke Model.fit :

abalone_model.fit(abalone_features, abalone_labels, epochs=10)
Epoch 1/10
104/104 [==============================] - 0s 1ms/step - loss: 60.2584
Epoch 2/10
104/104 [==============================] - 0s 1ms/step - loss: 11.4741
Epoch 3/10
104/104 [==============================] - 0s 1ms/step - loss: 8.5354
Epoch 4/10
104/104 [==============================] - 0s 1ms/step - loss: 8.0559
Epoch 5/10
104/104 [==============================] - 0s 1ms/step - loss: 7.6156
Epoch 6/10
104/104 [==============================] - 0s 1ms/step - loss: 7.2644
Epoch 7/10
104/104 [==============================] - 0s 1ms/step - loss: 6.9853
Epoch 8/10
104/104 [==============================] - 0s 1ms/step - loss: 6.7824
Epoch 9/10
104/104 [==============================] - 0s 1ms/step - loss: 6.6324
Epoch 10/10
104/104 [==============================] - 0s 1ms/step - loss: 6.5348
<tensorflow.python.keras.callbacks.History at 0x7f3f74717080>

Anda baru saja melihat cara paling dasar untuk melatih model menggunakan data CSV. Selanjutnya, Anda akan mempelajari cara menerapkan prapemrosesan untuk menormalkan kolom numerik.

Pemrosesan awal dasar

Praktik yang baik untuk menormalkan input ke model Anda. Lapisan experimental.preprocessing menyediakan cara mudah untuk membuat normalisasi ini ke dalam model Anda.

Layer tersebut akan menghitung mean dan varians setiap kolom, dan menggunakannya untuk menormalkan data.

Pertama Anda membuat lapisan:

normalize = preprocessing.Normalization()
.dll

Kemudian Anda menggunakan metode Normalization.adapt() untuk menyesuaikan lapisan normalisasi dengan data Anda.

normalize.adapt(abalone_features)

Kemudian gunakan lapisan normalisasi dalam model Anda:

norm_abalone_model = tf.keras.Sequential([
  normalize,
  layers.Dense(64),
  layers.Dense(1)
])

norm_abalone_model.compile(loss = tf.losses.MeanSquaredError(),
                           optimizer = tf.optimizers.Adam())

norm_abalone_model.fit(abalone_features, abalone_labels, epochs=10)
Epoch 1/10
104/104 [==============================] - 0s 2ms/step - loss: 93.4577
Epoch 2/10
104/104 [==============================] - 0s 1ms/step - loss: 54.7412
Epoch 3/10
104/104 [==============================] - 0s 2ms/step - loss: 16.7861
Epoch 4/10
104/104 [==============================] - 0s 2ms/step - loss: 5.8002
Epoch 5/10
104/104 [==============================] - 0s 1ms/step - loss: 4.9725
Epoch 6/10
104/104 [==============================] - 0s 1ms/step - loss: 4.9332
Epoch 7/10
104/104 [==============================] - 0s 1ms/step - loss: 4.9074
Epoch 8/10
104/104 [==============================] - 0s 1ms/step - loss: 4.9035
Epoch 9/10
104/104 [==============================] - 0s 1ms/step - loss: 4.9028
Epoch 10/10
104/104 [==============================] - 0s 1ms/step - loss: 4.8998
<tensorflow.python.keras.callbacks.History at 0x7f3f7454f4e0>

Tipe data campuran

Dataset "Titanic" berisi informasi tentang penumpang di Titanic. Tugas nominal pada kumpulan data ini adalah untuk memprediksi siapa yang selamat.

Titanic

Gambar dari Wikimedia

Data mentah dapat dengan mudah dimuat sebagai Pandas DataFrame , tetapi tidak langsung dapat digunakan sebagai masukan untuk model TensorFlow.

titanic = pd.read_csv("https://storage.googleapis.com/tf-datasets/titanic/train.csv")
titanic.head()
titanic_features = titanic.copy()
titanic_labels = titanic_features.pop('survived')

Karena jenis dan rentang data yang berbeda, Anda tidak bisa begitu saja menumpuk fitur ke dalam array NumPy dan meneruskannya ke model keras.Sequential . Setiap kolom perlu ditangani secara individual.

Sebagai salah satu opsi, Anda dapat memproses data Anda secara offline (menggunakan fitur apa pun yang Anda suka) untuk mengonversi kolom kategorik menjadi kolom numerik, lalu meneruskan output yang diproses ke model TensorFlow Anda. Kerugian dari pendekatan itu adalah jika Anda menyimpan dan mengekspor model Anda, preprocessing tidak disimpan dengannya. Lapisan experimental.preprocessing menghindari masalah ini karena mereka adalah bagian dari model.

Dalam contoh ini, Anda akan membuat model yang mengimplementasikan logika preprocessing menggunakan API fungsional Keras . Anda juga bisa melakukannya dengan subclassing .

API fungsional beroperasi pada tensor "simbolis". Tensor "bersemangat" normal memiliki nilai. Sebaliknya, tensor "simbolis" ini tidak. Sebaliknya, mereka melacak operasi mana yang dijalankan pada mereka, dan membangun representasi penghitungan, yang bisa Anda jalankan nanti. Berikut contoh singkatnya:

# Create a symbolic input
input = tf.keras.Input(shape=(), dtype=tf.float32)

# Do a calculation using is
result = 2*input + 1

# the result doesn't have a value
result
<tf.Tensor 'AddV2:0' shape=(None,) dtype=float32>
calc = tf.keras.Model(inputs=input, outputs=result)
print(calc(1).numpy())
print(calc(2).numpy())
3.0
5.0

Untuk membangun model preprocessing, mulailah dengan membangun sekumpulan objek simbolik keras.Input , yang cocok dengan nama dan tipe data dari kolom CSV.

inputs = {}

for name, column in titanic_features.items():
  dtype = column.dtype
  if dtype == object:
    dtype = tf.string
  else:
    dtype = tf.float32

  inputs[name] = tf.keras.Input(shape=(1,), name=name, dtype=dtype)

inputs
{'sex': <tf.Tensor 'sex:0' shape=(None, 1) dtype=string>,
 'age': <tf.Tensor 'age:0' shape=(None, 1) dtype=float32>,
 'n_siblings_spouses': <tf.Tensor 'n_siblings_spouses:0' shape=(None, 1) dtype=float32>,
 'parch': <tf.Tensor 'parch:0' shape=(None, 1) dtype=float32>,
 'fare': <tf.Tensor 'fare:0' shape=(None, 1) dtype=float32>,
 'class': <tf.Tensor 'class:0' shape=(None, 1) dtype=string>,
 'deck': <tf.Tensor 'deck:0' shape=(None, 1) dtype=string>,
 'embark_town': <tf.Tensor 'embark_town:0' shape=(None, 1) dtype=string>,
 'alone': <tf.Tensor 'alone:0' shape=(None, 1) dtype=string>}

Langkah pertama dalam logika preprocessing Anda adalah menggabungkan input numerik, dan menjalankannya melalui lapisan normalisasi:

numeric_inputs = {name:input for name,input in inputs.items()
                  if input.dtype==tf.float32}

x = layers.Concatenate()(list(numeric_inputs.values()))
norm = preprocessing.Normalization()
norm.adapt(np.array(titanic[numeric_inputs.keys()]))
all_numeric_inputs = norm(x)

all_numeric_inputs
<tf.Tensor 'normalization_1/truediv:0' shape=(None, 4) dtype=float32>

Kumpulkan semua hasil pemrosesan awal simbolis, untuk digabungkan nanti.

preprocessed_inputs = [all_numeric_inputs]

Untuk input string gunakan fungsi preprocessing.StringLookup untuk memetakan dari string ke indeks integer dalam sebuah kosakata. Selanjutnya, gunakan preprocessing.CategoryEncoding untuk mengubah indeks menjadi data float32 sesuai untuk model tersebut.

Pengaturan default untuk lapisan preprocessing.CategoryEncoding membuat vektor one-hot untuk setiap masukan. layers.Embedding A. layers.Embedding juga akan berfungsi. Lihat panduan dan tutorial lapisan praproses untuk lebih lanjut tentang topik ini.

for name, input in inputs.items():
  if input.dtype == tf.float32:
    continue

  lookup = preprocessing.StringLookup(vocabulary=np.unique(titanic_features[name]))
  one_hot = preprocessing.CategoryEncoding(max_tokens=lookup.vocab_size())

  x = lookup(input)
  x = one_hot(x)
  preprocessed_inputs.append(x)

Dengan kumpulan inputs dan processed_inputs , Anda bisa menggabungkan semua input yang diproses sebelumnya, dan membangun model yang menangani preprocessing:

preprocessed_inputs_cat = layers.Concatenate()(preprocessed_inputs)

titanic_preprocessing = tf.keras.Model(inputs, preprocessed_inputs_cat)

tf.keras.utils.plot_model(model = titanic_preprocessing , rankdir="LR", dpi=72, show_shapes=True)

png

model ini hanya berisi praproses input. Anda dapat menjalankannya untuk melihat apa yang dilakukannya pada data Anda. Model Keras tidak secara otomatis mengonversi Pandas DataFrames karena tidak jelas apakah harus dikonversi ke satu tensor atau ke kamus tensor. Jadi konversikan ke kamus tensor:

titanic_features_dict = {name: np.array(value) 
                         for name, value in titanic_features.items()}

Potong contoh pelatihan pertama dan teruskan ke model pemrosesan awal ini, Anda akan melihat fitur numerik dan string one-hots semuanya digabungkan bersama:

features_dict = {name:values[:1] for name, values in titanic_features_dict.items()}
titanic_preprocessing(features_dict)
<tf.Tensor: shape=(1, 33), dtype=float32, numpy=
array([[-0.61 ,  0.395, -0.479, -0.497,  0.   ,  0.   ,  0.   ,  1.   ,

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

Sekarang buat model di atas ini:

def titanic_model(preprocessing_head, inputs):
  body = tf.keras.Sequential([
    layers.Dense(64),
    layers.Dense(1)
  ])

  preprocessed_inputs = preprocessing_head(inputs)
  result = body(preprocessed_inputs)
  model = tf.keras.Model(inputs, result)

  model.compile(loss=tf.losses.BinaryCrossentropy(from_logits=True),
                optimizer=tf.optimizers.Adam())
  return model

titanic_model = titanic_model(titanic_preprocessing, inputs)

Saat Anda melatih model, teruskan kamus fitur sebagai x , dan label sebagai y .

titanic_model.fit(x=titanic_features_dict, y=titanic_labels, epochs=10)
Epoch 1/10
20/20 [==============================] - 0s 3ms/step - loss: 0.6595
Epoch 2/10
20/20 [==============================] - 0s 3ms/step - loss: 0.5576
Epoch 3/10
20/20 [==============================] - 0s 3ms/step - loss: 0.5002
Epoch 4/10
20/20 [==============================] - 0s 3ms/step - loss: 0.4719
Epoch 5/10
20/20 [==============================] - 0s 3ms/step - loss: 0.4533
Epoch 6/10
20/20 [==============================] - 0s 3ms/step - loss: 0.4415
Epoch 7/10
20/20 [==============================] - 0s 3ms/step - loss: 0.4346
Epoch 8/10
20/20 [==============================] - 0s 3ms/step - loss: 0.4299
Epoch 9/10
20/20 [==============================] - 0s 3ms/step - loss: 0.4285
Epoch 10/10
20/20 [==============================] - 0s 3ms/step - loss: 0.4261
<tensorflow.python.keras.callbacks.History at 0x7f3f74239b70>

Karena preprocessing adalah bagian dari model, Anda dapat menyimpan model dan memuatnya kembali di tempat lain dan mendapatkan hasil yang identik:

titanic_model.save('test')
reloaded = tf.keras.models.load_model('test')
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: test/assets
WARNING:tensorflow:5 out of the last 5 calls to <function recreate_function.<locals>.restored_function_body at 0x7f3f60030950> 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.
features_dict = {name:values[:1] for name, values in titanic_features_dict.items()}

before = titanic_model(features_dict)
after = reloaded(features_dict)
assert (before-after)<1e-3
print(before)
print(after)
tf.Tensor([[-1.903]], shape=(1, 1), dtype=float32)
tf.Tensor([[-1.903]], shape=(1, 1), dtype=float32)

Menggunakan tf.data

Di bagian sebelumnya, Anda mengandalkan pengacakan dan pengelompokan data bawaan model saat melatih model.

Jika Anda membutuhkan lebih banyak kontrol atas pipeline data input atau perlu menggunakan data yang tidak mudah masuk ke dalam memori: gunakan tf.data .

Untuk contoh lebih lanjut, lihat panduan tf.data .

Aktif di data memori

Sebagai contoh pertama penerapan tf.data ke data CSV pertimbangkan kode berikut untuk secara manual mengiris kamus fitur dari bagian sebelumnya. Untuk setiap indeks, dibutuhkan indeks tersebut untuk setiap fitur:

import itertools

def slices(features):
  for i in itertools.count():
    # For each feature take index `i`
    example = {name:values[i] for name, values in features.items()}
    yield example

Jalankan ini dan cetak contoh pertama:

for example in slices(titanic_features_dict):
  for name, value in example.items():
    print(f"{name:19s}: {value}")
  break
sex                : male
age                : 22.0
n_siblings_spouses : 1
parch              : 0
fare               : 7.25
class              : Third
deck               : unknown
embark_town        : Southampton
alone              : n

tf.data.Dataset paling dasar dalam pemuat data memori adalah konstruktor Dataset.from_tensor_slices . Ini mengembalikantf.data.Dataset yang mengimplementasikan versi umum dari fungsi slices atas, di TensorFlow.

features_ds = tf.data.Dataset.from_tensor_slices(titanic_features_dict)

Anda dapat melakukan iterasi melaluitf.data.Dataset seperti iterable python lainnya:

for example in features_ds:
  for name, value in example.items():
    print(f"{name:19s}: {value}")
  break
sex                : b'male'
age                : 22.0
n_siblings_spouses : 1
parch              : 0
fare               : 7.25
class              : b'Third'
deck               : b'unknown'
embark_town        : b'Southampton'
alone              : b'n'

Fungsi from_tensor_slices dapat menangani struktur apa pun dari kamus atau tupel bertingkat. Kode berikut membuat kumpulan data dari pasangan (features_dict, labels) :

titanic_ds = tf.data.Dataset.from_tensor_slices((titanic_features_dict, titanic_labels))

Untuk melatih model menggunakan Dataset ini, Anda setidaknya perlu shuffle dan batch data.

titanic_batches = titanic_ds.shuffle(len(titanic_labels)).batch(32)

Alih-alih meneruskan features dan labels ke Model.fit , Anda meneruskan Model.fit data:

titanic_model.fit(titanic_batches, epochs=5)
Epoch 1/5
20/20 [==============================] - 0s 4ms/step - loss: 0.4233
Epoch 2/5
20/20 [==============================] - 0s 4ms/step - loss: 0.4223
Epoch 3/5
20/20 [==============================] - 0s 4ms/step - loss: 0.4225
Epoch 4/5
20/20 [==============================] - 0s 4ms/step - loss: 0.4213
Epoch 5/5
20/20 [==============================] - 0s 4ms/step - loss: 0.4209
<tensorflow.python.keras.callbacks.History at 0x7f3f680cd9b0>

Dari satu file

Sejauh ini tutorial ini telah bekerja dengan data dalam memori. tf.data adalah toolkit yang sangat skalabel untuk membuat pipeline data, dan menyediakan beberapa fungsi untuk menangani pemuatan file CSV.

titanic_file_path = tf.keras.utils.get_file("train.csv", "https://storage.googleapis.com/tf-datasets/titanic/train.csv")
Downloading data from https://storage.googleapis.com/tf-datasets/titanic/train.csv
32768/30874 [===============================] - 0s 0us/step

Sekarang baca data CSV dari file dan buattf.data.Dataset .

(Untuk dokumentasi lengkap, lihat tf.data.experimental.make_csv_dataset )

titanic_csv_ds = tf.data.experimental.make_csv_dataset(
    titanic_file_path,
    batch_size=5, # Artificially small to make examples easier to show.
    label_name='survived',
    num_epochs=1,
    ignore_errors=True,)

Fungsi ini mencakup banyak fitur praktis sehingga data mudah digunakan. Ini termasuk:

  • Menggunakan tajuk kolom sebagai kunci kamus.
  • Secara otomatis menentukan jenis setiap kolom.
for batch, label in titanic_csv_ds.take(1):
  for key, value in batch.items():
    print(f"{key:20s}: {value}")
  print()
  print(f"{'label':20s}: {label}")
sex                 : [b'male' b'male' b'female' b'male' b'female']
age                 : [28. 11. 29. 28. 34.]
n_siblings_spouses  : [1 0 1 0 0]
parch               : [0 0 0 0 0]
fare                : [ 24.15   18.788  26.    221.779  10.5  ]
class               : [b'Third' b'Third' b'Second' b'First' b'Second']
deck                : [b'unknown' b'unknown' b'unknown' b'C' b'F']
embark_town         : [b'Queenstown' b'Cherbourg' b'Southampton' b'Southampton' b'Southampton']
alone               : [b'n' b'y' b'n' b'y' b'y']

label               : [0 0 1 0 1]

Itu juga dapat mendekompresi data dengan cepat. Berikut adalah file CSV dalam format gzip yang berisi set data lalu lintas antarnegara bagian metro

Macet.

Gambar dari Wikimedia

traffic_volume_csv_gz = tf.keras.utils.get_file(
    'Metro_Interstate_Traffic_Volume.csv.gz', 
    "https://archive.ics.uci.edu/ml/machine-learning-databases/00492/Metro_Interstate_Traffic_Volume.csv.gz",
    cache_dir='.', cache_subdir='traffic')
Downloading data from https://archive.ics.uci.edu/ml/machine-learning-databases/00492/Metro_Interstate_Traffic_Volume.csv.gz
409600/405373 [==============================] - 1s 2us/step

Mengatur compression_type argumen untuk membaca langsung dari file terkompresi:

traffic_volume_csv_gz_ds = tf.data.experimental.make_csv_dataset(
    traffic_volume_csv_gz,
    batch_size=256,
    label_name='traffic_volume',
    num_epochs=1,
    compression_type="GZIP")

for batch, label in traffic_volume_csv_gz_ds.take(1):
  for key, value in batch.items():
    print(f"{key:20s}: {value[:5]}")
  print()
  print(f"{'label':20s}: {label[:5]}")
holiday             : [b'None' b'None' b'None' b'None' b'None']
temp                : [280.66 283.22 284.23 280.7  287.79]
rain_1h             : [0. 0. 0. 0. 0.]
snow_1h             : [0. 0. 0. 0. 0.]
clouds_all          : [92 90 90 64 75]
weather_main        : [b'Mist' b'Drizzle' b'Rain' b'Clouds' b'Clouds']
weather_description : [b'mist' b'light intensity drizzle' b'light rain' b'broken clouds'
 b'broken clouds']
date_time           : [b'2012-10-19 21:00:00' b'2012-10-25 21:00:00' b'2013-05-23 16:00:00'
 b'2013-11-19 14:00:00' b'2013-05-16 08:00:00']

label               : [2942 2587 6305 5242 6404]

Caching

Ada beberapa overhead untuk mengurai data csv. Untuk model kecil, hal ini bisa menjadi penghambat dalam pelatihan.

Bergantung pada kasus penggunaan Anda, Dataset.cache gunakan Dataset.cache atau data.experimental.snapshot sehingga data csv hanya diurai pada epoch pertama.

Perbedaan utama antara metode cache dan snapshot adalah bahwa file cache hanya dapat digunakan oleh proses TensorFlow yang membuatnya, tetapi file snapshot dapat dibaca oleh proses lain.

Misalnya, traffic_volume_csv_gz_ds 20 kali, membutuhkan ~ 15 detik tanpa cache, atau ~ 2 detik dengan cache.

%%time
for i, (batch, label) in enumerate(traffic_volume_csv_gz_ds.repeat(20)):
  if i % 40 == 0:
    print('.', end='')
print()
...............................................................................................
CPU times: user 15.4 s, sys: 3.98 s, total: 19.4 s
Wall time: 12.4 s
%%time
caching = traffic_volume_csv_gz_ds.cache().shuffle(1000)

for i, (batch, label) in enumerate(caching.shuffle(1000).repeat(20)):
  if i % 40 == 0:
    print('.', end='')
print()
...............................................................................................
CPU times: user 1.48 s, sys: 179 ms, total: 1.65 s
Wall time: 1.32 s
%%time
snapshot = tf.data.experimental.snapshot('titanic.tfsnap')
snapshotting = traffic_volume_csv_gz_ds.apply(snapshot).shuffle(1000)

for i, (batch, label) in enumerate(snapshotting.shuffle(1000).repeat(20)):
  if i % 40 == 0:
    print('.', end='')
print()
...............................................................................................
CPU times: user 2.09 s, sys: 449 ms, total: 2.54 s
Wall time: 1.64 s

Jika pemuatan data Anda melambat karena memuat file csv, dan cache serta snapshot tidak mencukupi untuk kasus penggunaan Anda, pertimbangkan untuk mengenkode ulang data Anda ke dalam format yang lebih efisien.

Banyak file

Semua contoh sejauh ini di bagian ini dapat dengan mudah dilakukan tanpa tf.data . Satu tempat di mana tf.data benar-benar dapat menyederhanakan banyak hal adalah ketika menangani kumpulan file.

Misalnya, dataset gambar font karakter didistribusikan sebagai kumpulan file csv, satu per font.

Font

Gambar oleh Willi Heidelbach dari Pixabay

Unduh kumpulan data, dan lihat file di dalamnya:

fonts_zip = tf.keras.utils.get_file(
    'fonts.zip',  "https://archive.ics.uci.edu/ml/machine-learning-databases/00417/fonts.zip",
    cache_dir='.', cache_subdir='fonts',
    extract=True)
Downloading data from https://archive.ics.uci.edu/ml/machine-learning-databases/00417/fonts.zip
160317440/160313983 [==============================] - 8s 0us/step
import pathlib
font_csvs =  sorted(str(p) for p in pathlib.Path('fonts').glob("*.csv"))

font_csvs[:10]
['fonts/AGENCY.csv',
 'fonts/ARIAL.csv',
 'fonts/BAITI.csv',
 'fonts/BANKGOTHIC.csv',
 'fonts/BASKERVILLE.csv',
 'fonts/BAUHAUS.csv',
 'fonts/BELL.csv',
 'fonts/BERLIN.csv',
 'fonts/BERNARD.csv',
 'fonts/BITSTREAMVERA.csv']
len(font_csvs)
153

Saat menangani banyak file, Anda dapat meneruskan file_pattern bergaya glob ke fungsi experimental.make_csv_dataset . Urutan file diacak setiap iterasi.

Gunakan argumen num_parallel_reads untuk menyetel berapa banyak file yang dibaca secara paralel dan disisipkan bersama.

fonts_ds = tf.data.experimental.make_csv_dataset(
    file_pattern = "fonts/*.csv",
    batch_size=10, num_epochs=1,
    num_parallel_reads=20,
    shuffle_buffer_size=10000)

File csv ini memiliki gambar yang diratakan menjadi satu baris. Nama kolom diformat r{row}c{column} . Ini gelombang pertama:

for features in fonts_ds.take(1):
  for i, (name, value) in enumerate(features.items()):
    if i>15:
      break
    print(f"{name:20s}: {value}")
print('...')
print(f"[total: {len(features)} features]")
font                : [b'HARRINGTON' b'ISOC' b'GEORGIA' b'CAMBRIA' b'PROXY' b'SNAP'
 b'COUNTRYBLUEPRINT' b'PROXY' b'VIVALDI' b'GILL']
fontVariant         : [b'HARRINGTON' b'ISOCTEUR' b'GEORGIA' b'CAMBRIA' b'PROXY 9' b'SNAP ITC'
 b'COUNTRYBLUEPRINT' b'PROXY 9' b'VIVALDI'
 b'GILL SANS ULTRA BOLD CONDENSED']
m_label             : [   94  8800  8539 10659   305  8223  8217   728   170   115]
strength            : [0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4]
italic              : [0 0 0 0 1 0 0 1 0 0]
orientation         : [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
m_top               : [49 55 35 46 52 41 38 36 36 46]
m_left              : [22 33 24 22 27 23 24 40 27 21]
originalH           : [17 30 48 37 34 59 54  9 25 41]
originalW           : [30 21 62 39 12 34 25 24 27 26]
h                   : [20 20 20 20 20 20 20 20 20 20]
w                   : [20 20 20 20 20 20 20 20 20 20]
r0c0                : [  1   1   1   1   1 255 255 213   1   1]
r0c1                : [  1   1   3   1   1 255 255   1   1   1]
r0c2                : [  1   1  88   1   1 255 255   1   1   1]
r0c3                : [  1   1 232   1   1 255 255   1   1   1]
...
[total: 412 features]

Opsional: Bidang pengepakan

Anda mungkin tidak ingin bekerja dengan setiap piksel di kolom terpisah seperti ini. Sebelum mencoba menggunakan kumpulan data ini, pastikan untuk mengemas piksel ke dalam gambar-tensor.

Berikut adalah kode yang mengurai nama kolom untuk membuat gambar untuk setiap contoh:

import re

def make_images(features):
  image = [None]*400
  new_feats = {}

  for name, value in features.items():
    match = re.match('r(\d+)c(\d+)', name)
    if match:
      image[int(match.group(1))*20+int(match.group(2))] = value
    else:
      new_feats[name] = value

  image = tf.stack(image, axis=0)
  image = tf.reshape(image, [20, 20, -1])
  new_feats['image'] = image

  return new_feats

Terapkan fungsi itu ke setiap kumpulan dalam kumpulan data:

fonts_image_ds = fonts_ds.map(make_images)

for features in fonts_image_ds.take(1):
  break

Plot gambar yang dihasilkan:

from matplotlib import pyplot as plt

plt.figure(figsize=(6,6), dpi=120)

for n in range(9):
  plt.subplot(3,3,n+1)
  plt.imshow(features['image'][..., n])
  plt.title(chr(features['m_label'][n]))
  plt.axis('off')

png

Fungsi tingkat yang lebih rendah

Sejauh ini tutorial ini berfokus pada utilitas tingkat tertinggi untuk membaca data csv. Ada dua API lain yang mungkin berguna bagi pengguna tingkat lanjut jika kasus penggunaan Anda tidak sesuai dengan pola dasar.

Bagian ini membuat ulang fungsionalitas yang disediakan oleh make_csv_dataset , untuk mendemonstrasikan bagaimana fungsionalitas tingkat yang lebih rendah ini dapat digunakan.

tf.io.decode_csv

Fungsi ini menerjemahkan string, atau daftar string ke dalam daftar kolom.

Tidak seperti make_csv_dataset , fungsi ini tidak mencoba menebak tipe data kolom. Anda menentukan tipe kolom dengan memberikan daftar record_defaults berisi nilai tipe yang benar, untuk setiap kolom.

Untuk membaca data Titanic sebagai string menggunakan decode_csv Anda akan mengatakan:

text = pathlib.Path(titanic_file_path).read_text()
lines = text.split('\n')[1:-1]

all_strings = [str()]*10
all_strings
['', '', '', '', '', '', '', '', '', '']
features = tf.io.decode_csv(lines, record_defaults=all_strings) 

for f in features:
  print(f"type: {f.dtype.name}, shape: {f.shape}")
type: string, shape: (627,)
type: string, shape: (627,)
type: string, shape: (627,)
type: string, shape: (627,)
type: string, shape: (627,)
type: string, shape: (627,)
type: string, shape: (627,)
type: string, shape: (627,)
type: string, shape: (627,)
type: string, shape: (627,)

Untuk menguraikannya dengan tipe sebenarnya, buat daftar record_defaults dari tipe yang sesuai:

print(lines[0])
0,male,22.0,1,0,7.25,Third,unknown,Southampton,n
titanic_types = [int(), str(), float(), int(), int(), float(), str(), str(), str(), str()]
titanic_types
[0, '', 0.0, 0, 0, 0.0, '', '', '', '']
features = tf.io.decode_csv(lines, record_defaults=titanic_types) 

for f in features:
  print(f"type: {f.dtype.name}, shape: {f.shape}")
type: int32, shape: (627,)
type: string, shape: (627,)
type: float32, shape: (627,)
type: int32, shape: (627,)
type: int32, shape: (627,)
type: float32, shape: (627,)
type: string, shape: (627,)
type: string, shape: (627,)
type: string, shape: (627,)
type: string, shape: (627,)

tf.data.experimental.CsvDataset

Kelas tf.data.experimental.CsvDataset menyediakan antarmuka tf.data.experimental.CsvDataset Dataset CSV minimal tanpa fitur kemudahan fungsi make_csv_dataset : penguraian header kolom, inferensi jenis kolom, pengacakan otomatis, penyisipan file.

Konstruktor berikut menggunakan record_defaults dengan cara yang sama seperti io.parse_csv :

simple_titanic = tf.data.experimental.CsvDataset(titanic_file_path, record_defaults=titanic_types, header=True)

for example in simple_titanic.take(1):
  print([e.numpy() for e in example])
[0, b'male', 22.0, 1, 0, 7.25, b'Third', b'unknown', b'Southampton', b'n']

Kode di atas pada dasarnya sama dengan:

def decode_titanic_line(line):
  return tf.io.decode_csv(line, titanic_types)

manual_titanic = (
    # Load the lines of text
    tf.data.TextLineDataset(titanic_file_path)
    # Skip the header row.
    .skip(1)
    # Decode the line.
    .map(decode_titanic_line)
)

for example in manual_titanic.take(1):
  print([e.numpy() for e in example])
[0, b'male', 22.0, 1, 0, 7.25, b'Third', b'unknown', b'Southampton', b'n']

Banyak file

Untuk mengurai set data font menggunakan experimental.CsvDataset , Anda harus menentukan jenis kolom untuk record_defaults . Mulailah dengan memeriksa baris pertama dari satu file:

font_line = pathlib.Path(font_csvs[0]).read_text().splitlines()[1]
print(font_line)
AGENCY,AGENCY FB,64258,0.400000,0,0.000000,35,21,51,22,20,20,1,1,1,21,101,210,255,255,255,255,255,255,255,255,255,255,255,255,255,255,1,1,1,93,255,255,255,176,146,146,146,146,146,146,146,146,216,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,141,141,141,182,255,255,255,172,141,141,141,115,1,1,1,1,163,255,255,255,255,255,255,255,255,255,255,255,255,255,255,209,1,1,1,1,163,255,255,255,6,6,6,96,255,255,255,74,6,6,6,5,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255

Hanya dua kolom pertama yang merupakan string, sisanya adalah int atau float, dan Anda bisa mendapatkan jumlah fitur dengan menghitung koma:

num_font_features = font_line.count(',')+1
font_column_types = [str(), str()] + [float()]*(num_font_features-2)

Konstruktor CsvDatasaet dapat mengambil daftar file input, tetapi membacanya secara berurutan. File pertama dalam daftar CSV adalah AGENCY.csv :

font_csvs[0]
'fonts/AGENCY.csv'

Jadi, ketika Anda meneruskan daftar file ke CsvDataaset , catatan dari AGENCY.csv dibaca terlebih dahulu:

simple_font_ds = tf.data.experimental.CsvDataset(
    font_csvs, 
    record_defaults=font_column_types, 
    header=True)
for row in simple_font_ds.take(10):
  print(row[0].numpy())
b'AGENCY'
b'AGENCY'
b'AGENCY'
b'AGENCY'
b'AGENCY'
b'AGENCY'
b'AGENCY'
b'AGENCY'
b'AGENCY'
b'AGENCY'

Untuk Dataset.interleave banyak file, gunakan Dataset.interleave .

Berikut kumpulan data awal yang berisi nama file csv:

font_files = tf.data.Dataset.list_files("fonts/*.csv")

Ini mengocok nama file setiap periode:

print('Epoch 1:')
for f in list(font_files)[:5]:
  print("    ", f.numpy())
print('    ...')
print()

print('Epoch 2:')
for f in list(font_files)[:5]:
  print("    ", f.numpy())
print('    ...')
Epoch 1:
     b'fonts/ELEPHANT.csv'
     b'fonts/NINA.csv'
     b'fonts/COPPERPLATE.csv'
     b'fonts/GOTHICE.csv'
     b'fonts/SWIS721.csv'
    ...

Epoch 2:
     b'fonts/PALACE.csv'
     b'fonts/GABRIOLA.csv'
     b'fonts/COURIER.csv'
     b'fonts/CONSTANTIA.csv'
     b'fonts/QUICKTYPE.csv'
    ...

The interleave Metode mengambil map_func yang menciptakan anak- Dataset untuk setiap elemen dari orangtua- Dataset .

Di sini, Anda ingin membuat CsvDataset dari setiap elemen kumpulan data file:

def make_font_csv_ds(path):
  return tf.data.experimental.CsvDataset(
    path, 
    record_defaults=font_column_types, 
    header=True)

Set Dataset dikembalikan oleh elemen pengembalian interleave dengan beralih ke sejumlah anak- Dataset . Perhatikan, di bawah ini, bagaimana siklus cycle_length)=3 data selama cycle_length)=3 tiga file font:

font_rows = font_files.interleave(make_font_csv_ds,
                                  cycle_length=3)
fonts_dict = {'font_name':[], 'character':[]}

for row in font_rows.take(10):
  fonts_dict['font_name'].append(row[0].numpy().decode())
  fonts_dict['character'].append(chr(row[2].numpy()))

pd.DataFrame(fonts_dict)

Performa

Sebelumnya, telah dicatat bahwa io.decode_csv lebih efisien ketika dijalankan pada sekumpulan string.

Hal ini dimungkinkan untuk memanfaatkan fakta ini, saat menggunakan ukuran tumpukan besar, untuk meningkatkan kinerja pemuatan CSV (tapi coba caching dulu).

Dengan pemuat internal 20, kumpulan contoh 2048 membutuhkan waktu sekitar 17 detik.

BATCH_SIZE=2048
fonts_ds = tf.data.experimental.make_csv_dataset(
    file_pattern = "fonts/*.csv",
    batch_size=BATCH_SIZE, num_epochs=1,
    num_parallel_reads=100)
%%time
for i,batch in enumerate(fonts_ds.take(20)):
  print('.',end='')

print()
....................
CPU times: user 28.9 s, sys: 2.76 s, total: 31.7 s
Wall time: 11.7 s

Meneruskan kumpulan baris teks ke decode_csv berjalan lebih cepat, dalam waktu sekitar 5 decode_csv :

fonts_files = tf.data.Dataset.list_files("fonts/*.csv")
fonts_lines = fonts_files.interleave(
    lambda fname:tf.data.TextLineDataset(fname).skip(1), 
    cycle_length=100).batch(BATCH_SIZE)

fonts_fast = fonts_lines.map(lambda x: tf.io.decode_csv(x, record_defaults=font_column_types))
%%time
for i,batch in enumerate(fonts_fast.take(20)):
  print('.',end='')

print()
....................
CPU times: user 5.4 s, sys: 0 ns, total: 5.4 s
Wall time: 4.84 s

Untuk contoh lain tentang meningkatkan performa csv dengan menggunakan batch besar, lihat tutorial overfit dan underfit .

Pendekatan semacam ini mungkin berhasil, tetapi pertimbangkan opsi lain seperti cache dan snapshot , atau enkode ulang data Anda ke format yang lebih efisien.