воскресенье, 29 ноября 2020 г.

Нейронная сеть. Часть 1.

Приступая к изучению нового следует начинать с самого простого. Вот я и решил сделать на нейронной сети побитовое И.

Вообще то, побитовое И представляет собой операцию между двумя отдельными битами. Бит может быть 0 или 1. Таким образом, получается всего четыре варианта.

0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1

Но на вход нейронной сети не обязательно подавать 0 и 1. За 0 и 1 можно считать что угодно. Получение 0 и 1 на выходе также не обязательно. Необходима лишь возможность однозначной интерпретации результата работы нейронной сети.

Сама нейронная сеть состоит из нейронов. Неожиданно? Да? У нейронов может быть несколько входов и один выход. С каждым отдельным входом связан определенный весовой коэффициент (вес связи). Данные с входов умножаются на соответствующие им веса и все полученные значения складываются. Затем результат передается в функцию активации, а возвращенное функцией активации значение является выходными данными нейрона. Как не трудно догадаться, нейроны в сети соединены друг с другом определенным образом (данные с выхода одних нейронов поступают на вход других).

В нейронных сетях показанных ниже будет использоваться линейная функция активации.

 


y = x

Простой и очень быстрый вариант.

Самая первая нейронная сеть будет состоять из трех нейронов. Два входных нейрона и один выходной.



Отдельный входной нейрон можно представить, как нейрон с одним входом, весовой коэффициент которого равен 1 и линейной функцией активации. Данные на выходе такого нейрона такие же как и на входе. Поэтому какие либо вычисления для входных нейронов не требуются.

w0, w1 - веса связей выходного нейрона. От значения этих переменных зависит результат выдаваемый нейронной сетью. Первая сеть очень простая. Подходящие веса можно легко вычислить.

Код

#!/usr/bin/env python3
# coding: utf-8

# Neural network.
# First layer: 2 input neurons.
# Second  layer: 1 output neuron.
# Identity activation function.

class neural_network :

    def __init__ (self) :

        self.w0 = 0.4
        self.w1 = 0.4

    def activation_function (self, x) :
        """Identity function
        """
        return (x)

    def query (self, input0, input1) :

        output = (input0 * self.w0) + (input1 * self.w1)
        output = self.activation_function(output)

        return (output)

nn = neural_network ()

a = 0.1
b = 0.9

print (a, a, nn.query(a, a))
print (a, b, nn.query(a, b))
print (b, a, nn.query(b, a))
print (b, b, nn.query(b, b))

# End

Результат выполнения кода

$ python3 ./and_3_identity.py
0.1 0.1 0.08
0.1 0.9 0.40
0.9 0.1 0.40
0.9 0.9 0.72

Результат вполне приемлем. Если округлить результат до ближайшего целого, получается сносно.

Вторая нейронная сеть состоит из двух входных нейронов, двух нейронов скрытого слоя и одного выходного нейрона.



w0, w1 - веса связей первого нейрона скрытого слоя. w2, w3 - веса связей второго нейрона скрытого слоя. w4, w5 - веса связей выходного нейрона.

Код

#!/usr/bin/env python3
# coding: utf-8

# Neural network.
# First layer: 2 input neurons.
# Second  layer: 2 hidden neurons.
# Third  layer: 1 output neuron.
# Identity activation function.

class neural_network :

    def __init__ (self) :

        self.w0 = -4.2
        self.w1 = -3.8
        self.w2 = 1.7
        self.w3 = 1.5
        self.w4 = -0.3
        self.w5 = -0.5

    def activation_function (self, x) :
        """Identity function
        """
        return (x)

    def query (self, input0, input1) :

        hidden0 = (input0 * self.w0) + (input1 * self.w1)
        hidden0 = self.activation_function(hidden0)

        hidden1 = (input0 * self.w2) + (input1 * self.w3)
        hidden1 = self.activation_function(hidden1)

        output = (hidden0 * self.w4) + (hidden1 * self.w5)
        output = self.activation_function(output)

        return (output)

nn = neural_network ()

a = 0.1
b = 0.9

print (a, a, nn.query(a, a))
print (a, b, nn.query(a, b))
print (b, a, nn.query(b, a))
print (b, b, nn.query(b, b))

# End

Результат выполнения кода

$ python3 ./and_5_identity.py
0.1 0.1 0.07999
0.1 0.9 0.39199
0.9 0.1 0.40799
0.9 0.9 0.72000

Результат не сильно отличается от полученного ранее.

Третья нейронная сеть состоит из двух входных нейронов, трех нейронов скрытого слоя и одного выходного нейрона.



Сразу приведу один из возможных вариантов значений весов для этой нейронной сети.

w0 = 5.0
w1 = -2.4
w2 = 1.2
w3 = -0.8
w4 = -1.4
w5 = 1.0
w6 = 0.8
w7 = -4.4
w8 = -1.2

Код

#!/usr/bin/env python3
# coding: utf-8

# Neural network.
# First layer: 2 input neurons.
# Second  layer: 3 hidden neurons.
# Third  layer: 1 output neuron.
# Identity activation function.

class neural_network :

    def __init__ (self) :

        self.hidden_weight = [[5.0, -2.4], [1.2, -0.8], [-1.4, 1.0]]
        self.output_weight = [[0.8, -4.4, -1.2]]

    def activation_function (self, x) :
        """Identity function
        """
        return (x)

    def query (self, input_data) :

        hidden_data = [0, 0, 0]
        output_data = [0]

        hidden_data[0] += input_data[0] * self.hidden_weight[0][0]
        hidden_data[0] += input_data[1] * self.hidden_weight[0][1]
        hidden_data[0] = self.activation_function(hidden_data[0])

        hidden_data[1] += input_data[0] * self.hidden_weight[1][0]
        hidden_data[1] += input_data[1] * self.hidden_weight[1][1]
        hidden_data[1] = self.activation_function(hidden_data[1])

        hidden_data[2] += input_data[0] * self.hidden_weight[2][0]
        hidden_data[2] += input_data[1] * self.hidden_weight[2][1]
        hidden_data[2] = self.activation_function(hidden_data[2])

        output_data[0] += hidden_data[0] * self.output_weight[0][0]
        output_data[0] += hidden_data[1] * self.output_weight[0][1]
        output_data[0] += hidden_data[2] * self.output_weight[0][2]
        output_data[0] = self.activation_function(output_data[0])

        return (output_data)

nn = neural_network ()

a = 0.1
b = 0.9

print ([a, a], nn.query([a, a]))
print ([a, b], nn.query([a, b]))
print ([b, a], nn.query([b, a]))
print ([b, b], nn.query([b, b]))

# End

Веса записаны как списки. При таком использовании списки python очень похожи на массивы C. Используя этот код уже можно сделать более универсальную реализацию нейронной сети. А ранее представленный код должен был быть более наглядным и продемонстрировать насколько просто сделать нейронную сеть.

Результат выполнения кода

$ python3 ./and_6_identity.py
[0.1, 0.1] [0.08000000000000006]
[0.1, 0.9] [0.40000000000000036]
[0.9, 0.1] [0.39999999999999947]
[0.9, 0.9] [0.7199999999999998]

Результат работы третьей сети очень похож на результаты первой и второй сети. Так и должно быть :)

Можно подвести некоторые итоги. Использование скрытого слоя в нейронной сети, где применяется только линейная функция активации не кажется хорошей идеей. Однако, сеть с большим количеством нейронов позволяет получить аналогичный результат при большем числе вариантов значений весовых коэффициентов. Будет ли это полезно? Пока не знаю.

Комментариев нет:

Отправить комментарий