天天看点

BP神经网络的Python实现

BP神经网络的Python实现

利用python实现了简易的 bp神经网络模型,利用误差逆传播算法以及梯度下降法对网络进行训练,具体公式推到等可参考《机器学习》等相关书籍。

源码以及数据集可在链接 https://download.csdn.net/download/wz2671/10790394下载。

BP_TEST.py

# -*- coding: UTF-8 -*-

from BPNet.bpNet import *
import matplotlib.pyplot as plt

# 数据集
bpnet = BPNet()
bpnet.loadDataSet("testSet2.txt")
bpnet.normalize()

# 绘制数据集散点图
bpnet.drawClassScatter(plt)

# BP神经网络进行数据分类
bpnet.bpTrain()

# 计算和绘制分类线
x, z = bpnet.BPClassfier()
bpnet.classfyLine(plt, x, z)
plt.show()
# 绘制误差曲线
bpnet.TrendLine(plt)
plt.show()
           

bpNet.py

# -*- coding: utf-8 -*-

from numpy import *
import matplotlib.pyplot as plt
"""
BP神经网络的Python实现
公式推导等可参考:周志华《机器学习》
"""


class BPNet(object):
    def __init__(self):
        # 网络参数
        self.eb = 0.01          # 误差容限
        self.eta = 0.1          # 学习率
        self.mc = 0.3           # 动量因子
        self.maxiter = 2000     # 最大迭代次数
        self.errlist = []       # 误差列表
        self.data = None        # 数据集
        self.label = None       # 分类集
        self.nSampNum = 0       # 样本集行数
        self.nSampDim = 0       # 样本维度
        self.nHidden = 4        # 隐含层神经元
        self.nOut = 1           # 输出层
        self.iterator = 0       # 最优时迭代次数
        self.hide_wb = None       # 隐含层模型参数
        self.out_wb = None      # 输出层模型参数

    # 激活函数
    def logistic(self, net):
        return 1.0 / (1.0 + exp(-net))

    # 传递函数的导函数
    def dlogit(self, net):
        return multiply(net, (1.0 - net))

    # 矩阵各元素平方之和
    def errorfunc(self, inX):
        return sum(power(inX, 2)) * 0.5

    # 数据归一化
    def normalize(self):
        [m, n] = shape(self.data)
        for i in range(n - 1):
            self.data[:, i] = (self.data[:, i] - mean(self.data[:, i])) / (std(self.data[:, i]) + 1.0e-10)
        return self.data

    # 加载数据集
    def loadDataSet(self, filename):
        self.data = []
        self.label = []
        fr = open(filename)
        for line in fr.readlines():
            lineArr = line.strip().split()
            self.data.append([float(lineArr[0]), float(lineArr[1]), 1.0])
            self.label.append(int(lineArr[2]))
        self.data = array(self.data)
        self.label = array(self.label)
        m, n = shape(self.data)
        self.nSampNum = m       # 样本数量
        self.nSampDim = n       # 样本维度

    # Train the bp net
    def bpTrain(self):
        # 数据集矩阵化
        SampIn = mat(self.data.T)
        expected = mat(self.label)
        self.hide_wb = mat(2.0 * (random.rand(self.nHidden, self.nSampDim) - 0.5))
        self.out_wb = mat(2.0 * (random.rand(self.nOut, self.nHidden + 1) - 0.5))
        # 默认权值
        dout_wbOld = 0.0
        dhide_wbOld = 0.0

        for i in range(self.maxiter):
            # 工作信号正向传播
            # 输入层到隐含层
            hide_input = self.hide_wb * SampIn
            hide_output = vstack((self.logistic(hide_input), ones((1, self.nSampNum))))
            # 隐含层到输出层
            out_input = self.out_wb * hide_output
            out_output = self.logistic(out_input)

            # 误差计算
            err = expected - out_output
            sse = self.errorfunc(err)
            self.errlist.append(sse)
            # 判断是否收敛至最优
            if sse <= self.eb:
                self.iterator = i + 1
                break

            # 误差信号反向传播
            # 计算输出层梯度
            delta_out = multiply(err, self.dlogit(out_output))
            dout_wb = delta_out * hide_output.T
            # 计算隐含层梯度
            delta_hide = multiply(self.out_wb[:, :-1].T * delta_out, self.dlogit(hide_output[:-1, :]))
            dhide_wb = delta_hide * SampIn.T
            # 更新输出层和隐含层权值
            if i == 0:
                self.out_wb = self.out_wb + self.eta * dout_wb
                self.hide_wb = self.hide_wb + self.eta * dhide_wb
            else:
                self.out_wb = self.out_wb + (1.0 - self.mc) * self.eta * dout_wb + self.mc * dout_wbOld
                self.hide_wb = self.hide_wb + (1.0 - self.mc) * self.eta * dhide_wb + self.mc * dhide_wbOld
            dout_wbOld = dout_wb
            dhide_wbOld = dhide_wb

    # bp神经网络分类器
    def BPClassfier(self, steps=30):
        x = linspace(self.data.min()-1, self.data.max()+1, steps)
        xx = tile(x, (steps, 1))
        yy = xx.T
        # 三维矩阵的骚操作,一般人别想看懂
        hide_output = array(self.hide_wb).dot(stack((xx, yy, ones((30, 30)))).transpose((1, 0, 2)))
        out_output = array(self.out_wb).dot(vstack((self.logistic(hide_output), ones((1, steps, steps)))).transpose((1, 0, 2)))
        zz = self.logistic(out_output)
        return x, zz[0]

    # 绘制分类线
    def classfyLine(self, plt, x, z):
        plt.contour(x, x, z, 1, colors='black')

    # 绘制趋势线:
    def TrendLine(self, plt, color='r'):
        X = linspace(0, self.maxiter, self.maxiter)
        Y = log2(self.errlist)
        plt.xlabel("iteration")
        plt.ylabel("loss")
        plt.plot(X, Y, color)

    # 绘制分类点
    def drawClassScatter(self, plt):
        negat_point = self.label == 0
        plt.scatter(self.data[negat_point, 0], self.data[negat_point, 1], c='b', marker='o')
        plt.scatter(self.data[~negat_point, 0], self.data[~negat_point, 1], c='r', marker='s')

           

实现结果图

BP神经网络的Python实现
BP神经网络的Python实现

继续阅读