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、说明

  1. 这里实现的神经元模型为单层前馈性神经网络,激活函数使用的是对数几率函数;
  2. 优化目标函数为均方误差函数Ek,使用梯度下降法求解最优值,推导后的迭代公式如下图:(共四个:输出结点阈值,隐层与输出层权重,隐层结点阈值,输入层与隐层权重)
  3. 这里输入结点是1 × \times × x矩阵(列向量), 输入结点到隐层结点的权重矩阵为 x × \times × y , 所以是输入矩阵右乘权重矩阵,输出部分同理;
  4. 梯度下降法计算出的迭代公式对应的代码形式如下:
  5. 神经网络权值的初始化问题:不能初始化为0,要求关于0对称取值,取值范围大小随机(不同大小效果不一样),推荐使用HeInitialization 初试法,或者初始化0-1之间,-0.5,然后乘10或乘3或除10或除3等,多尝试一下取较好值;

参考:https://zhuanlan.zhihu.com/p/39076763



  1. 二分类,输出结点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))

运行结果

取不同初值,迭代重复训练一定次数后的结果: