《神经⽹络与深度学习》-自学笔记01

最近在工作中遇到一个用传统的规则模型无法很好解决的问题,于是才又想起了人工神经网络。终于在好奇心的驱使下,在网上找到了这本很多程序员都推荐的机器学习入门书籍《神经⽹络与深度学习》(英文书名:Neural Networks and Deep Learning),作者Michael Nielsen。

目前这本书有团队已经翻成中文了,更加方便学习,知乎上的链结,跳转前麻烦双击屏幕给点赞:

红色石头:火爆网络的《神经网络与深度学习》,有人把它翻译成了中文版!

再推荐一本复旦大学邱锡鹏教授写的入门的书籍,中文书名居然完全相同,也叫《神经⽹络与深度学习》。想学习更完整知识体系的朋友可以看看,书中还有贴心总结的“数学基础”章节,适合需要补习数学原理的朋友。

在自己推导反向传播公式的时候,发现知乎上的一本电子书非常棒,每一步推导都写得有理有据。而且还配有详细的图解,非常适合初学神经网络的小白。

这里与大家分享一下,自学《Neural Networks and Deep Learning》第一、二章的过程。

一、学习准备

  1. 下载github示例源码

全书的例子都是用python写的,开始看书前第一件事情就是把github的仓库拉到本地:

github.com/mnielsen/neu

作者还推荐一个兼容python3.5版本的github仓库地址,我们就以python3.5为例子:

github.com/MichalDaniel


2. 在linux上安装python3.5

首先,在ubuntu下安装python3

sudo apt-get install python3

但这样只安装了python3.4,要想使用python3.5,则必须升级python3.4

sudo add-apt-repository ppa:fkrull/deadsnakes
sudo apt-get update
sudo apt-get install python3.5

使用以上三行命令便可升级python3.4到python3.5。注意,在启动时需要命令行输入python3.5。

3. 安装numpy

apt-get安装的pyhton3.5中自带了pip,可以通过下面命令访问:

python3.5 -m pip -V
pip 1.5.4 from /usr/lib/python3/dist-packages (python 3.5)

但是pip的版本太老了,需要更新一下

python3.5 -m pip install --upgrade pip
Downloading/unpacking pip from https://files.pythonhosted.org/packages/36/74/38c2410d688ac7b48afa07d413674afc1f903c1c1f854de51dc8eb2367a5/pip-20.2-py2.py3-none-any.whl#sha256=d75f1fc98262dabf74656245c509213a5d0f52137e40e8f8ed5cc256ddd02923
  Downloading pip-20.2-py2.py3-none-any.whl (1.5MB): 1.5MB downloaded
Installing collected packages: pip
  Found existing installation: pip 1.5.4
    Not uninstalling pip at /usr/lib/python3/dist-packages, owned by OS
Successfully installed pip
Cleaning up...

pip默认安装包是从网站pypi.org/simple下载,我们可以将其改成国内的镜像网站,加速下载过程,下面以安装numpy库为例:

# 清华镜像
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple numpy

如果运行时报错,使用上述方案继续安装需要的库。

二、运行python代码

先按照书上的方法,把代码跑一遍先有个感观上的认识。其中mnist_loader主要加载训练和测试数据,network主要实现神经网络的初始化和训练及测试。输出的结果就是每次学习迭代后,使用10000个测试数据的正确率。

#python3.5
>>> import mnist_loader
>>> training_data, validation_data, test_data = mnist_loader.load_data_wrapper()
>>> import network
>>> net=network.Network([784,30,10])
>>> net.SGD(training_data, 30, 10, 3.0, test_data=test_data)
Epoch 0 : 9108 / 10000
Epoch 1 : 9309 / 10000
Epoch 2 : 9371 / 10000
Epoch 3 : 9392 / 10000
Epoch 4 : 9405 / 10000
Epoch 5 : 9404 / 10000
Epoch 6 : 9449 / 10000
Epoch 7 : 9410 / 10000
Epoch 8 : 9434 / 10000
Epoch 9 : 9475 / 10000
Epoch 10 : 9460 / 10000
Epoch 11 : 9494 / 10000
Epoch 12 : 9473 / 10000
Epoch 13 : 9479 / 10000
Epoch 14 : 9468 / 10000
Epoch 15 : 9496 / 10000
Epoch 16 : 9472 / 10000
Epoch 17 : 9489 / 10000
Epoch 18 : 9497 / 10000
Epoch 19 : 9488 / 10000
Epoch 20 : 9496 / 10000
Epoch 21 : 9502 / 10000
Epoch 22 : 9486 / 10000
Epoch 23 : 9486 / 10000
Epoch 24 : 9489 / 10000
Epoch 25 : 9501 / 10000
Epoch 26 : 9501 / 10000
Epoch 27 : 9498 / 10000
Epoch 28 : 9489 / 10000
Epoch 29 : 9497 / 10000

三、感受

看完第一、二章之后,感觉入门的难点主要是:

  1. 数学知识
  • 矩阵相关的加、减、乘和除
  • 导数、偏导数、梯度和微分

2. 反向传播的数学公式推导,理解单元素公式转变成向量化公式的过程

3. python知识

  • python内置函数:zip
  • numpy库相关的函数
  • 向量化代码
  • 理解如何从传统编程语言对每个元素操作,转变成使用numpy库的向量化编程风格

四、分享自学过程

1、前向传播

使用权重ω和偏置b沿前馈方向计算每个神经元的激活输出

v2-8aa8f434641bf1c091bc0deee2769a15_b.jpg
神经网络为[2,3,1]

下面是根据示意图进行的过程计算:

1.1 元素化计算过程

第一层,输入:

[[x1],
 [x2]]

第一层到第二层权重:

[[ω211, ω212],
 [ω221, ω222],
 [ω231, ω232]]

第二层偏置:

[[b21],
 [b22],
 [b23]]

第二层激活输出:

[[σ(x1*ω211+x2*ω212+b21)],
 [σ(x1*ω221+x2*ω222+b22)],
 [σ(x1*ω231+x2*w232+b23)]]

第二层到第三层权重:

[[ω311, ω312, ω313]]

第三层偏置:

[[b33]]

第三层激活输出:

[[σ(σ(x1*ω211+x2*ω212+b21)*ω311+ σ(x1*ω221+x2*ω222+b22)*ω312 + σ(x1*ω231+x2*w232+b23)*ω313 + b33)]]

1.2 向量化计算过程:

第一层输入:X,shape(2,1)
第一层到第二层的权重:W21, shape(3,2)
第二层偏置:B2, shape(3,1)
第二层激活输出: σ(W21*X+B2),注意矩阵的shape(3,1)
第二层到第三层权重:W32, shape(1,3)
第三层偏置:B3, shape(1,1)
第三层激活输出:σ(W32*σ(W21*X+B2)+B3), shape(1,1)

2、反向传播

使用梯度下降和偏导数的数学概念,从神经网络最后一层的输出开始,反向更新每个神经元的偏置b',以及每条神经元连接的权重ω'。

理解了梯度和偏导之后,再弄明白为什么叫反向传播,反向传播的到底是什么?这就要引入一个概念神经元误差:神经元误差是代价函数C关于第l层第j个神经元带权输入的偏导数,这个神经元误差代表带权输入给代价函数带来的变化率。在反向传播中,首先计算出输出层的神经元误差,再利用公式计算出前一层的神经元误差,实际上反向传播的就是神经元误差

(强烈推荐知乎上的一本书《深度学习的数学》,书中第四章非常详细的进行了反向传播的公式推导)

2.1 代价函数

用于衡量前向传播的输出与训练样本的期望输出的偏差

C=\frac{1}{2}\sum_{j}^{}{\left( y_{j}-a_{j}^{L} \right)^{2}} (公式1)

下面是二次代价函数的几何图形,反向传播就是为了更新权重ω和偏置b使代价函数接近图形的最低点。

v2-14a413cae3e4958ef72273d9054560fa_b.jpg

2.2 梯度

为什么选择函数的梯度?

因为梯度是函数在A点无数个变化方向中变化 最快的那个方向,要找最低点当然选择“梯度下降”最快。

为什么梯度下降,又变成求偏导数了呢?

因为数学家们发现,只要每一个变量 都沿着关于这个变量的偏导所指定的方向来变化,函数的整体变化就能达到最快。所以,梯度是偏导数的向量。

v2-087d1c1902631f44db340379fc23a561_b.jpg
反向传播示例图

上图的梯度向量为公式2

\left( \frac{\partial{C_{T}}}{\partial{\omega_{11}^{2}}}, ...,\frac{\partial{C_{T}}}{\partial{\omega_{11}^{3}}}, ..., \frac{\partial{C_{T}}}{\partial{b_{1}^{2}}}, ..., \frac{\partial{C_{T}}}{\partial{b_{1}^{3}}}, ...\right) (公式2)

2.3 神经元误差

为什么叫反向传播,反向传播的到底是什么?

这里就要引入一个概念“神经元误差”:神经元误差,是代价函数C关于第l层第j个神经元带权输入的偏导数,这个神经元误差代表带权输入给代价函数带来的变化率。
在反向传播中,首先计算出输出层的神经元误差,再利用公式计算出前一层的神经元误差,实际上反向传播的就是神经元误差。

神经元误差定义为公式3

\delta_{j}^{l} = \frac{\partial{C}}{\partial{z_{j}^{l}}} (公式3)

紧接着推导出,代价函数C关于第l层第j个神经元的第i条权重的偏导数为神经元误差乘以l-1层的激活输出值,公式4

\frac{\partial{C}}{\partial{\omega_{ij}^{l}}} = \delta_{j}^{l} a_{i}^{l-1} (公式4)

代价函数C关于第l层第j个神经元的偏置的偏导数为神经元误差,公式5

\frac{\partial{C}}{\partial{b_{j}^{l}}} = \delta_{j}^{l} (公式5)

下一步,只要带推导出上下层之间神经元误差的关系,就可以开始反向传播了:第l层第j个神经元的误差等于,该神经元到第l+1层每个神经元的权重与神经元的误差相乘求和,再乘以参数为第l层第j个神经元的带权输入的激活函数的导函数的值,公式6

\delta_{j}^{l} = \sum_{k}^{}{\omega_{kj}^{l+1}\delta_{k}^{l+1} \sigma^{'}\left( z_{j}^{l} \right)} (公式6)

反向传播简化了求导过程,只需要找出输出层的神经元误差,再使用公式计算反向推出各层的神经元误差,再利用神经元误差计算每层各神经元的偏导数,从而更新权重和偏置。

2.4 反向误差传播的过程

  1. 根据输入和前向传播计算出每层的激活值
  2. 计算输出层神经元误差
  3. 利用l层神经元和l+1层神经元误差的关系公式,反向计算每一层的神经元误差
  4. 用神经元误差计算梯度
  5. 用梯度更新权重和偏置

五、反向误差传播举例计算(代价函数为方差)

  1. 计算输出层神经元误差
σ31 = ∂C/∂a31*a'(z31) = (a31-t1)*a'(z31)
σ32 = ∂C/∂a32*a'(z32) = (a32-t2)*a'(z32)

2. 计算倒数第二层神经元误差

σ21 = (σ31*ω311 + σ32*ω321) * a'(z21)
σ22 = (σ31*ω312 + σ32*ω322) * a'(z22)
σ23 = (σ31*ω313 + σ32*ω323) * a'(z23)
σ24 = (σ31*ω314 + σ32*ω324) * a'(z24)

3. 计算输出层权重和偏置的偏导数

∂C/∂ω311 = σ31*a21
∂C/∂ω312 = σ31*a22
∂C/∂ω313 = σ31*a23
∂C/∂ω314 = σ31*a24
∂C/∂b31 = σ31

∂C/∂ω321 = σ32*a21
∂C/∂ω322 = σ32*a22
∂C/∂ω323 = σ32*a23
∂C/∂ω324 = σ32*a24
∂C/∂b32 = σ32

4. 计算倒数第二层的权重和偏置的偏导数

∂C/∂ω211 = σ21*a11
∂C/∂ω212= σ21*a12
∂C/∂ω213= σ21*a13
∂C/∂b21 = σ21

∂C/∂ω221 = σ22*a11
∂C/∂ω222= σ22*a12
∂C/∂ω223= σ22*a13
∂C/∂b22 = σ22

∂C/∂ω231 = σ23*a11
∂C/∂ω232= σ23*a12
∂C/∂ω233= σ23*a13
∂C/∂b23 = σ23

∂C/∂ω241 = σ24*a11
∂C/∂ω242 = σ24*a12
∂C/∂ω243 = σ24*a13
∂C/∂b24 = σ24

5. 更新权重和偏置

ω211 = ω211 - α * ∂C/∂ω211 = ω211 - α * σ21*a11
ω212 = ω212 - α * ∂C/∂ω212 = ω212 - α * σ21*a12
ω213 = ω213 - α * ∂C/∂ω213 = ω213 - α * σ21*a13
b21 = b21 - α * ∂C/∂b21 = b21 - α * σ21

ω221 = ω221 - α * ∂C/∂ω221 = ω221 - α * σ22*a11
ω222 = ω222 - α * ∂C/∂ω222 = ω222 - α * σ22*a12
ω223 = ω223 - α * ∂C/∂ω223 = ω223 - α * σ22*a13
b22 = b22 - α * ∂C/∂b22 = b22 - α * σ22

ω231 = ω231 - α * ∂C/∂ω231 = ω231 - α * σ23*a11
ω232 = ω232 - α * ∂C/∂ω232 = ω232 - α * σ23*a12
ω233 = ω233 - α * ∂C/∂ω233 = ω233 - α * σ23*a13
b23 = b23 - α * ∂C/∂b23 = b23 - α * σ23

ω241 = ω241 - α * ∂C/∂ω241 = ω241 - α * σ24*a11
ω242 = ω242 - α * ∂C/∂ω242 = ω242 - α * σ24*a12
ω243 = ω243 - α * ∂C/∂ω243 = ω243 - α * σ24*a13
b24 = b24 - α * ∂C/∂b24 = b24 - α * σ24

ω311 = ω311 - α * ∂C/∂ω311 = ω311 - α * σ31*a21
ω312 = ω312 - α * ∂C/∂ω312 = ω312 - α * σ31*a22
ω313 = ω313 - α * ∂C/∂ω313 = ω313 - α * σ31*a23
ω314 = ω314 - α * ∂C/∂ω314 = ω314 - α * σ31*a24
b31 = b31 - α * ∂C/∂b31 = b31 - α * σ31

ω321 = ω321 - α * ∂C/∂ω321 = ω321 - α * σ32*a21
ω322 = ω322 - α * ∂C/∂ω322 = ω322 - α * σ32*a22
ω323 = ω323 - α * ∂C/∂ω323 = ω323 - α * σ32*a23
ω324 = ω324 - α * ∂C/∂ω324 = ω324 - α * σ32*a24
b32 = b32 - α * ∂C/∂b32 = b32 - α * σ32

以上就是学习过程的总结,后续再更新学习第三章的总结。如果您看到这里,说明您很认真的阅读,同时觉得分享的东西还有点用,那就再麻烦您双击文章给个赞同,谢谢各位看官。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值