Усовершенствуйте свои инструменты с помощью функций на базе ИИ во многих продуктах JetBrains
Можно ли встроить Maven в нейронную сеть?
Мы попробовали, и это собирается. Мы скомпилировали часть системы принятия решений инструмента сборки в стиле Maven в фиксированную матрицу весов и использовали ее для сборки реальной Java-библиотеки. Результат совпадает с Apache Maven байт в байт. Чистая сборка с тестами заняла в 1,49 раза больше времени, чем та же логика, написанная на Python (доверительный интервал 95% от 1,4 до 1,54, 30 парных запускoв).
Каждый Java-разработчик видел, как Maven думает. Он разрешает зависимости, компилирует, тестирует и упаковывает. Большая часть этого времени уходит на javac и JUnit, но сквозь весь этот процесс проходит небольшой придирчивый фрагмент логики, который решает, что делать дальше. Какая версия библиотеки побеждает, когда два модуля не согласны друг с другом. Какие файлы отправляются компилятору и с какими флагами. Останавливает ли сборку упавший тест.
Мы хотели узнать, может ли этот фрагмент жить внутри нейронной сети. Не модель, обученная угадывать, что Maven обычно делает дальше: такой тип модели прав в большинстве случаев, а инструмент сборки, который прав в большинстве случаев, сломан. Нам нужна была сама логика принятия решений, скомпилированная в веса, чтобы сеть выдавала абсолютно правильный ответ или отказывалась отвечать.
Видео в начале этой публикации демонстрирует именно такую сеть. Каждая из ее 26 626 полос представляет собой одну строку таблицы весов (модель nmvn-exact-v2, объясняется в разделе об удешевлении), высота полосы показывает, как часто эта строка выполнялась во время одной сборки ZXing, а яркая точка воспроизводит реальные этапы этой сборки, шаг за шагом. Все, что определяет ход сборки, находится там.
От программы к таблице весов
Фокус заключается в следующем Handwired: вы можете написать программу, а затем установить веса сети так, чтобы сеть и была этой программой. Мы написали небольшой совместимый с Maven контроллер сборки на ограниченном подмножестве Python и скомпилировали его в таблицу из 29 625 × 7 чисел плюс 7 382 ячейки констант (это первая версия, v1; в следующем разделе таблица уменьшается до 26 626 строк, которые вы видите выше). Никакого обучения, никакого градиентного спуска: ноль шагов оптимизатора.
Его работа представляет собой цикл. На каждом шаге сеть ищет одну строку своей таблицы с помощью двух матричных умножений, выполняет арифметические операции, закодированные в этой строке, над небольшим файлом регистров и записывает результат обратно в память. Сеть не может открывать файлы или запускать javac. Когда ей это нужно, она записывает запрос в фиксированный слот своей памяти, а тонкий мост переносит запрос наружу и записывает исходный ответ обратно. Мост ничего не решает. Каждый выбор проистекает из весов.
байты pom.xml + результаты на данный момент Фиксированная таблица весовОдна строка на шаг,два матричных умножения для ее получения,без обучения Запрос«прочитать этот файл»«запустить javac с…» Мостдиск, javac, JUnit,bnd, zip исходный результат записывается обратно в память сети, и цикл продолжается
Тестируемым объектом был ZXing 3.5.3, библиотека штрихкодов: ее родительский проект, а также модули core и javase, собранные с помощью clean package и запущенными тестами.
Собирает ли оно проект на самом деле?
Да. Созданные им JAR-файлы совпадают с файлами Apache Maven байт в байт, они были собраны внутри песочницы, где Maven не может запуститься, сеть отключена, а прочитать ни Python-версию логики, ни собственные результаты Maven невозможно. Все 549 восходящих тестов были запущены и успешно пройдены, а свежесобранные JAR-файлы корректно кодировали и декодировали QR-коды в 27 проверках из 27.
519пройденных вариантов сборки, написанных вручную, каждый из которых проверен на реальном Maven
10 000пройденных сгенерированных вариантов проектов
33других небольших проекта собраны корректно с теми же весами
4 796 191шаг сети для одной полной сборки ZXing
Две проверки убедили нас, что работа действительно происходит на уровне весов. Версии сети для CPU и GPU сделали ровно одинаковые 1 731 запрос в том же порядке для полной сборки. А когда мы удалили или повредили файл весов, сборка вообще не происходила.
Посмотрите на сборку в действии
Слева: контроллер в виде обычного кода на Python. Справа: тот же контроллер в виде нейронной сети. Оба собирают ZXing по-настоящему, один за другим на одном и том же Mac, воспроизводясь на реальной скорости.
Цена вопроса
Это работает медленнее во всех измеренных нами сценариях. Python выполняет логику контроллера напрямую; сеть тратит целый раунд матричной арифметики на каждую крошечную инструкцию, и одна сборка ZXing требует 4 796 191 таких раундов.
В отношении одних только решений сеть сильно отстает. При полной сборке разрыв сокращается примерно до полутора раз, потому что большую часть времени занимает javac и JUnit, а обе версии используют одни и те же инструменты. Запуск сети на GPU сделал все только хуже, а не лучше. Программа, выполняющая инструкции последовательно одну за другой, не дает GPU задач для параллельного выполнения.
Так что это вовсе не более быстрый инструмент сборки. Это инструмент сборки, который можно представить в виде тензора.
Так что это вовсе не более быстрый инструмент сборки. Это инструмент сборки, который можно представить в виде тензора.
Удешевление без затрагивания сети
Время выполнения примерно равно количеству шагов, умноженному на стоимость одного шага, поэтому мы подсчитали, куда уходят шаги. Мы воспроизвели полную сборку ZXing в симуляторе на уровне инструкций и подсчитали каждую выполненную им инструкцию. Из 4 796 191 шага версии v1 652 773 (14%) просто копировали значение из одного регистра в другой, а еще 553 333 (12%) загружали константу или возвращались в начало цикла. Это компиляторный «клей», а не логика сборки.
Поэтому мы оставили сеть в покое и исправили компилятор. Теперь результаты попадают напрямую в регистр, который в них нуждается, константы передаются внутри использующей их инструкции, условия компилируются напрямую в ветвления, а проверка условий цикла происходит в конце, а не путем перехода в начало. Машина, ее граф шагов и ядро GPU остались прежними. Изменилась только таблица чисел, став при этом меньше.
на 23%меньше шагов сети для полной сборки ZXing (4 796 191 → 3 676 728)
на 10%меньше строк в таблице весов (29 625 → 26 626)
идентичные решения: при получении записанных входных данных версии v1, версия v2 делает те же 1 731 запрос в том же порядке на CPU и GPU
2 из 2критериев корректности повторно пройдены версией v2 (те же наборы тестов, сборка в изолированной среде, побайтово идентичные JAR-файлы)
GPU получает больший прирост, так как ее затраты зависят почти исключительно от количества шагов: на решения ушло всего 27,97 с для v1 и 21,61 с для v2 (на 23% меньше), что близко к сокращению количества шагов. Она по-прежнему остается самым медленным движком.
Мы повторно забили всю цепочку проверки корректности на новых весах: каждый набор тестов, изолированную сборку, которая должна выдавать побайтово идентичные JAR-файлы, негативные тесты и воспроизведение на CPU/GPU. Сокращение реально, но скромно там, где это имеет значение. Java-инструментарий по-прежнему занимает большую часть полной сборки, поэтому оптимизация доли сети влияет на конечный результат меньше, чем предполагает количество шагов.
Дело не только в Maven
Чтобы убедиться, что компилятор не настроен скрытно под одну программу, мы дали ему кое-что не связанное с этим: решатель лабиринтов (поиск в ширину, programs/maze/maze_nml.py). Он скомпилировался в 279 строк весов. Небольшое приложение одновременно запускает классическую и нейронную версии в виде отдельных процессов и отрисовывает каждую ячейку сразу же, как только программа сообщает о ней.
На трех разных лабиринтах размером 171×121 чистый Python, отладочная оболочка Python, нейронный запуск на CPU и нейронный запуск на GPU выдали идентичные последовательности событий: каждую посещенную ячейку в том же порядке, с теми же расстояниями. Первый лабиринт потребовал 2 572 288 шагов сети. Нейронная сеть на CPU работала в 161–168 раз дольше чистого Python, а на GPU — в 791–812 раз дольше (измерения производились собственным таймером каждой программы, по одному запуску на лабиринт, так что эти данные следует считать приблизительными).
Итак, это медленнее. Есть ли от этого хоть какая-то польза?
Справедливый вопрос. Мы задали его себе тоже. Если вам нужна более быстрая сборка, нет: продолжайте использовать Maven. И более мощный GPU ее не спасет, потому что сеть выполняет по одной инструкции за раз, и ничто в контроллере сборки не может быть распределено по тысячам ядер.
Однако скорость никогда не была самой интересной частью. В итоге мы получили нейронную сеть, где каждый вес имеет известное значение, а это большая редкость. Вот в чем, по нашему мнению, заключается ее ценность (начиная с того, в чем мы уверены больше всего).
Ответы для тех, кто препарирует нейросети
Исследования в области интерпретируемости пытаются понять, что делает сеть, основываясь только на ее весах. Самая сложная часть — оценить правильность ответа, поскольку для обученной модели никто не знает истину. Эта сеть поставляется вместе с истиной. За исключением стартовой заглушки из семи строк, каждая из ее 26 626 строк принадлежит известной функции среди 249 функций контроллера, и мы знаем, что делает каждая из них. Поэтому мы можем указать на строки do_surefire — части, которая запускает тесты и решает, приведет ли сбой к остановке сборки. Если какой-то инструмент заявляет, что нашел «цепь разрешения зависимостей», вы можете это проверить. Собранные вручную тестовые сети обычно представляют собой маленькие игрушки. Эта сеть выполняет реальную работу на реальной кодовой базе, и мы считаем это ее лучшим применением.
Точные компоненты внутри моделей, которые делают предположения
Модель, которая выбирает правильную версию библиотеки в 99% случаев, ошибается один раз на каждые сто сборок. Скомпилированные веса — это способ поместить точную подпрограмму в ту же форму, что и у обученной модели: те же тензоры, то же время выполнения, то же железо. Уточним: мы еще не объединяли ее с обученной моделью. Это следующий эксперимент, а не результат. Тем не менее, это то направление, которое кажется нам наиболее захватывающим.
Логика принятия решений, которую можно хешировать
Вся политика представляет собой один файл с числами. Перенесите ее с CPU на GPU, и она примет те же 1731 решение в том же порядке; подайте на вход записанную сборку, и она воспроизведем ее с абсолютной точностью. Именно так мы сравнивали решения v1 и v2 решение за решением в разделе об удешевлении. Вы можете сравнить этот файл (diff), подписать его и доказать, что конкретная сборка получена именно с его помощью. Справедливости ради, обычный код с файлом блокировки решает эту задачу большую часть времени. Тензорная версия добавляет то, что компонентом, запускающим политику, является один и тот же фиксированный цикл поисков и арифметических операций для любой программы, которую вы в нее компилируете, а меньшее время выполнения означает меньший объем кода, которому приходится доверять.
Еще один аргумент в ее пользу: затраты уменьшаются, когда решения представляют собой тонкую прослойку поверх тяжелых инструментов. При полной сборке ZXing javac и JUnit выполняют большую часть работы, поэтому здесь сеть обходится примерно в полтора раза дороже времени Python, а не в двадцать с лишним раз. Вспомогательная логика вокруг дорогостоящих шагов окупается той же скромной ценой.
Плохой инструмент для
- Более быстрых сборок или всего, где имеют значение миллисекунды
- Добавления новых GPU для решения проблемы
- Замены Maven
Стоит присмотреться для
- Тестирования инструментов интерпретируемости на сети с известным ответом
- Точных подпрограмм, живущих рядом с обученными моделями
- Логики принятия решений, которую можно хешировать, воспроизводить и сравнивать
То, на что мы не претендуем
- Это не весь Maven. Она обрабатывает одну сборку (clean package) одного реального проекта, причем Enforcer, Checkstyle, Javadoc и исходные JAR-файлы пропущены. Подписание, развертывание и все остальное, что запускается только на этапе verify, остаются за рамками. Плагины не являются нейронными: javac, JUnit, bnd и zip работают как обычные программы.
- Это не машинное обучение. Веса были скомпилированы из программы, а не получены путем обучения. Мы не пробовали использовать обученную версию и ожидаем, что она потерпит неудачу на проектах, которых раньше не видела.
Проверьте нашу работу
Весы, время выполнения и полные результаты доступны на Hugging Face по адресу shirman/neural-maven: методология, все одиннадцать сценариев, использование памяти, окружение и хеши подтверждений, а также «сырые» измерения, оба протокола, код анализа и контрольные суммы. Этого достаточно, чтобы пересчитать каждое число в этой публикации.





/)





