среда, 3 октября 2018 г.

TensorFlow: введение в Estimators API

В этом посте мы кратко осветим tf.estimator (оценщик) - высокоуровневое TensorFlow API, которое значительно упрощает программирование машинного обучения. Estimators заключают в себе следующие действия:

  • тренировка
  • оценка
  • прогнозирование
  • экспорт для сохранения

Можно использовать предсозданные Estimators либо писать собственные кастомные Estimators. Все Estimators - предсозданные или кастомные - это классы, основанные на tf.estimator.Estimator классе.

Преимущества использования Estimators

Estimators предоставляют следующие преимущества:

  • Можно исполнять, основанные на Estimators, модели на локальном хосте или в распределенном мульти-серверном окружении без изменения модели. Более того, можно исполнять, основанные на Estimators, модели на CPU, GPU, или TPU без записи модели.
  • Estimators упрощают обмен реализациями между разработчиками моделей.
  • Можно разрабатывать модели, реализующие самые последние достижения, с высокоуровневым интуитивно понятным кодом. Вкратце, намного проще создавать модели с Estimators, чем с низкоуровневыми TensorFlow API.
  • Estimators сами постороены на tf.keras.layers, которые упрощают кастомизацию.
  • Estimators сами создают графы.
  • Estimators предоставляют безопасный распределенный тренировочный цикл, который контролирует как и когда:
    • постороить граф
    • инициализировать переменные
    • загружать данные
    • обрабатывать исключения
    • создавать файлы контрольных точек и восстанавливать при провалах
    • сохранять резюме для TensorBoard

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

Предсозданные Estimators

Предсозданные Estimators позволяют работать на более высоком концептуальном уровне, чем основные TensorFlow API. Больше не нужно беспокоиться о создании вычислительного графа или сессий, поскольку Estimators делают все это сами. То есть предсозданный Estimator создает и управляет tf.Graph и tf.Session объектами. Более того предсозданные Estimators позволяют экспериментировать с различными архитектурами моделей, выполняя только минимальные изменения в коде. tf.estimator.DNNClassifier, например, - это предсозданный Estimator класс, который тренирует классификационные модели, основанные на тесносвязанных, опережающих нейронных сетях.

Структура программы предсозданных Estimators

TensorFlow программа основанная на предсозданном Estimator обычно состоит из четырех этапов:

  1. Запись одной или нескольких функций импортирования набора данных. Например, можно создать одну функцию для импорта тренировочного набора и другую функцию для импорта тестового набора. Каждая функция импортирования набора данных должна возвращать два объекта:

    • словарь, в котором ключи - это имена свойств, а значения - это Tensors (или SparseTensors), содержащие соответствующие данные свойств
    • Tensor, содержащий одну или несколько меток

    Например, следующий код иллюстрирует основной скелет для функции ввода:

    def input_fn(dataset):
       # манипулирование датасетом, извлечение словаря свойств и метки
       ...  
       return feature_dict, label
    

  2. Определение колонок свойств. Каждый tf.feature_column идентифицирует имя свойства, его тип, и любую предобработку ввода. Например, следующий код создает три колонки свойств, которые хранят цельночисловые или нецельночисловые данные. Первые две колонки свойств просто идентифицируют имя свойства и тип. Третья колонка свойства также определяет лямбда программу, которая будет вызываться для масштабирования сырых данных:

    # Определяем три числовые колонки свойств.
    population = tf.feature_column.numeric_column('population')
    crime_rate = tf.feature_column.numeric_column('crime_rate')
    median_education = tf.feature_column.numeric_column(
                   'median_education',
                   normalizer_fn=lambda x: x - global_education_mean)
    

  3. Создание инстанса соответствующего предсозданного Estimator. Например, вот пример создания инстанса предсозданного Estimator, называющегося LinearClassifier:

    # Создаем инстанс оценщика (estimator), передавая колонки свойств
    estimator = tf.estimator.LinearClassifier(
        feature_columns=[population, crime_rate, median_education],
        )
    

  4. Вызов метода тренировки, оценки, или вывода (метод производственного использования). Например, все Estimators предоставляют тренировочный метод, который тренирует модель.

    # my_training_set - это функция, созданная на первом шаге
    estimator.train(input_fn=my_training_set, steps=2000)
    

Преимущества предсозданных Estimators

Предсозданные Estimators воплощают лучшие практики, предоставляя следующие преимущества:

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

Если не использовать Estimators, то необходимо самому реализовывать все вышеперечисленное.

Кастомные Estimators

Сердце любого Estimator - предсозданного или кастомного - это функция модели, которая представляет собой метод, который строит граф для тренировки, оценки, и прогнозирования. При использовании предсозданного Estimator, задействуется уже реализованная функция модели. При использовании кастомного Estimator необходимо самому писать функцию модели.

Рекомендуемый рабочий поток

Рекомендуется использовать следующий рабочий поток:

  1. Предположим подходящий предсозданный Estimator существует - используем его для построения первой модели и используем ее результаты для определения базовой линии.
  2. Создаем и тестируем весь пайплайн, включая целостность и надежность данных с этим предсозданным Estimator.
  3. Если доступны подходящие альтернативные предсозданные Estimators, тогда выполняем эксперименты для определения, который предсозданный Estimator производит лучшие результаты.
  4. Возможно дальше улучшаем модель, строя собственный кастомный Estimator.

Создание Estimators из Keras моделей

Можно конвертировать существующие Keras модели в Estimators. Это позволяет Keras модели получить доступ к преимуществам Estimator, таким как распределенная тренировка. Вызываем tf.keras.estimator.model_to_estimator как в следующем примере:

# Создаем инстанс Keras inception v3 модели
keras_inception_v3 = \ 
  tf.keras.applications.inception_v3.InceptionV3(weights=None)

# Компилируем модель с оптимизатором, функцией потери, 
# и метриками, которые необходимы для тренировки
keras_inception_v3.compile(optimizer=tf.keras.optimizers.SGD(
                               lr=0.0001, momentum=0.9),
                          loss='categorical_crossentropy',
                          metric='accuracy')

# Создаем Estimator из компилированной Keras модели.
# Следует отметить, что состояние первоначальной keras модели
# сохраняется в созданном Estimator.
est_inception_v3 = tf.keras.estimator.model_to_estimator(
                              keras_model=keras_inception_v3)

# Используем произведенный Estimator как любой другой Estimator.
# Во-первых, восстанавливаем имя(имена) ввода Keras модели,
# так мы можем использовать их как имя(имена) колонок свойств
# фунции ввода Estimator:
keras_inception_v3.input_names  # выдает: ['input_1']

# Как только у нас есть имя(имена) ввода, 
# мы можем создать функцию ввода,
# например, для ввода в формате numpy ndarray:
train_input_fn = tf.estimator.inputs.numpy_input_fn(
    x={"input_1": train_data},
    y=train_labels,
    num_epochs=1,
    shuffle=False)

# Для тренировки вызываем функцию тренировки Estimator:
est_inception_v3.train(input_fn=train_input_fn, steps=2000)

Следует отметить, что имена колонок свойств и метки keras estimator приходят из соотвествующей скомпилированной keras модели. Например, ключи имен ввода для train_input_fn выше могут быть получены из keras_inception_v3.input_names, и аналогично, прогнозируемые выводные имена могут быть получены из keras_inception_v3.output_names.

Подробней о TensorFlow Estimators читайте в последующих постах.