Нейронные сети доказали, что они являются трендом нашего века, благодаря их успеху в различных областях. Сегодня я собираюсь поговорить о нейронных сетях, использующих синусоидальную функцию в качестве основы вместо линейной функции. Мы собираемся реализовать нейронную сеть на основе синусоидальной функции и оценим результаты.

Откуда взялась идея?

Идея использования синусоидальной функции в качестве основы для нейронных сетей пришла из моего опыта обработки сигналов. Если вы слышали о преобразовании Фурье раньше, вы знаете, что можете представить любую функцию с помощью функций косинуса и синуса, и вы можете четко показать суммированные функции в частотной области. Поговорка «Вы можете представить любую функцию с помощью функций косинуса и синуса» проникла в мое сердце. Я связал это с нейронными сетями, потому что мы также можем представить любую функцию с помощью нейронных сетей.

Хватит говорить, я знаю, что вы хотите увидеть математику, реализацию и результаты. Итак, продолжим ...

Базисная функция синуса в нейронной сети

Реализация

В качестве основы я использовал структуру классов и кода из Как построить свою собственную нейронную сеть с нуля на Python.

import numpy as np
class NeuralNetwork:
    #DEFINE INITIALS
    def __init__(self, x, y):
        self.input      = x
        self.y          = y
        self.weights_in = np.random.uniform(-1, 1,(self.y.shape[1],self.input.shape[1]))
        self.weights_out = np.random.uniform(-1, 1,(self.y.shape[1],self.input.shape[1]))     
        self.output     = np.random.uniform(-1, 1,self.y.shape)
        print('Output:',self.output)
        print('Y:',self.y)
#DEFINE FEEDFORWARD
    def feedforward(self,cnt):
        self.output[cnt] = np.sum(self.weights_out*self.input[cnt]*np.sin(np.pi*self.input[cnt]*self.weights_in),axis = 1)
        
    #DEFINE BACKPROPAGATION
    def backprop(self,cnt):
        error = np.square(self.y[cnt]-self.output[cnt])
        derror_doutput = self.y[cnt]-self.output[cnt]
        doutput_dweights_in = self.weights_out * np.square(self.input[cnt]) * np.pi * np.cos(np.pi*self.input[cnt]*self.weights_in)
        doutput_dweights_out = self.input[cnt]*np.sin(np.pi*self.input[cnt]*self.weights_in)
        dweights_in = np.dot(derror_doutput,doutput_dweights_in)
        dweights_out = np.dot(derror_doutput,doutput_dweights_out)
        self.weights_in += dweights_in*0.05
        self.weights_out += dweights_out*0.05
#PREDICT THE TEST DATA
    def predict(self,input_):
        predictions = []
        for elm in input_:
            predictions.append(np.sum(self.weights_out*elm*np.sin(np.pi*elm*self.weights_in),axis = 1).tolist())
        return np.array(predictions)
    
    #SAVE WEIGHTS
    def save_weights(self,dir_in = './weights_in.npy',dir_out = './weights_out.npy'):
        np.save(dir_in,self.weights_in)
        np.save(dir_out,self.weights_out)
        
    #IMPORT WEIGHTS
    def import_weights(self,dir_in = './weights_in.npy',dir_out = './weights_out.npy'):
        self.weights_in = np.load(dir_in)
        self.weights_out = np.load(dir_out)

Мы определили наш класс. Время проверить.

Мы представим логические элементы (И, ИЛИ, ИСКЛЮЧАЮЩЕЕ ИЛИ) с помощью нашей нейронной сети (что означает, что мы получим 3 выхода от нейронной сети для каждого логического элемента). Я дам 3 значения для каждой входной выборки. Входные данные не будут целыми числами, это будут числа с плавающей запятой, например 0,01 вместо 0 или 0,99 вместо 1.

Пример:

Ввод: [0.01,0.01,0.99]

И: 0,01, ИЛИ: 0,99, ИСКЛЮЧАЮЩЕЕ ИЛИ: 0,99

x = np.array([[0.01,0.1,0.01],[0.01,0.99,0.99],[0.99,0.99,0.01],[0.99,0.99,0.01],[0.9,0.9,0.9]])
y = np.array([[0.01,0.01,0.01],[0.01,0.99,0.99],[0.01,0.99,0.99],[0.01,0.99,0.99],[0.99,0.99,0.01]])
nn = NeuralNetwork(x,y)
#TRAIN NETWORK FOR 2000 TIMES.
for gen_cnt in range(2000):
    for cnt in range(5):
        nn.feedforward(cnt)
        nn.backprop(cnt)
#PREDICT THE TEST DATA
predictions = nn.predict(np.array([[0.01,0.2,0.2],[0.9,0.1,0.95]]))
print('Predictions:\n',np.around(predictions),'\nExpected:\n',[[0,0,0],[0,1,1]])

Я дал тестовые данные как [[0.01,0.2,0.2], [0.9,0.1,0.95]] вместо [[0.01,0.01,0.01], [0.99,0.01,0.99]], чтобы проверить, делает ли сеть обобщение.

Полученные результаты

Прогнозы:
[[0. 0. -0.] [0. 1. 1.]]
Ожидаемые:
[[0, 0, 0], [0, 1, 1 ]]

После нескольких тренировок я обнаружил, что лучшие веса:

Вес_дюйм:

0.793539 -0.866737 0.883148
1.32484 -0.20837 0.214222
0.359695 -1.21818 -0.329374

Выходной_вес:

  • 0.0841964 -0.147961 0.854469
    -0.958252 0.0361619 1.2046
    0.732407 0.0986183 -0.305971

Заключение

Как мы видим, концепция «Вы можете представить любую функцию с помощью синусоидальных функций» работает и для нейронных сетей. Несмотря на то, что мы создали нейронную сеть без какого-либо скрытого слоя, мы доказали, что синусоидальная функция может использоваться вместо линейной функции в качестве основы. Поскольку это динамические функции, нам не нужно было добавлять какую-либо функцию активации. Мы могли легко уловить нелинейность благодаря природе синусоидальных функций. Следующим шагом для меня является реализация базисной функции синуса для глубоких нейронных сетей. Это сложная проблема, опять же благодаря природе синусоидальной функции, но проблемы всегда приветствуются ...