BP神经网络 鸢尾花分类 Python 随机梯度下降法 Adagrad(自适应梯度下降法) dropout优化算法

这里用我自己的语言来讲解鸢尾花分类的三种算法,基础的是随机梯度下降法,第二部分用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算法优化后前期轮次的过拟合问题得到了较好的改善,但是误差波动趋势较为明显。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值