当前位置:   article > 正文

打开深度学习的锁:(3)进阶知识补充

打开深度学习的锁:(3)进阶知识补充

零、深度学习的技巧

1.偏差和方差解决技巧

1 先要解决偏差问题,当偏差解决以后再考虑方差问题。

2 当进行方差操作以后,一定要再次测试新的策略的会不会再次导致偏差问题, 也就是当解决了过拟合操作以后,一定要再次测试一下会不会欠拟合

减小偏差

  • 使用更复杂的模型
  • 增加模型参数
  • 减少正则化强度

减小方差

  • 使用更多的训练数据
  • 简化模型
  • 增加正则化强度(如L2正则化)
  • 使用集成方法(如bagging和boosting)

2.深度网络层数

先设计逻辑回归,然后一点点增加隐藏层的数量。

一、深度学习的核心

在深度学习中,模型的核心组成可以包括以下几个方面:

1. 参数(Weights and Biases)

  • 权重 ( w ):连接神经元之间的参数,用于调整输入特征的重要性。在深度神经网络中,每一个特征有自己的权重。宏观到每一层,不同的层都有自己的权重矩阵
  • 偏置 ( b ):每个神经元都有一个偏置,用于调整模型的输出,使其更灵活地拟合数据。

2. 网络架构(Network Architecture)

  • 层数(Layers):深度神经网络由多层神经元组成,包括输入层、隐藏层和输出层,但是在计算层数的时候不包括输入层

    在计算的时候,一般使用 L L L 或者 l l l 来所在表示层的位置。

  • 神经元数(Neurons):每一层中的神经元数,也决定了该层的复杂度。

    n n n来表示神经元的数量, l l l 层的神经元表示为 n [ l ] n^{[l]} n[l]

  • 线性函数(Linear Functions):提供基本的线性函数计算。

    公式为 z = W x + b z=Wx+b z=Wx+b l l l 层的线性函数为 z [ l ] = W [ l ] a [ l − 1 ] + b [ l ] z^{[l]}=W^{[l]}a^{[l-1]}+b^{[l]} z[l]=W[l]a[l1]+b[l] a [ l − 1 ] a^{[l-1]} a[l1]为前一层的激活值,对于第一层来说 a [ l − 1 ] a^{[l-1]} a[l1]是输入层。

    a i [ l ] a^{[l]}_i ai[l]表示第 l l l 层的第 i i i 个神经元的激活值

  • 激活函数(Activation Functions) 转换线性函数到非线性,如ReLU、sigmoid、tanh等,用于引入非线性,使模型能够学习复杂的模式。

    公式为 a [ l ] = g ( z [ l ] ) a^{[l]}=g(z^{[l]}) a[l]=g(z[l]),激活函数统一用 g g g 表示,激活值为 a a a,但是具体的算法则不一样。

2.1. 激活函数和其导数

Sigmoid 函数:

σ ( x ) = 1 1 + e − x \sigma(x) = \frac{1}{1 + e^{-x}} σ(x)=1+ex1
导数公式:
d σ ( z [ l ] ) d z [ l ] = a [ l ] ( 1 − a [ l ] ) \frac{d \sigma(z^{[l]})}{dz^{[l]}} = a^{[l]} (1 - a^{[l]}) dz[l]dσ(z[l])=a[l](1a[l])

ReLU 函数:

ReLU ( x ) = max ⁡ ( 0 , x ) \text{ReLU}(x) = \max(0, x) ReLU(x)=max(0,x)
导数公式:
d ReLU ( z [ l ] ) d z [ l ] = { 1 if  z [ l ] > 0 0 if  z [ l ] ≤ 0 \frac{d \text{ReLU}(z^{[l]})}{dz^{[l]}} =

{1if z[l]>00if z[l]0
dz[l]dReLU(z[l])={10if z[l]>0if z[l]0

Tanh 函数:

tanh ⁡ ( x ) = e x − e − x e x + e − x \tanh(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}} tanh(x)=ex+exexex
导数公式:
d tanh ⁡ ( z [ l ] ) d z [ l ] = 1 − ( a [ l ] ) 2 \frac{d \tanh(z^{[l]})}{dz^{[l]}} = 1 - (a^{[l]})^2 dz[l]dtanh(z[l])=1(a[l])2
tanh ⁡ ′ ( x ) = 1 − tanh ⁡ 2 ( x ) \tanh'(x) = 1 - \tanh^2(x) tanh(x)=1tanh2(x)

3. 损失函数(Loss Function)

  • 用于衡量模型预测值与真实值之间的差距。常见的损失函数有均方误差(MSE)、交叉熵损失(Cross-Entropy Loss)等。

4. 优化算法(Optimization Algorithm)

  • 用于更新模型参数以最小化损失函数。常见的优化算法有随机梯度下降(SGD)、Adam、RMSprop等。

5. 正则化(Regularization)

  • 防止过拟合的技术,如L1/L2正则化、Dropout等。

6. 学习率(Learning Rate)

  • 控制每次参数更新的步长大小,是优化过程中非常关键的超参数。

二、训练集、开发集、测试集

1:训练集(Training Set):60-80%

训练集的作用是为了学习数据的特征和模式,使模型能够对输入数据进行准确的预测。
主要的任务是获得学习到的 “模型”,也就是 W W W b b b 的值。

2:开发集(或验证集,Development Set/Validation Set):10-20%

在使用训练集获得了模型,即确定了 W W W b b b 的值以后使用开发集来测试==超参数==调优,例如学习率、正则化系数等。

2:测试集(Test Set):10-20%

检测最终的模型的性能,用于最终评估模型性能的数据集。

三:Bias(偏差)和Variance(方差)

Bias(偏差)

偏差是指模型预测值与真实值之间的差异。
高偏差表示模型在训练数据和测试数据上的预测都较差,即模型欠拟合(underfitting)。偏差高的模型通常过于简单,无法捕捉数据中的复杂模式。

特征:

  • 模型过于简单
  • 无法很好地拟合训练数据
  • 训练误差和测试误差都很高
    在这里插入图片描述

Variance(方差)

方差是指模型对训练数据中随机噪声的敏感程度
高方差表示模型在训练数据上表现很好,但在测试数据上表现较差,即模型过拟合(overfitting)。方差高的模型通常过于复杂,只记住训练数据中的噪声,但无法泛化到新的数据

特征:

  • 模型过于复杂
  • 在训练数据上表现很好,但在测试数据上表现较差
  • 训练误差低,测试误差高

在这里插入图片描述

Bias-Variance Tradeoff(偏差-方差权衡)

偏差和方差之间存在权衡关系,即在降低偏差的同时可能会增加方差,反之亦然。理想情况下,模型应当在偏差和方差之间找到一个平衡点,以确保其在训练数据和测试数据上都能有较好的表现。

  1. 高偏差、低方差:

    • 简单的线性模型
    • 训练误差和测试误差都较高
  2. 低偏差、高方差:

    • 复杂的神经网络模型
    • 训练误差低,测试误差高
  3. 适中偏差、适中方差:

    • 适度复杂的模型,如带有正则化的神经网络
    • 训练误差和测试误差都在合理范围内

解决方法

先要解决偏差问题,当偏差解决以后再考虑方差问题。

当进行方差操作以后,一定要再次测试新的策略的会不会再次导致偏差问题

减小偏差

  • 使用更复杂的模型
  • 增加模型参数
  • 减少正则化强度

减小方差

  • 使用更多的训练数据
  • 简化模型
  • 增加正则化强度(如L2正则化)
  • 使用集成方法(如bagging和boosting)

四:正则化(Regularization)

正则化就是利用一些手段,在模型训练解决解决模型过拟合、提高范化能力等问题。

不同的方法作用的阶段不同。

不过这之前需要明白一个概念:重要特征和最高权重

1. 重要特征和最高权重

PS:以下全为个人抽象理解,未来有极大概率修改这段话,切勿照本宣科。

在深度学习中,重要特征指的是“对预测影响较大”的特征值。

假设样本X有俩个特征:x1为0.9,x2为0.1

如果此时标签Y是1,那么x1就是重要特征,如果标签为0,那么x2就是重要特征。

虽然最后的关于特征的表示,是特征*权重,但是权重的值一般都比较小,类似0.01

即使一开始给非重要特征设置了高权重,在一次次优化中(类似梯度下降)非重要特征的权重也会变低,重要特征的权重会变高。

所以,从结果导向来看:重要特征就是权重高的特征非重要特征就是权重低的特征

2. L1正则化(Lasso正则化):作用于损失函数和权重

J ( w , b ) = 1 m ∑ i = 1 m L ( y ^ i , y i ) + λ m ∑ ℓ = 1 L ∥ ω [ ℓ ] ∥ J(w, b) = \frac{1}{m} \sum_{i=1}^m L(\hat y^{i},y^{i})+ \frac{\lambda}{m} \sum_{\ell=1}^L \|\omega^{[\ell]}\| J(w,b)=m1i=1mL(y^i,yi)+mλ=1Lω[]

d ω [ ℓ ] = d J d ω [ ℓ ] + λ m sign ( ω [ ℓ ] ) \text{d}\omega^{[\ell]} = \frac{d J}{d \omega^{[\ell]}} + \frac{\lambda}{m} \text{sign}(\omega^{[\ell]}) dω[]=dω[]dJ+mλsign(ω[])

解析:简单来说Lasso正则化就是在原有的损失函数上增加了一个 λ \lambda λ 倍的权重的方差,这样会导致如下的结果:

1:由于增加的内容基于权重的值,对于大权重的特征来说,损失会增大,所以下一次更新的时候权重会被减少很多。
2:对于小权重的特征来说,损失也会增大,但也没有那么大,所以下一次更新的时候权重会减少但是没有很多。

抽象举例,假设:大权重为100,小权重为1

这样操作以后,下一次更新也许大权重会变为 1 , 减少了99,也许小权重会变为 0.1,减少了 0.9。

虽然大权重变少了很多,但是还是比小权重高,所以对于模型来说,大权重的特征的重要性还是比小权重的特征的重要性要高。

为什么降低特征的权重可以减少过拟合呢?

因为可以减少对个别特征的过度依赖。泛化能力不足往往与模型对个别特征的过度依赖有关

在这里插入图片描述
此外,降低权重还有另外作用,减小非重要特征的影响力–权重被趋近于0。减小网络复杂度
在这里插入图片描述

对第一层来说,减小的是输入的特征的权重,优化的是输入样本的特征

但是对于深度网络的其它层来说,减小是上一层的输出的权重,优化的则是上一层神经网络

L1正则化前:
在这里插入图片描述L1正则化后:
在这里插入图片描述

3. L2正则化(Ridge正则化):作用于损失函数和权重

J ( w , b ) = 1 m ∑ i = 1 m L ( y ^ i , y i ) + λ 2 m ∑ j = 1 n w j 2 J(w, b) = \frac{1}{m} \sum_{i=1}^m L(\hat y^{i},y^{i})+ \frac{\lambda}{2m}\sum_{j=1}^n w_j^2 J(w,b)=m1i=1mL(y^i,yi)+2mλj=1nwj2

d ω [ ℓ ] = d J d ω [ ℓ ] + λ m ω [ ℓ ] \text{d}\omega^{[\ell]} = \frac{d J}{d \omega^{[\ell]}} + \frac{\lambda}{m} \omega^{[\ell]} dω[]=dω[]dJ+mλω[]

原理于L1类似,差异如下:

区别

  • L1正则化会导致模型参数中许多值变为零,从而产生稀疏解。这是因为L1正则化倾向于在优化过程中沿参数的坐标轴将其推向零,这也有助于特征选择。
  • L2正则化倾向于将参数值均匀地减小,而不是将它们推向零。这可以防止任何一个参数对模型结果产生过大影响,从而减轻模型过拟合的问题。

对异常值的敏感度

  • L1正则化对于异常值较不敏感,因为它倾向于选择某些特征而忽略其他特征,这使得模型更加简单且稳健。
  • L2正则化由于平方项的存在,对异常值较敏感,特别是当异常值的平方会对损失函数造成很大影响时。

解的唯一性

  • L1正则化可能会因为稀疏性而不产生唯一解,特别是当一些特征高度相关时。
  • L2正则化通常会产生唯一解,因为添加的惩罚项 λ ∑ j = 1 n w j 2 \lambda \sum_{j=1}^n w_j^2 λj=1nwj2 确保了损失函数是严格凸的

应用场景

  • L1正则化常用于特征选择和处理高维数据的场景,尤其是当一些特征是多余的或者相关性很高时。
  • L2正则化更适用于防止模型复杂度过高,需要处理模型中所有特征大体上都是重要的情况。

选择L1还是L2正则化通常取决于具体问题的需求和数据的特性。

例如,如果你需要一个简化的模型来解释模型是如何做出决策的(特征选择),L1可能是更好的选择。

如果你需要确保模型的所有参数都小一些,从而增强模型的泛化能力,那么L2可能是更合适的选择。同时L2也是最常用的正则化手段。

在实践中,也可以同时使用L1和L2正则化,这种组合被称为弹性网(Elastic Net)正则化。

4. Dropout正则化:作用于激活值

Dropout正则化不能用于测试阶段!!Dropout正则化不能用于测试阶段!!

相较于L1和L2利用损失函数来间接的弱化一些不重要的神经元。

Dropout 的核心思想更直接,就是在每次训练迭代中,随机将一些神经元的激活值 a a a 设置为零,每次训练设置的神经元都不同

Dropout 丢弃的不是神经元,丢弃的是当前个别神经元对于样本的预测,

或者说丢弃的是当前层某一个神经元对于原始输入样本的预测,每次训练迭代中丢的都不一样。

这个过程涉及到公式不明朗(在我看来是这样…)所以在此直接记录完成的代码。

# A的维度(当前神经元个数,样本的个数)
# A3:存放第三层的5个神经元对于最开始输入的10个样本的预测
A3 = np.random.randn(5, 10)

# 开始
# 1.设置 keep_prob 为 0.8 (即有 0.2 的概率舍弃)
keep_prob = 0.8 #概率为1-keep_prob

# 2.设计一个和A3形状一样的随机数矩阵
D3 = np.random.rand(a3.shape[0], a3.shape[1]) # 这里用的是rand,在[0,1) 之间取值
D3 = D3 < keep_prob #用True 和 False 随机填充 D3

# 3.利用随机矩阵的True 和 False随机丢弃 A3中的值
A3 = A3 * D3 #True == 1 / False == 0

# 4.扩大A3的值
A3 = A3/keep_prob #因为有(1-keep_prob)也就是20%,的值被舍弃了,所以扩大20%。
# A3= A3 /(8/10)
# A3= A3 *(10/8) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

其实我还是有点不理解第4步,不过先这样记着吧。

此外, Dropout正则化的设置比较灵活,对于重要的层,比如最后的输出层,我们也可以不用 Dropout,把 keep_prob 设置为1。
在这里插入图片描述

5. 其它正则化:

1.歪门邪道–数据扩增(Data Augmentation)

简单来说就是修改当前有的数据集为新数据。

举例数据集数据为图片,那么就可以水平反转图片、裁切图片、图片轻微扭曲

2.早停法(Early Stopping):基于验证集

简单来说,就是在测试寻找超参数(迭代次数、学习率等)的时候,找一个对于验证集来说损失最低的 W W W b b b, 即使这个 W W W b b b不是对于训练集的损失最低。
在这里插入图片描述

五、设置优化问

除了正则化以外,一些对于设置的优化方式,也可以帮助建立更好的模型,主要有以下几点。

1. 输入:Normalizing化

目的:可以将数据聚合到以0为原点,的方差标准化为 1。

在这里插入图片描述
公式:

第一步,获得输入的均值:
μ = 1 m ∑ i = 1 m x ( i ) \mu = \frac{1}{m} \sum_{i=1}^{m} x^{(i)} μ=m1i=1mx(i)
第二步,计算方差:
σ 2 = 1 m ∑ i = 1 m ( x ( i ) − μ ) 2 \sigma^2 = \frac{1}{m} \sum_{i=1}^{m} (x^{(i)} - \mu)^2 σ2=m1i=1m(x(i)μ)2
于是标准差:
σ = 1 m ∑ i = 1 m ( x ( i ) − μ ) 2 \sigma = \sqrt{\frac{1}{m} \sum_{i=1}^{m} (x^{(i)} - \mu)^2} σ=m1i=1m(x(i)μ)2

第三步,最终的标准化数据:
x ′ = x − μ σ x' = \frac{x - \mu}{\sigma} x=σxμ

通过输入Normalizing化,可以让特征分布的更均匀,损失函数图形更像一个碗,更容易梯度下降。
在这里插入图片描述

2. 防止梯度爆炸/梯度消失

防止梯度爆炸/梯度消失,主要是因为对于深层的神经网络,如果用统一的方式初始化 W 矩阵,W的初始值都相同。

在后续涉及到 W 乘法操作中可能会导致 W 过大或者过小,继而导致 Z 过大或者过小
在这里插入图片描述

所以我们需要优化W的初始化,即对不同的层用不同的W初始化函数

对于不同的激活函数,初始化的方法也不一样

1.对于ReLU作为激活函数: He

	WL=np.random.rand(shape) * np.sqrt( 2.0 / 前一层的神经元个数) # np.sqrt( 2 / n[l-1])
	# W的形状为(n[l], n[l-1]),n[l]为当前神经元个数; n[l-1]为前一层的神经元个数
  • 1
  • 2

2.对于Tanh\sigmoid 作为激活函数: Xavier

	WL=np.random.rand(shape) * np.sqrt( 1.0 / 前一层的神经元个数) # np.sqrt( 2 / n[l-1])
	# W的形状为(n[l], n[l-1]),n[l]为当前神经元个数; n[l-1]为前一层的神经元个数
  • 1
  • 2

也有第二个版本

	WL=np.random.rand(shape) * np.sqrt( 2.0 / (前一层的神经元个数)+(当前层的神经元个数)) # np.sqrt( 2 / n[l-1])
	# W的形状为(n[l], n[l-1]),n[l]为当前神经元个数; n[l-1]为前一层的神经元个数
  • 1
  • 2

3. 梯度检查(Gradient Checking)

当模型出现一些问题的时候,我们需要逐一排查,其中一个很重要的部分是对 梯度下降算法”和“反向传播”的检查,要进行梯度检查,必须要考虑下面这三点:

  1. 只有在debug的时候,代码调式的时候才可以使用。训练测试的时候不要使用。
  2. 考虑代码中是否用了正则化
  3. 不能与 dropout 一起用

1. 中心差分公式

梯度检查的核心来源于中心差分公式
f ′ ( x ) ≈ f ( x + h ) − f ( x − h ) 2 h f'(x) \approx \frac{f(x + h) - f(x - h)}{2h} f(x)2hf(x+h)f(xh)
函数 f ( x )在 x 的点导数 ≈ f ( x + 一个微小的偏量 ) − f ( x − 一个微小的偏量 ) 2 ∗ 一个微小的偏量 函数f(x)在x的点导数\approx \frac{f(x + 一个微小的偏量) - f(x -一个微小的偏量)}{2 * 一个微小的偏量} 函数fx)在x的点导数2一个微小的偏量f(x+一个微小的偏量)f(x一个微小的偏量)

在这里插入图片描述
不过,这个方法有一个必要的前提条件,

那就是 h h h, 这个移动的标量必须是一个极小值,类似 1 0 − 7 . 所得到的误差一般为 h 2 10^{-7}. 所得到的误差一般为h^2 107.所得到的误差一般为h2

2. 梯度检查

  1. 首先,将所有 L L L 层网络中的每一个 W W W b b b 聚合为一个单位
# θ ={w1,b1,w2,b2....wl,bl}
theta=np.concatenate([w1.flatten(),b1 , w2.flatten(),b2 , w3.flatten(),b3 , .....)}
  • 1
  • 2
  1. 然后,我们计算近似导数 dθ 的值
for i = L:= (J(θ1,θ2,θ3.....θi+h,...,θL)-J(θ1,θ2,θ3.....θi-h,...,θL)) / 2h
  • 1
  • 2
  1. 计算似导数 dθ 集与实际导集合的相对公差(relative error)

relative error = ∥ d θ − grad analytic ∥ ∥ d θ ∥ + ∥ grad analytic ∥ \text{relative error} = \frac{\left\| dθ - \text{grad}_{\text{analytic}} \right\|}{\left\| dθ \right\| + \left\| \text{grad}_{\text{analytic}} \right\|} relative error=dθ+ gradanalytic dθgradanalytic

这个移动的标量必须是一个极小值,类似 1 0 − 7 10^{-7} 107

如果 h h h 1 0 − 7 10^{-7} 107 ,那么relative error的值应该在 1 0 − 5 10^{-5} 105 1 0 − 9 10^{-9} 109 之间,否则为异常。

PS、Python技巧

1.随机数 randn 和 rand 的区别

在Python中,特别是在涉及到科学计算和数据处理的库NumPy中,randnrand函数都用来生成随机数,但它们的用途和输出的随机数类型有所不同:

  1. numpy.random.randn:

    • randn函数生成的是服从标准正态分布(均值为0,方差为1的正态分布)的随机数。
    • 可以生成任意形状的数组。
    • 例如,np.random.randn(2, 3)会生成一个2行3列的数组,数组中的每个元素都是从标准正态分布中随机抽取的。
  2. numpy.random.rand:

    • rand函数生成的是在区间[0, 1)内均匀分布的随机数。
    • 同样可以生成任意形状的数组。
    • 例如,np.random.rand(2, 3)会生成一个2行3列的数组,数组中的每个元素都是从[0, 1)区间的均匀分布中随机抽取的。

简而言之,主要区别在于:

  • randn用于生成符合标准正态分布的随机数。
  • rand用于生成符合均匀分布的随机数。

具体到应用:

初始化权重矩阵:randn

Dropout正则化:rand

2.同时设置网络层数

3.多维数组转一维向量

flatten 操作通常用于将多维数组(如矩阵或张量)变为一维数组(向量)

import numpy as np

a=np.random.rand(3,3)
print (a)
# [[0.81326486 0.08026124 0.38529666]
#  [0.26521685 0.2712353  0.37634291]
#  [0.70843229 0.34048282 0.32902673]]

a=a.flatten()
print(a)
#[0.81326486 0.08026124 0.38529666 0.26521685 0.2712353  0.37634291 0.70843229 0.34048282 0.32902673]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/602612
推荐阅读
相关标签
  

闽ICP备14008679号