Обзор
Структура нейронной сети состоит из входного слоя, скрытого слоя и выходного слоя.Каждый узел в нейронной сети связан со всеми узлами в предыдущем слое, который мы называем полностью связанным, как показано на рисунке ниже.
В нейронной сети, показанной на рисунке, исходные входные данные и выходные данные, рассчитанные первым скрытым слоем, будут переданы второму скрытому слою. Выходные данные второго слоя будут использоваться в качестве входных данных выходного слоя.
прямое распространение
Рассчитайте данные входного слоя для передачи скрытому слою:
Как видно из рисунка ниже, мы можем вычислить первый нейрон скрытого слояЗначение:
вэто функция активации
Как видно из рисунка ниже, мы можем вычислить второй нейрон скрытого слояЗначение:
Как видно из рисунка ниже, мы можем вычислить третий нейрон скрытого слояЗначение:
Пока что мы вычислили все значения от входного слоя до скрытого слоя.
Процесс вычисления скрытого слоя в выходной слой:
Как видно из рисунка ниже, мы можем вычислить скрытый слой до первого выходного нейронаЗначение:
Аналогично можно сделать вывод, что,Значение:
Чтобы упростить наш будущий процесс обработки данных, сейчас мы устанавливаемВходными данными слоя является вектор, вес, переменная смещения. Тогда мы можем получить из приведенного выше процесса решенияДанные для слоя:
На данный момент процесс прямого распространения нейронной сети завершен.
обратное распространение
Идея обратного реле заключается в том, что мы вычисляем выходное значение сети посредством прямого распространения, Зная выходное значение, мы можем найти остаток выходного слоя, а затем вернуть остаток из выходного слоя обратно в нейронный сеть каждого слоя.
Предположим, у нас есть фиксированная выборка, который содержитобразец. Мы можем использовать пакетный градиентный спуск для решения нейронных сетей. В частности, для одного образца, а его функция стоимости выглядит следующим образом (взято из сети):
Мы можем определить общую функцию затрат, как показано ниже (взято из сети):
выше оПервый член в определении представляет собой среднеквадратичную ошибку. Второй член - это член регуляризации (также называемый членом затухания веса), целью которого является уменьшение величины весов и предотвращение переобучения.
С общей функцией стоимости наша цель может быть преобразована в поиск минимального значения функции стоимости. Мы используемАлгоритм градиентного спускаЧтобы найти минимальное значение функции стоимости, мы приходим к следующей формуле:
Возьмем частную производную от общей функции затрат:
Как видно из приведенных выше двух уравнений, мы преобразуем задачу визначение
Итак, для первогокаждый выходной блок слоя (выходной слой), рассчитываем остатки по следующей формуле (рисунок ниже взят из сети):
правильноразличные слоипервоеОстаточный метод расчета каждого узла следующий (рисунок ниже взят из сети):
Вышеупомянутый процесс вывода сзади вперед является первоначальным значением «обратной проводимости».Для вычисления необходимых нам частных производных метод расчета следующий:
Реализация нейронной сети BP на Python
# -*- coding: utf-8 -*-
'''
Created on
@author: Belle
'''
from numpy.random.mtrand import randint
import numpy as np
'''双曲函数'''
def tanh(value):
return (1 / (1 + np.math.e ** (-value)))
'''双曲函数的导数'''
def tanhDer(value):
tanhValue = tanh(value)
return tanhValue * (1 - tanhValue)
'''
Bp神经网络model
'''
class BpNeuralNetWorkModel:
def __init__(self, trainningSet, label, layerOfNumber, studyRate):
'''学习率'''
self.studyRate = studyRate
'''计算隐藏层神经元的数量'''
self.hiddenNeuronNum = int(np.sqrt(trainningSet.shape[1] + label.shape[1]) + randint(1, 10))
'''层数据'''
self.layers = []
'''创建输出层'''
currentLayer = Layer()
currentLayer.initW(trainningSet.shape[1], self.hiddenNeuronNum)
self.layers.append(currentLayer)
'''创建隐藏层'''
for index in range(layerOfNumber - 1):
currentLayer = Layer()
self.layers.append(currentLayer)
'''输出层后面不需要求权重值'''
if index == layerOfNumber - 2:
break
nextLayNum = 0
'''初始化各个层的权重置'''
if index == layerOfNumber - 3:
'''隐藏层到输出层'''
nextLayNum = label.shape[1]
else:
'''隐藏层到隐藏层'''
nextLayNum = self.hiddenNeuronNum
currentLayer.initW(self.hiddenNeuronNum, nextLayNum)
'''输出层的分类值'''
currentLayer = self.layers[len(self.layers) - 1]
currentLayer.label = label
'''神经网络前向传播'''
def forward(self, trainningSet):
'''计算输入层的输出值'''
currentLayer = self.layers[0]
currentLayer.alphas = trainningSet
currentLayer.caculateOutPutValues()
preLayer = currentLayer
for index in range(1, len(self.layers)):
currentLayer = self.layers[index]
'''上一层的out put values就是这一层的zValues'''
currentLayer.zValues = preLayer.outPutValues
'''计算alphas'''
currentLayer.caculateAlphas()
'''最后一层不需要求输出值,只要求出alpha'''
if index == len(self.layers) - 1:
break
'''输入层计算out puts'''
currentLayer.caculateOutPutValues()
'''指向上一层的layer'''
preLayer = currentLayer
'''神经网络后向传播'''
def backPropogation(self):
layerCount = len(self.layers)
'''输出层的残差值'''
currentLayer = self.layers[layerCount - 1]
currentLayer.caculateOutPutLayerError()
'''输出层到隐藏层'''
preLayer = currentLayer
layerCount = layerCount - 1
while layerCount >= 1:
'''当前层'''
currentLayer = self.layers[layerCount - 1]
'''更新权重'''
currentLayer.updateWeight(preLayer.errors, self.studyRate)
if layerCount != 1:
currentLayer.culateLayerError(preLayer.errors)
layerCount = layerCount - 1
preLayer = currentLayer
'''
创建层
'''
class Layer:
def __init__(self):
self.b = 0
'''使用正态分布的随机值初始化w的值'''
def initW(self, numOfAlpha, nextLayNumOfAlpha):
self.w = np.mat(np.random.randn(nextLayNumOfAlpha, numOfAlpha))
'''计算当前层的alphas'''
def caculateAlphas(self):
'''alpha = f(z)'''
self.alphas = np.mat([tanh(self.zValues[row1,0]) for row1 in range(len(self.zValues))])
'''求f'(z)的值(即f的导数值)'''
self.zDerValues = np.mat([tanhDer(self.zValues[row1,0]) for row1 in range(len(self.zValues))])
'''计算out puts'''
def caculateOutPutValues(self):
'''计算当前层z = w * alpha的的下一层的输入值'''
self.outPutValues = self.w * self.alphas.T + self.b
'''计算输出层的残差'''
def caculateOutPutLayerError(self):
self.errors = np.multiply(-(self.label - self.alphas), self.zDerValues)
print("out put layer alphas ..." + str(self.alphas))
'''计算其它层的残差'''
def culateLayerError(self, preErrors):
self.errors = np.mat([(self.w[:,column].T * preErrors.T * self.zDerValues[:,column])[0,0] for column in range(self.w.shape[1])])
'''更新权重'''
def updateWeight(self, preErrors, studyRate):
data = np.zeros((preErrors.shape[1], self.alphas.shape[1]))
for index in range(preErrors.shape[1]):
data[index,:] = self.alphas * (preErrors[:,index][0,0])
self.w = self.w - studyRate * data
'''
训练神经网络模型
@param train_set: 训练样本
@param labelOfNumbers: 训练总类别
@param layerOfNumber: 神经网络层数,包括输出层,隐藏层和输出层(默认只有一个输入层,隐藏层和输出层)
'''
def train(train_set, label, layerOfNumber = 3, sampleTrainningTime = 5000, studyRate = 0.6):
neuralNetWork = BpNeuralNetWorkModel(train_set, label, layerOfNumber, studyRate)
'''训练数据'''
for row in range(train_set.shape[0]):
'''当个样本使用梯度下降的方法训练sampleTrainningTime次'''
for time in range(sampleTrainningTime):
'''前向传播 '''
neuralNetWork.forward(train_set[row,:])
'''反向传播'''
neuralNetWork.backPropogation()
тестовый код
# -*- coding: utf-8 -*-
'''
Created on 2018��5��27��
@author: Belle
'''
import BpNeuralNetWork
import numpy as np
train_set = np.mat([[0.05, 0.1], [0.3, 0.2]])
labelOfNumbers = np.mat([0.1, 0.99, 0.3])
layerOfNumber = 4
bpNeuralNetWork = BpNeuralNetWork.train(train_set, labelOfNumbers, layerOfNumber)
Ниже приведено выходное значение тестового кода.