Что вам важнее в DL-проекте, удобство или производительность? Посмотрим на проблему глазами инженера-разработчика сложных систем с элементами искусственного интеллекта. Как типичный инструментарий в этой сфере справляется с обучением и выполнением?
![Photo by Cristina Gottardi on Unsplash Photo by Cristina Gottardi on Unsplash](https://habrastorage.org/getpro/habr/upload_files/63c/3aa/681/63c3aa681453012413f25928ac8f6b64.png)
В этой статье мы запустим пару нейросетей в MATLAB и сравним быстродействие ResNet с opensource-фреймворками. Так что, если хотите обсудить, в чем (кроме удобства) коммерческий фреймворк может выиграть у опенсорса, добро пожаловать!
С чего начинается MATLAB-нейросеть?
Наши заказчики охотно используют нейросети в качестве компонентов своих систем машинного зрения, предиктивной аналитики, анализа цифровых сигналов и во многих других областях. Мы часто пользуемся MATLAB, потому что он позволяет нам разработать и задеплоить сложную систему силами совсем небольшой команды, интегрировать все что нужно с другими тулбоксами MATLAB, чтобы за один присест создать и GUI для лабораторного стенда, и сайт, и подключить внешний код на Python, если надо.
Так вот, хоть мы и используем MATLAB в каждом ML/DL проекте, русская версия сравнения сред для глубокого обучения из Википедии не содержит даже строчки про MATLAB.
Это повод поговорить об этом фреймворке и сравнить его с остальными.
Если вы никогда не видели, как запустить нейронку в MATLAB, вот небольшой пример. Предположим, что вам нужно классифицировать эту картинку:
![Знакомьтесь, кот "Hello world" Знакомьтесь, кот "Hello world"](https://habrastorage.org/getpro/habr/upload_files/08e/197/44e/08e19744e8a8ad36ffdf0c28b819899a.png)
Какой код позволит нам это сделать?
net = resnet50(); % Открываем скачанную нейросеть
im = imread('cat.png'); % Открываем картинку
sz = net.Layers(1).InputSize; % Подгоняем картинку под нужную размерность
im = im(1:sz(1),1:sz(2),1:sz(3));
label = classify(net, im) % К какому классу относится наш объект?
И вот, что мы получим в ответ:
label =
categorical
Egyptian cat
Перед классификатором – кошка египетской породы, а перед нами – высокоуровневый фреймворк. Здесь можно делать fit-predict, а можно скачать и запустить готовую нейросеть. Поэкспериментируем с зашумленными изображениями.
% Получим пары “класс, уверенность”
predict_scores = predict(net, im);
[scores,indx] = sort(predict_scores, 'descend');
classNames = net.Layers(end).ClassNames;
classNamesTop = classNames(indx(1:5));
% Настраиваем область отображения
h = figure;
h.Position(3) = 2*h.Position(3); % Сократим ширину окна на 50%
ax1 = subplot(1,2,1);
ax2 = subplot(1,2,2);
% Выводим график
image(ax1,im);
barh(ax2,scores(5:-1:1))
xlabel(ax2,'Уверенность')
yticklabels(ax2,classNamesTop(5:-1:1))
ax2.YAxisLocation = 'right';
Завернём код в небольшой цикл и получим:
![На скорую руку проверяем чувствительность классификации к условиям съемки и детекции На скорую руку проверяем чувствительность классификации к условиям съемки и детекции](https://habrastorage.org/getpro/habr/upload_files/a38/cf6/8b7/a38cf68b7e8493948de0ec0c301c8856.png)
Совсем небольшой скрипт, а сколько возможностей. Многие популярные предобученные нейронки уже заложены в MATLAB Deep Learning Toolbox, а те, которых нет, – можно импортировать из ONNX, или из TensorFlow 2, или запустить через интерфейс с Python. Вы легко добавите модуль определения карты глубины на базе MiDaS или повысите разрешение изображения при помощи ESRGAN, и ваш робот будет постить в инстаграм 3D-шедевры в высоком разрешении.
![Эксперименты на кошках: карта глубины (MiDaS), наложенная на фотографию в 3D, а также детали увеличенного изображения (ESRGAN) Эксперименты на кошках: карта глубины (MiDaS), наложенная на фотографию в 3D, а также детали увеличенного изображения (ESRGAN)](https://habrastorage.org/getpro/habr/upload_files/d13/927/f48/d13927f48330115b367b816237b3d5ad.png)
Это далеко не весь функционал: в MATLAB можно рисовать графы сетей и делать контроль версий моделей, а можно просто обучать модели внутри блоков Simulink – достаточно лишь указать им датасет.
Это, конечно, хорошо, но будет ли сеть выполняться достаточно быстро на вашей платформе?
Покажите мне, где нужно ускорить
Самая большая часть времени в проекте уходит на понимание задачи и данных: никто не сможет вернуть время, потраченное на решение ненужной бизнесу задачи, а из мусорных данных получаются в основном мусорные модели.
Порассуждаем на основе диаграммы, которая является вольным переопределением CRISP-DM:
![Вольная трактовка процесса CRISP-DM Вольная трактовка процесса CRISP-DM](https://habrastorage.org/getpro/habr/upload_files/df8/af5/3bc/df8af53bc7ea1aeb78ddcdd1ceaba281.png)
Что трудно ускорить: левая часть схемы выражает околобизнесовые затраты. Ускорить ее может наличие у компании опыта, хорошие практики/шаблоны, продуктивное общение с заказчиком и коллегами, удобство фреймворка, контроль версий, всякие генераторы кода и документации, и так далее. Объективно сравнить фреймворки по этой части довольно трудно.
Что значительно легче ускорить: вся правая часть схемы недавно была прерогативой дата сайентистов, но за последние 10 лет хорошо автоматизировалась (как за счет демократизации отрасли, так и за счет прогресса методов и штук вроде AutoML). В этой статье ограничимся тем, что сравним скорость выполнения и немного скорость обучения нейросетей.
Чего мы ожидаем от высокоуровневого фреймворка в плане скорости разработки?
![](https://habrastorage.org/getpro/habr/upload_files/296/0df/cf8/2960dfcf84780d62f1f7038ea5d45754.png)
Скоростного выполнения модели
Фреймворк должен оптимизировать код модели, а также позволять легко ее трансформировать и сравнивать производительность разных версий
![](https://habrastorage.org/getpro/habr/upload_files/a8a/4b8/164/a8a4b8164c6b5770846b91123a504658.png)
Автоподбора модели и легкого перебора гиперпараметров
Графический редактор графов, отладчик интерфейсов (между слоями нейросети, например), скрипты, AutoML, учебные материалы и шаблоны, дружелюбное сообщество
![](https://habrastorage.org/getpro/habr/upload_files/849/3e7/80d/8493e780d5b8a510020fc7af4f8d126e.png)
Простого и удобного инструментария для работы с данными
Эксплоративный анализ, визуализация, удобный GUI, рефакторинг, версионирование, создание отчетов
![](https://habrastorage.org/getpro/habr/upload_files/1ef/b9e/bb0/1efb9ebb03207f0a0a14950494d23e52.png)
Развёртки и поддержки проекта
Сборка проекта, интеграция всех источников данных и внешних компонентов, распаковка проекта на всех необходимых целевых платформах, симуляция и отладка в любых сценариях
Сравниваем скорость на ResNet-50
Что ж, значит в MATLAB тоже есть нейронки, отлично – не придется вручную писать обратное распространение ошибки. Что дальше? Недавно сотрудник MathWorks David Willingham представил доклад, где он сравнивает быстродействие трех фреймворков: MATLAB, PyTorch и Tensorflow.
![](https://habrastorage.org/getpro/habr/upload_files/085/c6e/bc9/085c6ebc90eb4ccb2e0a6f9db495adfc.png)
David Willingham
MathWorks, Deep Learning Product Manager https://www.mathworks.com/matlabcentral/profile/authors/106350
Первое представление о различиях можно подсмотреть в уже упомянутой таблице в Википедии. Здесь фреймворки отличаются только лицензией и поддержкой библиотек для параллельных вычислений (OpenCL и OpenMP), что для нас второстепенно.
![Фреймворки, которые мы будем сравнивать (укороченная версия исходной таблицы) Фреймворки, которые мы будем сравнивать (укороченная версия исходной таблицы)](https://habrastorage.org/getpro/habr/upload_files/16a/308/fd2/16a308fd2202fd0af62b1c209a13dd44.png)
Сейчас мы изучим результаты сравнения на инференсе, но для начала сравним скорость обучения ResNet-50. Приходится же иногда переобучаться под новый датасет или обучать кастомную архитектуру.
![Длительность одной эпохи обучения ResNet 50 Длительность одной эпохи обучения ResNet 50](https://habrastorage.org/getpro/habr/upload_files/a94/28d/4b7/a9428d4b783c018d2a364fe537b65858.png)
Итак, для сравнения взята стандартная сетка для классификации изображений – ResNet, вариант с 50 слоями. По некоторым бенчмаркам, обучение на ImageNet 1000 на GPU NVIDIA M40 в течение 90 эпох должно занимать 14 дней, по другим – выходит что A100 отработает 50 эпох за десяток часов (AIME). На обучении наши инструменты показывают примерно одинаковые результаты. Может быть, и правда все упирается в железо.
Зато, когда сеть уже обучена, ее производительность будет зависеть от массы факторов, которые интересно изучить. Ее же нужно запускать для каждого пользователя и для каждого примера (фотографии, нового измерения с датчика, речевого сигнала…), на любой платформе, от сервера до бортовых вычислителей автономного робота. Пересылка через всякие интерфейсы и обращение к базам данных может отнять львиную долю времени...
Сравним выполнение моделей. Сначала – быстродействие на CPU.
Быстродействие на CPU
Давайте сравним запуск на CPU нейросети ResNet в таком сценарии: вы работаете на встраиваемой платформе, где нет ускорителей, или в системе, где нет CUDA. Например, сюда входит очень многое из робототехники, от институтских омни-тележек до космических спутников.
Оказывается, код нашей сетки выполняется в MATLAB на CPU чуть быстрее, чем в других фреймворках.
![ResNet 50 на CPU ResNet 50 на CPU](https://habrastorage.org/getpro/habr/upload_files/37e/113/185/37e113185f6b481ec4b2d18a3f37d90d.png)
Оказывается, код нашей сетки выполняется в MATLAB на CPU чуть быстрее, чем в других фреймворках. Бенчмарк для CPU построен на Intel Xeon 3.6 GHz – такие солидные частоты редко встречаются на борту. На более приземленном CPU, возможно, код будет вести себя слегка иначе.
![ResNet 50 + MATLAB Coder ResNet 50 + MATLAB Coder](https://habrastorage.org/getpro/habr/upload_files/073/9fe/a0b/0739fea0b16e2c79b44433fe37b80d71.png)
А что, если скомпилировать все при помощи MATLAB Coder? Сеть в MATLAB выполняется в 2 раза быстрее, чем на Tensorflow и в 3 раза быстрее, чем на PyTorch. Да, это не самая тяжелая нейросеть, и хорошо изученная к тому же, есть много приемов оптимизации, которые MathWorks могли заложить в предобученную сеть, включенную в MATLAB.
Если у вас робототехнический проект с CPU на борту, то MATLAB – в принципе единственный коробочный продукт, который позволяет обучать модели и запускать их на любой встраиваемой платформе.
Сохранится ли эффект на GPU? Давайте узнаем.
Быстродействие на GPU
Использование GPU позволяет добиться феноменальных скоростей обучения или выполнения нейросетей... при запуске на сравнительно больших объемах данных.
![Батч размером 1 на CPU Батч размером 1 на CPU](https://habrastorage.org/getpro/habr/upload_files/b22/f00/adc/b22f00adc75730a48fc91bb032bd506f.png)
При прогоне через нейросеть на GPU одного примера за один проход (батч размера 1), если запускать сеть через скрипт, MATLAB есть над чем поработать, судя по графикам, 1 батч можно просто запускать на CPU, разницы не будет. Я обещал обсудить ситуации, когда MATLAB проигрывает – это как раз тот случай.
Пересылка из общей памяти в память GPU занимает много времени, и одновременная обработка данных (в виде батча) выгоднее, если в батче больше данных. Но, поскольку код модели и небольшой набор данных все-таки должны поместиться в памяти видеокарты, максимальный размер батча тоже ограничен.
![Батч размером 32 на GPU Батч размером 32 на GPU](https://habrastorage.org/getpro/habr/upload_files/435/dbf/b27/435dbfb276f876dcad3061d9190bdd27.png)
Если в батче 32 примера, то все гораздо лучше. Теперь мы хорошо загружаем видеокарту и все фреймворки демонстрируют примерно одинаковый прирост быстродействия относительно запуска на CPU. Но это не все, можно ускориться. В MATLAB для этого есть два способа скомпилировать нейронку для GPU.
![Код для GPU в форме MEX-функции Код для GPU в форме MEX-функции](https://habrastorage.org/getpro/habr/upload_files/a18/643/fd0/a18643fd0393be6dd2deb9299796ebdf.png)
MEX-функции – это оболочки для внешних программ. Они ведут себя в точности так же, как функции MATLAB/Simulink, но могут попутно с выполнением кода MATLAB вызывать внешнюю программу, C/C++ или иной код. Инструментарий MEX генерирует C++ код для GPU, но не требует лицензии на GPU Coder для задач предсказания (predict).
Упакованный в MEX код нейросети ResNet выполняется на GPU почти в 2 раза быстрее на одном изображении (на одном батче), чем в PyTorch или TensorFlow.
![Код для GPU из MATLAB GPU Coder Код для GPU из MATLAB GPU Coder](https://habrastorage.org/getpro/habr/upload_files/802/95a/e20/80295ae20d11d2bad9d020153f9fe992.png)
Второй способ для получения оптимизированного кода – GPU Coder. Это уже специальный генератор кода для GPU. Чтобы его применить, нужно всего лишь переключить одну галочку в настройках генератора кода (она называется Generate GPU code), после чего мы получаем встраиваемый оптимизированный CUDA-код, не требующий какого-то специального окружения для запуска на целевой платформе.
Автоматически оптимизированная для TensorRT нейросеть выполняется очень быстро – почти в 3 раза быстрее, чем та же сеть на GPU в Tensorflow или PyTorch. И это на одном батче.
Заключение
![Ускорение ResNet 50 в MATLAB за последние полгода Ускорение ResNet 50 в MATLAB за последние полгода](https://habrastorage.org/getpro/habr/upload_files/1fc/7e3/b35/1fc7e3b35bb280dd18f5209ead6e1323.png)
В своём докладе MathWorks отмечают, что за полгода выполнение ResNet было ускорено почти в 2 раза. Видимо, как в ядре MATLAB, так и в архитектуре нейросети, ещё есть что оптимизировать. Это вселяет оптимизм – будем ожидать, что разработчики и в следующих версиях сохранят такой темп улучшений.
В общем и целом, MATLAB отвечает всем нашим ожиданиям от высокоуровневого фреймворка в том что касается разработки систем с элементами искусственного интеллекта (список критериев – выше). Нам он облегчает и работу с данными, и подбор алгоритмов классического машинного обучения, и подключение глубоких нейросетей, и разработку собственных топологий, если нужно. Так что мы используем его в проектах с ИИ для самых разных заказчиков.
Пожалуйста, расскажите нам в комментариях о своем опыте работы с нейросетями в MATLAB, о бенчмарках или предпочтениях по фреймворкам. Желаем всем очень производительных AI-проектов, выполненных в комфортной среде!