1、参考
1、https://blog.csdn.net/qq_45769063/article/details/106747656?utm_medium=distribute.pc_relevant_download.none-task-blog-baidujs-1.nonecase&depth_1-utm_source=distribute.pc_relevant_download.none-task-blog-baidujs-1.nonecase
2、https://blog.csdn.net/qq_41398808/article/details/90904934
2、说明
- 这里实现的神经元模型为单层前馈性神经网络,激活函数使用的是对数几率函数;
- 优化目标函数为均方误差函数Ek,使用梯度下降法求解最优值,推导后的迭代公式如下图:(共四个:输出结点阈值,隐层与输出层权重,隐层结点阈值,输入层与隐层权重)
- 这里输入结点是1 × \times × x矩阵(列向量), 输入结点到隐层结点的权重矩阵为 x × \times × y , 所以是输入矩阵右乘权重矩阵,输出部分同理;
- 梯度下降法计算出的迭代公式对应的代码形式如下:
- 神经网络权值的初始化问题:不能初始化为0,要求关于0对称取值,取值范围大小随机(不同大小效果不一样),推荐使用HeInitialization 初试法,或者初始化0-1之间,-0.5,然后乘10或乘3或除10或除3等,多尝试一下取较好值;
参考:https://zhuanlan.zhihu.com/p/39076763
- 二分类,输出结点1个即可,取值(0-1)之间,大于0.5取1,小于0.5取0,多分类,则设置多个输出结点,输出结点的最大值作为预测值;
3、Code
import numpy as np
def loaddataset(filename):
'''加载数据'''
fp = open(filename)
#存放数据
dataset = []
#存放标签
labelset = []
for i in fp.readlines():
a = i.strip().split() #移除字符串首尾字符并进行分割
#每个数据行的最后一行是标签 dataset 的每个元素是一行数组
dataset.append([float(j) for j in a[:len(a)-1]])
labelset.append(int(float(a[-1])))
return dataset,labelset
#x为输入神经元个数,y为隐层神经元个数,z为输出层神经元个数
def parameter_initiallization(x,y,z):
#隐层阈值
value1 = np.random.randint(-5,5,(1,y)).astype(np.float64)
#输出层阈值
value2 = np.random.randint(-5,5,(1,z)).astype(np.float64)
#输入层与隐层连接权重
weight1 = np.random.randint(-5,5,(x,y)).astype(np.float64)
#隐层与输出层连接权重
weight2 = np.random.randint(-5,5,(y,z)).astype(np.float64)
return value1,value2,weight1,weight2
def sigmoid(z):
'''对数几率函数'''
return 1 / (1 + np.exp(-z))
def trainning(dataset,labelset,weight1, weight2,value1,value2):
'''神经网络训练'''
# x为步长(学习率)
x = 0.01
for i in range(len(dataset)):
#输入数据,将数据转换为矩阵形式
inputset = np.mat(dataset[i]).astype(np.float64)
#数据标签
outputset = np.mat(labelset[i]).astype(np.float64)
#隐层输入(矩阵乘法)
input1 = np.dot(inputset,weight1).astype(np.float64)
#隐层输出
output2 = sigmoid(input1-value1).astype(np.float64)
#输出层输入(矩阵乘法)
input2 = np.dot(output2,weight2).astype(np.float64)
#输出层输出
output3 = sigmoid(input2-value2).astype(np.float64)
#更新公式(参考西瓜书给出的公式)
tmp1 = np.multiply(output3,1-output3)
g = np.multiply(tmp1,outputset-output3)
tmp2 = np.multiply(output2,1-output2)
tmp3 = np.multiply(g,np.transpose(weight2))
e = np.multiply(tmp2,tmp3)
#隐层阈值更新值
value1_change = -x * e
#输出层阈值更新值
value2_change = -x * g
#隐层权重更新值
weight1_change = x * np.dot(np.transpose(inputset),e)
#输出层权重更新值
weight2_change = x * np.dot(np.transpose(output2),g)
#更新参数
value1 += value1_change
value2 += value2_change
weight1 += weight1_change
weight2 += weight2_change
#将训练后参数返回
return weight1,weight2,value1,value2
def testing(dataset,labelset,weight1,weight2,value1,value2):
#记录预测正确的个数
rightcount = 0
#使用训练后的参数进行判断
for i in range(len(dataset)):
inputset = np.mat(dataset[i]).astype(np.float64)
outputset = np.mat(labelset[i]).astype(np.float64)
#隐层输入
input1 = np.dot(inputset,weight1)
#隐层输出
output1 = sigmoid(input1 - value1)
#输出层输入
input2 = np.dot(output1,weight2)
#输出层输出
output2 = sigmoid(input2-value2)
if output2 > 0.5:
flag = 1
else:
flag = 0
if(labelset[i] == flag):
rightcount += 1
#输出预测结果
print("预测为%d 实际为%d"%(flag, labelset[i]))
#正确率
return rightcount/len(dataset)
if __name__ == "__main__":
#加载训练数据
dataset,labelset = loaddataset('./datasets/horseColicTraining.txt')
value1,value2,weight1,weight2 = parameter_initiallization(len(dataset[0]),len(dataset[0]),1)
#迭代次数为1500次,次数越大,准确性一般越高
for i in range(1500):
#循环迭代更新
weight1,weight2,value1,value2 = trainning(dataset,labelset,weight1,weight2,value1,value2)
rate = testing(dataset,labelset,weight1,weight2,value1,value2)
print('正确率:%f'%(rate))
运行结果
取不同初值,迭代重复训练一定次数后的结果: