楼下的蓝鸢尾花 和 它的果实
映射关系:
train 120条数据,4个特征值 |
W1
| arrY1 隐藏层为10层 |
W2 |
arrY2 每一条数据,有3种输出结果 |
测试数据,输入层 | 权重 | 隐藏层 | 权重 | 输出层 |
输入层到隐藏层:
隐藏层到输出层:
损失函数
trainL为测试集的真实标签,是预测的标签
对w1,w2进行更新,使用批量梯度下降,梯度即偏导数,需要根据损失函数对其分别求偏导
更新,学习率是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