Настраивание кодирования партнеров для организаций

Оптимизация кодирования партнеров для организаций

Генеративные модели искусственного интеллекта для сопровождения кода в основном обучаются на общедоступном исходном коде и тексте естественного языка. Хотя большой объем тренировочного корпуса позволяет моделям генерировать код для часто используемых функций, эти модели не знают о коде в личных репозиториях и связанных с ними стилях кодирования. В результате сгенерированные предложения могут потребовать переписывания, прежде чем они будут подходящими для включения во внутренний репозиторий.

Мы можем заполнить этот пробел и минимизировать дополнительное ручное редактирование, внедряя знания о коде из личных репозиториев поверх модели языка, обученной на общедоступном коде. Поэтому мы разработали возможность настройки для Amazon CodeWhisperer. В этой статье мы покажем вам два возможных способа настройки сопровождения кода с использованием аугментированной генерации и тонкой настройки.

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

  1. Ограниченная документация или информация о внутренних библиотеках и API, что заставляет разработчиков тратить время на изучение ранее написанного кода для воспроизведения использования.
  2. Отсутствие осведомленности и последовательности в реализации корпоративных практик, стилей и шаблонов программирования.
  3. Неумышленное использование устаревшего кода и API разработчиками.

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

Проблемы дизайна

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

Базовый подход к созданию настройки может заключаться в предварительном обучении модели на одном тренировочном корпусе, состоящем из существующего (общедоступного) набора данных для предварительного обучения и корпоративного (личного) кода. Хотя этот подход работает на практике, он требует (излишних) отдельных этапов предварительного обучения с использованием общедоступного набора данных для каждого предприятия. Он также требует избыточных издержек развертывания, связанных с размещением настроенной модели для каждого клиента, обслуживающей только запросы клиента, полученные от этого клиента. Отделение обучения на общедоступном и личном коде и развертывание настройки на системе с множеством пользователей позволяет избежать этих избыточных издержек.

Как настроить

В общих чертах существует два типа возможных техник настройки: аугментированная генерация по сопоставлению (Retrieval-augmented generation, RAG) и тонкая настройка (Fine-tuning, FT).

  • Аугментированная генерация по сопоставлению: RAG находит совпадающие фрагменты кода в репозитории, которые похожи на заданный фрагмент кода (например, код, непосредственно предшествующий курсору в IDE), и дополняет запрос LLM этими совпавшими кодовыми фрагментами. Это обогащает запрос и помогает модели генерировать более релевантный код. В литературе есть несколько исследованных техник в этой области. См. статьи Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks, REALM, kNN-LM и RETRO.

  • Настройка: Настройка (FT) берет предварительно обученную LLM и обучает ее дальше на конкретной, более маленькой кодовой базе (по сравнению с предварительно обучающим набором данных) для приспособления ее к соответствующему репозиторию. Настройка корректирует веса LLM на основе этого обучения, делая ее более подходящей для уникальных потребностей организации.

И RAG, и настройка являются мощными инструментами для улучшения производительности настраиваемого LLM. RAG может быстро адаптироваться к личным библиотекам или API с нижней сложностью обучения и низкой стоимостью. Однако поиск и дополнение извлеченных фрагментов кода к подсказке увеличивает задержку во время выполнения. Вместо этого, настройка не требует никакого дополнения контекста, поскольку модель уже обучена на личных библиотеках и API. Однако это приводит к более высоким затратам и сложностям обучения модели, когда ее необходимо поддерживать для нескольких пользовательских моделей внутри предприятия. Как мы обсудим позднее, эти проблемы могут быть устранены путем дальнейшей оптимизации подхода.

Извлечение с улучшенной генерацией

Процесс RAG включает в себя несколько этапов:

Индексирование

На основе входного набора кода администратором создается индекс, путем разделения файлов исходного кода на фрагменты. Простыми словами, фрагментирование превращает фрагменты кода в усваиваемые куски, которые, скорее всего, будут наиболее информативными для модели и легко извлекаемыми с учетом контекста. Размер фрагмента и способ его извлечения из файла являются выборами, которые влияют на конечный результат. Например, фрагменты могут быть разделены на основе строк кода или на основе синтаксических блоков и т.д.

Рабочий процесс администратора

Контекстный поиск

Поиск набора проиндексированных фрагментов кода на основе нескольких строк кода выше курсора и извлечение соответствующих фрагментов кода. Это извлечение может происходить с использованием разных алгоритмов. Эти варианты могут включать в себя:

  • Мешок слов (BM25) – Функция извлечения мешка слов, которая ранжирует набор фрагментов кода на основе частот запросов и длины фрагмента кода.

Извлечение на основе BM25

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

  • Семантическое извлечение [Contriever, UniXcoder] – Преобразует запрос и проиндексированные фрагменты кода в высокоразмерные векторы и ранжирует фрагменты кода на основе семантической схожести. Формально, часто используется поиск ближайших соседей (KNN) или приближенный поиск ближайших соседей (ANN) для нахождения других фрагментов с похожей семантикой.

Переработка семантики

BM25 сосредотачивается на лексическом сопоставлении. Поэтому замена “add” на “delete” может не изменить оценку BM25 на основе терминов в запросе, но функциональность, которая будет извлечена, может быть противоположной тому, что требуется. В отличие от этого, семантическое извлечение сосредотачивается на функциональности фрагмента кода, даже если имена переменных и API могут отличаться. Обычно комбинация извлечений на основе BM25 и семантики хорошо работает вместе, что позволяет достичь лучших результатов.

Расширенный вывод

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

Рабочий процесс разработчика

Тонкая настройка:

Тонкая настройка языковой модели выполняется для передачи знаний, при которой веса предварительно обученной модели обучаются на новых данных. Цель состоит в сохранении соответствующих знаний модели, уже обученной на большом корпусе, и уточнении, замене или добавлении новых знаний из нового корпуса — в нашем случае, новой базы кода. Простое обучение на новой базе кода приводит к катастрофическому забыванию. Например, языковая модель может «забыть» свои знания о безопасности или API, которые редко используются в корпоративной базе кода на данный момент. Для решения этой проблемы используются различные техники, такие как повторение опыта, GEM и PP-TF.

Тонкая настройка

Существуют два способа тонкой настройки. Один подход заключается в использовании дополнительных данных без дополнения запроса для тонкой настройки модели. Другой подход заключается в дополнении запроса во время тонкой настройки путем извлечения соответствующих рекомендаций по коду. Это помогает улучшить способность модели предоставлять лучшие рекомендации при наличии извлеченных фрагментов кода. Затем модель оценивается на отложенном наборе примеров после его обучения. Впоследствии настроенная модель развертывается и используется для генерации рекомендаций по коду.

Несмотря на преимущества использования специальных ЯММ для генерации кода в частных репозиториях, затраты могут быть запретными для малых и VoAGI-размерных организаций. Это связано с необходимостью использования вычислительных ресурсов, даже если они используются недостаточно в соответствии с размером команд. Один из способов достижения экономичности заключается в обслуживании нескольких моделей на одной и той же вычислительной мощности (например, многопользовательский SageMaker). Однако языковым моделям требуется одна или несколько выделенных графических процессоров в нескольких зонах для обработки ограничений по задержке и пропускной способности. Поэтому многопользовательское размещение полных моделей на каждом графическом процессоре невозможно.

Мы можем преодолеть эту проблему, обслуживая нескольких клиентов на одной и той же вычислительной мощности с помощью небольших адаптеров к ЯММ. Для снижения затрат на обучение используются техники эффективной настройки параметров (PEFT), такие как настройка запроса, настройка префикса и Low-Rank Adaptation (LoRA), что позволяет снизить затраты на обучение без потери точности. В частности, LoRA демонстрирует большой успех в достижении такой же точности (или даже лучшей), чем при полной настройке модели. Основная идея заключается в проектировании матрицы малого ранга, которая затем добавляется к матрицам с оригинальным весом матриц целевых слоев модели. Обычно эти адаптеры затем объединяются с исходными весами модели для обслуживания. Это приводит к той же размерности и архитектуре, что и у исходной нейронной сети. Оставляя адаптеры отдельными, мы можем обслуживать ту же базовую модель с множеством адаптеров для моделей. Это позволяет малым организациям получить преимущества экономии масштаба.

Адаптация с низким рангом (LoRA)

Измерение эффективности настройки

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

Также можно измерить полезность, количественно оценив, как часто внутренние API вызываются настройкой и сравнить это с вызовами в исходном исходном коде. Конечно, для успешного выполнения важно правильно учесть оба аспекта. В рамках нашего подхода к настройке мы разработали индивидуальную метрику, известную как индекс качества настройки (CQI), одну удобную для пользователя меру, варьирующуюся от 1 до 10. Метрика CQI отображает полезность предложений настроенной модели по сравнению с предложениями кода общей модели.

Сводка

Мы создали возможность настройки Amazon CodeWhisperer на основе смеси ведущих технических методов, обсуждаемых в этом блоге, и оценили ее с помощью исследований пользователей по производительности разработчиков, проведенных компанией Persistent Systems. В этих двух исследованиях, заказанных AWS, разработчикам было предложено создать медицинское программное приложение на языке Java, требующее использования их внутренних библиотек. В первом исследовании разработчики, не имеющие доступа к CodeWhisperer, выполняли задачу в среднем за ~8,2 часа, в то время как те, кто использовал CodeWhisperer (без настройки), выполнили задачу на 62 процента быстрее, в среднем за ~3,1 часа.

Во втором исследовании с другим набором групп разработчиков те, кто использовал CodeWhisperer, настроенный с использованием их собственной кодовой базы, выполнили задачу в среднем за 2,5 часа, что на 28 процентов быстрее, чем те, кто использовал CodeWhisperer без настройки, и выполнили задачу в среднем за ~3,5 часа. Мы настоятельно верим, что инструменты, подобные CodeWhisperer, настроенные для вашей кодовой базы, имеют ключевую роль в дальнейшем повышении производительности разработчиков, и рекомендуем попробовать его. Для получения дополнительной информации и начала работы посетите страницу Amazon CodeWhisperer.