1.测试集
在配置训练、验证和测试数据集的过程中做出正确决策会更高效的创建神经网络
在机器学习中,经常将样本分为训练集、验证集和测试集三部分。对于早期的机器学习的数据而言,经常使用 70%/30% 来划分验证集和测试集或者使用 60%/20%/20% 来划分训练集、验证集和测试集。
在大数据时代中,假如有1000000个数据,那么验证集就不需要太大,有10000条验证数据或者10000条测试数据就够了,即占到总量的10%以下。
举个例子:
假如需要做一个应用程序,分辨出用户上传的图片上含有猫的照片。
训练集:网页抓取,专业处理,分辨率高,这会导致训练集和验证集不是同一个分布
测试集:用户随机拍的,模糊,分辨率低
需要注意:验证集和测试集的数据来自同一分布。
- 偏差/方差
深度学习的误差很少权衡偏差和方差,总是分别考虑:
high bias:第1种情况,如果给这个数据集拟合一条直线,可能得到一个逻辑回归拟合,但并不能很好的拟合该数据集,即偏差高,为“欠拟合”。
high variance:第3种情况,如果拟合了一个很复杂的分类器,比如用了深度神经网络,可能很好的把数据即分类了,但是这种分类器方差较高,数据过度拟合。
**just right:**第2种情况,复杂度适中,数据拟合适度,称为适度拟合。
理解偏差和误差还可以通过训练集误差和验证集误差来评判:
**情况1:**假设训练集误差为 1%,验证集误差为11%,训练集设置较好,而验证集设置较差,过度拟合了训练集,高方差。
**情况2:**训练集误差为15%,而验证集误差为16%,而人的错误率几乎为0%,这个数据拟合不高,则为欠拟合,即偏差高。
**情况3:**训练集误差为15%,而验证集误差则更大,为30%,这种情况下,算法偏差高,方差也高。
**情况4:**训练集误差为0.5%,验证集误差为1%,偏差和方差都很低。
以上情况都是基于最优误差为0%(即基本误差很小)和训练集、验证数据来自同一分布前提下的。但是如果一张图片很模糊,人眼分辨误差为15%,那最后我们判断的思路就要换一下了。
算法偏差过高——选择新的算法,比如含有更多隐层或者隐藏单元的网格(解决掉偏差问题是最基础的,如果网络够大,通常可以很好的拟合训练集)—— 检查方差有没有问题(如果方差太大,搜集更多的数据)——直至找到一个偏差和方差都很小的框架。
在深度学习中,可以通过构建大的神经网络减小偏差而不影响方差,可以通过大量的数据减小方差而不影响误差,所以不用去权衡方差与偏差的关系。
3.L2正则表达式正则化(Regularization)
如果怀疑神经网络过度拟合了数据,即存在高方差问题,那么最先想到的方法可能是正则化或者准备更多的数据。
m i n w , b J ( w , b ) \underset{w,b}{min}J(w,b) w,bminJ(w,b) (通过优化w,b来减少代价函数)
具体一点,我们有:
J ( w , b ) = 1 m ∑ i = 1 m L ( y ∧ ( i ) , y ( i ) ) + λ 2 m ∥ w ∥ 2 2 J(w,b)=\frac{1}{m}\sum_{i=1}^{m}L(\overset{\wedge}{y}^{(i)},y^{(i)})+\frac{\lambda }{2m}\left \| w \right \|^{2}_{2} J(w,b)=m1∑i=1mL(y∧(i),y(i))+2mλ∥w∥22
其中,m代表的是样本的数量, λ \lambda λ是正则化参数(这也是一个超级参数), ∥ w ∥ 2 2 = ∑ j = 1 n x w j 2 = w T w \left \| w \right \|^{2}_{2} = \sum_{j=1}^{n_{x}} w_{j}^{2}=w^{T}w ∥w∥22=∑j=1nxwj2=wTw,这个称为L2正则表达式,只加w而不加a是因为w通常是一个高维参数矢量,已经可以表达高偏差问题了,w里有很多参数,基本上涵盖了所有参数,而不是b。
当然也有L1 表达式(regularization),可直接将 ∣ ∣ w ∣ ∣ 2 2 ||w || _{2}^{2} ∣∣w∣∣22换成||w||,公式为 ∣ ∣ w ∣ ∣ 1 = ∑ j = 1 n x w j ||w || _{1}= \sum_{j=1}^{n_{x}} w_{j} ∣∣w∣∣1=∑j=1nxwj
如果使用使用L1 正则表达式,则W会是个稀疏矩阵,即W向量中有很多0,尽管变稀疏了,但是却没有压缩内存,所以在训练模型的时候,更多的是使用L2正则化。
对于神经网络而言, J ( w [ 1 ] , b [ 1 ] , . . . , w l ] , b [ l ] ) = 1 m ∑ i = 1 m L ( y ∧ ( i ) , y l ) = λ 2 m ∑ l = 1 L ∣ ∣ w l ∣ ∣ F 2 J(w^{[1]},b^{[1]},...,w^{l]},b^{[l]})=\frac{1}{m}\sum_{i=1}^{m}L(\overset{\wedge}{y}^{(i)},y^{l})=\frac{\lambda}{2m}\sum_{l=1}^{L}||w^{l}||_{F}^{2} J(w[1],b[1],...,wl],b[l])=m1∑i=1mL(y∧(i),yl)=2mλ∑l=1L∣∣wl∣∣F2
其中, w : ( n [ l − 1 ] , n [ l ] ) w:(n^{[l-1]},n^{[l]}) w:(n[l−1],n[l]),这里l-1指的是隐藏单元的数量(我觉得这里是指下一层隐含层),n[l]表示l层单元的数量, ∣ ∣ w l ∣ ∣ F 2 = ∑ i = 1 n [ l − 1 ] ∑ j = 1 n [ l ] ( w i j [ l ] ) 2 ||w^{l}||_{F}^{2}=\sum_{i=1}^{n^{[l-1]}}\sum_{j=1}^{n^{[l]}}(w_{ij}^{[l]})^{2} ∣∣wl∣∣F2=∑i=1n[l−1]∑j=1n[l](wij[l])2,这里是指的该矩阵范数被称作“费罗 贝尼乌斯范数”,即矩阵每个元素的平方和。
正则化表达式主要是通过设置 λ \lambda λ来降低w的权重,从而实现对过拟合的调整
通过L2调整的方式:
对于矩阵W的导数,我们有dW[l]=(from back propagation)+
λ
m
W
[
l
]
\frac{\lambda}{m} W^{[l]}
mλW[l]
则对于新的更新迭代的下一轮W,我们有
W
[
l
]
:
=
W
[
l
]
−
α
d
W
[
l
]
W^{[l]}:=W^{[l]}-\alpha dW^{[l]}
W[l]:=W[l]−αdW[l]
则有 W [ l ] : = W [ l ] − α λ m W [ l ] − α ( f r o m b a c k p r o p a g a t i o n ) W^{[l]} :=W^{[l]}-\alpha \frac{\lambda}{m} W^{[l]}-\alpha (from back propagation) W[l]:=W[l]−αmλW[l]−α(frombackpropagation)
由于在梯度下降的时候,权重系数乘了一个比1小的系数,所以在每次迭代更新的时候,都会使得W这个权重变小,在不断迭代的过程中对权重进行衰减,所以也成为“权重衰减”。因为相应的把权重W给降低了,则输出的z=Wx+b 较小,如果是tanh函数,那么在接近0的时候呈线性,而不是复杂的非线性高方差拟合。
Python代码实现:
如何在代价函数的基础上增加惩罚项(forward propagation):
def compute_cost_with_regularization(A3,Y,parameters,lambd):
''''
Arguments:A3-post-activation,output of forward propagation,of shape
Y-"true" labels vector,of shape
parameters-python dictionary containing parameters of the model
lambd-hyper paramter lambd是超参数
Returns:
cost-vaule of the regularized loss function
''''
m=Y.shape[1] # if Y is the matrix 1 by m,and then Y.shape[1] is equal to m
W1=parameters["W1"] #这里假设是3层神经网络,这里为第一层的权重
W2=parameters["W2"]
W3=parameters["W3"]
cross_entropy_cost=compute_cost(A3,Y) #This gives you the cross-enteropy part of the cost,假设已经计算出了代价函数
L2_regularization_cost = (1/m)*(lambd/w)*(np.sum(np.square(W1))+np.sum(np.square(W2))+np.sum(np.square(W3))) #惩罚项,L2范数
cost function = cross_entropy_cost+L2_regularization_cost
return cost
Back propagation(反向传播):
def backward_propogation_with_regularization(X,Y,cache,lambd):
''''
X-input dataset,of shape(input size,number of examples)
Y-"true"label vector,of shape(output size,number of example)
cache-cache output from forward_propagation()
lambd-regularization hyperparameter,scalar
Returns:
gradients-A dictionary with the gradients with respect to each parameter,activation and pre-activation variables
''''
m=X.shape[1]
(Z1,A1,W1,b1,Z2,A2,W2,b2,Z3,A3,W3,b3)=cache
dZ3=A3-Y
dW3=1./m*np.dot(dZ3,A2.T)+(lambd/m)*W3
db3=1./m*np.sum(dZ3,axis=1,keepdims=True)
dA2=np.dot(W3.T,dZ3)
dZ2=np.multiply(dA2,np.int64(A2>0)#对激活函数进行求导,multiply是对应值相乘,这里应该是ReLU函数
dW2=1./m*np.dot(dZ2,A1.T)+(lambd/m)*W2
db2=1./m*np.sum(dZ2,axis=1,keepdims=True)
dA1=np.dot(W2.T,dZ2)
dZ1=np.multiply(dA1,np.int64(A1>0))
dW1=1./m*np.dot(dZ1,A1.T)+(lambd/m)*W1
db1=1./m*np.sum(dZ1,axis=1,keepdims=True)
gradients={"dZ3":dZ3,"dW3":dW3,"db3:":db3,"dZ2":dZ3,"dW2":dW3,"db2:":db3,"dZ1":dZ1,"dW1":dW1,"db1:":db1} #创建梯度下降的字典
return gradients
4.Dropout 正则化
当我们训练以下的神经网络的时候,出现了过拟合,dropout 会遍历网络的每一层,并设置消除神经网络中节点的概率,假设网络中的每个节点都以抛硬币的方式设置概率,保留和消除的概率都是0.5,设置完节点概率后,就会消除一些节点,然后用back propagation进行训练。
反向随机失活(inverted dropout)
处于完整性来考虑,我们用一个三层(l=3)网络来举例说明,说明如何在某一层中实施dropout,首先要定义向量d,d3表示一个三层的
dropout 向量,看是否d3=np.random.rand(a3.shape[0],a3.shape[1]) (创建一个维数与a3相同的矩阵)<keep-prob(是个数字,上个示例中它是0.5,本例中设为0.8,表示保存某个隐藏单元的概率,则消除任意一个隐藏单元的概率为0.2)
d3=np.random.rand(a3.shape[0],a3.shape[1]) #d3是一个布尔数组
a3=np.multiply(a3,d3) 将矩阵d3和a3矩阵对应元素相乘,作用是过滤掉d3中所有等于0的元素
a3 /= keep-prob #当我们删除a3中一些神经元的时候,为了使得z^[4]=w^[4]a^[3]+b^[4],那么我们需要修正或者弥补我们所需的那20%,从而使得a3的期望值不会改变,只是减少了网络的节点。
5.其他正则化方法
扩充(augment)训练数据来解决过拟合
如图,可以通过水平翻转、剪裁图片来增加训练集,虽然数据没那么多,
但是减少了扩张数据的代价。对于数字,还可以通过扭曲来增加训练集。
6.正则化输入
归一化输入需要俩个步骤:1.零均值化 (就是把数据集的散点移动到坐标轴附近,1图到2图) 2.归一化方差(下图的x1的方差比x2的方差要大得多,2图到3图,x1和x2的方差都为1)
如果需要用方差和均值来调整训练集数据,那么需要用相同的u和 σ 2 \sigma^{2} σ2来归一化测试集,而不是在训练集和测试集上分别预估u和 σ 2 \sigma^{2} σ2,因为我们希望的是,训练集和测试集都是通过相同u和 σ 2 \sigma^{2} σ2定义的相同数据转换,其中u和 σ 2 \sigma^{2} σ2是由训练集数据计算得来的。
为什么要归一化输入特征?
如下图,代价函数归一化之前和之后,归一化前,狭长型,归一化后,均匀许多。如果在归一化之前的图进行梯度下降,那么学习率需要很小,狭长型的那边需要迭代很多次。如果在归一化之后的,学习率和迭代步长可以较大,迭代次数也可以变小。
如果输入的特征取值范围相差很大,那么归一化起重要作用。如果相差不大,那么归一化特征就不是很重要了。
7.梯度消失和梯度爆炸
也就是说,当训练深度网络时,导数或坡度有时候会变得非常大。举个例子,假如我们有l层神经网络,输入特征为x[x1,x2],权重为 w [ l ] w^{[l]} w[l],设 b [ l ] b^{[l]} b[l]=0,激活函数g(z)=z,则有:
y ∧ = w [ l ] w [ l − 1 ] ⋯ w 1 x \overset{\wedge}{y}=w^{[l]}w^{[l-1]}\cdots w^{1}x y∧=w[l]w[l−1]⋯w1x
设权重
w
[
l
]
=
[
1.5
0
0
1.5
]
w^{[l]}=\begin{bmatrix} 1.5 & 0 \\ 0 & 1.5 \end{bmatrix}
w[l]=[1.5001.5] >0(1.5倍个单位矩阵),则
y
∧
=
1.
5
l
x
\overset{\wedge}{y}=1.5^{l}x
y∧=1.5lx,直接呈爆炸性增长,若w<1,则为爆炸性递减。
8.神经网络的权重初始化
先举一个神经元初始化的例子,单个神经元可能有4个输入特征,从X1到X4,经过激活函数a=g(z),最终得到 y ∧ \overset{\wedge}{y} y∧,则得到: z = w 1 x 1 + w 2 x 2 + ⋯ + w n x n z=w_{1}x_{1}+w_{2}x_{2}+\cdots +w_{n}x_{n} z=w1x1+w2x2+⋯+wnxn,为了预防z值过大或者过小,当n越大的时候,我们希望的是w[i]越小,最合理的方法就是设置w[i]=1/n (n为神经元的输入特征数量)
则有公式: W [ l ] = n p . r a n d o m . r a n d n ( s h a p e ) ∗ n p . s q r t ( 1 / n [ l − 1 ] ) W^{[l]}=np.random.randn(shape)*np.sqrt(1/n^{[l-1]}) W[l]=np.random.randn(shape)∗np.sqrt(1/n[l−1])
其中W为l层的权重矩阵,shape为矩阵的维数,其中sqrt表示平方根
对于其他变体函数,针对不同激活函数而言:
1.对于tanh 激活函数,则乘以
1
n
l
−
1
\sqrt{\frac{1}{n^{l-1}}}
nl−11,被称为Xavier 初始化,有些作者也习惯使用
2
n
[
l
−
1
]
+
n
[
l
]
\sqrt{\frac{2}{n^{[l-1]}+n^{[l]}}}
n[l−1]+n[l]2
2.对于ReLU 激活函数(最常用),则乘以 2 n l − 1 \sqrt{\frac{2}{n^{l-1}}} nl−12
9.梯度的数值逼近
在实施back propagation时,有一个测试叫作梯度检验,它的作用是确保backpropagation正确实施,需要逐渐实现梯度检验。
假设有一个函数为
f
(
θ
)
=
θ
3
f(\theta)=\theta^{3}
f(θ)=θ3,在
θ
\theta
θ右边取
θ
+
ε
\theta+\varepsilon
θ+ε,在左边取
θ
−
ε
\theta-\varepsilon
θ−ε,设取值分别为1,1.01,0.99,则
ε
=
0.01
\varepsilon =0.01
ε=0.01,如下图:
上图可得,较大的三角形的高比值更接近于 ε \varepsilon ε 的导数,得到的是一个双边公差,期望值为:
3 θ 2 = g ( θ ) ≈ f ( θ + ε ) − f ( θ + ε ) 2 ε 3\theta^{2}=g(\theta)\approx \frac{f(\theta+\varepsilon )-f(\theta+\varepsilon )}{2\varepsilon } 3θ2=g(θ)≈2εf(θ+ε)−f(θ+ε) (可自行代入数据感受下)
如果只考虑到单边误差,即 f ( θ + ε ) − f ( θ ) ε \frac{f(\theta+\varepsilon )-f(\theta )}{\varepsilon } εf(θ+ε)−f(θ) 或者 f ( θ ) − f ( θ − ε ) ε \frac{f(\theta)-f(\theta-\varepsilon)}{\varepsilon } εf(θ)−f(θ−ε),误差会更大。
所以,用双边误差的方法更逼近导数,更加精确。
10.梯度检验
假如有 W [ 1 ] , b [ 1 ] , ⋯   , W [ l ] , b [ l ] W^{[1]},b^{[1]},\cdots ,W^{[l]},b^{[l]} W[1],b[1],⋯,W[l],b[l],把所有的W矩阵都换成向量之后,做连接运算(得到一个巨型向量 θ \theta θ)
紧接着,我们有
d
W
[
1
]
,
d
b
[
1
]
,
⋯
 
,
d
W
[
1
]
,
d
b
[
l
]
dW^{[1]},db^{[1]},\cdots,dW^{[1]},db^{[l]}
dW[1],db[1],⋯,dW[1],db[l],用来初始化大向量
d
θ
d\theta
dθ
J ( θ ) = J ( θ 1 , θ 2 , ⋯   , θ n ) J(\theta)=J(\theta_{1},\theta_{2},\cdots,\theta_{n}) J(θ)=J(θ1,θ2,⋯,θn)
则我们有:
∂
J
(
θ
)
∂
θ
1
=
J
(
θ
1
+
ε
,
θ
2
,
⋯
 
,
θ
n
)
−
J
(
θ
1
−
ε
,
θ
2
,
⋯
 
,
θ
n
)
2
ε
\frac{\partial J(\theta)}{\partial \theta _{1}}=\frac{J(\theta_{1}+\varepsilon,\theta_{2},\cdots,\theta_{n})-J(\theta_{1}-\varepsilon,\theta_{2},\cdots,\theta_{n})}{2\varepsilon }
∂θ1∂J(θ)=2εJ(θ1+ε,θ2,⋯,θn)−J(θ1−ε,θ2,⋯,θn)
⋮
\vdots
⋮
∂
J
(
θ
)
∂
θ
n
=
J
(
θ
1
,
θ
2
,
⋯
 
,
θ
n
+
ε
)
−
J
(
θ
1
,
θ
2
,
⋯
 
,
θ
n
−
ε
)
2
ε
\frac{\partial J(\theta)}{\partial\theta _{n}}=\frac{J(\theta_{1},\theta_{2},\cdots,\theta_{n}+\varepsilon)-J(\theta_{1},\theta_{2},\cdots,\theta_{n}-\varepsilon)}{2\varepsilon }
∂θn∂J(θ)=2εJ(θ1,θ2,⋯,θn+ε)−J(θ1,θ2,⋯,θn−ε)
上面求出的 ∂ J ( θ ) ∂ θ n \frac{\partial J(\theta)}{\partial\theta _{n}} ∂θn∂J(θ)只是近似值,我们要判断的就是这个近似值 ∂ J ( θ ) ∂ θ n \frac{\partial J(\theta)}{\partial\theta _{n}} ∂θn∂J(θ) 和 ∂ J ( θ ) ∂ θ n t r u e \frac{\partial J(\theta)}{\partial\theta _{n}}_{true} ∂θn∂J(θ)true 真实值是否等同,则我们只需要检验其向量的差值:
∣ ∣ ∂ J ( θ ) ∂ θ n − ∂ J ( θ ) ∂ θ n t r u e ∣ ∣ 2 ||\frac{\partial J(\theta)}{\partial\theta _{n}}-\frac{\partial J(\theta)}{\partial\theta _{n}}_{true}||_{2} ∣∣∂θn∂J(θ)−∂θn∂J(θ)true∣∣2 再除以俩者的和
如果我们的 ε \varepsilon ε 取值是10(-7),当求出来的距离是10(-5)或者10^(-3),那么就要小心了,可能程序有bug