Интерес к Tensorflow неуклонно растет с момента его появления в ноябре 2015 года. Менее известным компонентом Tensorflow является формат файла TFRecord, собственный двоичный формат хранения Tensorflow.

Если вы работаете с большими наборами данных, использование двоичного формата файла для хранения ваших данных может существенно повлиять на производительность вашего конвейера импорта и, как следствие, на время обучения вашей модели. Двоичные данные занимают меньше места на диске, на их копирование уходит меньше времени и их можно гораздо эффективнее читать с диска. Это особенно верно, если ваши данные хранятся на вращающихся дисках из-за гораздо более низкой производительности чтения / записи по сравнению с SSD.

Однако чистая производительность - не единственное преимущество формата файлов TFRecord. Он оптимизирован для использования с Tensorflow несколькими способами. Во-первых, он позволяет легко комбинировать несколько наборов данных и легко интегрируется с функциями импорта и предварительной обработки данных, предоставляемыми библиотекой. Это является преимуществом, особенно для наборов данных, которые слишком велики для того, чтобы их можно было полностью хранить в памяти, поскольку только данные, которые требуются в данный момент (например, пакет), загружаются с диска и затем обрабатываются. Еще одно важное преимущество TFRecords заключается в том, что можно хранить данные последовательности - например, временные ряды или кодировки слов - таким образом, чтобы обеспечить очень эффективный и (с точки зрения кодирования) удобный импорт этого типа данных. Ознакомьтесь с руководством Чтение данных, чтобы узнать больше о чтении файлов TFRecord.

Итак, у использования TFRecords есть много преимуществ. Но там, где есть свет, должна быть тень, а в случае TFRecords недостатком является то, что вам нужно в первую очередь преобразовать свои данные в этот формат, и только ограниченная документация доступна о том, как это сделать. Существуют официальное руководство и ряд статей о написании TFRecords, но я обнаружил, что они покрыли мне лишь часть пути решения моей проблемы.

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

Структурирование TFRecords

Файл TFRecord хранит ваши данные в виде последовательности двоичных строк. Это означает, что вам необходимо указать структуру данных, прежде чем записывать их в файл. Для этого Tensorflow предоставляет два компонента: tf.train.Example и tf.train.SequenceExample. Вы должны сохранить каждый образец ваших данных в одной из этих структур, затем сериализовать его и использовать tf.python_io.TFRecordWriter для записи на диск.

tf.train.Example - это не обычный класс Python, а буфер протокола.

Как разработчик программного обеспечения, основная проблема, с которой я столкнулся вначале, заключалась в том, что многие компоненты в Tensorflow API не имели описания атрибутов или методов класса. Например, для tf.train.Example предоставляется только файл .proto с загадочными структурами, называемыми message, а также примеры в псевдокоде. Причина в том, что tf.train.Example - это не обычный класс Python, а буфер протокола. Буфер протокола - это метод, разработанный Google для эффективной сериализации структурированных данных. Теперь я расскажу о двух основных способах структурирования Tensorflow TFRecords, дам обзор компонентов с точки зрения разработчика и приведу подробный пример использования tf.train.Example и tf.train.SequenceExample.

Рекомендации фильмов с использованием tf.train.Example

Если ваш набор данных состоит из объектов, где каждый объект представляет собой список значений одного и того же типа, tf.train.Example является правильным компонентом для использования.

В качестве примера возьмем приложение для рекомендации фильмов из документации Tensorflow:

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

tf.train.BytesList, tf.train.FloatList и tf.train.Int64List лежат в основе tf.train.Feature. Все три имеют один атрибут value, который ожидает список соответствующих байтов, float и int.

Строки Python необходимо преобразовать в байты, ( например, my_string.encode (‘utf-8’)), прежде чем они будут сохранены в tf.train.BytesList.

tf.train.Feature обертывает список данных определенного типа, чтобы Tensorflow мог их понять. Он имеет единственный атрибут, который представляет собой объединение bytes_list / float_list / int64_list. Будучи объединением, сохраненный список может иметь тип tf.train.BytesList (имя атрибута bytes_list), tf.train.FloatList (имя атрибута float_list) или tf. train.Int64List (имя атрибута int64_list).

tf.train.Features - это набор именованных функций. У него есть единственный атрибут feature, который ожидает словарь, где ключ - это имя функции, а значение - tf.train.Feature.

tf.train.Example - один из основных компонентов для структурирования TFRecord. Tf.train.Example хранит объекты в одном атрибуте features типа tf.train.Features.

В отличие от предыдущих компонентов, tf.python_io.TFRecordWriter на самом деле является классом Python. Он принимает путь к файлу в своем атрибуте path и создает объект записи, который работает так же, как любой другой объект файла. Класс TFRecordWriter предлагает методы write, flush и close. Метод write принимает строку в качестве параметра и записывает ее на диск, что означает, что сначала должны быть сериализованы структурированные данные. С этой целью tf.train.Example и tf.train.SequenceExample предоставляют методы SerializeToString:

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

Вот полный пример, который записывает функции в файл TFRecord, затем считывает файл обратно и печатает проанализированные функции.

Теперь, когда мы рассмотрели структуру TFRecords, процесс их чтения прост:

  1. Прочтите TFRecord с помощью tf.TFRecordReader.
  2. Определите функции, которые вы ожидаете в TFRecord, используя tf.FixedLenFeature и tf.VarLenFeature, в зависимости от того, что было определено во время определения tf.train.Example.
  3. Разбирайте один tf.train.Example (один файл) за раз, используя tf.parse_single_example.

Рекомендации фильмов с использованием tf.train.SequenceExample

tf.train.SequenceExample - правильный выбор, если у вас есть функции, которые состоят из списков идентично типизированных данных и, возможно, некоторых контекстных данных.

Теперь возьмем немного другой набор данных, опять же из документации Tensorflow:

У нас есть ряд контекстных функций - Локаль, Возраст и Избранное - которые зависят от пользователя, а также список рекомендаций пользователя по фильму, который состоит из Название фильма, Рейтинг фильма и Актеры.

Данные выглядят очень похоже - в предыдущем примере у нас был набор функций, где каждая функция состояла из одного списка. Каждая запись в списке представляет одну и ту же информацию для разных фильмов, например рейтинг фильма. Это не изменилось, но теперь у нас также есть Actors, который представляет собой список актеров, сыгравших роль в фильме. Этот тип данных не может быть сохранен в tf.train.Example. Нам нужен другой тип структуры для этого типа данных, и Tensorflow предоставляет ее в виде tf.train.SequenceExample. В отличие от tf.train.Example, он хранит не список байтов, чисел с плавающей запятой или int64, а * список списков * байтов, чисел с плавающей запятой или int64, и поэтому подходит для нашего набора данных.

Более формально tf.train.SequenceExample имеет два атрибута:

  • context типа tf.train.Features
  • features_lists типа tf.train.FeatureLists

Данные из таблицы «Контекст» хранятся в context как tf.train.Features, как мы это делали для tf.train.Example. Данные из таблицы «Данные» - Название фильма, Рейтинг фильма и Актеры - хранятся каждый в отдельном tf.train.FeatureList.

tf.train.FeatureList имеет единственный атрибут feature, который ожидает список с записями типа tf.train.Feature. Сначала это может выглядеть как tf.train.Features, который также содержит несколько записей типа tf.train.Feature, но есть два больших отличия. Во-первых, все функции в списке должны иметь один и тот же тип внутреннего списка. Во-вторых, в то время как tf.train.Features - это словарь, содержащий (неупорядоченные) именованные функции, tf.train.FeatureList - это список, содержащий упорядоченные безымянные функции.

Типичным примером данных, хранящихся в tf.train.FeatureList, может быть временной ряд, где каждый tf.train.Feature в списке является временным шагом последовательности или списком актеров для нескольких разных фильмов.

tf.train.FeatureLists - это набор именованных экземпляров tf.train.FeatureList. Этот компонент имеет единственный атрибут feature_list, ожидающий словаря. Ключ dict - это имя tf.train.FeatureList, а значение - это сам tf.train.FeatureList.

tf.train.SequenceExample, как и tf.train.Example, является одним из основных компонентов для структурирования TFRecord. В отличие от tf.train.Example, у него есть два атрибута:

  1. context: этот атрибут ожидает тип tf.train.Features. Он содержит информацию, относящуюся к каждой из функций в атрибуте feature_list. Поведение контекста идентично атрибуту features в tf.train.Example.
  2. feature_lists: тип этого атрибута - tf.train.FeatureLists. Он содержит списки функций, где каждая функция снова представляет собой своего рода последовательные данные (например, временные ряды или кадры).

Вы можете найти больше информации о tf.train.SequenceExample в определении буфера протокола. В качестве примечания: хотя критерии соответствия существуют, они не обязательно применяются - например, feature_list_invalid из примера FeatureList не вызовет исключения.

Вот снова полный пример:

Чтение TFRecords на основе tf.train.SequenceExample работает так же, как и для tf.train.Examples. Единственная разница в том, что вместо одного набора функций нам нужно определить два: контекст и последовательность. Функции контекста работают точно так же, как показано ранее. Функции последовательности должны иметь тип tf.VarLenFeature или tf.FixedLenSequenceFeature и анализироваться с помощью tf.parse_single_sequence_example.

Заключение

Использование Tensorflow TFRecords - удобный способ поместить ваши данные в конвейер машинного обучения, но понимание всех деталей вначале может быть сложной задачей. Примеры в этом посте должны прояснить весь процесс и помочь вам начать.

Вы найдете все использованные мной фрагменты кода и многое другое на Github - не стесняйтесь копировать и использовать их как угодно.

Для создания этой истории я использовал ряд ресурсов:

  • Официальное руководство показывает пример кодирования того, как записывать данные изображения в TFRecord с помощью tf.train.Example.
  • В этом руководстве от Machine Learning Guru используется пример из официального руководства и он углубляется.
  • В этом сообщении StackOverflow показано, как использовать tf.train.SequenceExample.

Если вам понравилась эта история, нажмите кнопку 👏 и поделитесь ею, чтобы помочь другим найти ее! Подпишитесь на меня в Twitter / LinkedIn или на Mostly AI, если хотите узнать больше от меня.