TFRecord و tf.train.Example

مشاهده در TensorFlow.org در Google Colab اجرا شود مشاهده منبع در GitHub دانلود دفترچه یادداشت

فرمت TFRecord یک فرمت ساده برای ذخیره دنباله ای از رکوردهای باینری است.

بافرهای پروتکل یک کتابخانه بین پلتفرمی و بین زبانی برای سریال سازی کارآمد داده های ساخت یافته هستند.

پیام‌های پروتکل با فایل‌های .proto تعریف می‌شوند، اینها اغلب ساده‌ترین راه برای درک نوع پیام هستند.

پیام tf.train.Example (یا protobuf) یک نوع پیام منعطف است که نگاشت {"string": value} نشان می دهد. این برای استفاده با TensorFlow طراحی شده است و در سراسر API های سطح بالاتر مانند 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 حاوی یکی از 3 نوع سازگار تبدیل شود.

  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)

هر یک از این ویژگی‌ها را می‌توان با استفاده از یکی از _bytes_feature ، _float_feature ، _int64_feature وارد یک نوع tf.train.Example -compatible کرد. سپس می توانید یک پیام 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 ( CRC 32 بیتی با استفاده از چند جمله ای Castagnoli ) برای بررسی یکپارچگی است.

هر رکورد در قالب های زیر ذخیره می شود:

uint64 length
uint32 masked_crc32_of_length
byte   data[length]
uint32 masked_crc32_of_data

رکوردها برای تولید فایل به یکدیگر متصل می شوند. CRC ها در اینجا توضیح داده شده اند و ماسک یک 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 بیابید: راهنمای خطوط لوله ورودی Build TensorFlow .

استفاده از TFRecordDataset می تواند برای استانداردسازی داده های ورودی و بهینه سازی عملکرد مفید باشد.

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 از اجرای گراف استفاده می کند و برای ساخت شکل و نوع امضای خود به این توضیحات نیاز دارد:

# 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 همچنین دارای توابع Pure-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 را بدون استفاده از TensorFlow Ops به فرهنگ لغت آرایه های NumPy تبدیل می کند. برای جزئیات بیشتر به فایل PROTO مراجعه کنید.

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