依旧根据麦子学院彭亮老师的机器学习课程,并加上自己的理解进行代码巩固。
一. NN.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 NN 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))
三 . 运行结果:
/home/troy/anaconda2/bin/python /home/troy/2.py
([0, 0], array([ 0.01477642]))
([0, 1], array([ 0.99760303]))
([1, 0], array([ 0.99760177]))
([1, 1], array([ 0.04567761]))
Process finished with exit code 0
四. 手写体识别:
#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 NN 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
[[39 0 0 0 0 0 0 0 1 0]
[ 0 31 0 1 0 0 0 0 9 6]
[ 0 0 47 0 0 0 0 0 0 0]
[ 0 0 0 39 0 1 0 1 0 0]
[ 0 0 0 0 46 0 0 2 0 1]
[ 0 0 0 1 0 49 0 0 0 2]
[ 0 1 0 0 0 0 47 0 0 0]
[ 0 0 0 0 0 2 0 42 0 1]
[ 0 0 0 0 0 0 0 0 39 0]
[ 0 0 0 1 0 0 0 1 0 40]]
precision recall f1-score support
0 1.00 0.97 0.99 40
1 0.97 0.66 0.78 47
2 1.00 1.00 1.00 47
3 0.93 0.95 0.94 41
4 1.00 0.94 0.97 49
5 0.94 0.94 0.94 52
6 1.00 0.98 0.99 48
7 0.91 0.93 0.92 45
8 0.80 1.00 0.89 39
9 0.80 0.95 0.87 42
avg / total 0.94 0.93 0.93 450
Process finished with exit code 0
(注意:1797为实例个数,即1797张8*8图片)