引言

本着“凡我不能创造的,我就不能理解”的思想,本系列文章会基于纯Python以及NumPy从零创建自己的深度学习框架,该框架类似PyTorch能实现自动求导。

要深入理解深度学习,从零开始创建的经验非常重要,从自己可以理解的角度出发,尽量不使用外部完备的框架前提下,实现我们想要的模型。本系列文章的宗旨就是通过这样的过程,让大家切实掌握深度学习底层实现,而不是仅做一个调包侠。
本系列文章首发于微信公众号:JavaNLP

我们上篇文章了解了神经元的概念,本文来学习一下神经网络(Neural Network)的基本知识。

异或问题

我们先来看下著名的异或问题,该问题曾导致了神经网络研究的十年低谷。

本文以下图片来自nlp3

异或问题(XOR problem):输入两个布尔数值(0或1),当两个数值不同时输出为1,否则输出为0。

如上图,假设输入是x1、x2,输出是y。

在介绍神经网络之前,我们先来了解一下感知机(perceptron),感知机可以类比成一个神经元,但是它没有一个非线性激活函数。

感知机是一种二元分类器(具有权重www和偏置bbb),把输入xxx(实数值向量)映射到二元的输出上。输出可以记为0或1,或者说是-1和+1。感知机的计算方法如下:
y={0,if w⋅x+b≤01,if w⋅x+b>0(1)y= \begin{cases} 0, & \text {if $w \cdot x + b \leq 0$ } \\ 1, & \text{if $w \cdot x + b > 0$ } \end{cases} \tag 1 y={0,1,​if w⋅x+b≤0 if w⋅x+b>0 ​(1)
我们可以很容易构建出能计算与运算(AND)和或运算(OR)的感知机:

上图是实现与(a)和或(b)运算的感知机。输入分别是x1,x2x_1,x_2x1​,x2​​。上图连线上的数值代表权重或偏置。

比如(a)为x1+x2−1x_1 + x_2 -1x1​+x2​−1,输入为1,11,11,1时,结果为1>01 > 01>0,所以输出y=1y=1y=1。

除了与运算(AND) 和 或运算(OR),异或运算也很重要。

但是我们不可能通过一个感知机来实现异或运算。因为感知机是一个线性分类器,对于二维输入x1x_1x1​和x2x_2x2​,感知机方程w1x1+w2x2+b=0w_1x_1 + w_2x_2 + b =0w1​x1​+w2​x2​+b=0是一个直线的方程,该直线作为二维空间中的决策边界,其中一侧代表输出为000,另一侧代表输出为111。

下图显示了可能的逻辑输入(00、01、10和11),以及由AND和OR分类器的一组可能的参数绘制的线。但我们没有办法画出一条之线将XOR的正例(01和10)与负例(00和11)区分开来。我们说XOR不是一个线性可分的函数。

解决方案:神经网络

尽管异或函数无法被单个感知机表示,但可以被基于感知机单元的分层网络表示。我们看如何使用两层ReLU单元计算异或问题。

该两层网络中有三个ReLU单元,分别是h1,h2h_1,h_2h1​,h2​和y1y_1y1​。有向边上的数字代表每个单元的权重www,灰色有向边代表偏置。

假设输入x=[0,0]x=[0,0]x=[0,0],我们计算

这里用到了ReLU激活函数,所以h2h_2h2​的输出是000,对于其他的输入可以自己验证一下。

本例中我们固定的权重值,但实际上神经网络的权重是通过反向传播算法自动学习的。

下面我就来了解下最常见的神经网络。

前馈神经网络

前馈神经网络( Feedforward Neural Networks,FNN)是一个逐层传播的没有循环的多层网络。由于历史原因,多层前馈网络,也被称为多层感知机(multi-layer perceptron,MLP)。但这是一个技术误称,因为现代多层网络中的神经元不是感知机(感知机是纯线性的,但现代网络中的神经元带有非线性激活函数)。

简单(两层)前馈网络有三种节点:输入单元、隐藏单元和输出单元,如下图所示。

输入层xxx通常代表由多个标量组成的一个向量;神经网络的核心是隐藏层hhh,由隐藏单元hih_ihi​组成,每个隐藏单元都是我们前面了解的神经元,隐藏层对其输入计算加权和并应用一个非线性函数。在标准架构中,每层都是全连接的(每个神经元都连接了每个输入)。

为什么说这是一个两层神经网络,因为我们在描述层数的时候,通常忽略掉输入层。

注意每个隐藏单元都有一个权重参数和一个偏置。我们通过将每个单元iii的权重向量和偏差组合成整个层的权重矩阵WWW和偏置向量BBB来表示整个隐藏层的参数。权重矩阵WWW中的每个元素WjiW_{ji}Wji​表示从第iii个输入单元xix_ixi​到第jjj个隐藏单元hjh_jhj​的连接的权重。

使用一个矩阵WWW表示整个层的权重的优点是,现在通过简单的矩阵操作,可以非常有效地完成前馈网络的隐层计算。实际上,计算只有三个步骤:将权值矩阵乘以输入向量xxx,加上偏置向量bbb,再应用激活函数ggg(比如Sigmoid、tanh或ReLU等)。

隐藏层的输出,向量hhh,因此可以如下计算(这里假设使用Sigmoid作为激活函数):
h=σ(Wx+b)(2)h = \sigma(Wx+b) \tag 2 h=σ(Wx+b)(2)

有时,我们也用σ\sigmaσ泛指任意激活函数,而不仅代表Sigmoid。

Wx+bWx+bWx+b的结果是一个向量,因此σ\sigmaσ应用到该向量上。

下面我们介绍一些常用的记号,以更好的描述后面的内容。

在本例中,我们称输入层为网络的第000层(layer 0),n0n_0n0​表示输入层的输入个数,所以xxx是维度为n0n_0n0​的实数向量,或正式一点说x∈Rn0x \in \Bbb R^{n_0}x∈Rn0​的列向量[n0×1][n_0 \times 1][n0​×1];我们称隐藏层为第111层(layer 1),输出层为第222层(layer 2);隐藏层的维度(隐藏层中单元个数)是n1n_1n1​,所以h∈Rn1h \in \Bbb R^{n_1}h∈Rn1​,同时b∈Rn1b \in \Bbb R^{n_1}b∈Rn1​(因为每个隐藏单元都有一个偏置);然后权重矩阵WWW的维度是W∈Rn1×n0W \in \Bbb R^{n_1\times n_0}W∈Rn1​×n0​(结合公式(2)(2)(2))。

因此公式(2)(2)(2)中的某个输出hjh_jhj​,可以表示为hj=σ(∑i=0n0Wjixi+bj)h_j = \sigma(\sum_{i=0}^{n_0} W_{ji}x_i + b_j)hj​=σ(∑i=0n0​​Wji​xi​+bj​)。

经过隐藏层,我们将维度为n0n_0n0​的输入向量表示成了维度为n1n_1n1​的隐藏向量,然后传递给输出层计算最终的输出。输出的维度取决于实际的问题,比如回归问题则为一个实数值(只有一个输出)。但常见的是分类问题。若是二分类,那么输出层的维度就是222,即输出单元(输出节点)只有两个;若是多分类,那么输出单元则有多个。

我们来看下输出层发生了什么,输出层也有一个权重矩阵(UUU),(除了输入层没有权重,这也是为什么输入层没有计算层数的原因之一),但有些模型输出层是没有偏置bbb的,所以权重矩阵UUU直接与其输入向量hhh相乘得到中间输出zzz:
z=Uh(3)z = Uh \tag 3 z=Uh(3)
输出层有n2n_2n2​个输出节点,所以z∈Rn2z \in \Bbb R^{n_2}z∈Rn2​,权重矩阵U∈Rn2×n1U \in \Bbb R^{n_2 \times n_1}U∈Rn2​×n1​,其中UijU_{ij}Uij​是从隐藏层中第jjj个单元到输出层第iii个单元的权重。

注意,这里的zzz是一个实数向量,通常不是最终的输出,对于分类模型中,我们需要将其转换为一个概率分布。

有一个很方便的函数可以将实数向量归一化(normalizing)为概率分布,该函数就是Softmax。假设给定维度为ddd的向量zzz,Softmax定义为:
softmax(zi)=exp⁡(zi)∑j=1dexp⁡(zj)1≤i≤d(4)\text{softmax}(z_i) = \frac{\exp(z_i)}{\sum_{j=1}^d \exp(z_j)} \quad 1 \leq i \leq d \tag 4 softmax(zi​)=∑j=1d​exp(zj​)exp(zi​)​1≤i≤d(4)
即我们可以把一个具有一个隐藏层的神经网络分类器看作是构建一个向量hhh,它是输入的一个向量表示,然后对网络中的hhh中运行标准的多元逻辑回归。相比之下,逻辑回归中的特征主要是通过特征模板手工设计的。所以神经网络就像Softmax逻辑回归,但是优点为:(a)可以有更多的层,因为深度神经网络就像一层又一层的逻辑回归分类器;(b)中间层有许多可选的激活函数(tanh,ReLU,sigmoid)而不只是sigmoid(尽管我们可能使用σ\sigmaσ来表示任何激活函数);©不是通过特征模板形成特征,网络前面的层自己形成特征表示。

我们就可以得到本例中的两层前馈网络,又称为单隐藏层前馈网络,的最终表示:
h=σ(Wx+b)z=Uhy=softmax(z)(5)\begin{aligned} h &= \sigma(Wx + b) \\ z &= Uh \\ y &= \text{softmax}(z) \end{aligned} \tag{5} hzy​=σ(Wx+b)=Uh=softmax(z)​(5)
其中x∈Rn0,h∈Rn1,b∈Rn1,W∈Rn1×n0,U∈Rn2×n1x \in \Bbb R^{n_0}, h \in \Bbb R^{n_1}, b \in \Bbb R^{n_1}, W \in \Bbb R^{n_1 \times n_0}, U \in \Bbb R^{n_2 \times n_1}x∈Rn0​,h∈Rn1​,b∈Rn1​,W∈Rn1​×n0​,U∈Rn2​×n1​,然后输出向量y∈Rn2y \in \Bbb R^{n_2}y∈Rn2​。我们称该网络为两层神经网络。所以,这么说的话,逻辑回归是一层网络。在资源能支撑的情况下,我们可以自由加深前馈网络的层数,这样可以得到真正的深层神经网络。

更常见的记号表示

下面我们介绍一些更常见的记号,Andrew Ng也用的这套表示方法。具体来说,使用方括号中的上标来表示层数,从输入层的0开始。

因此,W[1]W^{[1]}W[1]表示(第一个)隐藏层的权重矩阵,b[1]b^{[1]}b[1]表示(第一个)隐藏层的偏置向量;njn_jnj​将表示第jjj层的单元数;g(⋅)g(\cdot)g(⋅)来代表激活函数,中间层往往用ReLU或tanh激活函数,输出层往往是softmax;a[i]a^{[i]}a[i]来表示第iii层的输出,z[i]z^{[i]}z[i]表示W[i]a[i−1]+b[i]W^{[i]}a^{[i-1]}+b^{[i]}W[i]a[i−1]+b[i];第0层是输入层,所以我们将更一般地将输入xxx称为a[0]a^{[0]}a[0]。

这样我们重新表示上面的单隐藏层前馈网络为:
z[1]=W[1]a[0]+b[1]a[1]=g[1](z[1])z[2]=W[2]a[1]+b[2]a[2]=g[2](z[2])y^=a[2](6)\begin{aligned} z^{[1]} &= W^{[1]}a^{[0]} + b^{[1]} \\ a^{[1]} &= g^{[1]}(z^{[1]}) \\ z^{[2]} &= W^{[2]}a^{[1]} + b^{[2]} \\ a^{[2]} &= g^{[2]}(z^{[2]}) \\ \hat y &= a^{[2]}\\ \end{aligned} \tag{6} z[1]a[1]z[2]a[2]y^​​=W[1]a[0]+b[1]=g[1](z[1])=W[2]a[1]+b[2]=g[2](z[2])=a[2]​(6)

替换偏置单元记号

为了简化网络的描述,我们可以省略显示地描述偏置bbb。为此,我们向每个层添加一个虚拟节点a0a_0a0​,其值将始终为111。因此,输入层000层将具有虚拟节点a0[0]=1a^{[0]}_0=1a0[0]​=1,层111将具有a0[1]=1a^{[1]}_0=1a0[1]​=1,以此类推。这个虚拟节点仍然具有一个关联的权重,该权重表示偏差值bbb,比如将下面的等式:
h=σ(Wx+b)h = \sigma(Wx+ b) h=σ(Wx+b)
替换为:
h=σ(Wx)(7)h = \sigma(Wx) \tag{7} h=σ(Wx)(7)
但是现在xxx向量不是n0n_0n0​个值,变成了n0+1n_0+1n0​+1个值,包括固定的值x0=1x_0=1x0​=1,这样变成了x=x0,⋯,xn0x= x_0,\cdots,x_{n_0}x=x0​,⋯,xn0​​。我们就可以更改计算hjh_jhj​的方式,从:
hj=σ(∑i=1n0Wjixi+bj)(8)h_j = \sigma \left( \sum_{i=1}^{n_0} W_{ji}x_i + b_j \right) \tag{8} hj​=σ(i=1∑n0​​Wji​xi​+bj​)(8)
变成了:
hj=σ(∑i=0n0Wjixi)(9)h_j = \sigma \left( \sum_{i=0}^{n_0} W_{ji}x_i \right) \tag{9} hj​=σ(i=0∑n0​​Wji​xi​)(9)
其中用Wj0W_{j0}Wj0​替换了bjb_jbj​,我们画图时也可以进行简化:

从上图左边(a)(a)(a)简化为右边的(b)(b)(b)。

References

  1. Speech and Language Processing

从零实现深度学习框架——神经网络入门相关推荐

  1. numpy pytorch 接口对应_拆书分享篇深度学习框架PyTorch入门与实践

    <<深度学习框架PyTorch入门与实践>>读书笔记 <深度学习框架PyTorch入门与实践>读后感 小作者:马苗苗  读完<<深度学习框架PyTorc ...

  2. 深度学习和深度学习框架CNTK入门(一)

    深度学习和深度学习框架CNTK入门(一) 深度学习介绍 是基于机器学习延伸出来的一个新的领域,由以人大脑结构为启发的神经网络算法为起源加之模型结构深度的增加发展,并伴随大数据和计算能力的提高而产生的一 ...

  3. python学习框架图-从零搭建深度学习框架(二)用Python实现计算图和自动微分

    我们在上一篇文章<从零搭建深度学习框架(一)用NumPy实现GAN>中用Python+NumPy实现了一个简单的GAN模型,并大致设想了一下深度学习框架需要实现的主要功能.其中,不确定性最 ...

  4. 深度学习框架Pytorch入门与实践——读书笔记

    2 快速入门 2.1 安装和配置 pip install torch pip install torchvision#IPython魔术命令 import torch as t a=t.Tensor( ...

  5. 深度学习框架PyTorch入门与实践:第二章 快速入门

    本章主要介绍两个内容,2.1节介绍如何安装PyTorch,以及如何配置学习环境:2.2节将带领读者快速浏览PyTorch中主要内容,给读者一个关于PyTorch的大致印象. 2.1 安装与配置 2.1 ...

  6. 从零实现深度学习框架——GloVe从理论到实战

    引言 本着"凡我不能创造的,我就不能理解"的思想,本系列文章会基于纯Python以及NumPy从零创建自己的深度学习框架,该框架类似PyTorch能实现自动求导.

  7. 从零实现深度学习框架——Seq2Seq从理论到实战【实战】

    引言 本着"凡我不能创造的,我就不能理解"的思想,本系列文章会基于纯Python以及NumPy从零创建自己的深度学习框架,该框架类似PyTorch能实现自动求导.

  8. 从零实现深度学习框架——RNN从理论到实战【理论】

    引言 本着"凡我不能创造的,我就不能理解"的思想,本系列文章会基于纯Python以及NumPy从零创建自己的深度学习框架,该框架类似PyTorch能实现自动求导.

  9. 从零实现深度学习框架——深入浅出Word2vec(下)

    引言 本着"凡我不能创造的,我就不能理解"的思想,本系列文章会基于纯Python以及NumPy从零创建自己的深度学习框架,该框架类似PyTorch能实现自动求导. 要深入理解深度学 ...

  10. PyTorch(一个快速灵活的深度学习框架)入门简介及安装方法

    一个快速灵活的深度学习框架--PyTorch 前言:2018年7月30日也是我接触PyTorch深度学习框架的第一天.听老师说这套框架比TensorFlow好用吧.行!开启pytorch之旅.出发! ...

最新文章

  1. Nginx+Keepalived+Proxy_Cache 配置高可用集群和高速缓存
  2. eyoucms如何调用指定栏目下的推荐文章
  3. ng-class使用
  4. Sass的安装(windows 10)
  5. 【转】Chrome与Chromedriver版本对应表(最新)【附下载链接】
  6. 十天学会php之第七天
  7. 超级记事本android,基于Android的超级记事本APP设计.doc
  8. PTAM入门、ROS下PTAM的安装配置及使用
  9. C语言每日一练——第118天:百钱百鸡问题
  10. 宋红康jvm学习p1-100
  11. 解决open-vm-tools安装时Failed to get unit file state for run-vmblockx2dfuse.mount
  12. 一场云端的“神仙打架”:BAT加华为的影响未来之争
  13. 高级货!Django实现基于人脸识别的门禁管理系统【源码】
  14. 计算机网络基础试卷分析,《计算机应用基础》期末试卷分析.doc
  15. 微软欲用Silverlight阻击Flash
  16. access 分组序号_二级Access数据库备考笔记之报表排序和分组
  17. IIR滤波器极点分析--关于稳定度
  18. BAT企业招聘的职位里,60%以上都在招大数据人才!
  19. 制作app的网站的收藏
  20. MATLAB/simulink时域分析之响应特性分析(0基础)

热门文章

  1. windows服务应用--做个简单的定时调用EXE功能(笔记)
  2. WEB前端开发规范文档+CSS命名规范
  3. Elasticsearch 之(33)document数据建模实战_文件搜索_嵌套关系_父子/祖孙关系数据...
  4. BigDecimal.divide方法
  5. 记录一次浏览器主页被劫持的经历
  6. eclipse引入jar类包的源代码
  7. Linux内核分析学习心得
  8. SQL中GROUP BY语句介绍
  9. 2.5.1 命令与参数
  10. c# 中实用包,实用dll。