python实现BP神经网络以及一阶优化
本博客神经网络的实现参考这位 博主的博客,记录我在使用这个神经网络时遇到的坑。为了解决这些问题而进行的一点优化。程序难免存在瑕疵,仅供参考,欢迎斧正。
1.神经网络原理
原理推导内容较多,可参考这篇文章多层神经网络BP算法 原理及推导
2.遇到的坑
2.1.学习效率过慢
神经网络学习本身是需要大量的数据来支撑的,只有学习内容足够多才能提高神经网络的准确率,所以这个坑是没有办法避开的。
这里些这个坑主要是因为在完成神经网络时,一个用c++实现的神经网络学习迭代了5个小时,让我倍受震惊。对我使用python来实现更是艰辛,所以就用了半天时间在网络上寻找解决方法,最后找到了不少的解决方法,我再把这些方法组合了一下。最终发现同样使用ORL人脸数据库,我搭建的神经网络只需要迭代100次即可达到较高的识别效率,泛化误差也比较理想。
2.1.1.自适应学习效率
自适应的学习率想法其实很简单,就是考虑到学习率不好设定,神经网络每一次迭代都有不一样的最佳学习效率,而我们无从得知,也好控制。
如果我们的程序可以在迭代过程中自己为自己调整学习效率就可以去除人去不断尝试学习效率调整的痛苦。而且在自适应的过程中会程序就会自己不断靠近当前的最优学习效率从而达到较好的优化效果。
所以就使用了一下的函数实现自适应的学习效率
def RateAdaptive(eta,k,c):
if k<1:
return 1.02*eta
if k>c:
return 0.98*eta
return eta
2.1.2.冲量项
冲量项是为了在自适应学习效率的过程中带来的过冲的情况。即自适应学习率的变化过大,而自适应的学习效率还未缓过来,学习效率依旧在较高的情况下,使用冲量项比较前后的学习情况确定更优的变化量。
冲量项具体实现就是保存上一次迭代的增量,和本次迭代算出的增量去一个加权平均。可以缓冲前后两次增量反向的情况导致的“白干活”。
2.2.梯度消失
本神经网络隐藏层和输出层均是ReLU激活函数,使用何神的初始化方法正好可以解决这个问题。
3.完整程序及结果
import numpy as np
import cv2 as cv
import time
#在bp神经网络的基础上添加了冲量项,并设置自适应的学习率
#自适应学习率函数
def RateAdaptive(eta,k,c):
if k<1:
return 1.02*eta
if k>c:
return 0.98*eta
return eta
def change(m):
"""把一个数据矩阵变成一行"""
M = []
for i in range(m.shape[1]):
temp = m[:][i]
M=M+list(temp)
return M
def loaddataset(path):
"""读取数据集"""
label = np.zeros((400,40))#标签
train = []#样本矩阵
flag = 0
for i in range(1,41):
for j in range(1,11):
img = cv.imread(path+f"s{
i}\\{
j}.pgm",0)
train.append(change(img))
label[flag,i-1] = 1
flag = flag+1
#二维数组转np数组
X = np.array(train)
return X,label
def mypca(data,n):
"""data:需要降维的矩阵
n取对应特征值最大的特征向量个数
"""
# 计算原始数据中每一列的均值,axis=0按列取均值
mean = np.mean(data, axis=0)
# 数据中心化,使每个feature的均值为0
zeroCentred_data = data - mean
# 计算协方差矩阵,rowvar=False表示数据的每一列代表一个feature
covMat = np.cov(zeroCentred_data, rowvar=False)
# 计算协方差矩阵的特征值和特征向量
featValue, featVec = np.linalg.eig(covMat