Многие люди, которые хотят обучить модель машинного обучения на приличном количестве табличных данных, сталкиваются со следующей ситуацией:

  • данные находятся в хранилище данных SQL
  • предварительная обработка данных не может выполняться в памяти, даже если масштабируется на несколько машин
  • высокая скорость ввода-вывода имеет решающее значение для успешного обучения модели
  • параметры модели должны оставаться согласованными между обучением модели и выводом

К счастью, сообщества TensorFlow и Apache Beam разработали именно те инструменты, которые помогут вам. В этой статье я представлю краткое введение в TensorFlow Transform, формат файла tfrecord и конвейеры Apache Beam, а также ссылки, по которым вы можете продолжить эти понятия. Но самое главное, я научу вас, как использовать и интегрировать их все — и всего с парой строк кода.

Комплексное решение, описанное в этой статье, предполагает, что ваши обучающие данные хранятся в BigQuery в Google Cloud и предназначены для обучения модели TensorFlow. Хотя представленный подход идеально подходит для этой установки, вы также сможете адаптировать его к вашей конкретной инфраструктуре.

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

Входные данные

Итак, для начала предположим, что ваши данные хранятся в таблице BigQuery в соответствии со следующей схемой таблицы:

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

Чтение вложенных данных из BigQuery в Apache Beam

Чтение данных из BigQuery в Beam так же просто, как вызов ReadFromBigQuery и предоставление ему входной таблицы:

Параметр method задает метод чтения, используемый для получения ваших данных. По умолчанию ReadFromBigQuery запускает запрос на экспорт и сохраняет содержимое таблицы в промежуточном файле. Вместо этого мы запросили ReadFromBigQuery чтение из хранилища BigQuery напрямую, чтобы предотвратить этот промежуточный шаг. Имейте в виду, что использование API хранилища влечет за собой дополнительные расходы.

Для тех, кто не знаком с Apache Beam: возможно, вы заметили, что SDK Beam python перезаписал оператор канала («|»). Такое объединение операций позволяет применять преобразования к выходным данным соответствующего предыдущего шага. Beam создает граф вычислений в фоновом режиме и выполняется только после вызова pipeline.run(). Если вы хотите немного поиграть, вы можете добавить следующую строку для вывода промежуточных результатов на консоль.

Также обратите внимание, что мы используем «Прямой» раннер — это исполнитель конвейера Beam, который будет выполнять ваш конвейер на вашем локальном компьютере.

Почему использование Beam — хорошая идея

Использование Beam делает ваш конвейер простым, переносимым и масштабируемым. — Вы видели это: с помощью всего пары строк кода мы считываем данные непосредственно из нашего источника данных в BigQuery и выполняем их на нашей локальной машине. Выполнив всего несколько дополнительных шагов настройки, мы могли бы отложить выполнение того же конвейера (включая все вычисления, которые мы придумаем позже) с использованием выбранного нами исполнителя — будь то Google Cloud Dataflow, Apache Spark, Apache Флинк и многие другие. Таким образом, мы сможем масштабировать вычисления на столько машин, сколько захотим, делая вычисления высоко масштабируемыми.

С Beam вы «написали один раз, запускаете где угодно»: ваш конвейер предварительной обработки не только становится переносимым, что позволяет вам легко переключаться между исполнителями и, следовательно, помогает избежать эффекта блокировки. Кроме того, он становится унифицированным, что позволяет использовать один и тот же конвейер как для пакетной, так и для потоковой обработки.

Преобразование данных и сохранение преобразования для обслуживания

Данные, прочитанные из хранилища BigQuery, предоставляются вам в виде словаря полей и могут анализироваться построчно. Это позволяет нам написать простую функцию Python, которая преобразует строки таблицы в желаемый формат вывода.

Применение этого преобразования к нашим данным — это всего лишь одна строка кода.

Затем мы направляем каждую преобразованную строку таблицы в TensorFlow Transform для эффективной предварительной обработки. Сначала определим функцию преобразования. Обратите внимание, что длина записей событий, предоставляемых parse_table_row, может различаться в разных примерах. Поэтому мы применяем функцию tft.sparse_tensor_to_dense_with_shape, чтобы дополнить все записи до одинаковой длины.

Поскольку вывод parse_table_row имеет формат экземпляр dict (альтернативы см. в разделе Начало работы с TFT), нам также необходимо предоставить объект dataset_metadata.DatasetMetadata в качестве входных данных для TensorFlow Transform.

Аргумент feature_spec, предоставленный для DatasetMetadata, такой же, как и для создания tf.train.Example. Например, см. этот учебник по TensorFlow для справки. В нашем случае feature_spec будет следующим.

Он также определяет ключи словаря, используемые в transform_fct. Определение tf.io.SparseFeature автоматически создаст разреженный тензор TensorFlow на основе двух столбцов BigQuery nested_field_1_4_3 и nested_field_1_4_4.

Почему вы должны использовать TensorFlow Transform (TFT)

«Вывод tf. Преобразование экспортируется в виде графика TensorFlow, который можно использовать как для обучения, так и для обслуживания. Использование одного и того же графика как для обучения, так и для обслуживания может предотвратить перекос, поскольку на обоих этапах применяются одни и те же преобразования». - Документация по преобразованию TensorFlow

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

При использовании TFT для решения этой задачи вы получаете сразу несколько преимуществ: во-первых, в нем есть все общие преобразования, которые вы можете придумать, уже реализованные и его API прост в использовании. Во-вторых, перед выполнением преобразований ваши данные будут преобразованы в собственные типы данных TensorFlow и собраны в пакеты с размерами пакетов, оптимизированными для вашей вычислительной среды. Это повышает эффективность вычислений. В-третьих, как только все параметры вашего преобразования будут скомпилированы, вы можете сохранить преобразование, а затем восстановить его в виде графа TensorFlow. Таким образом, при обучении нейронных сетей с помощью TensorFlow вы можете объединить граф преобразования (рассчитанный до обучения) с графом модели (рассчитанный во время обучения)и построить единый оптимизированный расчетный график для вашей среды вывода.

Но есть еще кое-что: что делать, если ваши данные велики? Что, если он настолько огромен, что даже после распространения ваших вычислений на все доступные вам машины данные не поместятся в память? Или что, если вы просто не хотите распределять свои рабочие нагрузки на более чем 10 000 компьютеров?

Именно эти вопросы привели меня к TFT. При использовании TFT размер ваших данных больше не должен вас беспокоить: для любого преобразования, требующего вычисления статистики по всему набору данных, TFT разбивает вычисления на два этапа: анализ и шаг преобразования, в результате которого ваши данные прошли два. Каждый проход выполняется за итерации, которые умещаются в памяти, а параметры, необходимые для выполнения преобразований на втором этапе, объединяются после первого прохода.

Запись преобразованных данных в файлы tfrecord

Теперь, когда мы вычислили преобразованные выходные данные вместе с параметрами функции преобразования, пришло время сохранить наши результаты.

Почему вы должны использовать файлы tfrecord в качестве входных данных для вашей модели TensorFlow

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

  1. Чтение с диска выполняется быстро, а чтение двоичных форматов еще быстрее
  2. Чтение с диска можно легко распределить между машинами
  3. Чтение TFRecords для последующего использования в TensorFlow требует минимальных усилий по реализации.

Формат основан на протокольных буферах, независимом от языка и платформы расширяемом механизме Google для сериализации структурированных данных. Таким образом, гарантируется оптимизированный размер хранилища и скорость чтения. При хранении ваших данных в файловой системе вы также можете легко распределить свои данные на несколько осколков файлов. Таким образом, при распределении рабочих нагрузок по обучению машинному обучению на несколько компьютеров нет необходимости передавать фактические данные с одного компьютера на другой. Вместо этого каждая машина может читать свой собственный файл непосредственно из своего источника. Чтение из сегментированных файлов TFRecord и распределение рабочих нагрузок также легко выполняются с помощью tf.data.Dataset API. На самом деле существует отдельный класс tf.data.TFRecordDataset, который поможет вам настроить конвейер данных на основе разделенных файлов TFRecord.

Чтение преобразованных данных из файлов tfrecord для обучения модели

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

Теперь мы готовы использовать набор данных, распределить его по любому количеству машин и выполнить обучение модели.

Воссоздание сохраненной функции преобразования для обслуживания модели

Теперь, когда мы успешно обучили нашу модель, пришло время обсудить, как мы собираемся запустить ее в производство. Одной из наших первоначальных проблем было то, как мы можем гарантировать, что модель ведет себя идентично между обучающей и обслуживающей средами.

Чтобы обеспечить совместимость, мы хотим, чтобы параметры модели и предварительной обработки были одинаковыми в обеих средах. С помощью TFT легко воспроизвести те же самые преобразования, которые использовались в нашем конвейере Apache Beam.

Только эти две строки кода соберут все параметры, вычисленные во время преобразования обучающих данных, и создадут из них слой TensorFlow. Этот слой теперь можно легко применить к любым новым входным данным.