-
环境介绍
语言:Py,版本3.6
环境:Anaconda3 (64-bit),
编译器:Spyder,Jupyter Notebook等
实现功能:使用BP神经网络实现数字识别
神经网络搭建的思想
一个神经网络的搭建,需要满足三个条件。
- 输入和输出
- 权重(
w
)和阈值(b
) - 多层感知器的结构
神经网络的运作过程如下。
- 确定输入和输出
- 找到一种或多种算法,可以从输入得到输出
- 找到一组已知答案的数据集,用来训练模型,估算
w
和b
- 一旦新的数据产生,输入模型,就可以得到结果,同时对
w
和b
进行校正
前期准备知识点
1、载入数据集
from sklearn.datasets import load_digits
import pylab as pl
digits = load_digits()#载入数据集
print(digits.data.shape)
#数据解释,图片是8*8的被转换成一行64.共有1797个图片
#输出结果:(1797, 64)
pl.gray()#灰度化图片
pl.matshow(digits.images[7])
pl.show()
2、数据归一化处理
这里使用的是线性函数归一化处理。
其他归一化处理方法:https://blog.csdn.net/uestc_c2_403/article/details/75804617
为什么归一化:
- 数据为什么要归一化处理?当数据集的数值过大,即便乘以较小的权重后仍然还是一个很大的数时,当代入sigmoid激活函数中,激活函数的输出就趋近于1,不利于学习
- https://zhuanlan.zhihu.com/p/27627299
#这两个方法使用的是同一个公式,写法不一样
import numpy as np
X = np.array([[1,0,5],
[3,0,1],
[4,1,0],
[5,1,1]])
#归一化方法1
X -= X.min()
X= X/X.max()
#归一化方法2
Max=np.max(X)
Min=np.min(X)
def MaxMinNormalization(x,Max,Min):
x = (x - Min) / (Max - Min);
return x;
s=MaxMinNormalization(X,Max,Min)
3、切分数据,与标签二值化
- 分割数据1/4为测试数据,3/4为训练数据
- sklearn中直接一条语句就可以切分数据了:将数据项、标签项切分出来,3/4做训练集,剩下的1/4做测试集。
- 为什么要标签二值化?因为我们存入的标签是0,1,2,,,9这十个数,而计算机的识别都是0-1字符串,所以满足计算机识别分类,就需要进行标签二值化。
#实现数据二值化和数据切分
# -*- coding: utf-8 -*-
"""
Created on Sat Aug 4 17:29:59 2018
@author: 高硕
"""
import numpy as np
from sklearn.cross_validation import train_test_split #切割数据,交叉验证法
from sklearn.preprocessing import LabelBinarizer#标签二值化
#标签二值化
a = np.array([0,1,2,3,4,5,6,7,8,9])
b = np.array([0,1,2,3,4,5,6,7,8,2])
labels_a = LabelBinarizer().fit_transform(a)#标签二值化 0,8,6 0->1000000000 3->0001000000
labels_b = LabelBinarizer().fit_transform(b)#标签二值化 0,8,6 0->1000000000 3->0001000000
print(a)
print(b)
#切割数据
X = np.array([[1,0,5],
[2,0,1],
[3,1,0],
[4,1,1],
[5,9,5],
[6,0,1],
[7,3,0],
[8,2,1]])
Y = np.array([1,2,3,4,5,6,7,8])
X_train,X_test,y_train,y_test = train_test_split(X,Y)
- 二值化标签结果:
- 数据分割结果
4、Python 生成 -1~1 之间的随机数矩阵
-
使用函数 np.random.random(),由于 np.random.random() 默认生成 0~1 之间的小数,因此需要转换一下
-
如生成 3*3 的 -1~1 之间的随机数矩阵,-1 + 2*np.random.random((3,3))
import numpy as np #生成-1到1之间的随机数,生成的矩阵为3*4 X = np.random.random((3,4))*2-1 print(X)
-
layers[0]+1=65
-
import numpy as np def test(layers):#(64,100,10) #权值的初始化,范围-1到1 V = np.random.random((layers[0]+1,layers[1]+1))*2-1 W = np.random.random((layers[1]+1,layers[2]))*2-1 return V,W,layers M,N,K= test([64,100,10])
结果:
-
5、添加一列,作为偏置
- 看懂如何加的,如何变化的
import numpy as np
def test(X):
#添加偏置
temp = np.ones([X.shape[0],X.shape[1]+1])#行不变,列多一个
temp[:,0:-1] = X#
X = temp
return X
X = np.array([[1,0,0],
[3,0,1],
[4,1,0],
[5,1,1]])
X_new= test(X)#创建网络
结果:
6、X = np.atleast_2d(X)
这一方法可以保证所有的输入X至少是二维数组,如果是一维数组则会转化为一个二位的1*len(X)的数组。如:
b = [1,2,3]np.atleast_2d(b)输出结果为array([[1, 2, 3]])
import numpy as np
b = [1,2,3]
c=np.atleast_2d(b)
全部代码
# -*- coding: utf-8 -*-
"""
Created on Sat Aug 4 16:58:11 2018
@author: 高硕
"""
import numpy as np
from sklearn.datasets import load_digits
from sklearn.preprocessing import LabelBinarizer#标签二值化
from sklearn.cross_validation import train_test_split #切割数据,交叉验证法
def sigmoid(x):
return 1/(1+np.exp(-x))
def dsigmoid(x):
return x*(1-x)
class NeuralNetwork:
def __init__(self,layers):#(64,100,10)
#权重的初始化,范围-1到1:+1的一列是偏置值
self.V = np.random.random((layers[0]+1,layers[1]+1))*2-1
self.W = np.random.random((layers[1]+1,layers[2]))*2-1
def train(self,X,y,lr=0.11,epochs=10000):
#添加偏置
#添加偏置值:最后一列全是1
temp = np.ones([X.shape[0],X.shape[1]+1])#行不变,列多一个
temp[:,0:-1] = X#
X = temp
#分批次训练思想。10000个分10次,一次1000
#这里的话是随机选取一个数据
for n in range(epochs+1):
#在训练集中随机选取一行(一个数据):randint()在范围内随机生成一个int类型
i = np.random.randint(X.shape[0]) #随机选取一个数据(训练集里的)
x = [X[i]]
#转为二维数据:由一维一行转为二维一行
x = np.atleast_2d(x)#转为2维数据
# L1:输入层传递给隐藏层的值;输入层64个节点,隐藏层100个节点
# L2:隐藏层传递到输出层的值;输出层10个节点
L1 = sigmoid(np.dot(x,self.V))#隐层输出
L2 = sigmoid(np.dot(L1,self.W))#输出层输出
# L2_delta:输出层对隐藏层的误差改变量
# L1_delta:隐藏层对输入层的误差改变量
L2_delta = (y[i]-L2)*dsigmoid(L2)
L1_delta= L2_delta.dot(self.W.T)*dsigmoid(L1)
# 计算改变后的新权重
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]):
#获取预测结果:返回与十个标签值逼近的距离,数值最大的选为本次的预测值
o = self.predict(X_test[j])
#将最大的数值所对应的标签返回
predictions.append(np.argmax(o))#获取预测结果
accuracy = np.mean(np.equal(predictions,y_test))
#np.equal():相同返回true,不同返回false
print('迭代次数:',n,'准确率:',accuracy)
def predict(self,x):
#添加偏置
# 添加偏置值:最后一列全是1
temp = np.ones(x.shape[0]+1)
temp[0:-1] = x
x = temp
# 转为二维数据:由一维一行转为二维一行
x = np.atleast_2d(x)#转为2维数据
# L1:输入层传递给隐藏层的值;输入层64个节点,隐藏层100个节点
# L2:隐藏层传递到输出层的值;输出层10个节点
L1 = sigmoid(np.dot(x,self.V))#隐层输出
L2 = sigmoid(np.dot(L1,self.W))#输出层输出
#print("l2",L2)
return L2
digits = load_digits()#载入数据
X = digits.data#数据
y = digits.target#标签
#输入数据归一化
X -= X.min()
X /= X.max()
nm = NeuralNetwork([64,100,10])#创建网络
X_train,X_test,y_train,y_test = train_test_split(X,y) #分割数据1/4为测试数据,3/4为训练数据
labels_train = LabelBinarizer().fit_transform(y_train)#标签二值化 0,8,6 0->1000000000 3->0001000000
labels_test = LabelBinarizer().fit_transform(y_test)#标签二值化
print('start')
nm.train(X_train,labels_train,epochs=20000)
print('end')
结果: