pplication of Seq2Seq Models on Code Correctio

We apply various seq2seq models on programming language correction tasks on Juliet Test Suite for C/C++ and Java of Software Assurance Reference Datasets(SARD), and achieve 75%(for C/C++) and 56%(for Java) repair rates on these tasks. We introduce Pyramid Encoder in these seq2seq models, which largely increases the computational efficiency and memory efficiency, while remain similar repair rate to their non-pyramid counterparts. We successfully carry out error type classification task on ITC benchmark examples (with only 685 code instances) using transfer learning with models pre-trained on Juliet Test Suite, pointing out a novel way of processing small programing language datasets.

<span>MyVerbatim</span><span>Verbatim</span> <span>frame=lines,framerule=0.8mm, fontsize=</span>

Introduction
============

Programming language correction (PLC), which can provide suggestions for people to debug code, identify potential flaws in a program, and help programmers to improve their coding skills, has been an important topic in Natural Language Processing (NLP) area. At present, most work in PLC used rule-based methods \[@jet2016 @syn2016 @gc2016 @ge2016 @singh2013automated\], using static analyzers, code transformations or control flow to identify and correct common suspicious code patterns or potential bugs. Machine learning methods has been a minority in PLC, examples are @gupta2018deep, who used reinforcement learning based on compiler error messages, and @pu2016sk_p, who used LSTM on correcting students' programming exercises in MOOCs.

Seq2seq (abbreviation of sequence to sequence) model is a group of neural network based model. It usually consist of an encoder and a decoder. The encoder takes a sequence as input, and produce an encoded representation of the input sequence. The decoder takes this representation and produce an output sequence. Therefore, this architecture is very suitable for Natural Language Processing (NLP), because language is consist of sequence of words. It is widely used in Neural Machine Translation, Text Generation, etc. An example of a seq2seq model structure is shown in Figure \[fig:seq2seq\].

![Model structure of a 3-layer seq2seq model with attention. The $i^{\mathrm{th}}$ layer takes the output of the previous layer ($\boldsymbol{h}^{(i-1)}$)as its input. $\boldsymbol{a}$ is the context vector, which can be calculated using different attention mechanisms.<span data-label="fig:seq2seq"></span>](seq2seq.jpg){width="50.00000%"}

In natural language correction (NLC), seq2seq models are the state-of-the-art methods \[@xie2016neural, @vaswani2017attention\]. Considering PLC and NLC are very similar in form, we apply various seq2seq models on PLC. Unlike our predecessors, we not only aim at correcting syntax errors, but also identifying potential flaws that will not be caught during compiling, for example, memory allocation errors, redundant code, etc. One of the dataset that can serve this purpose is the Juliet Test Suite, which contains over 100 Common Weakness Enumerations(CWEs), each of them contains hundreds of examples. Our results show that seq2seq models successfully repair over 70% of the code instances if 1 beam search candidate considered, and over 90% if 5 beam search candidates considered.

![Visualization of Pyramid Encoder in multi-layer seq2seq models. Pyramid Encoder reduces length of input sequence by half in every encoding layer. $h^{(i-1)}$ denotes output of $(i-1)^{\text{th}}$ encoder layer and $x^{(i)}$ denotes the input of $i^{\text{th}}$ encoder layer.<span data-label="fig:Pyramid"></span>](model.jpg){width="50.00000%"}

Besides applying regular seq2seq models, we introduce pyramid encoder structure. The motivation is as follows: Unlike NLC problems, where the average length of a sentence lies around dozens of words, the average length of code instances in PLC are usually hundreds of words, which results in enormous computational cost and memory requirement. Pyramid structure aims to reduce these costs by contracting the data flow and disgard redundant information. Figure \[fig:Pyramid\] shows a visual representation of the pyramid encoder, it can be implemented to most of the multi-layer seq2seq learning models. In our model comparison set, Pyramid Encoder increases networks' computational efficiency by 50% to 100% and memory efficiency by up to 600%, while remaining similar ability of reparation.

On the other hand, due to the privacy policies, most of the publicly available dataset are not collected from realistic program errors & fixes, but rather are generated by artificial tools. The ones that are collected realistically are usually very small. To handle this issue, we also applied transfer learning to inherit the knowledge learned from previous dataset to boost the network's performance on smaller and noisier dataset. Details of our project are available on GitHub[^1].

Related Work
============

The network models we used originated from various previous works on sequence to sequence networks. One of such networks is introduced in @xie2016neural, where the author proposed a pyramid structured bi-directional GRU to perform corrections on natural languages. They applied their model to fixing language errors on Lang-8 Corpus and CoNLL Shared Tasks, where the model achieved a BLEU score of 61.7 and 40.56 correspondingly.

Different attention mechanisms are applied in our networks. One of them is Bahdanau Attention \[@bahdanau2014neural\]. In this work, the content-based attention is applied with a encoder-decoder model, and achieved state-of-the-art performance on English-French translation task in 2014. The other is originally introduced by @luong2015effective, in their work, they examines two attention mechanism: one always attends to all source words and one that only looks at a subset of source words. They demonstrate that with local attention, the model is able to achieve the best BLEU score at that time.

The multilayer structure is derived from the idea in the works by @sutskever2014sequence. The GRU cell we used is adapted from @cho2014learning. The Transformer network we use originated from @vaswani2017attention, which is a novel encoder-decoder structure that use Multi-head Attention, a positional, instead sequential, mechanism. All of the above models and methods have been proven very successful in sequence to sequence learning.

Other related works include @jean2014using, where they introduced importance sampling method (to approximate expected gradient) to use a very large target dataset without increasing the training complexity of networks. Their modified neural machine translation with attention mechanism performed well on large-vocabulary tasks (i.e. language translation), with limited training set. As in area of programming language processing, @pu2016sk_p proposed a token-based RNN model with LSTM cells, which achieved some good results in correcting student's submission in MOOCs.

Model
=====

 

Overview
--------

Given a code instance, we wish to identify and correct potential flaws (if they exist) in it, which might lead to a failure in execution after successful compilation. We do not aim at correcting syntax errors, which could be handled by compilers already.

For this purpose, we applied two major families of seq2seq models: GRU and Transformer. We use learnable embedding layers, which allows the model to recognize the relationship between different words in the vocabulary. For the encoder, we applied Pyramid Encoder, where a pyramid module is dded in between layers of regular multi-layer encoders. For the purpose of testing generality of pyramid encoder, we combined it will different attention mechanisms.

Word-level reasoning
--------------------

In language correction, character-level reasoning is a more commonly applied method @xie2016neural. However, in code correction, we apply word-level models. The reason is that the basic building blocks of a code instance are syntax. In the field of programming language processing, out-of-vocabulary (OOV) is less a problem than in natural language due to a fixed syntax pool.

In order to prevent the model suffering from vast variation of variable names, we performed a certain degree of variable re-naming. We focused on renaming function names in our dataset while keeping other variables unchanged. This method reduced vocabulary size to $\sim$1000, and was proven to be effective in improving the performance.

We use a slightly different definition for "word" in the code correction scenario, comparing to its definition in natural language. In a code instance, any entity that is contained in the standard syntax list is considered as a "word", including a space. Details of our method of parsing the code instances to their most compact form is explained in the appendix.

 

Pyramid Encoder
---------------

Given a multi-layer seq2seq encoder, its input at $i^{\mathrm{th}}$ layer at step $t$ is $\boldsymbol{x}_t^{(i)}$, and output is $\boldsymbol{h}_t^{(i)}$: $$\boldsymbol{h}_t^{(i)} = \mathrm{Layer}^{(i)}(\boldsymbol{x}_t^{(i)})$$ in standard seq2seq models, the output of the $i^{\mathrm{th}}$ layer $\boldsymbol{h}^{(i)}$ is directly used as input of of the $i+1^{\mathrm{th}}$ layer, $\boldsymbol{x}^{(i+1)}$: $$\boldsymbol{x}_t^{(i+1)} = \boldsymbol{h}_t^{(i)}$$ and the time step $t = 1, 2, ..., T$, the layer number $i = 1, 2, ...,N$. Note that $\boldsymbol{x}_t^{(0)}$ is the embedded representation of the input instance.

For pyramid encoder, we introduce a pyramid module in between $\boldsymbol{h}^{(i)}$ and $\boldsymbol{x}^{(i+1)}$ as eq. \[eq: pyr\]: $$\label{eq: pyr}
    \boldsymbol{x}_{t'}^{(i+1)}= \mathrm{tanh}(\boldsymbol{W}_{\mathrm{pyr}}(\boldsymbol{h}_{2t}^{(i)}, \boldsymbol{h}_{2t + 1}^{(i)})+ b_{pyr})$$ This module reduced the length of the input $\boldsymbol{x}^{(i)}$ by half each time it is applied. The length of final output of the encoder is $T/2^{N-1}$. One could also take a bigger window such as 3, 4, 5... depending on their needs. The hope is that Pyramid structure will extract the important information and reduce the redundant information of each of the neighboring hidden state, therefore reduce the training cost while keep the accuracy of the correction. This is conceptually similar to a convolution, but without using filters.

For our GRU models, we use multi-layer bi-directional GRU, we implemented Pyramid encoder as described first in @xie2016neural:

$$\begin{aligned}
    \label{eq:forward}
    \boldsymbol{f}_t^{(i)} & = \mathrm{GRU} (\boldsymbol{f}_{t-1} ^{(i)}, \boldsymbol{x}_t^{(i)})\\
    \label{eq:backward}
    \boldsymbol{b}_t^{(i)} & = \mathrm{GRU} (\boldsymbol{b}_{t+1} ^{(i)}, \boldsymbol{x}_t^{(i)})\\
    \boldsymbol{h}_t^{(i)} & = \boldsymbol{f}_t^{(i)} + \boldsymbol{b}_t^{(i)}\\
    \boldsymbol{x}_{t'}^{(i + 1)} & = \mathrm{tanh}(\boldsymbol{W}_{\mathrm{pyr}}(\boldsymbol{h}^{(i)}_{2t}, \boldsymbol{h}^{(i)}_{2t + 1})+ b_{pyr})\end{aligned}$$

where $\boldsymbol{x}_{t'}^{(i+1)}$ denotes the input to next layer, $\boldsymbol{f}_t^{(i)}$ and $\boldsymbol{b}_t^{(i)}$ denotes output from a forward and a backward GRU respectively. GRU (Gated Recurrent Unit) is a RNN (Recurrent Neural Network) type model that included gating mechanism. It can be summarized in following equations (@cho2014learning):

$$\begin{aligned}
    \boldsymbol{r}_t & = \sigma(\boldsymbol{W}_{ir}\boldsymbol{x}_t + b_{ir} + \boldsymbol{W}_{hr} \tilde{\boldsymbol{h}}_{t-1} + b_{hr}\\
    \boldsymbol{z}_t & = \sigma(\boldsymbol{W}_{iz}\boldsymbol{x}_t + b_{iz} + \boldsymbol{W}_{hz} \tilde{\boldsymbol{h}}_{t-1} + b_{hz}\\
    \boldsymbol{n}_t & = \mathrm{tanh}(\boldsymbol{W}_{in}\boldsymbol{x}_t + b_{in} + \boldsymbol{r}_t * \boldsymbol{W}_{hn} \tilde{\boldsymbol{h}}_{t-1} + b_{hn}) \\
    \tilde{\boldsymbol{h}}_t &= (1-\boldsymbol{z}_t) * \boldsymbol{n}_t + \boldsymbol{z}_t *\tilde{\boldsymbol{h}}_{t-1}\end{aligned}$$

where $\tilde{\boldsymbol{h}}_t$ is the hidden state at step $t$, which is denoted by $\boldsymbol{f}_t$ in eq. \[eq:forward\] and $\boldsymbol{b}_t$ in eq. \[eq:backward\]. $\boldsymbol{r}_t$, $\boldsymbol{z}_t$, $\boldsymbol{n}_t$ are the reset, update and new gates, respectively. $\sigma$ is the sigmoid function.

Transformer is a novel family of seq2seq model that works very differently than RNN type models. In the original Transformer (see Figure \[fig:TFM\]), a Feed Forward layer directly takes in the output from the Multi-Head attention layer $\boldsymbol{c}_{\mathrm{att}}$, accompanied by a residual connection, shown in equation \[eq:TFM1\], \[eq:TFM2\]: $$\begin{aligned}
\label{eq:TFM1}
    \boldsymbol{c}_{\mathrm{att}}^{(i)} & = \mathrm{MultiHeadAtt}(\boldsymbol{x}^{(i)}) + \boldsymbol{x}^{(i)}\\
\label{eq:TFM2}
    \boldsymbol{x}^{(i+1)} & = \boldsymbol{c}_{\mathrm{att}}^{(i)} + \mathrm{FeedForward}(\boldsymbol{c}_{\mathrm{att}}^{(i)})\end{aligned}$$

In our model, we concatenate the neighboring elements in $\boldsymbol{c}_{\mathrm{att}}$ before we feed it into Feed Forward layer. As a result, the dimension of the first Linear layer in Feed Forward layer has to change from $[d_{\mathrm{model}} \times d_{\mathrm{ff}}]$ to $[ 2d_{\mathrm{model}} \times d_{\mathrm{ff}}]$. Here we use the same notation as in @vaswani2017attention, where $d_{\mathrm{model}}$ is the size of input, output and attention vectors, $d_{\mathrm{ff}}$ is the number of neurons in the Feed Forward layer. The residual connection also has to be changed accordingly, we tried two different approaches, simply averaging the neighboring element (eq. \[eq: ave\]), or concatenate the neighboring element and pass it through another affine transformation to recover its dimensions (eq. \[eq: aff\]). For simplicity, we denote former method with subscript "ave" and the latter with subscript "aff".

$$\begin{aligned}
    \boldsymbol{x}_{t', \mathrm{ave}}^{(i+1)} =& \frac{(\boldsymbol{c}_{\mathrm{att}, 2t}^{(i)} + \boldsymbol{c}_{\mathrm{att}, 2t+1}^{(i)})}{2} \\+&\mathrm{FeedForward}((\boldsymbol{c}_{\mathrm{att}, 2t}^{(i)}, \boldsymbol{c}_{\mathrm{att}, 2t+1}^{(i)})) \label{eq: ave}
\end{aligned}$$

$$\begin{aligned}
    \boldsymbol{x}_{t', \mathrm{aff}}^{(i+1)} =& \mathrm{tanh}(\boldsymbol{W}_{\mathrm{aff}}(\boldsymbol{c}_{\mathrm{att},2t}^{(i)}, \boldsymbol{c}_{\mathrm{att}, 2t + 1}^{(i)})+ b_{\mathrm{aff}})\\ +& \mathrm{FeedForward}((\boldsymbol{c}_{\mathrm{att}, 2t}^{(i)}, \boldsymbol{c}_{\mathrm{att}, 2t+1}^{(i)}))\label{eq: aff}
\end{aligned}$$

In our experiments, both methods shows close performance. Therefore when showing the results, unless otherwise specified, we use the results of "ave" version.

![Structure of Transformer (@vaswani2017attention). Our pyramid encoder module replaces The Feed Forward and the Add & Norm layer (red dashed rectangle).<span data-label="fig:TFM"></span>](TFM.jpg){width="50.00000%"}

 

Decoder and attention mechanisms
--------------------------------

For our GRU models, we use a regular multi-layer uni-directional GRU: $$\bar{\boldsymbol{h}}_{t}^{(i)} = \mathrm{GRU}(\bar{\boldsymbol{h}}_{t-1}^{(i)}, \bar{\boldsymbol{h}}_{t}^{(i-1)})$$ In our experiment, we did comparison study on Bahdanau Attention(eq. \[eq:bahdanau\]) and different Luong Attentions. Bahdanau Attention is described in following set of equations. $$\begin{aligned}
    \label{eq:bahdanau}
    u_{tk} & = (\boldsymbol{W}_1\bar{\boldsymbol{h}}_{t}^{(M)} + b_1)^\top(\boldsymbol{W}_2\boldsymbol{h}_{k}^{(N)} + b_2)\\
    \alpha_{tk} & = \frac{u_{tk}}{\sum_ju_{tj}}\\
    \boldsymbol{a}_t & = \sum_j \alpha_{tj}\boldsymbol{h}_{j}^{(N)}\label{eq:context}\end{aligned}$$ $u$ is the alignment score, $h$ and $\bar{\boldsymbol{h}}$ denotes the hidden state in encoder and decoder respectively. $M$, $N$ are the number of layers in decoder and encoder respectively. $a_t$ is the context vector, which will be concatenated with the decoder hidden state of last layer for predicting the next word $\hat{y_t}$.

Luong's global Attentions are generalizations to Bahdanau attention, but using different alignment score calculation methods. For simplicity, we omit the superscript $(M)$ and $(N)$. $$u_{tk} = 
    \begin{cases}
        \bar{\boldsymbol{h}}_{t}^\top\boldsymbol{h}_{k} & \mbox{dot}\\
        \bar{\boldsymbol{h}}_{t}^\top\boldsymbol{W_a}\boldsymbol{h}_{k} & \mbox{general}\\
        \boldsymbol{v}_a^\top \mathrm{tanh}(\boldsymbol{W_a} [\bar{\boldsymbol{h}}_{t}, \boldsymbol{h}_{k}]) &\mbox{concat}
    \end{cases}$$

We also tried one example of Luong's local attention, which is done by imposing a Gaussian on eq. \[eq:context\] at a desired attention center $p_t$: $$\begin{aligned}
    \boldsymbol{a}_t & = \sum_j (\alpha_{tj}\boldsymbol{h}_{j})\mathrm{exp}(-\frac{(j-p_t)^2}{2\sigma^2})\\
    p_t & = S\cdot\mathrm{sigmoid}(\boldsymbol{W_p}\bar{\boldsymbol{h}}_t)\end{aligned}$$ where $S$ denotes the total length of the hidden state from the last encoding layer, and $\sigma$ is a parameter chosen manually.

 

Beam Search
-----------

We use beam search in test and validation where text generation is involved. For each time step, we rank candidate based on their total negative logarithmic probability to current decoding time step $t_{\text{dec}}$: $$\text{score} = -\sum_t^{t_\text{dec}} \log(P(\hat{y}))$$ The search stop when there are five completed candidates.

Datasets
========

We perform our experiments mainly on the Juliet Test Suite for C/C++ (v1.2). (created by @juliet2013c) This dataset contains 61,387 test cases, each test case contains one flawed code instance and one to several repaired code instance. We note that the instances contains significant amount of dead code. To make the code more realistic, we remove the dead code. We also found that many of the code instances contains if conditions, that in the flawed code instance, it executes one branch, while in the repaired instance, it executes the other. These instances are unrealistic, therefore we removed them. We also performed function re-naming. After the pre-processing, we obtained 31,082 pairs of good-bad code instances.

To test model's generality, for some of the models, we also tested their performance on Juliet Test Suite for Java (v1.3). (released by @juliet2013j) After similar pre-processing described above, we obtain 23,015 pairs of instances.

For both datasets, we divide them up into 80%, 10%, 10% as train, test, and validation dataset respectively.

Results
=======

 

Repair Rate
-----------

We train our models on a GeForce GTX 1080 Ti graphic card. The metric we use for evaluation is the repair rate, which is the fraction of instances that are repaired after the model's edit. Since we performed beam search with beam width 5, each time a correction is being performed, we generate 5 correction candidates. Here we have two metrics in measuring the performance: 1 candidate repair rate and 5 candidate repair rate. The former corresponds to the scenario of code auto-correction, where there is no human judgement involved. The latter corresponds to correction suggesting, where the machine will identify an error and provide suggestions for the programmer for futher judgement. The comparisons of the repair rates for considered models and their counterparts with pyramid encoder are listed in Table \[tab:repair\_C\] and Table \[tab:repair\_Java\].

From these results we see, Pyramid encoder have close performance to regular encoder in most of the models we applied to, except for with Luong's local attention. The reason is that the encoder output in pyramid encoder is very "coarse-grained", each output position now represents information from $2^{(N-1)}$ words. This results in two drawbacks specifically to local attention: one, a much more "blurry" attention center; two, a much broader attention window. As a result, the attention is much less targeted, which damages the performance. Therefore, in the rest of the paper, we will exclude this attention mechanism from our discussion.

0.1in \[tab:repair\_C\]

0.1in \[tab:repair\_Java\]

 

Converging Speed
----------------

Since Pyramid encoder reduces the sequence lengths in higher layers, one can expect a smaller training cost per batch in both GRU and Transformer models. To quantify this effect, for each of the regular encoder-pyramid encoder model pairs in Table\[tab:repair\_C\], we set the batch size the same, and compare the average training speed in words per second, as shown in Table \[tab:speed\]. Here the batch size is chosen so that it optimizes the training speed on the given GPU for each model. In the model, we also included the number of epochs for the model to converge.

0.1in \[tab:speed\]

Apparently it takes similar number of epochs to converge for the same type of model with pyramid encoder and regular encoder. However, pyramid encoders largely increases the training speed, between 50% to 130%. Therefore it could easily shorten the training time by two to four folds while same performance is achieved. As an example, Figure \[fig:learning\_curve\] shows the learning curve for GRU model with general Luong's attention, comparing the regular encoder and pyramid encoder.

![Learning curve of GRU with Luong's general attention, comparing regular encoder to pyramid encoder. Pyramid encoder model shows fast converging speed.<span data-label="fig:learning_curve"></span>](LearningCurve.jpg){width="60.00000%"}

 

Memory cost
-----------

The last thing we compared is the memory cost of the pyramid encoder and the regular encoder. This measure is crucial in some scenario, where your input instances are very long, therefore the memory of GPU is only capable of holding a very small batch. In code correction, this is often the case.

The metric we use for comparison is memory cost per instance, $k$, which is defined as $$k = \frac{\Delta \text{Memory usage}}{\Delta \text{Batch size}}$$

Figure \[fig:MemoryUse\] shows the calculation process of $k$. Define $\mathcal{E} = 1/k$ as memory efficiency, We calculated the $k$ and $\mathcal{E}$ value for each of the models we applied, shown in Table \[tab:memory\]. We also included number of parameters in each model. From which we see that each pair of models have roughly the same model size.

![Memory cost per instance for GRU models with Bahdanau attention, $k$ is calculated by finding the slope of the linear fit (black dashed line). The red dashed line represents the maximum memory of a GeForce GTX 1080 Ti graphic card.<span data-label="fig:MemoryUse"></span>](MemoryUse.jpg){width="50.00000%"}

The pyramid encoder could increase the memory efficiency by 20% to 600% depending on the attention mechanisms used, while only increase the memory occupied by the model itself by around 10%. One should note that the memory efficiency directly effects the maximum batch size one is able to use on a single GPU, and therefore effects the utility of the GPU. For example, for regular GRU with Bahdanau Attention, given an input length of instances being 500, a GeForce GTX 1080 Ti graphic card could only carry out training with batch size of 8, this and does not fully utilize the GPU. with Pyramid encoder, it's capacity goes up to 60 instances each batch. In practice, this will drastically reduce the training time by increasing the GPU utility, together with the smaller computational cost of pyramid encoder as addressed in previous section.

.

0.1in \[tab:memory\]

Discussion
==========

 

Length analyses
---------------

Figure \[fig:LengthAnalyses\] shows the repair rate of the models with respect to the input length. We omitted the result of Transformer, Bahdanau's attention and Luong's general attention, because they are qualitatively similar to the result of Luong's dot attention. Despite the different attention mechanisms, these seq2seq models (with pyramid encoder or regular encoder) are relatively robust to longer input lengths. The performance drop at around 250 words and above 500 words are likely resulting from the shortage of samples, which one can easily observe from Figure \[fig:histogram\], the length histogram of source instances and target instances. The histogram also shows that the majority of code instances contains several hundred words, while natural language sentences are typically not longer than 50 words. This feature of code instances calls for a much higher computational resource requirement for PLC problems than NLC problems, which makes pyramid structure especially useful.

![Length analyses of Luong's general attention and Luong's concat attention. The results from the rest of the models are qualitatively similar to result of Luong's general attention, thus omitted. <span data-label="fig:LengthAnalyses"></span>](length_analyses.jpg){width="60.00000%"}

![Histogram of flawed code (left) and repaired code (right) instances. <span data-label="fig:histogram"></span>](hist.jpg){width="95.00000%"}

 

Examples of correction
----------------------

In this section we give several examples of successful corrections from our Pyramid GRU model on Juliet C/C++ Test Suite for closer examination of model and datasets. The red striked out texts denote the original faulted instance, blue buffed texts are the reparation done by the model.

Example 1: Memory allocation match

The flawed code creates a char variable whose size does not match its concatenating destination. The model is able to correct it so that their size matches each other.

\[commandchars=\
{}\] void main(){ char \* data; char data\_buf\[100\]; data=data\_buf; data\[100-1\]='\\0'; { char dest\[50\]=""; strncat(dest,data,strlen(data)); dest\[50-1\]='\\0'; printLine(data); } }

Example 2: Redundant code

This is an example that the model deletes repeated code where a variable is freed twice.

\[commandchars=\
{}\] void main(){ char \* data; data=NULL; data=(char \*)malloc(100\*sizeof(char)); free(data); }

Example 3: Possible Overflow

Here we show a slightly questionable example of correction provided by the dataset. In order to prevent potential string overflow emerging from environment variable, the repair suggestion given by the Juliet Test Suite is to abort the entire part of concatenating the environment string and replace the variable with an arbitrary string "\*.\*". This "correction" is easy for the model to learn, however, it has changed the original purpose of the program.

\[commandchars=\
{}\] void main(){ char \* data; char data\_buf\[100\]=""; data=data\_buf; \_spawnl(\_P\_WAIT,COMMAND\_INT\_PATH, COMMAND\_INT\_PATH, COMMAND\_ARG1,COMMAND\_ARG2, COMMAND\_ARG3,NULL); }

Example 4: Correction across functions

In this example, the models demonstrates the ability of making connections across the whole instance, between different functions. Here it prevents potential overflow in the sink function caused by a variable that was passed from the main function by adding an if condition.

\[commandchars=\
{}\] static void sink(unsigned char data) { unsigned char result = data + 1; } void main() { unsigned char data; data = ' '; data = (unsigned char)rand(); sink(data); }

 

Alternative method for small datasets: Transfer Learning
--------------------------------------------------------

One main difficulty that researchers often come across when attempting to apply machine learning methods to PLC problems is the availability of suitable datasets. Although there are many datasets and shared tasks available on @datasets, most of them includes less than 1,000 examples. This makes neural network based methods nearly impossible. To tackle this problem, we take the idea of transfer learning from @pan2009survey.

Our idea is to take the encoder part of the model that was trained on Juliet Test Suite, and attach it to a untrained decoder, which was designed for the specific problem. We aim to take the advantage that codes written in the same coding language shares the same syntax library and same construction rules.

Since many datasets available only provide the faulted code and their corresponding fault categories, here we give an example of fault classification using transfer learning, applying the model pre-trained on Juliet Test Suite for C/C++ on ITC benchmark (@itc2015).

 

### Model structure

Given a faulted code instance, our goal is to train a classification model that predicts the type of error of the faulted code from a given list of error categories.

We keep the encoder part of the pre-trained model and use it directly as the encoder in the classification problem. The exception is the embedding layer, because the vocabulary in the new dataset will contain new variable names that did not occur in pre-trained embedding, although the syntax will be the same. In practice, we manually expanded the embedding layer to accommodate the new "words", but keep the embedding of the old "words" unchanged. In order to add variation from the original model, we also re-initialized the weights in the last encoding layer.

For the decoder, instead of generating a sequence, we take the output of the first time step of the re-initiated decoder, pass it to a linear layer that project it to an $n_{\text{class}}$ dimensional vector. $n_{\text{class}}$ is the number of error classes. Model was trained on minimizing cross-entropy loss with ADAM optimizer.

 

### Results

We extracted 566 C/C++ code instances from the ITC bench mark. These instances are organized into 44 error categories, with the largest category containing around 30 instance and the smallest only containing 2 instances. Then the instances are divided into a training set of 485 instances, a validation set of 42 instances and test set of 39 instances. For comparison, we also tried Pyramid GRU and Pyramid Transformer with same model structure but no prior knowledge from Juliet Test Suites. The result is shown in Table \[tab: TFL\].

For the fresh GRU and Transformer models, we observed that the models has no predicting power as it produces constant prediction over all inputs. There is even no sufficient gradient on the loss landscape as the loss did not reduce during the training. Transfer learning, on the other hand, demonstrates a fair power of prediction, correctly classifies over 60% of instances, despite that ITC benchmark is written in very different style than Juliet Test Suites and that the dataset is 50 times smaller.

This result shows that one is able to use neural-network-based methods in code correction problems despite the shortage of data, which is a common problem in this field.

0.1in

\[tab: TFL\]

Conclusion
==========

In our work, we show that seq2seq models, successful in natural language correction, is also applicable in programming language correction. Our result shows seq2seq models can be well applied in providing suggestions to potential errors, and have a decent correct rate (above 70% in C/C++ dataset and above 50% in Java dataset) in code auto-correction. Although these results are only limited in Juliet Test Suites, we expect that given enough training data, seq2seq models can also perform well when applied on other PLC problems.

Based on the common used encoder-decoder structure, We introduce a general Pyramid Encoder in seq2seq models. Our result demonstrates that this structure significantly reduces the memory cost and computational cost. This is helpful because PLC are generally more computationally expensive than NLC, due to its longer average instance length.

The publicly available datasets in PLC are mostly small and noisy. Most datasets we found contains close to or less than 1000 code instances. This is far less than enough for training seq2seq and many other machine learning models. Our results on transfer learning pointed out a way of processing these small dataset using pre-trained model as an encoder, which boosts the performance by a large amount.

In future, we will further investigate the influence of different architectures in neural networks; for instance, parallel encoder/decoders, Tree2Tree models, etc. On the other hand, instead of code correction, we will modify and examine our model's performance on other tasks such as program generation, code optimising, etc. We will also examine the potential difference between artificial datasets and realistic datasets.

[^1]: See https://github.com/b19e93n/Pyramid-Seq2Seq-Code-Correction

{'source': 'arXiv_out/2001'}