C OMPOSITIONAL G ENERALIZATION AND D ECOMPOSITION IN N EURAL P ROGRAM S YNTHESIS
Google Research
A BSTRACT
When writing programs, people have the ability to tackle a new complex task by decomposing it into smaller and more familiar subtasks.
While it is difﬁcult to measure whether neural program synthesis methods have similar capabilities, what we can measure is whether they compositionally generalize, that is, whether a model that has been trained on the simpler subtasks is subsequently able to solve more complex tasks.
In this paper, we focus on measuring the ability of learned program synthesizers to compositionally generalize.
We ﬁrst characterize several different axes along which program synthesis methods would be desired to generalize, e.g., length generalization, or the ability to combine known subroutines in new ways that do not occur in the training data.
Based on this characterization, we introduce a benchmark suite of tasks to assess these abilities based on two popular existing datasets, SCAN and RobustFill.
Finally, we make ﬁrst attempts to improve the compositional generalization ability of Transformer models along these axes through novel attention mechanisms that draw inspiration from a humanlike decomposition strategy.
Empirically, we ﬁnd our modiﬁed Transformer models generally perform better than natural baselines, but the tasks remain challenging.
I NTRODUCTION
Program synthesis aims to assist programmers by automatically producing code according to a user’s speciﬁcation of what the code should do (Gulwani et al., 2017a).
Search-based program synthesis approaches, such as programming by example (PBE) systems, have been effective for small selfcontained tasks such as short Java functions (Shi et al., 2019), string manipulation (Gulwani, 2011;
Devlin et al., 2017; Shi et al., 2022), and tensor manipulation (Shi et al., 2020).
However, synthesizing complex or long programs can be expensive because the search space grows exponentially with respect to the program length.
Furthermore, many search-based approaches require signiﬁcant engineering effort to adapt to new programming libraries or languages.
Similarly, program synthesizers that use constraint solving (Solar-Lezama et al., 2006; Torlak & Bod´ık, 2013) are successful in narrow domain-speciﬁc languages (DSLs), but they often become intractable for longer programs and can be difﬁcult to extend beyond simple DSLs.
Neural program synthesizers, especially those based on large language models (Chen et al., 2021; Austin et al., 2021; Li et al., 2022), can produce longer or more complex code at a lower computation cost, but their successes are often limited to examples similar to those present in the training data (Furrer et al., 2020).
That is, they do not generalize well to new
APIs, novel concepts, or even novel combinations of concepts.
It is desirable for program synthesizers to generalize in many ways.
For example, an ideal synthesizer would produce longer code without a prohibitive increase in computational cost or a dramatic decrease in code quality.
It would adapt its general programming skills to handle new APIs and concepts with minimal extra guidance or engineering.
It would also be able to mix and match programming concepts, composing different code idioms in novel ways to solve novel problems.
These are all compositional generalization skills that human programmers naturally develop but are often difﬁcult for program synthesizers.
Compositional generality means the ability to generalize to test examples consisting of compositions of components seen during training, but where the distribution of compositional patterns is different (Keysers et al., 2020).
While current program synthesizers are far from reaching these lofty goals, we can measure the compositional generalization abilities of different synthesis techniques to help push the state-of-the-art toward these desirable human-like abilities.
Prior work has evaluated whether natural language processing systems can compositionally generalize, proposing benchmark datasets to measure the ability of language understanding models in interpreting learned concepts, e.g., jump , in compositionally novel contexts, e.g., jump twice (Marcus, 2001; Lake & Baroni, 2018).
We adapt those ideas to focus on how problem-solving in the form of programming is compositional.
For instance, complex computer programs are typically built by composing individual functions and API calls, which can be composed in novel ways to solve novel problems.
In this paper, we identify seven different compositional generalization tasks applicable to program synthesis and propose a new method of creating benchmark datasets that measure these forms of compositional generalization, for both zero-shot and few-shot generalization.
We apply our benchmark-creation method to two popular domains: SCAN (Lake & Baroni, 2018), which involves generating a sequence of actions speciﬁed by a natural language-like command, and RobustFill
(Devlin et al., 2017), which targets string manipulation programs speciﬁed by input-output examples.
Our benchmark-creation method is agnostic to the kind of program speciﬁcation used, and our RobustFill-based benchmark is the ﬁrst compositional generalization dataset using input-output examples to our knowledge, making it particularly applicable to program synthesis.
In addition to proposing benchmark datasets to measure the compositional generality of program synthesizers, we furthermore hypothesize that decomposition is particularly useful for achieving this compositional generality.
Decomposition is the problem-solving technique (broadly applicable even beyond programming) of breaking a complex task into multiple smaller parts, perhaps repeatedly, until each subtask is easy enough to handle.
Decomposition is especially important within software engineering where implementations of subtasks can be combined and reused in modular ways.
Applying decomposition is a skill so fundamental to software engineering that the ﬁrst programming course at Stanford University begins teaching decomposition within the ﬁrst week of class, immediately after introducing basic syntax, the concept of functions, and simple control ﬂow (Parlante, 2022).
Because compositional generality revolves around combining ideas in new ways, and the decomposition approach solves problems by isolating subtasks and combining their solutions, we argue that a decompositional programming strategy is likely to have high compositional generality (although this is not necessarily the only viable strategy).
Hence, we propose variations of the Transformer architecture motivated by the decomposition strategy, where the model is trained to recognize boundaries between subtasks and focus on solving one subtask at a time.
As a bonus, well-decomposed code is a hallmark of good coding style, so it is additionally desirable to encourage synthesizers to produce such code.
In our experiments, we ﬁnd that our decomposition-based Transformer variations outperform the vanilla Transformer architecture for some but not all of the compositional generalization tasks, with a greater improvement over the baseline for SCAN than for RobustFill.
Even so, our compositional generalization benchmarks remain difﬁcult overall in both the zero-shot and few-shot settings.
We hope that the datasets inspire continued research using different kinds of techniques toward the goal of compositionally general program synthesis.
C OMPOSITIONAL G ENERALIZATION IN P ROGRAMMING
The goal in program synthesis is to ﬁnd a program in a given language that is consistent with a speciﬁcation.
Formally, we are given a domain speciﬁc language (DSL) which deﬁnes a space
P of programs.
The task is described by a speciﬁcation X ∈ X and is solved by an unknown program P ∗ ∈ P .
For example, a speciﬁcation can be a set of input/output (I/O) examples denoted
X = { ( I 1 , O 1 ) , . . .
( I N , O N ) } .
Then, solving speciﬁcation X means ﬁnding a program P (not necessarily P ∗ ) that correctly solves all of the examples: P ( I i )
=
O i , ∀ i .
A speciﬁcation can also be a natural language description of a task, and the corresponding program implements said task.
Program synthesizers are more robust and more broadly applicable if they generalize well.
In this section we discuss several distinct forms of generalization that are desirable in program synthesis.
Current program synthesizers do not achieve high generalization in all of these ways.
At a high level, we identify three broad categories of generalization that an “ideal program synthesizer” should have:
• Length generalization : Produce longer code than appeared in the training set, but without a prohibitive increase in computational cost, and without a substantial decrease in quality.
• Mix and match concepts : Compose code idioms in novel ways to solve novel problems, but without combinatorially many training examples covering all combinations.
Apply general principles : Adapt to new, updated, or custom APIs by drawing on knowledge of other similar APIs, without excessive guidance or engineering.
These kinds of generalization can be described as compositional generalization , which revolves around understanding how basic building blocks can be composed in different ways to create larger structures.
Prior work in natural language processing has studied compositionality in natural language (Chomsky & Lightfoot, 2002; Talmor & Berant, 2018; Lake & Baroni, 2018; Keysers et al., 2020;
Gu et al., 2021).
For example, the SCAN dataset (Lake & Baroni, 2018) tests compositional generalization for translation models.
The SCAN task is to translate from a language-like command such as “jump left twice and walk” to a sequence of actions, in this case [LTURN, JUMP, LTURN,
JUMP, WALK] .
One compositional generalization task would be to train a model on commands except for those including “jump right”, and then test on commands containing “jump right”.
This zero-shot generalization task requires the model to understand “jump” and “right” individually, as well as the compositional pattern of an action verb followed by a direction.
Such understanding can be drawn from other training examples including “jump left”, “walk left”, and “walk right”.
We adapt compositional generalization to the context of program synthesis, focusing on how problemsolving (in the form of programs) is compositional.
Regardless of the programming language or
DSL, programs nearly always consist of compositions of smaller parts.
In general, a “program part” could mean a line of code, a block of statements, a function, or some other natural DSL-speciﬁc portion of code, where multiple such portions can be combined into a full program.
We can even view SCAN action sequences as programs (with SCAN commands being the speciﬁcation).
For
SCAN, we choose to deﬁne “parts” to be the portions of the action sequence that were separated by conjunctions (“and” and “after”) in the command.
In the example above, the program parts would be [LTURN, JUMP, LTURN, JUMP] and [WALK] , corresponding to “jump left twice” and “walk” from the command.
We use the notion of program parts to study how they are combined with different compositional patterns.
Thus, the conventions for partitioning a program into its composed parts may vary depending on the DSL and the compositional patterns being tested.
We expand the three broad categories of generalization above into 7 concrete compositional generalization tasks applicable to program synthesis.
Each generalization task describes a method of creating training and test sets with disjoint distributions, so that generalization may be tested in a zero-shot or few-shot setting.
The generalization tasks are as follows:
Length-Generalization : Can a model produce longer code than seen in training, when the problem requires it?
Here, “length” is measured by the number of composed parts in the program, not simply the number of tokens, so there is more emphasis on generalizing to more complex compositional patterns.
For this generalization task, we train on problems of lengths 1 to n and test on lengths n + 1 to m (where m > n ).
In our experiments we choose n = 6 and m = 10 .
Length-Generalization-Hard : Similar to above, but train on problems of length exactly n and test on lengths 1 to m except n .
To succeed on this generalization task, the synthesizer must recognize that problems may have varying difﬁculty with corresponding solutions of varying lengths, without seeing this fact demonstrated during training.
Length-Generalization-Hardest : Similar to above, but train on tasks of length exactly 1 and test on lengths 2 to n .
Because the training data has no examples of how program parts may be composed, we do not expect neural models to achieve high zero-shot generalization of this kind.
Few-shot generalization is more interesting for this task—after mastering how to solve individual parts of a program, the synthesizer must quickly learn the compositional patterns for composing those parts into larger programs.
Compose-Different-Concepts (a form of “mix and match concepts”):
Can a model use concepts in different combinations than seen in training?
We partition the DSL operations into multiple groups
or concepts , 1 train on compositions of operations from the same concept, and test on compositions from different concepts.
For example, if two concepts consist of operations { A 1 , A 2 , . . . } and { B 1 , B 2 , . . . } respectively, then this generalization task involves training on programs of the forms
A i ◦ A j and B i ◦ B j , and testing on the forms
A i ◦ B j and B i ◦ A j .
As a real-world example, this generalization task is similar to training on scripts containing only TensorFlow or only NumPy, but synthesizing code using both libraries.
Switch-Concept-Order (a form of “mix and match concepts”): Can a model compose concepts in different orders than seen in training?
We again partition the DSL operations into multiple concepts (groups).
We train on compositions of operations drawn from one sequence of concepts and test on a different sequence of concepts, e.g., train on A i ◦ B j and test on B i ◦ A j .
As a real-world example, in the training data a function might be primarily used to validate inputs at the beginning of the code, but we want to use the function in a different context, e.g., to validate results at the end of the code.
Compose-New-Operation (a form of “apply general principles”): Can a model learn to use a new isolated operation within a larger composition ?
In this task, we train on the isolated operation and compositions without the operation, and test on compositions using the operation.
For instance, in the SCAN domain, we could train on “walk left after run twice” and “jump”, and test on “jump left after jump twice”.
A real-world example of this kind of generalization would be composing a new function with others in a larger solution, after seeing examples of the function used in isolation.
Add-Operation-Functionality (a form of “apply general principles”): Can a model extend its understanding of an operation by drawing on parallels to other operations?
We omit from the training data some functionality of an operation that could be inferred from other context, and test on programs using that functionality.
For instance, in the SCAN domain, we could train on commands that do not contain “around right” (but contain other similar constructions like “opposite left” and “opposite right”), and test on commands containing “around right”.
This task can occur in the real world when a library function is upgraded with a new parameter whose behavior can be inferred from other functions.
B ENCHMARK C REATION
We create benchmark datasets for the 7 kinds of compositional generalization tasks described in
Section 2 for two popular domains, SCAN (Lake & Baroni, 2018) and RobustFill (Devlin et al., 2017).
While Section 2 focused on general descriptions of the tasks, this section instantiates these tasks for our speciﬁc domains.
Our benchmark creation process works for both natural-language speciﬁcations (as in SCAN) and input-output (I/O) speciﬁcations (as in RobustFill).
While the SCAN domain was used in prior work in natural language processing (Lake & Baroni, 2018), we have expanded the domain to make our benchmark more applicable to program synthesis.
Furthermore, our RobustFill benchmark is the ﬁrst dataset for measuring compositional generalization for program synthesis from I/O examples.
In the SCAN domain, the objective is to translate from a natural-language command to a program that is a sequence of actions.
Lake & Baroni (2018) originally describes SCAN commands as having at most one “and” or “after” conjunction, but we generalize the domain so that commands can contain an arbitrary number of “and” and “after” conjunctions between parts of the command.
2 We treat these conjunctions as the boundaries between program parts, so a command with n parts will have n − 1 conjunctions and should be translated to an action sequence containing n corresponding parts, although corresponding command and action sequence parts will appear in different orders whenever there is an “after” conjunction.
We show the DSL for commands, as well as how commands are translated to programs in Appendix A.
In the RobustFill domain, the objective is to synthesize a string manipulation program from I/O examples.
A RobustFill program is a concatenation of expressions, where an expression may be an operation that extracts a substring from the input, an operation that returns a modiﬁed version of the input, a special Compose operation (applying a modiﬁcation operation to the result of another operation), or a constant string.
See Appendix A for the full DSL of how programs are generated.
Due to this program structure, we treat each expression as a program part .
Appendix B provides more details for the setup of speciﬁc generalization tasks for both domains.
M ODELS
We approach our compositional synthesis benchmarks using a sequence-to-sequence (seq2seq) model, which has been shown to be successful on various natural language (Bahdanau et al., 2016; Vaswani et al., 2017) and program synthesis tasks (Parisotto et al., 2017; Devlin et al., 2017).
In this paper, we choose our seq2seq model to be a Transformer due to its impressive performance on natural language tasks over traditional RNNs (Vaswani et al., 2017).
Section 4.1 describes a baseline Transformer adapted to program synthesis.
In Section 4.2, we present modiﬁcations to the baseline model to encourage decomposition.
We call the modiﬁed architecture the Decompositional Transformer .
4. B ASELINE T RANSFORMER
Our baseline Transformer consists of two modules.
First, a Transformer encoder receives the speciﬁcation X word-by-word and produces an encoding, E ← TransformerEncoder( X ) .
Then, a
Transformer decoder takes the encoding and autoregressively generates a program token-by-token.
Formally, let P t − 1 =
[ p 1 , p 2 , . .
. , p t − 1 ] be the program generated so far.
The decoder predicts the next program token as p t ← TransformerDecoder
( P t − 1 , E ) .
As described by Vaswani et al.
(2017), the Transformer encoder and decoder both apply a stack of self-attention and feed-forward units.
In the case of speciﬁcation X being multiple I/O examples, our Transformer architecture performs double attention analogous to Devlin et al.
That is, for each example ( I i , O i ) , the encoder behaves as E i ← TransformerEncoder
( I i , O i ) , where the encoder now performs self-attention on input
I i followed by cross-attention on output O i to I i .
Finally, the encoding E is simply the concatenation across examples E ← Concat(( E i )
Ni =1 ) where N is the number of examples.
Relative attention.
Early self-attention mechanisms have added representations of the absolute positions of tokens to its inputs (Vaswani et al., 2017).
However, we use representations of relative positions, or distances between tokens, in line with recent work showing that relative attention is advantageous, particularly on length-generalization tasks (Shaw et al., 2018; Csord ´ as et al., 2021).
By considering logarithmic distances, our model is also encouraged to attend to more recent tokens during decoding, which can be desirable when programs consist of multiple smaller parts.
4. D ECOMPOSITIONAL T RANSFORMER
Inspired by the human problem-solving and programming strategy of decomposition, our Decompositional Transformer architecture leverages the baseline architecture but ensures that program parts are decoded independently of one another, using novel attention mechanisms.
We accomplish this decomposition using two notable modiﬁcations to the baseline Transformer architecture:
Subprogram separators.
We introduce a new separator token SEP to the program vocabulary.
This token will partition programs into sequences of program parts .
The program parts can be composed, for instance via concatenation, to form the full program.
We can straightforwardly add such tokens into the training data generated as described in Section 3.
In this manner, we provide explicit training supervision for the compositional nature of the ground-truth programs.
Thus, our models are trained to predict a SEP token after completing each program part.
To compensate during evaluation, we remove all SEP tokens from the generated program before evaluating its correctness.
Decompositional attention masks.
We incorporate novel attention mechanisms to ensure that program parts are decoded separately.
As in the baseline architecture, we ﬁrst use a Transformer to
Speciﬁcation: “jump left twice and run right after walk thrice”
Program: [Figure] encoder to produce an encoding E ← TransformerEncoder( X ) .
Let P t − 1 again be the program generated so far.
In contrast to the baseline Transformer, during decoding, the next token in the program is instead generated as p t ← TransformerDecoder( Q t − 1 , E ) , where we apply an attention mask to the self-attention layers so that Q t − 1 ⊆
P t − 1 consists of tokens relevant to solving the current subtask.
More speciﬁcally, if p t − 1 is not SEP , then Q t − 1 consists of the program part generated so far, namely all program tokens starting from the most recent SEP (inclusive).
Now, if p t − 1 is
SEP , then our model must identify the next subtask to solve, which naturally should depend on the previously-solved subtasks.
We propose three different choices of Q t − 1 when p t − 1 is SEP , where the more tokens Q t − 1 contains, the more information we give to our model to identify the next subtask:
Sep-Full-Attention :
In the most general case, we provide the Transformer decoder with the entire program generated so far, i.e., Q t − 1 =
P t − 1 when p t − 1 is SEP . 2.
Sep-to-Sep-and-Last :
In this case, Q t − 1 contains all previous SEP tokens, as well as the last program token in each previous program part.
We use the last tokens because they attend to their entire respective program part during decoding, thus providing a summary of what that part does. 3.
Sep-to-Last :
In the most restrictive case, Q t − 1 only contains the last program token in each previously generated program part.
We provide an illustration of each attention mask on an example program in Figure 1.
Note that relative attention encourages a similar behavior in attending more strongly to recent tokens; however, our attention masks are stricter and explicitly constrain attention to only include the necessary tokens.
E XPERIMENTS AND D ISCUSSION
We trained the various methods in Section 4 on each compositional generalization task in the SCAN and RobustFill datasets described in Section 3.
We trained with batch size 128 and default settings for hyperparameters (details in Appendix C), training each method 3 times with different random initializations.
We used 10K training steps for SCAN and 1M training steps for RobustFill, and we generated enough synthetic training data to avoid repeating examples.
After training for each generalization task, we evaluate on 10K test examples to measure zero-shot generalization.
Then, we ﬁne-tune the trained models on a single batch containing 20 examples from the training distribution and 20 from the test distribution, repeated for 30 steps.
Finally, we evaluate again on the same 10K test examples to measure few-shot generalization.
SCAN results are in Table 1 and RobustFill results are in Table 2.
For a more visual representation, Appendix D contains bar graphs for the same data.
All three improvements to vanilla Transformer (relative attention, separator tokens, and attention masks) generally help overall.
In the most extreme case, our best model using the Sep-to-Last attention mask has 74.4% zero-shot generalization for SCAN Compose-Different-Concepts , compared [Table] [Table] to 29.2% for a baseline Transformer with relative attention, or 10.5% without any of the improvements.
However, for some generalization tasks, the performance difference between models is much smaller.
Interestingly, adding separator tokens to the baseline Transformer (with and without relative attention) slightly decreases performance on zero-shot length generalization for both datasets.
This may be because the number of program parts is more obvious to the model, so the model is less likely to predict more SEP tokens than it has seen during training.
Thus, the model may have difﬁculty generalizing to out-of-distribution lengths.
Despite this drawback, applying our attention masks (enabled by the separator tokens) leads to the best length generalization in most cases.
All models struggled with zero-shot Switch-Concept-Order .
The ordering pattern is likely very obvious to the Transformer, much like how a language model would learn that sentences start with capital letters and end with punctuation.
Again we observe that the easier a pattern is to see, the harder zero-shot generalization would be—the model is more likely to overﬁt to that particular pattern, making it unlikely to deviate from that pattern when needed for generalization.
For several tasks, in particular Switch-Concept-Order in both domains, few-shot ﬁne-tuning is very effective.
Even though the model only sees 20 examples from the test distribution, the best model improves from 6.6% to 53.6% for RobustFill, or 17.5% to 66.8% for SCAN.
With ﬁne-tuning,
our
Decompositional Transformer models exceed 90% generalization on RobustFill’s
Compose-DifferentConcepts and SCAN’s
Compose-New-Operation and Add-Operation-Functionality .
Finally, we note that none of the three variations of attention masks were consistently better than any others.
Thus, it is possible that the best attention mask type could be application-speciﬁc.
For instance, Sep-to-Last is the best for zero-shot Compose-Different-Concepts in both domains, which can be explained by the observation that a model would perform well on this generalization task if it can effectively “forget” what concept was used in previous program parts, and Sep-to-Last is the most sparse attention mask with the least attention to previous parts.
R ELATED W ORK
Program Synthesis.
For surveys on program synthesis and machine learning for software engineering, see Gottschlich et al.
Solar-Lezama (2018); Gulwani et al. (2017b); Allamanis et al.
Much attention has focused on machine learning for programming by example (Devlin et al., 2017; Bunel et al., 2018;
Parisotto et al., 2017; Ellis et al., 2020).
Many methods incorporate learning to guide the search over programs, such as using learned premise selection (Balog et al., 2017; Odena & Sutton, 2020), syntax-guided search (Yin & Neubig, 2017; Lee et al., 2018), bottom-up search (Barke et al., 2020; Shi et al., 2020), two-level search (Nye et al., 2019), per-example search (Shrivastava et al.), and execution-guided synthesis methods (Zohar & Wolf, 2018; Ellis et al., 2019;
Chen et al., 2019; Odena et al., 2020; Shi et al., 2022).
Another class of program synthesis methods are symbolic search methods (Solar-Lezama, 2018; Gulwani et al., 2017b), such as bottom-up search and satisﬁability solvers.
Since purely symbolic search will not have problems with compositional generalization (barring failures or timeouts in search), it is an intriguing question for future work whether learning-based search methods face challenges with compositional generalization.
More generally, there is less work on systematic generalization for machine learning for code, although Bieber et al.
(2020) studies length generalization in the context of the learning-to-execute task (Zaremba & Sutskever, 2014).
Compositional Generalization Benchmarks.
Many datasets have been proposed by the NLP community to evaluate understanding of natural language sentences with compositionally novel structures, such as SCAN (Lake & Baroni, 2018).
These benchmarks are either constructed by synthesizing examples based on a ﬁne-grained schema of generalization patterns like this work (Bahdanau et al., 2019; Keysers et al., 2020; Kim & Linzen, 2020), or by repartitioning existing datasets with i.i.d.
samples into splits with disjoint compositional structures (Finegan-Dollak et al., 2018; Shaw et al., 2021).
Our dataset is related to the COGS benchmark (Kim & Linzen, 2020), which deﬁnes a taxonomy of compositional structures in English syntax for natural language understanding.
While many generalization concepts are similar to those proposed in Section 2 (e.g., extend operation functionality), we focus on measuring and modeling compositional generalization of computer programs under task speciﬁcations in both natural language and I/O examples.
Improving Compositional Generalization.
A large body of work develops specialized neural architectures with improved generalization performance (Russin et al., 2019; Li et al., 2019; Liu et al., 2020; Chen et al., 2020; Herzig & Berant, 2020), but is typically limited to speciﬁc domains and tasks.
More generalized approaches have been proposed, such as meta-learning (Lake, 2019;
Wang et al., 2020; Conklin et al., 2021), data augmentation (Andreas, 2020; Oren et al., 2021; Aky¨urek et al., 2021;
Wang et al., 2021; Qiu et al., 2021), and improving the representation of programs (Furrer et al., 2020; Herzig et al., 2021).
Related to our work, recent studies attempt to regularize the attention distribution over source tokens to improve generalization of language understanding models (Oren et al., 2020;
Yin et al., 2021), which encourage the model to attend to the aligned concept in the input (e.g., “right”) when predicting a function (e.g., Right ).
Instead of relying on such alignment information between the source and targets to regularize cross-attention distributions, we mask the self-attention scores in the decoder to capture the compositionality of programs, which is applicable to domains like RobustFill where the source-target alignments are not clearly deﬁned.
C ONCLUSION
We argue that compositional generalization is particularly important for neural program synthesis, for two reasons.
On the practical side, we would like synthesizers to be able to length generalize, generalize to novel combinations of concepts, and so on.
On the conceptual side, measuring compositional generalization might give us insight into what problem-solving strategies are learned by neural program synthesizers.
To that end, we propose a suite of generalization tasks, which measure different types of compositional generalization that are desirable for program synthesis.
These tasks can be applied to different synthesis domains to produce a set of benchmarks; we have introduced benchmarks for string manipulation programs and a simple navigation domain.
We show that these benchmarks are particularly difﬁcult for current sequence to sequence models and we present some early results on modiﬁcations to the Transformer attention mechanism to encourage better generalization.
Future work could explore whether large pre-trained Transformers also have difﬁculty with these benchmarks, as well as further methods for improving compositional generalization
A SCAN AND R OBUST F ILL DSL S
Figure 2 contains the DSL for SCAN translation tasks, and Figure 3 contains the DSL for our
RobustFill programs.
Command C :=
C 1 “ after ” C 2 | D
D := D 1 “ and ” D 2 | P
Part P := Q | Q “ twice ” | Q “ thrice ”
Q :=
l | r | a
Left-concept l := v “ left ” | v “ opposite left ” | v “ around left ”
Right-concept r := v “ right ” | v “ opposite right ” | v “ around right ”
Verb v := “ turn ” | a
Action a := “ walk ” | “ look ” | “ run ” | “ jump ”
C 1 “ after ” C 2 → C 2 C
D 1 “ and ” D 2 → D 1 D
Q “ twice ” → Q Q
Q “ thrice ” → Q Q Q “ turn left ” → LTURN “ turn right ” → RTURN a “ left ” → LTURN a a “ right ” → RTURN a “ turn opposite left ” → LTURN LTURN “ turn opposite right ” → RTURN RTURN a “ opposite left ” → LTURN LTURN a a “ opposite right ” → RTURN RTURN a “ turn around left ” → LTURN LTURN LTURN LTURN “ turn around right ” → RTURN RTURN RTURN RTURN a “ around left ” → LTURN a LTURN a LTURN a LTURN a a “ around right ” → RTURN a RTURN a RTURN a RTURN a “ walk ” → WALK “ [Figure]
[Figure]
B SCAN AND R OBUST F ILL G ENERALIZATION T ASK D ETAILS
RobustFill Details.
Unless stated otherwise, all programs described in the following paragraph have length between 2 and 6 (number of program parts).
For Compose-Different-Concepts , we group together all of the substring operations into substring concepts and all of the modiﬁcation operations plus constant strings as non-substring concepts (the Compose operation is omitted).
We use the same concepts for Switch-Concept-Order , where training examples use only the substring concept for the ﬁrst half of the parts and only the non-substring concept for the latter half, and test examples
Program P :=
Concat ( e 1 , e 2 , . . . )
Expression e := s | m | o | ConstStr ( c )
Compose o :=
m 1 ( m 2 ) | m ( s )
Substring s := SubStr ( k 1 , k 2 )
| GetSpan ( r 1 , i 1 , b 1 , r 2 , i 2 , b 2 ) |
GetToken ( t, i ) | GetUpto ( r ) |
GetFrom ( r )
Modiﬁcation m :=
ToCase ( a ) | Replace ( δ 1 , δ 2 ) | Trim () | GetFirst ( t, i ) | GetAll ( t ) | Substitute ( t, i, c )
| SubstituteAll ( t, c ) | Remove ( t, i ) | RemoveAll ( t )
Regex r :=
t 1 | . . .
| t n | δ 1 | . . .
| δ m
Type t := NUMBER | WORD | ALPHANUM | ALL CAPS | PROP CASE | LOWER | DIGIT | CHAR
Case a :=
PROPER | ALL CAPS | LOWER
Position k := − 100 | − 99 | . . .
| 1 | 2 | . . .
|
Index i := − 5 | − 4 | . . .
| − 1 | 1 | 2 | . . .
|
Boundary b := START | END
Delimiter δ := & , . ?
@()[]% {} / :; $#” (cid:48)
Character c :=
A − Z | a − z | 0 − 9 | & , . ?
have the ordering reversed.
For Compose-New-Operation , 25% of training examples are lengthprograms containing only a Compose operation, the remainder of the training examples are length 2-6 programs without the Compose operation, and the test examples are length 2-6 programs that use the Compose operation.
For Add-Operation-Functionality , all examples are length 1-6 programs, training examples are those where a substring operation is not used within a Compose operation, and test examples are those where a substring operation is used within a Compose operation.
SCAN Details.
We create compositional generalization tasks for the SCAN domain in largely the same way as for the RobustFill domain, with the following differences.
For Compose-DifferentConcepts and Switch-Concept-Order , we use all left-direction phrases as one concept, all rightdirection phrases as the other concept, and omit phrases without a direction.
For Compose-NewOperation , 10% of training examples are (exactly) the length 1 “jump” command, the remaining training examples are length 1-6 commands that do not contain “jump”, and the training examples are length 1-6 commands that do contain “jump” (but are not exactly “jump” itself).
For Add-OperationFunctionality , training commands do not contain “around right”, while test commands do contain “around right”.
The setup of the latter two generalization tasks closely mirrors tasks from Lake &
Baroni (2018).
C M ODEL AND T RAINING H YPERPARAMETERS
For our models, we used default hyperparameters already existing in the frameworks used in our implementation.
In particular, the Transformer has 4 attention heads, 3 layers, a hidden dimension of 512, and an embedding dimension of 256.
Relative attention uses 32 different buckets for relative positions, with a maximum distance of 128.
We use a dropout rate of 0.1.
During training, we use a learning rate schedule consisting of a base learning rate of 1 × 10 − 3 , linear warmup of 16000 steps, and square root decay.
During ﬁne-tuning, we use a constant learning rate of 1 × 10 − 4 .
D P LOTS FOR SCAN AND R OBUST F ILL R ESULTS
Table 1 and Table 2 in Section 5 provide zero-shot and few-shot generalization results for SCAN and RobustFill.
Figure 4, Figure 6, Figure 5, and Figure 7 provide bar graphs for a more visual representation of the same data.