本文介绍了通过 Python 实现 BP 神经网络分类算法,对不同半径的圆进行多分类(3 分类),特征即为圆的半径。
输入层 12 节点,一个 6 节点的隐藏层,输出层 3 个节点。

1.目标

通过 BP 算法实现对不同半径的圆的分类。

2.开发环境

IDE:PyCharm 2018.3.3(Community Edition)

Python 及相关库的版本号如下图所示:

BP神经网络识别图分类结果识别结果 bp神经网络分类python_BP神经网络

3.准备数据

目的: 生成 3 类圆在第一象限内的坐标(圆心都是原点)
第 1 类:半径范围为 1~10,分类标识为‘0’
第 2 类:半径范围为 10~20,分类标识为‘1’
第 3 类:半径范围为 20~30,分类标识为‘2’

代码如下:data_generate.py

import numpy as np
import math
import random
import csv


# 只生成第一象限内的坐标即可。每个圆生成12个坐标(x,y),相当于12个特征维度
def generate_circle(lower, upper):
    # 圆在第一象限内的坐标
    data_ur = np.zeros(shape=(12, 2))

    # 在上下限范围内,随机产生一个值作为半径
    radius = random.randint(int(lower), int(upper))

    # 在0~90度内,每隔7.5度取一次坐标,正好取12次
    angles = np.arange(0, 0.5 * np.pi, 1 / 24 * np.pi)
    for i in range(12):
        temp_ur = np.zeros(2)
        x = round(radius * math.cos(angles[i]), 2)
        y = round(radius * math.sin(angles[i]), 2)
        temp_ur[0] = x
        temp_ur[1] = y
        data_ur[i] = temp_ur

    return data_ur, label


# 将坐标保存到CSV文件中
def save2csv(data, batch, label):
    out = open("D:\\circles.csv", 'a', newline='')
    csv_write = csv.writer(out, dialect='excel')

    length = int(data.size / 2)
    for i in range(length):
        string = str(data[i][0]) + ',' + str(data[i][1]) + ',' + str(batch) + ',' + str(label)
        temp = string.split(',')
        csv_write.writerow(temp)
    out.close()


if __name__ == "__main__":
    '''
        生成3类圆,标签(label)分别为:0、1、2
        第1类圆的半径下限为1,上限为10
        第2类圆的半径下限为10,上限为20
        第3类圆的半径下限为20,上限为30
        圆心都为原点
    '''
lower = [1, 10, 20]  # 半径随机值的下限
upper = [10, 20, 30]  # 半径随机值的上限
label = ['0', '1', '2']  # 种类的标签

for i in range(len(label)):
    # 每类数据生成50组
    for j in range(50):
        data, label = generate_circle(lower[i], upper[i])
        batch = 50 * i + j + 1  # 数据的批次,用来区分每个坐标是属于哪个圆的
        save2csv(data, batch, label[i])

共 3 类圆,每类生成 50 个圆,每个圆有 12 个坐标,因此在输出文件 D:\circles.csv 中总共有 3×50×12=1800 行数据:

BP神经网络识别图分类结果识别结果 bp神经网络分类python_python_02

通过生成的坐标绘制散点图如下:

BP神经网络识别图分类结果识别结果 bp神经网络分类python_BP神经网络识别图分类结果识别结果_03

图中蓝色的点是 label 为 0 的圆,绿色的点是 label 为 1 的圆,红色的点是 label 为 2 的圆。

4.处理数据

目标: 根据第 3 步获得的坐标,计算每个圆的半径(勾股定理)作为神经网络的输入。

代码如下:data_process.py

需要注意的是,生成的 CSV 文件共有 15 列,前 12 列为坐标对应的半径值,最后三列组合起来表示分类(label):

BP神经网络识别图分类结果识别结果 bp神经网络分类python_python_04

(1,0,0)表示类型为“0”的圆,(0,1,0)表示类型为“1”的圆,(0,0,1)表示类型为“2”的圆,这样做的目的是为了下一步使用神经网络时处理起来方便。

5.构建 BP 神经网络

上一步处理好的数据可以作为训练数据,命名为:circles_data_training.csv 重复第 3 步和第 4 步,可以生成另一批数据作为测试数据,命名为:circles_data_test.csv 当然,也可以手动划分出训练数据和测试数据。
训练数据和测试数据在输入时,做了矩阵的转置,将列转置为行。

代码如下:data_analysis_bpnn.py

import pandas as pd
import numpy as np
import datetime
from sklearn.utils import shuffle


# 1.初始化参数
def initialize_parameters(n_x, n_h, n_y):
    np.random.seed(2)

    # 权重和偏置矩阵
    w1 = np.random.randn(n_h, n_x) * 0.01
    b1 = np.zeros(shape=(n_h, 1))
    w2 = np.random.randn(n_y, n_h) * 0.01
    b2 = np.zeros(shape=(n_y, 1))

    # 通过字典存储参数
    parameters = {'w1': w1, 'b1': b1, 'w2': w2, 'b2': b2}

    return parameters


# 2.前向传播
def forward_propagation(X, parameters):
    w1 = parameters['w1']
    b1 = parameters['b1']
    w2 = parameters['w2']
    b2 = parameters['b2']

代码中需要注意的几个关键参数

  1. learning_rate=0.0075,学习率(可调)
  2. n_h=6,隐藏层节点数(可调)
  3. n_input=12,输入层节点数
  4. n_output=3,输出层节点数
  5. num_iterations=10000,迭代次数(可调)

另外,对于 predict(parameters, x_test, y_test) 函数需要说明一下:
a2 矩阵是最终的预测结果,但是是以概率的形式表示的(可以打印看一下)。通过比较 3 个类的概率,选出概率最大的那个置为 1,其它两个置为 0,形成 output 矩阵。

运行结果:

BP神经网络识别图分类结果识别结果 bp神经网络分类python_神经网络_05

上图中第一红框表示神经网络预测出的分类结果,第二个红框表示测试集中真实的分类((1,0,0)表示这个圆属于类型“0”)。

每次运行时,正确率可能不一样,最高能达到 100%。通过调整刚才提到的关键参数中的学习率、隐藏层节点数、迭代次数可以提高正确率。