一,介绍
神经网络有多种,包括:反向传播神经网络(BP神经网络)、径向基函数神经网络(RBF神经网络)、竞争型学习神经网络(ART神经网络)等。
神经网络可以分为三个部分:输入层、隐藏层、输出层。其中隐藏层根据需要可以有多层。
在这里,我们主要介绍BP神经网络,一种最常用的神经网络。其思想是根据输入层数据加上权值进行计算获得输出层结果,再根据输出层结果和实际结果比较,调整权值,直到权值调整到输出结果符合预期后结束训练。
权重调整公式如下:
其中,η为学习速率,Wi为权重,y为实际输出值,为当前权重计算值,Xi为输入值。下面给出一个具体例子,迭代计算权值。
二,实例
假设,有如下神经网络:
i1,i2为输入层,h1,h2为隐藏层,o1,o2为输出层,b1,b2为阈值。激活函数用sigmoid函数。
step1,计算输入层--隐藏层
(1)计算加权输入
net(h1)=w1*i1+w2*i2+b1=0.15*0.05+0.2*0.1+0.35*1=0.3775
(2)用激活函数计算输出
同理,计算out(h2)=0.59688
step2,计算隐藏层--输出层
(1)计算加权输入
net(o1)=w5*out(h1)+w6*out(h2)+b2=0.4*0.59326+0.45*0.59688 +0.6*1=1.1059
(2)用激活函数计算输出
同理,计算out(o2)=0.77292
step3,计算反向传播误差。
step4,更新隐藏层到输出层权值
这里设定学习速率η=0.5
我们更新权值W5为例:
得到更新后的W5=0.35891。其他的权值,更新类似。
step5,更新输入层到隐藏层权值
同理:
获得:
其他权值更新类似
三,python实现神经网络
确定隐藏层节点数,经验公式如下:
数据如下:
1,青绿,蜷缩,浊响,清晰,凹陷,硬滑,是
2,乌黑,蜷缩,沉闷,清晰,凹陷,硬滑,是
3,乌黑,蜷缩,浊响,清晰,凹陷,硬滑,是
4,青绿,蜷缩,沉闷,清晰,凹陷,硬滑,是
5,浅白,蜷缩,浊响,清晰,凹陷,硬滑,是
6,青绿,稍蜷,浊响,清晰,稍凹,软粘,是
7,乌黑,稍蜷,浊响,稍糊,稍凹,软粘,是
8,乌黑,稍蜷,浊响,清晰,稍凹,硬滑,是
9,乌黑,稍蜷,沉闷,稍糊,稍凹,硬滑,否
10,青绿,硬挺,清脆,清晰,平坦,软粘,否
11,浅白,硬挺,清脆,模糊,平坦,硬滑,否
12,浅白,蜷缩,浊响,模糊,平坦,软粘,否
13,青绿,稍蜷,浊响,稍糊,凹陷,硬滑,否
14,浅白,稍蜷,沉闷,稍糊,凹陷,硬滑,否
15,乌黑,稍蜷,浊响,清晰,稍凹,软粘,否
16,浅白,蜷缩,浊响,模糊,平坦,硬滑,否
17,青绿,蜷缩,沉闷,稍糊,稍凹,硬滑,否
为了方便神经网络计算,我们采用独热编码的方式进行编码数据预处理,处理输入如下:
我们尝试采用两种不同的激活函数,sigmoid函数和tanh函数
python代码:
from math import log import numpy as np from random import random import pandas as pd # sigmoid函数 def logistic(x): return 1 / (1 + np.exp(-x)) # sigmoid函数导数 def logistic_derivative(x): return x * (1 - x) # tanh函数 def tanh(x): return np.tanh(x) # tanh函数导数 def tanh_deriv(x): return 1.0 - np.tanh(x) * np.tanh(x) class BPNeuralNetwork: def __init__(self, activation='tanh'): self.input_num = 0 # 输入层节点数 self.hide_num = 0 # 隐藏层节点数 self.output_num = 0 # 输出层节点数 self.input_value = [] # 输入层输出 self.hide_value = [] # 隐藏层输出 self.output_value = [] # 输出层输出 self.inputToHide_w = [] # 输入层到隐藏层权值 self.hideToOutput_w = [] # 隐藏层到输出层权值 self.hide_b = [] # 隐藏层阀值 self.output_b = [] # 输出层阀值 if activation == 'logistic': self.activation = logistic self.activation_deriv = logistic_derivative elif activation == 'tanh': self.activation = tanh self.activation_deriv = tanh_deriv # 读取数据 def createDataSet(self): dataSet=[] fr = open('watermelon.txt') for line in fr.readlines(): lineArr = line.strip().split(',') dataSet.append(lineArr[:]) # 添加数据 labels = ['编号','色泽','根蒂','敲声','纹理','头部','触感','好瓜'] return dataSet, labels # 创建随机数 def rand(self,a, b): return (b - a) * random() + a # 创建BP神经网络 def createBPNN(self, ni, nh, no): self.input_num = ni # 输入层节点数 self.hide_num = nh # 隐藏层节点数 self.output_num = no # 输出层节点数 self.input_value = np.zeros(self.input_num) # 输入层输出 self.hide_value = np.zeros(self.hide_num) # 隐藏层输出 self.output_value = np.zeros(self.output_num) # 输出层输出 self.inputToHide_w = np.zeros([self.input_num, self.hide_num]) # 输入到隐藏层权值矩阵 self.hideToOutput_w = np.zeros([self.hide_num, self.output_num]) # 隐藏到输出层权值矩阵 for i in range(self.input_num): for h in range(self.hide_num): self.inputToHide_w[i][h] = self.rand(0, 1) # 随机赋值 for h in range(self.hide_num): for j in range(self.output_num): self.hideToOutput_w[h][j] = self.rand(0, 1) # 随机赋值 self.hide_b = np.zeros(self.hide_num) # 创建隐藏层阀值矩阵 self.output_b = np.zeros(self.output_num) # 创建输出层阀值矩阵 for h in range(self.hide_num): self.hide_b[h] = self.rand(0, 1) # 初始化隐藏层阀值矩阵 for j in range(self.output_num): self.output_b[j] = self.rand(0, 1) # 初始化输出层阀值矩阵 # 计算隐藏层和输出层的输出值 def Pred(self, x): for i in range(self.input_num): self.input_value[i] = x[i] # 输入层赋值 for h in range(self.hide_num): total = 0.0 for i in range(self.input_num): total += self.input_value[i] * self.inputToHide_w[i][h] # 计算net(h) self.hide_value[h] = self.activation(total - self.hide_b[h]) # 计算out(h) for j in range(self.output_num): total = 0.0 for h in range(self.hide_num): total += self.hide_value[h] * self.hideToOutput_w[h][j] # 计算net(o) self.output_value[j] = self.activation(total - self.output_b[j]) # 计算out(o) # 反向传播更新权值 def BackPropagate(self, data_in, data_out, lr, epochs=10000): for k in range(epochs): i = np.random.randint(len(data_in)) x = data_in[i] y = data_out[i] self.Pred(x) output_grid = np.zeros(self.output_num) for j in range(self.output_num): output_grid[j] = (y[j] - self.output_value[j]) * self.activation_deriv(self.output_value[j]) # output_grid[j] = (y[j] - self.output_value[j]) * self.output_value[j] * (1 - self.output_value[j]) # 计算 (эE/эout(o))*(эout(o)/эnet(o)) hide_grid = np.zeros(self.hide_num) for h in range(self.hide_num): for j in range(self.output_num): hide_grid[h] += self.hideToOutput_w[h][j] * output_grid[j] hide_grid[h] = hide_grid[h] * self.activation_deriv(self.hide_value[h]) # hide_grid[h] = hide_grid[h] * self.hide_value[h] * (1 - self.hide_value[h]) # 计算输入层到隐藏层ΔW=-η*ΔE=-η*(out(h)-h)*out(h)*(1-out(h))*out(i) for h in range(self.hide_num): for j in range(self.output_num): self.hideToOutput_w[h][j] += lr * output_grid[j] * self.hide_value[h] # 更新隐藏层到输出层的权值 w+η*(эE/эout(o))*(эout(o)/эnet(o))*w for i in range(self.input_num): for h in range(self.hide_num): self.inputToHide_w[i][h] += lr * hide_grid[h] * self.input_value[i] # 更新输入层到隐藏层权值 w+η*( for j in range(self.output_num): self.output_b[j] -= lr * output_grid[j] # 更新输出层阀值 for h in range(self.hide_num): self.hide_b[h] -= lr * hide_grid[h] # 更新隐藏层阀值 # 训练神经网络 def TrainStandard(self, data_in, data_out, lr=0.5): e_k = np.zeros([len(data_in),self.output_num]) self.BackPropagate(data_in, data_out, lr) error = np.zeros(self.output_num) for k in range(len(data_in)): self.Pred(data_in[k]) y=data_out[k] for j in range(self.output_num): error[j]=(self.output_value[j] - y[j]) e_k[k] = error # 训练总误差 return e_k if __name__ == '__main__': Bpnn = BPNeuralNetwork('logistic') # 选择激活函数logistic或tanh myData,label = Bpnn.createDataSet() # 读取数据 df = pd.DataFrame(x[1:8] for x in myData) df.columns = label[1:8] dataProcessing = pd.get_dummies(df) dataIn = dataProcessing.iloc[:,0:17].values.tolist() # 输入 dataOut = dataProcessing.iloc[:,17:19].values.tolist() # 输出 Bpnn.createBPNN(17,6,2) e_k = Bpnn.TrainStandard(dataIn,dataOut) print(e_k) 当使用学习速率为0.5,logistic作为激活函数,训练1W次的时候,获得以下结果:
当使用学习速率为0.5,tanh作为激活函数,训练1W次的时候,获得以下结果: