bp神经网络python实现(关于公式的推导之后给出)

由于是小白,这篇bp的构建是参考了https://blog.csdn.net/huakai16/article/details/77479127#commentsedit

#!/user/bin/env python
# !-*-coding:utf-8 -*-
# !Time :2018/10/7 7:56 PM
# !Author : hyCong
# !@File  : .py
import sys

reload(sys)
sys.setdefaultencoding('utf-8')
from sklearn.datasets import load_digits  # 数据集
from sklearn.preprocessing import LabelBinarizer  # 标签二值化
from sklearn.cross_validation import train_test_split  # 数据集分割
import numpy as np
import pylab as pl  # 数据可视化


# digits = load_digits()  # 导入数据,改数据集有1797张图片,每张图片有64个属性特征
# print digits.data.shape
# pl.gray() #图像灰度化
# pl.matshow(digits.images[1])
# pl.show()
def sigmoid(x):  # 激活函数,隐层和输出层使用,这里使用sigmoid函数
    return 1 / (1 + np.exp(-x))  # 1/(1+e的x次方)


# layers = [64, 100, 10]
# digits = load_digits()
# X = digits.data
# print np.atleast_2d(X[0])


def dsigmoid(x):  # 取导数
    return x * (1 - x)


class NeuralNetwork:
    def __init__(self, layers):  # 构造的网络现在是三层layers【64,100,10】 表示输入层 隐藏层 输出层的单元个数
        # 初始化操作权值
        self.V = np.random.random(
            (layers[0] + 1, layers[1])) * 2 - 1  # 隐层的权值矩阵(65,100),多出来的一个是偏置值,65是64个输入层向量和一个偏置,100为隐层的神经元个数
        self.W = np.random.random((layers[1], layers[2])) * 2 - 1  # (100,10) 输出层的权值矩阵,输出层神经元个数10个,输入的隐层向量是100个

    def train(self, X, y, lr=0.1, epochs=10000):
        # lr为学习率即步长,epochs为迭代次数
        # 为数据集添加偏置
        # 将X原来的shape数据集取出来并添加一列属性赋给temp,多加的一列就是偏置数,设为1
        temp = np.ones([X.shape[0], X.shape[1] + 1])  # 建立一个行数和X.shape相同的矩阵,维数为X的维数+1
        temp[:, 0: -1] = X
        X = temp
        # 通过for迭代更新权值
        for n in range(epochs + 1):
            i = np.random.randint(X.shape[0])  # X.shape[0]存放的是样本的个数,随机取出一个样本
            x = X[i]  # 取出一个样本
            x = np.atleast_2d(x)  # 将x一维数组转化二维数组
            # 正向传播
            L1 = sigmoid(np.dot(x, self.V))  # 隐层的输出,将输入层的样本矩阵和隐层的权值(已经包含了偏置)进行点乘
            L2 = sigmoid(np.dot(L1, self.W))  # 输出层的数据矩阵,将隐层的输出矩阵和书橱层节点的权值矩阵(已添加偏置)进行点乘(100,10)
            # 反向传播
            # 根据推导出的输出层和隐藏层的误差公式进行计算

            L2_delta = (y[i] - L2) * dsigmoid(
                L2)  # (Dk-Ok)*Ok*(1-Ok) (101*10) 输出层10个神经元,每个神经元对应这个100个隐层的神经元(和一个偏置)传来的激活值所对应的误差值
            L1_delta = L2_delta.dot(self.W.T) * dsigmoid(L1)  # 点乘求和 ,继续向后推算隐藏层的误差(65*100)
            self.W += lr * L1.T.dot(L2_delta)
            self.V += lr * x.T.dot(L1_delta)
            # 每1000次预测准确率
            if n % 1000 == 0:
                predictions = []
                for j in range(X_test.shape[0]):
                    out = self.predict(X_test[j])  # 使用验证集进行测试
                    predictions.append(np.argmax(out))  # 返回预测的结果
                accuracy = np.mean(np.equal(predictions, y_test))  # 求预测结果与测试数据集的结果对比结果的平均值
                print('epoch:', n, 'accuracy:', accuracy)

    # 将测试数据向量x使用神经网络的两层权值进行计算输出
    def predict(self, x):
        # 为X添加一维
        temp = np.ones(x.shape[0] + 1)
        temp[0:-1] = x
        x = temp
        x = np.atleast_2d(x)
        L1 = sigmoid(np.dot(x, self.V))  # 隐层输出
        L2 = sigmoid(np.dot(L1, self.W))  # 输出层输出
        return L2  # 返回输出层的输出向量


digits = load_digits()  # 载入数据
X = digits.data
y = digits.target  # 结果集
# 数据归一化,x=(x-x.min)/(x.max-x.min)
X = (X - X.min()) / (X.max() - X.min())

# 创建神经网络对象,设置输入层 隐层 输出层的神经元个数(特征数)
nm = NeuralNetwork([64, 100, 10])

X_train, X_test, y_train, y_test = train_test_split(X, y)  # 将X和y进行随机划分为训练集和测试集

# 标签二值化
labels_train = LabelBinarizer().fit_transform(y_train)
labels_test = LabelBinarizer().fit_transform(y_test)

print "start"
nm.train(X_train, labels_train, epochs=60000)
print X_test[1]
for i in range(64):
    if (X_test[1][i]) < 0.1:
        print '  ',
    elif (X_test[1][i])<0.2:
        print '. ',
    elif (X_test[1][i]) < 0.4:
        print '- ',
    elif (X_test[1][i])<0.9:
        print '* ',
    else:
        print '@ ',
    if (i + 1) % 8 == 0:
        print '\n'
print np.argmax(nm.predict(X_test[1]))
print 'end'

使用训练之后的模型进行测试
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/c630565685/article/details/82972763