Когда следует запускать модель в браузере: пример прогнозиста численности заключенных

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

В Urban Institute мы создаем модели прогнозирования, которые широкая аудитория может использовать для оценки будущих тенденций или потенциальных последствий изменений политики. Обычно мы либо заранее рассчитываем все возможные результаты и сохраняем их в браузере, либо запускаем модель на выделенном сервере. Но эти варианты были непрактичны для нашей последней версии Prison Population Forecaster. Вместо этого мы попробовали что-то новое и запустили модель прямо в браузере.

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

Prison Population Forecaster - это инструмент обработки данных, который позволяет пользователям исследовать, как изменения политики повлияют на численность тюрем штата и расходы на исправительные учреждения. Пользователи могут регулировать среднюю продолжительность тюремного заключения и количество новых госпитализаций, чтобы увидеть прогнозы численности населения и расходов на следующие 10 лет.

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

Наша первая мысль: давайте предварительно обработаем данные

Когда в 2015 году Центр политики в области правосудия Урбана разработал первую версию прогноза численности населения в тюрьмах, результаты модели хранились в одном файле данных. Когда пользователь посещал инструмент, моделировались просто из этого существующего файла данных. Это сработало хорошо, потому что было ограниченное количество возможных результатов. Первый прогнозист позволял пользователю выбирать между 15 штатами или федеральным правительством, 6 видами правонарушений или допущений, 2 изменениями политики и 4 вариантами сокращения для 768 возможных результатов.

Однако в обновленном выпуске мы запланировали 18 отдельных категорий нарушений. Для каждой категории пользователи могут увеличивать или уменьшать продолжительность пребывания и допуска с шагом в 1 процентный пункт в диапазоне от снижения на 100 процентов до увеличения на 100 процентов, что приводит к 201 потенциальному варианту выбора (включая ноль или отсутствие изменений в качестве опции. ). Кроме того, в отличие от предыдущей версии, пользователь может комбинировать скидки для разных типов правонарушений. Эти расчеты повторяются в 45 штатах, для которых исследовательская группа располагала данными и могла точно моделировать. Следовательно, чтобы предварительно обработать все возможные результаты и сохранить их в базе данных, нам пришлось бы сделать 201 ^ (18 * 2) или 8 * 10 ^ 1082 (8 с 82 нулями), вычисления для каждого состояния .

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

Это не сработает: давайте попробуем запустить его на сервере

Затем мы оценили, можем ли мы запустить модель на выделенном сервере. В этой структуре каждый раз, когда пользователь создавал собственный прогноз тюремной политики, мы отправляли выбранные переменные на сервер, который запускал модель в R, а затем возвращал результаты пользователю в браузере. Мы использовали эту настройку для других функций моделирования Urban Institute с использованием более сложных и проприетарных кодовых баз, таких как Калькулятор налоговых предложений.

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

1) Это может занять много времени. Чтобы обработать модель на сервере, браузер должен связаться с сервером, дождаться, пока сервер запустит модель, и дождаться, пока сервер вернет результаты. Обычно это занимает всего несколько миллисекунд и незаметно для большинства инструментов. Но сокращение нескольких миллисекунд для каждого запуска модели дает заметную экономию при многократном последовательном запуске модели. Поскольку у нас был дизайн, который позволял вносить несколько изменений переменных в быструю последовательность, мы решили запустить модель в браузере, где мы могли бы извлечь выгоду из этой экономии миллисекунд, чтобы обеспечить работу без задержек.

2) Есть дополнительные расходы. Использование выделенного сервера стоит денег. Один сервер может стоить не так дорого, но при резком увеличении трафика могут потребоваться дополнительные серверы, чтобы время ответа не превышало 10 секунд. Нам нужно будет проверить скорость наших вычислений и определить количество запросов, которые может обработать один сервер. Как только мы достигнем этого предела, наша инфраструктура должна будет быстро добавить дополнительные серверы или иметь несколько серверов, ожидающих обработки потенциальных скачков трафика.

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

Почему бы не запустить его в браузере?

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

Во-первых, в JavaScript ничто не защищает нас от того, чтобы наша модель была взята, разбита и повторно использована где-то еще.

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

Во-вторых, JavaScript быстро справляется с арифметикой, но не справляется со сложными статистическими функциями.

Многие модели на основе R используют встроенные статистические функции R. Эти функции основаны на сложных математических формулах, и их сложно воспроизвести в JavaScript. К счастью, предсказатель численности населения в тюрьмах использует простую арифметику. Средние за прошлые периоды продолжительности пребывания и ежегодных госпитализаций для каждой категории правонарушений прогнозируются с использованием простых взвешенных средних значений, предполагая, что последние годы, вероятно, будут предсказывать будущее. Изменение ожидаемой продолжительности пребывания или количества госпитализированных в соответствии с категорией правонарушения изменяет прогнозируемое количество людей по сравнению с базовым уровнем, не требуя каких-либо сложных статистических функций. Самая сложная функция - это использование встроенной тангенциальной функции JavaScript. Следовательно, модель прогнозирования сможет быстро работать в JavaScript.

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

Перевод модели с R на JavaScript казался простым, пока мы не протестировали модель, сократив продолжительность пребывания в одной категории нарушений на 100 процентов.

По логике, сокращение на 100 процентов всегда должно означать, что количество людей, лишенных свободы за указанное преступление, будет равно нулю. Вместо этого модель сообщала, что количество заключенных составит несколько миллиардов! Что случилось?

Оказывается, один конкретный сценарий, сгенерированный базовым методом округления JavaScript и его общей (но не точной) точностью, создал странную проблему округления. Доля людей, оставшихся в тюрьме по сравнению с предыдущим годом, рассчитывается по следующему уравнению:

Из-за того, как рассчитывалась продолжительность пребывания, JavaScript иногда мог выдавать нам небольшое отрицательное число, например -0.00000001, вместо истинного нуля, как это было бы в R или Stata. Таким образом, имея сверхмалое отрицательное число в знаменателе правой части этого уравнения, мы получили бы сверхмалое отрицательное число в левой части. Небольшое дополнительное условное кодирование, которое проверяло отрицательные значения для переменной length of stay, решило эту проблему, все из-за того, как JavaScript обрабатывал некоторые математические операции.

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

Выигрывает моделирование в браузере

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

- Дэниэл Вуд

Хотите узнать больше? Подпишитесь на информационный бюллетень Data @ Urban.