这里用我自己的语言来讲解鸢尾花分类的三种算法,基础的是随机梯度下降法,第二部分用Adagrad(自适应梯度下降法)来替代随机梯度下降法进行优化,第三部分在基础代码上增加dropout算法来优化模型。

其中Adagrad(自适应梯度下降法)和dropout算法的原理需要大家自己去了解,了解了之后再看我的代码就可以很快地理解了!

目录

原理

选择 AdaGrad  (自适应梯度下降)  优化程序

选择 dropout 算法优化程序

原理

通过构建BP神经网络来实现鸢尾花数据的分类。

传入一组数据,经过神经元加权运算后得到下一个神经元的值,如此计算,最终输出一个分类结果。

BP神经网络的构建分为几个部分,首先要确定神经元层数和个数,再为神经元及其之间的链接赋予参数和算法,最后设计一套参数更新流程用来优化神经网络的效能。

具体原理和设置如下:

先确定神经元层数和个数。这里我选择构建四层的神经网络,第一层为输入层,第二层和第三层都为中间层,第四层为输出层。

因为鸢尾花数据中每朵花有四个特征属性,最后只有三种分类结果,所以我设置输入层为四个神经元(每类特征属性都能参与计算),输出层为三个神经元(分别对应三个类别的概率大小),两个中间层根据经验确定为二十五个神经元。

将不同层神经元进行全链接,中间的链接即为权重w,除了输入层,其它层神经元都赋予一个偏置b以及激活函数f,另外给最后输出结果一个评判误差的损失函数。

权重w和偏置b通过随机数生成,中间层激活函数设置为relu函数,输出层激活函数设置为softmax函数(用来分类),损失函数设置为交叉熵误差(因为分类时用到了独热编码,因此适合用交叉熵误差)。

参数更新的方法设置为随机梯度下降法。即通过反向传播计算不同参数的梯度,再用梯度进行参数的优化。

代码如下:

#训练集:鸢尾花150*50%

#网络结构:输入层(4)+中间层(25)+中间层(25)+输出层(3)

#中间层激活函数:relu,输出层激活函数:softmax

#损失函数:交叉熵误差

#随机梯度下降

import numpy as np

import matplotlib.pyplot as plt

from sklearn import datasets

#鸢尾花数据读入

iris_data=datasets.load_iris()

input_data=iris_data.data

correct=iris_data.target

n_data=len(correct)

#对数据进行预处理

#标准化

ave_input=np.average(input_data,axis=0)

std_input=np.std(input_data,axis=0)

input_data=(input_data-ave_input)/std_input

print(input_data)

#标签转化为独热编码

correct_data=np.zeros((n_data,3))

for i in range(n_data):

correct_data[i,correct[i]]=1.0

print(correct_data)

#切分训练集和测试集

index=np.arange(n_data)

index_train=index[index%2==0]

index_test=index[index%2!=0]

input_train=input_data[index_train,:]

input_test=input_data[index_test,:]

correct_train=correct_data[index_train,:]

corre_test=correct_data[index_test,:]

n_train=input_train.shape[0]

n_test=input_test.shape[0]

#设置参数

n_in=4

n_mid=10

n_out=3

wb_width=0.1

eta=0.1

epoch=100

batch_size=8

interval=100

#实现网络层

class Baselayer:

def __init__(self,n_upper,n):

self.w=wb_width*np.random.randn(n_upper,n)

self.b=wb_width*np.random.randn(n)

def updata(self,eta):

self.w=self.w-eta*self.grad_w

self.b=self.b-eta*self.grad_b

class MiddleLayer(Baselayer):

def forward(self, x):

self.x=x

self.u=np.dot(x,self.w)+self.b

self.y=np.where(self.u<=0,0,self.u)#relu函数

def backward(self, grad_y):

delta = grad_y*np.where(self.u<=0,0,1.0)#relu函数的求导--!!

self.grad_w = np.dot(self.x.T, delta)

self.grad_b = np.sum(delta, axis=0)

self.grad_x = np.dot(delta, self.w.T)

class OutputLayer(Baselayer):

def forward(self,x):

self.x=x

u=np.dot(x,self.w)+self.b

self.y=np.exp(u)/np.sum(np.exp(u),axis=1,keepdims=True)#SoftMax函数

def backward(self,t):

delta=self.y-t

self.grad_w=np.dot(self.x.T,delta)

self.grad_b=np.sum(delta,axis=0)

self.grad_x=np.dot(delta,self.w.T)

#实例化

middle_layer_1=MiddleLayer(n_in,n_mid)

middle_layer_2=MiddleLayer(n_mid,n_mid)

output_layer=OutputLayer(n_mid,n_out)

#定义函数

def forward_propagation(x):

middle_layer_1.forward(x)

middle_layer_2.forward(middle_layer_1.y)

output_layer.forward(middle_layer_2.y)

def back_propagation(t):

output_layer.backward(t)

middle_layer_2.backward(output_layer.grad_x)

middle_layer_1.backward(middle_layer_2.grad_x)

def update_wb():

middle_layer_1.updata(eta)

middle_layer_2.updata(eta)

output_layer.updata(eta)

def get_error(t,batch_size):

return -np.sum(t*np.log(output_layer.y+1e-7))/batch_size

train_error_x=[]

train_error_y=[]

test_error_x=[]

test_error_y=[]

#学习过程

n_batch=n_train//batch_size

for i in range(epoch):

#统计误差

forward_propagation(input_train)

error_train=get_error(correct_train,n_train)

forward_propagation(input_test)

error_test=get_error(corre_test,n_test)

train_error_x.append(i)

train_error_y.append(error_train)

test_error_x.append(i)

test_error_y.append(error_test)

index_random=np.arange(n_train)

np.random.shuffle(index_random)

for j in range(n_batch):

mb_index=index_random[j*batch_size:(j+1)*batch_size]

x=input_train[mb_index,:]

t=correct_train[mb_index,:]

forward_propagation(x)

back_propagation(t)

update_wb()

plt.plot(train_error_x,train_error_y,label="Train")

plt.plot(test_error_x,test_error_y,label="Test")

plt.legend()

plt.xlabel("epoch")

plt.ylabel("error")

plt.show()

首先我设置的层数为四层,输入层为四个神经元,两个中间层都为二十五个神经元,输出层为三个神经元。学习率为0.1,权重和偏置的缩放为0.01。

最后运行,输出的不同优化轮次的误差结果图像为:

 

可以看到优化20轮时训练集和测试集误差已经较低但趋势不完全一致,进行到30轮左右时训练集和测试集的结果误差趋势已经非常吻合接近。

选择 AdaGrad  (自适应梯度下降)  优化程序

更改代码如图:

自适应梯度下降法需要更改参数更新函数,我加了两个中间变量,并且优化了更新算法。

运行结果如下:

 

可以看到40轮左右之前过拟合现象明显且误差较大,60轮之后误差明显降低且模型训练效果较好。

选择 dropout 算法优化程序

我在中间层使用dropout算法,加了三行代码,引入了mask和rate参数,通过运算将每个计算完成的u赋予一个权重,可能为0可能为1-rate。这里我设定的rate为0.5。

运行结果如下:

 

可以看到使用dropout算法优化后前期轮次的过拟合问题得到了较好的改善,但是误差波动趋势较为明显。

相关文章

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。