深度学习与计算机视觉:基于Python的神经网络的实现
在前面两篇文章介绍了深度学习的一些基本概念,本文则使用Python实现一个简单的深度神经网络,并使用MNIST数据库进行测试。
神经网络的实现,包括以下内容:
- 神经网络权值的初始化
- 正向传播
- 误差评估
- 反向传播
- 更新权值
主要是根据反向传播的4个基本方程,利用Python实现神经网络的反向传播。
初始化
首先定义代表神经网络的类
NeuralNetwork,
class NeuralNetwork: def __init__(self,layers,alpha=0.1): self.W = [] self.layers = layers self.alpha = alpha
有三个属性,
W
存储各个层之间的权值矩阵,也是神经网络要更新学习的layers
神经网络的结构,例如:[2,2,1]
表示输入层有2个神经元,隐藏层2个神经元,输出层只有1个神经元。alpha
学习速率
接下来初始化各个层之间的权值矩阵
for i in np.arange(0,len(layers) - 2): w = np.random.randn(layers[i] + 1,layers[i + 1] + 1) self.W.append(w / np.sqrt(layers[i]))
注意上面生成权值矩阵的大小
layers[i] + 1,layers[i + 1] + 1,都加了1。 这是将神经元的偏置和权值统一的放到了权值矩阵里面。
\[ \left[ \begin{array}{c}w_{11} & w_{12} \\ w_{21} & w_{22}\end{array} \right] \cdot \left[\begin{array}{c}x_1 \\ x_2\end{array}\right] + \left[\begin{array}{c}b_1 \\ b_2\end{array}\right] = \left[\begin{array}{c}w_{11}x_1 + w{12}x_2 + b_1 \\ w_{21}x_1 + w_{22}x_2 + b_2 \end{array}\right] \]
可以将上式写成齐次的形式
\[
\left[
\begin{array}{c}w_{11} & w_{12} & b_1 \\ w_{21} & w_{22} &b_2 \end{array}
\right] \cdot \left[\begin{array}{c}x_1 \\ x_2 \\ 1\end{array}\right]
\]
使用统一的矩阵运算,在正向反向传播的时候更方便。
在输出层的神经元并没有偏置,所以要单独初始化输出层的权值矩阵
w = np.random.randn(layers[-2] + 1,layers[-1]) self.W.append(w / np.sqrt(layers[-2]))
下面实现Python的
magic function __repr__输出神经网络结构
def __repr__(self): return "NeuralNetWork:{}".format("-".join(str(l) for l in self.layers))
激活函数
在神经网络中使用
sigmoid作为激活函数,实现
sigmoid及其导数
def sigmoid(self,x): return 1.0 / (1 + np.exp(-x)) def sigmoid_deriv(self,x): return x * (1 - x)
正向反向传播
这一部分是神经的网络的核心了。下面实现
fit方法,在方法中完成神经网络权值更新(训练)的过程。
def fit(self,X,y,epochs=1000,displayUpdate=100): X = np.c_[X,np.ones((X.shape[0]))] for epoch in np.arange(0,epochs): for(x,target) in zip(X,y): self.fit_partial(x,target) # check to see if we should display a training update if epoch == 0 or (epoch + 1) % displayUpdate == 0: loss = self.calculate_loss(X,y) print("[INFO] epoch={},loss={:.7f}".format(epoch + 1,loss))
该函数有4个参数:
X
是输入的样本数据y
是样本的真是值epochs
训练的轮数displayUpdate
输出训练的loss
值。
X = np.c_[X,np.ones((X.shape[0]))]将输入训练的样本表示为齐次向量(也就是在末尾添1)。
fit_partial是对输入的每个样本进行训练,包括正向传播,反向传播以及权值的更新。
def fit_partial(self,x,y): A = [np.atleast_2d(x)] # 正向传播 # 层层之间的数据传递 for layer in np.arange(0,len(self.W)): # 输入经过加权以及偏置后的值 net = A[layer].dot(self.W[layer]) # 神经元的输出 out = self.sigmoid(net) # 保存下来,反向传播的时候使用 A.append(out)
上面完成了神经玩过的正向传播过程,下面根据反向传播的4个基本方程进行反向传播。
首先根据\(BP1\),
\[
\delta^L = \frac{\partial e}{\partial a^L} \odot \sigma'(z^L) \tag{BP1}
\]
计算输出层的误差\(\delta^L\)
error = A[-1] - y # 输出层的误差,均值方差作为损失函数 D = [error * self.sigmoid_deriv(A[-1])]
得到输出层的误差
D后,根据\(BP2\)计算各个层的误差
\[ \delta^{L-1} = (W^L)^T\delta^L \odot \sigma'(z^{L-1}) \tag{BP2} \]
for layer in np.arange(len(A) - 2,0 ,-1): delta = D[-1].dot(self.W[layer].T) delta = delta * self.sigmoid_deriv(A[layer]) D.append(delta) D = D[::-1]
将
D反转,和各个层的索引对应起来,下面根据\(BP3,BP4\)计算权值矩阵和偏置的导数
\[ \frac{\partial e}{b_j^l} = \delta_j^l \tag{BP3} \]
\[ \frac{\partial e}{w_{jk}^l} = \delta_j^l a_k^{l-1} \tag{BP4} \]
for layer in np.arange(0,len(self.W)): self.W[layer] += -self.alpha * A[layer].T.dot(D[layer])
首先求得权值和偏置的导数(权值和偏置统一到同一个矩阵中)
A[layer].T.dot(D[layer],然后将梯度乘以学习速率
alpha每次权值减小的步长。
上述就完成利用反向传播算法更新权值的过程。 关于反向传播四个基本方程的推导过程,可以参考文章深度学习与计算机视觉: 搞懂反向传播算法的四个基本方程
误差评估
上面代码已经实现了深度学习的训练过程,下面实现
predict输出使用训练好的模型预测的结果,
calculate_loss评估训练后模型的评估
def predict(self,X,addBias=True): p = np.atleast_2d(X) if addBias: p = np.c_[p,np.ones((p.shape[0]))] for layer in np.arange(0,len(self.W)): p = self.sigmoid(np.dot(p,self.W[layer])) return p def calculate_loss(self,X,targets): targets = np.atleast_2d(targets) predictions = self.predict(X,addBias=False) loss = 0.5 * np.sum((predictions - targets) ** 2) return loss
MNIST分类识别
使用上面实现的深度神经网络对MNIST手写体进行识别,首先导入必要的包
import NeuralNetwork from sklearn.preprocessing import LabelBinarizer from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report from sklearn import datasets
需要使用sklearn包中的一些工具,进行数据的处理。
# load MNIST数据集,并使用min/max对数据进行归一化 digits = datasets.load_digits() data = digits.data.astype("float") data = (data - data.min()) / (data.max() - data.min()) print("[INFO] samples: {}, dim: {}".format(data.shape[0], data.shape[1]))
将数据拆分为训练集和测试集,并对MNIST的类别进行编码
(trainX, testX, trainY, testY) = train_test_split(data, digits.target, test_size=0.25) # convert the labels from integers to vectors trainY = LabelBinarizer().fit_transform(trainY) testY = LabelBinarizer().fit_transform(testY)
下面构建神经网络结构,并使用训练集进行训练
nn = NeuralNetwork([data.shape[1], 32,16, 10]) print ("[INFO] {}".format(nn)) nn.fit(trainX, trainY, epochs=1000)
神经网络结构为:64-32-16-10,其中64为输入数据的大小,10输出类别的个数。
最后评估训练得到的模型
predictions = nn.predict(testX) print(classification_report(testY.argmax(axis=1), predictions.argmax(axis=1)))
最终的输出结果:
[INFO] loading MNIST (sample) dataset... [INFO] samples: 1797, dim: 64 [INFO] training network... [INFO] NeuralNetWork:64-32-16-10 [INFO] epoch=1,loss=607.1711647 [INFO] epoch=100,loss=7.1082795 [INFO] epoch=200,loss=4.0731690 [INFO] epoch=300,loss=3.1401868 [INFO] epoch=400,loss=2.8801101 [INFO] epoch=500,loss=1.8738122 [INFO] epoch=600,loss=1.7461474 [INFO] epoch=700,loss=1.6624043 [INFO] epoch=800,loss=1.1852884 [INFO] epoch=900,loss=0.6710255 [INFO] epoch=1000,loss=0.6336826 [INFO] evaluating network... precision recall f1-score support 0 1.00 0.95 0.97 39 1 0.84 1.00 0.92 38 2 1.00 0.98 0.99 41 3 0.93 0.98 0.95 52 4 0.91 0.97 0.94 40 5 0.98 0.98 0.98 41 6 1.00 0.96 0.98 51 7 1.00 0.98 0.99 48 8 0.98 0.89 0.93 55 9 0.98 0.93 0.95 45 micro avg 0.96 0.96 0.96 450 macro avg 0.96 0.96 0.96 450 weighted avg 0.96 0.96 0.96 450
如上测试结果,在测试集的上表现还算不错。
总结
本文使用Python简单的实现了一个神经网络。 主要是利用反向传播的4个基本方程,实现反向传播算法,更新各个神经元的权值。 最后使用该网络,对MNIST数据进行识别分类。
上面实现的神经网络只是“玩具”,用以加深对深度学习的训练过程以及反向传播算法的理解。后面将使用Keras和PyTorch来构建神经网络。
- 神经网络与深度学习 1.6 使用Python实现基于梯度下降算法的神经网络和MNIST数据集的手写数字分类程序
- 神经网络与深度学习 使用Python实现基于梯度下降算法的神经网络和自制仿MNIST数据集的手写数字分类可视化程序 web版本
- 神经网络与深度学习笔记(二)python 实现随机梯度下降
- 深度学习与神经网络-吴恩达(Part1Week4)-深度神经网络编程实现(python)-基础篇
- 【神经网络与深度学习】【计算机视觉】RCNN- 将CNN引入目标检测的开山之作
- 无需复杂深度学习算法,基于计算机视觉使用Python和OpenCV计算道路交通
- 【计算机视觉】【神经网络与深度学习】论文阅读笔记:You Only Look Once: Unified, Real-Time Object Detection
- [计算机视觉][神经网络与深度学习]SSD安装及其训练教程
- 【计算机视觉】【神经网络与深度学习】YOLO v2 detection训练自己的数据
- 【计算机视觉】【神经网络与深度学习】深度学习在图像超分辨率重建中的应用
- 深度学习论文-神经网络的代码实现(python版本)
- 深度学习与神经网络-吴恩达(Part1Week3)-单隐层神经网络编程实现(python)
- 【Python开发】【神经网络与深度学习】网络爬虫之python实现
- 【神经网络与深度学习】【计算机视觉】Fast R-CNN
- 【神经网络与深度学习】【计算机视觉】YOLO2
- 【神经网络与深度学习】【计算机视觉】图解YOLO
- [计算机视觉][神经网络与深度学习]R-FCN、SSD、YOLO2、faster-rcnn和labelImg实验笔记
- 【神经网络与深度学习】【计算机视觉】Faster R-CNN
- Python实现深度学习之-神经网络识别手写数字(更新中,更新日期:2017-07-12)
- 【神经网络与深度学习】【计算机视觉】SPPNet-引入空间金字塔池化改进RCNN