多层向前神经网络由以下部分组成:
输入层(input layer), 隐藏层 (hidden layers), 输入层 (output layers)
代码中叫做 sigmoid / sigmoidDer (命名不当,理解就好)
- 双曲函数(tanh) 以及 导数
numpy库提供了tanh函数 : numpy.tanh(x)
导数为 : 1.0−tanh(x)2
- 逻辑函数(logistic function) 以及 导数
函数为 : logistic(x)=11+e−x
导数为 : logistic(x)⋅(1−logistic(x))
简单的说就是通过迭代性的来处理训练集中的实例,经过神经网络后输入层预测值(predicted value)与真实值(target value)之间的误差不断调整权重weight来使其更加准确,最后反向计算误差来更新连接之间的权重weight
算法大致流程 :
向前更新传送过程
根据误差(error)反向传送过程
注意:本简单实现算法迭代过程使用了随机化,可以更改其条件达到更好的精确性
# coding:utf-8
from numpy import *
def tan(x):
return tanh(x)
def tanDer(x): # tanh的导数
return 1.0 - tanh(x) * tanh(x)
def logistic(x):
return 1 / (1 + exp(-x))
def logisticDer(x): # logistic的导数
return logistic(x) * (1 - logistic(x))
class NN(object):
def __init__(self, layer, sigmoid=tan, sigmoidD=tanDer): # layer是个列表 分别存着每一层的元素个数
self.weights = []
self.sigmoid = sigmoid
self.sigmoid_der = sigmoidD
for i in range(1, len(layer) - 1): # 随机 生成weight 和 bias
self.weights.append((2 * random.random((layer[i - 1] + 1, layer[i] + 1)) - 1) * 0.25)
self.weights.append((2 * random.random((layer[i] + 1, layer[i + 1])) - 1) * 0.25)
def fit(self, x, y, alpha=0.02, loopNum=10000): # 步长与循环次数 默认0.02 / 10000
x = atleast_2d(x) # 至少2维
tempx = ones([x.shape[0], x.shape[1] + 1]) # 多加一列
tempx[:, 0:-1] = x # 最后一列的1是常数
x = tempx
y = array(y)
for k in range(loopNum): # 随机选择下标
index = random.randint(x.shape[0])
units = [x[index]] # 当前单元(Unit)格的数值
for i in range(len(self.weights)): # 进过两次运算后计算出输出层(预测值) -- 公式 1
units.append(self.sigmoid(dot(units[i], self.weights[i]))) # dot all a1b1+a2b2.....
error = y[index] - units[-1] # Tj - Oj
deltas = [error * self.sigmoid_der(units[-1])] # 反向 输出层误差 -- 公式 2
for i in range(len(units) - 2, 0, -1):
# 隐藏层误差 -- 公式 3
deltas.append(deltas[-1].dot(self.weights[i].T) * self.sigmoid_der(units[i]))
deltas.reverse() # 从后往前更新 所以逆转一下
for i in range(len(self.weights)):
unit = atleast_2d(units[i])
delta = atleast_2d(deltas[i])
self.weights[i] += alpha * unit.T.dot(delta) # 根据公式不断更新weights -- 公式 4
def predict(self, x):
x = array(x)
temp = ones(x.shape[0] + 1)
temp[0:-1] = x
unit = temp
for i in range(0, len(self.weights)): # 不用保留之前层的数值,只保留最后一层数值,并且放入到sigmoid函数中
unit = self.sigmoid(dot(unit, self.weights[i])) # 数值*weight参数
return unit
if __name__ == '__main__':
'''简单数学逻辑运算'''
x = array([[0, 0], [0, 1], [1, 0], [1, 1]])
y = array([1, 0, 0, 1])
nn = NN([2, 2, 1], tan, tanDer)
nn.fit(x, y)
for i in [[0, 0], [0, 1], [1, 0], [1, 1]]:
print i,int(nn.predict(i) > 0.5)
print '01 is over\n'
'''从numpy库导入数据进行数字识别'''
from sklearn.datasets import load_digits
from sklearn.metrics import confusion_matrix, classification_report
from sklearn.preprocessing import LabelBinarizer
from sklearn.cross_validation import train_test_split
digits = load_digits()
X = digits.data
y = digits.target
X -= X.min()
X /= X.max() # for X range : 0-1
nn = NN([64, 500, 10], logistic)
X_train, X_test, y_train, y_test = train_test_split(X, y) # 随机切分数据集
labels_train = LabelBinarizer().fit_transform(y_train) # 二值化label
labels_test = LabelBinarizer().fit_transform(y_test) # 比如1就是 01000000000
print "start fitting number"
nn.fit(X_train, labels_train, alpha=0.001, loopNum=50000)
predictions = [] # 预测值
for i in range(X_test.shape[0]):
o = nn.predict(X_test[i])
predictions.append(argmax(o)) # argmax(o) 返回o数组中最大的元素的下标
print confusion_matrix(y_test, predictions) # 对比数值
print classification_report(y_test, predictions) # 分类报告
# print predictions
'''
[0, 0] 1
[0, 1] 0
[1, 0] 0
[1, 1] 1
01 is over
start fitting number
[[42 0 0 0 0 0 0 0 0 0]
[ 0 33 1 0 0 0 0 0 2 7]
[ 0 0 40 0 0 0 0 0 0 0]
[ 0 1 0 40 0 3 0 2 3 0]
[ 0 0 0 0 47 0 0 0 2 0]
[ 0 0 0 0 0 43 0 0 0 3]
[ 0 0 0 0 0 0 41 0 0 0]
[ 0 0 0 0 0 1 0 47 1 1]
[ 0 3 0 0 0 1 0 1 43 0]
[ 0 0 0 0 0 2 0 0 1 39]]
precision recall f1-score support
0 1.00 1.00 1.00 42
1 0.89 0.77 0.82 43
2 0.98 1.00 0.99 40
3 1.00 0.82 0.90 49
4 1.00 0.96 0.98 49
5 0.86 0.93 0.90 46
6 1.00 1.00 1.00 41
7 0.94 0.94 0.94 50
8 0.83 0.90 0.86 48
9 0.78 0.93 0.85 42
avg / total 0.93 0.92 0.92 450
'''
# 分析
# 关于01的与或运算应该是很准确了 原始数据进行了sigmoid函数计算
# 关于数字识别 第一个矩阵对角线上说明正确的个数
# 第二个矩阵 有正确率以及反向正确率 450张训练正确率93%尚可
# 可以改变参数比如步长,随机循环次数等等.....