bp的算法的推导:
神经网络代码如下:
import numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split
iris = datasets.load_iris()
train_data, test_data, train_label, test_label = train_test_split(iris.data, iris.target, test_size=0.2,random_state=0)
train_label = train_label.reshape(120,1)
'''
搭建神经网络
输入有四个特征
第一层设置20个神经元
第二层设置10个神经元
输出有3个
'''
#初始化权值 -1 到 1
V = np.random.random((4,20))*2-1 #输入到第一层
W = np.random.random((20,10))*2-1
K = np.random.random((10,1))*2-1 #第二层到输出(train_label 数值为0 1 2,通过输出预测)
#定义一些参数
loop = 500 #最大迭代轮数
l = 0.001 #学习率
#激函数
def sigmoid(x):
return 1/(1+np.exp(-x))
#更新
def update():
global loop
global train_data, train_label, V, W, K
#前向传播过程
y1 = sigmoid(np.dot(train_data,V))
y2 = sigmoid(np.dot(y1,W))
o = sigmoid(np.dot(y2,K))
#误差反向传播过程
'''
下面这个是数组的乘法:
矩阵的乘法和加法
矩阵的乘法和加法和线性代数的矩阵加法和乘法一致,运算符号也一样用*,**表示平方,例如e**2 =e*e。
数组的加法和乘法
数组的乘法和加法为相应位置的数据乘法和加法。
'''
o_delta = (train_label - o) * o * (1-o)
y2_delta = np.dot(o_delta, K.T) * y2 * (1-y2)
y1_delta = y2_delta.dot(W.T) * y1 * (1-y1)
K = K + l * np.dot(y2.T, o_delta)
W = W + l * np.dot(y1.T, y2_delta)
V = V + l * np.dot(train_data.T, y1_delta)
#迭代
for i in range(0,loop):
update()
if i%100 == 0:
y1 = sigmoid(np.dot(train_data, V))
y2 = sigmoid(np.dot(y1, W))
o = sigmoid(np.dot(y2, K))
print("error:")
print(np.mean(train_label - o.T))
#训练好的模型在训练集上的表现
y1 = sigmoid(np.dot(train_data,V))
y2 = sigmoid(np.dot(y1,W))
o = sigmoid(np.dot(y2,K))
#对输出的o进行处理
for i in range(0,len(o)):
if(o[i] < 0.5):
o[i] = 0
elif(o[i] > 1.5):
o[i] = 2
else:
o[i] = 1
count = 0
sum = 0
for i in range(0,len(o)):
if(o[i] == train_label[i]):
count +=1
sum+=1
print('Accuracy in train dataset %f' % (count/sum))
#训练好的模型在测试集上的表现
y1 = sigmoid(np.dot(test_data,V))
y2 = sigmoid(np.dot(y1,W))
o = sigmoid(np.dot(y2,K))
#对输出的o进行处理
for i in range(0,len(o)):
if(o[i] < 0.5):
o[i] = 0
elif(o[i] > 1.5):
o[i] = 2
else:
o[i] = 1
count = 0
sum = 0
for i in range(0,len(o)):
if(o[i] == test_label[i]):
count +=1
sum += 1
print("Accuracy in test dataset %f" % (count/sum))
结果为:
可以看到,准确率很低,这时候需要调整参数,比如学习率,迭代次数,每层神经元或者层数等等。第一层增加到40个神经元,迭代轮数增加到1000
结果为:
比之前好很多,但还是很低,比昨天用sklearn的神经网络低太多了。 后来想了想,sigmod函数输出是0-1之间,而鸾尾花数据集的标签是0,1,2,也就是这个模型根本无法预测出2类型的花。所以进行改动,把标签标准化一下,除以二,然后对输出的处理改为<0.4认为是0类被,>0.7认为是1类别。结果很好:
修改后的代码为:
import numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split
iris = datasets.load_iris()
train_data, test_data, train_label, test_label = train_test_split(iris.data, iris.target, test_size=0.2,random_state=0)
train_label = train_label.reshape(120,1)/2 #因为神经网络输出都是0-1,所以给它标准化
test_label = test_label/2
'''
搭建神经网络
输入有四个特征
第一层设置20个神经元
第二层设置10个神经元
输出有3个
'''
#初始化权值 -1 到 1
V = np.random.random((4,40))*2-1 #输入到第一层
W = np.random.random((40,10))*2-1
K = np.random.random((10,1))*2-1 #第二层到输出(train_label 数值为0 1 2,通过输出预测)
#定义一些参数
loop = 3000 #最大迭代轮数
l = 0.001 #学习率
#激函数
def sigmoid(x):
return 1/(1+np.exp(-x))
#更新
def update():
global loop
global train_data, train_label, V, W, K
#前向传播过程
y1 = sigmoid(np.dot(train_data,V))
y2 = sigmoid(np.dot(y1,W))
o = sigmoid(np.dot(y2,K))
#误差反向传播过程
'''
下面这个是数组的乘法:
矩阵的乘法和加法
矩阵的乘法和加法和线性代数的矩阵加法和乘法一致,运算符号也一样用*,**表示平方,例如e**2 =e*e。
数组的加法和乘法
数组的乘法和加法为相应位置的数据乘法和加法。
'''
o_delta = (train_label - o) * o * (1-o)
y2_delta = np.dot(o_delta, K.T) * y2 * (1-y2)
y1_delta = y2_delta.dot(W.T) * y1 * (1-y1)
K = K + l * np.dot(y2.T, o_delta)
W = W + l * np.dot(y1.T, y2_delta)
V = V + l * np.dot(train_data.T, y1_delta)
#迭代
for i in range(0,loop):
update()
if i%100 == 0:
y1 = sigmoid(np.dot(train_data, V))
y2 = sigmoid(np.dot(y1, W))
o = sigmoid(np.dot(y2, K))
print("error:")
print(np.mean(train_label - o.T))
#训练好的模型在训练集上的表现
y1 = sigmoid(np.dot(train_data,V))
y2 = sigmoid(np.dot(y1,W))
o = sigmoid(np.dot(y2,K))
#对输出的o进行处理
for i in range(0,len(o)):
if(o[i] < 0.4):
o[i] = 0
elif(o[i] > 0.7):
o[i] = 1
else:
o[i] = 0.5
count = 0
sum = 0
for i in range(0,len(o)):
if(o[i] == train_label[i]):
count +=1
sum+=1
print('Accuracy in train dataset %f' % (count/sum))
#训练好的模型在测试集上的表现
y1 = sigmoid(np.dot(test_data,V))
y2 = sigmoid(np.dot(y1,W))
o = sigmoid(np.dot(y2,K))
#对输出的o进行处理
for i in range(0,len(o)):
if(o[i] < 0.4):
o[i] = 0
elif(o[i] > 0.7):
o[i] = 1
else:
o[i] = 0.5
count = 0
sum = 0
for i in range(0,len(o)):
if(o[i] == test_label[i]):
count +=1
sum += 1
print("Accuracy in test dataset %f" % (count/sum))