Текст / АлиСямэнь F(x)Team- Сюй Лунь
Можно ли автоматически исправлять ошибки с помощью машинного обучения?Для многих студентов это может быть темой фантастики. Надежен он или нет, мы можем попробовать сами, и каждый может научиться.
Этот вопрос очень трудно сказать, и очень просто сказать. Мы создаем набор фрагментов кода с ошибками и исправленных фрагментов кода и обучаем их, используя такие методы, как машинный перевод. Затем мы используем обученную модель, чтобы предсказать, как будет исправлен новый код. Эта идея и набор данных взяты из статьи "An Empirical Study on Learning Bug-Fixing Patches in the Wild via Neural Machine Translation》
Проблема автоматического исправления кода очень проста, одно — это код с ошибками, а другое — код после исправления.
Его основной процесс смотрим на картинке:
Чтобы более широко адаптироваться к ситуации с кодом, автор абстрагирует код:
Давайте рассмотрим пример из набора данных:
Глючный код такой:
public java.lang.String METHOD_1 ( ) { return new TYPE_1 ( STRING_1 ) . format ( VAR_1 [ ( ( VAR_1 . length ) - 1 ) ] . getTime ( ) ) ; }
После исправления это выглядит так:
public java.lang.String METHOD_1 ( ) { return new TYPE_1 ( STRING_1 ) . format ( VAR_1 [ ( ( type ) - 1 ) ] . getTime ( ) ) ; }
Научит вас использовать CodeBERT для автоматического исправления ошибок
Когда дело доходит до AI4SE, искусственного интеллекта для разработки программного обеспечения, Microsoft всегда была в авангарде. Давайте узнаем, как использовать модель Microsoft CodeBERT для автоматического исправления ошибок.
Шаг 1: Установите инфраструктуру трансформаторов, потому что CodeBERT основан на этой инфраструктуре:
pip install transformers --user
Шаг 2: Установите PyTorch или Tensorflow в качестве серверной части Transformers.Если драйвер можно сделать, просто установите последнюю версию:
pip install torch torchvision torchtext torchaudio --user
Третий шаг, загрузите набор данных Microsoft
git clone https://github.com/microsoft/CodeXGLUE
Набор данных был загружен в CodeXGLUE/Code-Code/code-refinement/data/ и разделен на два набора данных, малый и средний.
Давайте сначала потренируемся с небольшим набором данных:
cd code
export pretrained_model=microsoft/codebert-base
export output_dir=./output
python run.py \
--do_train \
--do_eval \
--model_type roberta \
--model_name_or_path $pretrained_model \
--config_name roberta-base \
--tokenizer_name roberta-base \
--train_filename ../data/small/train.buggy-fixed.buggy,../data/small/train.buggy-fixed.fixed \
--dev_filename ../data/small/valid.buggy-fixed.buggy,../data/small/valid.buggy-fixed.fixed \
--output_dir $output_dir \
--max_source_length 256 \
--max_target_length 256 \
--beam_size 5 \
--train_batch_size 16 \
--eval_batch_size 16 \
--learning_rate 5e-5 \
--train_steps 100000 \
--eval_steps 5000
В зависимости от вычислительной мощности вашей машины я использовал графический процессор NVIDIA 3090 для обучения примерно за одну ночь. Самая эффективная модель хранится в output_dir/checkpoint-best-bleu/pytorch_model.bin.
Затем мы можем использовать тестовый набор для проверки наших результатов обучения:
python run.py \
--do_test \
--model_type roberta \
--model_name_or_path roberta-base \
--config_name roberta-base \
--tokenizer_name roberta-base \
--load_model_path $output_dir/checkpoint-best-bleu/pytorch_model.bin \
--dev_filename ../data/small/valid.buggy-fixed.buggy,../data/small/valid.buggy-fixed.fixed \
--test_filename ../data/small/test.buggy-fixed.buggy,../data/small/test.buggy-fixed.fixed \
--output_dir $output_dir \
--max_source_length 256 \
--max_target_length 256 \
--beam_size 5 \
--eval_batch_size 16
На моей машине после получаса вычислений вывод выглядит следующим образом:
10/26/2021 11:51:57 - INFO - __main__ - Test file: ../data/small/test.buggy-fixed.buggy,../data/small/test.buggy-fixed.fixed
100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 365/365 [30:40<00:00, 5.04s/it]
10/26/2021 12:22:39 - INFO - __main__ - bleu-4 = 79.26
10/26/2021 12:22:39 - INFO - __main__ - xMatch = 16.3325
10/26/2021 12:22:39 - INFO - __main__ - ********************
Как оценить качество кода, который мы генерируем? Мы можем сделать это, сравнив output/test_1.output и output/test_1.gold, которые мы сгенерировали, используя следующий скрипт evaluator.py:
python evaluator/evaluator.py -ref ./code/output/test_1.gold -pre ./code/output/test_1.output
Результат выглядит следующим образом:
BLEU: 79.26 ; Acc: 16.33
Первая — это метрика BLEU, которая описывает качество генерации НЛП, а вторая — показатель точности.
Каков уровень этого показателя? Мы можем сравнить с базовым уровнем:
Method | BLEU | Acc (100%) | CodeBLEU |
---|---|---|---|
Naive copy | 78.06 | 0.0 | - |
LSTM | 76.76 | 10.0 | - |
Transformer | 77.21 | 14.7 | 73.31 |
CodeBERT | 77.42 | 16.4 | 75.58 |
Хотя уровень точности не кажется высоким, CodeBERT улучшился на 60% по сравнению с технологией RNN, использованной в исходной статье.
Мы используем diff, чтобы интуитивно почувствовать разницу между сгенерированным и исходным:
С увеличением данных мы можем автоматически помогать нам исправлять ошибки, не тратя ни одной клетки мозга.Это просто «доход после сна».
Автоматически находить ошибки
Если мы чувствуем, что автоматическое решение ошибок далеко не практично, мы можем только сначала найти ошибки. Но не стоит недооценивать относительно слабое предложение автоматического обнаружения ошибок, которое значительно улучшило применимость и точность.
Набор данных с ошибками особенно прост, если используется поле, чтобы отметить, есть ошибка или нет.
Формат набора данных следующий, он хранится в формате jsonl:
{"project": "qemu", "commit_id": "aa1530dec499f7525d2ccaa0e3a876dc8089ed1e", "target": 1, "func": "static void filter_mirror_setup(NetFilterState *nf, Error **errp)\n{\n MirrorState *s = FILTER_MIRROR(nf);\n Chardev *chr;\n chr = qemu_chr_find(s->outdev);\n if (chr == NULL) {\n error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,\n \"Device '%s' not found\", s->outdev);\n qemu_chr_fe_init(&s->chr_out, chr, errp);", "idx": 8}
{"project": "qemu", "commit_id": "21ce148c7ec71ee32834061355a5ecfd1a11f90f", "target": 1, "func": "static inline int64_t sub64(const int64_t a, const int64_t b)\n\n{\n\n\treturn a - b;\n\n}\n", "idx": 10}
Не нужно писать код, мы тренируемся напрямую:
python run.py \
--output_dir=./saved_models \
--model_type=roberta \
--tokenizer_name=microsoft/codebert-base \
--model_name_or_path=microsoft/codebert-base \
--do_train \
--train_data_file=../dataset/train.jsonl \
--eval_data_file=../dataset/valid.jsonl \
--test_data_file=../dataset/test.jsonl \
--epoch 5 \
--block_size 200 \
--train_batch_size 32 \
--eval_batch_size 64 \
--learning_rate 2e-5 \
--max_grad_norm 1.0 \
--evaluate_during_training \
--seed 123456
Это время намного меньше, чем при автоматическом ремонте, и он будет выполнен за 20 минут. Затем запустите следующий набор тестов:
python run.py \
--output_dir=./saved_models \
--model_type=roberta \
--tokenizer_name=microsoft/codebert-base \
--model_name_or_path=microsoft/codebert-base \
--do_eval \
--do_test \
--train_data_file=../dataset/train.jsonl \
--eval_data_file=../dataset/valid.jsonl \
--test_data_file=../dataset/test.jsonl \
--epoch 5 \
--block_size 200 \
--train_batch_size 32 \
--eval_batch_size 64 \
--learning_rate 2e-5 \
--max_grad_norm 1.0 \
--evaluate_during_training \
--seed 123456
Рассчитать точность:
python ../evaluator/evaluator.py -a ../dataset/test.jsonl -p saved_models/predictions.txt
Результаты приведены ниже:
{'Acc': 0.6288433382137628}
Давайте сравним его с основными результатами отрасли:
Methods | ACC |
---|---|
BiLSTM | 59.37 |
TextCNN | 60.69 |
RoBERTa | 61.05 |
CodeBERT | 62.08 |
Точность сносная. С пользой от этого метода остается тот самый «доход после сна», о котором мы говорили ранее. Пока накапливается больше достоверных данных, его способность распознавания будет продолжать расти, что в основном не требует обслуживающего персонала.