手写bp全连接神经网络(封装类)

234 阅读1分钟

这次把代码封装了下,并加上了一些注释

import numpy as np


class BP:
    def __init__(self, w, b, x, y, lr):
        self.__w = w # 参数θ
        self.__b = b # 偏置项
        self.__x = x # 特征向量
        self.__y = y # label标签
        self.__lr = lr # 学习率

    def w(self, index):
        return self.__w[index - 1]

    def set_w(self, index, gd):
        self.__w[index - 1] = self.__w[index - 1] - self.__lr * gd

    def get_w(self):
        return self.__w

    def b(self, index):
        return self.__b[index - 1]

    def get_b(self):
        return self.__b

    def set_b(self, index, gd):
        self.__b[index - 1] = self.__b[index - 1] - self.__lr * gd

    def x(self, index):
        return self.__x[index - 1]

    def y(self, index):
        return self.__y[index - 1]

    def sigmoid(self, z):
        return 1.0 / (1 + np.exp(-z))

    def training(self):
        # 1. FP前向过程 计算损失
        h1 = self.sigmoid(self.w(1) * self.x(1) + self.w(2) * self.x(2) + self.b(1))
        h2 = self.sigmoid(self.w(3) * self.x(1) + self.w(4) * self.x(2) + self.b(1))
        h3 = self.sigmoid(self.w(5) * self.x(1) + self.w(6) * self.x(2) + self.b(1))
        o1 = self.sigmoid(self.w(7) * h1 + self.w(9) * h2 + self.w(11) * h3 + self.b(2))
        o2 = self.sigmoid(self.w(8) * h1 + self.w(10) * h2 + self.w(12) * h3 + self.b(2))
        loss = 0.5 * (self.y(1) - o1) ** 2 + 0.5 * (self.y(2) - o2) ** 2

        # print(h1, h2, h3)
        # 2. BP反向过程 参数更新
        # 基于求导的链式法则进行loss对w1的梯度求解
        # 梯度的简化写法:loss/w1 = loss/h1 * h1/ w1 = (loss/o1*o1/h1 + loss/o2*o2/h1) * h1/w1
        # loss / w2 = loss / h1 * h1 / w2 = (loss / o1 * o1 / h1 + loss / o2 * o2 / h1) * h1 / w2
        # loss / w3 = loss / h2 * h2 / w3 = (loss / o1 * o1 / h2 + loss / o2 * o2 / h2) * h2 / w3
        t1 = (o1 - self.y(1)) * o1 * (1 - o1)  # loss对net_o1的导数
        t2 = (o2 - self.y(2)) * o2 * (1 - o2)
        self.set_w(7, t1 * h1)
        self.set_w(8, t2 * h1)
        self.set_w(9, t1 * h2)
        self.set_w(10, t2 * h2)
        self.set_w(11, t1 * h3)
        self.set_w(12, t2 * h3)
        self.set_w(1, (t1 * self.w(7) + t2 * self.w(8)) * h1 * (1 - h1) * self.x(1))
        self.set_w(2, (t1 * self.w(7) + t2 * self.w(8)) * h1 * (1 - h1) * self.x(2))
        self.set_w(3, (t1 * self.w(9) + t2 * self.w(10)) * h2 * (1 - h2) * self.x(1))
        self.set_w(4, (t1 * self.w(9) + t2 * self.w(10)) * h2 * (1 - h2) * self.x(2))
        self.set_w(5, (t1 * self.w(11) + t2 * self.w(12)) * h3 * (1 - h3) * self.x(1))
        self.set_w(6, (t1 * self.w(11) + t2 * self.w(12)) * h3 * (1 - h3) * self.x(2))
        # 更新b:
        self.set_b(1,
                   t1 * self.w(7) * h1 * (1 - h1) + t1 * self.w(9) * h2 * (1 - h2) + t1 * self.w(11) * h3 * (1 - h3) +
                   t2 * self.w(8) * h1 * (1 - h1) + t2 * self.w(10) * h2 * (1 - h2) + t2 * self.w(12) * h3 * (1 - h3))
        self.set_b(2, t1 + t2)
        return loss, o1, o2


if __name__ == '__main__':
    _w = [0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65]
    _b = [0.35, 0.65]
    _x = [5.0, 10.0]
    _y = [0.3, 0.8]
    _lr = 0.5
    print("demo")
    bp = BP(_w, _b, _x, _y, _lr)
    for i in range(1000):
        _loss = bp.training()
    print(_loss)
    print(bp.get_w())
    print(bp.get_b())