TFRecord و tf.train مثال

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

تنسيق TFRecord هو تنسيق بسيط لتخزين سلسلة من السجلات الثنائية.

مخازن البروتوكول هي مكتبة متعددة المنصات ومتعددة اللغات لتسلسل فعال للبيانات المنظمة.

يتم تعريف رسائل البروتوكول بواسطة ملفات .proto ، وهي غالبًا أسهل طريقة لفهم نوع الرسالة.

الرسالة tf.train.Example (أو protobuf) هي نوع رسالة مرن يمثل تعيين {"string": value} . إنه مصمم للاستخدام مع TensorFlow ويتم استخدامه في جميع واجهات برمجة التطبيقات عالية المستوى مثل TFX .

يوضح هذا الكمبيوتر الدفتري كيفية إنشاء الرسالة tf.train.Example واستخدامها ، ثم إجراء تسلسل وكتابة وقراءة tf.train.Example للرسائل من وإلى ملفات .tfrecord .

يثبت

import tensorflow as tf

import numpy as np
import IPython.display as display

tf.train.Example

أنواع البيانات لـ tf.train.Example

بشكل أساسي ، فإن tf.train.Example هو تعيين {"string": tf.train.Feature} .

يمكن لنوع الرسالة tf.train.Feature قبول أحد الأنواع الثلاثة التالية (انظر ملف .proto كمرجع). يمكن إجبار معظم الأنواع العامة الأخرى على أحد هذه الأنواع:

  1. tf.train.BytesList (يمكن فرض الأنواع التالية)

    • string
    • byte
  2. tf.train.FloatList (يمكن فرض الأنواع التالية)

    • float (تعويم float32 )
    • double ( float64 )
  3. tf.train.Int64List (يمكن فرض الأنواع التالية)

    • bool
    • enum
    • int32
    • uint32
    • int64
    • uint64

لتحويل نوع TensorFlow قياسي إلى tf.train.Example متوافق مع tf.train.Feature ، يمكنك استخدام وظائف الاختصار أدناه. لاحظ أن كل دالة تأخذ قيمة إدخال قياسية وتقوم بإرجاع tf.train.Feature ، الميزة التي تحتوي على أحد أنواع list الثلاثة أعلاه:

# The following functions can be used to convert a value to a type compatible
# with tf.train.Example.

def _bytes_feature(value):
  """Returns a bytes_list from a string / byte."""
  if isinstance(value, type(tf.constant(0))):
    value = value.numpy() # BytesList won't unpack a string from an EagerTensor.
  return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))

def _float_feature(value):
  """Returns a float_list from a float / double."""
  return tf.train.Feature(float_list=tf.train.FloatList(value=[value]))

def _int64_feature(value):
  """Returns an int64_list from a bool / enum / int / uint."""
  return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))

فيما يلي بعض الأمثلة على كيفية عمل هذه الوظائف. لاحظ أنواع المدخلات المختلفة وأنواع المخرجات المعيارية. إذا كان نوع الإدخال لوظيفة ما لا يتطابق مع أحد الأنواع القابلة للإكراه المذكورة أعلاه ، فستقوم الوظيفة بإصدار استثناء (على سبيل المثال _int64_feature(1.0) ستخرج خطأ لأن 1.0 عبارة عن عدد عشري - لذلك ، يجب استخدامها مع وظيفة _float_feature بدلاً من ذلك ):

print(_bytes_feature(b'test_string'))
print(_bytes_feature(u'test_bytes'.encode('utf-8')))

print(_float_feature(np.exp(1)))

print(_int64_feature(True))
print(_int64_feature(1))
bytes_list {
  value: "test_string"
}

bytes_list {
  value: "test_bytes"
}

float_list {
  value: 2.7182817459106445
}

int64_list {
  value: 1
}

int64_list {
  value: 1
}

يمكن إجراء تسلسل لجميع الرسائل الأولية إلى سلسلة ثنائية باستخدام طريقة .SerializeToString :

feature = _float_feature(np.exp(1))

feature.SerializeToString()
b'\x12\x06\n\x04T\xf8-@'

إنشاء رسالة tf.train.Example

افترض أنك تريد إنشاء رسالة tf.train.Example من البيانات الموجودة. من الناحية العملية ، قد تأتي مجموعة البيانات من أي مكان ، ولكن إجراء إنشاء tf.train.Example ، سيكون مثال الرسالة من ملاحظة واحدة هو نفسه:

  1. داخل كل ملاحظة ، يجب تحويل كل قيمة إلى tf.train.Feature ، وهي ميزة تحتوي على أحد الأنواع الثلاثة المتوافقة ، باستخدام إحدى الوظائف المذكورة أعلاه.

  2. يمكنك إنشاء خريطة (قاموس) من سلسلة اسم الميزة إلى قيمة الميزة المشفرة المنتجة في رقم 1.

  3. يتم تحويل الخريطة التي تم إنشاؤها في الخطوة 2 إلى رسالة Features .

في دفتر الملاحظات هذا ، ستقوم بإنشاء مجموعة بيانات باستخدام NumPy.

ستحتوي مجموعة البيانات هذه على 4 ميزات:

  • خاصية منطقية ، False أو True باحتمالية متساوية
  • ميزة عدد صحيح يتم اختيارها عشوائيًا بشكل موحد من [0, 5]
  • ميزة سلسلة يتم إنشاؤها من جدول سلسلة باستخدام ميزة العدد الصحيح كفهرس
  • ميزة عائمة من التوزيع العادي القياسي

ضع في اعتبارك عينة تتكون من 10000 ملاحظة موزعة بشكل مستقل ومتماثل من كل من التوزيعات المذكورة أعلاه:

# The number of observations in the dataset.
n_observations = int(1e4)

# Boolean feature, encoded as False or True.
feature0 = np.random.choice([False, True], n_observations)

# Integer feature, random from 0 to 4.
feature1 = np.random.randint(0, 5, n_observations)

# String feature.
strings = np.array([b'cat', b'dog', b'chicken', b'horse', b'goat'])
feature2 = strings[feature1]

# Float feature, from a standard normal distribution.
feature3 = np.random.randn(n_observations)

يمكن إجبار كل ميزة من هذه الميزات في tf.train.Example نوع متوافق باستخدام واحدة من _bytes_feature ، _float_feature ، _int64_feature . يمكنك بعد ذلك إنشاء رسالة tf.train.Example من هذه الميزات المشفرة:

def serialize_example(feature0, feature1, feature2, feature3):
  """
  Creates a tf.train.Example message ready to be written to a file.
  """
  # Create a dictionary mapping the feature name to the tf.train.Example-compatible
  # data type.
  feature = {
      'feature0': _int64_feature(feature0),
      'feature1': _int64_feature(feature1),
      'feature2': _bytes_feature(feature2),
      'feature3': _float_feature(feature3),
  }

  # Create a Features message using tf.train.Example.

  example_proto = tf.train.Example(features=tf.train.Features(feature=feature))
  return example_proto.SerializeToString()

على سبيل المثال ، افترض أن لديك ملاحظة واحدة من مجموعة البيانات ، [False, 4, bytes('goat'), 0.9876] . يمكنك إنشاء وطباعة الرسالة tf.train.Example لهذه الملاحظة باستخدام create_message() . ستتم كتابة كل ملاحظة كرسالة Features وفقًا لما ورد أعلاه. لاحظ أن رسالة tf.train.Example هي مجرد غلاف حول رسالة Features :

# This is an example observation from the dataset.

example_observation = []

serialized_example = serialize_example(False, 4, b'goat', 0.9876)
serialized_example
b'\nR\n\x14\n\x08feature2\x12\x08\n\x06\n\x04goat\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x04\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x00\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04[\xd3|?'

لفك تشفير الرسالة ، استخدم الأسلوب tf.train.Example.FromString .

example_proto = tf.train.Example.FromString(serialized_example)
example_proto
features {
  feature {
    key: "feature0"
    value {
      int64_list {
        value: 0
      }
    }
  }
  feature {
    key: "feature1"
    value {
      int64_list {
        value: 4
      }
    }
  }
  feature {
    key: "feature2"
    value {
      bytes_list {
        value: "goat"
      }
    }
  }
  feature {
    key: "feature3"
    value {
      float_list {
        value: 0.9876000285148621
      }
    }
  }
}

تفاصيل تنسيق TFRecords

يحتوي ملف TFRecord على سلسلة من السجلات. لا يمكن قراءة الملف إلا بالتسلسل.

يحتوي كل سجل على سلسلة بايت ، لحمولة البيانات ، بالإضافة إلى طول البيانات ، و CRC-32C ( 32 بت CRC باستخدام كثير الحدود Castagnoli ) للتحقق من التكامل.

يتم تخزين كل سجل بالتنسيقات التالية:

uint64 length
uint32 masked_crc32_of_length
byte   data[length]
uint32 masked_crc32_of_data

يتم تجميع السجلات معًا لإنتاج الملف. موصوفة CRC هنا ، وقناع اتفاقية حقوق الطفل هو:

masked_crc = ((crc >> 15) | (crc << 17)) + 0xa282ead8ul

TFRecord الملفات باستخدام tf.data

توفر وحدة tf.data أيضًا أدوات لقراءة البيانات وكتابتها في TensorFlow.

كتابة ملف TFRecord

أسهل طريقة للحصول على البيانات في مجموعة بيانات هي استخدام طريقة from_tensor_slices .

عند تطبيقها على مصفوفة ، فإنها تُرجع مجموعة بيانات من الحجميات:

tf.data.Dataset.from_tensor_slices(feature1)
<TensorSliceDataset element_spec=TensorSpec(shape=(), dtype=tf.int64, name=None)>

عند تطبيقها على مجموعة من المصفوفات ، فإنها تُرجع مجموعة بيانات تتكون من مجموعات:

features_dataset = tf.data.Dataset.from_tensor_slices((feature0, feature1, feature2, feature3))
features_dataset
<TensorSliceDataset element_spec=(TensorSpec(shape=(), dtype=tf.bool, name=None), TensorSpec(shape=(), dtype=tf.int64, name=None), TensorSpec(shape=(), dtype=tf.string, name=None), TensorSpec(shape=(), dtype=tf.float64, name=None))>
# Use `take(1)` to only pull one example from the dataset.
for f0,f1,f2,f3 in features_dataset.take(1):
  print(f0)
  print(f1)
  print(f2)
  print(f3)
tf.Tensor(False, shape=(), dtype=bool)
tf.Tensor(4, shape=(), dtype=int64)
tf.Tensor(b'goat', shape=(), dtype=string)
tf.Tensor(0.5251196235602504, shape=(), dtype=float64)

استخدم الأسلوب tf.data.Dataset.map لتطبيق دالة على كل عنصر من عناصر مجموعة Dataset .

يجب أن تعمل الوظيفة المعينة في وضع الرسم البياني TensorFlow - يجب أن تعمل على tf.Tensors . يمكن تغليف وظيفة غير موتر ، مثل serialize_example ، tf.py_function لجعلها متوافقة.

يتطلب استخدام tf.py_function تحديد الشكل ونوع المعلومات التي لا تتوفر بخلاف ذلك:

def tf_serialize_example(f0,f1,f2,f3):
  tf_string = tf.py_function(
    serialize_example,
    (f0, f1, f2, f3),  # Pass these args to the above function.
    tf.string)      # The return type is `tf.string`.
  return tf.reshape(tf_string, ()) # The result is a scalar.
tf_serialize_example(f0, f1, f2, f3)
<tf.Tensor: shape=(), dtype=string, numpy=b'\nR\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04=n\x06?\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x00\n\x14\n\x08feature2\x12\x08\n\x06\n\x04goat\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x04'>

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

serialized_features_dataset = features_dataset.map(tf_serialize_example)
serialized_features_dataset
<MapDataset element_spec=TensorSpec(shape=(), dtype=tf.string, name=None)>
def generator():
  for features in features_dataset:
    yield serialize_example(*features)
serialized_features_dataset = tf.data.Dataset.from_generator(
    generator, output_types=tf.string, output_shapes=())
serialized_features_dataset
<FlatMapDataset element_spec=TensorSpec(shape=(), dtype=tf.string, name=None)>

واكتبها في ملف TFRecord:

filename = 'test.tfrecord'
writer = tf.data.experimental.TFRecordWriter(filename)
writer.write(serialized_features_dataset)
WARNING:tensorflow:From /tmp/ipykernel_25215/3575438268.py:2: TFRecordWriter.__init__ (from tensorflow.python.data.experimental.ops.writers) is deprecated and will be removed in a future version.
Instructions for updating:
To write TFRecords to disk, use `tf.io.TFRecordWriter`. To save and load the contents of a dataset, use `tf.data.experimental.save` and `tf.data.experimental.load`

قراءة ملف TFRecord

يمكنك أيضًا قراءة ملف TFRecord باستخدام فئة tf.data.TFRecordDataset .

يمكن العثور على مزيد من المعلومات حول استهلاك ملفات TFRecord باستخدام tf.data في tf.data: دليل إنشاء خطوط أنابيب الإدخال TensorFlow .

يمكن أن يكون استخدام TFRecordDataset s مفيدًا لتوحيد بيانات الإدخال وتحسين الأداء.

filenames = [filename]
raw_dataset = tf.data.TFRecordDataset(filenames)
raw_dataset
<TFRecordDatasetV2 element_spec=TensorSpec(shape=(), dtype=tf.string, name=None)>

في هذه المرحلة ، تحتوي مجموعة البيانات على رسائل tf.train.Example المتسلسلة. عند تكرارها ، فإنها ترجع هذه كموترات سلسلة عددية.

استخدم طريقة .take لإظهار أول 10 سجلات فقط.

for raw_record in raw_dataset.take(10):
  print(repr(raw_record))
<tf.Tensor: shape=(), dtype=string, numpy=b'\nR\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x00\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x04\n\x14\n\x08feature2\x12\x08\n\x06\n\x04goat\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04=n\x06?'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nR\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x04\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\x9d\xfa\x98\xbe\n\x14\n\x08feature2\x12\x08\n\x06\n\x04goat'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nQ\n\x13\n\x08feature2\x12\x07\n\x05\n\x03dog\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x01\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04a\xc0r?\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nQ\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x00\n\x13\n\x08feature2\x12\x07\n\x05\n\x03cat\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\x92Q(?'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nR\n\x14\n\x08feature2\x12\x08\n\x06\n\x04goat\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04>\xc0\xe5>\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x04'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nU\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04I!\xde\xbe\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x02\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x00\n\x17\n\x08feature2\x12\x0b\n\t\n\x07chicken'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nQ\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x00\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\xe0\x1a\xab\xbf\n\x13\n\x08feature2\x12\x07\n\x05\n\x03cat'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nQ\n\x13\n\x08feature2\x12\x07\n\x05\n\x03cat\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\x87\xb2\xd7?\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x00'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nR\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x04\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04n\xe19>\n\x14\n\x08feature2\x12\x08\n\x06\n\x04goat'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nR\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\x1as\xd9\xbf\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x04\n\x14\n\x08feature2\x12\x08\n\x06\n\x04goat'>

يمكن تحليل هذه الموترات باستخدام الوظيفة أدناه. لاحظ أن feature_description ضروري هنا لأن tf.data.Dataset s تستخدم تنفيذ الرسم البياني ، وتحتاج إلى هذا الوصف لبناء شكلها ونوع التوقيع:

# Create a description of the features.
feature_description = {
    'feature0': tf.io.FixedLenFeature([], tf.int64, default_value=0),
    'feature1': tf.io.FixedLenFeature([], tf.int64, default_value=0),
    'feature2': tf.io.FixedLenFeature([], tf.string, default_value=''),
    'feature3': tf.io.FixedLenFeature([], tf.float32, default_value=0.0),
}

def _parse_function(example_proto):
  # Parse the input `tf.train.Example` proto using the dictionary above.
  return tf.io.parse_single_example(example_proto, feature_description)

بدلاً من ذلك ، استخدم tf.parse example لتحليل الدُفعة بأكملها مرة واحدة. طبق هذه الوظيفة على كل عنصر في مجموعة البيانات باستخدام طريقة tf.data.Dataset.map :

parsed_dataset = raw_dataset.map(_parse_function)
parsed_dataset
<MapDataset element_spec={'feature0': TensorSpec(shape=(), dtype=tf.int64, name=None), 'feature1': TensorSpec(shape=(), dtype=tf.int64, name=None), 'feature2': TensorSpec(shape=(), dtype=tf.string, name=None), 'feature3': TensorSpec(shape=(), dtype=tf.float32, name=None)}>

استخدم التنفيذ الحثيث لعرض الملاحظات في مجموعة البيانات. توجد 10000 ملاحظة في مجموعة البيانات هذه ، لكنك ستعرض أول 10 فقط. يتم عرض البيانات كقاموس من الميزات. كل عنصر عبارة عن tf.Tensor ، ويعرض العنصر numpy لهذا الموتر قيمة الميزة:

for parsed_record in parsed_dataset.take(10):
  print(repr(parsed_record))
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=0>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=4>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'goat'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=0.5251196>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=4>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'goat'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=-0.29878703>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'dog'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=0.94824797>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=0>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'cat'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=0.65749466>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=4>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'goat'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=0.44873232>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=0>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=2>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'chicken'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=-0.4338477>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=0>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'cat'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=-1.3367577>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=0>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'cat'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=1.6851357>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=4>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'goat'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=0.18152401>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=4>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'goat'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=-1.6988251>}

هنا ، تقوم الدالة tf.parse_example بفك ضغط حقول tf.train.Example إلى موترات قياسية.

ملفات TFRecord في بايثون

تحتوي وحدة tf.io أيضًا على وظائف Python النقية لقراءة ملفات TFRecord وكتابتها.

كتابة ملف TFRecord

بعد ذلك ، اكتب 10000 ملاحظة في الملف test.tfrecord . يتم تحويل كل ملاحظة إلى رسالة tf.train.Example ، ثم يتم كتابتها في ملف. يمكنك بعد ذلك التحقق من إنشاء ملف test.tfrecord :

# Write the `tf.train.Example` observations to the file.
with tf.io.TFRecordWriter(filename) as writer:
  for i in range(n_observations):
    example = serialize_example(feature0[i], feature1[i], feature2[i], feature3[i])
    writer.write(example)
du -sh {filename}
984K    test.tfrecord

قراءة ملف TFRecord

يمكن تحليل هذه الموترات المتسلسلة بسهولة باستخدام tf.train.Example.ParseFromString :

filenames = [filename]
raw_dataset = tf.data.TFRecordDataset(filenames)
raw_dataset
<TFRecordDatasetV2 element_spec=TensorSpec(shape=(), dtype=tf.string, name=None)>
for raw_record in raw_dataset.take(1):
  example = tf.train.Example()
  example.ParseFromString(raw_record.numpy())
  print(example)
features {
  feature {
    key: "feature0"
    value {
      int64_list {
        value: 0
      }
    }
  }
  feature {
    key: "feature1"
    value {
      int64_list {
        value: 4
      }
    }
  }
  feature {
    key: "feature2"
    value {
      bytes_list {
        value: "goat"
      }
    }
  }
  feature {
    key: "feature3"
    value {
      float_list {
        value: 0.5251196026802063
      }
    }
  }
}

هذا يعيد tf.train.Example . مثال أولي صعب الاستخدام كما هو ، لكنه في الأساس تمثيل لـ:

Dict[str,
     Union[List[float],
           List[int],
           List[str]]]

تقوم الكود التالي يدويًا بتحويل Example إلى قاموس مصفوفات NumPy ، دون استخدام TensorFlow Ops. الرجوع إلى ملف PROTO للحصول على detials.

result = {}
# example.features.feature is the dictionary
for key, feature in example.features.feature.items():
  # The values are the Feature objects which contain a `kind` which contains:
  # one of three fields: bytes_list, float_list, int64_list

  kind = feature.WhichOneof('kind')
  result[key] = np.array(getattr(feature, kind).value)

result
{'feature3': array([0.5251196]),
 'feature1': array([4]),
 'feature0': array([0]),
 'feature2': array([b'goat'], dtype='|S4')}

تجول: قراءة وكتابة بيانات الصورة

هذا مثال شامل على كيفية قراءة بيانات الصورة وكتابتها باستخدام سجلات TFRecords. باستخدام صورة كبيانات إدخال ، ستكتب البيانات كملف TFRecord ، ثم تقرأ الملف مرة أخرى وتعرض الصورة.

يمكن أن يكون هذا مفيدًا ، على سبيل المثال ، إذا كنت تريد استخدام عدة نماذج على نفس مجموعة بيانات الإدخال. بدلاً من تخزين بيانات الصورة الخام ، يمكن معالجتها مسبقًا في تنسيق TFRecords ، ويمكن استخدامها في جميع عمليات المعالجة والنمذجة الإضافية.

أولاً ، لنقم بتنزيل صورة قطة في الثلج وهذه الصورة لجسر ويليامزبرغ ، نيويورك قيد الإنشاء.

إحضار الصور

cat_in_snow  = tf.keras.utils.get_file(
    '320px-Felis_catus-cat_on_snow.jpg',
    'https://storage.googleapis.com/download.tensorflow.org/example_images/320px-Felis_catus-cat_on_snow.jpg')

williamsburg_bridge = tf.keras.utils.get_file(
    '194px-New_East_River_Bridge_from_Brooklyn_det.4a09796u.jpg',
    'https://storage.googleapis.com/download.tensorflow.org/example_images/194px-New_East_River_Bridge_from_Brooklyn_det.4a09796u.jpg')
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/320px-Felis_catus-cat_on_snow.jpg
24576/17858 [=========================================] - 0s 0us/step
32768/17858 [=======================================================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/194px-New_East_River_Bridge_from_Brooklyn_det.4a09796u.jpg
16384/15477 [===============================] - 0s 0us/step
24576/15477 [===============================================] - 0s 0us/step
display.display(display.Image(filename=cat_in_snow))
display.display(display.HTML('Image cc-by: <a "href=https://commons.wikimedia.org/wiki/File:Felis_catus-cat_on_snow.jpg">Von.grzanka</a>'))

jpeg

display.display(display.Image(filename=williamsburg_bridge))
display.display(display.HTML('<a "href=https://commons.wikimedia.org/wiki/File:New_East_River_Bridge_from_Brooklyn_det.4a09796u.jpg">From Wikimedia</a>'))

jpeg

اكتب ملف TFRecord

كما في السابق ، قم بترميز الميزات كأنواع متوافقة مع tf.train.Example . يقوم هذا بتخزين ميزة سلسلة الصور الأولية ، بالإضافة إلى ميزة الارتفاع والعرض والعمق label العشوائية. يتم استخدام الأخير عند كتابة الملف للتمييز بين صورة القط وصورة الجسر. استخدم 0 لصورة القط ، و 1 لصورة الجسر:

image_labels = {
    cat_in_snow : 0,
    williamsburg_bridge : 1,
}
# This is an example, just using the cat image.
image_string = open(cat_in_snow, 'rb').read()

label = image_labels[cat_in_snow]

# Create a dictionary with features that may be relevant.
def image_example(image_string, label):
  image_shape = tf.io.decode_jpeg(image_string).shape

  feature = {
      'height': _int64_feature(image_shape[0]),
      'width': _int64_feature(image_shape[1]),
      'depth': _int64_feature(image_shape[2]),
      'label': _int64_feature(label),
      'image_raw': _bytes_feature(image_string),
  }

  return tf.train.Example(features=tf.train.Features(feature=feature))

for line in str(image_example(image_string, label)).split('\n')[:15]:
  print(line)
print('...')
features {
  feature {
    key: "depth"
    value {
      int64_list {
        value: 3
      }
    }
  }
  feature {
    key: "height"
    value {
      int64_list {
        value: 213
      }
...

لاحظ أن جميع الميزات مخزنة الآن في الرسالة tf.train.Example . بعد ذلك ، قم بتشغيل الكود أعلاه واكتب أمثلة الرسائل إلى ملف يسمى images.tfrecords :

# Write the raw image files to `images.tfrecords`.
# First, process the two images into `tf.train.Example` messages.
# Then, write to a `.tfrecords` file.
record_file = 'images.tfrecords'
with tf.io.TFRecordWriter(record_file) as writer:
  for filename, label in image_labels.items():
    image_string = open(filename, 'rb').read()
    tf_example = image_example(image_string, label)
    writer.write(tf_example.SerializeToString())
du -sh {record_file}
36K images.tfrecords

اقرأ ملف TFRecord

لديك الآن الملف - images.tfrecords - ويمكنك الآن تكرار السجلات الموجودة فيه لقراءة ما كتبته مرة أخرى. بالنظر إلى أنك في هذا المثال ستعيد إنتاج الصورة فقط ، فإن الميزة الوحيدة التي ستحتاج إليها هي سلسلة الصورة الأولية. قم باستخراجه باستخدام المحولات الموضحة أعلاه ، وهي example.features.feature['image_raw'].bytes_list.value[0] . يمكنك أيضًا استخدام التصنيفات لتحديد أي سجل يمثل القط وأي سجل يمثل الجسر:

raw_image_dataset = tf.data.TFRecordDataset('images.tfrecords')

# Create a dictionary describing the features.
image_feature_description = {
    'height': tf.io.FixedLenFeature([], tf.int64),
    'width': tf.io.FixedLenFeature([], tf.int64),
    'depth': tf.io.FixedLenFeature([], tf.int64),
    'label': tf.io.FixedLenFeature([], tf.int64),
    'image_raw': tf.io.FixedLenFeature([], tf.string),
}

def _parse_image_function(example_proto):
  # Parse the input tf.train.Example proto using the dictionary above.
  return tf.io.parse_single_example(example_proto, image_feature_description)

parsed_image_dataset = raw_image_dataset.map(_parse_image_function)
parsed_image_dataset
<MapDataset element_spec={'depth': TensorSpec(shape=(), dtype=tf.int64, name=None), 'height': TensorSpec(shape=(), dtype=tf.int64, name=None), 'image_raw': TensorSpec(shape=(), dtype=tf.string, name=None), 'label': TensorSpec(shape=(), dtype=tf.int64, name=None), 'width': TensorSpec(shape=(), dtype=tf.int64, name=None)}>

استرجع الصور من ملف TFRecord:

for image_features in parsed_image_dataset:
  image_raw = image_features['image_raw'].numpy()
  display.display(display.Image(data=image_raw))

jpeg

jpeg