Эта статья является частью серии статей о Fovea, программном обеспечении для взаимодействия в реальном времени от Fractal Media.

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

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

Наша система реального времени состоит из четырех этапов:

  1. Сбор данных отслеживания взгляда зрителя запускается через Ядро зрачка на ноутбук,
  2. Видеопрезентация запускается на дисплее,
  3. Данные отслеживания взглядапериодически анализируются нейронной сетью (т. е. моделью) и генерируется прогноз.
  4. Прогноз изменяет видео на дисплее.

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

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

Стоит отметить, что Ray не поддерживал вычисления с отслеживанием состояния до недавнего времени, только недавно сделав возможными приложения, подобные нашему.

Требования

  1. Установлен Pupil Core и все зависимости,
  2. Модель Keras или Tensorflow,
  3. Сериализованный протокол, который передает данные в модель (т. е. вы передаете данные отслеживания глаз в определенных точках вашего скрипта для обработки моделью),
  4. Пошаговое руководство полезно для ознакомления с типами объектов Ray.

Установка и выделение памяти для Ray

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

pip install -U ray

В зависимости от того, насколько ресурсоемким является ваше приложение, вам может потребоваться ограничить объем памяти, который использует Ray. Мы обнаружили, что следующий параметр инициализации работает хорошо. Добавьте следующее в основной файл класса плагина (например, shared_modules/your_plugin/your_plugin.py).

import ray
ray.init(object_store_memory=100000000)

Актеры

Основным преимуществом Ray для тех, кто реализует модели Tensorflow или Keras, являются субъекты с выделенной памятью.

Мы формализуем их в отдельном файле Python, хранящемся в каталоге плагинов. Назовите его multi_ray.py.

import ray
import tensorflow as tf
# here you can import numpy, models, optimizers, etc. whatever you need to get your model to run 

@ray.remote
class Simulator(object):
    def __init__(self):
        self.model = self.load_model("../models/")
    def simulate(self, numerical=None, categorical=None):
        if numerical is None:
            prediction = 'no input'
        else:
            prediction = self.model.predict({'numeric_input': numerical})
        return prediction
    def load_model(self, model_dir):
        with open('../models/num_scaler.pkl', 'rb') as f:
            num_scaler = pickle.load(f)
        def scale_x(x):
            # reshape values
            nsamples, nx, ny = x.shape
            values = np.reshape(x, (-1, ny))
            scaled = num_scaler.transform(values)
            scaled = np.reshape(scaled, (nsamples, nx, ny))
            return scaled
        # root mean squared error (rmse) for regression
        def rmse(y_true, y_pred):
            return backend.sqrt(backend.mean(backend.square(y_pred - y_true), axis=-1))
        with open(model_dir + 'saved_data.pkl', 'rb') as f:
            X_test, y_test = pickle.load(f)
        self.X_te_numerical = scale_x(X_test)
        tfmodel = tf.keras.models.load_model(model_dir + 'model.h5', custom_objects={'rmse': rmse})
        return tfmodel

Здесь мы инициализируем актора с отслеживанием состояния, который загружает модель. Наиболее важной структурой здесь является tfmodel, но мы оставили здесь некоторые дополнительные параметры на случай, если вы настроили объекты модели Keras, чтобы показать, что вы действительно можете вызывать функции (например, масштабирование или вычисление ошибок для некоторых загруженных значений). ) при первоначальной загрузке модели в отдельное хранилище памяти, что является важной функцией при инициализации интерактивных систем.

Обратите внимание, что вы также можете определить использование ЦП и ГП при объявлении удаленного субъекта (вместо функции ray.init()).

@ray.remote(num_cpus=2, num_gpus=0.5)
class Simulator(object):
    # see above

Теперь мы будем импортировать и использовать симулятор в нашем основном файле плагина, создав одного актера. Вы должны поместить это перед определением класса плагина.

from .multi_ray import *
simulators = [Simulator.remote() for _ in range(1)]
class Your_Plugin(Plugin):
    # your original code here

Отправка и получение данных от Актера

Оператор .remote актора позволяет нам вызывать его методы. В нашем упрощенном примере мы будем отправлять числовые данные через функцию актера simulate из класса Your_Plugin. Мы оставляем здесь двусмысленность, если вы хотите отправить данные нескольким акторам, и напишите пример, который будет отправлять некоторые данные из fixation_buffer актору.

self.ref_time = time.time()
if time.time() - self.ref_time > 10:
    results = ray.get([s.simulate.remote(self.fixation_buffer) for s in simulators])

self.fixation_buffer относится к некоторому буферу данных, связанных с глазами, которые мы храним в нашем плагине. Периодически (в данном примере раз в 10 секунд) мы можем отправлять некоторый буфер данных в функцию simulate, которая будет работать параллельно и независимо от вашего основного потока.

Поскольку мы загрузили вашу модель в память при инициализации симуляторов, прогнозы генерируются намного быстрее, чем загрузка и прогнозирование модели на каждом интервале!

Вывод

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