神经网络的编程基础(吴恩达课程笔记)

神经网络的编程基础(吴恩达课程笔记)

2.7 计算图

  • 前向过程:计算网络的输出
  • 反向过程:计算对应的梯度或导数

2.8 使用计算图求导数

当输入变化时,知道导数可以轻松计算出输出的变化。

反向传播:链式求导法则
d J d a = d J d v ⋅ d v d a \dfrac{dJ}{da}=\dfrac{dJ}{dv}·\dfrac{dv}{da} dadJ=dvdJdadv
FinalOutputVar:简写为dJ,最终的输出变量

dvar指最终输出变量对中间变量var的导数。
d J d v a r → d v a r ( p y t h o n ) \dfrac{dJ}{dvar} \to dvar (python) dvardJdvar(python)

2.9逻辑回归中的梯度下降

z = w T x + b y ^ = a = σ ( z ) = s i g m o i d ( z ) = 1 1 + e − z L ( a , y ) = − ( y log ⁡ ( a ) + ( 1 − y ) log ⁡ ( 1 − a ) ) z = w^{T}x+b \\ \hat{y}=a=\sigma(z)=sigmoid(z)=\frac{1}{1+e^{-z}}\\ L(a,y)=-(y\log(a)+(1-y)\log(1-a)) z=wTx+by^=a=σ(z)=sigmoid(z)=1+ez1L(a,y)=(ylog(a)+(1y)log(1a))

a是logistic回归的输出,y是样本的标签值。

1. 计算导数(derivative computation)
  • 1.反向传播第一步:计算L对a的导数,使用如上的(3)式。

d a = − y a + 1 − y 1 − a da=-\frac{y}{a}+\frac{1-y}{1-a} da=ay+1a1y

  • 2.反向传播第二步:计算a对z的导数,使用如上(2)式,并化成变量为a的式子。

d a d z = a ⋅ ( 1 − a ) d z = d L d z = d L d a ⋅ d a d z = a − y d a d z = e − z ( 1 + e − z ) 2 = e − z ⋅ a 2 = 1 − a a ⋅ a 2 = a ( 1 − a ) \dfrac{da}{dz}=a·(1-a)\\ dz=\dfrac{dL}{dz}=\dfrac{dL}{da}·\dfrac{da}{dz}=a-y\\ \dfrac{da}{dz}=\frac{e^{-z}}{(1+e^{-z})^{2}}={e^{-z}}·a^{2}=\frac{1-a}{a}·a^{2}=a(1-a) dzda=a(1a)dz=dzdL=dadLdzda=aydzda=(1+ez)2ez=eza2=a1aa2=a(1a)

  • 以两个参数为例:
    z = w 1 x 1 + w 2 x 2 + b z=w_1x_1+w_2x_2+b z=w1x1+w2x2+b
  • 3.反向传播第三步:计算z对w和b的导数dw1,dw2。
    ∂ L ∂ w 1 = d w 1 = x 1 ⋅ d z ∂ L ∂ w 2 = d w 2 = x 2 ⋅ d z ∂ L ∂ b = d b = d z \dfrac{\partial L}{\partial w_1}=dw_1=x_1·dz\\ \dfrac{\partial L}{\partial w_2}=dw_2=x_2·dz\\ \dfrac{\partial L}{\partial b}=db=dz w1L=dw1=x1dzw2L=dw2=x2dzbL=db=dz
2.实现单个样本实例的梯度下降(logistic回归)(gradient descent)
  • 更新w、b,以下即为单个样本实例的一次梯度更新步骤。
    w 1 : = w 1 − α ⋅ d w 1 w 2 : = w 2 − α ⋅ d w 2 b : = b − α ⋅ d b w_1:=w_1-\alpha·dw_1\\ w_2:=w_2-\alpha·dw_2\\ b:=b-\alpha·db w1:=w1αdw1w2:=w2αdw2b:=bαdb

2.10 m个样本的梯度下降(gradient descen on m examples)

成本函数的定义
J ( w , b ) = 1 m ∑ 0 < i ≤ m L ( a ( i ) , y ( i ) ) a ( i ) = y ^ ( i ) = σ ( z ( i ) ) = σ ( w T x ( i ) + b ) J(w,b)=\frac{1}{m}\sum_{0<i \le m}{L(a^{(i)},y^{(i)})}\\ a^{(i)}=\hat{y}^{(i)}=\sigma(z^{(i)})=\sigma(w^Tx^{(i)}+b) J(w,b)=m10<imL(a(i),y(i))a(i)=y^(i)=σ(z(i))=σ(wTx(i)+b)
成本函数实际上是1到m项损失函数和的平均。
∂ J ( w , b ) ∂ w 1 = 1 m ∑ 0 < i ≤ m ∂ L ( a ( i ) , y ( i ) ) ∂ w 1 \frac{\partial J(w,b)}{\partial w_1}=\frac{1}{m}\sum_{0<i \le m}{\dfrac{\partial L(a^{(i)},y^{(i)})}{\partial w_1}} w1J(w,b)=m10<imw1L(a(i),y(i))
代码流程:

J=0;dw1=0;dw2=0;db=0;
for i = 1 to m
    z(i) = wx(i)+b;
    a(i) = sigmoid(z(i));
    J += -[y(i)log(a(i))+(1-y(i))log(1-a(i));
    dz(i) = a(i)-y(i);
    dw1 += x1(i)dz(i);
    dw2 += x2(i)dz(i);
    db += dz(i);
J/= m;
dw1/= m;
dw2/= m;
db/= m;
w=w-alpha*dw
b=b-alpha*db

遇到的问题:

需要两个for循环,一个遍历n个特征,另一个循环遍历m个样本。

解决方法:

向量化Vectorization,消除显性的for循环。

2.11 向量化(Vectorization)

什么是向量化

z = w T x + b w = ( . . . . . )     w ∈ R n x = ( . . . . . )      x ∈ R n x z=w^Tx+b\\ w=\begin{pmatrix}.\\ ...\\.\end{pmatrix}\ \ \ w\isin \reals^{n}\\x=\begin{pmatrix}.\\...\\. \end{pmatrix}\ \ \ \ x\isin \reals^{n_x} z=wTx+bw=.....   wRnx=.....    xRnx

  • 非向量方法实现:

    z=0;
    for i in range(n_x):
      z+=w[i]*x[i]
    z+=b
    
  • 向量方法实现:

    z=np.dot(w,x)+b             # z=w_t*x+b,使用numpy库
    
    #example
    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”)#打印for循环的版本的时间
    #向量化快了接近300倍
    
    • CPU&GPU均有并行化指令,即SIMD指令(Single Instruction Multiple Data),GPU比CPU更擅长并行化运算。

2.12 向量化的更多例子

经验法则:尽量避免for循环

1.向量相乘的计算:

U = A ⋅ v U=A·v U=Av

u=np.dot(A,v)
2.向量指数运算:

v T = ( v 1   v 2   ⋅ ⋅ ⋅   v n ) u T = ( e ( v 1 )   e ( v 2 )   ⋅ ⋅ ⋅   e ( v 3 ) ) v^T=(v_1\ v_2\ ···\ v_n)\\ u^T=(e^{(v_1)}\ e^{(v_2)}\ ···\ e^{(v_3)}) vT=(v1 v2  vn)uT=(e(v1) e(v2)  e(v3))

import numpy as np
u = np.exp(v)

np.log()
np.abs()
np.maximum()
v**2 #获取每个值的平方
1/v 
3.逻辑回归的梯度下降:
J=0;dw1=0;dw2=0;db=0;##位置一
for i = 1 to m
    z(i) = wx(i)+b;
    a(i) = sigmoid(z(i));
    J += -[y(i)log(a(i))+(1-y(i))log(1-a(i));
    dz(i) = a(i)-y(i);
    ##位置二                      
    dw1 += x1(i)dz(i); #n_x=2
    dw2 += x2(i)dz(i);#去掉此处遍历n_x个特征w(n_X)的循环 for j in range(1,n_x):
    db += dz(i);
J/= m;
dw1/= m;##位置三
dw2/= m;
db/= m;
w=w-alpha*dw
b=b-alpha*db
  • 做法:不将dw_1,dw_2,…显式地初始化为0.而是将dw变成一个向量
dw = np.zeros((n_x,1))##位置一
dw+=x(i)dz(i)##位置二
dw/=m##位置三

2.13 向量化逻辑回归(Vectorization Logistic Regression)

逻辑回归的向量化

z ( i ) = w T x ( i ) + b y ^ ( i ) = a ( i ) = σ ( z ( i ) ) z^{(i)} = w^{T}x^{(i)}+b \\ \hat{y}^{(i)}=a^{(i)}=\sigma(z^{(i)}) z(i)=wTx(i)+by^(i)=a(i)=σ(z(i))

X = ( . . . x ( 1 ) x ( 2 ) . . . x ( m ) . . . )      x ( i ) ∈ R n x X=\begin{pmatrix} ...\\ x^{(1)} x^{(2)} ... x^{(m)}\\ ... \end{pmatrix}\ \ \ \ x^{(i)}\isin \reals^{n_x} X=...x(1)x(2)...x(m)...    x(i)Rnx

X是一个n_x*m的矩阵。

1.构建一个1*m的矩阵Z,计算得到Z。

Z = ( z ( 1 ) z ( 2 ) . . . z ( m ) ) = w T ⋅ X + ( b   b   . . .   b   ) 1 ∗ m = ( w T x ( 1 ) + b    w T x ( 2 ) + b . . . w T x ( m ) + b ) 1 ∗ m Z=\begin{pmatrix}z^{(1)} z^{(2)} ... z^{(m)} \end{pmatrix}=w^T·X+\begin{pmatrix}b\ b\ ...\ b\ \end{pmatrix}_{1*m}=\begin{pmatrix} w^Tx^{(1)}+b\ \ w^Tx^{(2)}+b ... w^Tx^{(m)}+b \end{pmatrix}_{1*m} Z=(z(1)z(2)...z(m))=wTX+(b b ... b )1m=(wTx(1)+b  wTx(2)+b...wTx(m)+b)1m

Z=np.dot(w.T,x)+b 
'''
此处的b为实数,在计算时,python会将b自动扩展成一个1*m的行向量。“broadcasting”
'''
2.构建一个1*m的矩阵A,计算得到A。

A = ( a ( 1 ) a ( 2 ) . . . a ( m ) ) = σ ( Z ) A=\begin{pmatrix} a^{(1)} a^{(2)} ... a^{(m)} \end{pmatrix} =\sigma(Z) A=(a(1)a(2)...a(m))=σ(Z)

将矩阵Z作为输入,通过python可以非常高效地输出A。

2.14向量化logistic回归的梯度计算

d z ( i ) = a ( i ) − y ( i ) d z = ( d z ( 1 )   d z ( 2 )   ⋅ ⋅ ⋅   d z ( m ) ) 1 ∗ m A = ( a ( 1 ) a ( 2 ) . . . a ( m ) ) Y = ( y ( 1 ) y ( 2 ) . . . y ( m ) ) dz^{(i)}=a^{(i)}-y^{(i)}\\ dz=(dz^{(1)}\ dz^{(2)}\ ···\ dz^{(m)})_{1*m}\\ A=\begin{pmatrix} a^{(1)} a^{(2)} ... a^{(m)} \end{pmatrix}\\ Y=\begin{pmatrix} y^{(1)} y^{(2)} ... y^{(m)} \end{pmatrix} dz(i)=a(i)y(i)dz=(dz(1) dz(2)  dz(m))1mA=(a(1)a(2)...a(m))Y=(y(1)y(2)...y(m))

1.去掉计算dz的循环
  • dz的循环:
###详细代码见2.12节3.逻辑回归的梯度下降
for i = 1 to m
    z(i) = wx(i)+b;
    a(i) = sigmoid(z(i));
    dz(i) = a(i)-y(i);
  • 去循环的方法:

d z = A − Y = ( a ( 1 ) − y ( 1 )   a ( 2 ) − y ( 2 )   ⋅ ⋅ ⋅   ) dz=A-Y=(a^{(1)}-y^{(1)}\ a^{(2)}-y^{(2)}\ ···\ ) dz=AY=(a(1)y(1) a(2)y(2)  )

2.去掉遍历训练集的循环
去掉计算dw,db的循环
  • 与2.12去掉位置二的循环的分别:
    • 2.12的循环是在对每个训练样本,遍历其所有特征值w1,w2,…,wn,n为每个样本特征的个数,即n_x,在2.12的例子中,特征个数为2。
    • 2.14中的该循环是已经计算出每个样本的所有特征w1,w2,…,wn,对m个样本遍历,相加求每个特征在m个样本下的平均值。
2.1dw,db在训练集上的循环:
###
#此处的dw已经是向量了,即是经过2.12第三节位置二处理后的dw
dw=0,db = 0
for i in range(1,m):
  dw+=x(i)dz(i)
  db += dz(i);
dw/=m
db/= m;
#与2.12-3处的代码进行对照,与下面这部分相同。
for i = 1 to m:  
  ###位置二
	dw1 += x1(i)dz(i); #n_x=2
	dw2 += x2(i)dz(i);
  dwn += xn(i)dz(i);
	db += dz(i);
dw1/= m;##位置三
dw2/= m;
dwn/= m;
db/= m;
2.2去循环的方法:
  • db的去循环

d b = 1 m ∑ 0 < i ≤ m d z ( i ) db=\frac{1}{m}\sum_{0<i \le m}dz^{(i)} db=m10<imdz(i)

db=1/m*np.sum(dz)
  • dw的去循环

d w = 1 m X d z T = 1 m ( x ( 1 )   x ( 2 )   . . . x ( m ) ) n ∗ m ( d z ( 1 ) d z ( 2 ) . . . d z ( m ) ) m ∗ 1 = 1 m ( x ( 1 ) d z ( 1 ) + x ( 2 ) d z ( 2 ) + . . . + x ( n ) d z ( n ) ) n ∗ 1 注 : x ( i ) 为 n x 维 的 列 向 量 。 dw=\frac{1}{m}Xdz^T\\ =\frac{1}{m} \begin{pmatrix} x^{(1)}\ x^{(2)} \ ... x^{(m)}\\ \end{pmatrix}_{n*m} \begin{pmatrix} dz^{(1)}\\ dz^{(2)}\\ ...\\ dz^{(m)} \end{pmatrix}_{m*1}\\= \frac{1}{m} \begin{pmatrix} x^{(1)dz^{(1)}}+ x^{(2)dz^{(2)}}+ ...+ x^{(n)dz^{(n)}} \end{pmatrix}_{n*1}\\ 注:x^{(i)}为n_x维的列向量。 dw=m1XdzT=m1(x(1) x(2) ...x(m))nmdz(1)dz(2)...dz(m)m1=m1(x(1)dz(1)+x(2)dz(2)+...+x(n)dz(n))n1x(i)nx

3.总结梳理
  • 未向量化的过程
J=0;dw1=0;dw2=0;db=0;
for i = 1 to m
    z(i) = wx(i)+b;##位置一
    a(i) = sigmoid(z(i));
    J += -[y(i)log(a(i))+(1-y(i))log(1-a(i));
    dz(i) = a(i)-y(i);
    ##位置二                      
    dw1 += x1(i)dz(i); #n_x=2
    dw2 += x2(i)dz(i);#去掉此处遍历n_x个特征w(n_X)的循环 for j in range(1,n_x):
    db += dz(i);
J/= m;
dw1/= m;##位置三
dw2/= m;
db/= m;
w=w-alpha*dw
b=b-alpha*db
  • 向量化的步骤
1. 将位置二的循环向量化(去掉遍历每个特征的内循环)
dw+=x(i)dz(i)
2.将位置一的循环向量化(去掉计算z,a时遍历每个样本的循环)
Z=w_T*x+b=np.dot(w.T,x)+b #见2.13-1
A=sigma(z)#见2.13-2
dz=A-Y#见2.14-1
dw=1/m*X*dz_T#见2.14-2.2
db=1/m(np.sum(dz))#见2.14-2.2
#见2-10
w=w-alpha*dw
b=b-alpha*db

以上即实现了一次迭代的梯度下降。

2.15 python中的广播

如何能够不使用循环按列求和,再将每个元素处以该列的和计算出来呢?

import numpy as np
A = np.array([56.0,0.0,4.4,68.0],
            [1.2,104.0,52.0,8.0],
            [1.8,135.0,99.0,0.9])
print(A)
cal =A.sum(axis=0)#axis=0表示求和按列执行
print(cal)
percentage = 100*A/cal.reshape(1,4)
#不使用reshape结果也对,使用更严谨,确保是正确的矩阵形状,reshape()是O(1)运算
print(percentage)

关于axis:axis=0表示竖直相加,竖轴为0,水平轴为1。

  • 对于m*n的矩阵,无论行或列相不相同,都会先复制到m行,再复制得到n列。
  • 如果是3*2的矩阵与2*2的矩阵进行矩阵运算呢。
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值