Приступая к изучению нового следует начинать с самого простого. Вот я и решил сделать на нейронной сети побитовое И.
Вообще то, побитовое И представляет собой операцию между двумя отдельными битами. Бит может быть 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]
Результат работы третьей сети очень похож на результаты первой и второй сети. Так и должно быть :)
Можно подвести некоторые итоги. Использование скрытого слоя в нейронной сети, где применяется только линейная функция активации не кажется хорошей идеей. Однако, сеть с большим количеством нейронов позволяет получить аналогичный результат при большем числе вариантов значений весовых коэффициентов. Будет ли это полезно? Пока не знаю.
Комментариев нет:
Отправить комментарий