An example of a simple neural network, as a result, figure out what's what

Published on July 14, 2019

An example of a simple neural network, as a result, figure out what's what

    Neural networks - this is a topic that causes great interest and a desire to understand it. But, unfortunately, it does not lend itself to everyone. When you see volumes of obscure literature, you lose the desire to study, but you still want to keep abreast of what is happening.

    In the end, it seemed to me that there is no better way to figure it out than just take and create your own small project.

    You can read the lyric background by expanding the text, or you can skip this and go directly to the description of the neural network.

    What is the point of doing your project.
    Pros:

    1. You better understand how neurons are arranged
    2. You better understand how to work with existing libraries
    3. Learning something new in parallel
    4. Tickle your Ego, creating something of your own

    Minuses:

    1. You’re creating a bicycle, more likely than worse than existing ones
    2. No one cares about your project.


    Language selection.
    На момент выбора языка я более-менее знал С++, и был знаком с основами Python. Работать с нейронками проще на Python, но С++ знал лучше и нет проще распараллеливания вычислений, чем OpenMP. Поэтому я выбрал С++, а API под Python, чтобы не заморачиваться, будет создавать swig, который работает на Windows и Linux. (Пример, как сделать из кода С++ библиотеку для Python)

    OpenMP and GPU acceleration.
    На данный момент в Visual Studio установлена OpenMP версии 2.0., в которой есть только CPU ускорение. Однако начиная с версии 3.0 OpenMP поддерживает и GPU ускорение, при этом синтаксис директив не усложнился. Осталось лишь дождаться, когда OpenMP 3.0 будет поддерживаться всеми компиляторами. А пока, для простоты, только CPU.

    My first rake.
    В вычислении значения нейрона есть следующий момент: перед тем, как мы вычисляем функцию активации, нам надо сложить перемножение весов на входные данные. Как учат это делать в университете: прежде чем суммировать большой вектор маленьких чисел, его надо отсортировать по возрастанию. Так вот. В нейросетях кроме как замедление работы программы в N раз ничего это не даёт. Но понял я это лишь тогда, когда уже тестировал свою сеть на MNIST.

    Putting a project on GitHub.
    Я не первый, кто выкладывает своё творение на GitHub. Но в большинстве случаев, перейдя по ссылке, видишь лишь кучу кода с надписью в README.md «Это моя нейросеть, смотрите и изучайте». Чтобы быть лучше других хотя бы в этом, более-менее описал README.md и заполнил Wiki. Посыл же простой — заполняйте Wiki. Интересное наблюдение: если заголовок в Wiki на GitHub написан на русском языке, то якорь на этот заголовок не работает.

    License.
    Когда создаёшь свой маленький проект, лицензия — это опять же способ пощекотать своё Эго. Вот интересная статья на тему, для чего нужна лицензия. Я же остановил свой выбор на APACHE 2.0.

    Description of the network.


    Specifications:
    Title FoxNN (Fox-Neural-Network )
    operating system Windows Linux
    Languages C ++, Python
    Acceleration CPU (GPU in the plans)
    External dependencies No (pure C ++, STL, OpenMP)
    Compilation flags -std = c ++ 14 -fopenmp
    Layers linear (convolutional plans)
    Optimizations Adam, Nesterov
    Random weight change there is
    Wikipedia (instruction) there is


    The main advantage of my library is the creation of a network with one line of code.

    It is easy to notice that in linear layers the number of neurons in one layer is equal to the number of input parameters in the next layer. Another obvious statement - the number of neurons in the last layer is equal to the number of output values ​​of the network.

    Let's create a network that receives three parameters at the input, which has three layers with 5, 4 and 2 neurons.

    import foxnn
    nn = foxnn.neural_network([3, 5, 4, 2]) 
    

    If you look at the picture, you can just see: first 3 input parameters, then a layer with 5 neurons, then a layer with 4 neurons and, finally, the last layer with 2 neurons.



    By default, all activation functions are sigmoid (I like them more).
    If desired, on any layer you can change to another function.

    The most popular activation features are available.


    nn.get_layer(0).set_activation_function("gaussian")
    

    Easy to create training set. The first vector is the input data, the second vector is the target data.

    data = foxnn.train_data()
    data.add_data([1, 2, 3], [1, 0]) #на вход три параметра, на выход два параметра
    

    Network Training:

    nn.train(data_for_train=data, speed=0.01, max_iteration=100, size_train_batch=98)
    

    Enabling optimization:

    nn.settings.set_mode("Adam")
    

    And a method to simply get the network value:

    nn.get_out([0, 1, 0.1])
    

    A little bit about the name of the method.
    Отдельно get переводится как получить, а outвыход. Хотел получить название "дай выходное значение", и получил это. Лишь позже заметил, что получилось выметайся. Но так забавнее, и решил оставить.

    Testing


    It has already become an unwritten tradition to test any network based on MNIST . And I was no exception. All code with comments can be found here .

    Creates a training sample:
    from mnist import MNIST
    import foxnn
    mndata = MNIST('C:download/')
    mndata.gz = True
    imagesTrain, labelsTrain = mndata.load_training()
    def get_data(images, labels):
        train_data = foxnn.train_data()
        for im, lb in zip(images, labels):
            data_y = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] # len(data_y) == 10
            data_y[lb] = 1 
            data_x = im
            for j in range(len(data_x)):
                # приводим пиксель в диапазон (-1, 1)
                data_x[j] = ((float(data_x[j]) / 255.0) - 0.5) * 2.0  
            train_data.add_data(data_x, data_y) # добавляем в обучающую выборку
        return train_data
    train_data = get_data(imagesTrain, labelsTrain)
    


    Create a network: three layers, 784 parameters for input, and 10 for output:
    nn = foxnn.neural_network([784, 512, 512, 10])
    nn.settings.n_threads = 7 # распараллеливаем процесс обучения на 7 процессов
    nn.settings.set_mode("Adam") # используем оптимизацию Адама
    


    We train:
    nn.train(data_for_train=train_data, speed=0.001, max_iteration=10000, size_train_batch=98)
    


    What happened:

    In about 10 minutes (only CPU acceleration), you can get an accuracy of 75%. With Adam’s optimization, 88% percent accuracy can be obtained in 5 minutes. In the end, I managed to achieve an accuracy of 97%.

    The main disadvantages (there are already plans for revision):
    1. В Python ещё не протянуты ошибки, т.е. в python ошибка не будет перехвачена и программа просто завершится с ошибкой.
    2. Пока обучение указывается в итерациях, а не в эпохах, как это принято в других сетях.
    3. Нет GPU ускорения
    4. Пока нет других видов слоёв.
    5. Надо залить проект на PyPi.


    For a little completion of the project, this article was lacking. If at least ten people are interested and play, then there will already be a victory. Welcome to my github .

    PS: If you need to create something of your own in order to understand, do not be afraid and create.