Neural Networks and Deep Learning

Neural Networks Basics

What is a Neural Network?

在这里我们使用房价预测作为模型

当我们处理一组零散的房价信息并绘制房价图时,对于图上的数据,我们想到利用线性回归画出直线

image-20220320194856427

但我们发现,这条直线的前方明显是的,但很明显,房价永远都不会是负的,我们选择添加拟合函数来表示这个房价图

image-20220320195042174

而这个实现功能的拟合函数,就是一个非常简单的神经网络

image-20220320195229292

中间的节点,就类似于一个神经元,这样,我们的网络就实现了左边函数的功能,神经元的功能,就是接受输入的值,对其进行线性运算,取不小于0的值,最后得出预测的价格

而左边的函数在DL中非常常见,先是0,后是一条直线我们将其称为“修正线性单元”(Rectified linear unit, relu)

image-20220320200011063

其中的“修正”,即使指过滤值为0的数

回到原题,大的神经网络就是由多个孤立的神经元“组合”而成的

image-20220320200624890

中间的节点被叫做“隐藏单元”


Supervised Learning with Neural Networks

目前比较有价值的DL,都基于一种ML,我们称为“监督学习”(Supervised Learning)

image-20220320201425661

  • 对于图像,我们经常应用的是卷积神经网络(CNN)
  • 对于序列数据,例如含有时间成分的音频,我们会根据时间将其表示为一维时间序列,我们常用的是循环神经网络(RNN)
  • 等等

下面是几个网络的结构示意

image-20220320202044023

结构化与非结构化

image-20220320202258455

结构化一般是指数据库

非结构化一般是指如音频、图像、文本此类包含多种复杂信息的文件,例如图像的像素、文本中的某个单词


Binary Classification(二分分类)

我们以一张图为例

image-20220320214428924

对于这张图,我们想提取它的标签,如果图中有猫,就返回”1“,否则返回“0”

怎样处理数据呢?我们用”y”表示输出的结果标签

image-20220320220432493

计算机在保存图片时,会将其保存为3个独立矩阵,分别对应图片的RGB三个通道

我们定义一个“特征向量” —— x,要将像素的亮度值放进特征向量中,就是把这些像素值都提取出来,放入”x“中

image-20220320223535254

最终得到了一个包含RGB各个像素的很长的特征向量,而如果图片为64 64的,那么向量x的总维度即为64 64 * 3

image-20220320223808141

我们用’nx’来表示输入的特征性向量的维度

回到正题,在二分分类问题中,我们的目标是训练一个分类器,它以图片的特征向量x作为输入

,以此来预测结果

在这里我们再偏题一下,介绍一下常用的一些符号

  • (x, y)

    • 表示一个单独的样本,x时nx维的特征向量,标签y为预测结果(上题中即为0或1)
  • m

    • 表示训练样本的数量
  • (x^(1), y^(1))

    • 表示样本1的输入和输出
  • image-20220320224658498

    • 强调测试数据的个数
  • image-20220320224806998

    • nx * m 的矩阵X (xxx.shape()就是用来输出矩阵的维度的)
  • image-20220320225012180


Logistic Regression

对于一张猫图,我们希望given一个x,获取它所对应的预测值

image-20220320225620333

我们已知的Logistic回归的参数为

  • x —— 输入值(转置的矩阵)
  • w —— 一个n_x维向量
  • b —— 实数

如何计算“y帽”?

image-20220320225855415

x的线性函数?—— 但这不是一个非常好的二元分类算法,这样算出来的结果可能比1大得多,甚至可能是负值,这样是没意义的

因此,在Logistic回归中,我们将sigmoid()函数加在上面

image-20220320230153739

下面是sigmoid(z)的图形 —— 一个从零到一的光滑曲线

image-20220320230314727

然后是它的式子

image-20220320230435627


Logistic Regression cost function

为了训练Logistic回归中的参数b和w,需要定义一个cost function(成本函数)

image-20220320231512675

我们想通过传入的训练集,找到参数w和b

要做到这点,我们需要记录函数的loss functioin(损失/误差函数),来衡量算法的运行情况

我们首先尝试将其值等于

image-20220320231824798

但这样写的话,我们会发现之后讨论的优化问题都会变成非凸的,最后会得到多个局部最优解,梯度下降法,可能找不到全局最优值,因此我们选择使用如下函数

image-20220320233249955

image-20220320233446727

注意,损失函数是在单个训练样本中定义的,用来衡量单一训练样例的结果,因此最终我们将定义一个成本函数,去衡量参数w和b在全体训练样本上的表现

成本函数:

image-20220321141538089

在训练模型时,我们就要找出合适的b与w,让下面的成本函数尽可能的小


Gradient Descent(梯度下降法)

我们的目标:找到使其对应的成本函数为最小值的w和b

像下图一样,成本函数J就像一个“大碗”,是一个凸函数

image-20220321141742674

梯度下降法所做的就是,从初始点开始,朝最陡的下坡方向走一步,并通过多次迭代到达全局最优解

为了简化思考,我们先省略b,使用一维图像来分析

image-20220321143049282

为了更新w,我们将会重复进行以下操作:(:= —— 更新)

$w := w - \alpha \frac{d J(w)}{d(w)}$

$\alpha$表示学习率,它可以控制每一次迭代

在二维图像中,我们也是通过这个公式对w和b进行更新优化的

$w := w - \alpha \frac{d J(w, b)}{d(w)}$ $b := b - \alpha \frac{d J(w, b)}{d(b)}$

Logistic Regression Gradient descent

首先来复习一下logistic回归的公式

image-20220321153756722

其中,a是logistic回归的输出,y是样本的基本真值标签值

上述公式的流程图(正向传播)表示

image-20220321154201937

负向传播图示:

image-20220321171203553


Vectorization(向量化)

我们通过向量化来消除代码中的显式for循环

当我们计算$z = w^Tx + b$时(w与x都为列向量),如果我们使用非向量化手段去实现,我们需要使用for循环,而在处理大量数据时,会导致运行太慢的问题,因此我们选择使用向量化手段

在python或者numpy中,我们需要使用命令z = np.dot(w, x),计算$w^Tx$,下面是两种写法的代码对比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import numpy as np

a = np.array([1, 2, 3, 4])
print(a)

import time

a = np.random.rand(1000000)
b = np.random.rand(1000000)

# 记录当前时间
tic = time.time()
c = np.dot(a, b)
toc = time.time()

print(c)
print("Vectorized version:" + str(1000 * (toc - tic)) + 'ms')

c = 0
tic = time.time()
for i in range(1000000):
c += a[i] * b[i]
toc = time.time()

print(c)
print('For loop:' + str(1000 * (toc - tic)) + 'ms')

对比的运行时间如下:

image-20220321165722544

当需要对很多元素进行运算时,numpy里的方法会帮助我们很轻松的完成目的

image-20220321170754722


Vectorizing Logistic Regression (向量化Logistic回归)

我们需要进行正向传播,如下所示

image-20220321171603164

我们的目标是不通过显式的for循环,获取输出结果,而事实上,仅需一行代码,就能实现我们的目的

我们定义一个“nx * m”的矩阵,

再次定义一个“1 * m”的矩阵(行向量)[b b b … b]

image-20220321172006377

而这个行向量可以表示为$w^TX + $$
\begin{bmatrix}
b&b&b&…&b\
\end{bmatrix}
$

以第一项为例,它可以表示为w的转置乘$x^(1^)$再加b

image-20220321175321963

Z就是z变量堆叠后得到的变量

为了计算$w^TX + $$
\begin{bmatrix}
b&b&b&…&b\
\end{bmatrix}
$,numpy的指令即为=

image-20220321175718081

在运算中,当我们把向量加上一个实数时,Python会自动把实数b拓展成1 * m的行向量,这即是Python中的Broadcasting(广播)


Vectorizing Logistic Regression’s Gradient Computation(向量化logistic回归的梯度输出)

本节的学习目标为学会同时计算m个训练数据的梯度

以下非向量化和向量化的对比

image-20220321192342197

image-20220321193448186

尽管我们多次强调避免for循环,但是如果希望多次迭代运行,梯度下降,我们仍然需要for循环


Broadcasting in Python

我们以下题为例

Apples Beef Eggs Potatoes

$
\begin{bmatrix}
56.0&0.0&4.4&68.0\1.2&104.0&52.0&8.0\1.8&135.0&99.0&0.9
\end{bmatrix}
$

第一行为Carbs,第二行为Protein,第三行为Fat

我们要求各个食物的Carbs含量,即分别使用其Carbs/总量,在这里我们为了避免使用for循环计算每一列的和,我们将其视作一个3 * 4的矩阵A,使用一行Python代码对各列求和,再用第二行代码,让四列的每一列都除以对应的和

image-20220321200537125

在当你运算$
\begin{bmatrix}
1\2\3\4
\end{bmatrix}+100
$时,Python会将这个数自动展开为一个1*4向量$
\begin{bmatrix}
100\100\100\100
\end{bmatrix}
$,最终它们可以运算为$
\begin{bmatrix}
101\102\103\104
\end{bmatrix}
$这个向量,这就是广播的一种应用

再举个例子$
\begin{bmatrix}
1&2&3\4&5&6
\end{bmatrix}
+
\begin{bmatrix}
100&200&300
\end{bmatrix}
$时,Python会自动将其转化为2*3的$
\begin{bmatrix}
100&200&300\100&200&300
\end{bmatrix}
$矩阵


A note on python / numpy vectors

image-20220321203533236

声明,确保是一个向量

image-20220321203739767


Explanation of logistics regression cost function

image-20220321205207768

我们将两个条件概率公式合并为下面的一个

image-20220321205248086

用log来表示最小化损失函数

image-20220321205542827


Shallow Neural Networks

Neural Network Overview

image-20220321224334950



Neural Network Representation

我们从只有一个隐藏层的神经网络看起

image-20220321224705869

我们来对其命名一下,将x1、x2、x3所在的层叫做“输入层”,中间一层称为“隐藏层”,右面只有一个节点的就是“输出层”,它负责输出,预测值y帽

在一个神经网络中,当使用监督学习训练它时,训练集包含了输入x以及目标输出y,“隐藏层”的指的是,在训练集中,这些中间节点的真正数值在训练集中是看不到的

在神经网络中,我们使用中括号上标来指出值是来自于哪一层

image-20220321225530313

由于我们不把输入层看作一个标准层,上图所示的就是一个双层神经网络


Computing a Neural Network’s Output

image-20220321230022193

这里的圆圈代表了回归计算的两个步骤,首先按照步骤求出z,然后在第二步计算激活函数(sigmoid),然后不断重复

image-20220321230230791

我们来演示一下上图的部分流程

image-20220321230313775

第一步,我们选取了隐函数的第一个节点,首先计算$z = w^T + b$,当然要在上面加上标

image-20220321230557993

第二步,计算$a^{[1]}_1 = sigmoid(z^{[1]}_1)$ 即 image-20220321230807992,对于z和a,按符号约定写成$a^[1^]_1$这种结构,我们现在看的是第一隐层的第一个节点,上标表示层数,下标表示当前所在的节点,所以上下标都为1

之后,我们将目标切换为第二个节点

第一步,image-20220321231235839

第二步,$a^{[1]}_2 = sigmoid(z^{[1]}_2)$ 即 image-20220321231325708

第三和第四个节点同理

**整理**

image-20220321231532678

而我们都知道,使用for循环对z进行运算太过低效,因此我们来考虑向量化

我们将所有w的转置堆叠起来,很明显,这是由w的转置构成的行矩阵

image-20220321231928033

思路类似,我们将a的值爷堆叠起来

image-20220321232230383

在其中,sigmoid函数作用于Z的四个元素也就相当于将sigmoid函数作用

到Z的每个元素

**整理**

image-20220321232510270

前两个式子计算四个隐层中的Logistic回归单元,而输出层的Logistic回归则是由下面两个完成的


image-20220323164244959


Explanation for vectorized implementation

模拟神经网络的正向传播

image-20220323170705095


Active functions

在上述例子中,我们一直使用 sigmoid ($\sigma$) 函数作为Active functions(激活函数)

但实际上,有个函数总比它表现得更好,这即是 tahn函数,或称“双曲正切函数”

image-20220323171536180

tanh 函数几乎在所有场合都比 sigmoid 函数优越,但输出层除外

因为如果y为0或1,我们更希望y帽的值介于0和1之间,因此在解决二元分类问题时,我们可以使用 sigmoid 函数作为输出层,所以这里注意:不同层的激活函数可以是不同的

注意两个函数都有的缺点,那就是当z非常大或者非常小时,那么导数的梯度就可能会很小

在这里我们提到“修正线性单元(Relu)”,其形状如下:

image-20220323172605761

在选择激活函数时有一些经验法则,若你输出的值为0或1,sigmoid很适合作为输出层的激活函数,而其他单元都使用ReLU

现在,所谓的修正线性单元,已经成为激活函数的默认选择了

ReLU仍存在着一些缺点,即当z为负时,倒数为0

ReLU和带泄露的ReLU的好处在于,对于很多z空间,激活函数的斜率和0差的很远,因此在实践中使用,神经网络的学习速度通常会比sigmoid和tanh快(这是因为ReLU虽然有z一半的斜率为0,但在实践中,通常由足够多的隐藏单元,令z大于0,使得没有像sigmoid和tanh一样,当函数斜率接近于0时,减慢学习速度的效应,)

下面再展示一下带泄露的ReLU函数的图像

image-20220323174011431


Why do you need non-linear activation function

有很多层的神经网络,如果使用线性激活函数,或是没有激活函数,无论神经网络有多少层,一直在座的只是计算线性激活函数 ,如果你只是要这样计算,那还需要什么隐藏层呢?


Gradient descent for neural networks

本节会提供公式,帮助我们实现反向传播/梯度下降算法

下图的左边是正向传播,右边是反向传播

image-20220323204130505

这里需要注意的是np.sum()是numpy的一个函数,用来对矩阵的一个维度求和,水平相加求和,而加上开关keepdims,就是为了防止python直接输出这些秩为1的古怪数组

g是使用的隐藏层的激活函数的导数

中间的“*”,是指逐元素乘积

image-20220323203423027

实现后向传播有个技巧,即是确保矩阵的维度互相匹配

image-20220323203912460


Random Initialization

当训练神经网络时,随机初始化权重非常重要,对于logistic回归,可以将权重初始化为0,但如果将神经网络的各参数数组全部初始化为0,再使用梯度下降法,那会完全无效

将w和b全部初始化为0,会导致隐藏单元进行同样的计算(对称性),他们对输出单元的影响也一样大,即便经过迭代,同样的对称性却不会改变,隐藏单元依旧是对称的,因此此时无论训练神经网络多长时间,隐藏单元任然在计算完全一样的函数,使得多个隐藏单元没有意义,而我们需要让不同的隐藏单元去计算不同的函数,这个问题的解决方案就是随机初始化所有参数

下面是例子

image-20220323205419260

为什么我们将其乘0.01?实际上,我们通常喜欢把权重矩阵初始化非常非常小的随机值

因为在使用sigmod或者tanh函数时

image-20220323205627855image-20220323205647504

如果w过大/小,会造成z过大/小,最终落在函数的平缓部分,梯度的斜率非常小,这意味着梯度下降法会非常慢,这会让学习变得很慢


Deep Neural Networks

Deep L-layer Neural network(深层神经网络)

image-20220325134325759


Forward and backward propagation

在神经网络中,几乎每一层都有其对应的前向和反向传播步骤,本节 我们将介绍怎样实现这个

***前向传播 Forward propagation for layer l***
  • 输入 $a^{[l - 1]}$
  • 输出 $a^{[l]},\,cache(z^{[l]})$(cache — 缓存)

更新前向传播的公式是:$z^{[l]}\,=\,w^{[l]}\,*\,a^{[l-1]}\,+b^{[l]}$,$a^{[l]}\,=\,g^{[l]}(z^{[l]})$

实现向量化过程:$z^{[l]}\,=\,w^{[l]}\,*\,A^{[l-1]}\,+\,b^{[l]}$(b是python广播),$A^{[l]}\,=\,g^{[l]}(z^{[l]})$

***反向传播 Backward propagation for layer l***
  • 输入 $da^{[l]}$
  • 输出 $da^{[l-1]}$,$dW^{[l]}$,$db^{[l]}$

计算步骤:

$dz^{[l]}\,=\,da^{[l]}\,\,g^{[l]’}(z^{[l]})$,$dW^{[l]}\,=\,dz^{[l]}\,a^{[l-1]}$,$db^{[l]}\,=\,dz^{[l]}$,$da^{[l-1]}\,=\,W^{[l]T}\,*\,dz^{[l]}$

向量化:

$dz^{[l]}\,=\,dA^{[l]}\,\,g^{[l]’}(z^{[l]})$,$dW^{[l]}\,=\,\frac{1}{m}dz^{[l]}\,\,A^{[l-1]T}$,

$db^{[l]}\,=\,\frac{1}{m}np.sum(dz^{[l]},axis=1,keepdims=True)$

$dA^{[l-1]}\,=\,W^{[l]T}\,*\,dz^{[l]}$

***Summary***

image-20220325152631661


Getting your matrix dimensions right(核对矩阵维数)

image-20220325154411102

首先确定$z^{[l]}$的维度为$(n^{[l]},1)$,$x$组成的的维度为$(n^{[l-1]},1)$,要使$w^{[l]}$与$x$相乘得到的矩阵与$z^{[l]}$的形状相同,$w^{[l]}$的维度必须为$(n^{[l]},n^{[l-1]})$,而$b^{[l]}$要与其相加,因此其维度应该与$z^{[l]}$相同,为$(n^{[l]},1)$,在反向传播时需要的$dw^{[l]}$与$db^{[l]}$也是一样,但是Z、A与X的维度会在向量化后发生变化,如下图所示

image-20220325155254443


Why deep representations?(为什么使用深层表示)

摸🐟,放截图

image-20220325213753982


Building blocks of deep neural networks

image-20220325215811410


Parameters VS Hyperparameters(参数 VS 超参数)

参数:

image-20220325220023005

除了上述参数,还有其他参数,需要输入到学习算法中,比如学习率$\alpha$、隐层数$L$、隐藏单元数$n^{[l]}$或者是激活函数$sigmooid$,这些参数需要编写者来控制,但它确实影响了最后参数$W$和$b$的值,因此它们被称为超参数