本系列文章是吴恩达深度学习攻城狮系列课程的笔记,分为五部分。
这一部分讲了深度学习和神经网络的最基础的概念,这一章尤为重要,尤其是要理解神经网络的合理性,建立直觉。
我的笔记不同于一般的笔记,我的笔记更加凝练,除了结论以及公式,更多的是对知识的理解,结合课程可以加速理解,省去很多时间,但是请注意,笔记不能替代课程,应该结合使用。
结构化机器学习项目,我建议放在最后看。
首先学这一节对你后面的学习没有影响,我就是跳过去学的。而且他更多的讲的是策略,尤其是举了很多后面的例子,你听了不仅不太好懂,而且没啥意思,所以我建议放在最后看。
神经网络与深度学习(Neural Networks and Deep Learning)
改善深层神经网络:超参数调整,正则化,最优化(Hyperparameter Tuning)
卷积神经网络(Convolutional Neural Networks)
序列模型与循环神经网络(Sequence Models)
结构化机器学习项目(Structuring Machine Learning Projects)
梯度下降的公式为:
w = w − α d w w=w-\alpha dw w=w−αdw
这让我们想到牛顿法:
x = x − f ( x ) f ′ ( x ) x=x-\dfrac{f(x)}{f^\prime(x)} x=x−f′(x)f(x)
这两个有什么区别呢?思想都是迭代,但是实际完全不一样,最简单的场景:
我们从 x 0 x_0 x0开始跑,就会发现,最后gradient-descent会收敛到 x g x_g xg但是牛顿法收敛到 x n x_n xn
虽然方向都是导数负方向,但是步长是这两个方法的本质区别“”
使用计算图+链式法则求导,省略部分步骤,直接到关键步
避免使用显式的for loop,而是改用numpy的向量和矩阵运算函数,其中内置了大量的加速算法,以及调用多线程,充分利用CPU以及GPU的计算资源,可以将性能提高百倍以上。
总体流程为fp: w , b , X − > Z , σ − > A w,b,X->Z,\sigma->A w,b,X−>Z,σ−>A,bp: A , Y − > d Z , X − > d w , d b A,Y->dZ,X->dw,db A,Y−>dZ,X−>dw,db, 将 w 和 b 将w和b 将w和b迭代然后不断循环,直至足够准确。
损失函数 L ( a , y ) = − [ y log ( a ) + ( 1 − y ) log ( 1 − a ) ] L(a,y)=-[y\log(a)+(1-y)\log(1-a)] L(a,y)=−[ylog(a)+(1−y)log(1−a)]
成本函数
定义 a = P ( y = 1 ∣ X ) a=P(y=1|X) a=P(y=1∣X),即给定样本下得出y=1的概率。那么,反过来。 P ( y = 0 ∣ X ) = 1 − a P(y=0|X)=1-a P(y=0∣X)=1−a,即,给定X得出y=0的概率为1-a
对于单个样本,即 X X X,他的真实结果不是0,就是1,也就是说,是两点分布。那么我们可以写出 P ( y ∣ X ) = a y ( 1 − a ) 1 − y P(y|X)=a^y(1-a)^{1-y} P(y∣X)=ay(1−a)1−y,这是个很经典的两点分布写法,分别取y=1和0,可以得出我们最开始的两种情况。
然后左右两边同取log(实际上是ln),得 log ( P ) = y a + ( 1 − y ) ( 1 − a ) \log(P)=ya+(1-y)(1-a) log(P)=ya+(1−y)(1−a),因为我们用梯度下降,是要最小化,所以为了最大化概率P,我们要在损失函数前加负号,这样,当我们把损失函数最小化,那么里面的非负部分就是最大化的了,即P最大。
成本函数使用极大似然估计推导。
首先,假设m个样本都是独立同分布的,这个应该在找样本的时候就确保好,然后我们就可以用最大似然估计了。
P ( X ∣ θ ) = ∏ P ( y i ∣ X i ) P(X|\theta)=\prod P(y^i|X^i) P(X∣θ)=∏P(yi∣Xi),然后用最大似然估计的套路,左右取ln,得出 log P ( X ∣ θ ) = − ∑ L ( a i , y i ) \log P(X|\theta)=-\sum L(a^i,y^i) logP(X∣θ)=−∑L(ai,yi),为了使P最大,需要令 ∑ L ( a i , y i ) \sum L(a^i,y^i) ∑L(ai,yi)最小,出于某种原因,我们给他前面加了一个常数来进行一个缩放,最后就是 J ( w , b ) = 1 m ∑ L ( a i , y i ) J(w,b)=\dfrac{1}{m}\sum L(a^i,y^i) J(w,b)=m1∑L(ai,yi)
其实这个也可以直观理解。
让所有样本的平均损失最小,不就整体最优了嘛。
设X=A{[0]},\hat{Y}=A{[L]},则逐层计算,这个for loop现在没有办法避免:
for i = 1 to L:
Z [ i ] = W [ i ] A [ i − 1 ] + B [ i ] Z^{[i]}=W^{[i]}A^{[i-1]}+B^{[i]} Z[i]=W[i]A[i−1]+B[i]
A [ i ] = g ( Z [ i ] ) A^{[i]}=g(Z^{[i]}) A[i]=g(Z[i])
这个式子可以分块理解,还原他们堆叠之前的状态,然后这个分块列向量乘以分块行向量再加B向量(广播后实际为矩阵),出来一个矩阵,这个矩阵每行对应于单节点的logistic regression,然后垂直堆叠起来一层的结果。
我们换个角度理解这个产生的矩阵,经过sigmoid函数作用后生成的A矩阵,如果从列来看,实际上每一列都相当于一个样本 X ( i ) X^{(i)} X(i)经过一层神经网络后产生的新样本,只不过该样本的维数(长度)变成了当前层神经元的个数,但是很明显,样本数量没有变化。
也就是说:
节点数 n [ i ] n^{[i]} n[i]=参数矩阵 W [ i ] W^{[i]} W[i]的高度=样本矩阵 A [ i ] A^{[i]} A[i]的高度.
以上随着神经网络的层而变化。
但是:
A [ i ] 矩阵的宽度 ≡ 初始样本数 A^{[i]}矩阵的宽度\equiv 初始样本数 A[i]矩阵的宽度≡初始样本数
以上不随层而变化。
我们从更高层的角度去理解W和Z,B的形状:
B和W是按照神经元垂直堆叠的,所以这两个的 高度 ≡ 当前层神经元个数 高度\equiv 当前层神经元个数 高度≡当前层神经元个数
然后因为激活函数不改变形状,所以实际上结果 A ∼ Z ∼ W W W ⋯ X A\sim Z\sim WWW\cdots X A∼Z∼WWW⋯X,因为最右矩阵是X,所以A,Z矩阵的宽度恒定为m
至于W的宽度,这个根据上一层的n定。
最后,不管你有多少层,最终还是输出了一个 A m × 1 A_{m\times 1} Am×1,因此,Lost和Cost的计算方法完全相同。
d Z n [ i ] × m [ i ] = { A [ i ] − Y , i = L d A [ i ] ∗ g [ i ] ′ ( Z [ i ] ) , i ≠ L , ∗ 为 e l e m e n t − w i s e 逐元素相乘 dZ^{[i]}_{n^{[i]}\times m}= \begin{cases} A^{[i]}-Y, & i=L \\ dA^{[i]}*g^{[i]\prime}(Z^{[i]}), & i\neq L,*为element-wise逐元素相乘 \end{cases} dZn[i]×m[i]={A[i]−Y,dA[i]∗g[i]′(Z[i]),i=Li=L,∗为element−wise逐元素相乘
其中,dA的计算是反向递归的,要给一个递归初始值
d A [ i − 1 ] = { [ − y ( 1 ) a ( 1 ) + 1 − y ( 1 ) 1 − a ( 1 ) , ⋯ , − y ( m ) a ( m ) + 1 − y ( m ) 1 − a ( m ) ] 1 × m , i = L W [ i ] T d Z [ i ] , i ≠ L dA^{[i-1]}= \begin{cases} [-\dfrac{y^{(1)}}{a^{(1)}}+\dfrac{1-y^{(1)}}{1-a^{(1)}},\cdots,-\dfrac{y^{(m)}}{a^{(m)}}+\dfrac{1-y^{(m)}}{1-a^{(m)}}]_{1\times m},& i=L \\ W^{[i]T}dZ^{[i]},& i\neq L \\ \end{cases} dA[i−1]=⎩ ⎨ ⎧[−a(1)y(1)+1−a(1)1−y(1),⋯,−a(m)y(m)+1−a(m)1−y(m)]1×m,W[i]TdZ[i],i=Li=L
第一个式子可以迁移,第二个式子直观理解只能通过维数来理解他的合理性。
d W n [ i ] × n [ i − 1 ] [ i ] = 1 m d Z [ i ] A [ i − 1 ] T dW^{[i]}_{n^{[i]}\times n^{[i-1]}}=\dfrac{1}{m} dZ^{[i]}A^{[i-1]T} dWn[i]×n[i−1][i]=m1dZ[i]A[i−1]T
这个可以迁移理解,在Logistic Regression里, d w = 1 m X d Z T dw=\dfrac{1}{m}XdZ^T dw=m1XdZT,而我们这里的W矩阵是若干个 w T w^T wT纵向堆叠而成,所以我们要做一个转置。
d B n [ i ] × 1 [ i ] = 1 m n p . s u m ( d Z [ i ] , a x i s = 1 , k e e p d i m s = T r u e ) . r e s h a p e ( n [ i ] , 1 ) dB^{[i]}_{n^{[i]}\times 1}=\dfrac{1}{m} np.sum(dZ^{[i]},axis=1,keepdims=True).reshape(n^{[i]},1) dBn[i]×1[i]=m1np.sum(dZ[i],axis=1,keepdims=True).reshape(n[i],1)
这个如此理解,对每一个节点,我们都要对所有样本进行均值,所以进行横向求均值,形成若干个b堆叠而成的向量,最后一层的B就是一个实数。
写到这里,我不由得感叹矩阵的强大,真tm哪个小天才能想出这种玩意,能让公式随着维数的增加而保持形式稳定,太离谱了!
其实可以看出来,除了最后一层有点特殊以外,每一层的处理方式都是相同的,那可不可以编写一个函数去一次性处理一层的任务呢?
可以,以下是流程图:
Input: A [ i − 1 ] A^{[i-1]} A[i−1]
Process:
Z [ i ] = n p . d o t ( W [ i ] , A [ i − 1 ] ) + B [ i ] Z^{[i]}=np.dot(W^{[i]},A^{[i-1]})+B^{[i]} Z[i]=np.dot(W[i],A[i−1])+B[i]
A [ i ] = g [ i ] ( Z [ i ] ) A^{[i]}=g^{[i]}(Z^{[i]}) A[i]=g[i](Z[i])
Cache: Z [ i ] Z^{[i]} Z[i]
Output: A [ i ] A^{[i]} A[i]
Input: d A [ i ] dA^{[i]} dA[i]
Process:
d Z [ i ] = d A [ i ] ∗ g [ i ] ′ ( Z [ i ] ) dZ^{[i]}=dA^{[i]}*g^{[i]\prime }(Z^{[i]}) dZ[i]=dA[i]∗g[i]′(Z[i])
d W [ i ] = 1 m n p . d o t ( d Z [ i ] , A [ i − 1 ] T ) dW^{[i]}=\dfrac{1}{m}np.dot(dZ^{[i]},A^{[i-1]T}) dW[i]=m1np.dot(dZ[i],A[i−1]T)
d B [ i ] = 1 m n p . s u m ( d Z [ i ] , a x i s = 1 , k e e p d i m s = T r u e ) dB^{[i]}=\dfrac{1}{m}np.sum(dZ^{[i]},axis=1,keepdims=True) dB[i]=m1np.sum(dZ[i],axis=1,keepdims=True)
d A [ i − 1 ] = n p . d o t ( W [ i ] T , d Z [ i ] ) dA^{[i-1]}=np.dot(W^{[i]T},dZ^{[i]}) dA[i−1]=np.dot(W[i]T,dZ[i])
Output: d A [ i − 1 ] , d W [ i ] , d B [ i ] dA^{[i-1]} , dW^{[i]} , dB^{[i]} dA[i−1],dW[i],dB[i]
赋值 A [ 0 ] = X A^{[0]}=X A[0]=X
不断调用fp函数,生成A和Z
赋值 d A [ L ] = [ − y ( 1 ) a ( 1 ) + 1 − y ( 1 ) 1 − a ( 1 ) , ⋯ , − y ( m ) a ( m ) + 1 − y ( m ) 1 − a ( m ) ] 1 × m dA^{[L]}=[-\dfrac{y^{(1)}}{a^{(1)}}+\dfrac{1-y^{(1)}}{1-a^{(1)}},\cdots,-\dfrac{y^{(m)}}{a^{(m)}}+\dfrac{1-y^{(m)}}{1-a^{(m)}}]_{1\times m} dA[L]=[−a(1)y(1)+1−a(1)1−y(1),⋯,−a(m)y(m)+1−a(m)1−y(m)]1×m
反向调用bp函数,生成dA,dW,dB,更新W,B矩阵
首先,W不能对称,即W的行不能相同。如果有相同,那这两个神经元就造成了浪费,如果完全对称,那么每层神经元就相当于一个神经元
然后,乘一个系数调整使得权重足够小,防止Z矩阵元素过大导致sigmoid或者tanh函数饱和,从而拖慢学习速度。
B其实随便,因为W已经随机了
首先,从图像识别来看,神经网络就相当于从细微的特征入手,然后逐层组装,最后合成一个目标特征。
然后,深层神经网络可以在计算复杂问题的时候有效降低神经元规模,用深度换取空间复杂度。这个起源于电路理论。
emm,我其实也不太理解,看了几个小文章,大概理解了:逐层抽象提取分类,可以让简单的特征被下一层复用,有一种类似于通过动态规划来降低递归的重复计算的作用。暂时这么理解吧。