最简单的BP神经网络复现1

在这里插入图片描述
在这里插入图片描述

代码

# author:yck
# readme:使用时,请从第77行开始阅读

import numpy as np
class neutral_network(object):
    def __init__(self,nodes_num,learning_rate):
        self.nodes_num = nodes_num   # nodes_num:每层的结点数,最后一层必须为1,第一层符合输入的特征维度
        self.layers = len(nodes_num)     #BP神经网络层数
        self.learning_rate = learning_rate    #学习率
        self.w = []      # weight
        self.grad = []   # 梯度方向
        self.loss_func = "MSE"  #损失函数
        self.node = []   # 记录各结点的值
        for i in range(0,self.layers-1):
            self.w.append(np.random.rand(self.nodes_num[i+1],self.nodes_num[i]+1))   #+1是因为偏置项,也可合并为w
            self.grad.append(np.zeros((self.nodes_num[i+1],self.nodes_num[i]+1)))
            layer_node = [0.0] * self.nodes_num[i]
            layer_node.append(1.0)   #这里多一个1,同样是把偏置项考虑进w中。x就多一个1。
            self.node.append(np.array(layer_node))
        self.node.append(np.array([0.0]))

    def sigmoid(self,x):
        if x >= 0:
            return 1.0 / (1 + np.exp(-x))
        else:
            return np.exp(x) / (np.exp(x) + 1)

    def grad_sigmoid(self,y):   ## sigmoid函数求导
        return y * (1 - y)

    def forward(self,x): # x为一个向量,代表训练数据。x向量长度必须与nodes_num第一维相同
        # 赋值
        for i in range(len(x)):
            self.node[0][i] = x[i]

        # 前向传播
        layer_num = 0
        for layer in self.w:
            layer_num += 1
            for vector_num in range(len(layer)):
                if vector_num < len(layer)-1:
                    self.node[layer_num][vector_num] = self.sigmoid(np.dot(layer[vector_num],self.node[layer_num-1]))
                else:
                    self.node[layer_num][vector_num] = np.dot(layer[vector_num], self.node[layer_num - 1])

    def backwards(self,y):   # y为一个输出,代表真实值
        # 反向传播,做的个别地方可能不一定那么对,也有可能有大问题,欢迎大家指正。
        if self.loss_func == "MSE":
            x_predict = self.node[-1][0]
            xishu = -2 * (y - x_predict)   # 光对损失函数求导
            for i in range (len(self.grad)-1,-1,-1):
                if i == len(self.grad)-1:  # 最后一层不做激活
                    self.grad[i] = xishu * self.node[i]
                elif i ==len(self.grad)-2:   #倒数第二层
                    self.grad[i] = xishu * self.w[i+1] * np.array([self.grad_sigmoid(self.node[i+1])])
                else:   # 前面的层
                    w_new = self.w[i+1] * np.array([self.grad_sigmoid(self.node[i+1])])
                    w_new = np.concatenate((self.w[i+1],np.array([[0] * w_new.shape[1]])),axis=0)  # 有具体解释
                    self.grad[i] = np.matmul(self.grad[i+1],w_new)    # 链式法则
            for i in range(0,len(self.grad)-1):
                self.grad[i] = np.matmul(self.grad[i].T,np.array([self.node[i]]))   #乘小尾巴X


        #展示梯度
        for i in range(len(self.grad)):
            if i < len(self.grad)-1 :
                self.grad[i] = self.grad[i][:-1]
                self.w[i] = self.w[i] - self.learning_rate * self.grad[i]
            else:
                self.w[i] = self.w[i] - self.learning_rate * self.grad[i]

        print("已更新权重为:")
        print(self.w)


# 使用说明:
# nodes_num:从输入层到输出层依次的结点数,因为这个代码是预测,最后一个一定是1。第一个必须和输入的特征x的长度相匹配。
# 比如下例子中,x的长度为5,这个nodes_num第一个数也得是5。
# 当前仅拟合一组数据
n = neutral_network(nodes_num=[5,2,1],learning_rate=0.05)
x = [0.1,0.2,0.3,0.4,0.5]
y = 3   #真实值

train_epoch = 20   #训练轮数
n.forward(x)
for i in range(train_epoch):
    print("---------------------------------------------")
    print("第{}次训练开始".format(i))
    n.backwards(y)
    n.forward(x)
    print("当前预测值为 :{},    真实值为 :{}".format(n.node[-1][0],y))

在这里插入图片描述

测试:

在这里插入图片描述

在这里插入图片描述

**

这个是个笨办法,我感觉也不一定对。请各位指正。

**

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值