à propos du projet
Il existe de nombreux problèmes intéressants dans le domaine du traitement des langages de programmation, dont la solution automatique peut être utile pour créer des outils pratiques pour les développeurs.
Le code source des programmes diffère à bien des égards des textes en langage naturel, mais il peut également être considéré comme une séquence de jetons et des méthodes similaires peuvent être utilisées. Par exemple, dans le domaine du traitement du langage naturel, le modèle de langage BERT est activement utilisé. Le processus de sa formation comprend deux étapes : une pré-formation sur un grand ensemble de données non étiquetées et une formation supplémentaire pour des tâches spécifiques sur des ensembles de données étiquetés plus petits. Cette approche permet de résoudre de nombreuses tâches avec une très bonne qualité.
Travaux récents ( 1 , 2, 3 ) a montré que si vous entraînez le modèle BERT sur un grand ensemble de données de code de programme, il s'acquitte bien de plusieurs tâches dans ce domaine (parmi lesquelles, par exemple, la localisation et l'élimination des variables mal utilisées et la génération de commentaires sur les méthodes) .
Le projet vise à étudier l'utilisation de BERT pour d'autres tâches de code source. En particulier, nous nous sommes concentrés sur la tâche de générer automatiquement des messages de validation.
À propos de la tâche
Pourquoi avons-nous choisi cette tâche ?
Premièrement, les systèmes de contrôle de version sont utilisés dans le développement de nombreux projets, de sorte qu'un outil permettant de résoudre automatiquement ce problème peut être pertinent pour un large éventail de développeurs.
Deuxièmement, nous avons émis l'hypothèse que l'utilisation de BERT pour cette tâche pourrait conduire à de bons résultats. Cela est dû à plusieurs raisons :
- dans les travaux existants ( 4 , 5 , 6 ), les données sont collectées à partir de sources ouvertes et nécessitent un filtrage sérieux, il y a donc peu d'exemples pour la formation. C'est là que la capacité du BERT à s'entraîner sur de petits ensembles de données peut s'avérer utile ;
- Le résultat de l'état de l'art au moment de travailler sur le projet se trouvait dans le modèle d'architecture Transformer, qui a été prêché de manière assez spécifique sur un petit ensemble de données ( 6 ). Il était intéressant pour nous de le comparer avec le modèle basé sur BERT, qui est pré-entraîné de manière différente, mais sur beaucoup plus de données.
Au cours du semestre, j'ai eu à faire les choses suivantes :
- étudier le domaine;
- trouver un ensemble de données et sélectionner une représentation des données d'entrée ;
- développer un pipeline pour la formation et l'évaluation de la qualité ;
- mener des expériences.
Données
Il existe plusieurs jeux de données ouverts pour cette tâche, j'ai choisi le plus filtré ( 5 ).
L'ensemble de données a été collecté à partir des 1000 meilleurs référentiels GitHub ouverts en langage Java. Après filtrage, sur les millions d'exemples originaux, il en reste environ 30 000.
Les exemples eux-mêmes sont des paires de la sortie de la commande git diff et du message court correspondant en anglais. Cela ressemble à ceci :
Les modifications et les messages dans l'ensemble de données sont courts - pas plus de 100 et 30 jetons, respectivement.
Dans la plupart des travaux existants sur le problème de la génération automatique de messages pour les commits, une séquence de jetons de git diff est transmise aux modèles.
Il y a une autre idée : sélectionner explicitement deux séquences, avant et après modifications, et les aligner à l'aide de l'algorithme classique de calcul de la distance éditoriale. Ainsi, les jetons modifiés sont toujours dans les mêmes positions.
Idéalement, nous aimerions essayer plusieurs approches et comprendre comment elles affectent la qualité de la résolution de ce problème. Au début, j'en ai utilisé une assez simple : deux séquences ont été introduites dans l'entrée du modèle, avant et après les modifications, mais sans aucun alignement.
BERT pour les tâches séquence à séquence
Les données d'entrée et de sortie pour la tâche de génération automatique de messages pour les commits sont des séquences dont la longueur peut différer.
Pour résoudre de tels problèmes, une architecture codeur-décodeur est généralement utilisée, qui se compose de deux composants :
- le modèle d'encodeur construit une représentation vectorielle basée sur la séquence d'entrée,
- le modèle-décodeur génère une séquence de sortie sur la base de la représentation vectorielle.
Le modèle BERT est basé sur un encodeur de l'architecture Transformer et n'est pas à lui seul adapté à une telle tâche. Plusieurs options sont possibles afin d'obtenir un modèle séquence à séquence à part entière, la plus simple est d'utiliser une sorte de décodeur avec. Cette approche avec un décodeur de l'architecture Transformer s'est bien montrée, par exemple, pour la tâche de traduction automatique neuronale ( 7 ).
Pipeline
Pour mener les expériences, un code était nécessaire pour entraîner et évaluer la qualité d'un tel modèle de séquence à séquence.
Pour travailler avec le modèle BERT, j'ai utilisé la bibliothèque Transformers de HuggingFace, et pour l'implémentation en général, le framework PyTorch.
Comme au début j'avais peu d'expérience avec PyTorch, je me suis largement appuyé sur des exemples existants pour les modèles séquence à séquence d'autres architectures, m'adaptant progressivement aux spécificités de ma tâche. Malheureusement, cette approche a abouti à beaucoup de code de mauvaise qualité.
À un moment donné, il a été décidé de commencer la refactorisation, en réécrivant pratiquement le pipeline. La bibliothèque PyTorch Lightning a aidé à structurer le code, ce qui vous permet de collecter toute la logique principale du modèle dans un module et de l'automatiser de plusieurs manières.
Expériences
Au cours des expériences, nous avons voulu comprendre si l'utilisation du modèle BERT pré-entraîné améliore le résultat de l'état de l'art dans ce domaine.
Parmi les modèles BERT entraînés sur le code, seul CodeBERT ( 1 ) nous est parvenu , puisque seul il avait le langage de programmation Java dans les exemples d'entraînement. Tout d'abord, en utilisant CodeBERT comme encodeur, j'ai essayé des décodeurs de différentes architectures :
- GRU.
, - . GRU Transformer, , .
- . - Transformer.
, — .
, GPT-2 (8) — Transformer, , — distilGPT-2 (9).
Il n'y avait pas assez de temps pour d'autres expériences au semestre d'automne, je les ai poursuivies en hiver. Nous avons examiné plusieurs autres façons de représenter l'entrée : nous avons essayé d'aligner les séquences avant et après les modifications, et nous avons également simplement déposé un git diff.
Les principaux résultats des expériences sont les suivants :
En résumé
En général, l'hypothèse concernant les avantages de l'utilisation de CodeBERT pour cette tâche n'a pas été confirmée ; dans tous les cas, le modèle Transformer formé à partir de zéro a montré une qualité supérieure. La meilleure méthode dans ce domaine reste le modèle CoreGen6 : il s'agit également d'un Transformer, mais en plus pré-entraîné à l'aide de la fonction objectif proposée par les auteurs.
Pour résoudre ce problème, de nombreuses autres idées peuvent être envisagées : par exemple, essayez la représentation des données basée sur des arbres de syntaxe abstraite, qui est souvent utilisée lorsque vous travaillez avec du code de programme ( 10 , 11), essayez d'autres modèles pré-formés ou effectuez une pré-formation spécifique à un domaine si les ressources sont disponibles. Au semestre de printemps, nous nous sommes concentrés sur une application plus pratique des résultats obtenus et nous nous sommes engagés dans l'auto-complétion des messages aux commits. Je vous en parlerai dans la deuxième partie :)
En conclusion, je tiens à dire que c'était vraiment intéressant de participer au projet, je me suis plongé dans un nouveau domaine pour moi-même et j'ai beaucoup appris pendant cette période. Le travail sur le projet a été très bien organisé, pour lequel un grand merci à mes dirigeants.
Merci pour l'attention!
Sources de
- Feng, Zhangyin et al. "Codebert : Un modèle pré-entraîné pour la programmation et les langages naturels." 2020
- Buratti, Luca, et al. «Exploring Software Naturalness through Neural Language Models.» 2020
- Kanade, Aditya, et al. «Learning and Evaluating Contextual Embedding of Source Code.» 2020
- Jiang, Siyuan, Ameer Armaly, and Collin McMillan. «Automatically generating commit messages from diffs using neural machine translation.» 2017
- Liu, Zhongxin, et al. «Neural-machine-translation-based commit message generation: how far are we?.» 2018
- Nie, Lun Yiu, et al. «CoreGen: Contextualized Code Representation Learning for Commit Message Generation.» 2021
- Rothe, Sascha, Shashi Narayan, and Aliaksei Severyn. «Leveraging pre-trained checkpoints for sequence generation tasks.» 2020
- Radford, Alec, et al. «Language models are unsupervised multitask learners.» 2019
- Sanh, Victor, et al. «DistilBERT, a distilled version of BERT: smaller, faster, cheaper and lighter.» 2019
- Yin, Pengcheng, et al. «Learning to represent edits.» 2018
- Kim, Seohyun, et al. «Code prediction by feeding trees to transformers.» 2021