1. 简单非线性关系数据集测试(XOR)
X: Y
00 0
01 1
10 1
11 0
NeuralNetwork.py:
# coding=utf-8
import numpy as np
def tanh(x):
return np.tanh(x)
def tanh_deriv(x):
return 1.0 - np.tanh(x) * np.tanh(x) # tanh函数的导数
def logistic(x):
return 1 / (1 + np.exp(-x)) # 逻辑函数
def logistic_derivative(x):
return logistic(x) * (1 - logistic(x)) # 逻辑函数的导数,用来计算权重的更新
class NeuralNetwork:
def __init__(self, layers, activation='tanh'): # 构造函数,self相当于指针
'''
:param layers: 列表,包含了每一层的神经元个数
:param activation: 激活函数的选择
'''
if activation == 'logistic':
self.activation = logistic
self.activation_deriv = logistic_derivative
elif activation == 'tanh':
self.activation = tanh
self.activation_deriv = tanh_deriv
self.weights = []
for i in range(1, len(layers) - 1): # 从第一层到最后的输出的前一层,都要赋予一个初始权重
self.weights.append(
(2 * np.random.random((layers[i - 1] + 1, layers[i] + 1)) - 1) * 0.25) # 对i层与i-1层之间的权重进行随机的赋值
self.weights.append(
(2 * np.random.random((layers[i] + 1, layers[i + 1])) - 1) * 0.25) # 对i层与i+1层之间的权重进行随机的赋值 -0.25到0.25之间
def fit(self, X, y, learning_rate=0.2, epochs=10000):
'''
:param X: 二维矩阵,每一行对应一个实例,列数代表了特征数
:param y: 标签
:param learning_rate:
:param epochs: 达到预设的循环次数,最多循环10000次
:return:
'''
X = np.atleast_2d(X) # 确认x的维度最少为2维数组
temp = np.ones([X.shape[0], X.shape[1] + 1]) # 初始化矩阵全是1(行数,列数+1是为了有偏置b)
temp[:, 0:-1] = X # 行全选,第一列到倒数第二列
X = temp # 主要是偏置的赋值
y = np.array(y) # 转化为数组的形式,数据结构转换
for k in range(epochs):
i = np.random.randint(X.shape[0]) # 随机抽取一行
a = [X[i]]
for l in range(len(self.weights)):
a.append(self.activation(np.dot(a[l], self.weights[l]))) # 内积实现加权求和,activation实现非线性转换
# 向前传播,得到每个节点的输出结果
error = y[i] - a[-1]
deltas = [error * self.activation_deriv(a[-1])] # 输出层的误差
for l in range(len(a) - 2, 0, -1):
deltas.append(deltas[-1].dot(self.weights[l].T) * self.activation_deriv(a[l])) # 隐含层误差
deltas.reverse() # 对误差进行顺序颠倒
for i in range(len(self.weights)):
layer = np.atleast_2d(a[i])
delta = np.atleast_2d(deltas[i])
self.weights[i] += learning_rate * layer.T.dot(delta) # 更新权重 w=w+(l)*E*a ,l为学习率,E为误差,o为输入
def predict(self, x):
x = np.array(x)
temp = np.ones(x.shape[0] + 1) # 偏置的加入
temp[0:-1] = x
a = temp
for l in range(0, len(self.weights)):
a = self.activation(np.dot(a, self.weights[l])) # 预测时不需要保存a中间量的值
return a
实现异或操作代码:
# coding=utf-8
from NeuralNetwork import NeuralNetwork
import numpy as np
nn = NeuralNetwork([2, 12, 1], 'tanh')
x = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y = np.array([0, 1, 1, 0])
nn.fit(x, y)
for i in [[0, 0], [0, 1], [1, 0], [1, 1]]:
print(i, nn.predict(i))
结果:
[0, 0] [-0.01971361]
[0, 1] [0.99467795]
[1, 0] [0.99349545]
[1, 1] [-0.09293012]
2.手写数字识别:
每个图片8*8
识别数字:0,1,2,3,4,5,6,7,8,9
HandwrittenDigitsRecognition.py:
# coding=utf-8
import numpy as np
from sklearn.datasets import load_digits
from sklearn.metrics import confusion_matrix, classification_report # 对结果的衡量
from sklearn.preprocessing import LabelBinarizer # 转化为10位的0 1二进制数据类型
from NeuralNetwork import NeuralNetwork
from sklearn.model_selection import train_test_split # 训练集合,测试集的划分
import pylab as pl
# 看一下手写体长啥样
digits = load_digits() # 下载手写体数字集
print(digits.data.shape)
pl.gray()
pl.matshow(digits.images[0])
pl.show()
X = digits.data # 特征量
y = digits.target # 标签
X -= X.min() # normalize the values to bring them into the range 0-1
X /= X.max() # 转化到0-1之间
nn = NeuralNetwork([64, 100, 10], 'logistic') # 输入为8*8的图像,64个特征,输出有10类,0-9 ,隐藏层一层,有100个单元
X_train, X_test, y_train, y_test = train_test_split(X, y) # 划分
labels_train = LabelBinarizer().fit_transform(y_train) # 二进制,如5,则变成[0,0,0,0,0,1,0,0,0,0]
labels_test = LabelBinarizer().fit_transform(y_test)
print('start fitting')
nn.fit(X_train, labels_train, epochs=3000) # 3000次循环
predictions = []
for i in range(X_test.shape[0]):
o = nn.predict(X_test[i])
predictions.append(np.argmax(o)) # 选最大的概率
print(confusion_matrix(y_test, predictions)) # 混淆矩阵
print(classification_report(y_test, predictions)) # 查准率:true positive/预测 positive; 召回率: true positive/实际 positive
结果:
(1797, 64)
start fitting
[[43 0 0 0 1 0 0 0 0 0]
[ 0 39 1 0 1 0 1 0 6 2]
[ 0 0 39 0 0 0 0 0 0 0]
[ 0 0 2 51 0 2 0 0 1 1]
[ 0 2 0 0 34 0 0 2 0 0]
[ 0 0 0 0 0 43 0 0 0 0]
[ 1 2 0 0 0 0 42 0 0 0]
[ 0 0 0 0 0 0 0 44 0 1]
[ 0 1 2 0 0 1 0 0 42 1]
[ 0 1 0 1 0 0 0 0 0 40]]
precision recall f1-score support
0 0.98 0.98 0.98 44
1 0.87 0.78 0.82 50
2 0.89 1.00 0.94 39
3 0.98 0.89 0.94 57
4 0.94 0.89 0.92 38
5 0.93 1.00 0.97 43
6 0.98 0.93 0.95 45
7 0.96 0.98 0.97 45
8 0.86 0.89 0.88 47
9 0.89 0.95 0.92 42
avg / total 0.93 0.93 0.93 450
附:VisualizeDigits.py:
from sklearn.datasets import load_digits
digits = load_digits() # 下载手写体数字集
print (digits.data.shape)
import pylab as pl
pl.gray()
pl.matshow(digits.images[0])
pl.show()