My Notes From Spark+AI Summit 2020 (Application-Agnostic Talks)
Юджин Ян делится конспектами с конференции Spark+AI Summit 2020 (24–26 июня), сосредоточившись на докладах, не привязанных к конкретным приложениям. Ник Пентрит из IBM рассказал о четырёх способах повышения эффективности моделей: улучшение архитектуры (MobileNet V1 с 4 млн параметров против 24 млн у Inception V3), обрезка весов, квантизация и дистилляция (DistilBERT, TinyBERT), включая каскад моделей рекомендательной системы ленты Instagram. Шон Оуэн из Databricks привёл 6 шагов масштабирования обучения — от GPU и ранней остановки до Petastorm и Horovod — снизив время обучения с 60 до 9 минут. Джо Спайсак из Facebook представил экосистему PyTorch (TorchElastic, TorchServe), а Йешвант Виджаякумар из Adobe объяснил вероятностные структуры данных (фильтр Блума, HyperLogLog, count-min sketch) как моноиды. Цзяньнэн Ли из Workday разобрал стоимость ввода-вывода broadcast join против sort-merge join в Apache Spark: при большем числе ядер быстрее SMJ, а при значительно большей левой таблице — BHJ.
Мои заметки с Spark+AI Summit 2020 (доклады, не привязанные к приложениям)
[ machinelearning deeplearning survey ] · чтение на 11 мин
Spark+AI Summit 2020 прошёл 24–26 июня. Я пока прошёл лишь половину, но он уже наполнен жемчужинами практических знаний.
Однако понять, какие доклады посетить, бывает непросто. Например, 24 июня было почти 100 сессий, не считая ключевых выступлений и форумов. ctrl+f по следующим словам даёт такие совпадения:
«beginner»: 4 «intermediate»: 56 «advanced»: 7 «sponsored»: 24 «ask me anything»: 6
У большинства людей нет времени, чтобы перебрать все эти доклады и посетить их. Поэтому я привожу в порядок свои заметки и делюсь кратким обзором отдельных докладов. Эта статья посвящена докладам, не привязанным к конкретным приложениям; следующая будет о специфичных для приложений.
Содержание
Масштабирование глубокого обучения через уменьшение моделей Как (не) масштабировать глубокое обучение за 6 шагов Масштабирование AI-исследований до продакшена с PyTorch Вероятностные структуры данных для людей Улучшение broadcast join в Apache Spark
Масштабирование глубокого обучения через уменьшение моделей (24 июня)
Nick Pentreath, ведущий инженер в IBM Center for Open Data and AI, делится четырьмя способами повысить эффективность обучения и работы моделей.
Улучшения архитектуры. Inception V3 использует стандартный свёрточный блок и имеет 24 миллиона параметров. Напротив, MobileNet V1 использует поканальные (depth-wise) свёрточные блоки и имеет всего 4 миллиона параметров. Однако при этом страдает и точность (78,8% против 70,9% на ImageNet).
Тенденции в глубоком обучении меняются. Раньше CNN-модели были нацелены на точность (продвижение выше по оси Y). В последнее время фокус сместился к точности и эффективности (сохранение низких значений по оси X и небольшого размера моделей).
Изначально модели двигались в верхний правый угол; теперь акцент сделан на верхний левый и сохранение их небольшими
Google также рассказал о EfficientNet, которая использует поиск нейронных архитектур (neural architecture search) для нахождения оптимальных архитектур. Однако поиск подходящей архитектуры потребляет много ресурсов.
Обрезка модели (pruning). Многие веса в нейронной сети не используются. Вот пример того, как можно обрезать до половины весов в Inception V3 и MobileNet V1 с минимальной потерей точности на ImageNet.
Половину весов можно обрезать с минимальной потерей производительности
Квантизация. Мы можем снизить числовую точность весов, группируя значения по корзинам (то есть уменьшая разрядность с 32 бит до 16 бит, сохраняя при этом гистограммное распределение).
Распределение весов можно сохранить и при пониженной точности
Квантизация бывает двух видов: после обучения (post-training) и с учётом обучения (training-aware). Квантизация после обучения позволяет избежать повторного обучения модели, но при этом есть некоторое падение точности (77,2% против 63,7%). Квантизация с учётом обучения сложнее, зато потеря точности меньше (77,5% против 70,9%)
Дистилляция модели. Из примеров с обрезкой ясно, что наши крупные нейронные сети обычно переизбыточно параметризованы. Один из способов их уменьшить — обучить меньшую модель (ученика) имитировать предсказания большей модели (учителя).
Дистиллированную модель (ученика) можно обучать на выходе модели-учителя и на истинных метках
Меньшую модель можно обучать как на «мягких» метках учителя, так и на истинных метках. Мягкие метки обычно имеют более высокую энтропию и несут больше информации при меньшей дисперсии. Поэтому меньшую модель можно обучать на меньшем объёме данных и с более высокой скоростью обучения.
В некоторых случаях дистиллированная модель оказывается сильнее исходной, обеспечивая более высокую точность и эффективность (что дополнительно подтверждает, что большинство моделей переизбыточно параметризованы). Среди успешных дистиллированных моделей — DistilBERT и TinyBERT.
Рекомендательная система ленты Instagram использует стек моделей, первым слоем которого является дистиллированная модель. Вот как это работает на этапе инференса:
Первый проход: дистилляционная модель, которая имитирует следующие два этапа и отбирает 150 кандидатов. Второй проход: лёгкая нейронная сеть (с полным набором плотных признаков) сужает список до 50 кандидатов. Финальный проход: глубокая нейронная сеть (с полным набором плотных и разреженных признаков) выбирает топ-25 кандидатов.
Они рассказали, как обучается дистилляционная модель: сначала они записывают входные данные (кандидатов) и соответствующий выход от моделей-учителей. Затем дистилляционная модель обучается на записанных данных, чтобы воспроизводить результаты, оптимизируя ранжирующую функцию потерь NDCG по выходу модели-учителя.
Дополнительное чтение:
Слайды «Scaling Up Deep Learning By Scaling Down» Benchmark Analysis of Representative Deep Neural Network Architectures To prune, or not to prune: exploring the efficacy of pruning for model compression Deep compression: Compressing deep neural networks with pruning, trained quantization and Huffman coding. Distilling the Knowledge in a Neural Network
Как (не) масштабировать глубокое обучение за 6 шагов (24 июня)
Sean Owen, ведущий архитектор решений в Databricks, делится 6 советами о том, как масштабировать обучение моделей глубокого обучения, в следующем порядке:
Эти шаги используют 10%-ю выборку данных для быстрого экспериментирования и итераций (Шаг 0 — «Используй выборку и работай в памяти»):
Используй GPU: облако упрощает доступ к ним. Используй раннюю остановку (early stopping): в приведённом примере это сократило время обучения с 60 до 18 минут при лучшей точности (76% против 76,7%). Используй большие размеры батчей, чтобы загрузить GPU по максимуму: это ещё сократило время обучения до 9 минут при схожей точности (76,3%)
Эти шаги используют полный набор данных для оптимизации производительности модели:
Используй Petastorm для итерации по большим данным: Petastorm был разработан Uber для итеративной подачи данных на основе Parquet в фреймворки глубокого обучения (изначально TensorFlow, теперь поддерживается и PyTorch) почти так же эффективно, как в памяти. Хотя мы используем в 10 раз больше данных, время одной эпохи увеличивается лишь в 11 раз. Точность поднимается до 83%. Используй несколько GPU: большинство современных фреймворков глубокого обучения позволяют использовать несколько GPU с минимальными изменениями кода. Используй Horovod на нескольких машинах: если нескольких GPU на одной машине недостаточно, рассмотри Horovod, который помогает масштабировать обучение на GPU по нескольким машинам.
Дополнительное чтение:
How (Not) To Scale Deep Learning in 6 Easy Steps Meet Horovod: Uber’s Open Source Distributed Deep Learning Framework for TensorFlow (Теперь работает и с PyTorch, ура!)
Масштабирование исследований до продакшена с PyTorch (26 июня)
Joe Spisak, руководитель продукта PyTorch в Facebook, делится знаниями о PyTorch и его экосистеме, которая помогает упростить обучение и развёртывание моделей в масштабе.
Чтобы уменьшить размер модели и требования к вычислениям, PyTorch имеет встроенную обрезку и квантизацию моделей. Facebook годами развёртывает квантизованные модели, и это помогает с инференсом в масштабе, особенно на устройствах.
Чтобы обучать модели в масштабе, есть TorchElastic. Он позволяет запускать распределённые задачи PyTorch отказоустойчивым и эластичным образом. Это гарантирует, что задачи не прерываются, когда машина(ы) выходят из строя или когда вашу AWS spot-инстанс перебивают по цене.
Чтобы развёртывать модели в масштабе, есть TorchServe, разработанный совместно с AWS. Он упрощает лёгкое обслуживание моделей, предоставляет обработчики по умолчанию для распространённых задач, версионирование моделей для A/B-тестирования и т. д.
Дополнительное чтение:
Introducing TorchServe: a PyTorch model serving framework TorchElastic on GitHub TorchServe on GitHub
Вероятностные структуры данных для людей (25 июня)
Yeshwanth Vijayakumar, руководитель проекта/архитектор в Adobe, рассказывает о трёх вероятностных структурах данных для быстрых запросов по большим наборам данных. Эти структуры работают, потому что они являются моноидами. Стоп, а что такое моноиды?
Вот упрощённое объяснение. Моноиды обладают следующими свойствами:
Их можно комбинировать с другими значениями (того же типа), образуя новые значения (того же типа): int(1) + int(2) = int(3). Операции ассоциативны (порядок не важен): 1 + (2 + 3) = (1 + 2) + 3. У них есть нейтральный элемент: 1 + 0 == 1, где 0 — нейтральный элемент
Фильтры Блума (Bloom filters) проверяют принадлежность вероятностным образом (например, set.exist(item)). Их можно использовать для ответа на вопросы вроде: видел ли пользователь этот товар раньше?
Если результат — False, то item точно отсутствует в set. Если результат — True, есть вероятность, что элемента в множестве всё же нет.
HyperLogLog подсчитывает число различных элементов в множестве (например, set.count_distinct()). Это можно использовать для ответа на вопросы вроде: сколько уникальных пользователей купили товары A, B и C?
Поскольку HyperLogLog — моноид, мы можем подсчитать число уникальных пользователей для каждого товара, а затем выполнить объединение по всем товарам.
Count-min sketch можно представить как таблицу частот событий в потоке данных. Это можно использовать для ответа на вопросы вроде: сколько товаров продал этот продавец сегодня?
Он использует хеш-функции для отображения событий в частоты — поэтому он использует сублинейное пространство вместо O(n). Однако, поскольку он использует хеш-функцию, он может завышать счёт некоторых событий из-за коллизий.
Дополнительное чтение:
Улучшение broadcast join в Apache Spark (25 июня)
Jianneng Li, инженер-программист в Workday, делится практическими наблюдениями и результатами экспериментов по оптимизации broadcast join.
Всегда ли broadcast join быстрее (если данные помещаются в память)? Не обязательно. У broadcast join есть значительные накладные расходы, в том числе:
Сбор транслируемой (broadcasted) таблицы (на драйвере) Построение хеш-таблицы (на драйвере) Отправка хеш-таблицы исполнителю (executor) Десериализация хеш-таблицы (на исполнителе)
В чём разница по стоимости ввода-вывода (I/O) между (обычным) sortMergeJoin и broadcastHashJoin? Допустим, у нас есть две таблицы: A — большая таблица, а B — меньшая таблица, которая будет транслироваться. Также у нас есть n ядер.
Для sortMergeJoin (SMJ) суммарная стоимость I/O равна 3(A/n) + 3(B/n):
По A: Чтение (A/n), Сортировка, Запись (A/n) По B: Чтение (B/n), Сортировка, Запись (B/n) Join: Чтение (A/n), Чтение (B/n), Соединение
Для broadcastHashJoin (BHJ) суммарная стоимость I/O равна: A/n + B/n + 2B:
По B: Чтение (B/n), Построение хеш-таблицы, Запись (B) Join: Чтение (A/n), Чтение (B), Соединение
Упрощая вышесказанное, разница в стоимости между SMJ и BHJ составляет 2(A + B)/n - 2B. Это можно ещё упростить, рассматривая A как кратное B: если в A 10 миллионов строк, а в B — 2 миллиона строк, то B = 1 и A = 5. Таким образом, разница в стоимости между SMJ и BHJ составляет (A+1)/n.
Когда (A+1)/n меньше 1 (то есть у вас много ядер), SMJ будет быстрее. Но если (A+1)/n намного больше 1 (то есть ваша левая таблица намного больше правой, транслируемой таблицы), то быстрее будет BHJ.
В эксперименте, где A = 60 миллионов, а B = 15 миллионов (то есть A+B = 5), мы видим, что при более чем 5 ядрах SMJ показывает лучшие результаты (то есть меньше времени). В противном случае лучше BHJ.
Когда число ядер превышает 5, sort-merge join работает лучше.
Аналогично, при постоянном n (числе ядер), равном 18, мы видим, что BHJ превосходит SMJ, когда A+B превышает 20.
По мере того как левая таблица A растёт относительно транслируемой таблицы B, broadcast-hash join работает лучше.
Однако при автоматической трансляции (через настройку порога broadcast) убедитесь, что меньшая таблица находится справа. Даже когда меньшая таблица слева, Spark попытается транслировать большую таблицу справа, что приведёт к неэффективности.
Workday сейчас работает над BHJ на стороне исполнителя (в Spark сейчас BHJ на стороне драйвера), что показало колоссальное улучшение производительности broadcast (SPARK-17556). Надеюсь, это скоро вольют в основную ветку.
Были и другие отличные сессии по оптимизации Spark, но у меня не хватило времени привести в порядок заметки по ним. Я рекомендую:
Fine Tuning and Enhancing Performance of Apache Spark Jobs (25 июня): IBM рассказывает, что они сделали, чтобы сократить задачу с 4+ часов до 35 минут. How to Performance-Tune Apache Spark Applications in Large Clusters (25 июня): Uber делится приёмами по улучшению хранилища, CPU/времени выполнения, эффективности вычислений и памяти. Optimize Large Scale Graph Applications Using Spark with 4-5x Performance (25 июня): PayPal рассказывает о том, как улучшить масштабируемость больших графовых вычислений и оптимизацию продакшен-задач. Memory Optimization and Reliable Metrics in ML Pipelines at Netflix (26 июня): Netflix рассказывает о том, как они оптимизировали использование памяти для задачи, делясь подходами от перепартиционирования и прохода по промежуточным датафреймам до собственного управления памятью.
Дополнительное чтение:
Performance Tuning: Converting sort-merge join to broadcast join What is the Difference between Broadcast hash join and Broadcast Nested loop join? SPARK-17556 Executor side broadcast for broadcast joins
С нетерпением жду применения этих практических знаний
Практические знания с Spark+AI Summit 2020 бесценны. Мне не терпится применить их в своей работе над spark-пайплайнами и глубоким обучением. На следующей неделе я поделюсь некоторыми специфичными для приложений докладами с конференции.
Spark+AI Summit 2020 был эпичным. Несколько отличных докладов👇:Improving Broadcast Joins In Apache Spark (25 июня)• broadcastHashJoin не всегда быстрее; построение хеш-таблицы имеет накладные расходы• Больше ядер: sortMergeJoin работает лучше• Больше левая таблица: broadcastHashJoin работает лучше— Eugene Yan (@eugeneyan) July 1, 2020
P.S. Я пропустил какие-нибудь хорошие сессии? Дайте знать в комментариях ниже =)
Если это было вам полезно, пожалуйста, цитируйте эту статью так:
Yan, Ziyou. (Jun 2020). My Notes From Spark+AI Summit 2020 (Application-Agnostic Talks). eugeneyan.com. https://eugeneyan.com/writing/notes-from-sparkai-summit-application-agnostic/.
или
@article{yan2020spark, title = {My Notes From Spark+AI Summit 2020 (Application-Agnostic Talks)}, author = {Yan, Ziyou}, journal = {eugeneyan.com}, year = {2020}, month = {Jun}, url = {https://eugeneyan.com/writing/notes-from-sparkai-summit-application-agnostic/} }
Присоединяйтесь к 11 800+ читателям, получающим обновления о машинном обучении, RecSys, LLM и инженерии.