1.二分分类
如图2.1就是一个二分分类问题的例子,识别此图并输出标签,如果是猫输出1,否则输出0,我们用y表示输出标签。
2.图片表示
计算机保存一张图片,要保存三个独立矩阵,分别对应图片中的红绿色三通道。
一般的,我们会把红绿蓝三个通道的值逐个都列出来如图2.3一样,作为神经网络输入特征向量x。如果图片是64*64,那么向量x的总维度为64*64*3=12288,用=12288或n=12288表示输入的特征向量的维度。
3.符号统一
(x,y)表示一个单独样本,其中x是维的特征向量,表示为x∈,标签y的值为0或1,表示为y∈{0,1}。
有m个训练样本,表示为m train example:{(,),(,),...,(,)}。
如图2.4,大写X表示特征向量训练集,样本约定为列向量堆叠,X∈,Python命令X.shape=(, m)。大写Y表示标签集,Y∈,Y.shape=(1, m)。
4.logistic回归
图2.5就是一个logistic回归模型。有一张图,需要识别是不是猫图,输入特征向量x,得到预测值 =p(y=1|x),其中x∈,参数w∈,参数b∈R,输出为 =+b。由于希望0<<1,所以 =σ(+b),其中σ是sigmoid(z)函数,σ(z)=1/(1+)。如果z非常大,则σ接近1,反之,接近0。
所以,我们要做的是学习参数w和b,让 变成比较好的估计,相对于y比较好的估计。图2.5中红色是另外一种符号约定方式,我们统一用绿色方式。
5.logistic回归成本函数
为了训练logistic回归模型的参数w和b,需要定义一个成本函数,它衡量的是在全体训练样本上的表现。
如图2.6,我们约定第i个训练样本为,第i个标签为,第i个预测值为。定义成本函数前,我们先定义一个损失函数,它指的是单个训练样例预测与期望输出的差异。
如图2.7,我们列举了两个二分类适用的损失函数,当然你也可以使用其他更合适的损失函数,第一个损失函数也能表示单个训练集预测与期望输出的差异,但该函数是非凸的,有多个局部最优解,很难找到全局最优解。第二函数是凸的,可以找到全集最优解。
证:
设y=1时 p(y|x)=
则y=0时 p(y|x)=1-
则 p(y|x)=
则log(p(y|x)) = ylog( )+(1-y)log(1- )
由于log函数式单调递增,则log(p(y|x))肯定能找到最大值
而我们需要做的是最小化损失函数,则-log(p(y|x)
根据损失函数,我们列出成本函数,如图2.8。这个成本函数是基于参数的总成本,在训练logistic回归模型式时,我们要找到合适的参数w和b,让成本函数J尽可能小。
6.梯度下降法
梯度下降法是用来训练或者说学习训练集上参数w和b。
成本函数J是参数w和b的函数,被定义为平均值,即1/m的损失函数之和。损失函数可以衡量算法的效果,成本函数可以衡量参数w和b在训练集上的效果。
如图2.10,这里假设训练集只有一个特征值,则只有参数只有一个w和一个b,实际上会有很多特征值,即有很多个不同的w和一个b。
成本函数是凸函数,通过不断学习,找到合适参数w和b,使成本函数J最小。一开始我们需要先初始化参数w和b,对于logistic回归而言,基本任何初始化方式都有效,通常初始化为0,但对于logistic回归我们更多的是随机初始化。因为函数式凸的,无论在哪初始化,都应该到达同一点,或者大致相同点。
梯度下降法所做的是,从初始化点开始,朝最陡的下坡方向走一步,这是梯度下降的一次迭代。在下降一步后,或许收敛到全局最优解,在那里停下,或许继续下降,直到收敛到最有解或接近全局最优解。
如图2.11,为了方便理解,我们暂时忽略参数b,为了使成本函数最小化,则需要重复执行w=w-α*dJ(w)/dw,其中α是学习率即下降步长,dJ(w)/dw是导数。
把参数b加上,则
w=w-α*∂J(w,b)/∂w,
b=b-α*∂J(w,b)/∂b
多个参数用∂ ,代表偏导数,
单参数用d ,表示导数。
我们约定w的导数(或偏导)用dw 表示,即 w=w-α*dw,b的导数(或偏导)用 db表示,即b=b-α*db 。
7.导数
自行翻阅微积分,特别要熟悉链式法则。
8.计算图
一个神经网络的计算都是按照前向和反向传播过程实现的。首先计算出神经网络的输出,紧接着进行一个反向传输操作,后者指的是计算导数。
如图2.12,假设成本函数为 ,先进行前向计算,目的是计算出成本函数和为反向传播提供值,
若a=5,b=3,c=2,
则令u=bc,v=a+u,J=3v,
则第一步u=bc=6,
则第二步v=a+u=11,
最后一步J=3v=33。
如图2.13,接着我们进行反向传播,目的是计算出参数a,b,c的导数,
第一步dJ/dv=3,dv/du=1,dv/da=1,du/db=c=2,du/dc=b=3
第二步dJ/du=dJ/dv * dv/du=3 * 1=3,
最后一步
dJ/da=dJ/dv * dv/da=3 * 1=3,
dJ/db=dJ/du * du/db=3 * 2=6,
dJ/dc=dJ/du * du/dc=3 * 3=9。
9.logistic回归的梯度下降
如图2.14,描述了logistic回归的前向过程。
如图2.15,是logistic回归的反向传播过程,目的是计算参数w1,w2,b的导数,
第一步da=dL(a,y)/da=-y/a + (1-y)/(1-a),da/dz=a(1-a),
第二步dz=dL(a,y)/dz=dL(a,y)/da * da/dz=a-y,dz/dw1=x1,
第三步
dw1=dL(a,y)/dw1=dL(a,y)/da * da/dz * dz/dw1=(a-y)x1,
dw2=dL(a,y)/dw1=dL(a,y)/da * da/dz * dz/dw2=(a-y)x2,
db=dL(a,y)/db=dL(a,y)/da * da/dz * dz/db=a-y。
接着计算 w1=w1-αdw1, w2=w2-αdw2, b=b-αb,然后进行下次迭代。
10.m个样本的梯度下降
如图2.16,m个样本logistic回归反向过程求导只需要每个样本相加然后除以m即可。For循环是很缓慢的过程,解决这个问题就会用到向量化技术。
11.向量化
向量化通常是消除你代码中显式for循环的方法。在深度学习中,你会发现数据集越大深度学习算法表现得才越优越,所以你的代码运行得非常快非常重要,不然在训练时你会花大把时间去等待。
在深度学习领域,向量化是一个很关键的技巧。
使用类似np.dot()的内置函数或者其他能让你去掉显示for循环的函数,就能够实现向量化,这样能够使程序充分使用并行化(单指令多数据流)去更快地计算。相对CPU,GPU能够更快地进行并行化处理。从而成立一条经验法则,只要有可能,在神经网络编程中,一定要避免显式的for循环。
12.更多向量化例子
如图2.18,对向量v的每个元素进行指数运算,用for循环如左侧所示一个个运算,为了更快运算我们去除for循环改成右侧的np.exp(v),右侧的向量化运算会快很多。向量化的内置函数还有np.log()计算log,np.abs()计算绝对值,np.maximum()找最大值,v**2计算每个元素的平方等。
13.向量化logistic回归
如图2.19,把m个样本集合到一个ndarray表示为X,X∈,则Z=np.dot(,X)+b,A=σ(Z)。b会自动转成符合运算的形状,每个元素都等于b,这是python广播机制。
14.向量化logistic回归的梯度输出
如图2.20,把m个a集合到一个ndarray表示为A,m个y集合到一个ndarray表示为Y,则dZ=A-Y,db=1/m * np.sum(dZ),dw=1/m * X * 。
如图2.21,从左到右是logistic回归去除for循环改成向量化,但是迭代过程仍然需要用for循环控制迭代次数。
15.关于python/numpy向量说明
Python/numpy提供了很大灵活性,同时这也有不好的地方。比如一行代码可以实现你想要的功能,太灵活了可能会引入很细微的错误。比如,你用一个横向量加一个列向量,你可能预计会报错说维度不匹配,但由于广播机制存在,你会得到一个求和之后的矩阵。
所以我们要加入一些技巧和提示,从而消除代码中的bug。
我们不要使用秩为1即shape为(n,)的数组,因为这既不是横向量也不是列向量,a.T和a是一样的。而是要把shape设成(n,1)列向量或者(1,n)横向量,并且判断shape不符合时作出提示。