输入一张64*64的图片并识别,是猫输出标签1;不是,输出标签0。
符号定义:
x:表示一个 n x n_{x} nx维数据,为输入数据, ( n x , 1 ) (n_{x},1) (nx,1),此例 n x n_{x} nx= 64 ∗ 64 ∗ 3 64*64*3 64∗64∗3=12288;y:表示输出结果,取值为(0,1); X = [ x 1 , x 2 , . . . , x m ] X=[x^{1},x^{2},...,x^{m}] X=[x1,x2,...,xm]:表示所有的训练数据集的输入值,维度为 ( n x , m ) (n_{x},m) (nx,m),m为样本数; Y = [ y 1 , y 2 , . . . , y m ] Y=[y^{1},y^{2},...,y^{m}] Y=[y1,y2,...,ym]:表示所有的训练数据集的输出值,维度为 ( 1 , m ) (1,m) (1,m),此处约定为行向量,方便计算。逻辑回归是一个二分类算法。 假设函数(Hypothesis Function): z = w T x + b z=w^{T}x+b z=wTx+b
使用假设函数直接预测并不能取得较好结果。 逻辑回归主要参数:
输入的特征向量: x ∈ R n x x\in R^{n_{x}} x∈Rnx,其中 nx是特征数量;
用于训练的标签: y ∈ ( 0 , 1 ) y\in (0,1) y∈(0,1)
权重: w ∈ R n x w\in R^{n_{x}} w∈Rnx
偏置: b∈R,
输出: y ^ = σ ( w T x + b ) \hat{y}=\sigma (w^{T}x+b) y^=σ(wTx+b)
Sigmoid 函数: σ = σ ( z ) = σ ( w T x + b ) = 1 1 + e − z \sigma=\sigma (z)=\sigma(w^{T}x+b)=\frac{1}{1+e^{-z}} σ=σ(z)=σ(wTx+b)=1+e−z1
图像:
分类问题中,倾向于用概率表示分类结果,故引入 σ \sigma σ函数,将 w T x + b w^{T}x+b wTx+b约束在[0,1]之间。
损失函数(loss function)用于衡量预测结果与真实值之间的误差。
最简单的损失函数定义方式为平方差损失(多个样本时也称二次代价函数): L ( y ^ , y ) = 1 2 ( y ^ − y ) 2 L(\hat{y},y)=\frac{1}{2}(\hat{y}-y)^{2} L(y^,y)=21(y^−y)2 但 Logistic 回归中我们并不倾向于使用这样的损失函数,因为之后讨论的优化问题会变成非凸的,最后会得到很多个局部最优解,梯度下降法可能找不到全局最优值。 一般使用交叉熵 L ( y ^ , y ) = − y l o g y ^ + ( 1 − y ) l o g ( 1 − y ^ ) L(\hat{y},y)=-ylog\hat{y}+(1-y)log(1-\hat{y}) L(y^,y)=−ylogy^+(1−y)log(1−y^)
损失函数是在单个训练样本中定义的,它衡量了在单个训练样本上的表现。而代价函数(cost function,或者称作成本函数)衡量的是在全体训练样本上的表现,即衡量参数 w 和 b 的效果. J ( w , b ) = 1 m ∑ i = 1 m L ( y ^ ( i ) , y ( i ) ) J(w,b)=\frac{1}{m}\sum_{i=1}^{m}L(\hat{y}^{(i)},y^{(i)}) J(w,b)=m1i=1∑mL(y^(i),y(i))
理解 y=1时,想尽可能的减小损失函数, y ^ \hat{y} y^就要尽可能的大; y=0时,想尽可能的减小损失函数, y ^ \hat{y} y^就要尽可能的小。 在全局中,减小代价函数时,就需要无数次迭代找到最小代价函数时的w和b。
函数的最陡增长方向。按梯度的方向走,函数增长得就越快。那么按梯度的负方向走,函数值自然就降低得最快了。
简单起见,假设w和b都是一维实数,此时,J关于w和b的图像如下所示:
由此可见,J是一个凸函数(convex),(实际上在逻辑回归中,我们必须定义J为凸函数,非凸函数有多个局部最低点),这样就保证我们无论怎么初始化w,b都一定能够找到合适的最优解。
w : = w − α d J ( w , b ) d w w:=w-\alpha \frac{dJ(w,b)}{dw} w:=w−αdwdJ(w,b) b : = b − α d J ( w , b ) d b b:=b-\alpha \frac{dJ(w,b)}{db} b:=b−αdbdJ(w,b) 其中 α 表示学习速率,即每次更新的 w 的步伐长度。当 w 大于最优解 w′ 时,导数大于 0,那么 w 就会向更小的方向更新。反之当 w 小于最优解 w′ 时,导数小于 0,那么 w 就会向更大的方向更新。迭代直到收敛。
如上所示的流程中,利用一下公式求导。
神经网络中的计算即是由多个计算网络输出的前向传播与计算梯度的后向传播构成。反向传播(Back Propagation)即是当我们需要计算最终值相对于某个特征变量的导数时,我们需要利用计算图中上一步的结点定义,即利用以上链式法则求导。
使用Computation Graph计算
假设输入的特征向量维度为 2,即输入参数共有 x1, w1, x2, w2, b 这五个。
首先反向求出 L 对于 a 的导数: d a = d L ( a , y ) d a = − y a + 1 − y 1 − a da=\frac{dL(a,y)}{da}=-\frac{y}{a}+\frac{1-y}{1-a} da=dadL(a,y)=−ay+1−a1−y
然后继续反向求出 L 对于 z 的导数: d z = d L d z = d L ( a , y ) d z = a − y dz=\frac{dL}{dz}=\frac{dL(a,y)}{dz}=a-y dz=dzdL=dzdL(a,y)=a−y
继续反向求出 L 对于 w和b 的导数: d w 1 = d L d w 1 = x 1 ∗ d z dw_{1}=\frac{dL}{dw_{1}}=x_{1}*dz dw1=dw1dL=x1∗dz d w 2 = d L d w 2 = x 2 ∗ d z dw_{2}=\frac{dL}{dw_{2}}=x_{2}*dz dw2=dw2dL=x2∗dz d b = d z db=dz db=dz
依此类推求出最终的损失函数相较于原始参数的导数之后,根据如下公式进行参数更新:
w 1 : = w 1 − α d w 1 w_{1}:=w_{1}-\alpha dw_{1} w1:=w1−αdw1 w 2 : = w 2 − α d w 2 w_{2}:=w_{2}-\alpha dw_{2} w2:=w2−αdw2 b : = b − α d b b:=b-\alpha db b:=b−αdb
因此,对于单个样本的梯度下降法,只需要使用 d z = d L d z = d L ( a , y ) d z = a − y dz=\frac{dL}{dz}=\frac{dL(a,y)}{dz}=a-y dz=dzdL=dzdL(a,y)=a−y计算dz,然后更新参数w和b。
我们需要将对于单个用例的损失函数扩展到整个训练集的代价函数: J ( w , b ) = 1 m ∑ i = 1 m L ( y ^ ( i ) , y ( i ) ) J(w,b)=\frac{1}{m}\sum_{i=1}^{m}L(\hat{y}^{(i)},y^{(i)}) J(w,b)=m1i=1∑mL(y^(i),y(i)) a ( i ) = y ^ ( i ) = σ ( z ( i ) ) σ ( w T x ( i ) + b ) a^{(i)}=\hat{y}^{(i)}=\sigma (z^{(i)})\sigma (w^{T}x^{(i)}+b) a(i)=y^(i)=σ(z(i))σ(wTx(i)+b)
对于某个权重参数 w1,其导数计算为: ∂ J ( w , b ) ∂ w 1 = 1 m ∑ i = 1 m ∂ L ( a ( i ) , y ( i ) ) ∂ w 1 \frac{\partial J(w,b)}{\partial w_{1}}=\frac{1}{m}\sum_{i=1}^{m}{\frac{\partial L(a^{(i)},y^{(i)}) }{\partial w_{1}}} ∂w1∂J(w,b)=m1i=1∑m∂w1∂L(a(i),y(i)) 即:
下面的截图就是一个非向量化的实现: 左边是求导过程,右边是梯度下降过程(只下降了一步,需要两个for循环,一个是遍历m个样本,另一个是遍历每个特征):
非向量化计算 z = w T x + b z=w^{T}x+b z=wTx+b,代码如下:
z=0 for i in range(n_x): z+=w[i]*x[i] z+=b向量化计算:
z=np.dot(w,x)+b用向量化代替for循环(多次迭代时,仍然需要for循环)。
Numpy中一般要求输入数组的shape一致。当数组中shape不相等时就会出现广播机制,满足规则,就可以运算,否则出错。 四条规则:
让所有输入数组都向其中 shape 最长的数组看齐,shape 中不足的部分都通过在前面加 1 补齐;输出数组的 shape 是输入数组 shape 的各个轴上的最大值;如果输入数组的某个轴和输出数组的对应轴的长度相同或者其长度为 1 时,这个数组能够用来计算,否则出错;当输入数组的某个轴的长度为 1 时,沿着此轴运算时都用此轴上的第一组值。演示:
import numpy as np a=np.random.randn(5) print(a) print(a.shape)输出结果:
print(a.T)#转置 print((a.T).shape)发现输出结果一样,实际上,a是一个一维数组,shape函数返回一个元组类型的值(单个元素不能构成元组,后面得加“,”)
a=np.random.randn(5,1) print(a) print(a.shape)输出: 向量是一个二维数组,是一个特殊的矩阵。而矩阵又是最常用的二维数组。 具体可参考:numpy的数组、向量与矩阵