Статьи TensorFlow | TFRecord формата ввода данных TensorFlow

TensorFlow

"Введение"TFRecord является важным компонентом экосистемы TensorFlow. Это формат хранения двоичных последовательностей. Использование этого формата может сделать чтение и обработку входных данных более эффективными, тем самым повышая скорость общего процесса обучения. Чрезвычайно гибкий, он может облегчить построение и анализ данных сложных признаков. В этой статье подробно описан процесс создания и чтения файлов данных TFRecord, а также предоставлен соответствующий пример кода для справки.

Введение в формат TFRecord

TFRecordдаTensorFlowВажный компонент экосистемы, который по сути является файловым форматом для хранения содержимого двоичных последовательностей.TFRecordФайл сериализуетсяprotobufструктура данных, которая может быть предоставлена ​​напрямуюTensorFlowПрограмма для чтения и использования для обучения модели.

Для файлов данных в текстовом формате накладные расходы на хранение и чтение относительно велики.TFRecordОтформатированные файлы данных занимают меньше места на диске и читаются более эффективно, поэтому используйтеTFRecordФормат хранения может в определенной степени повысить эффективность обработки данных.

Кроме того, данные в текстовом формате больше подходят для обработки定长且维度单一的характерные данные, для变长以及多维度的Обработка данных признаков будет более проблематичной, иTFRecordОтформатированные данные не имеют этого ограничения, что обеспечивает большую гибкость при чтении и обработке данных.

TFRecord ProtoBuf

при создании или чтенииTFRecordфайл, нам нужно соединиться сTFRecordзависит от форматаprotobufпротоколы имеют определенное понимание того, что они составленыTFRecordважная часть документа.

Example

ExampleОтносится к выборке входных данных, которая состоит из ряда функций. ТотprotobufФормат следующий:

message Example {
  Features features = 1;
}

вышеFeaturesотносится к совокупности признаков, которыеprotobufФормат следующий:

message Features {
  // Map from feature name to feature.
  map<string, Feature> feature = 1;
}

здесьFeaturesиспользоватьmapконструкция для хранения, гдеmapизkeyпредставляет имя функции, котораяstringтип,valueпредставляет конкретное собственное значение, котороеFeatureтип.

Кроме того, можно увидетьExampleтолько что инкапсулированныйFeaturesструктура, суть которойFeaturesэквивалентны.

Feature

Featureотносится к определенному собственному значению, котороеprotobufФормат следующий:

message Feature {
  // Each feature can be exactly one kind.
  oneof kind {
    BytesList bytes_list = 1;
    FloatList float_list = 2;
    Int64List int64_list = 3;
  }
}

отFeatureКак видно из определения, он может принимать данные в трех форматах, а именно:

  1. BytesListформат, который может представлятьstringилиbyteтип данных.

  2. FloatListформат, который может представлятьfloatиdoubleтип данных.

  3. Int64Listформат, который может представлятьboolтип,enumтип,int32тип,uint32тип,int64тип иuint64и многие другие типы данных.

Вышеупомянутые три формата в основном охватывают все распространенные типы ввода данных и используются для генерации и анализа.TFRecordданные, вы можете использовать соответствующие данные в соответствии с конкретным типом данныхFeatureструктура.

Реализация Python

вышеprotobufПосле преобразования файлов в структуры данных для конкретного языка эти структуры можно использовать для построения и сериализации данных объектов. Ниже сpythonЯзык в качестве примера, чтобы представить конкретное использование этих структур данных. (Примечание: вTensorFlowизpythonИнсталляционный пакет уже содержитExampleа такжеFeatureи другие связанные структуры данных, мы можем использовать их напрямую без повторного использованияprotocИнструмент создан. )

Во-первых, нам нужно построитьFeatureобъект. так какFeatureСтруктурная поддержка3данные в различных форматах, поэтому здесь мы используем3функция для создания различных типовFeatureобъект. Пример кода выглядит следующим образом:

import tensorflow as tf
import numpy as np

def _bytes_feature(value):
    """Returns a bytes_list from a string / byte."""
    if isinstance(value, type(tf.constant(0))):
        # BytesList won't unpack a string from an EagerTensor.
        value = value.numpy()
    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]))

# Print BytesList.
print(_bytes_feature(b'test_string'))
print(_bytes_feature(u'test_bytes'.encode('utf-8')))
# Print FloatList.
print(_float_feature(np.exp(1)))
# Print Int64List.
print(_int64_feature(True))
print(_int64_feature(1))
# Serialize and Deserialize Feature.
serialized_feature = _float_feature(np.exp(1)).SerializeToString()
print(serialized_feature)
feature_proto = tf.train.Feature.FromString(serialized_feature)
print(feature_proto)

в_bytes_feature,_float_featureи_int64_featureфункции используются для созданияBytesList,FloatListиInt64ListформатированныйFeatureобъект, предполагается, что это3параметры функцииvalueявляются единым значением.

так какtf.train.*ListАргументы, полученные функцией, представляют собой списки (list) или массив (array), поэтому приведенный выше код добавит[]нотация для представления списка, если входной параметрvalueЭта операция не требуется, если это уже список или массив. Кроме того, необходимо обратить внимание на3параметры функцииvalueОсновной тип*Listсовпадают, иначе будет сообщено об ошибке.

в сгенерированномFeatureобъект, вы можете назвать егоSerializeToStringметод сериализации, в результате чего получается сериализованная строка. Также вы можете использоватьtf.train.Feature.FromStringметод восстановления сериализованных данных вFeatureобъект.

Затем мы можем построитьExampleобъект и сериализовать его. Предположим, у нас есть4своего родаFeature, они естьbooleanтиповые характеристики,integerтиповые характеристики,stringтиповые характеристики иfloatхарактеристики типа, мы сначала4вид функции через выше3После кодирования функция возвращает соответствующийFeatureобъект, затем построитьFeature Mapсловарь и сгенерироватьFeaturesобъект, последний использованныйFeaturesгенерация объектаExampleобъект и сериализовать его. Объедините вышеуказанный процесс в одну функциюserialize_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
    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()

# Serialize and Deserialize Example.
serialized_example = serialize_example(False, 4, b'goat', 0.9876)
print(serialized_example)
example_proto = tf.train.Example.FromString(serialized_example)
print(example_proto)

Точно так же вы можете позвонитьExampleобъектSerializeToStringчтобы сериализовать его в строку, вызовитеtf.train.Example.FromStringспособ сериализацииExampleРеставрация объекта.

Генерация файла TFRecord

Предположим, у нас есть4видыFeature, как описано в предыдущем разделе, и предполагая их исходные данные (numpy) создается, как показано в следующем коде:

# 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)
print(feature0, feature1, feature2, feature3)

Теперь мы собираемся использовать это4своего родаFeatureдля создания содержащего10,000образцов данныхTFRecordфайл можно создать следующими способами.

Сгенерировано с использованием tf.data

первое использованиеtf.data.Dataset.from_tensor_slicesфункция для созданияdateset, код выглядит так:

features_dataset = tf.data.Dataset.from_tensor_slices(
    (feature0, feature1, feature2, feature3))
# Print dataset.
print(features_dataset)
# Print one element in dataset.
for f0, f1, f2, f3 in features_dataset.take(1):
    print(f0, f1, f2, f3)

Затем мы используем определение, определенное в предыдущем разделе.serialize_exampleфункция для создания сериализованного строкового типаdataset, код выглядит так:

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=(),
)
# Print serialized dataset.
print(serialized_features_dataset)
# Print one element in serialized_features_dataset.
for s in serialized_features_dataset.take(1):
    print(s)

Наконец, мы сериализуемdatasetнаписатьTFRecordВ файле код выглядит так:

filename = 'train.tfrecord'
writer = tf.data.experimental.TFRecordWriter(filename)
writer.write(serialized_features_dataset)

Обратите внимание здесьwriterиспользуетtf.data.experimental.TFRecordWriterобъект, посвященныйсерийныйdatasetобъект записывается вTFRecordВ файле, который будет описан позжеtf.io.TFRecordWriterобъекты различаются.

Сгенерировано с помощью tf.io

Сначала преобразуйте каждую выборку данных вtf.train.Exampleобъект и сериализовать его перед записьюTFRecordВ файле используется то же, что описано выше здесьserialize_exampleфункция для сериализации, код выглядит следующим образом:

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

здесьwriterиспользуетtf.io.TFRecordWriterобъект, который напрямую записывает сериализованную строку вTFRecordв файле.

В общем, это поколениеTFRecordфайл вpythonОн наиболее часто используется и может быть выбран в соответствии с конкретной ситуацией при фактическом использовании.

Сгенерировано с помощью MapReduce

Во время обработки данных мы можем использоватьMapReduceПроведем некоторые операции предварительной обработки, а также надеемся, что сможем напрямую использоватьMapReduceзадача создать несколькоTFRecordфайлы данных для использования в распределенном обучении, чтобы удовлетворить эту потребность,TensorFlowEco предоставляет библиотеку расширенийtensorflow-hadoop, который содержитTFRecordформатированныйMapReduce InputFormatиOutputFormatвыполнить. Используя эту библиотеку расширений, мы можем напрямую использоватьMapReduceзадачи для создания и чтенияTFRecordфайл. Часть кода примера выглядит следующим образом:

// Main function.
import org.tensorflow.hadoop.io.TFRecordFileOutputFormat;
Job job = Job.getInstance(config, "TFRecord");
job.setOutputFormatClass(TFRecordFileOutputFormat.class);

// Mapper or Reducer.
import java.util.Arrays;
import com.google.protobuf.ByteString;
import org.tensorflow.example.BytesList;
import org.tensorflow.example.Example;
import org.tensorflow.example.Feature;
import org.tensorflow.example.Features;
import org.tensorflow.example.FloatList;
import org.tensorflow.example.Int64List;
// map or reduce function
// *List value.
Int64List value0 = Int64List.newBuilder().addAllValue(Arrays.asList(0L)).build();
Int64List value1 = Int64List.newBuilder().addAllValue(Arrays.asList(4L)).build();
BytesList value2 = BytesList.newBuilder()
        .addAllValue(Arrays.asList(ByteString.copyFrom("goat".getBytes()))).build();
FloatList value3 = FloatList.newBuilder().addAllValue(Arrays.asList(0.9876f)).build();
// All features.
Feature feature0 = Feature.newBuilder().setInt64List(value0).build();
Feature feature1 = Feature.newBuilder().setInt64List(value1).build();
Feature feature2 = Feature.newBuilder().setBytesList(value2).build();
Feature feature3 = Feature.newBuilder().setFloatList(value3).build();
// Feature map.
Features feature = Features.newBuilder().putFeature("feature0", feature0)
        .putFeature("feature1", feature1).putFeature("feature2", feature2)
        .putFeature("feature3", feature3).build();
// Example.
Example example = Example.newBuilder().setFeatures(feature).build();
// Write to TFRecord file.
context.write(new BytesWritable(example.toByteArray()), NullWritable.get());

Обратите внимание, что для соответствияhadoopверсия, вам может потребоваться изменитьtensorflow-hadoopв исходном кодеpom.xmlфайл, будетhadoop.versionустановите то, что вы используетеhadoopверсию и использоватьmavenинструмент для перекомпиляции проекта, затем сгенерированныйjarпакет, импортированный вMapReduceВ проекте избегайте ошибок из-за несоответствия версий.

Кроме того, чтобы сделатьMapReduceПроект можно нормально скомпилировать, нужно еще импортироватьorg.tensorflow:protoбиблиотека, а такжеcom.google.protobuf:protobuf-javaбиблиотека, доступная изmavenОфициальный репозиторий ищите это2последнюю версию библиотеки и добавил вgradleилиmavenВ файле конфигурации проекта, а затем скомпилируйте проект.

Сгенерировано с помощью TFRecorder

из-за созданияTFRecordПри написании файлов часто приходится писать большой объем сложного кода, чтобы оптимизировать сложность кода,TensorFlowОфициально с открытым исходным кодомTensorFlow Recorderпроект (т.е.TFRecorder) для более легкого созданияTFRecordдокумент.

TFRecorderРазрешить пользователям изPandas dataframeилиCSVСоздать напрямуюTFRecordsфайл без написания сложного кода. Это особенно удобно для обработки графических данных.TFRecorderПрежде, чем генерировать крупномасштабныеTFRecordОтформатируйте данные изображения, необходимо написать конвейер данных для загрузки изображения из хранилища и сериализации результата какTFRecordформате, и теперь требуется всего несколько строк кода, чтобы сгенерировать изображение на основеTFRecordдокумент. Пример кода выглядит следующим образом:

import pandas as pd
import tfrecorder

# From Pandas DataFrame
df = pd.read_csv('/path/to/data.csv')
df.tensorflow.to_tfr(output_dir='/my/output/path')

# From CSV
tfrecorder.create_tfrecords(
    source='/path/to/data.csv',
    output_dir='/my/output/path',
)

# From an image directory
tfrecorder.create_tfrecords(
    source='/path/to/image_dir',
    output_dir='/my/output/path',
)

БолееTFRecorderПожалуйста, обратитесь к его официальной документации для использования.

Чтение файла TFRecord

TensorFlowОбеспечивает специальное чтениеTFRecordдокументAPIинтерфейсtf.data.TFRecordDataset, интерфейс может бытьTFRecordСодержимое файла считывается вdatasetсередина. Код выглядит следующим образом:

# Read TFRecord file to dataset.
raw_dataset = tf.data.TFRecordDataset(filename)
print(raw_dataset)

В настоящее времяdatasetСохраняется в виде строки в сериализованном формате. Если ее нужно преобразовать в реальное значение, потребуются дальнейшие операции.

Вернуться к примеру

мы можем поставитьraw_datasetКаждый элемент в сводится кtf.train.Example, как правило, в небольшом диапазонеTFRecordДанные используются для проверки, пример кода выглядит следующим образом:

for raw_record in raw_dataset.take(1):
    example = tf.train.Example()
    example.ParseFromString(raw_record.numpy())
    print(example)
    # or
    example_proto = tf.train.Example.FromString(raw_record.numpy())
    print(example_proto)

Использование модели для обучения

Чтобы использовать это во время обучения моделиdataset, нам надоraw_datasetКаждый элемент в разрешаетFeatureMap, чтобы соответствоватьKerasВход и выход модели. Код выглядит следующим образом:

def _parse_function(example_proto):
    # 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),
    }
    # Parse the single input `tf.train.Example` proto using the dictionary above.
    # return tf.io.parse_single_example(example_proto, feature_description)
    # Parse the batch input tf.train.Example protos using the dictionary above.
    return tf.io.parse_example(example_proto, feature_description)

# Print parsed dataset.
parsed_dataset = raw_dataset.map(_parse_function)
print(parsed_dataset)
# Print one element in parsed_dataset.
for parsed_record in parsed_dataset.take(1):
    print(parsed_record)

используется здесьtf.io.parse_exampleфункция для разбора сериализованной строки в указанный тип данных, нам нужно подготовить заранееfeature_descriptionсловарь, определяющийfeatureимя, длина (фиксированная/переменная), тип данных и значение по умолчанию для синтаксического анализа. Наконец мы звонимraw_datasetизmapметод применения аналитической функции кdatasetкаждый элемент в .

В качестве альтернативы мы также можем использоватьtf.io.parse_single_exampleфункцию для анализа, но обратите внимание, что она не связана сtf.io.parse_exampleРазница между первым подходит для анализа одного сериализованного элемента, а второй подходит дляbatchанализ. существуетTensorFlow 数据输入的最佳实践представлено в статьеdatasetвекторизацияmapоперация, т.е.datasetПодать заявку первымbatchКонвертируйте, а затем применяйтеmapПреобразование для повышения эффективности, поэтому рекомендуется использовать последнюю в качестве функции разбора сериализованных данных.

Наконец мы можемparsed_datasetиспользуется при обучении моделей. Пример кода выглядит следующим образом:

model.fit(parsed_dataset)

Примечание:labelданные должны бытьfeaturesданные там жеdatasetсередина,TensorFlowбудет вводить и выводить в соответствии с модельюTensorизnameидти сdatasetПолучите соответствующие данные для обучения.

использованная литература

  1. TFRecord and tf.train.Example
  2. Адрес файла ProtoBuf, связанный с TFRecord
  3. Спаситель при создании TFRecords — TensorFlow Recorder теперь с открытым исходным кодом!
  4. Адрес TFRecorder Github
  5. Hadoop MapReduce InputFormat/OutputFormat for TFRecords