@[toc]
определение
Нейронная сеть — не очень сложная штука, в самой простой нейронной сети используется только простая обобщенная линейная регрессия и градиентный спуск.
Применение: применение нейронной сети очень широкое, и самым простым является прогнозирование данных, которое также следует использовать для прогнозирования данных, а также можно использовать для классификации из-за топологии работы нейронной сети. Например, если мы выполняем обработку признаков на картинке, а затем предсказываем и классифицируем извлеченные признаки, то мы можем добиться простого распознавания изображений и так далее (разумеется, тут задействованы сверточные нейронные сети и т.д.)
Этот пост описывает простейший алгоритм нейронной сети и реализует нейронную сеть вручную (на основе Python).
Фундаментальный
основной переход
На самом деле, использование простейшего процесса для описания принципа работы нейронной сети на самом деле является «решением грубой силы».
В качестве простого примера (демонстрирующего одномерную линейную регрессию с градиентным спуском) предположим, что у нас есть набор чисел
x = [1 2 3 4 5]
выходной сбор
y = [1 2 3 4 5]
Мы предполагаем отношение y = w*x +b
Теперь все, что нам нужно сделать, это знать значения w и b.
Самый простой способ, который вы знаете наверняка, этоСначала случайным образом сгенерируйте значение w b, то используем ошибку дляизменить w bсоответствующее значение. Итак, здесь, чтобы вычислить ошибку, нам нужноспособ вычислить значение ошибки и изменить соответствующее значение w b, например, мы вычисляем D(фактическое y, прогнозируемое y) по дисперсии .
Предполагая, что x = 1 в это время, начальное w = 2, b = 1, затем после расчета (конечно, мы фактически используем среднее значение x и среднее значение y)
y прогноз = 3 дисперсия = 4
На этом этапе мы можем применить алгоритм градиентного спуска.
Эта дисперсия называется функцией потерь loss = (w*x + b - y)^2
Возьмем частную производную по w, b соответственно, тогда получим
w` = w - w частная производная x размер шага
b` = b - b частная производная x размер шага
После входа в цикл мы получаем w = 1 b = 0
Из всего процесса кажется, что я только что представил, как использовать градиентный спуск, но если мы используем блок-схему, вы увидите это.
Фактически это эквивалентно «нейронной сети» только с одним узлом посередине (скрытый слой).
Базовая структура нейронной сети
На этом этапе мы можем ввести понятие нейронной сети, Ранее мы обнаружили, что когда мы вычисляем wb, есть случайное начальное значение (конечно, оно также может начинаться с 0 по умолчанию) через узел, тогда возникает проблема. Для сложной подгонки, предсказания начальное значение wb может привести к разным результатам, и одного узла может оказаться недостаточно.тщательныйПоэтому, обращаясь к биологическому миру (на самом деле я хотел бы сказать, что три сапожника бьют одного Чжугэ Ляна), мы можем разделить несколько узлов, а затем разделить значение x по весу, затем бросить его в узел и рассчитать его, а затем следовать определенному весу. Веса объединяются обратно, и, наконец, мы получаем значение wb для каждого узла и, наконец, объединяем их вместе.
Таким образом, это усложняется примерно так:
Затем вы понимаете, что этого недостаточно, поэтому вы видите много онлайн-блефа.
или
Но хотя это и так, общий принцип аналогичен предыдущему.
руки вверх
В этом случае я не стал переписывать его сам, а напрямую использовал простой купол, реализованный другими. В конце концов, ваш рукописный материал не так хорош, как готовый каркас, там много деталей, которые нужно учитывать, но основной принцип предложения аналогичен.
Цель
Нейронная сеть, которую мы собираемся смоделировать на этот раз,
Из предыдущего примера также следует понять, что первое, что мы делаем, это выбираем подходящее (или угадывающее уравнение) уравнение подгонки в качестве скрытого слоя.
Итак, здесь называется функция активации
Мы выбираем наиболее часто используемые
def sigmoid (x):
return 1/(1+numpy.exp(-x))
Это также функция активации, которую я использовал напрямую, когда занимался математическим моделированием (конечно, я делал это с помощью набора инструментов MATLAB).
использовать функцию активации
Теперь, когда мы выбрали функцию активации, следующий шаг — разделить значение X в соответствии с весом, как указано выше, а затем ввести его в операцию функции активации, а затем вывести в соответствии с весом. Конечно, мы не знаем этот вес, наша тренировка фактически определяет этот вес и определяет вес каждого слоя, и, наконец, мы можем вывести очень сложное уравнение. (Да, я делал то же самое, когда занимался математическим моделированием. Поскольку нет многокритериальной оптимизации, я напрямую подгоняю соотношение весов между каждой целью через нейронную сеть, получаю очень сложное уравнение и затем запускаю наследование. Ссылка:woohoo.n чистая информация.com/text/show/4…
Код здесь такой, судя по этой картинке
def feedforward(self,x):
h1 = x[0]*self.w1+x[1]*self.w2+self.b1
h1f = sigmoid(h1)
h2 = x[0]*self.w3+x[1]*self.w4+self.b2
h2f = sigmoid(h2)
o1 = h1f*self.w5+h2f*self.w6+self.b3
of = sigmoid(o1)
Затем мы инициализируем, сначала случайным образом задавая значение, а затем обучаем позже
class nerualnetwo():
def __init__(self):
self.w1 = numpy.random.normal()
self.w2 = numpy.random.normal()
self.w3 = numpy.random.normal()
self.w4 = numpy.random.normal()
self.w5 = numpy.random.normal()
self.w6 = numpy.random.normal()
self.b1 = numpy.random.normal()
self.b2 = numpy.random.normal()
self.b3 = numpy.random.normal()
функция потерь
Это по сравнению с предыдущим примером, как я узнаю, что эта вещь w b хороша, поэтому ее нужно исправить, вот дисперсия
def mse_loss(y_tr,y_pre):
return((y_tr - y_pre)**2).mean()
Оптимизация обратной связи (на основе градиентного спуска)
На самом деле нет необходимости использовать градиентный спуск для оптимизации веса каждого узла, но это проще всего реализовать и лучше понять. (также я могу написать)
Здесь для нахождения производной используется градиентный спуск. Но здесь есть разница
У нас есть два уровня градиентного спуска:
вход в скрытый слой
скрытый слой для вывода
Итак, этот блок требует двух функций
def der_sigmoid(x):
return sigmoid(x)*(1-sigmoid(x))
der_L_y_pre = -2*(y_tr-y_pre)
Обратите внимание здесь -2*(y_tr-y_pre)
На самом деле это y_pre, частная производная предсказания y.
Поскольку есть два последовательных слоя, весь градиентный спуск выглядит так:
self.w1 -= learn_rate * der_L_y_pre * der_y_pre_h1 * der_h1_w1
self.b1 -= learn_rate * der_L_y_pre * der_y_pre_h1 * der_h1_b1
в:der_h1_b1 = der_sigmoid(valcell[0])
*der_h1_w1 = der_sigmoid(valcell[0])x[0]
**那么这种处理方式叫做偏导的链式法则!!!**
То есть частные производные, полученные отдельно для w b
Что касается валцеллаh1,h1f,h2,h2f,o1,of
ты хочешь ввести
Коррекция градиента
Это легко сказать, на самом деле комбинезон зашагивает в петлю, а тут прямо 1000 раз пересчитывается
Следующее также является ядром всей операции
def train(self,data,all_y_tr):
epochs = 1000
learn_rate = 0.1
for i in range(epochs):
for x , y_tr in zip(data,all_y_tr):
valcell = self.feedforward(x)
y_pre = valcell[5]
der_L_y_pre = -2*(y_tr-y_pre)
der_y_pre_h1 = der_sigmoid(valcell[4])*self.w5
der_y_pre_h2 = der_sigmoid(valcell[4])*self.w6
der_h1_w1 = der_sigmoid(valcell[0])*x[0]
der_h1_w2 = der_sigmoid(valcell[0])*x[1]
der_h2_w3 = der_sigmoid(valcell[2])*x[0]
der_h2_w4 = der_sigmoid(valcell[2])*x[1]
der_y_pre_w5 = der_sigmoid(valcell[4])*valcell[1]
der_y_pre_w6 = der_sigmoid(valcell[4])*valcell[3]
der_y_pre_b3 = der_sigmoid(valcell[4])
der_h1_b1 = der_sigmoid(valcell[0])
der_h2_b2 = der_sigmoid(valcell[2])
#重新赋予权值和偏置
self.w1 -= learn_rate * der_L_y_pre * der_y_pre_h1 * der_h1_w1
self.w2 -= learn_rate * der_L_y_pre * der_y_pre_h1 * der_h1_w2
self.w3 -= learn_rate * der_L_y_pre * der_y_pre_h2 * der_h2_w3
self.w4 -= learn_rate * der_L_y_pre * der_y_pre_h2 * der_h2_w4
self.w5 -= learn_rate * der_L_y_pre * der_y_pre_w5
self.w6 -= learn_rate * der_L_y_pre * der_y_pre_w6
self.b1 -= learn_rate * der_L_y_pre * der_y_pre_h1 * der_h1_b1
self.b2 -= learn_rate * der_L_y_pre * der_y_pre_h2 * der_h2_b2
self.b3 -= learn_rate * der_L_y_pre *der_y_pre_b3
#每10步输出一次当前损失值
if i % 10 ==0 :
y_pred = numpy.apply_along_axis(self.simulate,1,data)
loss = mse_loss (all_y_tr , y_pred)
print(i,loss)
На этом этапе, после обучения, мы знаем вес каждого слоя и можем участвовать в операции.
Функция работы
def simulate (self,x):
h1 = x[0]*self.w1+x[1]*self.w2+self.b1
h1f = sigmoid(h1)
h2 = x[0]*self.w3+x[1]*self.w4+self.b2
h2f = sigmoid(h2)
o1 = h1f*self.w5+h2f*self.w6+self.b3
of = sigmoid(o1)
На самом деле это рабочая модель.После того, как модель обучена, веса известны, и хорошо бы ввести их в уравнение.
общий код
import numpy
def sigmoid (x):
return 1/(1+numpy.exp(-x))
def der_sigmoid(x):
return sigmoid(x)*(1-sigmoid(x))
def mse_loss(y_tr,y_pre):
return((y_tr - y_pre)**2).mean()
class nerualnetwo():
def __init__(self):
self.w1 = numpy.random.normal()
self.w2 = numpy.random.normal()
self.w3 = numpy.random.normal()
self.w4 = numpy.random.normal()
self.w5 = numpy.random.normal()
self.w6 = numpy.random.normal()
self.b1 = numpy.random.normal()
self.b2 = numpy.random.normal()
self.b3 = numpy.random.normal()
def feedforward(self,x):
h1 = x[0]*self.w1+x[1]*self.w2+self.b1
h1f = sigmoid(h1)
h2 = x[0]*self.w3+x[1]*self.w4+self.b2
h2f = sigmoid(h2)
o1 = h1f*self.w5+h2f*self.w6+self.b3
of = sigmoid(o1)
return h1,h1f,h2,h2f,o1,of
def simulate (self,x):
h1 = x[0]*self.w1+x[1]*self.w2+self.b1
h1f = sigmoid(h1)
h2 = x[0]*self.w3+x[1]*self.w4+self.b2
h2f = sigmoid(h2)
o1 = h1f*self.w5+h2f*self.w6+self.b3
of = sigmoid(o1)
return of
def train(self,data,all_y_tr):
epochs = 1000
learn_rate = 0.1
for i in range(epochs):
for x , y_tr in zip(data,all_y_tr):
valcell = self.feedforward(x)
y_pre = valcell[5]
der_L_y_pre = -2*(y_tr-y_pre)
der_y_pre_h1 = der_sigmoid(valcell[4])*self.w5
der_y_pre_h2 = der_sigmoid(valcell[4])*self.w6
der_h1_w1 = der_sigmoid(valcell[0])*x[0]
der_h1_w2 = der_sigmoid(valcell[0])*x[1]
der_h2_w3 = der_sigmoid(valcell[2])*x[0]
der_h2_w4 = der_sigmoid(valcell[2])*x[1]
der_y_pre_w5 = der_sigmoid(valcell[4])*valcell[1]
der_y_pre_w6 = der_sigmoid(valcell[4])*valcell[3]
der_y_pre_b3 = der_sigmoid(valcell[4])
der_h1_b1 = der_sigmoid(valcell[0])
der_h2_b2 = der_sigmoid(valcell[2])
self.w1 -= learn_rate * der_L_y_pre * der_y_pre_h1 * der_h1_w1
self.w2 -= learn_rate * der_L_y_pre * der_y_pre_h1 * der_h1_w2
self.w3 -= learn_rate * der_L_y_pre * der_y_pre_h2 * der_h2_w3
self.w4 -= learn_rate * der_L_y_pre * der_y_pre_h2 * der_h2_w4
self.w5 -= learn_rate * der_L_y_pre * der_y_pre_w5
self.w6 -= learn_rate * der_L_y_pre * der_y_pre_w6
self.b1 -= learn_rate * der_L_y_pre * der_y_pre_h1 * der_h1_b1
self.b2 -= learn_rate * der_L_y_pre * der_y_pre_h2 * der_h2_b2
self.b3 -= learn_rate * der_L_y_pre *der_y_pre_b3
if i % 10 ==0 :
y_pred = numpy.apply_along_axis(self.simulate,1,data)
loss = mse_loss (all_y_tr , y_pred)
print(i,loss)
if __name__ == "__main__":
data = numpy.array([[-2, -1],[25, 6],[17, 4],[-15, -6]])
all_y_trues = numpy.array([1,0,0,1])
ner = nerualnetwo()
ner.train(data,all_y_trues)
Суммировать
На самом деле самая базовая нейросеть тут такая.Основа это две вещи.Конечно,деталей много.
функция активации
Автоматически корректировать вес
Выберите подходящую функцию активации, активируйте и используйте метод самокоррекции, чтобы минимизировать функцию потерь. Затем по мере увеличения количества слоев нейронной сети она усложняется.Конечно, показатель точности не обязательно пропорционален количеству слоев.Я проверял это.