mypro334 发表于 2022-12-31 12:55

BP神经网络(Adagrad与Dropout优化算法)

架构:构建具有 2 个中间层的 3 分类的 BP 神经网络.
原模型效果(数据集选用鸢尾花数据集)



原神经网络模型

原模型代码:
import numpy as np
import tensorflow as tf
from sklearn import datasets
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split


iris_data=datasets.load_iris()
#数据划分
data=iris_data.data
label=iris_data.target
#z分数标准化
avg=np.average(data,axis=0)
std=np.std(data,axis=0)
data=(data-avg)/std
#转换独热编码
label=tf.keras.utils.to_categorical(label,3)
#切分train和dev
train_data,dev_data,train_label,dev_label=train_test_split(data,label,train_size=0.8)
#params
#输入维度
n_in=4
#中间层神经元个数
n_mid=25
#输出维度
n_out=3
#w和b的扩散程度
wb_width=0.1
#学习率
eta=0.01
#训练次数
epoch=100
#一次训练个数
batch_size=8


class Baselayer:
    def __init__(self,n_upper,n):
      #随机产生w的初始值
      self.w=wb_width*np.random.randn(n_upper,n)
      # 随机产生b的初始值
      self.b=wb_width*np.random.randn(n)
    def updata(self,eta):
      # 根据学习率更新w
      self.w-=eta*self.grad_w
      # 根据学习率更新b
      self.b-=eta*self.grad_b

#Baselayer为父类,MiddleLayer为子类(中间层)
class MiddleLayer (Baselayer):
    #定义前项传播算法
    def forward(self,x):
      self.x=x
      #结合权重和b计算函数值
      self.u=np.dot(x,self.w)+self.b
      #relu函数激活层,小于0=0,否则返回本身
      self.y=np.where(self.u<=0,0,self.u)
    #定义反向传播算法
    def backward(self,grad_y):
      #relu函数导数,根据正向传播结果计算梯度
      delta=grad_y*np.where(self.u<=0,0,1)
      #计算新的w
      self.grad_w=np.dot(self.x.T,delta)
      #计算新的b
      self.grad_b = np.sum(delta,axis=0)
      #计算新的x
      self.grad_x=np.dot(delta,self.w.T)

#Baselayer为父类,OutputLayer为子类(输出层)
#输出层与中间层情况一样,不在做过多的解释(最后换为SoftMax函数)
class OutputLayer (Baselayer):
    def forward(self,x):
      self.x=x
      u=np.dot(x,self.w)+self.b
      #SoftMax函数
      self.y=np.exp(u)/np.sum(np.exp(u),axis=1,keepdims=True)
    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)

#输入层,输入四维张量数据,神经元个数为25个
middle_layer1=MiddleLayer(n_in,n_mid)
#第一层神经元个数为25个,所以第二层输入也为25个,神经元个数为25个
middle_layer2=MiddleLayer(n_mid,n_mid)
#第二层输入也为25个,神经元个数为25个
middle_layer3=MiddleLayer(n_mid,n_mid)
#输出层,第三层神经元个数为25个,输出为三维张量数据。
output_layer=OutputLayer(n_mid,n_out)

#集合函数把类定义的函数改为模型可接受的数据形式
#前向传播
def forward_propagation(x):
    #第一层数据传入
    middle_layer1.forward(x)
    #第一层结果传入第二层
    middle_layer2.forward(middle_layer1.y)
    #第二层结果传到第三层
    middle_layer3.forward(middle_layer2.y)
    #第三层结果传到输出层
    output_layer.forward(middle_layer3.y)

#反向传播
def back_propagation(t):
    #从后往前,链式法则更新梯度
    output_layer.backward(t)
    middle_layer3.backward(output_layer.grad_x)
    middle_layer2.backward(middle_layer3.grad_x)
    middle_layer1.backward(middle_layer2.grad_x)

#数据更新
def updata_wb():
    #依据学习率更新第一层的w和b
    middle_layer1.updata(eta)
    #依据学习率更新第二层的w和b
    middle_layer2.updata(eta)
    #依据学习率更新第三层的w和b
    middle_layer3.updata(eta)
    # 依据学习率更新最后一层的w和b
    output_layer.updata(eta)

#交叉熵计算loss
def get_erro(t,batch_size):
    #信息量公式   I(x)=-log(P(x))
    #交叉熵公式H(p,q)= ∑ p(x i )log(q(x i ))
    return - np.sum(t*np.log(output_layer.y+1e-7))/batch_size

#建立数据收集列表
train_error_data=[]
train_error_label=[]
dev_error_data=[]
dev_error_label=[]

#学习
#查看学习组数
batch=train_data.shape//batch_size

#统计误差
for i in range(epoch):
    #train
    #调用向前传播算法函数
    forward_propagation(train_data)
    #计算交叉熵的loss
    error_train=get_erro(train_label,train_data.shape)
    #记录到数据收集列表
    train_error_data.append(i)
    train_error_label.append(error_train)
    #test
    # 调用向前传播算法函数
    forward_propagation(dev_data)
    # 计算交叉熵的loss
    error_test = get_erro(dev_label, dev_data.shape)
    # 记录到数据收集列表
    dev_error_data.append(i)
    dev_error_label.append(error_test)
    #取索引
    index_random=np.arange(train_data.shape)
    #打乱索引
    np.rndom.shuffle(index_random)
    #
    for j in range(batch):
      #选取batch中的一组,每组随机8个数据
      mb_index=index_random
      #根据索引切出数据
      x=train_data
      #根据索引切出标签
      t=train_label
      #调用向前传播
      forward_propagation(x)
      #调用向后传播
      back_propagation(t)
      #更新数据
      updata_wb()

plt.plot(train_error_data, train_error_label, label="Train")
plt.plot(dev_error_data,dev_error_label,label="Test")
plt.legend()
plt.xlabel("epoch")
plt.ylabel("error")
plt.show()
#准确率
#调用向前传播算法
#train
forward_propagation(train_data)
#取最大预测值的概率索引与正确标签,如果相等则加一做和
count_train=np.sum(np.argmax(output_layer.y,axis=1)==np.argmax(train_label,axis=1))
#dev
forward_propagation(dev_data)
#取最大预测值的概率索引与正确标签,如果相等则加一做和
count_dev=np.sum(np.argmax(output_layer.y,axis=1)==np.argmax(dev_label,axis=1))
print('训练集准确率')
print(count_train/train_data.shape)
print('验证集准确率')
print(count_dev/dev_data.shape)一、分析不同优化算法对神经网络结果的影响.(以下代码为片段的更改请大家注意)
1.AdaGrad优化



加入AdaGrad优化

       AdaGrad优化,是基于梯度进行保留。设置b的值为,积累量初始设置为r=0。之后对积累历史梯度求平方和。之后通过公式对梯度进行运算。



AdaGrad原理

AdaGrad优化部分:
    def updata(self,eta):
      #adagrad
      b=1e-10
      r=0
      i=0
      #累积历史梯度的平方和
      r=r+self.grad_w**2
      i=i+self.grad_b**2
      #更新参数
      self.w-=eta/(np.sqrt(r+b))*self.grad_w
      self.b-=eta/(np.sqrt(i+b))*self.grad_b2.Dropout优化



加入Dropout优化

       简单的说就是,随机抛弃一定中间层神经元的数量,共两种方法实现,一个是针对数据集进行随机抛弃,还有一个是根据神经元的个数进行随机抛弃。
方法一:数集改变
    def forward(self,x):
      self.x=x
      self.u=np.dot(x,self.w)+self.b
      #drop函数
      mask=np.random.binomial(1,1-rate,self.u.shape)
      self.u*=mask
      self.u=self.u/(1-rate)
      self.y=np.where(self.u<=0,0,self.u)

方法二:神经元个数的更改
class MiddleLayer (Baselayer):
    def forward(self,x):
      self.x=x
      self.u=(np.dot(x,self.w)+self.b)*discard_prob
      self.y=np.where(self.u<=0,0,self.u)
.......
def dropout (n_mid,discard_prob):
    # Dropout算法
    # 每个神经元被丢弃的概率
    #discard_prob = 0.5
    # 计算时还成retain_prob
    retain_prob = 1 - discard_prob
    # np.random.binomial这个函数是用来计算一个随机变量X,每个神经元判断
    # 一次,size是有多少神经元生成0,1向量,0表示屏蔽。
    sample = np.random.binomial(n=1, p=retain_prob, size=n_mid)
    sum=sample.sum()
    return sum

n_mid_1=dropout(25,discard_prob)
n_mid_2=dropout(25,discard_prob)
n_mid_3=dropout(25,discard_prob)

middle_layer1=MiddleLayer(n_in,n_mid_1)
middle_layer2=MiddleLayer(n_mid_1,n_mid_2)
middle_layer3=MiddleLayer(n_mid_2,n_mid_3)
output_layer=OutputLayer(n_mid_3,n_out)
页: [1]
查看完整版本: BP神经网络(Adagrad与Dropout优化算法)