В конечном счете в каждом нетривиальном проекте машинного обучения появляется масса ошибок и внутренними инструментами, которые невозможно сопровождать. Эти инструменты — обычно patchwork из Jupyter Notebooks и приложения Flask — сложны в развертывании, требуют логики архитектуры «клиент-сервер» и плохо интегрируются с конструкциями МО, такими как сессии Tensorflow GPU.

Впервые я заметил это в Carnegie Mellon, затем в Berkeley, Google X и во время создания автономных роботов в Zoox. Эти инструменты обычно создавались в качестве небольших Jupyter notebooks: инструмент калибровки сенсора, приложение сравнения симуляции, приложение выравнивания лидара, инструмент воспроизведения сценария и так далее.

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

Рабочий процесс создания приложений инженерами машинного обучения.

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

Рабочий процесс команды разработчиков по созданию приложений с чистого листа.

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

Таким образом, мы вернулись к созданию собственных инструментов, развертыванию приложений Flask, написанию HTML, CSS и JavaScript, а также к попыткам контролировать все версии, начиная от notebooks и заканчивая таблицами стилей. Затем я и мой старый друг из Google X, Тиаго Тейшейра, задумались: можно ли сделать процесс создания инструментов таким же простым, как написание сценариев Python?

Мы хотели предоставить инженерам машинного обучения возможность создавать приложения без помощи команды разработчиков. Эти внутренние инструменты должны возникать естественным образом в рабочем процессе МО. Их написание должно походить на обучение нейронной сети или проведение специального анализа в Jupyter! В то же время мы хотели сохранить гибкость фреймворка приложений. В целом и общем мы пытались добиться следующего:

Процесс сборки приложения Streamlit.
Шаг 1: Добавьте несколько вызовов API в существующий сценарий Python.
Шаг 2: Продемонстрируйте свой инструмент с отличной производительностью

Совместно с бета-сообществом, включающим инженеров из Uber, Twitter, Stitch Fix и Dropbox, в течение целого года мы работали над созданием Streamlitбесплатного open-source фреймворка приложений для инженеров МО. Основные принципы Streamlit:

#1: Использование сценариев Python. Приложения Streamlit — это простые сценарии, которые запускаются сверху вниз и не содержат скрытого состояния. Анализировать код можно с помощью вызовов функций. Если вы знакомы с написанием сценариев Python, то сможете написать приложения Streamlit. Например, вывод информации на экран выглядит следующим образом:

import streamlit as st
st.write('Hello, world!')

#2: Обработка виджетов в качестве переменных. В Streamlit нет обратных вызовов! Каждое взаимодействие просто перезапускает сценарий сверху вниз. В результате такого подхода получаем действительно чистый код:

import streamlit as st

x = st.slider('x')
st.write(x, 'squared is', x * x)
Интерактивное приложение Streamlit в трех строках кода.

#3: Повторное использование данных и вычислений. Streamlit представляет примитивный тип кеша, который ведет себя как постоянное, неизменяемое по умолчанию хранилище данных, предоставляя приложениям Streamlit возможность повторно использовать информацию. Например, следующий код загружает данные только один раз из проекта Udacity Self-Driving Car, в результате чего получается простое и быстрое приложение:

import streamlit as st
import pandas as pd

# Reuse this data across runs!
read_and_cache_csv = st.cache(pd.read_csv)

BUCKET = "https://streamlit-self-driving.s3-us-west-2.amazonaws.com/"
data = read_and_cache_csv(BUCKET + "labels.csv.gz", nrows=1000)
desired_label = st.selectbox('Filter to:', ['car', 'truck'])
st.write(data[data.label == desired_label])
Результат выполнения примера st.cache.

Streamlit работает следующим образом:

  1. Весь сценарий запускается с нуля для каждого взаимодействия с пользователем.
  2. Streamlit присваивает каждой переменной актуальное значение с учетом состояний виджета.
  3. Благодаря кэшированию Streamlit пропускает избыточные выборки данных и вычисления.

Процесс в картинках:

Пользовательские события запускают Streamlit для повторного запуска сценария с нуля. Во время каждого запуска сохраняется только кэш.

Звучит интригующе? Тогда попробуйте Streamlit прямо сейчас! Просто запустите:

$ pip install --upgrade streamlit 
$ streamlit hello

   Теперь Streamlit доступен в браузере.

   Local URL: http://localhost:8501
   Network URL: http://10.0.1.29:8501

Веб-браузер с указанием на локальное приложение Streamlit откроется автоматически. Если этого не произошло, просто нажмите на ссылку.

Чтобы увидеть больше примеров, подобных этой фрактальной анимации, запустите streamlit hello из командной строки.

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

В Streamlit можно с легкостью создать подобный инструмент. В этой демонстрации Streamlit можно выполнять семантический поиск по всему набору фото-данных беспилотного автомобиля Udacity, визуализировать метки наземной истины и запускать нейронную сеть (YOLO) в реальном времени из приложения [1].

Эта 300-строчная демонстрация Streamlit сочетает в себе семантический визуальный поиск и интерактивный вывод нейронной сети.

Все приложение — это полностью автономный 300-строчный сценарий Python, большая часть которого представлена кодом машинного обучения. Оно содержит лишь 23 вызова Streamlit. Вы можете запустить его прямо сейчас!

$ pip install --upgrade streamlit opencv-python
$ streamlit run
https://raw.githubusercontent.com/streamlit/demo-self-driving/master/app.py

Эти простые идеи предоставляют ряд важных преимуществ:

Приложения Streamlit — это чистые файлы Python. Таким образом, со Streamlit можно использовать любой редактор и отладчик.

Мой любимый шаблон для написания приложений Streamlit с VSCode слева и Chrome справа.

Сценарии на чистом Python с легкостью работают с Git и другими системами контроля версий, включая коммиты, pull requests, проблемы и комментарии. Поскольку основным языком Streamlit является Python, все преимущества этих инструментов предоставляются бесплатно ?.

Приложения Streamlit — это сценарии Python, с помощью которых можно с легкостью управлять версиями с Git.

Streamlit предоставляет среду программирования в режиме реального времени. Просто нажмите Always rerun (Постоянный перезапуск) при обнаружении Streamlit изменений исходного файла.

Нажмите “Always rerun” для включения живого программирования.

Кэширование упрощает настройку вычислительных конвейеров. Удивительно, но связывание кэшированных функций автоматически создает эффективные вычислительные конвейеры! Рассмотрим этот код, адаптированный из демонстрации Udacity:

import streamlit as st
import pandas as pd

@st.cache
def load_metadata():
    DATA_URL = "https://streamlit-self-driving.s3-us-west-2.amazonaws.com/labels.csv.gz"
    return pd.read_csv(DATA_URL, nrows=1000)

@st.cache
def create_summary(metadata, summary_type):
    one_hot_encoded = pd.get_dummies(metadata[["frame", "label"]], columns=["label"])
    return getattr(one_hot_encoded.groupby(["frame"]), summary_type)()

# Piping one st.cache function into another forms a computation DAG.
summary_type = st.selectbox("Type of summary:", ["sum", "any"])
metadata = load_metadata()
summary = create_summary(metadata, summary_type)
st.write('## Metadata', metadata, '## Summary', summary)

Конвейер выглядит следующим образом: load_metadata → create_summary. При каждом запуске сценария Streamlit пересчитывает только то подмножество конвейера, которое требуется для получения правильного ответа.

Для повышения производительности приложений Streamlit пересчитывает только то, что необходимо для обновления UI.

Streamlit разработан для графических процессоров. Streamlit обеспечивает прямой доступ к примитивам машинного уровня, таким как TensorFlow и PyTorch, и дополняет эти библиотеки. Например, в этой демонстрации в кэше Streamlit хранится весь NVIDIA celebrity face GAN [2]. Благодаря этому подходу выводы выполняются практически мгновенно при передвижении ползунка пользователем.

Приложение Streamlit демонстрирует модель NVIDIA celebrity face GAN [2] с использованием Shaobo Guan’s TL-GAN [3].

Streamlit — это бесплатная open-source библиотека, а не проприетарное веб-приложение. Приложения Streamlit можно обслуживать локально. Streamlit также можно запустить локально на ноутбуке без подключения к интернету! Более того, существующие проекты могут постепенно принимать Streamlit.

Несколько способов постепенного принятия Streamlit.

Мы рассмотрели лишь некоторые из возможностей Streamlit. Одним из наиболее интересных его аспектов является легкость объединения примитивов в сложные приложения, похожие на сценарии.

Блок-схема компонентов Streamlit.

Читайте также:


Перевод статьи Adrien Treuille: Turn Python Scripts into Beautiful ML Tools

Предыдущая статьяКонкурентность и параллелизм в Golang. Горутины.
Следующая статьяКак организовать код в Python