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

1 день

Итак, сегодня вы начали свою новую работу в качестве программиста Python в самом новом и популярном стартапе в Силиконовой долине. Задача состоит в том, чтобы революционизировать то, как мы воспринимаем социальные сети! Давайте создадим следующий Pintrest, Twitter, Instagram, Snapchat или Facebook, чтобы достичь вечной славы.

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

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

Вооружившись Python 3.x и несколькими мощными библиотеками (OpenCV, scikit-image, numpy и Keras для последних достижений глубокого обучения), вы чувствуете себя хорошо подготовленными. Вы открываете свой любимый текстовый редактор и хакаете:

Работа выполнена! Кусок пирога. Но вы ввели цикл for! Не беспокойтесь, для этого и нужны циклы for (без каламбура). В конце концов, для того, чтобы зацикливаться на вещах. Но потерпите меня, все быстро испортится.

День 2

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

Идеально. Проверьте код в системе контроля версий, закройте User Story. Время кофе!

День 3

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

Опять же, это легко. Вы просто добавляете оператор «println» в начало цикла for, и Стивен с радостью обновляет свои фильтры Splunk и оповещения о мониторинге:

Время от времени кто-то из тестировщиков заносит в список ИСТОЧНИКОВ неправильные ссылки (да как они смеют?). Конвейер ломается, данные находятся в несогласованном состоянии и обработка останавливается. Вам явно нужна какая-то форма обработки ошибок. Вы полагаете, что широкий подход Try/Catch All-Approach должен помочь:

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

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

День 4

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

После некоторых экспериментов вы получаете MVP (минимально жизнеспособный продукт). Реализация выглядит так:

Он использует реализацию scikit-learn KMeans для кластеризации цветов в общие группы (в данном случае 8).

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

  • Вы должны убедиться, что извлекли цвета, прежде чем делать изображение в оттенках серого (порядок обработки становится актуальным).
  • Должны ли вы делать выборку доминирующих цветов до или после изменения размера изображения? В этом случае эффект, вероятно, незначителен, и вы решите пойти на последнее. Теперь у вас есть две операции изменения размера в вашем коде, одна в цикле for, а другая скрыта в функции «dominant_colors».

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

Теперь конвейер обрабатывает почти 1 миллион изображений в день без тегов.

Пометка изображения влечет за собой дополнительные накладные расходы на этапе обработки (~ 500 мс на изображение). Обработка всех изображений, загруженных за один день, займет 5,7 дня (в однопоточном режиме).

Очевидно, что это не сработает, но масштабируйтесь любым мыслимым образом!

Каковы основные проблемы решения?

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

  • Смешивание ввода-вывода с логикой обработки.
  • Запутанная логика обработки (несколько операций над данными изображения) вместе с порядком обработки (последовательный).
  • Переплетение ввода-вывода с порядком обработки (оттенки серого перед миниатюрой или наоборот?).

Итак, каковы шаги назад к здравомыслию?

Решение вышеперечисленных проблем — хороший первый шаг, но переход от однопоточной нераспределенной системы к масштабируемой системе обработки никогда не бывает легким. Вот несколько идей, которые мы рассмотрим во второй части:

  • Отделите обработку от ввода/вывода. например путем разделения обработки изображений и чтения/записи на диск на отдельные функции (или даже записи в отдельные системы хранения).
  • Внедрите параллельную или асинхронную обработку.
  • Создавайте модульные тесты для изолированного тестирования логики обработки.

Полный исходный код этой части 1 находится на Github.

Все еще любопытно?

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

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