吴恩达-深度学习(1-3节)

DeepLearning三步骤

  1. 定义一组函数(就是函数集)其实就是神经网络(neural network)

  2. 判断函数的好坏(loss function)从function set中选取一个最小的Loss function

  3. 选择一个最好的函数

一个neural network其实就是一个function,经过一层一层的计算最后得到最后的结果

不同的情况采用不同的神经网络框架

  1. 真实财产(例如房地产和在线广告):标准的神经网络

  2. 图像领域:CNN

  3. 序列数据(语音和文字):RNN或者RNNs

  4. 更复杂的应用(无人驾驶等):复杂或者是混合的神经网络架构

神经网络简述

常见的三种神经网络:标准神经网络,CNN(卷积神经网络),RNN(循环神经网络)

CNN适用于解决图像问题,RNN适用于解决一维序列数据问题。

结构化数据:数据的数据库,每个特征都有清晰的定义;

非结构化数据:例如音频,原始音频以及图像等。

二元分类

每张彩色图片对应着红绿蓝三种颜色通道,那么如果需要保存一张图片的话,就需要存储三个矩阵,分别对应三个颜色。

  • 如果图片大小为64x64像素,那么就有三个64x64的矩阵,分别对应图片中红、绿、蓝三种像素的强度值

  • 为了把这些像素值放到一个特征向量中,需要把这些像素值提取出来,放入一个特征向量 x

首先把所有的像素都取出来,如果图片的大小为64x64像素,那么向量 x 的总维度,将是64乘以64乘以3,这是三个像素矩阵中像素的总量。在这个例子中它为12,288。现在我们用 nx=12,288 ,来表示输入特征向量的维度。有时候为了简洁,会直接用小写的 n 来表示输入特征向量 x 的维度。(n表示的是向量X的长度而不是特征)

符号定义

在这个系列课程里使用到的一些定义如下:

  • x :表示一个 nx 维数据,为输入数据,维度为 (nx, 1)

  • y :表示输出结果,取值为 (0, 1)

  • (x(i), y(i)) :表示第 i 组数据,可能是训练数据,也可能是测试数据,此处默认为训练数据;

  • X = [x(1), x(2), ..., x(m)] :表示所有的训练数据集的输入值,放在一个 nx × m 的矩阵中,其中 m 表示样本数目;

  • Y = [y(1), y(2), ..., y(m)] :对应表示所有训练数据集的输出值,维度为 1 × m

  • 一对(x, y) 来表示一个单独的样本, x 代表 nx 维的特征向量, y 表示标签(输出结果)只能为0或1。

定义训练集由 m 个训练样本组成时,有:

  • (x(1),y(1)) 表示第一个样本的输入和输出

  • (x(m),y(m)) 表示最后一个样本

  • 有时为了强调这是训练样本的个数,会写作 Mtrain

  • 当涉及到测试集的时候,我们会使用 Mtest 来表示测试集的样本数

 X.shape=(nx,m) #说明x这是一个nx*m维的矩阵
 Y.shape=(1,m) #说明y是一个1*m维的矩阵

Logistic Regression

Logistic Regression其实就是给定一个x,输出的是y^,代表着当x满足条件时y等于1(例如图片的话,y=1则代表着是这个类型的图片)的概率为多大,y^其实就是概率值。

那么其实就是要得到y^的值为多大。如果采用y^=wT*x+b(其中w是一个参数向量)输出的结果可能是个负数或者是大于1的,这显然在概率中不成立。所以采用σ函数作用于wT*x+b上,则y^=σ(wT*x+b),其中z=wT*x+b。

σ(z)就可以用下面这张图片来表示:g(z)就表示σ(z)

img

图像如下图所示:

img

因为要保证y^是个非负数,所以采用上图的函数来计算y^。

所以当使用logistic的时候那么需要做的就是学习调整w和b,使得y^变成一个好的估计

y^=σ(wT*x+b)(其中z=wT*x+b)的另一种表示:

当X0=1的时候,X是一个nx+1维的向量。

y^=σ(θT*X),θ=[θ0,θ1,......θnx]T,其中θ0就是等于b,θ1,......θnx就是等于w。

Logistic Regerssion cost function

损失函数是定义在单个训练样本上的,也就是就算一个样本的误差,用L表示

代价函数是定义在整个训练集上面的,也就是所有样本的误差的总和的平均,也就是损失函数的总和的平均

为了训练回归模型的参数w和b,则需要定义一个cost function,cost function可以用来衡量w和b的效果的。

要确定参数w和b,那么就需要给定训练数据来对模型进行训练,使得y^≈y(y是数据中给定的)

Loss(error) Function可以用来查明你的y^和y到底有多接近。Loss Function可以定义为:L(y^,y)= 1/2(y^-y)2

但是在logistic regression中一般不这样定义,因为这样会变成一个非凸函数,非凸函数就会得到许多个局部最优解,根据梯度下降法,找不到全局的最优解。(左边这个就是一个非凸函数)

img

在Logistic Regerssion采用这样的Loss Function:L(y^,y)=-( y logy^+ (1-y) log(1-y^) )

在Logistic Regression采用下面这样的cost function,用 J 表示:J(w,b)=-1/m Σ(i=1到m)[ y(i) logy^(i)+ (1-y(i)) log(1-y^(i)]

cost function其实就是loss function的平均求和

要找到w和b使得 J 尽可能的小

Gradient Desecnt

用gradient descent来训练或学习训练集上的参数w和b(找到使得 J 最小的w和b)

梯度下降是从初始点开始,朝着最陡的下坡方向走一步,直到走到最低点。

梯度下降法就是一直在重复下面的这个过程:

 Repeat{
     w:=w-α*dJ(W)/dw(可以直接写成w:=w-dw)
 }

对上面过程的解释:α是代表学习率,α控制每一次迭代或者梯度下降法中的步长。dJ(W)/dw就是导数,是对参数w的更新就是w的变化量

b和w通过下面的方式进行更新:

w:=w-α*dJ(w,b)/dw

b:=b-α*dJ(w,b)/db

导数是等于▲y/▲x(y的变化值处于x的变化值)

导数

导数会用到前向传播以及反向传播中

下图就是链式求导法则:

v是由a,b,c三个参数构成的,J是由v构成的

如果要求出J对于a的导数,那么就只需要知道J先对v求导然后v再对a求导,得到最终的J对a的导数。整理如下:

dJ/da=dJ/dv*dv/da

在python中:使用d FinalOutputVar/d var就是最后输出的参数对于其中一个参数求导数

在本题的例子中d FinalOutputVar/d var得到的结果就是d J/d a

前向传播

前向传播就是通过输入的参数如何得到最后的代价函数J

z(1) = wT*x+b,z(2) = wT*x+b,......

a(1)=σ(z(1)),a(2)=σ(z(2)),.......

反向传播

反向传播就是通过J如何计算得到最开始的参数值

向量化

如果在遍历数据的时候采用for循环的话会非常的复杂而且计算量会很大,所以可采取向量化的方式来摆脱for循环。在使用向量化之后或许一个for循环都不需要使用。

当使用非向量化的操作的时候,如果要计算z=wT*x+b的话需要用到for循环,像下面这样:

 for i in range(n-x):
     z += w[i]*x[i]
 z += b

但是在向量化的操作的时候,如果要计算z的话,那么只需要使用numpy的包就可以了,像下面这样:

 z = np.dot(w^T^,x)+b #这行命令就可以计算z=w^T^*x的结果

向量化logistic regression

下图显示的是使用for循环来实现的logistic regression求导

上图的错误了,dz是等于a(i)-y(i),其中a(i)表示的是预测值, y(i)表示的是真实值,在这里,loga的导数等于1/a,因为在交叉熵中loga就等于lna

dz(i)表示的是代价函数J对于z(i)的导数,就是d J/d z(i),其中y^(i)其实就是等于a(i)

其他d也都是一样的,都是dJ对于d 某个字母的导数

在dw1+=x1(i)*dz(i)以及dw2+=x2(i)*dz(i)

就可以用下面这行命令进行代替

 dw = np.zero(n-x,1) # 其中的n-x代表的是矩阵的高度
 dw += x[i]*dz[i]

使用上述的命令可以成功的消去一些for循环。

向量化前向传播

z(1) = wT*x+b,z(2) = wT*x+b,......

a(1)=σ(z(1)),a(2)=σ(z(2)),.......

使用向量化的话就是

X = [x1,x2,......xm]

令Z = [Z1,Z2,......Zm]

b=[b,b,b,...,b]

Z = wT*X+b

那么就可以使用下面的命令来对上面的过程进行简化

 z = np.dot(w^T^,X)+b

向量化反向传播

根据上面的图片可以知道

dz(1)=a(1)-y1),dz(2)=a(2)-y(2),......,dz(m)=a(m)-y(m)

使用向量化的话就是

令dz=[dz1,dz2,......,dzm]

A = [a1,a2,......,am]

Y = [y1,y2,......,ym]

dz = A-Y

向量化regression

db = 1/m ∑ dz(i)

db = 1/m np.sum(dz)

dw = 1/m * X * dzT

最后面的w和b的变化其实就是梯度下降的一次迭代。

numpy

numpy一些函数

 np.dot(a,b) # 会计算a*b的值,就是计算a[i]*b[i]的值
 np.random.randn(1000) # 会创建一个1000维度的数组
 np.exp(v)# 会让向量中的每个元素i变成e^i^
 np.log(v)
 np.abs(v) 
 np.maximum(v) # 和上面的exp一样,会对v中的每个向量执行操作
 np.zeros(3,3) # 创建一个3*3的矩阵的全零矩阵

numpy向量说明

  1. 尽量不要用这种秩为1的矩阵

例如:A= [1,2,3,4,5]这样的1*5的矩阵,可以用A.shape查看矩阵的形状,得到的结果是(5,)的就最好不要用

 # 不要用下面这种形式来定义矩阵
 np.random.randn(5)  #这会得到一个1*5的矩阵
 # 最好用这种形式来定义
 np.random.randn(5,1) #这会得到一个5*1的矩阵

如果不确定得到的矩阵是什么样的可以使用assert函数

 assert(a.shape == (5,1))

广播

广播其实就是numpy如何处理一些特殊的矩阵,例如一些不对称的矩阵的加减乘除等等,下面有几个例子

1.下面是一个例子用来计算每个物质的含量占总含量的百分之多少:

要在python中写入矩阵可以按照下面的定义来定义矩阵

 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]])

 cal = A.sum(axis = 0) # 代表着对矩阵A中的竖轴的数值进行相加
 percentage = 100*A/(cal.reshape(1,4)) #相当于是一个3*4的矩阵除以1*4的矩阵 reshape函数的意思是将结果变成一个1*4的矩阵

2.一个向量加上一个常数(这个就相当于logistic regression中加上b原理一样)

 A = np.array([56.0,0.0,4.4,68.0])
 A += 100 # 那么python会将100扩展成为1*3的矩阵,并将A矩阵中的每个数字加上100得到一个最终的矩阵

3.一个2x3的就矩阵加上一个1x3的矩阵

python会将后面那个1x3的矩阵复制变成一个2个1x3的矩阵,其中2个1x3的矩阵数值是一样的

jupyter

1.先在pycharm命令行中添加清华大学的软件源

  • 这个是仅使用一次,即只在这次下载软件使用清华的源
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple some-package 
# 其中some-package是你要下载的包的名字
  • 如果要在以后的下载中默认清华的源,那么可以使用下面的命令
python -m pip install --upgrade pip 
# 如果pip升级的过程使用默认源比较慢,可以用python -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --upgrade pip来升级pip,并继续执行下面的命令即可
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple  
2.使用pip命令下载jupyter
pip install jupyter 
# 注意:如果有开VPN的话,需要先关闭否则会导致连接不上清华的源
3.再使用命令启动jupyter即可
jupyter notebook

神经网络

神经网络表示

[x1,x2,x3]表示的是输入层,中间很多节点的表示隐藏层(中间训练的这些东西的数值我们是不知道的),最后只有一个节点的是输出层(输出预测的y值)

使用符号来标记上面的这些不同的层

a[0]表示输入的特征向量,也就是a[0]=X

a[1]表示隐藏层,其中隐藏层的第一个节点是a1[1],第二个节点是a2[2],......,以此类推。

隐藏层有两个参数:W和b,在上图中用W[1]和b[1]来表示隐藏层的参数,W[1]是一个4x3的矩阵,其中4是说明有四个节点,3是说明有三个输入的特征值(x1,x2,x3),b是一个4x1的矩阵

a[2]表示输出层。输出层也有两个参数分别是W[2]和b[2],在上图中W[2]是一个1x4的矩阵,b[2]是一个1x1的矩阵。因为输出层只有一个节点,有四个输入。

上图的神经网络架构被称为两层神经网络结构,因为输入层不算一层,只有一层隐藏层以及一层输出层。

单样本神经网络输出

在神经网络中,使用这样的定义才计算z[1]等参数。

使用Z[1]来表示[Z1[1],......,Z4^[1]]的集合。分别用下面的符号表示不同的式子。

如下图所示:展示了如何计算得到最终的输出的结果。Z[1]得到的结果是第一层隐藏层四个节点计算得到的结果。Z[2]表示的是第二层单个的输出节点的东西,将Z[2]进行计算可以得到最终的a[2],这就是最终的y^。

双层神经网络矩阵维度总结

在一个两层神经网络中,通常会有以下参数和数据:

  1. 输入数据 ( X ) 的维度: ( (n_x, m) ),其中 ( n_x ) 是输入特征的数量,( m ) 是样本的数量。

  2. 第一层的权重 ( W^{[1]} ) 的维度: ( (n_h, n_x) ),其中 ( n_h ) 是第一层隐藏层的神经元数量,( n_x ) 是输入特征的数量。

  3. 第一层的偏置 ( b^{[1]} ) 的维度: ( (n_h, 1) )。

  4. 第二层的权重 ( W^{[2]} ) 的维度: ( (n_y, n_h) ),其中 ( n_y ) 是输出层的神经元数量,( n_h ) 是第一层隐藏层的神经元数量。

  5. 第二层的偏置 ( b^{[2]} ) 的维度: ( (n_y, 1) )。

  6. 第一层的加权输入 ( Z^{[1]} ) 的维度: ( (n_h, m) )。

  7. 第一层的激活值 ( A^{[1]} ) 的维度: ( (n_h, m) )。

  8. 第二层的加权输入 ( Z^{[2]} ) 的维度: ( (n_y, m) )。

  9. 第二层的激活值 ( A^{[2]} ) 的维度: ( (n_y, m) )。

这些维度会根据具体的神经网络架构和数据集情况而变化。

多样本向量化

上面显示的是单个样本在神经网络中如何输出。下面将说明多个样本在神经网络中如何表示以及说明。

这里的多个样本是用X(1),X(2),......,X(m)来表示的,对应的估计值是用a[2](1)来表示的,其中[2]表示的是第2层,(1)表示的是第1个样本

下图通过一个for循环的方式来遍历所有的输入数据。

对于数据集中的每一个样本(i从1到m),执行以下步骤。(这里的W[1],W[2],b[1]和b[2]都是模型初始化的参数,会在模型的学习过程中修改的)

  1. z[1](i) = W[1]x(i) + b[1]:计算第一层的z值,通过将权重矩阵W[1]与输入向量x(i) 相乘,然后加上偏置向量b[1]得到z值。

  2. a[1][i]=σ(z[1](i)):对z[1](i)应用激活函数σ,得到第一层的激活值a[1][i]。

  3. z[2](i) = W[2]a[1](i) + b[2]:使用第一层的激活值a[1](i) ,再次计算预激活值,这次是为了第二层,同样地加上第二层的偏置向量b[2]。

  4. a[2](i) = σ(z[2](i)):将激活函数σ应用于z[2](i),得到最终的输出a[2](i),这是对第i个样本的预测或处理结果。

其实就是先计算第一层的第一个数据再计算第二个一直计算到第m个数据,然后再计算第二层的数据,最后得到最终的输出值。

可以将上面的for循环使用下列向量化的方式进行代替。

将输入的x[i]写成列向量的形式变成一个大的矩阵X

Z[1]和A[1]也是一样的,当然还有Z[2]和A[2]也是一样的。

激活函数

隐藏层和输出层里面的激活函数都是可以选择的(前面所提到的σ就是一个激活函数)

在隐藏层部分,激活函数已经不采用σ函数了,采用tanh(不是tan函数)函数比σ函数好。这是因为tanh函数的输出范围是[-1, 1],使得其均值接近于 0,这有助于加速收敛速度。

在输出层部分,如果进行的是二元分类的任务,那么输出层一般采用σ函数,因为σ函数的取值范围是[0,1],而tanh函数的取值范围是[-1,1]

采用这种形式来表明当前这个激活函数应用于哪一层:假设g为激活函数,则g[1]和g[2]表示第一层和第二层的激活函数。

上述两个激活函数都有一个问题,那就是当z很大的时候,函数的斜率会变得非常的小趋近于0(梯度消失问题),这会影响梯度下降算法。所以可以采用ReLU函数来作为隐藏层的激活函数。

ReLU函数的表达式是:g( z )=max(0 , z),函数的图像如下图所示:

有以下四种隐藏函数:除非在做二元分类的任务,否则一般不采用σ激活函数,tanh函数也比较少用,目前采用最多的是ReLU激活函数以及leak ReLU激活函数。

leak ReLU激活函数的函数表达式是:g(z)=max(0.01*z , z)其中0.01是可选的,也可以将0.01看成一个调整的参数但是一般不去调整这个数值。

激活函数的导数:

当g是σ函数的时候,即g(z) = 1/1+e^{-z},令a = g(z)

dg(z) / dz = a*(1-z)

当g是tanh函数的时候,即g(z) = e^z-e^{-z}/e^z+e^{-z},令a = g(z)

dg(z) / dz = 1-a2

当g是ReLU函数的时候,即g(z) = max(0 , z)

dg(z) / dz = 0(当z<0的时候) 或 =1(当z>=0的时候)

当g是laeky ReLU函数的时候,即g(z) = max(0.01*z , z)

dg(z) / dz = 0.01(当z<0的时候) 或 =1(当z>=0的时候)

神经网络的梯度下降法

可以借助这张图对下面这些推导过程的理解

下图是一个正向传播以及反向传播的过程示意图:

前向传播(Forward Propagation):

  • z[1] = W[1]X + b[1]: 这一步计算第一层的加权输入,其中W[1]是权重矩阵,X是输入矩阵,b[1]是偏置向量。

  • A[1] = g[1](z[1]): 表示第一层的激活函数g[1](通常是sigmoid或ReLU函数)到加权输入(z[1]上,以获得第一层的激活输出A[1]。

  • z[2]= W[2]A[1] + b[2]: 类似地,第二层的加权输入z[2]是第一层的激活输出A[1] 与第二层的权重W[2]的乘积,再加上偏置b[2]。

  • A[2] = g[2](z[2]) = σ(z[2]): g[2]表示第二层的激活函数,第二层的激活输出A[2],其中σ表示sigmoid激活函数(σ是假设第二层采用的是σ函数)。

反向传播(Back Propagation):

  • dZ[2] = A[2] - Y: 计算输出层误差,即预测结果A[2]与真实值Y之间的差。

  • dW[2] = 1/m * dZ[2]A[1]T: 计算对权重W[2]的梯度,A[1]T是A[1]的转置,m是样本数量。

  • db[2] = 1/m * np.sum(dZ[2], axis=1, keepdims=True): 计算对偏置b[2]的梯度,通过对dZ[2]求和(np.sum表示NumPy的求和函数,axis=1表示沿着行的方向,keepdims=True保持原有的维度,防止python自己生成类似于 (n,) 这种维度的矩阵)。

  • dZ[1] = W[2]T * dZ[2] * g[1]'(z[1]): 计算第一层的误差dZ[1],其中W[2]T是W[2]的转置,g[1]'是第一层激活函数的导数。

  • dW[1] = 1/m * dZ[1]XT: 计算对权重W[1]的梯度。

  • db[1] = 1/m * np.sum(dZ[1], axis=1, keepdims=True): 计算对偏置b[1] 的梯度。

这个过程通过计算损失函数关于每个参数的梯度,然后使用这些梯度通过梯度下降算法更新参数,从而减少预测误差,优化网络性能。反向传播是实现这一目的的关键步骤,通过它网络能够学习从输入数据到输出结果的映射。

随机初始化

训练神经网络的时候需要随机初始化权重

在初始化参数的时候不可以将参数初始化为全0矩阵,因为如果将W和b矩阵全部都初始化为全0矩阵,就会导致任意的x输入都会得到一样的输出(因为Z = WT * X + b)。所以只能将b设置为全0矩阵,不能将W设置为全0矩阵。

根据上面这个简单的神经网络来随机初始化参数:

 w[1] = np.random.randn(2,2)*0.01
 b[1] = np.zero(2,1)

对于上面的代码为什么要*0.01的解释:

因为如果初始化的W权重太大,那么得到的Z就会落到一个比较大的位置,根据σ和tanh函数的图像可知,当Z较大的时候,函数的斜率就会变得很小趋近于0。

  • 30
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值