本文主要来源于吴恩达《深度学习与神经网络》。本文根据课程内容作一个串联。html
本文内容安排以下:python
咱们以一个分类问题做为研究背景。研究问题为判断输入图片是否为猫咪的二分类。算法
在解决问题以前,咱们先对使用的数学符号作一个定义:网络
在介绍逻辑回顾处理图片分类。咱们处理的问题是二分类,输入一张图片判断图片中是否有猫。输入图片格式为RGB三色图,像素取值为0~255。app
逻辑回归用于处理二分类问题。逻辑回归中\(\hat{h} = P(y=1|x)\)用于计算输入样本为1的几率。以单个样本为例,其计算公式为函数
其中,\(x \in R^{n_x}\), \(w \in R^{n_x}\) ,\(b \in R\)。输出结果的取值范围为[0, 1]。oop
逻辑回归实际上是线性回归的进一步加工,线性回归计算结果的取值范围为\((-\infty, +\infty)\),咱们将线性回归的计算结果使用sigmoid将范围压缩到[0, 1].学习
Sigmoid是一种非线性的S型函数,取值范围在[0, 1],这种输出值能够别理解为几率表示。Sigmoid函数的计算公式和曲线以下。优化
从上图能够看出,sigmoid取值范围为[0, 1],当自变量z很是小时,sigmoid趋近于0;当z很是大时,sigmoid趋近于1(实际上当z=10时,输出值为0.9999,很是趋近于1)。spa
咱们如今知道了如何使用逻辑回归计算一个样本为正例的几率,那么如何评估模型的好坏呢?这就依赖于损失函数。
给定一个样本\((x^{(i)}, y^{(i)})\),使用逻辑回归计算这个样本为正例的几率P(y=1|x),
理想状况下,输出结果\(\hat y\)应该和样本标签y尽量相等,即\(\hat y^{(i)} \approx y^{(i)}\)
当y=1时,\(L(\hat y, y)=-log\hat y\);当y=0时,\(L(\hat y, y) = -log(1-\hat y)\).
在所有训练样本上,损失函数cost function为
损失函数是参数w,b的函数,咱们想要经过最小化损失函数找到最佳的参数w,b,最后用于样本的预测[经过最小化损失函数,咱们能够保证预测结果与真实样本标签之间差距尽量小,进而保证预测结果的准确性]。
LR损失函数可使用最大似然估计来进行推导。
知道了模型的损失函数,接下来就是经过最小化损失函数获得最终的参数w,b。经常使用的方法是使用梯度降低法,使用当前位置的偏导数对参数进行更新,反复屡次后,损失函数到达最低点,此时w,b即为最终结果。
使用梯度降低算法,w,b的更新公式以下:
其中,\(\alpha\)为学习率,含义是每次参数更新的步幅;若是\(\alpha\)过大,致使参数更新幅度过大,可能会错过模型的最优值;若是\(\alpha\)过下,致使每次更新幅度很小,模型须要更多的迭代次数才能收敛。在程序代码中,咱们使用dw表示\(\frac{\partial J(w, b)}{\partial w}\), db表示\(\frac{\partial J(w, b)}{\partial b}\).
神经网络的计算过程通常分为两个阶段:前向传播和反向传播。使用计算图来描述计算过程更清晰:将整个计算过程分步骤进行计算。
假设J(a, b, c) = 3(a + bc),其中a=5, b=3, c=2.这个计算过程可使用计算图来描述,如:
设定u = bc, v = a + u, J=3v.
反向传播过程,须要计算da, db, dc.此时,能够经过计算图依据链式法则进行计算。
在计算图中,蓝色线为前向传播计算过程,红色线为反向传播计算过程。
经过上面的计算图咱们知道了神经网络的计算流程。下面咱们使用计算图来描述单个样本的逻辑回归的计算过程,而后扩展到m个样本上;以后介绍LR的优化过程,即向量化。
单个样本的逻辑回归计算公式以下:
咱们假设训练样本x的维度为2(有两个特征x一、x2)。
描述逻辑回归的loss函数的计算图将运算过程分为3步, 分别为计算z、\(\hat y\),以及L(a,y)。
逻辑回归的参数更新法则以下:
所以,接下来的计算过程主要集中在偏导数\(\frac{\partial L}{\partial w_1}\), \(\frac{\partial L}{\partial w_2}\)以及\(\frac{\partial L}{\partial b}\)的计算。
从计算图来看:
在反向传播过程当中根据链式法则,咱们能够知道
知道了单个样本的反向传播过程,接下来咱们将样本数扩展到m个,看看计算有什么变化。
对于m个样本,逻辑回归的cost function计算过程以下:
对应的偏导数为:
\(\frac{\partial J}{\partial w_1} = \frac1{m}*\sum_{i=1}^m(a^{(i)}-y^{(i)})*x_1^{(i)}\)
\(\frac{\partial J}{\partial w_2} = \frac1{m}*\sum_{i=1}^m(a^{(i)}-y^{(i)})*x_2^{(i)}\)
\(\frac{\partial J}{\partial b} = \frac1{m}*\sum_{i=1}^m(a^{(i)}-y^{(i)})\)
其实就是将m个样本的偏导数求和,而后取平均。
使用伪代码描述这个过程以下:
J=0; dw1=0; dw2=0; db=0 for i = 1 to m: # 前向传播计算损失函数 z(i) = w * x(i) + b a(i) = sigmoid(z(i)) J += -[y(i)loga(i) + (1-y(i))log(1-a(i))] # 反向传播计算导数 dz(i) = a(i) - y(i) dw1 += dz(i)*x1(i) # x1(i):第i个样本的第一个特征 dw2 += dz(i)*x2(i) db += dz(1) # 遍历完m个样本,计算梯度均值 J /= m dw1 /= m dw2 /= m db /= m
梯度计算完成后,对参数进行一次更新:
w1 -= alpha * dw1 w2 -= alpha * dw2 b -= alpha * db
这个过程是对样本集的一次遍历,梯度降低算法能够规定遍历的次数,遍历n次后整个梯度降低过程就完成了。
整个计算过程当中,使用的是显示的for循环,咱们可使用矩阵运算来对整个计算过程进行优化。
Z计算: \(z = w^Tx+b\)
对于单个样本,\(z = w^Tx + b\); 其中, \(w \in R^{n_x},x \in R^{n_x}, b \in R\)
for-loop形式
z = 0 for i in range(n_x): z += w[i]*x[i] z += b
向量形式
import numpy as np z = np.dot(w.T, x) + b
对于m个样本,z的计算结果为一个向量。$X \in R^{n_x * m},w \in R^{n_x} $
for-loop 方法
z = np.zeros((1, m)) for i in range(m): for j in range(n_x): z[i] += w[j]*X[j][i]
向量形式
z = np.dot(w.T, X)
使用矩阵运算后的LR计算过程以下:
# w: [n_x, 1]; x: [n_x, m], b: float Z = np.dot(w.T, X) + b # [1, m] A = sigmoid(Z) # 反向传播计算梯度dw, db dZ = A -Y dw = 1./m * X * dZ.T db = 1./m * np.sum(dZ) # 参数更新 w -= learning_rate * dw b -= learning_rate * db
使用矩阵运算,减小了对样本的for训练遍历以及对梯度计算过程当中对参数的遍历。
Whenever possible, avoid explicit for-loops.
值得注意的是,这里关于非参数的矩阵表示,如训练样本矩阵X,标签矩阵Y都是以列的方式进行堆叠而成的。矩阵运算将for循环集中在一次计算过程当中完成。
从某种角度上说,逻辑回归LR也能够看做一种神经网络,示意图以下。
中间的神经元完成两种运算,分别为z和a。
浅层神经网络示意图以下,其中每一个“圆圈”的运算相似于LR,区别在于第二步a的计算中使用的激活函数不一样。LR激活函数为sigmoid,这里能够为relu、tanh、sigmoid等等。
这个神经网络有输入层、隐藏层和输出层三层组成,可是通常状况下输入层忽略不计,因此这个神经网络有2层组成。
咱们这里设定\(w_i^{[l]}\)表示神经网络第l层的第i个神经元的权重参数。对于单个样本而言,这个浅层神经网络的计算过程以下:
在隐藏层:
\(z_1^{[1]} = w_1^{[1]T}*x + b_1^{[1]},\ a_1^{[1]} = \sigma(z_1^{[1]});\)
\(z_2^{[1]} = w_2^{[1]T}*x + b_2^{[1]},\ a_2^{[1]} = \sigma(z_2^{[1]});\)
\(z_3^{[1]} = w_3^{[1]T}*x + b_3^{[1]},\ a_3^{[1]} = \sigma(z_3^{[1]});\)
\(z_4^{[1]} = w_4^{[1]T}*x + b_4^{[1]},\ a_4^{[1]} = \sigma(z_4^{[1]});\)
输出结果获得一个[4, 1]向量:[\(a_1^{[1]};a_2^{[1]};a_3^{[1]};a_4^{[1]}\)]. 咱们使用\(a^{[1]}\)表示这个结果,同时做为输出层的输入继续计算。
输出层计算结果:
\(z_1^{[2]} = w_1^{[2]T}*a^{[1]} + b_1^{[2]}, \hat y=a^{[2]} = \sigma(z^{[2]})\)
使用矩阵表示整个计算过程以下,隐藏层的参数用\(W^{[1]}\)表示,由隐藏层各个神经元对应权重参数以行的方式堆叠而成,这里形状为[4, 3] (权重参数的第一维度为本层神经元的数目,另外一个维度为上一层网络的神经元数目)
单个样本的矩阵表示计算过程以下:
\(z^{[1]} = W^{[1]}x + b^{[1]}\)
\(a^{[1]} = \sigma(z^{[1]})\)
\(z^{[2]} = W^{[2]}a^{[1]} + b^{[2]}\)
\(a^{[2]}=\sigma(z^{[2]})\)
若是将样本数扩展到m个,使用for循环的计算过程为:
for i = 1 to m: z[1](i) = W[1]x(i) + b[1] a[1](i) = sigma(z[1](i)) z[2](i) = W[2]a[1](i) + b[2] a[2](i) = sigma(z[2](i))
若是使用矩阵运算,咱们设定m个训练样本以列的方式进行堆叠,用X表示,形状为[3, m]。使用矩阵运算过程以下,
Z[1] = W[1]X + b[1] A[1] = sigma(Z[1]) Z[2] = W[2]A[1] + b[2] A[2] = sigma(Z[2])
示意图以下:
反向传播主要用于计算梯度dw1, dw2, dw3, db.为了方便理解,咱们先用for循环进行介绍,以后再使用矩阵进行计算优化。
单个样本
计算过程相似于逻辑回归的反向传播过程。
\(dz^{[2]} = a^{[2]} - y\)
\(dW^{[2]} = dz^{[2]} * \frac{\partial dz^{[2]}}{\partial W^{[2]}} = dz^{[2]} * a^{[1]T}\)
$db^{[2]} = dz^{[2]} * \frac{\partial dz^{[2]}}{\partial b^{[2]}} = dz^{[2]} $
\(dz^{[1]} = dz^{[2]} * \frac{\partial dz^{[2]}}{\partial a^{[1]}} * \frac{\partial a^{[1]}}{\partial z^{[1]}} = W^{[2]T}*dz^{[2]} * g^{[1]^{'}}(z^{[1]})\)
\(dW^{[1]} = dz^{[1]} * \frac{\partial dz^{[1]}}{\partial W^{[1]}} = dz^{[1]} * x^T\)
\(db^{[1]} = dz^{[1]} * \frac{\partial dz^{[1]}}{\partial b^{[1]}} = dz^{[1]} * 1 = dz^{[1]}\)
对应的向量形式为(将m个样本堆叠在一块儿,一同计算):
深层神经网络是指包括多个隐藏的神经网络模型。如
深层神经网络计算过程相似于浅层神经网络,分为前向传播计算loss,反向传播计算梯度,而后更新权重;反复更新直到模型收敛。
模型的前向传播郭恒比较简单,咱们接下来主要介绍模型的反向传播。以神经网络的某一层为例:
Input: \(da^{[l]}\)
Output: \(da^{[l-1]}, dW^{[l]}, db^{[l]}\)
咱们知道前向传播过程当中:
\(z^{[l]} = W^{[l]}*a^{[l-1]} + b^{[l]}\)
\(a^{[l]} = g(z^{[l]})\)
那么,
\(dz^{[l]} = da^{[l]} * g^{[l]'}(z^{[l]})\)
\(da^{[l-1]} = W^{[l]T} * dz^{[l]}\)
\(dW^{[l-1]} = dz^{[l]} * a^{[l-1]}\)
\(db^{[l-1]} = dz^{[l]}\)
获得\(da^{[l-1]}\)以后,咱们能够继续往前传播。
为了方便运算,咱们能够在前向传播过程当中保存计算结果\(g(z^{[l]})\)。
深度神经网络的计算图能够描述以下。
神经网络的前向传播和反向传播计算过程能够总结以下:
本文自下而上的对神经网络进行了介绍。首先,从逻辑回归开始介绍其计算过程、反向传播、更新方法,在介绍过程当中先以单个样本的计算开始,而后扩展到m个样本,以后为了提升计算速度,采用向量化方法进行计算;咱们了解了逻辑回归以后,介绍浅层神经网络。浅层神经网络是一个2层神经网络,每层神经网络的神经元能够看作是一个“逻辑回归”计算单元,区别在于使用的激活函数不一样。浅层神经网络的介绍也是先从单个样本开始,经过单个样本明白其计算过程,而后扩展到m个样本,最终使用向量化方式完成计算。最后,介绍深层神经网络,深层神经网络只是增长了隐藏层的数目,其计算过程和浅层神经网络十分类似。
欢迎关注个人公众号,一同窗习成长。