Как некоторые из вас, возможно, знают, автозавершение кода, которое мы разрабатывали для Pharo до этого момента, основывалось только на информации AST (тип), которая может быть выведена из самого исходного кода. Однако с самого начала мы имели в виду еще одну идею: задействовать некоторые подходы машинного обучения (ML) для повышения качества предлагаемых предложений.

Для этого мы просмотрели несколько документов, чтобы увидеть, какой прогресс был достигнут в попытках объединить автозавершение кода и машинное обучение. Чтобы лучше объяснить исследование, я разделю сообщение в блоге на три разные части: часть 1 немного закладывает основу, часть 2 описывает различные подходы, которые мы рассмотрели, и ресурсы, которые мы прочесали, и Часть 3 посвящена подходу, который мы выбрали для нашей стратегии развития, поэтому, например, если вас интересует только один из разделов, вы знаете, какой из них следует прочитать (хотя все же рекомендуется просмотреть раздел 2, прежде чем двигаться дальше. к разделу 3).

Часть 1. Основы

Автозавершение кода было определено как наиболее часто используемая функция в любой IDE [3]. С другой стороны, это также инструмент, который постоянно совершенствуется, и не совсем ясно, когда он действительно станет действительно хорошим. Например, если вам дают вводящие в заблуждение предложения и на самом деле код с включенным автозавершением раздражает больше, чем отключено, вы знаете, что это плохо и что нужно что-то делать. Однако для качественного завершения кода вы можете возразить, что было бы здорово иметь идеальный инструмент завершения кода, который вместо того, чтобы просто предлагать вам варианты после нескольких нажатий клавиш, на самом деле мог бы предлагать целые строки кода за раз. Однако было бы не только почти невозможно получить что-то подобное правильно (по крайней мере, до сих пор, насколько мне известно, не было инструмента, который предлагал вам варианты, которые всегда можно было бы скомпилировать и запустить без ошибок. ), но, кроме того, большинство разработчиков довольны гораздо меньшим. Таким образом, между абсолютно ужасным инструментом и идеальным есть определенное окно возможностей, в которое все еще могут быть внесены действительно хорошие улучшения, не требуя неоправданного количества времени и усилий со стороны людей, разрабатывающих инструмент.

Это та точка, в которой мы сейчас находимся с нашим завершением кода в Pharo. Это довольно хорошо, обычно не предлагает слишком неуместных вещей (и если это так, они будут быстро удалены после добавления пары дополнительных символов к завершаемому токену, то есть пары нажатий клавиш), может быть, иногда нет предложить достаточно (есть еще пара исправлений, над которыми мы работаем, чтобы улучшить это настолько, насколько мы можем, используя только статическую информацию AST), так что для всех намерений и целей это достаточно приличный инструмент, и мы можем остановиться на этом. За исключением того, что все еще существует подход (на основе машинного обучения), который, согласно некоторым документам по этой теме (который будет рассмотрен в разделе 2), должен помочь нам еще больше повысить точность предложений, в частности, это означает, что наиболее актуальные предложения должны быть в верхней части список опций, которые мы получаем для каждого нажатия клавиши.

Имея в виду эту идею, мы переходим к исследованию, проведенному в отношении завершения / предложения кода на основе ML, чтобы увидеть, сможем ли мы найти что-то, что одновременно а) применимо к нашему автозавершению кода и б) достаточно просто для того, чтобы приложить усилия. t превышают выгоду.

Часть 2: Соответствующее исследование

Первичные исследования в этой области начались с предположения, что программное обеспечение является естественным. В предшествующей статье по теме [1] это объясняется следующим образом: «Программное обеспечение естественно в том смысле, что оно создается людьми в процессе работы со всеми сопутствующими ограничениями и ограничениями - и, таким образом, подобно естественному языку, оно также является естественным. вероятно, будет повторяющимся и предсказуемым ». Более того, дальнейшие исследования показали, что код даже более предсказуем и полон шаблонов, чем человеческие языки. В этой статье они также доходят до доказательства того, что (а) код может быть успешно смоделирован с помощью статистических языковых моделей и (б) такие модели могут быть использованы для поддержки инженеров-программистов. Повторяемость возникает в корпусах кода на лексическом, синтаксическом и семантическом уровнях, так почему бы не найти ему хорошее применение с помощью машинного обучения?

Allamanis et al. в своей статье «Обзор машинного обучения для большого кода и естественности» [2] говорится следующее: «Программная инженерия и языки программирования (SE / PL) должны совершить такой же переход [как исследования обработки естественного языка (NLP)], расширяя традиционные методы, которые рассматривают только формальную структуру программ с информацией о статистических свойствах кода », также использующие повторяющиеся и предсказуемые шаблоны в коде.

Во-первых, такие попытки были сделаны Hindle et al. и впоследствии опубликованы в своей статье «О естественности программного обеспечения» [1]. Их решение заключалось в фиксации статистической закономерности высокого уровня на уровне n-грамм (вероятностные цепочки токенов). Идея модели n-грамм для завершения кода состоит в том, что она берет n-1 предыдущих токенов, которые уже введены в текстовый буфер, и пытается угадать следующий токен. Модель, построенная на основе корпуса, дает оценки максимального правдоподобия вероятности конкретного выбора следующего токена; эту вероятность можно использовать для ранжирования вероятных следующих токенов (более подробную информацию можно прочитать в разделе 3).

Изрядная доля исследований, основанных на подходе модели n-грамм, была построена на этом. Например, Tu et al. [4] также «заметил, что код имеет высокую степень локальности, где идентификаторы (например, имена переменных) часто повторяются на близком расстоянии» [2]. Таким образом, они применили механизм кеширования, который присваивает более высокую вероятность токенам, которые наблюдались совсем недавно (другой подход, который мы могли бы попытаться адаптировать в Pharo в какой-то момент).

После этого исследователи обратились к глубокому обучению, в частности к использованию RNN (глубокие рекуррентные нейронные сети), чтобы превзойти n-граммы. Эти модели предсказывают каждый токен последовательно, но ослабляют предположение о фиксированном размере контекста, вместо этого представляя контекст с использованием распределенного векторного представления [2]. Karpathy et al. [5] использовали LSTM на уровне символов, однако в основном это было сделано для исследования точности прогнозов, которые LSTM делают для кодовых шаблонов в целом. Таким образом, публикации, которые мы просмотрели до сих пор, указывают на тот факт, что все эксперименты, касающиеся RNN и LSTM, рассчитывали только точность потенциальных прогнозов, если бы кто-то использовал его для предложения кода, а на самом деле тестировал его на практической задаче. Сама по себе не была должным образом задокументирована (*), тогда как модель n-грамм использовалась специально для этой задачи и имеет публикации, описывающие эксперименты. Еще одна проблема с использованием нейронных моделей заключается в том, что их труднее и дороже обучать, а также требуется гораздо больше данных, чем модели n-грамм, что является одной из основных причин, почему мы не рассматриваем возможность использования нейронных моделей в Pharo.

Некоторые исследования, также в основном в области предложения кода, также были проведены при разработке моделей на уровне AST. Эти модели генерируют синтаксически правильный код, но по своей сути они не являются хорошими моделями статистических зависимостей между токенами кода, потому что токены, которые находятся рядом друг с другом в коде, могут фактически находиться далеко в самом AST. В этом случае модели уровня AST менее полезны, чем n-граммы, потому что они часто могут даже не улавливать близкие зависимости, которые имеют значение.

Для более подробной информации вы можете перейти на https://ml4code.github.io/ - сайт, созданный авторами статьи Обзор машинного обучения для большого кода и естественности [2], на котором есть ссылки и описания всех статей в данной области (большинство из которых они рассмотрели в самой исходной статье), а также дополнительные ресурсы для репозиториев данных и т. д.

Что касается показателей, то измерение результатов завершения кода зависит от многих факторов, и хорошо контролируемое человеческое исследование может очень помочь. Однако есть другой способ оценки производительности модели - в основном тот же, что и языковые модели в НЛП, с использованием недоумения или кросс-энтропии (это измерение того, насколько хорошо вероятностное распределение или вероятностная модель предсказывает выборку. использоваться для сравнения вероятностных моделей. Низкое недоумение указывает на то, что распределение вероятностей хорошо предсказывает выборку). Поскольку мы предполагаем, что хорошая модель - это та, которая фиксирует закономерности в корпусе, точка перекрестной энтропии заключается в том, что она измеряет среднее количество дополнительных битов информации на токен кода, которое требуется модели для распаковки правильного вывода с использованием идеального кода. . Hindle et al. [1] выразили идею проще, сказав, что она измеряет «насколько удивительным является тестовый документ для языковой модели, оцениваемой по корпусу».

Часть 3: Наш подход

Как было указано выше, к сожалению, большая часть связанных исследований не имеет практической реализации, подтверждающей это, и наиболее документированное использование подходов машинного обучения для автозавершения кода связано с экспериментами с моделями n-грамм. Впервые они были описаны в статье Хиндла, Абрама и др. «О естественности программного обеспечения». [1], который, возможно, является наиболее полным описанием этой конкретной идеи, реализованной на практике, поскольку авторы фактически использовали разработанный плагин предложения кода в широко используемой среде Eclipse IDE и сумели существенно улучшить результаты.

С помощью моделей n-грамм можно статистически смоделировать, насколько вероятно, что токены будут следовать за другими токенами. Модели n-грамм предполагают марковское свойство, что означает, что на появление токенов влияет только ограниченный префикс длины n-1. Эти модели оцениваются по корпусу с использованием простого частотного подсчета последовательностей токенов на основе максимального правдоподобия [1]. По сути, для каждого из токенов, которые мы будем оценивать в нашей задаче завершения кода, идея состоит в том, чтобы увидеть, насколько вероятно, что этот конкретный токен появится после уже доступной последовательности токенов, на основе информации, которую мы уже рассчитано.

На уровне идеи авторы статьи описывают свой подход как нечто, что могло бы дополнить регулярное завершение на основе контекста. Другими словами, в то время как они описывают регулярное завершение кода как что-то, что «может применяться» в текущем синтаксическом контексте, модель n-грамм фиксирует то, что «наиболее часто применяется», и делает это без использования какой-либо семантической информации.

Основная часть экспериментов, проделанных авторами, относилась к Java. По их словам, модели могли успешно предлагать нелингвистические токены (токены, не являющиеся ключевыми словами Java) примерно в 50% случаев; что свидетельствует о том, что низкая энтропия, производимая моделями (согласно экспериментам, проведенным и описанным в исходной статье), была вызвана не только простотой языка Java. Следовательно, можно сказать, что модели n-граммов предоставляют предложения, которые зависят от проекта, а не просто предлагают ключевые слова Java, которые можно угадать из контекста [1]. В зависимости от того, как мы решим использовать этот факт, это также может быть преимуществом для завершения Pharo.

Резюме:

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

Как только мы начнем работать над этим, следующий материал будет более практическим и специфичным для Pharo. На данный момент надеюсь, что это было достаточно полезно как для пользователей Pharo, знакомых с подходами машинного обучения для SE, так и для энтузиастов машинного обучения, изучающих, как некоторые из вещей, которые они знают, были использованы для некоторых основных задач разработки программного обеспечения.

Заявление об ограничении ответственности:

(*) Да, я знаю TabNine! Это выглядит круто, но, по сути, это бизнес-инструмент, который предоставляет решение без описания подхода к нему или того, как это было сделано, что вряд ли может быть для нас.

Ресурсы:

  1. Хиндл, Абрам и др. О естественности программного обеспечения. 34-я Международная конференция по программной инженерии (ICSE), 2012 г.. IEEE, 2012. [ссылка]
  2. Алламанис, Милтиадис и др. Обзор машинного обучения на предмет объемного кода и естественности. ACM Computing Surveys (CSUR) 51,4 (2018): 81. [ссылка]
  3. Аманн, Свен и др. Исследование использования визуальной студии на практике. 23-я Международная конференция IEEE по анализу, развитию и реинжинирингу программного обеспечения (SANER), 2016 г.. Vol. 1. IEEE, 2016. [ссылка]
  4. Чжаопенг Ту, Чжендун Су и Премкумар Деванбу. О локальности программного обеспечения. Материалы 22-го Международного симпозиума ACM SIGSOFT по основам программной инженерии. ACM, 2014. [ссылка]
  5. Карпати, Андрей, Джастин Джонсон и Ли Фей-Фей. Визуализация и понимание повторяющихся сетей. Препринт arXiv arXiv: 1506.02078 (2015). ["ссылка на сайт"]