EX3:神经网络手写数字识别(多类分类)
之前实现了多类逻辑回归来识别手写数字。 然而,逻辑回归不能形成更复杂的假设,因为它只是一个线性分类器。 (虽然可以向其中添加多项式特征,但训练成本可能非常高。)在这部分练习中,将使用与之前相同的训练集实现一个神经网络来识别手写数字。 神经网络将能够表示形成非线性假设的复杂模型。
目标是实现前馈传播算法。
1.数据读取
import numpy as np
from scipy.io import loadmat
data=loadmat('ex3data1.mat')
weights=loadmat('ex3weights.mat')
这里用到的data和ex3逻辑回归练习中是一样的,weights是已经训练好的神经网络权重,我们看一下它长什么样子
print一下可以看到weights中包含‘Theta1’和‘Theta2’两个部分,可以知道本次练习中我们用到的神经网络应当有两层hidden layer。
分别看看这两个权重的维度:
print(weights['Theta1'].shape,weights['Theta2'].shape)#((25,401),(10,26))
根据读取到的权重维度,可以直到网络一共有两层,其中Layer1包含25个neuron,Layer2包含10个neuron,这10个neuron的输出就是神经网络预测的结果。
注意:Layer1的输出在进入Layer2的运算前添加了偏置项。所以Layer2的系数矩阵维度发生变化,为(10,26)。
练习中神经网络架构示意图:
2.实现神经网络前馈传播计算
现在为神经网络实现前馈传播,实现为每个示例计算并返回相关预测的前馈计算。与一对多分类策略类似,神经网络的预测将是输出最大的标签。
注意到系数矩阵Theta1
包含401列,即我们输入的X
需要包含偏置列。
首先构造一下要用到的X
和y
:
#构造X,y
X=data['X']
y=data['y']
(X.shape,y.shape)#((5000, 400), (5000, 1))
我们总共有5000个样本,包含400个特征,还包含对应的label,下面我们为X添加偏置列:
ones_col=np.ones(X.shape[0])
X=np.c_[ones_col,X]
X.shape#(5000, 401)
X和y都构造完毕,接下来我们实现神经网络前馈传播算法,该函数将返回神经网络的预测结果。
首先构造激活函数——Sigmoid函数,便于在前馈传播计算中使用。
def sigmoid(z):
return 1/(1+np.exp(-z))
构造函数前,我们首先分析一下数据在该神经网络中的计算过程:
首先是输入数据X,X与Theta1相乘后经过激活函数生成下一层神经网络的输入:
X
:
(
5000
,
401
)
T
h
e
t
a
1
:
(
25
,
401
)
z
1
=
T
h
e
t
a
1.
d
o
t
(
X
T
)
a
1
=
g
(
z
1
)
:
(
25
,
5000
)
X:(5000,401) \\Theta1:(25,401) \\z1=Theta1.dot(X^T) \\a1=g(z1):(25,5000)
X:(5000,401)Theta1:(25,401)z1=Theta1.dot(XT)a1=g(z1):(25,5000)
第一层的计算结果要先添加一行偏置项(全1)再进入下一层的计算,与Theta2相乘以后经过激活函数得到输出:
a
1
:
(
25
,
5000
)
T
h
e
t
a
2
:
(
10
,
26
)
a
1
添
加
行
:
(
26
,
5000
)
z
2
=
T
h
e
t
a
2.
d
o
t
(
a
1
)
a
2
=
g
(
z
2
)
:
(
10
,
5000
)
a1:(25,5000) \\Theta2:(10,26) \\a1添加行:(26,5000) \\z2=Theta2.dot(a1) \\a2=g(z2):(10,5000)
a1:(25,5000)Theta2:(10,26)a1添加行:(26,5000)z2=Theta2.dot(a1)a2=g(z2):(10,5000)
每一列都是针对某一个样本的输出结果.
最后我们要输出该神经网络的预测结果,用到numpy库中一个函数argmax,函数说明如下
numpy.argmax(a,axis=0/1)
对二维矩阵a:
若axis=0则沿列方向搜索每一列最大的数并返回其列索引;
若axis=1则沿行方向搜索每一列最大的数并返回其行索引
注意我们的索引范围应当在0-9,而预测的数字为1-10,所以我们要将argmax返回的结果+1再输出。
def predict(Theta1,Theta2,X):
#layer1
a1=sigmoid(Theta1.dot(X.T))
#add bias
ones_col=np.ones((1,a1.shape[1]))
a1=np.r_[ones_col,a1]
#layer2
a2=sigmoid(Theta2.dot(a1))
pre_max=np.argmax(a2,axis=0)#搜索每一列最大值并返回列索引
return pre_max+1
函数构造完毕,我们来输出一下网络预测的准确性:
result=predict(weights['Theta1'],weights['Theta2'],X)
correct=np.array([1 if result[i]==y[i] else 0 for i in range(len(y))])
print("Accuracy:{}%".format(correct.sum()/len(correct)*100))#Accuracy:97.52%
根据练习说明文档中写的“我们将得到accuracy大概97.5%”可知算法正确运行。