| 26 | using namespace dlib; |
| 27 | |
| 28 | int main(int argc, char** argv) try |
| 29 | { |
| 30 | // This example is going to run on the MNIST dataset. |
| 31 | if (argc != 2) |
| 32 | { |
| 33 | cout << "This example needs the MNIST dataset to run!" << endl; |
| 34 | cout << "You can get MNIST from http://yann.lecun.com/exdb/mnist/" << endl; |
| 35 | cout << "Download the 4 files that comprise the dataset, decompress them, and" << endl; |
| 36 | cout << "put them in a folder. Then give that folder as input to this program." << endl; |
| 37 | return 1; |
| 38 | } |
| 39 | |
| 40 | |
| 41 | // MNIST is broken into two parts, a training set of 60000 images and a test set of |
| 42 | // 10000 images. Each image is labeled so that we know what hand written digit is |
| 43 | // depicted. These next statements load the dataset into memory. |
| 44 | std::vector<matrix<unsigned char>> training_images; |
| 45 | std::vector<unsigned long> training_labels; |
| 46 | std::vector<matrix<unsigned char>> testing_images; |
| 47 | std::vector<unsigned long> testing_labels; |
| 48 | load_mnist_dataset(argv[1], training_images, training_labels, testing_images, testing_labels); |
| 49 | |
| 50 | |
| 51 | // Now let's define the LeNet. Broadly speaking, there are 3 parts to a network |
| 52 | // definition. The loss layer, a bunch of computational layers, and then an input |
| 53 | // layer. You can see these components in the network definition below. |
| 54 | // |
| 55 | // The input layer here says the network expects to be given matrix<unsigned char> |
| 56 | // objects as input. In general, you can use any dlib image or matrix type here, or |
| 57 | // even define your own types by creating custom input layers. |
| 58 | // |
| 59 | // Then the middle layers define the computation the network will do to transform the |
| 60 | // input into whatever we want. Here we run the image through multiple convolutions, |
| 61 | // ReLU units, max pooling operations, and then finally a fully connected layer that |
| 62 | // converts the whole thing into just 10 numbers. |
| 63 | // |
| 64 | // Finally, the loss layer defines the relationship between the network outputs, our 10 |
| 65 | // numbers, and the labels in our dataset. Since we selected loss_multiclass_log it |
| 66 | // means we want to do multiclass classification with our network. Moreover, the |
| 67 | // number of network outputs (i.e. 10) is the number of possible labels. Whichever |
| 68 | // network output is largest is the predicted label. So for example, if the first |
| 69 | // network output is largest then the predicted digit is 0, if the last network output |
| 70 | // is largest then the predicted digit is 9. |
| 71 | using net_type = loss_multiclass_log< |
| 72 | fc<10, |
| 73 | relu<fc<84, |
| 74 | relu<fc<120, |
| 75 | max_pool<2,2,2,2,relu<con<16,5,5,1,1, |
| 76 | max_pool<2,2,2,2,relu<con<6,5,5,1,1, |
| 77 | input<matrix<unsigned char>> |
| 78 | >>>>>>>>>>>>; |
| 79 | // This net_type defines the entire network architecture. For example, the block |
| 80 | // relu<fc<84,SUBNET>> means we take the output from the subnetwork, pass it through a |
| 81 | // fully connected layer with 84 outputs, then apply ReLU. Similarly, a block of |
| 82 | // max_pool<2,2,2,2,relu<con<16,5,5,1,1,SUBNET>>> means we apply 16 convolutions with a |
| 83 | // 5x5 filter size and 1x1 stride to the output of a subnetwork, then apply ReLU, then |
| 84 | // perform max pooling with a 2x2 window and 2x2 stride. |
| 85 |
nothing calls this directly
no test coverage detected