TFRecord ו-tf.train.דוגמה

הצג באתר TensorFlow.org הפעל בגוגל קולאב צפה במקור ב-GitHub הורד מחברת

פורמט TFRecord הוא פורמט פשוט לאחסון רצף של רשומות בינאריות.

מאגרי פרוטוקול הם ספרייה חוצת פלטפורמות, חוצה שפות להסדרה יעילה של נתונים מובנים.

הודעות פרוטוקול מוגדרות על ידי קבצי .proto , אלו הן לרוב הדרך הקלה ביותר להבין סוג הודעה.

ההודעה tf.train.Example (או protobuf) היא סוג הודעה גמיש המייצג מיפוי {"string": value} . הוא מיועד לשימוש עם TensorFlow ומשמש בכל ה-APIs ברמה גבוהה יותר כגון 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]
  • תכונת מחרוזת שנוצרה מטבלת מחרוזת על ידי שימוש בתכונת המספרים השלמים כאינדקס
  • תכונת ציפה מהתפלגות נורמלית סטנדרטית

שקול מדגם המורכב מ-10,000 תצפיות הפזורות באופן עצמאי וזהה מכל אחת מההתפלגויות לעיל:

# 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 מתוארים כאן , והמסכה של 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)>

מיושם על טאפל של מערכים, הוא מחזיר מערך נתונים של tuples:

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 input pipelines .

שימוש ב- 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 משתמשים בביצוע גרף, וצריכים את התיאור הזה כדי לבנות את חתימת הצורה והסוג שלהם:

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

השתמש בביצוע נלהב כדי להציג את התצפיות במערך הנתונים. יש 10,000 תצפיות במערך הנתונים הזה, אבל תציג רק את 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 ב- Python

מודול tf.io מכיל גם פונקציות Pure-Python לקריאה וכתיבה של קבצי TFRecord.

כתיבת קובץ TFRecord

לאחר מכן, כתוב את 10,000 התצפיות לקובץ 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 לפרטים.

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