神经网络笔记1-三层BP神经网络

  • 神经网络性质简介
  • 信息正向传输
  • 预期神经网络的获得
    • 误差反向更新(输出层→隐藏层)
    • 误差反向更新(隐藏层→输入层)
  • 伪代码实现
    • 训练函数
    • 测试函数,用训练好的神经网络预测
  • 手写数字识别举例
    • 识别单个数字举例
    • 识别全部数字举例
    • 主程序框架搭建

神经网络性质简介

神经网络是用几个层之间建立联系,正像一个黑匣子一样,例如有一个机器,带皮的苹果进到这个黑匣子里,输出变成一个削完皮的苹果,带皮的香蕉进去自动变成剥完皮的香蕉。那么这个黑匣子就是一个剥皮的“网络”。在代码中我们也有类似的神经网络,这个神经网络就类似于我们大脑的神经元,神经网络包含很多层,每一层都有很多神经元,神经元的输入可能和之前很多神经元的输出都有联系。这个联系的紧密程度我们可以用一个权重值来表示。每两层之间的所有权重值可以构成一个矩阵,叫它传输矩阵,它建立了两层神经元之间的联系。
神经网络包含多个层:输入层、隐藏层、输出层。一般来讲它们之间的数据是逐次传输的。
例如我们希望有一个神经网络,输入一张图片,这个神经网络就能够输出这张图片上写着什么。那么这个神经网络就是我们要寻找的识别网络。我们可以将图片转化成一个向量,将向量的每一个元素作为输入层的不同神经元的输入,这样在输入层和隐藏层的传输矩阵的作用下,图片的数据经过变换来到了隐含层。同理,隐含层将数据通过隐藏层和输出层的传输矩阵作用到输出层的不同神经元上,这样我们期待的输出就是图片上写的内容。
下文将详细阐述神经网络的数据传输过程和如何构造预期的神经网络。

输入层的层数要与输入一致,输出层的层数要与期望输出个数一致。理论上隐藏层可以设置多个,并且单元数没有限制。但是本文只讨论三层的神经网络,三层BP神经网络可以逼近任意连续的函数,简单易行,可靠性好,故只选择一个隐含层。
设隐藏层单元个数为ppp,输入层单元个数为mmm,输出层单元个数为nnn,隐藏层数不是越多越好,在用神经网络逼近函数的时候,保证准确率高,有经验公式:
p=5+m+n±5p=5+\sqrt{m+n}\pm 5p=5+m+n​±5


为了方便统一表述,我们用1,2,3来分别代表输入层、隐藏层、输出层。
设第kkk层的输入为向量rk\mathbf{r}^{k}rk,其第iii个单元的值为rikr_{i}^{k}rik​
第kkk层的输出为向量ak\mathbf{a}^{k}ak,其第iii个单元的值为aika_{i}^{k}aik​
第kkk层第iii个输出单元到第k+1k+1k+1层第jjj个输入单元的传输常数为wi,jkw_{i,j}^{k}wi,jk​,构成矩阵Wk=[wi,jk]T\mathbf{W}^{k}=[ w_{i,j}^{k} ]^{T}Wk=[wi,jk​]T,其中iii从000开始,有一个常数项输入,第一列就是常数项偏置列。
注意矩阵Wk\mathbf{W}^{k}Wk是按照角标转置后排列的。

信息正向传输

传输过程可以写成如下表达:
rjk+1=∑i=0wi,jkaikr_{j}^{k+1} =\sum_{i=0} w_{i,j}^{k} a_{i}^{k} rjk+1​=i=0∑​wi,jk​aik​

这个式子的意义是某一层的某一个单元与前一层的所有单元都有关,而其中的权重值为wi,jkw_{i,j}^{k}wi,jk​
矩阵写法为:
rk+1=Wk[1...ak]\mathbf{r} ^{k+1}=\mathbf{W} ^{k} \begin{bmatrix} 1\\ ...\\ \mathbf{a} ^{k} \end{bmatrix}rk+1=Wk⎣⎡​1...ak​⎦⎤​

其中a0k=1a_{0}^{k}=1a0k​=1这一项说明传输矩阵有一列作为常数项偏置作为某一个单元的输入。
在每层的输入和输出中间有一个传递关系:
采用核函数
g(x)=11+e−xg(x)=\frac{1}{1+e^{-x} } g(x)=1+e−x1​

该函数为LOGISTIC函数,其具有微分性质:
g′(x)=g(x)(1−g(x))g'(x)=g(x)(1-g(x))g′(x)=g(x)(1−g(x))

这个函数就是每个单元对输入的数据都进行了一次归一化处理,这使得每层的输出都是(0,1)(0,1)(0,1)的概率数。故有
ak=g(rk)\mathbf{a} ^{k} =g(\mathbf{r} ^{k} )ak=g(rk)

设输入向量为x=[x1,x2,...,xm]T\mathbf{x} =[x_{1} ,x_{2} ,...,x_{m} ]^{T}x=[x1​,x2​,...,xm​]T,输出向量为y=[y1,y2,...,yn]T\mathbf{y} =[y_{1} ,y_{2} ,...,y_{n} ]^{T}y=[y1​,y2​,...,yn​]T输出向量与最后一层的输出同阶数
有:
r1=x\mathbf{r}^{1}=\mathbf{x}r1=x

我们的目标就是通过神经网络的输出a3\mathbf{a} ^{3}a3去逼近输出y\mathbf{y}y

预期神经网络的获得

误差反向更新(输出层→隐藏层)

定义损失函数
L=∥y−a3∥2=∑i(yi−ai3)2L=\left \| \mathbf{y}- \mathbf{a} ^{3} \right \| ^{2} =\sum_{i} (y_{i} -a_{i}^{3} )^{2} L=∥∥​y−a3∥∥​2=i∑​(yi​−ai3​)2
这个函数就表示训练前的网络在对输入数据处理得到的输出与期望输出的偏离程度。我们希望这个损失函数越小越好。因此理论上我们想逼近损失函数的极小值(也就是0)。损失函数内部有很多参数,我们需要更新的参数就是wi,jkw_{i,j}^{k}wi,jk​
这就需要梯度下降法来不断更新这些权重值。
梯度下降法可以参考我之前写的文章:梯度下降法线性回归模拟:https://blog.csdn.net/m0_53253879/article/details/123811100?spm=1001.2014.3001.5501

设迭代次数为lll,由梯度下降法公式
wi,jk←wi,jk−α∂L∂wi,jkw_{i,j}^{k} ←w_{i,j}^{k} -\alpha \frac{\partial L}{\partial w_{i,j}^{k}} wi,jk​←wi,jk​−α∂wi,jk​∂L​

先更新第222层到第333层的wi,j2w_{i,j}^{2}wi,j2​:
∂L∂wα,β2=∂∑i(yi−ai3)2∂wα,β2=∂∑i(yi−g(ri3))2∂wα,β2{ \frac{\partial L}{\partial w_{\alpha, \beta }^{2}}= \frac{\partial \sum_{i} (y_{i} -a_{i}^{3} )^{2}}{\partial w_{\alpha, \beta}^{2}}= \frac{\partial \sum_{i} (y_{i} -g(r_{i}^{3}) )^{2}}{\partial w_{\alpha, \beta}^{2}}}∂wα,β2​∂L​=∂wα,β2​∂∑i​(yi​−ai3​)2​=∂wα,β2​∂∑i​(yi​−g(ri3​))2​
=∂∑i(yi−g(∑j=0wj,i2aj2))2∂wα,β2=∂(yα−g(∑j=0wj,β2aj2))2∂wα,β2{= \frac{\partial \sum_{i} (y_{i} -g(\sum_{j = 0} w_{j,i}^{2} a_{j}^{2}) )^{2}}{\partial w_{\alpha, \beta}^{2}}= \frac{\partial(y_{\alpha } -g(\sum_{j = 0} w_{j ,\beta}^{2} a_{j}^{2}) )^{2}}{\partial w_{\alpha, \beta}^{2}}}=∂wα,β2​∂∑i​(yi​−g(∑j=0​wj,i2​aj2​))2​=∂wα,β2​∂(yα​−g(∑j=0​wj,β2​aj2​))2​
=−2(yα−g(∑j=0wj,β2aj2))g′(∑j=0wα,j2aj2))aα2\small =-2(y_{\alpha } -g(\sum_{j = 0} w_{j ,\beta}^{2} a_{j}^{2}) )g'(\sum_{j = 0} w_{\alpha ,j}^{2} a_{j}^{2}) )a_{\alpha }^{2}=−2(yα​−g(∑j=0​wj,β2​aj2​))g′(∑j=0​wα,j2​aj2​))aα2​
=−2(yα−g(∑j=0wj,β2aj2))g(∑j=0wj,β2aj2))(1−g(∑j=0wj,β2aj2)))aα2\small =-2(y_{\alpha } -g(\sum_{j = 0} w_{j ,\beta}^{2} a_{j}^{2}) )g(\sum_{j = 0} w_{j ,\beta}^{2} a_{j}^{2}) )(1-g(\sum_{j = 0} w_{j ,\beta}^{2} a_{j}^{2}) ))a_{\alpha }^{2}=−2(yα​−g(∑j=0​wj,β2​aj2​))g(∑j=0​wj,β2​aj2​))(1−g(∑j=0​wj,β2​aj2​)))aα2​

因此:
−12∂L∂wi,j2=(yj−aj3)aj3(1−aj3)ai2{\normalsize -\frac{1}{2} \frac{\partial L}{\partial w_{i, j }^{2}}=(y_{j } -a_{j}^{3})a_{j}^{3}(1-a_{j}^{3}) a_{i }^{2}} −21​∂wi,j2​∂L​=(yj​−aj3​)aj3​(1−aj3​)ai2​

记:
Δi2=(yi−ai3)ai3(1−ai3)Δk=[Δ0k,Δ1k,...Δnk]TA3=diag(a13,a23,...,an3)a~2=[1...a2]\begin{matrix} \Delta _{i}^{2}=(y_{i } -a_{i}^{3})a_{i}^{3}(1-a_{i}^{3})\\ \mathbf{\Delta }^{k}=[\Delta _{0}^{k} ,\Delta _{1}^{k},...\Delta _{n}^{k} ]^{T} \\ \mathbf{A} ^{3} =diag(a_{1}^{3} ,a_{2}^{3},...,a_{n}^{3})\\ \tilde{\mathbf{a}} ^{2} = \begin{bmatrix} 1\\ ...\\ \mathbf{a} ^{2} \end{bmatrix} \end{matrix}Δi2​=(yi​−ai3​)ai3​(1−ai3​)Δk=[Δ0k​,Δ1k​,...Δnk​]TA3=diag(a13​,a23​,...,an3​)a~2=⎣⎡​1...a2​⎦⎤​​
故有:
−12∂L∂wi,j2=Δj2ai2-\frac{1}{2} \frac{\partial L}{\partial w_{i, j }^{2}}=\Delta _{j}^{2}a_{i }^{2}−21​∂wi,j2​∂L​=Δj2​ai2​

Δ2=A3(I−A3)(y−a3)wi,j2←wi,j2−αΔj2ai2\begin{matrix} \mathbf{\Delta }^{2}=\mathbf{A} ^{3}(\mathbf{I}-\mathbf{A} ^{3})(\mathbf{y}- \mathbf{a} ^{3} ) \\ w_{i,j}^{2} ←w_{i,j}^{2} -\alpha \Delta _{j}^{2}a_{i }^{2} \end{matrix} Δ2=A3(I−A3)(y−a3)wi,j2​←wi,j2​−αΔj2​ai2​​

写成矩阵形式有
W2←W2−αΔ2(a~2)T\mathbf{W} ^{2} ←\mathbf{W} ^{2} -\alpha \mathbf{\Delta }^{2}(\tilde{\mathbf{a}} ^{2})^{T} W2←W2−αΔ2(a~2)T

这里需要注意的是−12∂L∂wi,j2-\frac{1}{2} \frac{\partial L}{\partial w_{i, j }^{2}}−21​∂wi,j2​∂L​中的−12-\frac{1}{2}−21​被学习率α\alphaα吸收了,因为学习率是一个可变参数

误差反向更新(隐藏层→输入层)

−12∂L∂wα,β1=∑i(yj−aj3)aj3(1−aj3)ai2wj,i2∑j∂aj2∂wα,β1-\frac{1}{2} \frac{\partial L}{\partial w_{\alpha ,\beta }^{1}}= \sum_{i} (y_{j } -a_{j}^{3})a_{j}^{3}(1-a_{j}^{3}) a_{i }^{2}w_{j,i}^{2}\sum_{j}\frac{\partial a_{j}^{2} }{\partial w_{\alpha ,\beta }^{1} } −21​∂wα,β1​∂L​=i∑​(yj​−aj3​)aj3​(1−aj3​)ai2​wj,i2​j∑​∂wα,β1​∂aj2​​

上面这个求导式子相当繁琐,根据链式法则,我们只给出结果如下:
−12∂L∂wi,j1=aj2(1−aj2)ai1∑kwjk2Δk2-\frac{1}{2} \frac{\partial L}{\partial w_{i, j }^{1}}=a_{j}^{2}(1-a_{j}^{2}) a_{i }^{1}\sum_{k} w_{jk}^{2} \Delta _{k}^{2} −21​∂wi,j1​∂L​=aj2​(1−aj2​)ai1​k∑​wjk2​Δk2​


Δj1=aj2(1−aj2)∑kwjk2Δk2A2=diag(a12,a22,...,an2)a~1=[1...a1]\begin{matrix} \Delta _{j}^{1} =a_{j}^{2}(1-a_{j}^{2})\sum_{k} w_{jk}^{2} \Delta _{k}^{2} \\ \mathbf{A} ^{2} =diag(a_{1}^{2} ,a_{2}^{2},...,a_{n}^{2}) \end{matrix}\\ \tilde{\mathbf{a}} ^{1} = \begin{bmatrix} 1\\ ...\\ \mathbf{a} ^{1} \end{bmatrix} Δj1​=aj2​(1−aj2​)∑k​wjk2​Δk2​A2=diag(a12​,a22​,...,an2​)​a~1=⎣⎡​1...a1​⎦⎤​

在上面几个式子中,W2\mathbf{W} ^{2}W2的常数偏置列在求导中消失了,我们定义矩阵W~2\tilde{\mathbf{W}} ^{2}W~2为W2\mathbf{W} ^{2}W2删除偏置列(第一列)并取转置之后的矩阵。

故有:
Δ1=A2(I−A2)W~2Δ2\mathbf{\Delta } ^{1} =\mathbf{A} ^{2} (\mathbf{I}- \mathbf{A} ^{2})\tilde{\mathbf{W}} ^{2} \mathbf{\Delta }^{2} Δ1=A2(I−A2)W~2Δ2

W1←W1−αΔ1(a~1)T\mathbf{W} ^{1} ←\mathbf{W} ^{1} -\alpha \mathbf{\Delta }^{1}(\tilde{\mathbf{a}} ^{1})^{T} W1←W1−αΔ1(a~1)T

再经过不断的更新,wi,jkw_{i,j}^{k}wi,jk​逐渐变成我们期待的网络,进而对于每个输入,都可以达到我们预期的输出。
但是这里需要强调的是,该神经网络不是对某一个样本输入一直进行训练达到损失函数的收敛,而是大量的数据作为输入样本依次通过神经网络,每个样本输入都会对神经网络进行一次训练。在大量样本都对该神经网络进行训练之后,神经网络对于某个样本的输出就能有一个大体的判断。所有样本也可以对神经网络进行多次训练,但是损失函数不会收敛到0,而是会在一定范围内进行波动。

伪代码实现

训练函数

从文件获取x=[x1,x2,...,xm]T\mathbf{x} =[x_{1} ,x_{2} ,...,x_{m} ]^{T}x=[x1​,x2​,...,xm​]T
从文件获取y=[y1,y2,...,yn]T\mathbf{y} =[y_{1} ,y_{2} ,...,y_{n} ]^{T}y=[y1​,y2​,...,yn​]T
中间隐藏层层数p=5+m+np=5+\sqrt{m+n}p=5+m+n​
第一层输入r1=x∈Rm×1\mathbf{r}^{1}=\mathbf{x}\in R^{m\times 1}r1=x∈Rm×1
第一层输出a1∈Rm×1\mathbf{a}^{1}\in R^{m\times 1}a1∈Rm×1
第二层输入r2∈Rp×1\mathbf{r}^{2}\in R^{p\times 1}r2∈Rp×1
第二层输出a2∈Rp×1\mathbf{a}^{2}\in R^{p\times 1}a2∈Rp×1
第三层输入r3∈Rn×1\mathbf{r}^{3}\in R^{n\times 1}r3∈Rn×1
第三层输出a3∈Rn×1\mathbf{a}^{3}\in R^{n\times 1}a3∈Rn×1
第一层到第二层传递矩阵W1∈Rp×(m+1)\mathbf{W} ^{1}\in R^{p\times (m+1)}W1∈Rp×(m+1)
第二层到第三层传递矩阵W2∈Rn×(p+1)\mathbf{W} ^{2}\in R^{n\times (p+1)}W2∈Rn×(p+1)
增广向量a~1=[1...a1]∈R(m+1)×1\tilde{\mathbf{a}} ^{1} = \begin{bmatrix} 1\\ ...\\ \mathbf{a} ^{1} \end{bmatrix}\in R^{(m+1)\times 1}a~1=⎣⎡​1...a1​⎦⎤​∈R(m+1)×1
增广向量a~2=[1...a2]∈R(p+1)×1\tilde{\mathbf{a}} ^{2} = \begin{bmatrix} 1\\ ...\\ \mathbf{a} ^{2} \end{bmatrix}\in R^{(p+1)\times 1}a~2=⎣⎡​1...a2​⎦⎤​∈R(p+1)×1


定义函数g(x)=11+e−xg(x)=\frac{1}{1+e^{-x} }g(x)=1+e−x1​
定义学习参数α=\alpha=α=
定义迭代次数k=0k=0k=0
损失函数赋初值L(0)=∥y−(a3)∥2L^{(0)}=\left \| \mathbf{y}- (\mathbf{a} ^{3}) \right \| ^{2}L(0)=∥∥​y−(a3)∥∥​2
第一层到第二层传递矩阵赋初值(W1)(\mathbf{W} ^{1})(W1)
第二层到第三层传递矩阵赋初值(W2)(\mathbf{W} ^{2})(W2)


(正向更新)
a1=g(r1)\mathbf{a} ^{1} =g(\mathbf{r} ^{1} )a1=g(r1)
(r2)(0)=(W1)(0)a~1(\mathbf{r} ^{2})^{(0)}=(\mathbf{W} ^{1})^{(0)}\tilde{\mathbf{a}} ^{1}(r2)(0)=(W1)(0)a~1
(a2)(0)=g(r2)(0)(\mathbf{a} ^{2})^{(0)} =g(\mathbf{r} ^{2} )^{(0)}(a2)(0)=g(r2)(0)
(a~2)(0)=[1...(a2)(0)](\tilde{\mathbf{a}} ^{2})^{(0)} = \begin{bmatrix} 1\\ ...\\ \mathbf(\mathbf{a} ^{2})^{(0)} \end{bmatrix}(a~2)(0)=⎣⎡​1...(a2)(0)​⎦⎤​
(r3)(0)=(W2)(0)a~2(\mathbf{r} ^{3})^{(0)}=(\mathbf{W} ^{2})^{(0)}\tilde{\mathbf{a}} ^{2}(r3)(0)=(W2)(0)a~2
(a3)(0)=g(r3)(0)(\mathbf{a} ^{3})^{(0)} =g(\mathbf{r} ^{3} )^{(0)}(a3)(0)=g(r3)(0)
(a~3)(0)=[1...(a3)(0)](\tilde{\mathbf{a}} ^{3})^{(0)} = \begin{bmatrix} 1\\ ...\\ \mathbf(\mathbf{a} ^{3})^{(0)} \end{bmatrix}(a~3)(0)=⎣⎡​1...(a3)(0)​⎦⎤​
(A2)(0)=diag((a~2)(0))(\mathbf{A} ^{2})^{(0)} =diag((\tilde{\mathbf{a}} ^{2})^{(0)})(A2)(0)=diag((a~2)(0))
(A3)(0)=diag((a~3)(0))(\mathbf{A} ^{3})^{(0)} =diag((\tilde{\mathbf{a}} ^{3})^{(0)})(A3)(0)=diag((a~3)(0))
(Δ2)(0)=(A3)(0)(I−(A3)(0))(y−(a3)(0))(\mathbf{\Delta }^{2})^{(0)}=(\mathbf{A} ^{3})^{(0)}(\mathbf{I}-(\mathbf{A} ^{3})^{(0)})(\mathbf{y}- (\mathbf{a} ^{3})^{(0)} )(Δ2)(0)=(A3)(0)(I−(A3)(0))(y−(a3)(0))
(Δ1)(0)=(A2)(0)(I−(A2)(0))W~2(Δ2)(0)(\mathbf{\Delta }^{1})^{(0)}=(\mathbf{A} ^{2})^{(0)} (\mathbf{I}- (\mathbf{A} ^{2})^{(0)})\tilde{\mathbf{W}} ^{2}(\mathbf{\Delta }^{2})^{(0)}(Δ1)(0)=(A2)(0)(I−(A2)(0))W~2(Δ2)(0)
损失函数赋初值L(0)=∥y−(a3)(0)∥2L^{(0)}=\left \| \mathbf{y}- (\mathbf{a} ^{3})^{(0)} \right \| ^{2}L(0)=∥∥​y−(a3)(0)∥∥​2



循环,按样本数对每个样本执行如下操作
(误差反向更新)
W2←W2−αΔ2(a~2)T\mathbf{W} ^{2} ←\mathbf{W} ^{2} -\alpha \mathbf{\Delta }^{2}(\tilde{\mathbf{a}} ^{2})^{T}W2←W2−αΔ2(a~2)T
W1←W1−αΔ1(a~1)T\mathbf{W} ^{1} ←\mathbf{W} ^{1} -\alpha \mathbf{\Delta }^{1}(\tilde{\mathbf{a}} ^{1})^{T}W1←W1−αΔ1(a~1)T
(正向传递)
r2=W1a~1\mathbf{r} ^{2}=\mathbf{W} ^{1}\tilde{\mathbf{a}} ^{1}r2=W1a~1
a2=g(r2)\mathbf{a} ^{2} =g(\mathbf{r} ^{2} )a2=g(r2)
a~2=[1...a2]\tilde{\mathbf{a}} ^{2}= \begin{bmatrix} 1\\ ...\\ \mathbf{a} ^{2} \end{bmatrix}a~2=⎣⎡​1...a2​⎦⎤​
r3=W2a~2\mathbf{r} ^{3}=\mathbf{W} ^{2}\tilde{\mathbf{a}} ^{2}r3=W2a~2
a3=g(r3)\mathbf{a} ^{3} =g(\mathbf{r} ^{3} )a3=g(r3)
a~3=[1...a3]\tilde{\mathbf{a}} ^{3} = \begin{bmatrix} 1\\ ...\\ \mathbf{a} ^{3} \end{bmatrix}a~3=⎣⎡​1...a3​⎦⎤​
A2=diag(a2)\mathbf{A} ^{2} =diag(\mathbf{a} ^{2})A2=diag(a2)
A3=diag(a3)\mathbf{A} ^{3} =diag(\mathbf{a} ^{3})A3=diag(a3)
Δ2=A3(I−A3)(y−a3)\mathbf{\Delta }^{2}=\mathbf{A} ^{3}(\mathbf{I}-\mathbf{A} ^{3})(\mathbf{y}- \mathbf{a} ^{3})Δ2=A3(I−A3)(y−a3)
Δ1=A2(I−A2)W~2Δ2\mathbf{\Delta }^{1}=\mathbf{A} ^{2}(\mathbf{I}- \mathbf{A} ^{2})\tilde{\mathbf{W}} ^{2} \mathbf{\Delta }^{2}Δ1=A2(I−A2)W~2Δ2
L=∥y−a3∥2L=\left \| \mathbf{y}- \mathbf{a} ^{3} \right \| ^{2}L=∥∥​y−a3∥∥​2


测试函数,用训练好的神经网络预测

a1=g(x)\mathbf{a} ^{1} =g(\mathbf{x} )a1=g(x)
a~1=[1...a1]\tilde{\mathbf{a}} ^{1} = \begin{bmatrix} 1\\ ...\\ \mathbf{a} ^{1} \end{bmatrix}a~1=⎣⎡​1...a1​⎦⎤​
a2=g(W1a~1)\mathbf{a} ^{2}=g(\mathbf{W} ^{1} \tilde{\mathbf{a}} ^{1})a2=g(W1a~1)
a~2=[1...a2]\tilde{\mathbf{a}} ^{2} = \begin{bmatrix} 1\\ ...\\ \mathbf{a} ^{2} \end{bmatrix}a~2=⎣⎡​1...a2​⎦⎤​
y=g(W2a~2)\mathbf{y}=g(\mathbf{W} ^{2} \tilde{\mathbf{a}} ^{2})y=g(W2a~2)
(总公式:y=g(W2[1...g(W1[1...g(x)])]\mathbf{y}=g(\mathbf{W} ^{2} \begin{bmatrix} 1\\ ...\\ g(\mathbf{W} ^{1} \begin{bmatrix} 1\\ ...\\ \mathbf g(\mathbf{x} ) \end{bmatrix}) \end{bmatrix}y=g(W2⎣⎢⎢⎢⎢⎡​1...g(W1⎣⎡​1...g(x)​⎦⎤​)​⎦⎥⎥⎥⎥⎤​)
返回 y\mathbf{y}y

手写数字识别举例

手写数字的训练集下载链接如下:
手写数字识别训练集:百度网盘分享https://pan.baidu.com/s/1A61uqPB_TTfyJ8sT4OqKIw?pwd=8f7a
每张图片是个28×2828\times 2828×28像素的图片,

将这个图片作为输入需要将图片导入Python并形成归一化灰度矩阵
新建文件NeuralClass.py,在该文件中编写我们所需要的函数
把数据集放置到Python文件夹里,读取数据的函数如下:

from PIL import Image# 输入图片,生成归一化灰度矩阵(黑色为1)
def get_gray_mt(pic_root):img = Image.open(pic_root)                  # 读取图片img = img.convert('L')                      # 灰度化cols, rows = img.size                       # 图像大小Value = [[0] * cols for i in range(rows)]   # 创建一个大小与图片相同的二维数组for x in range(0, rows):for y in range(0, cols):img_array = np.array(img)v = img_array[x, y]                 # 获取该点像素值Value[x][y] = 255 - v               # 取反色,存入数组Value = np.array(Value)/255return Value

该函数对于输入图片地址可以转化成一个矩阵。但对于神经网络的输入必须是一个列向量,因此还需要以下函数把矩阵转化成列向量,读取方式是按行读取,把输入矩阵的每一行首尾相连形成一个矩阵。

from math import *
import numpy as np# 将矩阵转化为列向量
def vector_c(A):cols, rows = A.shapevec = A.reshape(1, cols * rows)return np.array(vec[0])

Python提供的numpy库所提供的矩阵函数有限,因此我们需要手动编写某些特定需要的函数:
为了实现与有偏置项的W1\mathbf{W} ^{1}W1和W2\mathbf{W} ^{2}W2矩阵相乘,在每层的输出向量需要提供一个函数在向量头部加1形成增广向量:

# 求增广向量,头部添加1
def enlarge_vec(x):a = np.ones((1, len(x) + 1))for i in range(len(x)):a[0][i+1] = x[i]return a
# 将向量转化成对角矩阵
def vec_diag(x):A = np.eye(len(x))for i in range(len(x)):A[i][i] = x[i]return A

矩阵W~2\tilde{\mathbf{W}} ^{2}W~2为W2\mathbf{W} ^{2}W2删除偏置列(第一列)并取转置之后的矩阵,因此我们写出下面这个函数用来删除矩阵的某一列。

# 删除矩阵某一列的函数(输入矩阵, 需要删除的列数)
def dlt_c(A, c0):r, c = A.shapeB = np.zeros((r, c - 1))for i in range(r):for j in range(c-1):if j < c0:B[i][j] = A[i][j]elif j > c0:B[i][j - 1] = A[i][j]return B

最重要的每层的输入输出之间核函数LOGISTIC函数,可以对整个向量或矩阵中的每一个元素均取一遍函数。

# 核函数(LOGISTIC)
def sigmoid_vec(x):return 1/(1+np.exp(-x))

识别单个数字举例

有了以上基础,我们可以定义如下神经网络类:

# 神经网络类
class Neural_NetWork3:

(下面的代码为逐次书写)
这个网络里面初始化包含输入的训练集,输入层,隐藏层,输出层的层数,还有传输矩阵的初始化,损失函数列表。当给定某个训练样本时可以更新传输矩阵训练网络

 # 初始化def __init__(self, input_x, Input_lyout):self.x = input_x                                        # 输入所有数据self.ly_in = int(len(input_x[0][0]))                    # 输入层层数(784)self.ly_out = Input_lyout                               # 输出层层数self.ly_hid = int(sqrt(self.ly_in + self.ly_out) + 5)   # 隐藏层层数self.samplenum = int(len(input_x[0]))                   # 每个数字选取的样本数self.Loss = []                                          # 损失函数列表(在训练中会存入变化情况)# 输入层到隐藏层的传输矩阵,设置初值,在第一列设置偏置列self.W1 = np.random.normal(0.0, 1 / sqrt(self.ly_in), (self.ly_hid, self.ly_in + 1))# 隐藏层到输出层的传输矩阵,设置初值,在第一列设置偏置列self.W2 = np.random.normal(0.0, 1 / sqrt(self.ly_hid), (self.ly_out, self.ly_hid + 1))pass

为了保证迭代的稳定性,给出的W1\mathbf{W} ^{1}W1和W2\mathbf{W} ^{2}W2初值设定在(0,1m)(0,\frac{1}{\sqrt{m} } )(0,m​1​)和(0,1p)(0,\frac{1}{\sqrt{p} } )(0,p​1​)区间内的随机数。初值设定有时不能过大或者全为零,这样有可能导致训练时出现发散。
这里的x\mathbf{x}x是一个三阶张量,其按次序的两个索引分别为[样本所表示数字的第几个样本] [样本表示的数字]
在训练单个数字的判断网络时,输出向量为一标量,当需要训练的目标数字样本进入神经网络时,目标输出量为111,当其他样本通过该网络时,目标输出量为000。在经过大量的样本训练后,网络就能够对某一个数字样本进行识别,在输出就会比较靠近1,当其他样本经过神经网络时,输出就会比较靠近000。因此可以通过输出标量的值来判断是某个训练数字的概率。

  • 单个数字判断
  • 输出向量大于0.50.50.5(判定预测“是”该数字)
  • 输出向量小于0.50.50.5(判定预测“不是”该数字)
    将样本逐次通过该神经网络
    参考伪代码可以写出训练函数如下:
 # 神经网络的训练函数,训练某个数字的函数def Neural_Train_num(self, pre_num, alpha=0.2):for j in range(self.samplenum):for i in range(10):y = np.zeros((self.ly_out, 1))y[0][0] = (i == pre_num)W2_conv = dlt_c(self.W2, 0)         # W2删除第一列a1 = self.x[i][j]a1_en = enlarge_vec(a1)             # a1的增广向量,头部加1r2 = np.dot(self.W1, a1_en.T)       # 隐藏层输入向量a2 = sigmoid_vec(r2)                # 隐藏层输出向量a2_en = enlarge_vec(a2)             # a2的增广向量,头部加1r3 = np.dot(self.W2, a2_en.T)       # 输出层输入向量a3 = sigmoid_vec(r3)                # 输出层输出向量A2 = vec_diag(a2)                   # 由a2生成对角矩阵A3 = vec_diag(a3)                   # 由a3生成对角矩阵self.Loss.append(abs(np.linalg.norm(y - a3)))# 反向传递Delta2 = np.dot(A3 - np.dot(A3, A3), y - a3)Delta1 = np.dot(A2 - np.dot(A2, A2), W2_conv.T)Delta1 = np.dot(Delta1, Delta2)Del_W2 = np.dot(Delta2, a2_en)Del_W1 = np.dot(Delta1, a1_en)self.W2 = self.W2 + alpha * Del_W2self.W1 = self.W1 + alpha * Del_W1

预测神经网络的正确性时,有如下逻辑:
在给定图片输入时:

  • 若输出大于0.50.50.5,且该图片表示的数字正好是之前给定的数字则表示预测成功
  • 若输出小于0.50.50.5,且该图片表示的数字不是之前给定的数字则表示预测成功
  • 否则为预测失败
    将所有样本通过该网络可以给出预测的正确率,这是衡量该神经网络优良性的重要指标。
    写出如下函数:
 # 预测某个数字的正确率,输入为某个想要预测的图片上显示的数字def Neural_Rate_num(self, Predict_num):ra = 0      # 预测正确样本数rn = 0      # 计算样本总数for i in range(self.samplenum):for j in range(10):rn += 1a1 = self.x[j][i]a1_en = enlarge_vec(a1)           # a1的增广向量,头部加1r2 = np.dot(self.W1, a1_en.T)         # 隐藏层输入向量a2 = sigmoid_vec(r2)                  # 隐藏层输出向量a2_en = enlarge_vec(a2)           # a2的增广向量,头部加1r3 = np.dot(self.W2, a2_en.T)         # 输出层输入向量a3 = sigmoid_vec(r3)                  # 输出层输出向量if j == Predict_num and np.linalg.norm(a3) > 0.5:ra += 1if j != Predict_num and np.linalg.norm(a3) < 0.5:ra += 1return ra / rn

下面这个函数用来判断单独某张图片的预测结果

 # 测试单独某张图片预测结果,输出为是或否def Neural_Predict_num(self, x_Pre):a1 = x_Prea1_en = enlarge_vec(a1)r2 = np.dot(self.W1, a1_en.T)a2 = sigmoid_vec(r2)a2_en = enlarge_vec(a2)r3 = np.dot(self.W2, a2_en.T)a3 = sigmoid_vec(r3)print(a3)if a3[0] > 0.5:return Trueelse:return False

识别全部数字举例

识别全部数字时只需要把输出向量的阶数改为101010即可,每一行表示某一个数字的期望输出列。当需要训练的目标数字样本进入神经网络时,目标输出量对应的行为111,例如一个表示0的图片输入时,目标输出的第一行为1,其余为0;一个表示1的图片输入时,目标输出的第二行为1,其余为0,以此类推。
写出预测全部数字的训练函数如下:

 # 神经网络的训练函数,训练全部数字的函数def Neural_Train_0_9(self, alpha=0.2):for j in range(self.samplenum):for i in range(10):y = np.zeros((self.ly_out, 1))y[i][0] = 1W2_conv = dlt_c(self.W2, 0)         # W2删除第一列并取转置a1 = self.x[i][j]a1_en = enlarge_vec(a1)             # a1的增广向量,头部加1r2 = np.dot(self.W1, a1_en.T)       # 隐藏层输入向量a2 = sigmoid_vec(r2)                # 隐藏层输出向量a2_en = enlarge_vec(a2)             # a2的增广向量,头部加1r3 = np.dot(self.W2, a2_en.T)       # 输出层输入向量a3 = sigmoid_vec(r3)                # 输出层输出向量A2 = vec_diag(a2)                   # 由a2生成对角矩阵A3 = vec_diag(a3)                   # 由a3生成对角矩阵self.Loss.append(abs(np.linalg.norm(y - a3)))# 反向传递Delta2 = np.dot(A3 - np.dot(A3, A3), y - a3)Delta1 = np.dot(A2 - np.dot(A2, A2), W2_conv.T)Delta1 = np.dot(Delta1, Delta2)Del_W2 = np.dot(Delta2, a2_en)Del_W1 = np.dot(Delta1, a1_en)self.W2 = self.W2 + alpha * Del_W2self.W1 = self.W1 + alpha * Del_W1

当预测某一张图片时,就用其输出向量中最大的值所在的行数表示其预测结果。根据之前的设定,正好从python计数向量第0行到第9行表示数字1~9,参照前面的函数可以写出预测全部数字的预测函数如下:

 # 预测所有数字的正确率def Neural_Rate_0_9(self):ra = 0      # 预测正确样本数rn = 0      # 计算样本总数for i in range(self.samplenum):for j in range(10):rn += 1a1 = self.x[j][i]a1_en = enlarge_vec(a1)             # a1的增广向量,头部加1r2 = np.dot(self.W1, a1_en.T)       # 隐藏层输入向量a2 = sigmoid_vec(r2)                # 隐藏层输出向量a2_en = enlarge_vec(a2)             # a2的增广向量,头部加1r3 = np.dot(self.W2, a2_en.T)       # 输出层输入向量a3 = sigmoid_vec(r3)                # 输出层输出向量if np.argmax(a3) == j:ra += 1return ra / rn# 测试单独某张图片预测结果,输出为0~9中的某一个数def Neural_Predict_0_9(self, x_Pre):a1 = x_Prea1_en = enlarge_vec(a1)r2 = np.dot(self.W1, a1_en.T)a2 = sigmoid_vec(r2)a2_en = enlarge_vec(a2)r3 = np.dot(self.W2, a2_en.T)a3 = sigmoid_vec(r3)return np.argmax(a3)

主程序框架搭建

创建文件main.py写入主程序框架

  • 导入库函数
  • 调整matplotlib函数中文显示
  • 导入数据
    数据只需要把上文下载的压缩包直接解压到项目路径即可:
    (在“手写”文件夹中,读者也可以自行修改路径并从如下代码中完善:)
from tqdm import tqdm
import matplotlib.pyplot as plt
import random
from NeuralClass import *# matplotlib画图中中文显示会有问题,需要这两行设置默认字体可以显示中文
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = Falsesamplenum = int(input('请输入每个数字图片所取的样本数(0~500):'))          # 每个数字图片所取的样本数# x[样本所表示数字的第几个样本][样本表示的数字]
x = [list() for i in range(10)]
print('数据读取中...')
for i in tqdm(range(samplenum)):for j in range(10):x[j].append(vector_c(get_gray_mt('手写\\'+str(j)+'\\'+str(j)+'_' + str(i+1) + '.bmp')))
print('读取完成!')

导入数据引入库函数tqdm为数据导入过程添加进度条,导入全部5000个图片数据需要1~2分钟。
生成的三阶张量x\mathbf{x}x就是训练集,其按次序的两个索引分别为[样本所表示数字的第几个样本] [样本表示的数字]。
需要注意的是,在选择好需要学习的网络对网络进行训练的时候可能将所有样本只从网络中训练一次不能达到很高的正确率,因此需要对网络继续进行训练,调整学习参数,将所有样本再次经过网络…

将神经网络写到主程序中搭建如下框架:

#mermaid-svg-pukxxoFx7fEY1kS6 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-pukxxoFx7fEY1kS6 .error-icon{fill:#552222;}#mermaid-svg-pukxxoFx7fEY1kS6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-pukxxoFx7fEY1kS6 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-pukxxoFx7fEY1kS6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-pukxxoFx7fEY1kS6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-pukxxoFx7fEY1kS6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-pukxxoFx7fEY1kS6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-pukxxoFx7fEY1kS6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-pukxxoFx7fEY1kS6 .marker.cross{stroke:#333333;}#mermaid-svg-pukxxoFx7fEY1kS6 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-pukxxoFx7fEY1kS6 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-pukxxoFx7fEY1kS6 .cluster-label text{fill:#333;}#mermaid-svg-pukxxoFx7fEY1kS6 .cluster-label span{color:#333;}#mermaid-svg-pukxxoFx7fEY1kS6 .label text,#mermaid-svg-pukxxoFx7fEY1kS6 span{fill:#333;color:#333;}#mermaid-svg-pukxxoFx7fEY1kS6 .node rect,#mermaid-svg-pukxxoFx7fEY1kS6 .node circle,#mermaid-svg-pukxxoFx7fEY1kS6 .node ellipse,#mermaid-svg-pukxxoFx7fEY1kS6 .node polygon,#mermaid-svg-pukxxoFx7fEY1kS6 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-pukxxoFx7fEY1kS6 .node .label{text-align:center;}#mermaid-svg-pukxxoFx7fEY1kS6 .node.clickable{cursor:pointer;}#mermaid-svg-pukxxoFx7fEY1kS6 .arrowheadPath{fill:#333333;}#mermaid-svg-pukxxoFx7fEY1kS6 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-pukxxoFx7fEY1kS6 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-pukxxoFx7fEY1kS6 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-pukxxoFx7fEY1kS6 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-pukxxoFx7fEY1kS6 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-pukxxoFx7fEY1kS6 .cluster text{fill:#333;}#mermaid-svg-pukxxoFx7fEY1kS6 .cluster span{color:#333;}#mermaid-svg-pukxxoFx7fEY1kS6 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-pukxxoFx7fEY1kS6 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

训练全部数字的神经网络
训练某个数字的神经网络
开始
读取数据
选择训练网络类型
输入学习率
训练网络
是否继续训练
显示损失函数变化图像
预测图片-显示图片--循环
是否重新选择网络训练
结束

写出代码如下:

while 1:bool_form = int(input('选择训练全部数字的网络输入”1“,选择训练某个数字的网络输入”0”:'))if bool_form == 1:# 构建初始网络Net1 = Neural_NetWork3(x, 10)while 1:alpha = float(input('请输入学习率(建议输入0~1):'))print('开始训练神经网络...')Net1.Neural_Train_0_9(alpha)rate1 = Net1.Neural_Rate_0_9()print('判断0~9数字正确率为:' + str(round(rate1, 3) * 100) + '%')bool1 = float(input('是否继续训练?继续请输入1,退出请输入其他数字:'))if bool1 != 1:breakplt.figure('损失函数变化图象')plt.plot(Net1.Loss)plt.xlabel('迭代次数')plt.ylabel('损失函数$L =||\\mathbf{y}-\\mathbf{a}_{output}||^{2}$')plt.show()while 1:pre_num1 = int(input('请输入需要预测的图片(用图片上的数字表示):'))# 从选择的数字中随机抽取一张图片pre_spnum = random.randint(0, samplenum - 1)pre_result = Net1.Neural_Predict_0_9(x[pre_num1][pre_spnum])print('预测结果为:' + str(pre_result))if pre_result == pre_num1:print('预测成功!')else:print('预测失败!')img = Image.open('手写\\' + str(pre_num1) + '\\' + str(pre_num1) + '_' + str(pre_spnum + 1) + '.bmp')img.show()bool2 = float(input('是否继续预测?继续请输入1,退出请输入其他数字:'))if bool2 != 1:breakelif bool_form == 0:# 构建初始网络Net2 = Neural_NetWork3(x, 1)pre_num = int(input('请输入需要预测的数字(0~9):'))while 1:alpha = float(input('请输入学习率(建议输入0~1):'))print('开始训练神经网络...')Net2.Neural_Train_num(pre_num, alpha)rate1 = Net2.Neural_Rate_num(pre_num)print('判断数字' + str(pre_num) + '数字正确率为:' + str(round(rate1, 3) * 100) + '%')bool1 = float(input('是否继续训练?继续请输入1,退出请输入其他数字:'))if bool1 != 1:breakplt.figure('损失函数变化图象')plt.plot(Net2.Loss)plt.xlabel('迭代次数')plt.ylabel('损失函数$L =||\\mathbf{y}-\\mathbf{a}_{output}||^{2}$')plt.show()while 1:pre_num1 = int(input('请输入需要预测的图片(用图片上的数字表示):'))# 从选择的数字中随机抽取一张图片pre_spnum = random.randint(0, samplenum - 1)pre_result = Net2.Neural_Predict_num(x[pre_num1][pre_spnum])print(pre_result)if pre_result == True:print('预测结果为:是' + str(pre_num))if pre_num1 == pre_num:print('预测成功!')else:print('预测失败!')else:print('预测结果为:非' + str(pre_num))if pre_num1 != pre_num:print('预测成功!')else:print('预测失败!')img = Image.open('手写\\' + str(pre_num1) + '\\' + str(pre_num1) + '_' + str(pre_spnum + 1) + '.bmp')img.show()bool2 = float(input('是否继续预测?继续请输入1,退出请输入其他数字:'))if bool2 != 1:breakbool_all = int(input('是否重新选择网络训练?“是”请输入“1”,退出请输入“0”:'))if bool_all == 0:break

画图显示时用到了LaTeX编码,网址如下:
https://www.latexlive.com/
执行以上main.py文件过程示例如下:

C:\ProgramData\Anaconda3\python.exe C:/TJUcmj/学科/Python/NeuralNetwork3/Neural_main.py
请输入每个数字图片所取的样本数(0~500):500
数据读取中…
100%|██████████| 500/500 [01:33<00:00, 5.37it/s]
读取完成!
选择训练全部数字的网络输入”1“,选择训练某个数字的网络输入”0”:0
请输入需要预测的数字(0~9):5
请输入学习率(建议输入0~1):0.2
开始训练神经网络…
判断数字5数字正确率为:96.1%
是否继续训练?继续请输入1,退出请输入其他数字:1
请输入学习率(建议输入0~1):0.2
开始训练神经网络…
判断数字5数字正确率为:96.89999999999999%
是否继续训练?继续请输入1,退出请输入其他数字:1
请输入学习率(建议输入0~1):0.5
开始训练神经网络…
判断数字5数字正确率为:97.2%
是否继续训练?继续请输入1,退出请输入其他数字:0


请输入需要预测的图片(用图片上的数字表示):8
[[0.00016551]]
False
预测结果为:非5
预测成功!


是否继续预测?继续请输入1,退出请输入其他数字:1
请输入需要预测的图片(用图片上的数字表示):5
[[0.0074179]]
False
预测结果为:非5
预测失败!


是否继续预测?继续请输入1,退出请输入其他数字:1
请输入需要预测的图片(用图片上的数字表示):5
[[0.96203601]]
True
预测结果为:是5
预测成功!


是否继续预测?继续请输入1,退出请输入其他数字:0
是否重新选择网络训练?“是”请输入“1”,退出请输入“0”:1
选择训练全部数字的网络输入”1“,选择训练某个数字的网络输入”0”:1
请输入学习率(建议输入0~1):0.5
开始训练神经网络…
判断0~9数字正确率为:91.5%
是否继续训练?继续请输入1,退出请输入其他数字:1
请输入学习率(建议输入0~1):0.2
开始训练神经网络…
判断0~9数字正确率为:94.5%
是否继续训练?继续请输入1,退出请输入其他数字:1
请输入学习率(建议输入0~1):0.2
开始训练神经网络…
判断0~9数字正确率为:95.1%
是否继续训练?继续请输入1,退出请输入其他数字:1
请输入学习率(建议输入0~1):0.3
开始训练神经网络…
判断0~9数字正确率为:95.6%
是否继续训练?继续请输入1,退出请输入其他数字:1
请输入学习率(建议输入0~1):0.8
开始训练神经网络…
判断0~9数字正确率为:94.39999999999999%
是否继续训练?继续请输入1,退出请输入其他数字:1
请输入学习率(建议输入0~1):0.1
开始训练神经网络…
判断0~9数字正确率为:96.5%
是否继续训练?继续请输入1,退出请输入其他数字:0


请输入需要预测的图片(用图片上的数字表示):0
预测结果为:0
预测成功!


是否继续预测?继续请输入1,退出请输入其他数字:1
请输入需要预测的图片(用图片上的数字表示):7
预测结果为:7
预测成功!


是否继续预测?继续请输入1,退出请输入其他数字:1
请输入需要预测的图片(用图片上的数字表示):4
预测结果为:4
预测成功!


是否继续预测?继续请输入1,退出请输入其他数字:0
是否重新选择网络训练?“是”请输入“1”,退出请输入“0”:0

进程已结束,退出代码 0

以上是本项目全部内容,自己开发的开源代码供大家学习使用,如有问题请不吝斧正。
本项目存在的问题:在训练某个数字的神经网络时,正样本数和负样本数应该相等,而本项目中为了两个训练网络的连续性,负样本数是正样本数的9倍。因此在训练完整个神经网络之后虽然整体正确率很高,但是在判断本数字时正确率可能比较低。
提供思路如下:
将样本循环训练提出到神经网络类之外在主程序进行,在训练某个数字的神经网络时可以调节负样本的数量。
读者可以自行修改。

神经网络笔记1-三层BP神经网络相关推荐

  1. 基于三层BP神经网络的人脸识别

    实验四.基于三层BP神经网络的人脸识别 一. 实验要求 采用三层前馈BP神经网络实现标准人脸YALE数据库的识别,编程语言为C系列语言. 二.BP神经网络的结构和学习算法 实验中建议采用如下最简单的三 ...

  2. 模式识别八--三层BP神经网络的设计与实现

    文章转自:http://www.kancloud.cn/digest/prandmethod/102850 本文的目的是学习和掌握BP神经网络的原理及其学习算法.在MATLAB平台上编程构造一个3-3 ...

  3. 模式识别:三层BP神经网络的设计与实现

    本文的目的是学习和掌握BP神经网络的原理及其学习算法.在MATLAB平台上编程构造一个3-3-1型的singmoid人工神经网络,并使用随机反向传播算法和成批反向传播算法来训练这个网络,这里设置不同的 ...

  4. Python实现三层BP神经网络

    题外话 看论文,仿真实现,最基本的能力!研一的时候定要多看看论文,提升自己的代码能力! 引言 本篇博客默认读者有一定的BP神经网络的基础,BP神经网络的基本知识就不阐述了! BP神经网络结构 本文内容 ...

  5. 三层BP神经网络公式推导及C语言实现

    公式推导   三层BP神经网络如上图所示.其中, x i x_i xi​表示第 i i i个输入层节点的输入值,也是其输出值, z j z_j zj​表示第 j j j个隐藏层节点的输出值, y k ...

  6. bp神经网络原理 实现过程,BP神经网络的实现包括

    1.BP神经网络原理 人工神经网络有很多模型,但是日前应用最广.基本思想最直观.最容易被理解的是多层前馈神经网络及误差逆传播学习算法(Error Back-Prooaeation),简称为BP网络. ...

  7. bp神经网络解决什么问题,bp神经网络的改进方法

    BP神经网络的核心问题是什么?其优缺点有哪些? . 人工神经网络,是一种旨在模仿人脑结构及其功能的信息处理系统,就是使用人工神经网络方法实现模式识别.可处理一些环境信息十分复杂,背景知识不清楚,推理规 ...

  8. bp神经网络解决什么问题,BP神经网络的基本思想

    BP神经网络的核心问题是什么?其优缺点有哪些? . 人工神经网络,是一种旨在模仿人脑结构及其功能的信息处理系统,就是使用人工神经网络方法实现模式识别.可处理一些环境信息十分复杂,背景知识不清楚,推理规 ...

  9. bp神经网络数据预测实例,bp神经网络实例分析

    BP人工神经网络方法 (一)方法原理人工神经网络是由大量的类似人脑神经元的简单处理单元广泛地相互连接而成的复杂的网络系统.理论和实践表明,在信息处理方面,神经网络方法比传统模式识别方法更具有优势. 人 ...

最新文章

  1. 面试官比较看重简历中的哪些维度,有什么写简历的技巧、建议和总结?
  2. Python制作植物大战僵尸小游戏
  3. ubuntu常用的命令
  4. Windows 系统补丁管理策略
  5. java中的mapper是什么_Java使用ObjectMapper的简单示例
  6. LOAM: Lidar Odometry and Mapping in Real-time
  7. VIVO怎么创建计算机快捷方式,vivo手机快捷键怎么调出来
  8. 怎么一步步编写简单的PHP的Framework(十九)
  9. 基于semisync实现MySQL的主从半同步复制
  10. 背包九讲----02完全背包问题
  11. 专业计算机英语词汇翻译,计算机专业英语词汇与翻译复习题(已完成)
  12. IE6 浏览器常见兼容问题 大汇总(23个)
  13. 简易检测wifi信号强度协助检测网络
  14. Sklearn 卡方检验
  15. 什么是CPU,GPU,TPU,DPU,NPU,BPU
  16. python替换 输入手机号_python file模块 替换输入内容脚本
  17. Android 反编译APK详解
  18. 信息系统项目管理之10大管理的过程解释
  19. Java基础篇:什么是hashCode 以及 hashCode()与equals()的联系
  20. 3.0时代:激光投影让娱乐更真实

热门文章

  1. jdk7和8的一些新特性介绍
  2. PostgreSQL多维空间对象——cube插件
  3. Netbackup for sap 7.0学习之七:使用nbu进行sap系统的灾难恢复测试
  4. 数据安全特点有哪些?现在企业如何保障数据安全?
  5. 三家企业“支招”,数据安全防护指南来了!
  6. 假相当位温MATLAB绘图,关于假相当位温的精确计算
  7. 解决Java记事本输出中文乱码问题
  8. 细数2021年前端圈发生的30多件大事
  9. win10电脑怎么设置最佳性能?
  10. Numpy中的数组、行/列向量及其之间的转化