鸢尾花BP算法实现 Python

楼下的蓝鸢尾花 和 它的果实

  

映射关系:

120\times 4 

train

120条数据,4个特征值

4\times 10 

W1

 

120\times 10

arrY1

隐藏层为10层

10\times 3 

W2

120\times 3 

arrY2

每一条数据,有3种输出结果

测试数据,输入层权重隐藏层权重输出层

输入层到隐藏层:y_1=x*w_1,arrY_1=sigmoid(y_1)

隐藏层到输出层:y2=arrY2*w_2,arrY_2=sigmoid(y2), sigmoid=\frac{1}{1+e^{-x}}

损失函数Loss(w_1,w_2)=\frac{1}{2}(trainL-arrY_2)^2

trainL为测试集的真实标签,arrY_2是预测的标签

对w1,w2进行更新,使用批量梯度下降,梯度即偏导数,需要根据损失函数对其分别求偏导\frac{\partial Loss(w_1,w_2)}{\partial w_1},\frac{\partial Loss(w_1,w_2)}{\partial w_2}

更新w_1-=studyRate*\frac{\partial Loss(w_1,w_2)}{\partial w_1}, w_2-=studyRate*\frac{\partial Loss(w_1,w_2)}{\partial w_2},学习率是0.9,学习率即步长。

没有设置偏置,如果设置了偏置,对偏置也需要进行更新,类似对权重的更新。

 

# -*- coding: UTF-8 -*-
import numpy as np
from numpy import *#解决引入array is not defined
import math
import random
import csv
import pandas as pd
import datetime
e=2.71828183
#定义隐藏层,输出结果,特征值
h1,re,f=10,3,4
#训练数据120条,测试数据30条
trainNum,testNum=120,30
#学习率0.9
studyRate=0.9
#开始测试
def testBP(testData,testLabel,w1T,w2T):
    y1=np.dot(testData,w1)
    derivativeY1=np.zeros((testNum,h1))
    arrY1,derivativeY1=derivative(y1,derivativeY1)
    y2=np.dot(arrY1,w2)
    derivativeY2=np.zeros((testNum,re))
    arrY2,derivativeY2=derivative(y2,derivativeY2)
    predictResult=[]

    count=0
    predictWrong={}
    for i in range(len(arrY2)):
        listY2=arrY2[i].tolist()
        predictValue=max(listY2)
        result=listY2.index(predictValue)
        predictResult.append (result)
        if(result==testLabel[i]):
            count+=1
        else:#将正确结果、预测错误的结果存入字典中
            predictWrong[i]={"the correct ":testLabel[i],"the predict":result}
    #输出错误预测的个数
    print("the wrong predict numbers are:",testNum-count)
    #返回预测结果,正确率,和预测错误的数据的字典
    return predictResult,(count+0.0)/testNum,predictWrong
#对列表中的每个元素求sigmoid(),和求出其导数,sigmoid()的导数为自身*(1-自身),返回sigmoid()和其导数
def derivative(arr,deri):
    for i in range(len(arr)):
        for j in range(len(arr[0])):
             arr[i][j]=sigmoid(arr[i][j])
             deri[i][j]=arr[i][j]*(1-arr[i][j])
    return arr,deri
#开始训练,w1和w2在每次训练后都有更新
def statrTrain(trainData,trainL,w1,w2):
    y1=np.dot(trainData,w1)
    derivativeY1=np.zeros((trainNum,h1))

    arrY1,derivativeY1=derivative(y1,derivativeY1)
    #arrY1作为隐藏层的输入
    y2=np.dot(arrY1,w2)
    derivativeY2=np.zeros((trainNum,re))
    #隐藏层输出,对每个元素求sigmoid()和其导数
    arrY2,derivativeY2=derivative(y2,derivativeY2)
    #以上得到预测的结果arrY2
    #反向传播
    #根据损失函数Loss对w2求导,使用批量梯度下降
    derivativeW2=np.multiply(-(trainL-arrY2)/trainData.shape[1],derivativeY2)

    #根据损失函数Loss对w1求导
    derivativeW1=np.multiply(np.dot(derivativeW2,w2.T),derivativeY1)
    '''不能把w2的更新放在上面的语句上面,我就栽这个地方,调了很久,因为对w1求导时,w2应该还未更新,如果把上面的语句放在求derivativeW1之上,会影响到derivativeW1的求值,因为用到了w2的值,w2的跟新应该放在w1求导之后'''
    #更新w1 w2
    w2-=studyRate*np.dot(arrY1.T,derivativeW2)
    w1-=studyRate*np.dot(trainData.T,derivativeW1)

    loss=1/2.0 *sum(np.multiply(trainL-arrY2,trainL-arrY2))
    #计算损失函数
    return w1,w2,loss
#归一化处理
def regulate(data):
    data=(data-data.min())/(data.max()-data.min())
    return data
def sigmoid(x):
    #return (1.0/(1.0+exp(-x)))#overflow encountered in exp x导致溢出
    return .5 * (1 + np.tanh(.5 * x))
#one hot 编码
def oneHot(lable,num):
    matrixL=[[0.01,0.01,0.01] for i in range(num)]
    #若以上代码为matrixL=[0.01,0.01,0.01]*num,为浅拷贝,每一列的地址相同,那么在后面 matrixL[i][j-1]=0.99中,每一列的值都相同了
    #matrixL=np.zeros(10,4)
    i=0
    for j in lable:

        j=int(j)
        matrixL[i][j]=0.99
        i+=1
    return matrixL

if __name__=='__main__':
    #pandas读取csv文件
    #trainTable=pd.read_table(trainCsv,sep=',')
    trainCsv="F:\ANN\iris_training.csv"
    testCsv="F:\ANN\iris_test.csv"
    trainD=pd.read_csv(trainCsv)
    trainD=array(trainD)
    trainData=trainD[:,0:4]#读取列表的前四列,前四列为鸢尾花的特征值
    trainL=trainD[:,-1]#读取列表的最后一列,最后一列为标签内容

    testD=pd.read_csv(testCsv)
    testD=array(testD)
    testData=testD[:,0:4]
    testL=testD[:,-1]
#随机生成权重
    w1=2*np.random.random((f,h1))-1#生成(-1,1)之间的大小为(f,h1)的随机数列表,使之在y轴左右分布
    w2=2*np.random.random((h1,re))-1
#one hot编码对训练集的标签
    trainLOneHot=oneHot(trainL,len(trainL))

#训练集和测试集数据归一化处理
    train=regulate(trainData)
    test=regulate(testData)
#训练1000次,每次的权重都有更新
    for i in range(1000):
        w1,w2,loss=statrTrain(train,trainLOneHot,w1,w2)
    print("the loss is:",loss)
    predictResult,correctRate,predictWrong=testBP(test,testL,w1,w2)
    print("the correct rate is",correctRate)
    print("the wrong predict:\n",predictWrong)

没有设置偏置,对预测结果影响很小。最后显示第23条数据是预测错误的,正确的结果为1,预测是2。

数据集链接:https://pan.baidu.com/s/13sM2Ui1XKsuOYj5CY8e9UA,提取码:xopc

  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值