يوم مجتمع ML هو 9 نوفمبر! الانضمام إلينا للحصول على التحديثات من TensorFlow، JAX، وأكثر معرفة المزيد

تحميل بيانات CSV

عرض على TensorFlow.org تشغيل في Google Colab عرض المصدر على جيثبتحميل دفتر

يقدم هذا البرنامج التعليمي أمثلة على كيفية استخدام بيانات CSV مع TensorFlow.

هناك جزئين رئيسيين لهذا:

  1. تحميل البيانات من القرص
  2. معالجتها مسبقًا في شكل مناسب للتدريب.

يركز هذا البرنامج التعليمي على التحميل ، ويقدم بعض الأمثلة السريعة للمعالجة المسبقة. لالبرنامج التعليمي الذي يركز على الجانب تجهيزها ترى تجهيزها دليل طبقات و التعليمي .

اقامة

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

في بيانات الذاكرة

بالنسبة لأي مجموعة بيانات CSV صغيرة ، فإن أبسط طريقة لتدريب نموذج TensorFlow عليها هي تحميلها في الذاكرة كإطار بيانات الباندا أو مصفوفة NumPy.

وهناك مثال بسيط نسبيا هو مجموعة البيانات أذن البحر .

  • مجموعة البيانات صغيرة.
  • جميع ميزات الإدخال جميعها عبارة عن قيم فاصلة عائمة ذات نطاق محدود.

هنا هو كيفية تحميل البيانات إلى الباندا 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()

يحتوي على بيانات مجموعة من القياسات من أذن البحر ، وهو نوع من القواقع البحرية.

صدفة أذن البحر

"أذن البحر قذيفة" (عن طريق نيكي دوغان بوج ، CC BY-SA 2.0)

تتمثل المهمة الاسمية لمجموعة البيانات هذه في التنبؤ بالعمر من القياسات الأخرى ، لذلك افصل الميزات والتسميات للتدريب:

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

بالنسبة لمجموعة البيانات هذه ، ستتعامل مع جميع الميزات بشكل متماثل. قم بتجميع الميزات في مصفوفة 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 ]])

بعد ذلك ، اجعل نموذج الانحدار يتنبأ بالعمر. لأنه ليس هناك سوى موتر مدخل واحد، وهو keras.Sequential نموذج يكفي هنا.

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

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

لتدريب هذا النموذج، لتمرير السمات والعلامات ل Model.fit :

abalone_model.fit(abalone_features, abalone_labels, epochs=10)
Epoch 1/10
104/104 [==============================] - 1s 2ms/step - loss: 68.1297
Epoch 2/10
104/104 [==============================] - 0s 2ms/step - loss: 13.3981
Epoch 3/10
104/104 [==============================] - 0s 1ms/step - loss: 8.9458
Epoch 4/10
104/104 [==============================] - 0s 1ms/step - loss: 8.3894
Epoch 5/10
104/104 [==============================] - 0s 1ms/step - loss: 7.8835
Epoch 6/10
104/104 [==============================] - 0s 1ms/step - loss: 7.4897
Epoch 7/10
104/104 [==============================] - 0s 1ms/step - loss: 7.1716
Epoch 8/10
104/104 [==============================] - 0s 1ms/step - loss: 6.9468
Epoch 9/10
104/104 [==============================] - 0s 1ms/step - loss: 6.7714
Epoch 10/10
104/104 [==============================] - 0s 1ms/step - loss: 6.6458
<tensorflow.python.keras.callbacks.History at 0x7f7bf0178110>

لقد رأيت للتو الطريقة الأساسية لتدريب نموذج باستخدام بيانات CSV. بعد ذلك ، ستتعلم كيفية تطبيق المعالجة المسبقة لتسوية الأعمدة الرقمية.

المعالجة الأولية الأساسية

إنها ممارسة جيدة لتطبيع المدخلات في النموذج الخاص بك. و experimental.preprocessing توفر طبقات وسيلة مريحة لبناء هذا التطبيع في النموذج الخاص بك.

ستحسب الطبقة مسبقًا المتوسط ​​والتباين لكل عمود ، وتستخدمهما لتسوية البيانات.

تقوم أولاً بإنشاء الطبقة:

normalize = preprocessing.Normalization()

ثم استخدام Normalization.adapt() طريقة للتكيف الطبقة التطبيع إلى البيانات الخاصة بك.

normalize.adapt(abalone_features)

ثم استخدم طبقة التسوية في نموذجك:

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: 91.9882
Epoch 2/10
104/104 [==============================] - 0s 2ms/step - loss: 52.3517
Epoch 3/10
104/104 [==============================] - 0s 1ms/step - loss: 16.0901
Epoch 4/10
104/104 [==============================] - 0s 1ms/step - loss: 5.8372
Epoch 5/10
104/104 [==============================] - 0s 1ms/step - loss: 5.0929
Epoch 6/10
104/104 [==============================] - 0s 2ms/step - loss: 5.0442
Epoch 7/10
104/104 [==============================] - 0s 1ms/step - loss: 5.0062
Epoch 8/10
104/104 [==============================] - 0s 1ms/step - loss: 4.9882
Epoch 9/10
104/104 [==============================] - 0s 2ms/step - loss: 4.9629
Epoch 10/10
104/104 [==============================] - 0s 2ms/step - loss: 4.9666
<tensorflow.python.keras.callbacks.History at 0x7f7be008f910>

أنواع البيانات المختلطة

تحتوي مجموعة البيانات "تايتانيك" على معلومات حول ركاب تيتانيك. المهمة الاسمية في مجموعة البيانات هذه هي التنبؤ بمن نجا.

سفينة التايتنك

الصورة من ويكيميديا

يمكن بسهولة أن يتم تحميل البيانات الخام باعتباره الباندا DataFrame ، ولكن ليست صالحة للاستعمال فورا كمدخل لنموذج 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')

بسبب أنواع مختلفة من البيانات ونطاقات لا يمكنك ببساطة كومة من الميزات في نمباي مجموعة وتمريرها إلى keras.Sequential نموذج. يجب التعامل مع كل عمود على حدة.

كخيار واحد ، يمكنك معالجة بياناتك مسبقًا دون اتصال بالإنترنت (باستخدام أي أداة تريدها) لتحويل الأعمدة الفئوية إلى أعمدة رقمية ، ثم تمرير الإخراج المعالج إلى نموذج TensorFlow الخاص بك. عيب هذا النهج هو أنه إذا قمت بحفظ النموذج الخاص بك وتصديره ، فلن يتم حفظ المعالجة المسبقة به. و experimental.preprocessing طبقات تجنب هذه المشكلة لأنهم جزء من هذا النموذج.

في هذا المثال، عليك بناء نموذج التي تنفذ منطق تجهيزها باستخدام Keras API وظيفية . يمكنك أيضا القيام بذلك عن طريق إن شاء subclasses ترث .

تعمل واجهة برمجة التطبيقات الوظيفية على موترات "رمزية". موترات عادية "حريصة" لها قيمة. على النقيض من ذلك ، فإن هذه الموترات "الرمزية" لا تفعل ذلك. بدلاً من ذلك ، يتتبعون العمليات التي يتم إجراؤها عليهم ، ويبنون تمثيلاً للحساب ، بحيث يمكنك تشغيله لاحقًا. إليك مثال سريع:

# 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
<KerasTensor: shape=(None,) dtype=float32 (created by layer 'tf.__operators__.add')>
calc = tf.keras.Model(inputs=input, outputs=result)
print(calc(1).numpy())
print(calc(2).numpy())
3.0
5.0

لبناء نموذج تجهيزها، تبدأ من خلال بناء مجموعة من رمزية keras.Input الأشياء، ومطابقة أسماء وأنواع البيانات من الأعمدة 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': <KerasTensor: shape=(None, 1) dtype=string (created by layer 'sex')>,
 'age': <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'age')>,
 'n_siblings_spouses': <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'n_siblings_spouses')>,
 'parch': <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'parch')>,
 'fare': <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'fare')>,
 'class': <KerasTensor: shape=(None, 1) dtype=string (created by layer 'class')>,
 'deck': <KerasTensor: shape=(None, 1) dtype=string (created by layer 'deck')>,
 'embark_town': <KerasTensor: shape=(None, 1) dtype=string (created by layer 'embark_town')>,
 'alone': <KerasTensor: shape=(None, 1) dtype=string (created by layer 'alone')>}

تتمثل الخطوة الأولى في منطق المعالجة المسبقة في تجميع المدخلات الرقمية معًا وتشغيلها عبر طبقة تسوية:

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
<KerasTensor: shape=(None, 4) dtype=float32 (created by layer 'normalization_1')>

اجمع كل نتائج المعالجة المسبقة الرمزية ، لتسلسلها لاحقًا.

preprocessed_inputs = [all_numeric_inputs]

لسلسلة المدخلات استخدام preprocessing.StringLookup وظيفة لتعيين من السلاسل إلى مؤشرات صحيح في المفردات. بعد ذلك، استخدام preprocessing.CategoryEncoding لتحويل الفهارس في float32 مناسبا البيانات للنموذج.

الإعدادات الافتراضية ل preprocessing.CategoryEncoding طبقة خلق متجه واحد حار لكل المدخلات. A layers.Embedding من شأنه أيضا أن يعمل. رؤية تجهيزها دليل طبقات و البرنامج التعليمي لمعرفة المزيد عن هذا الموضوع.

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)
WARNING:tensorflow:vocab_size is deprecated, please use vocabulary_size.
WARNING:tensorflow:max_tokens is deprecated, please use num_tokens instead.
WARNING:tensorflow:vocab_size is deprecated, please use vocabulary_size.
WARNING:tensorflow:max_tokens is deprecated, please use num_tokens instead.
WARNING:tensorflow:vocab_size is deprecated, please use vocabulary_size.
WARNING:tensorflow:max_tokens is deprecated, please use num_tokens instead.
WARNING:tensorflow:vocab_size is deprecated, please use vocabulary_size.
WARNING:tensorflow:max_tokens is deprecated, please use num_tokens instead.
WARNING:tensorflow:vocab_size is deprecated, please use vocabulary_size.
WARNING:tensorflow:max_tokens is deprecated, please use num_tokens instead.

مع مجموعة من inputs و processed_inputs ، يمكن لسلسلة جميع المدخلات preprocessed معا، وبناء نموذج الذي يعالج في تجهيزها:

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)

بي إن جي

هذا model يحتوي فقط على تجهيزها الإدخال. يمكنك تشغيله لمعرفة ما يفعله ببياناتك. نماذج Keras لا تلقائيا تحويل الباندا DataFrames لأنه ليس من الواضح ما إذا كان يجب تحويلها إلى موتر واحد أو إلى القاموس من التنسورات. لذا قم بتحويله إلى قاموس موترات:

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

قم بتقطيع المثال التدريبي الأول وقم بتمريره إلى نموذج المعالجة المسبقة هذا ، سترى الميزات الرقمية وسلسلة التسخين الأول متسلسلة معًا:

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

الآن قم ببناء النموذج فوق هذا:

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)

عند تدريب نموذج، لتمرير القاموس من الميزات كما x ، والتسمية كما y .

titanic_model.fit(x=titanic_features_dict, y=titanic_labels, epochs=10)
Epoch 1/10
20/20 [==============================] - 1s 3ms/step - loss: 0.5665
Epoch 2/10
20/20 [==============================] - 0s 3ms/step - loss: 0.4980
Epoch 3/10
20/20 [==============================] - 0s 3ms/step - loss: 0.4643
Epoch 4/10
20/20 [==============================] - 0s 3ms/step - loss: 0.4463
Epoch 5/10
20/20 [==============================] - 0s 3ms/step - loss: 0.4333
Epoch 6/10
20/20 [==============================] - 0s 3ms/step - loss: 0.4297
Epoch 7/10
20/20 [==============================] - 0s 3ms/step - loss: 0.4252
Epoch 8/10
20/20 [==============================] - 0s 4ms/step - loss: 0.4234
Epoch 9/10
20/20 [==============================] - 0s 4ms/step - loss: 0.4213
Epoch 10/10
20/20 [==============================] - 0s 4ms/step - loss: 0.4202
<tensorflow.python.keras.callbacks.History at 0x7f7c8ff43510>

نظرًا لأن المعالجة المسبقة جزء من النموذج ، يمكنك حفظ النموذج وإعادة تحميله في مكان آخر والحصول على نتائج متطابقة:

titanic_model.save('test')
reloaded = tf.keras.models.load_model('test')
INFO:tensorflow:Assets written to: test/assets
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.843]], shape=(1, 1), dtype=float32)
tf.Tensor([[-1.843]], shape=(1, 1), dtype=float32)

باستخدام tf.data

في القسم السابق ، اعتمدت على خلط البيانات المضمنة في النموذج وتجميعها أثناء تدريب النموذج.

إذا كنت بحاجة إلى المزيد من السيطرة على خط أنابيب إدخال البيانات أو الحاجة إلى استخدام البيانات التي لا تناسب بسهولة في الذاكرة: استخدام tf.data .

لمزيد من الأمثلة انظر دليل tf.data .

تشغيل في بيانات الذاكرة

وكمثال أول تطبيق tf.data لبيانات CSV النظر في التعليمات البرمجية التالية إلى شريحة يدويا القاموس من الميزات من المقطع السابق. لكل فهرس ، يأخذ هذا الفهرس لكل ميزة:

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

قم بتشغيل هذا واطبع المثال الأول:

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 في تحميل بيانات الذاكرة هو Dataset.from_tensor_slices المنشئ. هذا عائدات tf.data.Dataset أن تنفذ نسخة معممة من أعلاه slices وظيفة، في TensorFlow.

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

يمكنك تكرار أكثر من tf.data.Dataset مثل أي الثعبان الآخر iterable:

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'

و from_tensor_slices وظيفة يمكن التعامل مع أي هيكل من القواميس متداخلة أو الصفوف. التعليمة البرمجية التالية يجعل مجموعة بيانات (features_dict, labels) أزواج:

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

لتدريب النموذج باستخدام هذه Dataset ، سوف تحتاج إلى ما لا يقل عن shuffle و batch من البيانات.

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

بدلا من تمرير features و labels ل Model.fit ، يمكنك تمرير ورقة العمل:

titanic_model.fit(titanic_batches, epochs=5)
Epoch 1/5
20/20 [==============================] - 0s 4ms/step - loss: 0.4199
Epoch 2/5
20/20 [==============================] - 0s 4ms/step - loss: 0.4199
Epoch 3/5
20/20 [==============================] - 0s 4ms/step - loss: 0.4192
Epoch 4/5
20/20 [==============================] - 0s 4ms/step - loss: 0.4189
Epoch 5/5
20/20 [==============================] - 0s 4ms/step - loss: 0.4185
<tensorflow.python.keras.callbacks.History at 0x7f7c8e8ee810>

من ملف واحد

لقد عمل هذا البرنامج التعليمي حتى الآن مع البيانات الموجودة في الذاكرة. tf.data عبارة عن مجموعة أدوات تدرجية عالية لبناء خطوط أنابيب البيانات، ويوفر عدد قليل من الوظائف للتعامل ملفات 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

الآن قراءة البيانات CSV من الملفات وإنشاء tf.data.Dataset .

(للاطلاع على الوثائق الكاملة، انظر 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,)

تتضمن هذه الوظيفة العديد من الميزات المريحة بحيث يسهل التعامل مع البيانات. هذا يشمل:

  • استخدام رؤوس الأعمدة كمفاتيح القاموس.
  • تحديد نوع كل عمود تلقائيًا.
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'female' b'male' b'male' b'male']
age                 : [28. 28. 70.  1. 28.]
n_siblings_spouses  : [1 0 1 5 1]
parch               : [0 0 1 2 0]
fare                : [82.171  7.225 71.    46.9   15.85 ]
class               : [b'First' b'Third' b'First' b'Third' b'Third']
deck                : [b'unknown' b'unknown' b'B' b'unknown' b'unknown']
embark_town         : [b'Cherbourg' b'Cherbourg' b'Southampton' b'Southampton' b'Southampton']
alone               : [b'n' b'y' b'n' b'n' b'n']

label               : [0 1 0 0 0]

يمكنه أيضًا فك ضغط البيانات أثناء التنقل. وهنا ملف CSV مضغوط بطريقة gzip تحتوي على المترو بيانات حركة المرور بين الدول

ازدحام مروري.

الصورة من ويكيميديا

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

تعيين compression_type حجة لقراءة مباشرة من ملف مضغوط:

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                : [275.36 264.13 265.53 278.63 289.91]
rain_1h             : [0.   0.   0.   0.   1.52]
snow_1h             : [0. 0. 0. 0. 0.]
clouds_all          : [90 90 75 90 80]
weather_main        : [b'Rain' b'Clouds' b'Clouds' b'Rain' b'Mist']
weather_description : [b'light rain' b'overcast clouds' b'broken clouds' b'light rain' b'mist']
date_time           : [b'2013-03-10 19:00:00' b'2013-01-02 19:00:00' b'2012-12-06 06:00:00'
 b'2013-04-25 18:00:00' b'2013-07-31 04:00:00']

label               : [2743 2687 5545 5020  822]

التخزين المؤقت

يوجد بعض الحمل الزائد لتحليل بيانات csv. بالنسبة للنماذج الصغيرة ، يمكن أن يكون هذا هو عنق الزجاجة في التدريب.

تبعا لحالة استخدامك قد يكون فكرة جيدة لاستخدام Dataset.cache أو data.experimental.snapshot بحيث البيانات CSV يتم تحليل فقط على العصر الأول.

والفرق الرئيسي بين cache و snapshot الطرق هو أن cache ملفات يمكن استخدامها إلا عن طريق عملية TensorFlow التي خلقت لهم، ولكن snapshot ملفات يمكن قراءتها من قبل عمليات أخرى.

على سبيل المثال، بالتكرار عبر traffic_volume_csv_gz_ds 20 مرة، يأخذ ~ 15 ثانية من دون التخزين المؤقت، أو ~ 2S مع التخزين المؤقت.

%%time
for i, (batch, label) in enumerate(traffic_volume_csv_gz_ds.repeat(20)):
  if i % 40 == 0:
    print('.', end='')
print()
...............................................................................................
CPU times: user 14.9 s, sys: 3.58 s, total: 18.5 s
Wall time: 11 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.42 s, sys: 115 ms, total: 1.53 s
Wall time: 1.22 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.26 s, sys: 431 ms, total: 2.69 s
Wall time: 1.62 s

إذا تباطأ تحميل البيانات عن طريق ملفات CSV تحميل، و cache و snapshot غير كافية لحالة استخدامك، والنظر في إعادة ترميز البيانات الخاصة بك في شكل أكثر تنظيما.

ملفات متعددة

يمكن بسهولة أن تتم جميع الأمثلة حتى الآن في هذا القسم دون tf.data . مكان واحد حيث tf.data يمكن تبسيط الأمور حقا هو عند التعامل مع مجموعات من الملفات.

على سبيل المثال، صور خط الأحرف بيانات يتم توزيعها كمجموعة من ملفات CSV، واحد في الخط.

الخطوط

الصورة عن طريق ويلي Heidelbach من Pixabay

قم بتنزيل مجموعة البيانات ، وإلقاء نظرة على الملفات الموجودة بداخلها:

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

عند التعامل مع مجموعة من الملفات التي يمكن أن تمر على غرار غلوب file_pattern إلى experimental.make_csv_dataset وظيفة. يتم ترتيب الملفات عشوائيًا في كل تكرار.

استخدام num_parallel_reads حجة لمجموعة كيفية قراءة العديد من الملفات في نفس الوقت ومعشق معا.

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)

تحتوي ملفات csv هذه على الصور مسطحة في صف واحد. يتم تنسيق أسماء الأعمدة r{row}c{column} . ها هي الدفعة الأولى:

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'GLOUCESTER' b'REFERENCE' b'TREBUCHET' b'MONEY' b'GLOUCESTER' b'MONEY'
 b'GLOUCESTER' b'JUICE' b'CAMBRIA' b'BRUSH']
fontVariant         : [b'GLOUCESTER MT EXTRA CONDENSED' b'MS REFERENCE SANS SERIF'
 b'TREBUCHET MS' b'scanned' b'GLOUCESTER MT EXTRA CONDENSED' b'scanned'
 b'GLOUCESTER MT EXTRA CONDENSED' b'JUICE ITC' b'CAMBRIA'
 b'BRUSH SCRIPT MT']
m_label             : [  116 63521   507    53   402    54  8747   213 10766  8776]
strength            : [0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4]
italic              : [1 0 0 0 0 0 0 1 0 1]
orientation         : [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
m_top               : [41 21 23  0 31  0 22 20 25 44]
m_left              : [25 26 23  0 15  0 20 27 23 24]
originalH           : [42 68 64 32 63 27 68 61 73 25]
originalW           : [18 30 30 19 22 16 18 33 32 36]
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 1 1 1 1 1]
r0c1                : [ 1  1  1 91  1  1  1  1  1  1]
r0c2                : [  1   1   1 239   1   1   1   1   1  40]
r0c3                : [  1   1   1 255   1   1   1   1   1  74]
...
[total: 412 features]

اختياري: حقول التعبئة

ربما لا ترغب في العمل مع كل بكسل في أعمدة منفصلة مثل هذه. قبل محاولة استخدام مجموعة البيانات هذه ، تأكد من حزم وحدات البكسل في موتر الصورة.

إليك رمز يوزع أسماء الأعمدة لإنشاء صور لكل مثال:

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

طبق هذه الوظيفة على كل دفعة في مجموعة البيانات:

fonts_image_ds = fonts_ds.map(make_images)

for features in fonts_image_ds.take(1):
  break

ارسم الصور الناتجة:

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

بي إن جي

وظائف المستوى الأدنى

حتى الآن ، ركز هذا البرنامج التعليمي على أعلى مستوى من الأدوات المساعدة لقراءة بيانات csv. هناك نوعان من واجهات برمجة التطبيقات الأخرى التي قد تكون مفيدة للمستخدمين المتقدمين إذا كانت حالة الاستخدام الخاصة بك لا تتناسب مع الأنماط الأساسية.

هذه الوظيفة القسم يعيد تكوين المقدمة من make_csv_dataset ، لشرح كيفية هذه الوظيفة المستوى الأدنى يمكن استخدامها.

tf.io.decode_csv

تقوم هذه الوظيفة بفك تشفير سلسلة أو قائمة سلاسل في قائمة أعمدة.

على عكس make_csv_dataset هذه الوظيفة لا تحاول تخمين أنواع البيانات عمود. تحديد أنواع الأعمدة من خلال توفير قائمة من record_defaults تحتوي على قيمة من النوع الصحيح، لكل عمود.

لقراءة البيانات تيتانيك كسلاسل باستخدام decode_csv أن أقول لكم:

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

تحليل لهم أنواعها الفعلية، وإنشاء قائمة record_defaults أنواع المقابلة:

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

و tf.data.experimental.CsvDataset توفر الحد الأدنى من الدرجة في CSV Dataset اجهة دون مزايا الراحة من make_csv_dataset وظيفة: رأس العمود التوزيع، العمود نوع الاستدلال، خلط التلقائي، ملف التداخل.

هذا المنشئ يتبع الاستخدامات record_defaults بنفس طريقة 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']

الكود أعلاه يعادل في الأساس:

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

ملفات متعددة

تحليل الخطوط بيانات باستخدام experimental.CsvDataset ، تحتاج أولا إلى تحديد أنواع الأعمدة ل record_defaults . ابدأ بفحص الصف الأول من ملف واحد:

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

أول حقلين فقط عبارة عن سلاسل ، والباقي عبارة عن ints أو عائم ، ويمكنك الحصول على العدد الإجمالي للعناصر من خلال حساب الفواصل:

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

و CsvDatasaet منشئ يمكن أن قائمة ملفات الإدخال، ولكن يقرأ لهم بالتتابع. الملف الأول في قائمة ملفات CSV هو AGENCY.csv :

font_csvs[0]
'fonts/AGENCY.csv'

وذلك عند تمرير تمرير قائمة الملفات ل CsvDataaset السجلات من AGENCY.csv تقرأ أولا:

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'

لتعشيق ملفات متعددة، استخدم Dataset.interleave .

فيما يلي مجموعة بيانات أولية تحتوي على أسماء ملفات csv:

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

يؤدي هذا إلى خلط أسماء الملفات في كل فترة:

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/BROADWAY.csv'
     b'fonts/COPPERPLATE.csv'
     b'fonts/STENCIL.csv'
     b'fonts/COOPER.csv'
     b'fonts/GABRIOLA.csv'
    ...

Epoch 2:
     b'fonts/MONOSPAC821.csv'
     b'fonts/ONYX.csv'
     b'fonts/HARLOW.csv'
     b'fonts/TIMES.csv'
     b'fonts/JOKERMAN.csv'
    ...

و interleave يأخذ الأسلوب map_func أن يخلق يرعى الطفل Dataset لكل عنصر من الآباء و Dataset .

هنا، تريد إنشاء CsvDataset من كل عنصر من مجموعة البيانات من الملفات:

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

و Dataset إرجاعها من قبل عناصر عوائد تعشيق من قبل ركوب الدراجات على مدى عدد من بالأطفال Dataset الصورة. ملاحظة أدناه، كيف دورات بيانات على cycle_length)=3 ثلاثة ملفات الخط:

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)

أداء

في وقت سابق، لوحظ أن io.decode_csv هو أكثر كفاءة عند تشغيل على مجموعة من السلاسل.

ومن الممكن الاستفادة من هذه الحقيقة، عند استخدام أحجام دفعة كبيرة لتحسين أداء تحميل CSV (ولكن في محاولة التخزين المؤقت أولا).

مع اللودر المدمج 20 ، 2048 مثال للدفعات يستغرق حوالي 17 ثانية.

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 26.8 s, sys: 1.75 s, total: 28.6 s
Wall time: 11.1 s

يمر دفعات من خطوط النص إلى decode_csv يعمل بشكل أسرع، في نحو 5S:

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 9.29 s, sys: 0 ns, total: 9.29 s
Wall time: 1.48 s

على سبيل المثال أخرى لزيادة أداء CSV باستخدام دفعات كبيرة رؤية overfit والتعليمي underfit .

هذا النوع من النهج قد عمل، ولكن تنظر في خيارات أخرى مثل cache و snapshot ، أو إعادة enncoding البيانات إلى تنسيق أكثر مبسطة.