BP简介
Bp神经网络的一大特点就是:信号前向计算,误差反向传播。根据这一特点来编写网络
标准BP算法流程
学习完一个样本就计算每层的误差信号并调整权重
批训练BP算法流程
学习完所有样本,根据总误差计算各层的误差信号并调整权重
代码
本文使用多层bp神经网络进行手写数字的识别。采用标准bp算法流程,但训练结束条件为达到训练次数就结束。
class BPNeuralNetwork(object):
def __init__(self,layers,learing_rate,epochs):
self.layers=layers
self.learing_rate=learing_rate
self.epochs=epochs
self.W=self.initW()
@property
def getW(self):
return self.W
@property
def getV(self):
return self.V
def initW(self):
W=[]
for i in range(0,len(self.layers)-1):
#输出层
if(i==len(self.layers)-2):
W.append(np.random.random((self.layers[i]+1,self.layers[i+1]))*2-1)
#隐藏层
else:
W.append(np.random.random((self.layers[i]+1,self.layers[i+1]+1))*2-1)
return W
def sigmoid(self,x):
return 1/(1+np.exp(-x))
def dsigmoid(self,x):
return x*(1-x)
def back_propagete(self,label,outputs):
#反向传播
'''一直没找出原因,最后发现是传入label错误,最开是将所有label传入,然后label[i]-outputs[i].
导致每次的标签都不一样,得不到正确结果'''
deltas=[]
n=len(self.layers)
delta=0
for i in range(n-1,0,-1):
if(i==n-1):
delta=(label-outputs[i])*self.dsigmoid(outputs[i])
else:
delta= delta.dot(self.W[i].T)*self.dsigmoid(outputs[i])
#逆序,插入前面
deltas.insert(0,delta)
for j in range(n-2,-1,-1):
#更新权值
d=self.learing_rate*(outputs[j].T).dot(deltas[j])
self.W[j] += d
def update(self,input_data):
outputs=[]
outputs.append(input_data)
for i in range(0,len(self.layers)-1):
#正向学习
input_data=self.sigmoid(np.dot(input_data,self.W[i]))
outputs.append(input_data)
return outputs
def fit(self,data,label):
#添加偏置
temp = np.ones([data.shape[0],data.shape[1]+1])
temp[:,0:-1] = data
data = temp
for n in range(self.epochs+1):
#随机选取一个数据
i = np.random.randint(data.shape[0])
x = [data[i]]
#转为2维数据
x = np.atleast_2d(x)
outputs=self.update(x)
self.back_propagete(label[i],outputs)
#每训练1000次预测一次准确率
if n%1000==0:
predictions = []
for j in range(X_test.shape[0]):
o = self.predict(X_test[j])
#获取预测结果
predictions.append(np.argmax(o))
accuracy = np.mean(np.equal(predictions,y_test))
print(f'epoch:[',n,f'/ {self.epochs}] accuracy:',accuracy)
def predict(self,x):
#添加偏置
temp = np.ones(x.shape[0]+1)
temp[0:-1] = x
x = temp
x = np.atleast_2d(x)#转为2维数据
for i in range(0,len(self.layers)-1):
x=self.sigmoid(np.dot(x,self.W[i]))
return x
if __name__ =="__main__":
#加载手写数字数据集
digits = load_digits()
X = digits.data
y = digits.target
#输入数据归一化
X -= X.min()
X /= X.max()
#创建网络
nm = BPNeuralNetwork([64,100,10],0.11,20000)
X_train,X_test,y_train,y_test = train_test_split(X,y)
#标签二值化
labels_train = LabelBinarizer().fit_transform(y_train)
#标签二值化
labels_test = LabelBinarizer().fit_transform(y_test)
print('start training')
nm.fit(X_train,labels_train)
print('end')
最终准确率在97%左右
调整学习率、网络层数、训练次数发现:
- 学习率过大 收敛速度快,但是震荡不稳定
- 学习率过小,收敛得慢,同等训练次数,不能达到较好的效果
- 网络层数,确实没看出有什么规律
- 可能是网络自身限制,最多也就准确率97%的样子