We introduce the hierarchical compositional network (HCN), a directed generative model able to discover and disentangle, without supervision, the building blocks of a set of binary images. The building blocks are binary features defined hierarchically as a composition of some of the features in the layer immediately below, arranged in a particular manner. At a high level, HCN is similar to a sigmoid belief network with pooling. Inference and learning in HCN are very challenging and existing variational approximations do not work satisfactorily. A main contribution of this work is to show that both can be addressed using max-product message passing (MPMP) with a particular schedule (no EM required). Also, using MPMP as an inference engine for HCN makes new tasks simple: adding supervision information, classifying images, or performing inpainting all correspond to clamping some variables of the model to their known values and running MPMP on the rest. When used for classification, fast inference with HCN has exactly the same functional form as a convolutional neural network (CNN) with linear activations and binary weights. However, HCN’s features are qualitatively very different.
We introduce the hierarchical compositional network (HCN), a directed generative model able to discover and disentangle, without supervision, the building blocks of a set of binary images. The building blocks are binary features defined hierarchically as a composition of some of the features in the layer immediately below, arranged in a particular manner. At a high level, HCN is similar to a sigmoid belief network with pooling. Inference and learning in HCN are very challenging and existing variational approximations do not work satisfactorily. A main contribution of this work is to show that both can be addressed using max-product message passing (MPMP) with a particular schedule (no EM required). Also, using MPMP as an inference engine for HCN makes new tasks simple: adding supervision information, classifying images, or performing inpainting all correspond to clamping some variables of the model to their known values and running MPMP on the rest. When used for classification, fast inference with HCN has exactly the same functional form as a convolutional neural network (CNN) with linear activations and binary weights. However, HCN’s features are qualitatively very different.
1 INTRODUCTION
Deep neural networks coupled with the availability of vast amounts of data have proved very successful over the last few years at visual discrimination (Goodfellow et al., 2014; Kingma & Welling, 2013; LeCun et al., 1998; Mnih & Gregor, 2014). A basic desire of deep architectures is to discover the blocks –or features– that compose an image (or in general, a sensory input) at different levels of abstraction. Tasks that require some degree of image understanding can be performed more easily when using representations based on these building blocks.
It would make intuitive sense that if we were to train one of the above models (particularly, those that are generative, such as variational autoencoders or generative adversarial networks) on images containing, e.g. text, the learned features would be individual letters, since those are the building blocks of the provided images. In addition to matching our intuition, a model that realizes (from noisy raw pixels) that the building blocks of text are letters, and is able to extract a representation based on those, has found meaningful structure in the data, and can prove it by being able to efficiently compress text images.
However, this is not the case with existing incarnations of the above models1. We can see in Fig. 1 the features recovered by the hierarchical compositional network (HCN) from a single image with no supervision. They appear to be reasonable building blocks and are easy to find for a human. Yet we are not aware of any model that can perform such apparently simple recovery with no supervision.
The HCN is a multilayer generative model with features defined at each layer. A feature (at a given position) is defined as the composition of features of the layer immediately below (by specifying their relative positions). To increase flexibility, the positions of the composing features can be perturbed slightly with respect to their default values (pooling). This results in a latent variable model, with some of the latent variables (the features) being shared for all images while others (the pool states) are specific for each image.
Comparing HCN with other generative models for images, we note that existing models tend to have at least one of the following limitations: a) priors are not rich enough; typically, the sources of variation are not distributed among the layers of the network, and instead the generative model is expressed as X = f(Y )+ε where Y and ε are two set of random variables, X is the generated image and f(·) is the network, i.e., the entire network behaves as a sophisticated deterministic function, b) the inference method (usually a separate recognition network) considers all the latent variables as independent and does not solve explaining away, which leads to c) the learned features being not directly interpretable as reusable parts of the learned images.
Although directed models enjoy important advantages such as the ability to represent causal semantics and easy sampling mechanics, it is known that the “explaining away” phenomenon makes inference difficult in these models (Hinton et al., 2006). For this reason, representation learning efforts have largely focused on undirected models (Salakhutdinov & Hinton, 2009), or have tried to avoid the problem of explaining away by using complementary priors (Hinton et al., 2006).
An important contribution of this work is to show that approximate inference using max-product message passing (MPMP) can learn features that are composable, interpretable and causally meaningful. It is also noteworthy that unlike previous works, we consider the weights (a.k.a. features) to be latent variables and not parameters. Thus, we do not use separate expectation-maximization (EM) stages. Instead, we perform feature learning and pool state inference jointly as part of the same message passing loop.
When augmented with supervision information, HCN can be used for classification, with inference and learning still being taken care of by a largely unmodified MPMP procedure. After training, discrimination can be achieved via a fast forward pass which turns out to have the same functional form as a convolutional neural network (CNN).
The rest of the paper is organized as follows: we describe the HCN model in Section 2; Section 3 describes learning and inference in the single layer and multilayer HCNs; Section 4 tests the HCN experimentally and we conclude with a brief discussion in Section 5.
2 THE HIERARCHICAL COMPOSITIONAL NETWORK
The HCN model is a discrete latent variable model that generates binary images by composing parts with different levels of abstraction. These parts are shared across all images. Training the model involves learning such parts from data as well as how to combine them to create each concrete image. The HCN model can be expressed as a factor graph consisting only of three types of factors: AND, OR and POOL. These perform the obvious binary operations and will be defined more precisely later in this section. The flexibility of the model allows training in supervised, semisupervised and unsupervised settings, including missing image data. Once trained, the HCN can be used for classification, missing value completion (pixel inference), sparsification, denoising, etc. See Fig. 2 for a factor graph of the complete model. Additional details of each layer type are given in Fig. 4.
At a high level, the HCN consists of a class layer at the top followed by alternating convolutional layers and pooling layers. Inside each layer there is a sparsification, a representation and weights
1Discriminative models find features that are good for classification, but not for generation (the training objective is not constrained enough). Existing generative models also fail at recovering the building blocks of an image because they either a) mix positive and negative weights (which turns out to be critical for them being trainable via backpropagation) or b) lack inference mechanisms able to perform explaining away.
(a.k.a. features), each of which is a multidimensional array of latent variables. The class layer selects a category, and within it, which template is going to be used, producing the top-level sparsification. A sparsification is simply an encoding of the representation. A sparsification encodes a representation by specifying which features compose it and where they should be placed. The features are in turn stored in the form of weights. Convolutional layers deterministically combine the sparsification and the weights of a layer to create its representation. Pooling layers randomly perturb the position of the active elements (within a local neighborhood), introducing small variations in the process.
2.1 BINARY CONVOLUTIONAL FEATURE LAYER (SINGLE-LAYER HCN)
This layer can perform non-trivial feature learning on its own. We refer to it as a single-layer HCN. See Section 4.1 for the corresponding experiments.
In this case, since there is no additional top-down structure, a binary image is created by placing features at random locations of an image. Wherever two features overlap, they are ORed, i.e., if a pixel of the binary image is activated due to two features, it is simply kept active. We will call W to the features, S to the sparsification of the image (locations at which features are placed in that image) and X to the image. All of these variables are multidimensional binary arrays.
The values of each of the involved arrays for a concrete example with a single-channel image is given in Fig. 3 (to display S we maximize over f ). The corresponding diagram is shown in Fig. 4.
In practice, each image X is possibly multichannel, so it will have size FX × HX ×WX , where the first dimension is the number of channels in the image and the other two are its height and width. S has size FS × HS ×WS , where the first dimension is the number of features and the other two are its height and width. We refer to an entry of Sn as Sfrc. Setting an entry Sfrc = 1 corresponds to placing feature f at position (r, c) in the final image X . The features themselves are stored in W , which has size FbelowW × FW × HW ×WW , where FW = FS and F belowW = FX . I.e., each feature is a
small 3D array containing one of the building blocks of the image. Those are placed in the positions specified by S, and the same block can be used many times at different positions, hence calling this layer convolutional2.
We can fully specify a probabilistic model for a binary images by adding independent priors over the entries of S and W and connecting those to X through a binary convolution and a noisy channel. The complete model is
p(S) = ∏ frc p(Sfrc) = ∏ frc p Sfrc S (1− pS) 1−Sfrc
p(W ) = ∏ afrc p(Wafrc) = ∏ afrc p Wafrc W (1− pW ) 1−Wafrc (1)
p(X|R) = ∏ arc pnoisy(Xarc|Rarc) with R = bconv(S,W ) and pnoisy(1|0) = p10, pnoisy(0|1) = p01,
which depends on four scalar parameters pS , pW , p01, p10, controlling the density of features in the image, of pixels in each feature, and the noise of the channel, respectively. The indexes a, f, r, c run over channels, features, rows and columns, respectively.
We have used the binary convolution operator R = bconv(S,W ). A binary convolution performs the same operation as a normal convolution, but operates on binary inputs and truncates outputs above 1. Our latent variables are arranged as three- and four-dimensional arrays, so we define R = bconv(S,W ) to mean Ra,:,: = min(1, ∑ f conv2D(Sf,:,:,Wa,f,:,:)) where conv2D(·, ·) is the usual 2D convolution operator, R and S are binary 3D arrays and W is a binary 4D arrays. The operator min(1, ·) truncates values above 1 to 1, performing the ORing of two overlapping features previously mentioned.
The binary convolution (and hence model (1)) can be expressed as a factor graph, as seen in Fig. 4. The AND factor can be written as AND(b|t1, t2) and takes value 0 when the bottom variable b is the logical AND of the two top variables t1 and t2. It takes value −∞ in any other case. The OR factor, OR(b|t1 . . . , tM ) takes value 0 when the bottom variable b is the logical OR of the M top variables t1 . . . , tM . It takes value −∞ in any other case. When this layer is not used in standalone mode, but inside a multilayer HCN, the variables R are connected to the pooling layer immediately below (instead of being connected to the imageX through the noisy channel) and the variables S are connected to the pooling layer immediately above (instead of being connected to the prior).
2.2 THE CLASS LAYER
We assume for now that a single class is present in each image. We can then write log p(c1, . . . , cK) = POOL(c1, . . . , cK |1)
where ck are mutually exclusive binary variables representing which of the K categories is present.
In general, we define POOL(b1, . . . , bM |t = 1) = − logM when exactly one of the bottom variables b1, . . . , bm takes value 1 (we say that the pool is active), and POOL(b1, . . . , bM |t = 0) = 0 when bm = 0 ∀m (the pool is off). It takes value −∞ in any other case.
2Additionally, the convolution implies the relations HX = HW + HS − 1 and WX = WW + WS − 1
Within each category, we might have multiple templates. Each template corresponds to a different visual expression of the same conceptual category. For instance, if one category is furniture, we could have a template for chair and another template for table. Each category has binary variables representing each of the J templates, sjk with j ∈ [1 . . . J ]. If a category is active, exactly one of its templates will be active. The joint probability of the templates is then
log p(SL|c1, . . . , cK) = ∑ k log p(s1k, . . . , sJk|ck) = ∑ k POOL(s1k, . . . , sJk|ck)
where these JK variables are arranged as a 3D array of size 1 × 1 × JK called SL which forms the top-level sparsification of the template. A sample from SL will always have exactly one element set to 1 and the rest set to 0. Superscript L is used to identify the layer to which a variable belongs. Since there are L layers, SL is the top layer sparsification.
2.3 THE POOLING LAYER
In a multilayer HCN, feature layers and pooling layers appear in pairs. Inside layer `, the pooling layer ` is placed below the feature layer `.
Since the convolutional feature layer is deterministic, any variation in the generated image must come from the pooling layers (and the final noisy channel). Each pooling layer shifts the position of the active units in R` to produce the sparsification S`−1 in the layer below. This shifting is local, constrained to a region of size3 HP ×WP × 1, the pooling window. When two or more active units in R` are shifted towards the same position in S`−1, they result in a single activation, so the number of active units in S`−1 is equal or smaller than the number of activations in R`.
The above description should be enough to know how to sample S`−1 from R`, but to provide a rigorous probabilistic description, we need to introduce the intermediate binary variablesU∆r,∆c,f,r,c,, which are associated to a shift ∆r,∆c of the element R`frc. The HP WP intermediate variables associated to the same element R`frc are noted as U ` :,:,frc. Since an element can be shifted to a single position per realization and only when it is active, the elements in U `:,:,frc are grouped into a pool
log p(U `|R`) = ∑ frc log p(U `:,:,frc|R`frc) = ∑ frc POOL(U `:,:,frc|R`frc)
and then S`−1 can be obtained deterministically from U ` by ORing the HP WP variables of U that can potentially turn it on, log p(S`−1|U `) = ∑ fr′c′ log p(S
`−1 fr′c′ |U `) =∑
fr′c′ OR(S `−1 fr′c′ |{U∆r,∆c,f,r,c}r′:r+∆r,c′:c+∆c). i.e., the above expression evaluates to 0 if the above OR relations are satisfied and to −∞ if they are not. 3The described pooling window only allows for spatial perturbations, i.e., translational pooling. A more general pooling layer would also pool in the third dimension (Goodfellow et al., 2013), across features, which would introduce richer variation and also impose a meaningful order in the feature indices. Though we do not pursue that option in this work, we note that this type of pooling is required for a rich hierarchical visual model. In fact, the pooling over templates that we special-cased in the description of the class layer would fit as a particular case of this third-dimension pooling.
2.4 JOINT PROBABILITY WITH MULTIPLE IMAGES
The observed binary image X corresponds to the bottommost sparsification4 S0 after it has traversed, element by element, a noisy channel with bit flip probabilities p(Xfrc = 1|S0frc = 0) = p10 < 0.5 and p(Xfrc = 0|S0frc = 1) = p01 < 0.5. This defines p(X|S0).
Finally, if we consider the weight variables to be independent Bernoulli variables with a fixed perlayer sparse prior p`W that are drawn once and shared for the generation of all images, we can write the joint probability of multiple images, latent variables and weights as log p({Xn, Hn, Cn}Nn=1, {W `}L`=1) = L∑
`=1
log p(W `) + N∑ n=1 log p(Xn|S0n) + log p(SLn |Cn) + log p(Cn)
+ N∑ n=1 L∑ `=1 log p(S`−1n |U `n) + log p(U `n|R`n) + log p(R`n|S`n,W `)
where we have collected all the category variables {ck} of each image in Cn and the remaining latent variables in Hn and for convenience. Each image uses its own copy of the latent variables, but the weights are shared across all images, which is the only coupling between the latent variables.
The above expression shows how, in addition to factorizing over observations (conditionally on the weights), there is a factorization across layers. Furthermore, the previous description of each of these layers implies that the entire model can be further reduced to small factors of type AND, OR and POOL, involving only a few local variables each.
Since we are interested in a point estimate of the features, given the images {Xn}Nn=1 and a (possibly empty)5 subset of the labels {Cn}Nn=1, we will attempt to recover the maximum a posteriori6 (MAP) configuration over features, sparsifications, and unknown labels. Note that for classification, selecting {W `}L`=1 by maximizing the joint probability is very different from selecting it by maximizing a discriminative loss of the type log p({Cn}Nn=1|{Xn}Nn=1, {W `}L`=1), since in this case, all the prior information p(X) about the structure of the images is lost. This results in more samples being required to achieve the same performance, and less invariance to new test data.
Once learning is complete, we can fix {W `}L`=1, thus decoupling the model for every image, and use approximate MAP inference to classify new test images, or to complete them if they include missing data (while benefiting from the class label if it is available).
Even though we only consider the single-class-per-image setting, the compositional property of this model means that we can train it on single-class images and then, without retraining, change the class layer to make it generate (and therefore, recognize) combinations of classes in the same image.
3 LEARNING AND INFERENCE
We will consider first the simpler case of a single-layer HCN, as described in Section 2.1. Then we will tackle inference in the multilayer HCN.
3.1 LEARNING IN SINGLE-LAYER HCN
In this case, for model (1), we want to find
S∗,W ∗ = arg max S,W p(X|S,W )p(S)p(W ). (2)
This is a challenging problem even in simple cases. In fact, it can be easily shown that boolean matrix factorization (BMF), a.k.a. boolean factor analysis, arises as a particular case of (2) in which the
4Alternatively, one could introduce the noisy channel between R0 and X , but that would be equivalent to our formulation using a pooling window of size 1× 1× 1 at the bottommost layer.
5The model was described as unsupervised, but the class is represented in latent variable Cn, which can be clamped to its observed value, if it is available.
6Note that we are performing MAP inference over discrete variables, where concerns about the arbitrariness of MAP estimators (see e.g., (Beal, 2003) Chapter 1.3) do not apply.
heights and widths of all the involved arrays are set to one. BMF is a decades-old problem proved to be NP-complete in (Stockmeyer, 1975) and with applications in machine learning, communications and combinatorial optimization. Another related problem is non-negative matrix factorization (NMF) (Lee & Seung, 1999), but NMF is additive instead of ORing the contributions of multiple features, which is not desired here.
One of the best-known heuristics to address BMF is the Asso (Miettinen et al., 2006). Unfortunately, it is not clear how to extend it to solve (2) because it relies on assumptions that no longer hold in the present case. The variational bound of (Jaakkola & Jordan, 1999) addresses inference in the presence of a noisy-OR gate and was successfully used in by (Šingliar & Hauskrecht, 2006) to obtain the noisy-OR component analysis (NOCA) algorithm. NOCA addresses a very similar problem to (2), the two differences being that a) the weight values are continuous between 0 and 1 (instead of binary) and b) there is no convolutional weight sharing among the features. NOCA can be modified to include the convolutional weight sharing, but it is not an entirely satisfactory solution to the feature learning problem as we will show. We observed that the obtained local maxima, even after significant tweaking of parameters and learning schedule, are poor for problems of small to moderate size.
We are not aware of other existing algorithms that can solve (2) for medium image sizes. The model (1) is directly amenable to mean-field inference without requiring the additional lower-bounding used in NOCA, but we experimented with several optimization strategies (both based in mean field updates and gradient-based) and the obtained local maxima were consistently worse than those of NOCA.
In (Ravanbakhsh et al., 2015) it is shown that max-product message passing (MPMP) produces stateof-the-art results for the BMF problem, improving even on the performance of the Asso heuristic. We also address problem (2) using MPMP. Even though MPMP is not guaranteed to converge, we found that with the right schedule, even with very slight or no damping, good solutions are found consistently.
Model (1) can be expressed both as a directed Bayesian network or as a factor graph using only AND and OR factors, each involving a small number of local binary variables. Finding features and sparsifications can be cast as MAP inference7 in this factor graph.
MPMP is a local message passing technique to perform MAP inference in factor graphs. MPMP is exact on factor graphs without loops (trees). In loopy models, such as (1), it is an approximation with no convergence guarantees8, although convergence can be often attained by using some damping 0 < α ≤ 1. See Appendix C for a quick review on MPMP and Appendix D for the message update equations required for the factors used in this work. Unlike Ravanbakhsh et al. (2015) which uses parallel updates and damping, we update each AND-OR factor9 in turn, following a random in a sequential schedule. This results in faster convergence with less or no damping.
3.2 LEARNING IN MULTILAYER HCN (UNSUPERVISED, SEMISUPERVISED, SUPERVISED)
Despite its loopiness, we can also apply MPMP inference to the full, multilayer model and obtain good results. The learning procedure iterates forward and backward passes (a precise description can be found in Algorithm 1 below). In a forward pass, we proceed updating the bottom-up messages to variables, starting from the bottom of the hierarchy (closer to the image) and going up to the class layer. In a backward pass, we update the top-down messages visiting the variables in top-down order. Messages to the weight variables are updated only in the forward pass. We use damping only in the update of the bottom-up messages from a pooling layer during the forward pass. The AND-OR factors in the binary convolutional layer form trees, so we treat each of these trees as a single factor, since closed form message updates for them can be obtained. Those factors are updated once in random order inside each layer, i.e., sequentially. The pools at the class layer also from a tree, so we also treat them as a single factor. The message updates for AND, OR and POOL factors follow trivially from their definition and are provided in Appendix D.
7Note that we do not marginalize the latent variables (or the weights), but find their MAP configuration given a set of images. The sparse priors on the weights and the sparsification act as regularizers and prevent overfitting.
8MPMP works by iterating fixed point equations of the dual of the Bethe free energy in the zero-temperature limit. Convexified dual variants (see Appendix C) are guaranteed to converge, but much slower.
9Each OR factor is connected to several AND factors which together form a tree. We update the incoming and outgoing messages of the entire tree, since they can be computed exactly.
After enough iterations, weights are set to 1 if their max-marginal difference is positive and to 0 otherwise. This hard assignment converts some of the AND factors into a pass-through and the rest in disconnections. Thus the weight assignments define the connectivity between S` and R` on a new graph without ANDs. This is the learned model, that we can use to perform inference with with on new test images.
3.3 INFERENCE IN MULTILAYER HCN
Typical inference tasks are classification and missing value imputation. For classification, we find that a single forward pass seems good enough and further forward and backward passes are not needed (see Algorithm 1 for the description of the forward and backward passes). For missing value imputation a single forward and top-down pass is enough. In order to achieve higher quality explaining-away10, we use a top-down pass instead of a backward pass. A top-down pass differs from a backward pass in that we replace step 5) with multiple alternating executions of steps 5) and 2). Therefore, it is not strictly a backward pass, but it proceeds top-down in the sense that once a layer has been fully processed, it is never visited again.
Interestingly, the functional form of the forward pass of an HCN is the same as that of a standard CNN, see Section 3.4, and therefore, an actual CNN can be used to perform a fast forward pass.
Algorithm 1 Learning in Hierarchical Compositional Networks
Input: Hyperparameters p01, p10, {p`W }L`=1, data {Xn, Cn}Nn=1 and network structure (pool and weight sizes for each layer) Init Initialize bottom-up messages and messages to {W `} to zero. Initialize the top-down messages to −∞. Initialize messages to W from its prior uniformly at random in (0.9pW , pW ) to break symmetry. Set constant bottom-up messages to S0: m(S0frc) = (k1 − k0)Xfrc + k0 with k1 = log 1−p01p10 and k0 = log
p01 1−p10repeat
Forward pass: for ` in 1, . . . , L do
1) Update messages from OR to U ` in parallel 2) Update messages from POOL to R` in parallel with damping α 3) Update messages from AND-OR to W ` and S` sequentially in random order
end for Update message from all class layer POOLs to SL. Hard assign Cn if label is available. Backward pass: for ` in L, . . . , 1 do
4) Update messages from AND-OR to R` sequentially in random order 5) Update messages from POOL to U ` in parallel 6) Update messages from OR to S`−1 in parallel end for Compute max-marginals by summing incoming messages to each variable
until Fixed point or iteration limit return Max-marginal differences of S`, W ` and R`
3.4 ABOUT THE HCN FORWARD PASS
3.4.1 FUNCTIONAL CORRESPONDENCE WITH CNN
After a single forward pass in an HCN (considering that the weights are known, after training), we get an estimate of the MAP assignment over categories. In practice, this assignment seems good enough for classification and further forward and backward passes are not needed.
The functional form of the first forward pass can be simplified because of the initial strongly negative top-down messages. Under these conditions, the message update rules applied to the pooling layers of the HCN have exactly the same functional form11 as the max-pooling layer in a standard CNN. Similarly, applying the message update rule to the convolutional layers of the HCN —when the
10 To avoid symmetry problems, instead of making the distribution of each POOL perfectly uniform, we can introduce slight random perturbations while keeping the highest probability value at the center of the pool. Doing so speeds up learning and favors centered backward pass reconstructions in the case of ties.
11See the Appendix D for the update rules of the messages of each type factor.
weights are known— has the same functional form as performing a standard (not binary) convolution of the bottom-up messages with the weights, just like in a standard CNN. At the top, the max-marginal over categories will select the one with the template with the largest bottom-up message. This can be realized with max-pooling over the feature dimension as done in (Goodfellow et al., 2013), or closely approximated using a fully connected layer and a softmax, as in more standard CNNs.
Simply put, the binary weights learned by an HCN can be copied to a standard CNN with linear activations and they will both produce the same classification results when we applied to the bottom-up messages (which are a positive scaling of the input data X plus a constant).
3.4.2 INVARIANCE TO NOISE LEVEL
Consider we generate two data sets with the HCN model using the same weights but different bit-flip probabilities. If those probabilities are known, would we use different classifiers for each dataset? If we use a single forward pass, changing p01 and p10 produces a different monotonic transformation of all the bottom-up messages at every layer of the hierarchy, but the selected category, which depends only on which variable has the largest value, will not change. So, with a single-pass classifier, our class estimation does not change with the noise level. This has the important implication that an HCN does not need to be trained with noisy data to classify noisy data. It can be trained with clean data (where there is more signal and learning parts is easier) and used on noisy data without retraining.
4 EXPERIMENTS
In the following, we experimentally characterize both the single-layer and multilayer HCN.
4.1 SINGLE-LAYER HCN
We create several synthetic (both noisy and noiseless) images in which the building blocks –or features– are obvious to a human observer and check the ability of HCN to recover the them. The task is deceptively simple, and the existing the state of the art at this task, NOCA, is unable to solve several of our examples. Since the number of free parameters of the model is so small (3 in the case of a symmetric noisy channel), these can be easily explored using grid search and selected using maximum likelihood. The sensitivity of the results to these parameters is small.
HCN only requires straightforward MPMP with random order over the factors. For NOCA, initializing the variational posterior over the latent sources and choosing how to interleave the updates of this posterior with the update of the additional variational parameters (Šingliar & Hauskrecht, 2006) is tricky. For best results, during each E step we repeated the following 10 times: update the variational parameters for 20 iterations and then update the variational posterior (which is a single closed form update). The M update also required an inner loop of variational parameter updating.
The performance of HCN and NOCA can be assessed visually in Fig. 5. Column (a) shows each input image (these are single-image datasets) and the remaining columns show the features and reconstructions obtained by HCN and NOCA. In some of the input images we have added noise that flips pixels with 3% probability. For HCN (respectively NOCA), we binarize all the beliefs (respectively, variational posteriors) from the [0, 1] range by thresholding at 0.5 and then perform a binary convolution to obtain the reconstruction. Because noise is not included in this reconstruction, a cleaner image may be obtained, resulting in unsupervised denoising (rows 1 and 4 of Fig. 5).
For a quantitative comparison, refer to Tab. 1. One algorithm-independent way to measure performance in the feature learning problem is to measure compression. It is known that to transmit a long sequence of N bits which are 1 with probability p, we only need to transmit NH(p) bits with an optimal encoding, where H is the entropy. Thus sparse sequences compress well. In order to transmit these images without loss, we need to transmit either one sequence of bits (encoding the image itself) or three sequences of bits, one encoding the features, another encoding the sparsification and a last one encoding the errors between the reconstruction and the original image. Ideally, the second method is more efficient, because the features are only sent once and the sparsification and errors sequences are much sparser than the original image. The ratio between the two is shown together with running time on a single CPU. Unused features are discarded prior to computing compression.
4.2 ONLINE LEARNING
The above experiments use a batch formulation, i.e., consider simultaneously all the available training data {Xn}N1 . Since the amount of memory required to store the messages for MPMP scales linearly with the training data, this imposes a practical limit in the number of images that can be processed. In order to overcome this limit, we also consider a particular message update schedule in which the messages outgoing from factors connected to each image and sparsification Xn, Sn are updated only once and therefore, after an image has been processed, can be discarded, since they are never reused. This effectively allows for online processing of images without memory scaling issues. Two modifications are needed in practice for this to work well: first, instead of processing only one image at a time, better results are obtained if the factors of multiple images (forming a minibatch) are processed in random order. Second, a forgetting mechanism must be introduced to avoid accumulating an unbounded amount of evidence from the processed minibatches.
In detail, the beliefs of the variablesW are initialized uniformly at random in the interval (0.9pW , pW ) (we call these initial beliefs b(0)prior(Wafrc)) and the beliefs of the variables {Sn}N1 are initialized to pS . The initial outgoing messages from all the AND-OR factors are set to 0. Since each factor is only processed once, this allows implementing MPMP without ever having to store messages and only requiring to store beliefs. After processing the first minibatch using MPMP (with no damping), we call the resulting belief over each of the weights b(0)post(Wafrc) (as it standard for MPMP of binary variables, beliefs are represented using max-marginal differences in log space). Instead of processing the second minibatch using b(0)post(Wafrc) as the initial belief, we use b (1) prior(Wafrc) = λb (0) post(Wafrc) + (1− λ)b (0) prior(Wafrc), i.e., we “forget” part of the observed evidence, substituting it with the prior. This introduces an exponential weighing in the contribution of each minibatch. The forgetting factor is λ ∈ (0, 1] specifies the amount of forgetting. When λ = 1 this reduces to normal MPMP (no forgetting), when λ = 0, we completely forget the previous minibatch and process the new one from scratch.
Fig. 6 illustrates online learning. HCN is shown 30 small images containing 5 randomly chosen and randomly placed characters with 3% flipping noise (see Fig. 5.(a) and (b) for two examples). They are learned in different manners. Fig. 5.(c): as a single batch with damping α = 0.8 and using 100 epochs (each factor is updated 100 times); Fig. 6.(d): with minibatches of 5 images, no damping, λ = 0.95 and using 100 epochs; Fig. 6.(e): with minibatches of 5 images, no damping, λ = 0.95, using a single epoch, but using 3000 images, so that running time is the same.
4.3 MULTI-LAYER HCN: SYNTHETIC DATA
We create a dataset by combining two traits: a) either a square (with four holes) or a circle and b) either a forward or a backward diagonal line. This results in four patterns, which we group in two categories, see Fig. 7.(a). Categories are chosen such that we cannot decide the label of an image based only on one of the traits. The position of the traits is jittered within a 3× 3 window, and after combining them, the position of the individual pixels is also jittered by the same amount. Finally, each pixel is flipped with probability 10−3. This sampling procedure corresponds a 2-layer HCN sampling for some parameterization. We generate 100 training samples and 10000 test samples.
4.3.1 UNSUPERVISED LEARNING
We train the HCN as described in Section C on the 100 training data samples, not using any label information. We do set the architecture of the network to match the architecture generating the data. There are four hyperparameters in this model, p01, p10, p1W , p 2 W . Their selection is not critical. We
will choose them to match the generation process. MAP inference does discover and disentangle almost perfectly the compositional parts at the first and second layers of the hierarchy, see Figs. 7.(b) and 8.(a). In 8.(a), rows correspond with templates and columns correspond to each of the features of the first layer. We can see that the model has “understood” the data and can be used to generate more samples from it. Performing inference on this model is very challenging. We are not aware of any previous method that can learn the features of this simple dataset with so few samples. In other experiments we verified that, using local message passing as opposed to gradient descent was critical to successfully minimize our objective function. Results with the quality of Figs. 7.(b) and 8.(a) were obtained in every run of the algorithm. Running time is 7 min on a single CPU.
We can now clamp the discovered weights on both layers and use the fast forward pass to classify each training image as belonging to one of the four discovered templates (i.e., cluster them). We can even classify the test images as belonging to one of the four templates. When doing this, all the images in the training set get assigned to the right template and only 60 out of 10000 images in the test set do not get classified in the right cluster. This means that if we had just 4 labeled images, one from each cluster, we could perform 4-class minimally-supervised classification with just 0.6% error.
Finally, we run a single forward-backward pass of the inference algorithm on a test image with missing pixels. We show the inferred missing pixels in Fig. 7.(c). See also footnote 10.
4.3.2 SUPERVISED LEARNING
Now we retrain the model using label information. This results in the same weights being found, but this time the templates are properly grouped in two classes, as shown in Fig. 8.(a). Classification error on the test set is very low, 0.07%. We now compare the HCN classification performance with that of a CNN with the same functional form but trained discriminatively and with a standard CNN with ReLU activations, a densely connected layer and softmax activation. We minimize the crossentropy loss function with L2 regularization on the weights. The test errors are respectively 0.5% and 2.5%, much larger than those of HCN. We then consider versions of our training set with different levels of pixel-flipping noise. The evolution of the test error is shown in Fig. 8.(c). For the competing methods we needed many random restarts to obtain good results. Their regularization parameter was chosen based on the test set performance.
4.4 MULTI-LAYER HCN: MNIST DATA
We turn now to a problem with real data, the MNIST database (LeCun et al., 1998), which contains 60000/10000 training/testing images of size 28× 28. We want to generalize from very few samples, so we only use the first 40 digits of each category to train. We pre-process each image with a fixed set of 16 oriented filters, so that the inputs are a 16-channel image. We use a 2-layer HCN with 32 templates per class and 64 lower level features of size 26 × 26 and two layers of 3 × 3 pooling, p1W = 0.001, p 2 W = 0.05. These values are set a priori, not optimized. Then we test on both the regular MNIST training set and different corrupted versions12 of it (same preprocessing 12See Appendix E for examples of each corruption type.
and no retraining). We follow the same preprocessing and procedure using a regular CNN with discriminative training and explore different regularizations, architectures and activation types, only fixing the pooling sizes and number of layers to match the HCN. We select the parameterization that minimizes the error on the clean test set. This CNN uses 96 low level features. Results for all test sets are reported on Fig. 9.(c). It can be seen that HCN generalizes better. The weights of the first layer of the HCN after training are shown in Fig. 9.(a). Notice how HCN is able to discover reusable parts of digits.
The training time of HCN scales exactly as that of a CNN. It is linear in each of its architectural parameters: Number of images, number of pixels per image, features at each layer, size of those features, etc. However, the forward and backward passes of an HCN are more complex and optimized code for them is not readily available as it is for a CNN, so a significant constant factor separates the running times of both. Training time for MNIST is around 17 hours on a single CPU. The RAM required to store all the messages for 400 training images in MNIST goes up to around 150GB. To scale to bigger training sets, an online extension (see Section 4.2) needs to be used.
5 CONCLUSIONS AND FUTURE WORK
We have described the HCN, a hierarchical feature model with a rich prior and provided a novel method to solve the challenging learning problem it poses. The model effectively learns convolutional features and is interpretable and flexible. The learned weights are binary, which is advantageous for storage and computation purposes (Courbariaux et al., 2015; Han et al., 2015). Future work entails adding more structure to the prior, leveraging more refined MAP inference techniques, exploring other update schedules and further exploiting the generalization-without-retraining capabilities of this model.
A RELATED WORK
There is a plethora of previous works that address hierarchical feature learning, usually in the setting or real-valued images, as opposed to binary ones: Fidler et al. (2014); Zhu et al. (2008; 2010); Wu et al. (2010); Si & Zhu (2013); Poon & Domingos (2011). Many of those works explicitly use AND-OR graphs, in the same spirit as our work. The most outstanding difference, however, between previous works and HCN is that HCN allows multiple features to overlap, thus creating new compositions. For instance, if feature H is a centered horizontal line and feature V is a centered vertical line, HCN can create a new feature “cross” that combines both, and the fact that both are overlapping and sharing a common active pixel (and many common inactive pixels) is properly handled. In contrast, previously cited models cannot overlap features, so they partition the input space and dedicate separate subtrees to each of them, and do so recursively. We can see in Figure 5, top row, how we can generate 25 different cross variations using only two features. This would not be possible with any of the cited models, which would need to span each combination as a separate feature. This fundamental difference makes HCN combinatorially more powerful, but also less tractable. Both learning and inference become harder because feature reuse introduces the well-known “explaining away” phenomenon (Hinton et al., 2006).
As a side, note the difference between the meaning of “OR” as used in the present work and in previous works on AND-OR graphs: what they call “OR”, is what we term POOL (an exclusive bottom-up OR of elements), whereas HCN has a novel third type of gate, the “OR” connection (a non-exclusive, top-down OR of elements) to be able to handle explaining away. Standard AND-OR (or more clearly, AND-POOL) graphs lack the top-down ORing and therefore are not able to handle explaining away.
In the compositional hierarchies of Fidler et al. (2014), the lack of feature reuse allows for inference to be exact, since the graphical model is tree-like. Features are learned using a heuristic that relies on the exact inference, similar in spirit to EM. The AND-OR template learning methods of (Zhu et al., 2008; 2010) use respectively max-margin and incremental concave-convex procedures to optimize a discriminative score. Therefore they require supervision (unlike HCN) and a tractable inference procedure (to make the discriminative score easy to optimize), which again is achieved by not allowing overlapping features. The sum-product networks (SPNs) of (Poon & Domingos, 2011) express features as product nodes. In order to achieve feature overlapping, two product nodes spanning the same set of pixels (but with possibly different activation patterns) should be active simultaneously. This would violate the consistency requirement of SPNs, making HCN a more compact way to express feature overlap13 (with the price to be paid being lack of exact inference).
The AND-OR template (AOT) learning of (Wu et al., 2010) again cannot deal properly with the generation of superimposed features, having to create new features to handle every combination. In Section B we will compare AOT feature learning and HCN feature learning and check how these limitations make AOT unable to disentangle the generative features.
Grammars exclude the sharing of sub-parts among multiple objects or object parts in a parse of the scene (Jin & Geman, 2006), and they limit interpretations to single trees even if those are dynamic (Williams & Adams, 1999). Our graphical model formulation makes the sharing of lower-level features explicit by using local conditional probability distributions for multi-parent interactions, and allows for MAP configurations (i.e, the parse graphs) that are not trees.
The deep rendering model (DRM) of Patel et al. (2015) is, to some extent, a continuous counterpart of the present work. Although DRMs allow for feature overlap, the semantics are different: in HCN the amount of activation of a given pixel is the same whether there are one or many features (causes) activating it, whereas in DRM the activation is proportional to the number of causes. This means that the difference between DRM and HCN is analogous to the difference between principal component analysis and binary matrix factorization: while the first can be solved analytically, the second is hard and not analytically tractable. This results in DRM being more tractable, but less appropriate to handle problems with binary events with multiple causes, such as the ones posed in this paper.
Two popular approaches to handle learning in generative models, largely independent of the model itself, are variational autoencoders (VAEs) and generative adversarial networks (GANs). We are not
13An exponentially big SPN could indeed encode an HCN.
aware of any work that uses a VAE or GAN with a generative model like HCN and such an option is unlikely to be straightforward.
Most common VAEs rely on the reparameterization trick for variance reduction. However, this trick cannot be applied to HCN due to the discrete nature of its variables, and alternative methods would suffer from high variance. Another limitation of VAEs wrt HCN is that they perform a single bottom-up pass and lack of explaining away: HCN combines top-down and bottom-up information in multiple passes, isolating the parent cause of a given activation, instead of activating every possible cause.
GANs need to compute ∇WD(GW (ε)) where D(·) is the discriminative network and GW (ε) is a generative network parameterized by the features W . In this case, not only W is binary, but also the generated reconstructions at every layer, so the GAN formulation cannot be applied to HCN as-is. One could in principle relax the binary assumption of features and reconstructions and use the GAN paradigm to train a neural network with sigmoidal activations, but it is unclear that the lack of binary variables will still produce proper disentangling (the convolutional extension of NOCA also has this problem due to the use of non-binary features and produces results that are inferior to HCN).
B COMBINING WITH GRAYSCALE PREPROCESSING
The HCN is a binary model. However, to process real-valued data, it can be coupled with an initial grayscale-to-binary preprocessing step to do feature detection. We tested this by generating a grayscale version of our toy data and then computing the bottom-up messages to S0 by convolving the input image with a filter bank. This is roughly equivalent to replacing the noisy binary channel of HCN with a Gaussian channel. We used 16 preprocessing filters, which means that S0 has 16 channels. 200 training images (unsupervised) were used. Two filter sizes, 3× 3 and 7× 7 were tested. We also run the AOT feature learning method of Wu et al. (2010) on the same data for comparison. The results of training on 200 training images (unsupervised) is provided in Figure 10. When the larger filter is used, the diagonal bars are harder to identify so their disentangling is poorer.
C MAX-PRODUCT MESSAGE PASSING (MPMP)
The HCN model can be expressed both as a directed Bayesian network or as a factor graph using only POOL, AND, and OR factors, each involving a small number of local binary variables. Both
learning and ulterior classification can be cast as MAP inference in this factor graph. Other tasks, such as filling in unknown image data can also be performed by MAP inference.
MAP inference can be performed exactly on factor graphs without loops (trees) in linear time, but it is an NP-hard problem for arbitrary graphs (Shimony, 1994). The factor graph describing our model is highly structured, but also very loopy.
There is large body of works (Wang & Daphne, 2013; Meltzer et al., 2009; Globerson & Jaakkola, 2008; Kolmogorov, 2006; Werner, 2007), addressing the problem of MAP inference in loopy factor graphs. Perhaps the simplest of these methods is the max-product algorithm, a variant of dynamic programming proposed in (Pearl, 1988) to find the MAP configuration in trees.
The max-product algorithm defines a set of messages ma→i(yi) going from each factor a to each of its variables yi. The sum of the messages incoming to a variable µ(yi) = ∑ a:yi∈ya ma→i(yi) defines its approximate max-marginal14 µ(yi). The max-product algorithm then proceeds by updating the outgoing messages from each factor in turn so as to make the approximate max-marginals consistent with that factor. This algorithm is not guaranteed to converge if there are loops in the graph, and if it does, it is not guaranteed to find the MAP configuration. Damping the updates of the factors has been shown to improve convergence in loopy belief propagation (Heskes, 2002) and was justified as local divergence minimization in (Minka et al., 2005). Using a damping factor 0 < α ≤ 1 for max-product, the update rule is
mt+1a→i(yi) = (1− α)m t a→i(yi) + αmax
ya\i log φa(yi, ya\i) + ∑ yj∈ya\i mta→j(yj) + κ (3)
and the original update rule is recovered for α = 1. The value κ is arbitrary and does not affect the algorithm. We select it to make mt+1a→i(yi = 0) = 0, so that messages can be stored as a single scalar. When storing messages in this way, their sum provides the max-marginal difference, which is enough for our purposes.
Eq. (3) can be computed exactly for the three type of factors appearing in our graph, so message updating can be performed in closed form. Despite the graph of our model being very loopy, it turns out that a careful choice of message initialization, damping and parallel and sequential updates produces satisfactory results in our experiments. For further details about max-product inference and MAP inference via message passing in discrete graphical models we refer the reader to (Koller & Friedman, 2009).
D MAX-PRODUCT MESSAGE UPDATES FOR AND, OR AND POOL FACTORS
In the following we provide the message update equations for the different types of factors used in the main paper. The messages are in normalized form: each message is a single scalar and corresponds to the difference between the unnormalized message value evaluated at 1 and the unnormalized message value evaluated at 0. For each update we assume that the incoming messages mIN(·) for all the variables of the factor are available. The incoming messages are the sum of all messages going to that variable except for the one from the factor under consideration.
The outgoing messages are well-defined even for ±∞ incoming messages, by taking the corresponding limit in the expressions below.
D.1 AND FACTOR
Bottom-up messages
mOUT(t1) = max(0,mIN(t2) + mIN(b))−max(0,mIN(t2)) mOUT(t2) = max(0,mIN(t1) + mIN(b))−max(0,mIN(t1))
Top-down message
mOUT(b) = min(mIN(t1) + mIN(t2),mIN(t1),mIN(t2)) 14The max-marginal of a variable in a factor graph gives the maximum value attainable in that factor graph
for each value of that variable.
D.2 POOL FACTOR
Bottom-up message
mOUT(t) = max(mIN(b1), . . . ,mIN(bM ))− logM
Top-down messages
mOUT(bm) = min(mIN(t)− logM,−max j 6=m mIN(bj))
D.3 OR FACTOR
Bottom-up messages mOUT(tm) = min(mIN(b) + ∑ j 6=m max(0,mIN(tj)),max(0,mIN(ti))−mIN(ti)) with i = argmax i 6=m mIN(ti)
Top-down message mOUT(b) = mIN(ti) + ∑ j 6=i max(0,mIN(tj)) with i = argmax m mIN(tm)
E IMAGE CORRUPTION TYPE ILLUSTRATION
The different types of image corruption used in Section 4.4 are shown in the following Figure:

This paper presents an approach to learn object representations by composing a set of templates which are leaned from binary images.
In particular, a hierarchical model is learned by combining AND, OR and POOL operations. Learning is performed by using approximated inference with MAX-product BP follow by a heuristic to threshold activations to be binary.
Learning hierarchical representations that are interpretable is a very interesting topic, and this paper brings some good intuitions in light of modern convolutional neural nets.
I have however, some concerns about the paper:
1) the paper fails to cite and discuss relevant literature and claims to be the first one that is able to learn interpretable parts.
I would like to see a discussion of the proposed approach compared to a variety of papers e.g.,:
- Compositional hierarchies of Sanja Fidler
- AND-OR graphs used by Leo Zhu and Alan Yuille to model objects
- AND-OR templates of Song-Chun Zhu's group at UCLA
The claim that this paper is the first to discover such parts should be removed.
2) The experimental evaluation is limited to very toy datasets. The papers I mentioned have been applied to real images (e.g., by using contours to binarize the images).
I'll also like to see how good/bad the proposed approach is for classification in more well known benchmarks.
A comparison to other generative models such as VAE, GANS, etc will also be useful.
3) I'll also like to see a discussion of the relation/differences/advantages of the proposed approach wrt to sum product networks and grammars.
Other comments:
- the paper claims that after learning inference is feed-forward, but since message passing is used, it should be a recurrent network.
- the algorithm and tech discussion should be moved from the appendix to the main paper
- the introduction claims that compression is a prove for understanding. I disagree with this statement, and should be removed.
- I'll also like to see a discussion relating the proposed approach to the Deep Rendering model.
- It is not obvious how some of the constraints are satisfied during message passing. Also constraints are well known to be difficult to optimize with max product. How do you handle this?
- The learning and inference algorithms seems to be very heuristic (e.g., clipping to 1, heuristics on which messages are run). Could you analyze the choices you make?
- doing multiple steps of 5) 2) is not a single backward pass
I'll reconsider my score in light of the answers


Static analyzers are meta-programs that analyze programs to detect potential errors or collect information. For example, they are used as security tools to detect potential buffer overflows. Also, they are used by compilers to verify that a program is well-formed and collect information to generate better code. In this paper, we address the following question: can a static analyzer be learned from data? More specifically, can we use deep learning to learn a static analyzer without the need for complicated feature engineering? We show that long short-term memory networks are able to learn a basic static analyzer for a simple toy language. However, pre-existing approaches based on feature engineering, hidden Markov models, or basic recurrent neural networks fail on such a simple problem. Finally, we show how to make such a tool usable by employing a language model to help the programmer detect where the reported errors are located.
1 INTRODUCTION
Can programming language tools, such as static analyzers, be learned from data using deep learning? While research projects trying to use machine learning to design better programming language tools are burgeoning, they all rely on feature engineering (Brun & Ernst, 2004; Kolter & Maloof, 2006; Yamaguchi et al., 2012; Tripp et al., 2014; Raychev et al., 2015; Allamanis et al., 2015; Nguyen & Nguyen, 2015; Gvero & Kuncak, 2015; Long & Rinard, 2016). Unfortunately, feature engineering for programs is difficult and indeed the features often seem ad-hoc and superficial.
This raises the question of whether it could be possible to approach a complicated problem such as static analysis – the automated detection of program properties – from almost raw features. In this paper, our goal is to present a very simple experiment that clearly shows that not only feature engineering can completely fail for even the simplest static analysis task, but that deep learning with neural networks can indeed be successful.
The task in which we are interested is simple: we want to ensure that program variables are defined before they are used. We design a toy language to focus on the problem, and indeed our language is so simple that if it satisfies the aforementioned property, then it is semantically valid. Since programs are sequences of tokens, we experiment with different types of sequence learning methods (Xing et al., 2010). We try feature-based methods in which we extract features from the sequence and then use a classifier to decide whether or not the program is semantically valid. We show that they all fail, including methods that compute a sequence embedding. Then, we try different modelbased methods (Lipton, 2015): hidden Markov models (HMM), recurrent neural networks (RNN), and long short-term memory networks (LSTM). Our results show that HMM and RNN do poorly (albeit better than random), while an LSTM is almost perfectly accurate. This finding is somewhat surprising as static analysis is essentially a document classification problem and LSTMs are known to perform poorly on related tasks, such as sentiment analysis (Dai & Le, 2015).
The obvious question about such an experiment is: why would we want to learn a static analyzer for a problem that we know of a perfectly fine engineered solution? The answer is that we want to initiate investigation into the use of deep-learning for program analysis, and our broader hopes are two-fold. First, static analyzers are very complicated and often limited by the amount of false positive and false negatives they generate. In cases where false negatives are unacceptable, a learned static analyzer may not be the right approach. But when the goal is rather to find a good balance
between false positives and false negatives, learned static analyzers might be more flexible. Second, as we will briefly show in the paper, learned static analyzers have a resilience to small errors that might lead to more robust tools. Indeed, even though our goal is to detect errors in syntactically valid programs, our tool work despite the presence of small syntactic errors, such as the omission of the semicolon. This resilience to errors is in our opinion a very promising aspect of learned methods for the analysis of programs.
Another key problem with static analysis programs is that to be useful, they need to help the programmer understand what is the cause of the error. In that case, models based on recurrent neural networks really shine because they can be trained to provide such information. Indeed, in our experiment, we show how to use a language model to locate the position of erroneous variables in examples classified by the static analyzer as being wrong. This is very important for practical static analysis since a tool that merely reports the existence of an error in a large code file is not useful.
The paper is organized as follows. In section 2 we introduce the programming language of study and the corresponding static analysis task. In section 3, we review how we created the dataset used to learn the static analyzer and the methods that we have tried. In section 4, we explain how we learn to report error messages to help the programmer understand how to fix an error.
2 A STATIC ANALYSIS TASK
Our goal is to study the following static analysis problem: given a program, is every variable defined before it is being used? Because this problem is undecidable for a Turing complete language, programming languages such as Java impose constraints on what is a correct variable initialization. For example, a variable may not in general be defined within only one branch of an if-then-else statement and used afterward since it can be impossible to guarantee which branch will be executed for every run.
In order to better understand whether this is feasible and which methods work, we design a toy language. As an example, in this language, we can write a program that computes the 42th Fibonnacci number as follows.
1 v0 = 1 ; v1 = 1 ; 2 v2 = 0 ; 3 w h i l e ( v2 < 42) { 4 v3 = v1 ; 5 v1 = v0 + v1 ; 6 v0 = v3 ; 7 v2 = v2 + 1 ; 8 } 9 r e t u r n v1 ;
If we were to invert lines 4 and 6, then not only would the program be incorrect, but it would be semantically invalid since in the first execution of the loop, variable v3 has not yet been defined.
In order to precisely explain what the task is, we now briefly present the syntax and semantics of our experimental programming language.
2.1 THE LANGUAGE
We present the syntax of the language in Backus-Naur form in figure 1. The symbols delimited by 〈〉 are non-terminals while the symbols delimited by ‘’ are terminals. Symbol 〈program〉 is the starting non-terminal. A program is composed of an optional statement followed by an expression. The statement can be a list of statements, control-flow statements like conditionals or iterations, or the binding of an expression to a variable. The expressions are simple arithmetic expressions. For simplicity, the test expressions used in conditional statements are distinct from the other expressions, which is a simple syntactic way to enforce basic type safety. The integers are simple integer values of the form [0− 9]+ while the identifiers are of the form v[0− 9]+. The semantics of our experimental programming language is presented as a big-step operational semantics in figure 2. For simplicity, we only present a subset of the rules. It is composed of
four predicates. The predicate Γ ` e ⇒ v denotes the value v resulting from evaluating e in the environment Γ. The environment is simply a list of bindings from variables to their values. We present four rules that define this predicate, ADD, INT, LOOKUP, TEST1, and TEST2. The most important is the LOOKUP rule which states that the value of a variable is the value associated to it in the environment. Note that this is only well-defined if the variable actually is in the environment, otherwise the semantics is undefined. The goal of our static analyzer is to ensure this can never happen.
The predicate Γ, s ⇒ Γ denotes the execution of a statement that transforms the environment by adding variable bindings to it. For example, the INTRO rule shows that a variable assignment adds a variable binding to the environment, The CLOSURE rule states that a possible transition is the reflexive and transitive execution of a single statement Γ, s ∗→ Γ. The rules WHILE1 and WHILE2 formalize the execution of a while loop. Finally, the predicate JpK = v denotes the evaluation of a complete program into a resulting value.
2.2 THE TASK
Now that we have presented the language, we can state more precisely the goal of the static analysis. A program such as “v1 = 4; return v1 + v2;”, while syntactically valid, is not well-defined since variable v2 has not been defined. A static analyzer is a function that takes such a program as an input and returns a Boolean value.
analyze : token sequence 7−→ Boolean
Function analyze should return true only if every variable is defined before it is used. We chose the input to be the sequence of tokens of the program rather than the raw characters for simplicity. It is easy to define such a function directly, but our goal is to see whether we can learn it from examples. Note that unlike previous work combining static analysis and machine learning, we are not trying to improve a static analyzer using machine learning, but rather learning the static analyzer completely from data.
3 LEARNING A STATIC ANALYZER
To learn the static analyzer, we compile a balanced set of examples in which programs are labeled with a single Boolean value indicating whether the program should be accepted or not.
The dataset contains 200,000 examples, half of which are valid programs and half of which are invalid programs. The invalid programs are of two forms. Half of them contain variables that have not been defined at all, the other half contains programs where the order of statements has been swapped and a variable use appears before its definition. Note that this swapping of statements results in documents that have the exact same bag-of-words, but different labels. Of the 200,000
examples, we use 150,000 as the training set and 50,000 as the test set while making sure to respect a perfect balance between valid and invalid programs.
To create this dataset, we have built our own compiler and example generator for our language. The example generator only produces syntactically valid programs. The programs are generated using a variety of random decisions: for example, when trying to generate a statement, we must decide with what probability we want to choose a variable assignment versus a while loop or another type of statement. We vary the probability to try to avoid producing a dataset with a spurious signal, but this is a very delicate issue. We also try our classifiers on hand-written programs.
We apply several different machine learning methods, including LSTM to the problem (described below) and present results in Table 1.
N-grams and classification We attempt to learn the static analyzer using a classic approach of feature engineering followed by classification. We try both unigram and bigrams features and classify the examples using either a linear logistic regression or a non-linear multilayer perceptron. We expect this approach to fail since n-gram features fail to capture statement ordering, and this serves as a test to make sure our dataset does not contain any spurious signal. Indeed, these methods do not perform better than random.
Sequence embedding and classification We also attempt to use an LSTM for our feature engineering. In this case, we first train an LSTM as language model. Then, for classification, we first execute our language model on the example program and use the last hidden state as an embedding. This embedding is used as an input to both a logistic regression and a multilayer perceptron. This approach fails as well and does not perform better than random. It is important to note that we might also consider using an RNN encoder-decoder to produce the embedding but we leave this for future work.
Sequence classication We tried three model-based approaches to sequence classification. First, we tried to use an HMM trained using the Baum-Welch algorithm. Second, we tried to train a vanilla RNN with a cross-entropy loss using stochastic gradient descent (SGD). Third, we tried to train an LSTM with cross-entropy loss and SGD. More precisely, we use the variant of SGD known as RMSProp. In both cases we used the Keras framework.
These sequence classification approaches perform better than the other approaches. However, the HMM and the RNN still perform poorly. Interestingly, the LSTM can achieve an accuracy of 98.3%. The training of the LSTM is very robust, we did not need to do any complicated parameter search to obtain these results. The false negative rate (i.e. the program is correct but predicted as faulty) is 1.0% and the false positive rate (i.e. the program is faulty but classified as correct) is 2.5%.
Using differentiable data structures The key problem in detecting uninitialized variables is to remember which variables have been defined up to some program point. A solution is to employ a set data structure: if we encounter a variable definition, we add the variable to the set; if we encounter a variable use, we test whether that variable is in the set of defined variables. With this in mind, we design a differentiable set data structure to augment an RNN to see if the resulting network can learn (from the training data alone) a policy of how to use the set.
The set is represented by a vector f and intended to be used as a bitmap by the network. The intent is that each possible value correspond to a bit in the vector and is set to 1 if the element is in the set and 0 otherwise. An action a on the set can be either adding an element to the set, or testing if some value is in the set. Values v are indices into the set representation.
Controller update: ht = RNN([xt, ft−1], ht) (1) Action: at = σ(Waxt + ba) (2) Input representation: vt = softmax(Wi2 tanh(Wi1xt + bi1) + bi2) (3) Set update: ft = max{ft−1, at ∗ vt} (4) Set test pt = 〈ft, vt〉 (5) Decision: yt = σ(Wyht + Uypt + by) (6)
RNN can be a simple Ellman network or LSTM. The architecture is shown in Figure 4.
Unfortunately, training differentiable data structures is sometimes difficult, requiring extensive hyper-parameter tuning and cross validation to find a good weight initialization. Further, LSTMs are often able to learn the training data single-handedly causing the network to learn a policy that ignores the data structure. To circumvent these problem, we annotate the training data with additional intermediate signals: specifically, we annotate each token with a binary label that is true if and only if the token is a variable use that has not been initialized. Note that the additional labels results in a per-token classification problem, but we convert the network back into a program classifier by employing min-pooling over the per-token soft max outputs. We experiment with both per-program (sequence classification) and per-token (sequence transduction) classifiers as described next.
Sequence classification: As in previous experiments, we train using the program as the input sequence and a single Boolean label to indicate whether the program is valid or not. For the network with differentiable set to produce one output we apply min-pooling across all the decisions. This method improves over an LSTM and achieves an accuracy of 99.3%. Note that, we did not need to do any complicated parameter search to obtain these results. The false negative rate (i.e. the program is faulty but classified as correct) is 0.8% and the false positive rate (i.e. the program is correct but predicted as faulty) is 0.6%.
To understand the behavior of the network, we remove the last minpooling layer, and look at the decision made by the network for each input token. This reveals an interesting pattern: the network correctly identifies the first error location and subsequently emit incorrect outputs. Thus, it is comparable to conventional (non-ML) static analysis algorithms that give up after the first error. For example, in the example in figure 3a the first variable use is correctly identified as invalid but the rest of the output is incorrect. information.
Sequence transduction: Finally, we run an experiment at token level granularity. In this case, the network produce not just a single output but as many outputs as inputs (many-to-many architecture), we refer to this approach as sequence transduction to distinguish from the recurrent networks that produce a single label (many-to-one architecture). The training data also contains the label for each token in the program. This can achieve an accuracy of 99.7%. The training of the transduction task is very robust, we did not need to do any complicated parameter search to obtain these results. The false negative rate is 0.4% and the false positive rate is 0.2%.
Given the token level data, it seems that the network has inducted a use of the set data structure that correspond to what an traditional algorithm would do. Aside from using the set to keep track of defined variables, it correctly handles the tricky case of a statement such as v1 = v1 + 3; by making sure that the variable v1 is introduced in the set only after the statement is finished. For example, in the example presented in figure 3b, the declaration of the variable v14 utilizes the value of the still undeclared variable v14 and the network correctly identifies it.
Unfortunately, and interestingly, the accuracy is not perfect. Even though it looks like the correct use of the set has been learned, there are a few rare cases where the network makes simple mistakes. For example, some of the errors happen on some the simplest and shortest programs where the network fails to insert the declared variable into the set.
splitjoin
Conclusion In conclusion, an out-of-the-box LSTM achieves a promising accuracy on this task, and an LSTM equipped with a differentiable set data-structure has an almost perfect accuracy. Interestingly, none of the other approaches including HMM or RNN, could deliver satisfactory results.
4 REPORTING USEFUL ERROR MESSAGES
While the above experiment demonstrates that it is possible to learn an accurate static analyzer; practically, such an analyzer is somewhat useless unless we can also help the programmer locate the potential errors. That is, imagine if a tool reported that there is a potential buffer overflow in your code base without any indication of where the problem is: it would not be of much use.
Therefore we train a second LSTM as a language model over true instances of our programming language. That is, we train the LSTM to predict the next character in the sequence, and for every character in the sequence, the model provides the probability of observing this specific character. The idea is that we want to look at all the variable-use in the program and if the probability of this variable use is below a certain threshold, then we report the use as a potential source of error.
We present several such examples in Figure 5. We color a variable-use in blue if its probability is above the threshold and in purple if it is below the threshold and therefore potentially the source of the error.
As we can see from the examples, the method works well. The first four examples show simple cases with only two variables. Note that from the perspective of a bag-of-words classifier, these two programs are identical. Yet the LSTM language model, which takes into account the “word” order is able to model them differently. Examples 5-11 are more complicated in that the variables are used or defined several times. In Example 9, the language model accurately reports the first use of v2 as incorrect and the second use of v2 as correct. This is a somewhat interesting example as the incorrect use of v2 is in the definition of v2 itself. In example 10, we can see that the language model can handle multiple incorrect variable uses; this success crucially depends on the ability of the language model to recover from the error and still accurately model the remainder of the program. Finally, examples 12 and 13 demonstrate robustness. Despite the fact that these two examples are syntactically incorrect, the language model correctly reports the semantic errors. The resilience of the learned tools to small errors is part of what makes them so promising for program analysis.
5 RELATED WORK
There is a growing body of work in employing machine learning to improve programming language tools. In such works, machine learning is used to complement the traditional static analysis methods; further, they rely on extensive feature engineering. In Brun & Ernst (2004), dynamic analysis is used to extract features that are used to detect latent code errors. In Kolter & Maloof (2006), n-
gram features are used to detect viruses in binary code. In Yamaguchi et al. (2012), parts of the abstract syntax tree of a function is embedded into a vector space to help detect functions similar to a known faulty one. In Tripp et al. (2014), various lexical and quantitative features about a program is used to improve an information analysis and reduce the number of false alarms reported by the tool. In Raychev et al. (2015), dependency networks are used with a conditional random field to de-obfuscate and type Javascript code. In Allamanis et al. (2015), the structure of the code is used to suggest method names. In Nguyen & Nguyen (2015), n-grams are used to improve code completion tools. In Gvero & Kuncak (2015), program syntax is used to learn to tool that can generate Java expressions from free-form queries. In Long & Rinard (2016), a feature extraction algorithm is designed to improve automatic patch generation.
6 CONCLUSION
We have shown that it is possible to learn a static analyzer from data. Even though the problem we address is particularly simple and on a toy language, it is interesting to note that in our experiments, only LSTM networks provided a reasonable enough solution. We have also shown that it is possible to make the static analyzer useful by using a language model to help the programmer understand where to look in the program to find the error.
Of course, this experiment is very far from any practical tool. First, dealing with more complicated programs involving memory, functions, and modularity should be vastly more complex. Also, our solution is very brittle. For example, in our language, the space of variable names is very restricted, it might be much more difficult to deal with normal variable names where a specific variable name could not appear at all in the training dataset.
Finally, a fundamental issue are false positives, that is, programs that are wrongly classified as being without error. This is a serious problem that may make such a tool risky to use. However, note that there are useful programming language tools that indeed generate false positive. For instance, a tool that report buffer overflows might not catch every error, but it is still useful if it catches some. Another possibility is to consider approaches were a result is verified by an external tools. For example, in the field of certified compilation, Tristan & Leroy (2008) have shown that it can be acceptable to use an untrusted, potentially bogus, program transformation as long as each use can be formally checked. Also, as exemplified by Gulwani & Necula (2003; 2004; 2005) some static analysis algorithms do trade a small amount of unsoundness for much faster computation, which can be necessary when applying programming tools to very large code base.

This paper takes a first step towards learning to statically analyze source code. It develops a simple toy programming language that includes loops and branching. The aim is to determine whether all variables in the program are defined before they are used. The paper tries a variety of off-the-shelf sequence classification models and develops a new model that makes use of a ``differentiable set'' to keep track of which variables have been defined so far. Result show that an LSTM model can achieve 98% accuracy, and the differentiable set model can achieve 99.3% accuracy with sequence-level supervision and 99.7% accuracy with strong token-level supervision. An additional result is used whereby an LSTM language model is trained over correct code, and then low probability (where a threshold to determine low is tuned by hand) tokens are highlighted as sources of possible error.
One further question is if the authors could clarify what reasoning patterns are needed to solve these problems. Does the model need to, e.g., statically determine whether an `if` condition can ever evaluate to true in order to solve these tasks? Or is it just as simple as checking whether a variable appears on a LHS before it appears on a RHS later in the textual representation of the program?
Strengths:
- Learning a static analyzer is an interesting concept, and I think there is good potential for this line of work
- The ability to determine whether variables are defined before they are used is certainly a prerequisite for more complicated static analysis.
- The experimental setup seems reasonable
- The differentiable set seems like a useful (albeit simple) modelling tool
Weaknesses:
- The setup is very toy, and it's not clear to me that this makes much progress towards the challenges that would arise if one were trying to learn a static analyzer
- The models are mostly very simple. The one novelty on the modelling front (the differentiable set) provides a small win on this task, but it's not clear if it is a useful general construct or not.
Overall:
I think it's an interesting start, and I'm eager to see how this line of work progresses. In my opinion, it's a bit too early to accept this work to ICLR, but I'd be excited about seeing what happens as the authors try to push the system to learn to analyze more properties of code, and as they push towards scenarios where the learned static analyzer would be useful, perhaps leveraging strengths of machine learning that are not available to standard programming languages analyses.