Introduction to Neural Networks

Problem Set 6

Initialization

Off[General::spell1];
SetOptions[ArrayPlot,Mesh->False,AspectRatio->Automatic,PlotRange->All,ColorFunction->"GrayTones",DataReversed->True,ImageSize->Small];
SetOptions[ListPlot,ImageSize->Small];

The purpose of this exercise is to provide exposure to methods of handling bigger datasets for unsupervised learning (Exercises 1, 2, and 3), for multi-channel convolutions (Exercise 4), and supervised learning using back-prop (Exercise 5).

Most of the details of the algorithms are hidden. But hopefully the class lectures will have provided understanding of what is happening “under the hood”. For example, you won’t see back propagation made explicit in any of the code for Exercise 5.

The only requirement is that you read through and execute each cell. And then turn in your notebook in as usual.

If the file is too big, you may need to send in a URL for the TA to download your notebook.


Use the Mathematica documentation for anything you don’t understand, e.g. the function for Singular Value Decomposition, and the various Neural Network functions to understand what the code is doing.

Exercise 1 - Dimensionality reduction: Principal Components of natural images

An important theory of neural receptive field organization says that the receptive field structure of sensory neurons, such as the simple cells of V1 are organized to efficiently representing incoming image information (Barlow). One way to efficiently code a large dimensional data set is to project the data onto a few axes that capture the most variance. PCA and SVD are two ways to do this. In theory both methods produce the same answers. Practically, SVD, is often the preferred method.

Convert (GrayLonesome256x256.jpg) to image data:

granite = ImageData[];

Use the following to break this large 256x256 image into a series of 16x16 pixel subimages to use as samples

patchsize = 32;
subfacelist1 = ImageData@ImageAdjust[#]&/@Flatten[ImagePartition[, patchsize]];
Dimensions[subfacelist1]

The idea is that each subimage will be used as a statistical sample. We compute the outer product of each, and then average all  to get an estimate of the autocovariance matrix.

Calculate the autocovariance matrix for the resulting collection of images

patchmean = Mean[Flatten/@subfacelist1];

subfacelist2 = Table[subfacelist1[[i]] - Mean[subfacelist1[[i]]], {i,1,Dimensions[subfacelist1][[1]]}];

subfacelist2 = Table[subfacelist1[[i]] - Partition[patchmean,32], {i,1,Dimensions[subfacelist1][[1]]}];

autocov0=Sum[Outer[Times,Flatten[subfacelist2[[i]]],Flatten[subfacelist2[[i]]]],{i,1,Dimensions[subfacelist2][[1]]}]/Dimensions[subfacelist2][[1]];

This next line does all of the above, so should give almost the same answer, the same if one were to use Bessel’s correction (divide by 64-1, instead of 64) in the Outer product estimate above. We will use autocov in the rest of this section.

autocov = Covariance[Flatten/@subfacelist1];
Dimensions[Flatten/@subfacelist1]

Note that we 64 patches, each 32x32 = 1024 in size after flattening.

Using Mathematica's built-in functions, calculate the eigenvectors and eigenvalues of the autocovariance matrix

eigenpictures = Eigenvectors[autocov];
Dimensions[eigenpictures ]

Use  the Partition[] function to display the first 16 eigenvectors as "eigenpictures".

Table[ImageAdjust@Image[Partition[eigenpictures[[i]],patchsize]],{i,1,16}]

Note how the eigenpictures capture increasingly higher spatial frequencies.

Use ListPlot to show the eigenvalues. These numbers represent the variances that each eigenvector “accounts for”.

eigenvalues = Eigenvalues[autocov];
ListPlot[eigenvalues]

But the eigenvalues should not be negative. What happened? Beyond about 60, most of the eigenvalues are too small to be reliable computed. One can use Chop[ ] to set these to zero:

ListPlot[Chop[eigenvalues][[1;;90]]]

As an alternative, calculate the principal components using Singular Value Decomposition (SVD)

This is usually the preferred method.

Instead of calculating the covariance matrix and submitting it to Eigenvector[], we use the list of 64 flattened images as input to the function, and submit them directly to SingularValueDecomposition[ ].

Dimensions[Flatten/@subfacelist2]

{u,w,v}= SingularValueDecomposition[Flatten/@subfacelist2];
Dimensions[#]&/@ {u,w,v}

The columns of v are the principal components, i.e. the eigenvectors of the covariance matrix--without actually having to precompute it.

svdprincipals = Transpose[v];

Table[ImageAdjust@Image[Partition[svdprincipals[[i]],patchsize]],{i,1,16}]

Note how some of the signs are flipped in comparison to the covariance eigenvectors.

The non-zero diagonal elements of w are the square roots of the eigenvalues of the covariance matrix. SVD is  numerically more robust. Normalize the SVD values by the number of data patches, and then plot the results from PCA and SVD on the same graph:

ListPlot[{Chop[eigenvalues[[1;;64]]],Diagonal[w]^2/(64-1)},PlotMarkers->{"-","|"}]

Exercise 2 - Use SVD to find principal components of human faces

In the first exercise, we didn’t worry about where in the large sample scene our image patches came from.  If instead of the mountain landscape, we’d used a large face, the basic story would have remained the same. But what if we used a set of pre-registered faces? 

Instead of finding the eigenvectors of the covariance matrix, we will use SVD.

Original images are from here: http://vis-www.cs.umass.edu/lfw/
via: http://vis-www.cs.umass.edu/lfw/#download

This link provides faces that have been aligned: http://vis-www.cs.umass.edu/lfw/lfw-deepfunneled.tgz

Execute the next cell to initialize the face dataset

faces = {,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,};

As a spot check, take a random sample of images, and check the dimensions:

RandomSample[faces,12]
Dimensions[faces]
ImageDimensions[faces[[1]]]

We have 1049 faces, each 26x26 pixels.

SVD

Extract the image data from the Image[] data structures, calculate the mean and subtract it off:

facesdt = Transpose[Flatten[ImageData[#]& /@ faces,{3,2}]];
averageface = Mean[facesdt];
Image[Partition[Mean@facesdt,26]]
facesd = Map[(#-averageface)&,facesdt];
Dimensions[facesd]

Clear[u,v,w]
{u,w,v}=SingularValueDecomposition[facesd];

ImageRotate[Image[Partition[Transpose[v][[#]],26]]//ImageAdjust,-Pi/2]& /@ Range[1,32]

ListPlot[Diagonal[w]]

What use is SVD? Reconstruct a novel from the first 20 and then 200 eigenfaces of the training set.

This next face, testface, was not in the original training set.

testface = Flatten[ImageData[ImageRotate[Downsample[,4],Pi/2]]];

ImageAdjust@Image[Partition[averageface +Total[Transpose[v][[#]] testface.Transpose[v][[#]]& /@ Range[1,600]],26]];
GraphicsRow[{ImageRotate[%,-Pi/2],Downsample[,4]}]

The reconstruction isn’t too bad, given that we used only 200 out of the 1024 possible dimensions required to specify the face without compression. This kind of compression is called “lossy” compression.

Exercise 3 - Use an autoencoder neural network to do dimensionality reduction

This exercise shows a different approach to dimensionality reduction. It will seek out a subspace to efficiently represent a higher-dimensional image space. Like the above examples, it will exploit statistical structure in the training dataset.

Autoencoder dimensionality reduction

Calculate the mean image. This will be used as an option in NetEncoder[ ] which will subtract off the mean “under the hood”.

trainingImages=faces;
meanImage=Image[Mean@Map[ImageData,trainingImages]]

net=NetGraph[
{FlattenLayer[],50,Ramp,26^2,Tanh,ReshapeLayer[{1,26,26}],MeanSquaredLossLayer[]},
{1->2->3->4->5->6->NetPort["Output"],6->NetPort[7,"Input"],NetPort["Input"]->NetPort[7,"Target"]},
"Input"->NetEncoder[{"Image",{26,26},"Grayscale","MeanImage"->meanImage}],
"Output"->NetDecoder[{"Image","Grayscale"}]
]

Note how we start with 26x26 = 676 dimensions, which get squeezed down to just 50 by layers 3/4. The algorithm will use the MeanSquaredLossLayer[ ] to measure the discrepancy between the input and output images after having been squeezed through the 50 dimensional bottleneck. 

This next line does the training, i.e. fits the weights to minimize the loss.

trained=NetTrain[net,<|"Input"->trainingImages|>,"Loss"];

Now that it is trained, we extract the feedforward part of the network for testing.

reconstructor=Take[trained,{NetPort["Input"],NetPort["Output"]}]

Let’s try the testimage used for SVD above. First, we’ll need to put back the average face to do full reconstruction:

testimagei =Downsample[,4];

Run the test image through the autoencoder network:

ImageAdd[reconstructor[#],meanImage]&/@testimagei

Compare with the original:

GraphicsRow[{testimagei ,ImageAdd[reconstructor[#],meanImage]&/@testimagei}]

We can also extract the first part of the network to examine the internal low-dimensional representation as output.

encoder=Take[trained,{NetPort["Input"],3}]

features = encoder[trainingImages];
Dimensions[features[[1]]]

Think of these 50 numbers as a “code” for each 26x26 pixel image. Can we interpret the code? One thing to try is to see whether similar codes produce similar faces. I can’t see any perceptually consistent groupings. Do you?

components=ClusteringComponents[features,4,1];Map[Part[trainingImages,RandomSample[#,10]]&,PositionIndex[components]]

Exercise 4 -Multi-layer, multi-channel convolutional neural network: Handwired weights.

This exercise uses Mathematica’s built-in neural network functions to do multi-layer neural network computations.  The program takes in an image and produces two “neural images” as outputs, one convolved with a vertical filter, and a second with a horizontal filter. This would be a reasonable model of simple cell filtering in V1.

Two channels: horizontal and vertical filters

“Hand-wire” the weights:

oriented1 = {{-0.5,1,-0.5},{-0.5,1,-0.5},{-0.5,1,-0.5}};
oriented2 =Transpose[oriented1];

Check them visually:

{Image[oriented1],Image[oriented2]}

Specify a test image

Image inputs will have the horizontal and vertical sizes corresponding to the zebra test image:

zebraDS2 =Downsample[,2];
ImageDimensions[zebraDS2]

Define the two channel neural network

Set up the encoder to turn Image[] formatted inputs into a 1 x 214 x 320 sized tensor. And then use NetChain[] to specify a 2 channel feedforward convolutional network. Each channel has a 3x3 kernel (the oriented filters), with the above weights. The “point-wise” non-linearity is defined by ElementwiseLayer[Ramp]. 
The “Ramp” argument sets all negative values to zero. Another alternative would be to use a sigmoid, such as the  logistic function. 

Then initialize the network.

enc=NetEncoder[{"Image",ImageDimensions[zebraDS2],ColorSpace->"Grayscale"}];lenet=NetChain[{
ConvolutionLayer[2,{3,3},"Weights"->{{oriented1},{oriented2}}],
ElementwiseLayer[Ramp],PoolingLayer[{4,4},"Stride"->1],ElementwiseLayer[Ramp]},
"Output"->"Image",
"Input"->enc];
lenet=NetInitialize@lenet

Without ElementwiseLayer[Ramp], we’d just have a linear convolutional network.

Inspect the network to confirm that the weights are what was specified:

weights = NetExtract[lenet,{1,"Weights"}]

Dimensions[NetExtract[lenet,{1,"Weights"}]]

We see that weights is a 4-tensor, so to extract the 3x3 matrices and visualize them:

Image@weights[[;;,1]][[1]]
Image@weights[[;;,1]][[2]]

Apply the network to the zebra image

GraphicsRow[{lenet@zebraDS2//ImageAdjust,zebraDS2}]

What do the colors mean? The output is a decoding of the tensor into Image format. It took the two channels, horizontal and vertical, and mapped them to colors. Vertical appears to show up as green, and horizontal as warmer colors...sort of.

The distinct filter contributions can be seen better if we  separate the two output channels. Extract the first three layers, leaving out the final decoder layer.

featureNet=Take[lenet,3]

Note that the output has 2 channels, each 209x315 size. Think of these outputs as “neural images” corresponding to different orientation channels.

featureNet=Take[lenet,3]
GraphicsRow[{Image[(featureNet@zebraDS2)[[1,;;]]],Image[(featureNet@zebraDS2)[[2,;;]]]}]

The “blockiness” of the output in part reflects the pooling operation above. Try changing the “stride” to 2 in lenet, and then initialize again.

Just for fun

This has only been tried on a Macbook with camera. Uncomment and try executing then next cell if you dare.

(*Dynamic[Image[ImageAdjust@lenet @ CurrentImage[],Magnification->4]]*)

Exercise 5 -Convolutional network: Supervised learning

Set up deep convolutional neural network to learn to classify image patches belonging to one of three classes:

{background, elbows, heads}

Each patch is 51x51 pixels. They are in color, so the input tensor is 3x51x51.

Execute cell to define <trainingset>. Open the enclosed cell if you want to see all of them

trainingset = {->1,->1,->2,->2,->1,->1,->1,->2,->2,->1,->2,->2,->2,->0,->2,->1,->0,->2,->2,->0,->2,->2,->0,->2,->1,->2,->0,->2,->2,->2,->0,->1,->0,->2,->2,->0,->0,->1,->0,->1,->2,->0,->1,->2,->1,->2,->0,->0,->2,->2,->0,->0,->1,->0,->1,->2,->2,->2,->1,->0,->1,->0,->0,->0,->1,->1,->1,->2,->2,->0,->0,->2,->1,->1,->0,->0,->1,->1,->0,->0,->0,->0,->0,->0,->0,->2,->2,->1,->0,->1,->0,->1,->2,->0,->2,->0,->2,->2,->2,->2,->2,->2,->1,->2,->0,->2,->1,->0,->0,->0,->0,->1,->1,->2,->2,->1,->0,->0,->0,->0,->0,->1,->0,->2,->0,->2,->2,->2,->2,->2,->2,->1,->0,->1,->1,->1,->2,->1,->0,->2,->1,->1,->0,->0,->2,->2,->2,->2,->2,->0,->0,->2,->0,->0,->0,->1,->1,->1,->2,->1,->2,->1,->1,->1,->2,->2,->0,->0,->0,->1,->1,->0,->0,->0,->1,->2,->0,->1,->2,->1,->1,->1,->1,->0,->1,->2,->2,->0,->2,->0,->1,->0,->1,->0,->0,->2,->1,->2,->1,->0,->1,->2,->2,->0,->1,->2,->2,->2,->2,->1,->0,->1,->2,->0,->2,->2,->1,->2,->1,->2,->0,->1,->2,->1,->2,->1,->2,->1,->1,->1,->2,->1,->2,->0,->1,->2,->2,->2,->0,->0,->1,->0,->2,->1,->1,->1,->2,->2,->0,->0,->0,->1,->0,->1,->0,->0,->2,->2,->0,->2,->2,->1,->1,->2,->0,->1,->1,->2,->2,->2,->2,->2,->0,->1,->1,->1,->0,->0,->2,->0,->2,->0,->1,->0,->0,->2,->1,->1,->0,->2,->2,->0,->0,->1,->0,->2,->0,->1,->0,->0,->2,->1,->2,->2,->0,->0,->2,->0,->0,->1,->0,->2,->2,->0,->1,->0,->0,->0,->0,->1,->1,->0,->2,->0,->1,->2,->1,->2,->2,->1,->0,->0,->1,->2,->1,->0,->2,->2,->1,->2,->1,->2,->2,->1,->0,->1,->1,->0,->1,->2,->1,->2,->1,->2,->0,->2,->1,->2,->0,->0,->0,->0,->0,->1,->2,->2,->0,->0,->2,->2,->0,->1,->0,->1,->0,->1,->0,->0,->0,->1,->2,->2,->2,->1,->1,->0,->2,->0,->2,->1,->2,->1,->1,->0,->1,->0,->0,->2,->0,->2,->2,->1,->0,->1,->0,->0,->0,->1,->0,->0,->2,->2,->0,->1,->1,->2,->1,->2,->1,->1,->2,->2,->2,->1,->0,->2,->1,->2,->2,->2,->0,->2,->2,->1,->0,->2,->2,->2,->0,->2,->0,->2,->0,->2,->1,->2,->2,->0,->0,->2,->2,->1,->1,->1,->2,->1,->0,->1,->0,->2,->0,->1,->0,->0,->2,->1,->0,->2,->2,->2,->2,->0,->0,->1,->2,->1,->0,->2,->0,->1,->0,->0,->2,->2,->1,->0,->2,->1,->1,->0,->0,->1,->1,->2,->0,->0,->1,->1,->0,->2,->1,->1,->0,->1,->2,->2,->1,->0,->2,->2,->1,->1,->0,->2,->2,->2,->2,->2,->0,->1,->2,->1,->1,->2,->1,->2,->1,->0,->1,->0,->1,->1,->1,->1,->1,->1,->0,->0,->0,->1,->0,->0,->0,->2,->2,->0,->2,->1,->2,->0,->2,->0,->0,->0,->0,->2,->2,->2,->0,->2,->2,->1,->0,->0,->2,->0,->2,->2,->2,->1,->0,->2,->1,->2,->2,->0,->2,->0,->1,->0,->0,->0,->0,->2,->1,->1,->0,->1,->1,->0,->0,->2,->2,->2,->1,->0,->0,->0,->1,->0,->2,->2,->0,->0,->2,->1,->2,->2,->1,->0,->0,->2,->2,->0,->2,->2,->0,->0,->1,->2,->2,->2,->1,->1,->0,->0,->2,->0,->2,->0,->2,->2,->2,->1,->0,->2,->2,->0,->2,->2,->2,->1,->0,->2,->1,->2,->0,->2,->1,->2,->1,->2,->2,->1,->0,->0,->0,->0,->0,->0,->2,->2,->0,->0,->0,->1,->1,->0,->2,->2,->1,->2,->0,->0,->0,->0,->2,->2,->1,->1,->1,->2,->2,->2,->2,->0,->0,->0,->1,->0,->1,->0,->0,->0,->2,->2,->2,->0,->1,->0,->1,->1,->2,->0,->2,->1,->0,->0,->2,->2,->1,->0,->0,->1,->1,->1,->2,->0,->2,->2,->2,->1,->1,->2,->0,->0,->1,->0,->2,->0,->1,->0,->2,->0,->2,->1,->0,->1,->2,->0,->2,->2,->0,->2,->1,->1,->2,->0,->1,->2,->0,->2,->0,->0,->1,->0,->2,->0,->1,->2,->0,->0,->2,->1,->0,->0,->2,->1,->0,->2,->1,->1,->0,->1,->0,->1,->1,->2,->0,->1,->2,->1,->1,->2,->2,->2,->1,->1,->1,->0,->2,->1,->2,->2,->0,->0,->1,->2,->1,->1,->2,->0,->2,->0,->1,->2,->0,->1,->2,->2,->1,->0,->0,->2,->1,->1,->0,->2,->0,->0,->2,->1,->0,->0,->0,->0,->1,->0,->2,->0,->1,->1,->0,->0,->0,->1,->2,->1,->2,->1,->1,->0,->2,->2,->1,->2,->2,->1,->0,->0,->1,->2,->1,->2,->1,->0,->2,->0,->0,->0,->1,->2,->2,->0,->0,->2,->1,->1,->1,->1,->1,->0,->0,->1,->2,->2,->1,->1,->0,->1,->1,->0,->0,->1,->0,->1,->1,->0,->1,->0,->0,->0,->1,->2,->1,->1,->2,->1,->2,->0,->0,->2,->0,->0,->0,->2,->1,->2,->1,->1,->1,->0,->2,->0,->1,->1,->0,->2,->2,->2,->2,->2,->0,->0,->2,->0,->2,->1,->2,->1,->0,->1,->2,->2,->2,->0,->0,->0,->1,->2,->2,->2,->0,->2,->0,->1,->1,->2,->2,->2,->2,->1,->2,->2,->1,->2,->2,->2,->0,->1,->2,->2,->1,->2,->2,->0,->1,->2,->1,->1,->1,->0,->0,->2,->0,->2,->2,->2,->1,->1,->0,->0,->1,->2,->0,->0,->1,->2,->1,->1,->1,->1,->0,->2,->2,->1,->2,->0,->1,->0,->1,->2,->2,->0,->1,->2,->2,->1,->0,->1,->1,->1,->1,->2,->0,->0,->1,->0,->0,->0,->2,->1,->0,->1,->0,->0,->0,->2,->0,->0,->2,->2,->0,->2,->0,->1,->1,->1,->2,->1,->1,->0,->1,->1,->2,->1,->0,->0,->1,->0,->2,->0,->2,->0,->2,->2,->0,->2,->1,->2,->2,->1,->2,->1,->2,->1,->1,->0,->0,->0,->1,->1,->1,->2,->0,->1,->1,->2,->1,->2,->0,->2,->1,->1,->2,->0,->0,->0,->0,->2,->0,->1,->0,->2,->0,->1,->1,->2,->2,->1,->2,->0,->2,->1,->1,->2,->2,->2,->0,->0,->1,->2,->1,->1,->0,->1,->2,->2,->2,->0,->1,->2,->1,->1,->2,->2,->0,->1,->2,->2,->2,->0,->2,->1,->0,->0,->1,->2,->2,->1,->1,->1,->0,->0,->0,->1,->0,->0,->1,->2,->1,->1,->2,->0,->0,->2,->2,->0,->2,->0,->1,->0,->0,->1,->1,->0,->0,->2,->1,->1,->1,->2,->2,->0,->1,->2,->2,->0,->1,->0,->1,->1,->2,->0,->2,->0,->1,->2,->0,->0,->2,->2,->0,->0,->0,->0,->1,->2,->1,->2,->0,->0,->1,->2,->1,->2,->2,->0,->2,->0,->2,->1,->2,->0,->1,->1,->1,->2,->2,->1,->2,->1,->0,->0,->0,->2,->0,->0,->0,->0,->1,->2,->0,->1,->1,->1,->2,->0,->1,->0,->2,->2,->2,->0,->0,->2,->0,->2,->2,->1,->2,->1,->1,->1,->0,->2,->1,->2,->2,->2,->0,->0,->2,->1,->0,->1,->0,->2,->1,->2,->0,->1,->0,->2,->1,->0,->1,->2,->2,->1,->2,->1,->2,->2,->1,->1,->1,->2,->1,->1,->2,->0,->0,->0,->0,->1,->1,->2,->2,->1,->0,->1,->1,->1,->2,->1,->2,->2,->1,->0,->1,->0,->1,->2,->1,->1,->2,->0,->1,->0,->1,->2,->1,->2,->1,->1,->2,->2,->1,->2,->0,->0,->0,->1,->1,->0,->0,->1,->2,->0,->2,->1,->2,->2,->1,->1,->1,->0,->1,->0,->1,->0,->0,->2,->1,->0,->1,->2,->0,->1,->2,->1,->2,->1,->1,->2,->2,->1,->2,->0,->2,->1,->2,->1,->0,->0,->1,->1,->2,->1,->1,->2,->1,->2,->1,->0,->1,->0,->0,->0,->2,->0,->0,->0,->2,->0,->1,->1,->2,->0,->1,->2,->1,->0,->1,->1,->1,->0,->1,->0,->2,->0,->0,->2,->2,->2,->2,->0,->0,->1,->2,->2,->1,->0,->2,->0,->2,->2,->0,->1,->1,->2,->2,->0,->2,->1,->0,->2,->1,->0,->2,->2,->0,->1,->1,->2,->0,->2,->2,->0,->2,->2,->2,->0,->2,->0,->1,->0,->1,->2,->0,->0,->1,->0,->0,->1,->1,->2,->1,->0,->1,->1,->1,->2,->2,->1,->2,->0,->2,->0,->2,->2,->1,->0,->1,->0,->1,->1,->2,->0,->2,->2,->1,->1,->1,->1,->1,->2,->2,->2,->0,->2,->0,->0,->1,->1,->2,->2,->0,->0,->1,->1,->1,->2,->1,->0,->2,->0,->2,->0,->0,->2,->1,->1,->0,->2,->0,->0,->2,->2,->0,->1,->0,->2,->1,->2,->1,->1,->2,->2,->2,->2,->1,->2,->1,->2,->0,->1,->1,->0,->0,->0,->1,->2,->2,->2,->0,->1,->0,->1,->1,->2,->0,->1,->1,->1,->1,->2,->0,->2,->1,->1,->0,->2,->0,->2,->0,->1,->1,->0,->2,->2,->2,->1,->0,->1,->1,->2,->2,->1,->2,->1,->0,->2,->2,->0,->0,->1,->0,->0,->2,->1,->0,->1,->1,->1,->2,->0,->1,->1,->0,->2,->1,->1,->1,->2,->2,->0,->0,->1,->1,->1,->1,->2,->1,->1,->1,->2,->2,->1,->1,->1,->1,->2,->2,->2,->1,->1,->2,->2,->0,->0,->2,->2,->1,->2,->0,->0,->0,->0,->0,->2,->2,->2,->0,->0,->1,->1,->0,->1,->2,->0,->1,->1,->0,->2,->2,->1,->0,->0,->0,->2,->2,->0,->0,->1,->2,->0,->2,->1,->1,->2,->0,->0,->1,->2,->0,->1,->2,->1,->1,->2,->2,->1,->2,->0,->1,->1,->2,->2,->0,->1,->1,->1,->0,->2,->1,->0,->0,->0,->2,->0,->2,->1,->2,->1,->1,->0,->1,->2,->1,->2,->0,->0,->1,->0,->2,->2,->0,->1,->1,->0,->0,->2,->2,->1,->0,->0,->1,->0,->0,->2,->0,->2,->1,->1,->1,->2,->0,->2,->0,->2,->0,->0,->0,->0,->2,->0,->1,->2,->0,->2,->1,->1,->2,->2,->2,->0,->1,->1,->1,->1,->1,->2,->1,->2,->2,->0,->2,->1,->2,->2,->0,->0,->1,->0,->1,->2,->1,->1,->0,->2,->0,->0,->2,->2,->0,->0,->0,->1,->2,->2,->2,->0,->0,->1,->2,->0,->2,->0,->2,->0,->0,->1,->2,->1,->1,->2,->2,->1,->2,->0,->0,->0,->1,->2,->2,->1,->0,->1,->2,->2,->2,->0,->1,->2,->0,->2,->2,->2,->2,->1,->1,->0,->1,->1,->0,->0,->0,->1,->0,->0,->1,->2,->2,->1,->2,->1,->1,->2,->0,->0,->0,->0,->1,->1,->1,->2,->1,->1,->2,->1,->0,->2,->2,->2,->0,->1,->0,->1,->0,->1,->1,->2,->2,->0,->0,->0,->2,->2,->0,->0,->0,->1,->1,->0,->2,->0,->0,->2,->0,->2,->1,->2,->2,->2,->2,->2,->1,->2,->2,->1,->0,->0,->0,->1,->2,->0,->2,->2,->1,->2,->0,->2,->0,->1,->2,->1,->1,->2,->2,->1,->0,->0,->2,->2,->2,->0,->1,->2,->2,->0,->2,->1,->0,->0,->0,->2,->1,->2,->2,->2,->1,->1,->0,->1,->2,->0,->2,->2,->0,->1,->2,->2,->1,->2,->2,->0,->0,->1,->2,->2,->0,->0,->1,->0,->0,->2,->0,->1,->2,->1,->1,->1,->1,->0,->2,->1,->0,->0,->0,->1,->0,->1,->1,->2,->1,->2,->1,->0,->1,->1,->1,->0,->2,->2,->2,->2,->1,->2,->2,->1,->1,->1,->2,->2,->1,->2,->1,->0,->1,->2,->0,->1,->2,->2,->2,->0,->2,->0,->1,->1,->1,->0,->0,->0,->1,->0,->1,->0,->1,->1,->1,->2,->0,->1,->2,->2,->2,->2,->1,->2,->1,->1,->2,->0,->2,->0,->2,->2,->2,->1,->0,->0,->1,->0,->0,->1,->1,->0,->1,->0,->1,->0,->2,->2,->2,->1,->1,->2,->1,->0,->0,->1,->1,->0,->0,->2,->1,->0,->1,->1,->0,->2,->1,->1,->0,->1,->1,->2,->1,->1,->0,->1,->2,->0,->2,->2,->0,->0,->1,->2,->0,->2,->2,->1,->0,->1,->1,->2,->0,->0,->2,->0,->1,->0,->1,->2,->2,->0,->2,->0,->1,->2,->0,->0,->1,->1,->1,->1,->1,->0,->0,->2,->1,->1,->0,->2,->1,->2,->1,->0,->1,->0,->2,->1,->1,->2,->0,->0,->2,->2,->2,->1,->2,->0,->1,->2,->2,->1,->1,->2,->0,->1,->2,->2,->2,->0,->1,->1,->0,->1,->0,->1,->0,->0,->2,->2,->1,->1,->2,->1,->1,->2,->0,->0,->1,->0,->1,->2,->2,->0,->0,->2,->0,->0,->1,->1,->0,->0,->2,->1,->2,->1,->0,->0,->1,->1,->1,->1,->0,->0,->1,->2,->2,->1,->2,->0,->2,->1,->2,->1,->0,->1,->1,->1,->2,->1,->1,->0,->2,->2,->2,->2,->2,->1,->1,->2,->2,->1,->2,->0,->0,->0,->0,->1,->2,->0,->2,->0,->1,->1,->2,->2,->0,->2,->1,->2,->1,->1,->0,->2,->1,->2,->0,->0,->1,->2,->2,->2,->1,->0,->1,->1,->2,->0,->1,->1,->0,->2,->0,->2,->2,->0,->0,->2,->2,->0,->0,->1,->2,->0,->0,->1,->1,->2,->0,->1,->1,->2,->0,->0,->2,->0,->1,->0,->0,->2,->1,->0,->0,->2,->0,->0,->2,->0,->0,->1,->2,->0,->0,->2,->0,->0,->0,->1,->1,->0,->1,->0,->1,->0,->1,->2,->2,->2,->2,->0,->0,->1,->1,->0,->1,->0,->2,->1,->1,->2,->1,->2,->2,->0,->1,->0,->0,->1,->0,->2,->2,->1,->2,->2,->1,->1,->2,->0,->1,->0,->2,->1,->0,->0,->0,->0,->1,->2,->0,->2,->2,->1,->2,->0,->2,->0,->1,->0,->0,->2,->0,->2,->1,->1,->2,->1,->1,->2,->1,->2,->0,->0,->2,->0,->1,->0,->0,->1,->2,->2,->2,->1,->1,->0,->0,->2,->1,->0,->0,->2,->1,->2,->2,->2,->0,->2,->0,->1,->2,->2,->1,->2,->2,->0,->2,->0,->1,->1,->0,->0,->2,->2,->1,->2,->2,->0,->0,->0,->0,->1,->1,->0,->0,->0,->1,->0,->0,->1,->1,->1,->0,->2,->1,->0,->1,->1,->2,->2,->0,->1,->0,->0,->2,->1,->2,->2,->2,->1,->1,->2,->0,->0,->1,->1,->0,->2,->2,->0,->2,->2,->0,->0,->1,->2,->1,->1,->2,->1,->0,->1,->1,->2,->1,->2,->2,->1,->2,->1,->1,->1,->2,->1,->0,->0,->2,->0,->2,->2,->1,->1,->0,->2,->1,->0,->0,->1,->2,->0,->2,->1,->1,->2,->2,->2,->1,->1,->0,->0,->0,->2,->0,->1,->0,->2,->2,->0,->2,->2,->0,->0,->0,->1,->2,->1,->2,->0,->0,->2,->1,->0,->0,->1,->0,->0,->2,->2,->2,->2,->2,->0,->0,->2,->2,->2,->1,->2,->2,->1,->0,->0,->2,->0,->0,->1,->0,->0,->0,->2,->2,->1,->1,->2,->0,->2,->1,->1,->1,->2,->1,->2,->0,->1,->0,->2,->0,->0,->1,->2,->1,->2,->1,->1,->2,->1,->0,->2,->1,->2,->1,->2,->2,->0,->1,->0,->2,->2,->0,->1,->0,->1,->0,->0,->1,->1,->2,->2,->2,->2,->0,->0,->2,->1,->2,->0,->2,->0,->2,->0,->1,->1,->2,->0,->0,->1,->0,->0,->1,->1,->2,->1,->0,->0,->1,->0,->0,->2,->2,->1,->0,->1,->2,->2,->2,->1,->0,->0,->2,->2,->1,->1,->2,->0,->1,->2,->0,->2,->0,->1,->2,->0,->1,->0,->1,->1,->2,->0,->1,->1,->2,->1,->1,->1,->0,->0,->2,->1,->2,->1,->1,->2,->0,->0,->1,->2,->2,->1,->0,->2,->1,->0,->2,->2,->0,->1,->1,->0,->1,->1,->0,->2,->1,->1,->1,->0,->1,->2,->2,->0,->1,->1,->1,->2,->2,->1,->0,->2,->2,->0,->2,->2,->2,->2,->1,->1,->2,->1,->0,->2,->2,->1,->2,->1,->0,->1,->0,->0,->1,->2,->2,->0,->2,->2,->0,->0,->1,->0,->1,->2,->2};

Execute cell to define <testset>. Open the enclosed cell if you want to see all of them

testset = {->0,->2,->0,->2,->0,->0,->2,->2,->1,->1,->0,->1,->0,->0,->2,->2,->2,->0,->2,->0,->0,->1,->0,->1,->1,->0,->2,->0,->2,->0,->2,->0,->0,->1,->0,->2,->1,->1,->2,->2,->1,->1,->1,->1,->0,->2,->0,->2,->2,->1,->1,->0,->0,->0,->0,->1,->0,->1,->2,->0,->1,->0,->0,->1,->1,->0,->0,->2,->2,->0,->2,->2,->1,->1,->1,->2,->2,->1,->2,->2,->0,->1,->2,->1,->1,->1,->0,->0,->2,->1,->1,->2,->0,->1,->2,->1,->0,->0,->2,->0,->0,->0,->1,->1,->1,->1,->2,->0,->2,->2,->1,->0,->1,->2,->0,->2,->0,->0,->2,->0,->1,->2,->1,->2,->1,->2,->0,->1,->2,->2,->0,->2,->2,->0,->0,->0,->2,->0,->2,->2,->2,->0,->1,->1,->1,->1,->2,->2,->2,->1,->1,->2,->1,->1,->1,->2,->1,->0,->1,->1,->1,->0,->1,->0,->0,->1,->2,->0,->1,->1,->2,->0,->2,->0,->1,->2,->0,->0,->0,->2,->2,->2,->0,->0,->0,->0,->1,->0,->1,->0,->0,->0,->0,->2,->2,->2,->2,->0,->0,->0,->2,->2,->2,->2,->0,->1,->2,->1,->1,->1,->1,->1,->0,->2,->2,->2,->2,->2,->1,->2,->0,->0,->2,->0,->0,->0,->0,->1,->2,->2,->2,->1,->0,->2,->0,->0,->1,->1,->2,->1,->0,->1,->0,->2,->1,->0,->0,->0,->0,->0,->1,->1,->1,->1,->2,->2,->0,->2,->1,->0,->2,->0,->0,->1,->2,->0,->1,->0,->2,->1,->0,->1,->2,->2,->0,->1,->1,->2,->2,->2,->0,->1,->0,->2,->2,->1,->0,->0,->0,->0,->0,->2,->1,->0,->2,->1,->1,->2,->0,->2,->2,->1,->1,->0,->1,->2,->2,->2,->1,->2,->0,->0,->0,->0,->1,->1,->0,->0,->2,->0,->1,->2,->0,->0,->2,->2,->1,->0,->2,->1,->1,->1,->2,->2,->2,->0,->0,->0,->1,->0,->1,->0,->1,->0,->1,->1,->1,->2,->0,->1,->2,->1,->2,->2,->1,->2,->0,->2,->0,->1,->0,->2,->0,->1,->2,->1,->1,->0,->1,->1,->2,->0,->1,->0,->0,->1,->2,->2,->1,->0,->1,->2,->2,->0,->2,->2,->0,->0,->1,->2,->2,->1,->0,->2,->0,->2,->1,->2,->2,->2,->0,->0,->1,->0,->2,->2,->0,->1,->0,->1,->0,->2,->1,->2,->2,->1,->1,->0,->2,->0,->0,->1,->0,->2,->2,->1,->1,->1,->1,->1,->2,->2,->2,->0,->1,->1,->0,->0,->2,->1,->2,->1,->2,->0,->1,->1,->2,->1,->0,->0,->2,->0,->0,->0,->2,->0,->1,->2,->2,->2,->1,->2,->2,->1,->0,->1,->1,->2,->0,->0,->2,->1,->1,->0,->1,->0,->2,->2,->2,->0,->0,->0,->0,->2,->1,->0,->0,->2,->1,->0,->1,->2,->2,->1,->0,->2,->1,->0,->1,->1,->2,->0,->2,->0,->2,->2,->2,->2,->0,->2,->0,->2,->1,->0,->1,->1,->0,->2,->2,->1,->2,->1,->2,->1,->2,->1,->1,->0,->1,->2,->1,->0,->0,->0,->0,->2,->0,->2,->2,->0,->2,->1,->2,->1,->1,->1,->2,->0,->0,->2,->0,->1,->2,->1,->0,->1,->1,->2,->1,->1,->2,->0,->2,->2,->0,->2,->2,->1,->0,->2,->0,->1,->1,->2,->2,->1,->2,->0,->2,->0,->1,->0,->2,->2,->0,->0,->2,->2,->1,->1,->0,->1,->0,->1,->2,->2,->2,->1,->2,->1,->1,->1,->1,->1,->1,->1,->2,->0,->1,->0,->2,->1,->2,->2,->0,->1,->0,->0,->0,->1,->0,->0,->0,->1,->1,->0,->0,->1,->2,->2,->2,->0,->2,->2,->0,->2,->0,->1,->0,->1,->1,->0,->1,->2,->2,->1,->2,->0,->0,->1,->1,->2,->2,->1,->0,->0,->2,->1,->2,->0,->2,->1,->0,->1,->2,->0,->2,->2,->2,->0,->1,->1,->2,->0,->1,->1,->1,->1,->1,->1,->2,->2,->2,->2,->0,->0,->1,->1,->1,->1,->2,->0,->2,->1,->1,->1,->0};

Check a random samplings of the training and testsets. Look OK?

RandomSample[trainingset,12]
RandomSample[testset,12]

Inspect the number of training and test pairs.

{Dimensions[trainingset],Dimensions[testset],Union@Values[trainingset]}

Train supervised convolutional network to do head vs. elbow vs. background classification

classes=Union@Values[trainingset]

lenet=NetChain[
{ConvolutionLayer[40,5],Ramp,PoolingLayer[2,2,"Stride"->2],ConvolutionLayer[20,5],Ramp,PoolingLayer[2,2],FlattenLayer[],500,Ramp,3,SoftmaxLayer[]},
"Output"->NetDecoder[{"Class",classes}],
"Input"->NetEncoder[{"Image",{51,51}}]
];

trained=NetTrain[lenet,trainingset,ValidationSet->testset, MaxTrainingRounds->4]

Click on any of the above layers to get more details.  What is the stride length used in the pooling operation?

Defaults can usually be changed by specifying options during the setup of NetChain[].

Find out what SoftmaxLayer does. Wiki has the answer.

Quick comparison of predicted and actual class on a random selection from testset:

minitest = RandomSample[testset,16]

trained[Keys@minitest]
Values[minitest]

Summarize performance on the whole test set

cm=ClassifierMeasurements[trained,testset];
{"accuracy = ",cm["Accuracy"]}
cm["ConfusionMatrixPlot"]

This performance isn’t very good, given that current DCNN algorithms are getting accuracies within a few percent of perfect and with many more classes. However, they are also using bigger training sets. 

You could try again with a different permutation of the dataset. Try scrambling the training and test sets by first merging and then pulling out random samples for each. 

	{newtrainingset,newtestset}=TakeDrop[Join[trainingset, testset],2787]. 

Any ideas to improve the performance?

Output the confusion matrix in standard form. Double check the above accuracy by calculating the proportion correct.

Values@Values[cm["ConfusionFunction"]]//MatrixForm
N@Total@Diagonal[%]/Length[testset]