深度学习八股文

机器学习基础知识 1、逻辑回归和线性回归的区别
线性回归解决的是回归问题,逻辑回归相当于是线性回归的基础上,来解决分类问题。
线性回归(Linear Regression):
深度学习八股文
文章图片

逻辑回归:
深度学习八股文
文章图片

从上面两个公式:逻辑回归可以理解为在线性回归后加了一个 sigmoid 函数。将线性回归变成一个0~1输出的分类问题。逻辑回归本质上是一个线性回归模型,因为除去sigmoid映射函数关系,其他的步骤,算法都是线性回归的。可以说,逻辑回归都是以线性回归为理论支持的,只不过逻辑回归可以轻松解决 0/1 分类问题。
基础知识

  1. 为什么深度学习模型的参数都在 0-1 之间?
    因为参数越小代表模型越简单,越是复杂的模型,越是尝试对所有样本进行拟合,包括异常点。这就会造成在较小的区间中产生较大的波动,这个较大的波动也会反映在这个区间的导数比较大。只有越大的参数才可能产生较大的导数。因此参数越小,模型就越简单。
  2. 实现参数的稀疏有什么好处?
    因为参数的稀疏,在一定程度上实现了特征的选择。一般而言,大部分特征对模型是没有贡献的。这些没有用的特征虽然可以减少训练集上的误差,但是对测试集的样本,反而会产生干扰。稀疏参数的引入,可以将那些无用的特征的权重置为0.
  3. batch_size的大小对学习率的影响?
    (1)batch-size大,学习率也可以取得大一点,而且,batch-size大通常更新次数少,所以需要更多的epoch才能让loss收敛。
    (2)batch-size小,学习率应该取得小一点,取的大会发生nan(梯度爆炸了),batch-size小通常更新次数多,较少的epoch就课可以让loss收敛,但是缺点是训练过程慢。
  4. 为什么batch-size小,学习率取的大会发生nan?
    学习率较高的情况下,直接影响到每次更新值的程度比较大,走的步伐因此也会大起来。如下图,过大的学习率会导致无法顺利地到达最低点,稍有不慎就会跳出可控制区域,此时我们将要面对的就是损失成倍增大(跨量级)。
    深度学习八股文
    文章图片

  5. 关于L0、L1和L2范数
    参考:关于L1, L2的深度学习知识点
    所有的范数都可以用闵可夫斯基距离(也叫L ? P L-P L?P 范数)公式求得,闵可夫斯基距离公式:
    L p = ( ∑ 1 n x i p ) 1 p , x ? = ( x 1 , x 2 , . . . . , x n ) L_p =(\sum_{1}^{n} x_i^p)^\frac{1}{p}, \vec x=(x_1,x_2, ....,x_n) Lp?=(1∑n?xip?)p1?,x =(x1?,x2?,....,xn?)
    (1) L0 范数( ∣ ∣ x ? ∣ ∣ 0 ||\vec x||_0 ∣∣x ∣∣0?)按照闵可夫斯基公式可知会带开0次方,但是开0次方无法计算,所以一般L0范数就是指一个向量a ? \vec a a中非0 0 0 元素的个数。L0范数很难优化求解.
    (2) L1范数( ∣ ∣ x ? ∣ ∣ 1 ||\vec x|| _1 ∣∣x ∣∣1?)指向量中各个元素绝对值之和.
    L 1 = ( ∑ 1 n ∣ x i ∣ ) , x ? = ( x 1 , x 2 , . . . . , x n ) L_1 =(\sum_{1}^{n} |x_i|), \vec x=(x_1,x_2, ....,x_n) L1?=(1∑n?∣xi?∣),x =(x1?,x2?,....,xn?)
    (3) L2范数( ∣ ∣ x ? ∣ ∣ 2 ||\vec x|| _2 ∣∣x ∣∣2?)指向量各元素的平方和然后求平方根.
    L 2 = ( ∑ 1 n x i 2 ) , x ? = ( x 1 , x 2 , . . . . , x n ) L_2 =\sqrt {(\sum_{1}^{n} x_i^2)}, \vec x=(x_1,x_2, ....,x_n) L2?=(1∑n?xi2?) ?,x =(x1?,x2?,....,xn?)
L 2 L2 L2的用处:
  1. L 2 L2 L2损失函数,也叫L2 loss,也被称为最小平方误差(LSE):
    L = ∑ i = 1 n ( y i ? f ( x i ) ) 2 L = \sum_{i=1}^{n} (y_i - f(x_i))^2 L=i=1∑n?(yi??f(xi?))2
    它是把目标值 y i y_i yi?与估计值 f ( x i ) f(x_i) f(xi?)的差值的平方和最小化。一般回归问题会使用此损失.
  2. 岭回归(Ridge Regression)和 L 2 L2 L2的关系(岭回归)
    岭回归并不是使用了 L 2 L2 L2损失函数的回归,而是在损失函数后面加了 L 2 L2 L2正则项。一般来说,回归的表达形式是:
    y ^ = ∑ j = 1 n w j x j + b \hat y=\sum_{j=1}^{n} w_j x_j + b y^?=j=1∑n?wj?xj?+b
    一般情况下,使用最小二乘法求解上述回归问题的目标是最小化如下的式子:
    w = a r g m i n w ∑ i = 1 n ( y i ? y ^ ) 2 w=argmin_w \sum_{i=1}^{n}(y_i-\hat y)^2 w=argminw?i=1∑n?(yi??y^?)2
    那么,岭回归就是要在上述最小化目标中加上一个惩罚项:
    w r i d g e = a r g m i n w ∑ i = 1 n ( y i ? y ^ ) 2 + λ ∑ j = 1 n β j 2 w^{ridge}=argmin_w \sum_{i=1}^{n}(y_i-\hat y)^2+\lambda \sum_{j=1}^{n}\beta_j^2 wridge=argminw?i=1∑n?(yi??y^?)2+λj=1∑n?βj2?
    这里的 λ \lambda λ也是待求参数。也就是说,岭回归是带L2范数惩罚的最小二乘回归.
  3. L 2 L2 L2正则化(搞懂L2正则化、l2范数求导_L1和L2 详解)
    一般来说,监督学习可以看作最小化下面的损失函数:
    1 N ∑ i = 1 N L ( y i , f ( x i ) ) \frac{1}{N} \sum_{i=1}^{N}L(y_i, f(x_i)) N1?i=1∑N?L(yi?,f(xi?))
    L 2 L2 L2正则就是在损失函数后面加一个 L 2 L2 L2正则化项来最小化模型的结构损失。
    1 N ∑ i = 1 N L ( y i , f ( x i ) ) + λ ∣ ∣ w ∣ ∣ 2 \frac{1}{N} \sum_{i=1}^{N}L(y_i, f(x_i)) + \lambda||w||^2 N1?i=1∑N?L(yi?,f(xi?))+λ∣∣w∣∣2,其中 λ \lambda λ就是权重衰减系数
    注意: L 2 L2 L2正则化是加上参数向量的平方和,不完全等价 L 2 L2 L2范数
  4. 权重衰减(权重衰减,学习率衰减)也叫L2正则化
    L2正则化的目的就是为了让权重衰减到更小的值,在一定程度上减少模型过拟合的问题,所以权重衰减也叫L2正则化。
  5. 欧式距离
    欧式距离衡量的是多维空间中两个点之间的绝对距离。也可以理解为:m维空间中两个点之间的真实距离,或者向量的自然长度(即该点到原点的距离)。在二维和三维空间中的欧氏距离就是两点之间的实际距离。具体的计算公式如下:
    d i s t ( X , Y ) = ∑ i = 1 n ( x i ? y i ) 2 dist(X, Y)=\sqrt{\sum_{i=1}^{n}(x_i - y_i)^2} dist(X,Y)=i=1∑n?(xi??yi?)2 ?
    注意:欧式距离的计算类似于 L 2 L2 L2范数的计算,都需要开根号
  6. 训练过程中,几句代码的作用
output = net(input)# l = loss(output, y.view(-1, 1))# 损失的计算 optimizer.zero_grad() # 梯度清零,等价于net.zero_grad() l.backward()# 反向传播求导 optimizer.step()# 参数的更新

优化器optimizer和损失函数loss function的区别:
(1)优化器定义了哪些参数是要用来更新的,并且设置了更新的方式(学习率、动量、SGD等),还有一些权重衰减的设置。
(2)损失函数是用来计算损失的,也可以说损失函数是负责反向传播求导用的。
  1. 激活函数的作用
    (1)激活函数是用来加入非线性因素的,解决线性模型所不能解决的问题。如果不用激活函数,每一层输出都是上层输入的线性函数 w 2 ( w 1 x + b 1 ) + b 2 w_2(w_1x+b_1)+b_2 w2?(w1?x+b1?)+b2?。容易验证,无论神经网络有多少层,输出都是输入的线性组合,与没有隐藏层效果相当,因此引入非线性函数作为激活函数,这样深层神经网络就有意义了(不再是输入的线性组合,可以逼近任意函数)
  2. ReLu激活函数和Sigmoid激活函数
    (1)sigmoid等函数,算激活函数时(指数运算),计算量大,反向传播求误差梯度时,求导涉及除法,计算量相对大,而采用Relu激活函数,整个过程的计算量节省很多
    (2)对于深层网络,sigmoid函数反向传播时,很容易就会出现 梯度消失 的情况(在sigmoid接近饱和区时,变换太缓慢,导数趋于0,这种情况会造成信息丢失),从而无法完成深层网络的训练
    (3)ReLu会使一部分神经元的输出为0,这样就造成了 网络的稀疏性,并且减少了参数的相互依存关系,缓解了过拟合问题的发生
  3. 为什么训练过程中的数据都要归一化?
训练神经网络的优化算法(参考:优化算法) 1、梯度下降和随机梯度下降(SGD)
方向导数和梯度
(1)标准梯度下降是在权值更新前对所有样例汇总误差,然后在进行反向传播。而随机梯度下降的权值的通过考察某个(或者某个batch)的训练样例来更新的。也就是标准梯度下降可以理解为一个epoch更新一次误差,而随机梯度下降就是一个batch更新一次 loss。
(2)在标准梯度下降中,权值更新的每一步对多个样例求和,需要更多的计算
(3)如果标准误差曲面有多个局部极小值,随机梯度下降有时可能避免陷入这些局部极小值中
2、动量法下降(momentum
因为梯度的物理意义是当前位置下降最快的方向,所以随机梯度下降法可能会出现不同维度收敛的速度不一样的情况(就容易发散),可能在x方向下降的慢,但是y方向下降快。这个时候就可以用动量法。相比于小批量随机梯度下降,动量法在每个时间步的自变量更新量近似于将最近 1 / ( 1 ? γ ) 1 / ( 1 ? γ ) 1/(1?\gamma)1/(1?\gamma) 1/(1?γ)1/(1?γ)个时间步的普通更新量(即学习率乘以梯度)做了指数加权移动平均后再除以 1 ? γ 1?\gamma 1?γ,所以,在动量法中,自变量在各个方向上的移动幅度不仅取决当前梯度,还取决于过去的各个梯度在各个方向上是否一致。
3、AdaGrad 算法
之前介绍过的优化算法中,目标函数自变量的每一个元素在相同时间步都使用同一个学习率来自我迭代,它根据自变量在每个维度的梯度值的大小来调整各个维度上的学习率,从而避免统一的学习率难以适应所有维度的问题。
(4)RMSProp算法
AdaGrad 算法因为调整学习率时分母上的变量s t s_t st? 一直在累加按元素平方的小批量随机梯度,所以目标函数自变量每个元素的学习率在迭代过程中一直在降低(或不变)。因此,当学习率在迭代早期降得较快且当前解依然不佳时,AdaGrad算法在迭代后期由于学习率过小,可能较难找到一个有用的解。RMSProp算法是动量法和AdaGrad 算法的结合。
4、AdaDelta算法
除了RMSProp算法以外,另一个常用优化算法AdaDelta算法也针对AdaGrad算法在迭代后期可能较难找到有用解的问题做了改进,有意思的是,AdaDelta算法没有学习率这一超参数。
5、Adam算法
RMSProp算法基础上对小批量随机梯度也做了指数加权移动平均
各种Norm 以及 Dropout 1、BN
(参考:BN)
0、BN的原理,为什么需要BN?
通常来说,数据标准化预处理对于浅层模型就足够有效了,随着训练的进行,当每层中参数更新时,靠近输出层的输出较难出现剧烈变化。但对深层神经网络来说,即使输入数据已做标准化,训练中模型参数的更新依然很容易造成靠近输出层输出的剧烈变化。这种计算数值的不稳定性通常令我们难以训练出有效的深度模型(这也是为社么神经网络的参数都在 [ ? 1 , 1 ] [-1,1] [?1,1]之间的原因,主要还是防止数据分布的巨大波动)。BN 的提出正是为了应对深度模型训练的挑战。
1、训练时的BN
在模型训练时,批量归一化利用小批量上的均值和标准差,不断调整神经网络中间输出,从而使整个神经网络在各层的中间输出的数值更稳定。Pytorchnn模块定义的BatchNorm1dBatchNorm2d类使用起来更加简单,二者分别用于全连接层和卷积层,都只需要指定输入的num_features参数值。
(1)对全连接层做批量归一化:BN层一般在全连接层和激活函数中间。即FC-BN-ReLU, θ ( B N ( x ) ) \theta(BN(x)) θ(BN(x))。
(2)对卷积层做批量归一化:对卷积层来说,BN 发生在卷积计算之后、应用激活函数之前。如果卷积计算输出多个通道,我们需要对这些通道的输出分别做批量归一化,且每个通道都拥有独立的拉伸和偏移参数,并均为标量。
2、预测时的BN
使用批量归一化训练时,我们可以将批量大小设得大一点,从而使批量内样本的均值和方差的计算都较为准确。将训练好的模型用于预测时,我们希望模型对于任意输入都有确定的输出。因此,单个样本的输出不应取决于批量归一化所需要的随机小批量中的均值和方差。一种常用的方法是在训练时通过移动平均估算整个训练数据集的样本均值和方差,并在预测时使用它们得到确定的输出。可见,和丢弃层一样,批量归一化层在训练模式和预测模式下的计算结果也是不一样的。
BN的优缺点 BN的优点:
- 防止过拟合:单个样本的输出依赖于整个 mini-batch,防止对某个样本过拟合;
- 加快收敛:梯度下降过程中,每一层的 W 和 b 都会不断变化,导致输出结果的分布在不断变化,后层网络就要不停地去适应这种分布变化。用 BN 后,可以使每一层输入的分布近似不变,数据都被拉到了非饱和区,所以收敛快。
- 防止梯度弥散:forward 过程中,逐渐往非线性函数的取值区间的上下限两端靠近,(以 Sigmoid 为例),此时后面层的梯度变得非常小,不利于训练。BN可以缓解这个问题。
- 允许较大的学习率
- 有轻微正则化的作用
BN的缺点
- 每次是在一个batch上计算均值、方差,如果batch size太小,则计算的均值、方差不足以代表整个数据分布
- batch size太大,会超过内存容量;需要跑更多的epoch,导致总训练时间变长;会直接固定梯度下降的方向,导致很难更新。
- 对于小 batch-size 偏差太大
BN的数学公式及其伪代码 BN的数学表达式为:
y = x ? E [ x ] V a r [ x ] + ? ? γ + β y=\frac{x-E[x]}{Var[x] + \epsilon } * \gamma + \beta y=Var[x]+?x?E[x]??γ+β
式中引入了缩放因子 γ \gamma γ和平移因子 β \beta β,这也是BN中的两个可学习参数,作者在文章里解释了他们的作用:
  • Normalize 到 μ = 0 , δ = 1 \mu =0, \delta =1 μ=0,δ=1 , 会导致新的分布丧失从前层传递过来的特征与知识
  • 以 Sigmoid 为例,加入 γ , β \gamma, \beta γ,β可以防止大部分值落在近似线性的中间部分,导致无法利用非线性的部分
    BN的计算方式如下
    • 首先,对小批量 B \mathfrak{B} B求均值和方差:
      μ B ? 1 m ∑ i = 1 m x ( i ) \mu_\mathfrak{B} \longleftarrow \frac{1}{m}\sum_{i=1}^{m} x^{(i)} μB??m1?i=1∑m?x(i)
      δ B 2 ? 1 n ∑ i = 1 m ( x ( i ) ? μ B ) 2 \delta_\mathfrak{B}^2 \longleftarrow \frac{1}{n}\sum_{i=1}^{m}(\bf{x^{(i)}}-\mu_\mathfrak{B})^2 δB2??n1?i=1∑m?(x(i)?μB?)2
      其中的平方计算是按元素求平方。
    • 接下来,使用按元素开方和按元素除法对 x ( i ) \bf{x^{(i)}} x(i)标准化:
      x ^ ( i ) ? x ( i ) ? μ B δ B 2 + ε \hat{x}^{(i)}\longleftarrow \frac{x^{(i)-\mu_\mathfrak{B}}}{\sqrt[]{\delta_\mathfrak{B}^2 + \varepsilon } } x^(i)?δB2?+ε ?x(i)?μB??
      这里ε > 0 \varepsilon > 0 ε>0是个很小的常数,保证分母大于 0。
    • 在标准化的基础上,批量归一化层引入了两个可以学习的模型参数,拉伸(scale)参数γ \bf{\gamma} γ 和偏移(shift)参数β \bf{\beta} β。这两个参数和 x i \bf{x}^{i} xi形状相同,都是d d d 维向量。他们与 x i \bf{x}^{i} xi分别做按元素乘法(符号 ⊙ \odot ⊙)和加法运算:
      y ( i ) ? γ ⊙ x ^ ( i ) + β \bf{y}^{(i)}\longleftarrow \gamma \odot \bf{\hat{x}}^{(i)}+\beta y(i)?γ⊙x^(i)+β
      至此,我们得到了x ( i ) \bf{x}^{(i)} x(i) 的批量归一化的输出 y ( i ) \bf{y}^{(i)} y(i)。值得注意的是,可学习的拉伸和偏移参数保留了不对 x ( i ) \bf{x}^{(i)} x(i)做归一化的可能:此时只需要学出 γ = δ B 2 + ? \gamma = \sqrt{\delta_\mathfrak{B}^2+\epsilon } γ=δB2?+? ?和β = μ B \beta = \bf{\mu}_\mathfrak{B} β=μB?
BN的代码如下
self.gamma = nn.Parameter(torch.ones(shape))# 这里的 gamma, beta 都是可学习参数 self.beta = nn.Parameter(torch.zeros(shape))def batch_norm(is_training, X, gamma, beta, moving_mean, moving_var, eps, momentum): # 判断当前模式是训练模式还是预测模式 if not is_training: # 如果是在预测模式下,直接使用传入的移动平均所得的均值和方差 X_hat = (X - moving_mean) / torch.sqrt(moving_var + eps)# bn的公式 else: assert len(X.shape) in (2, 4)# if len(X.shape) == 2:# 使用全连接层的情况,计算特征维上的均值和方差 mean = X.mean(dim=0) var = ((X - mean) ** 2).mean(dim=0) else: # 使用二维卷积层的情况,计算通道维上(axis=1)的均值和方差。这里我们需要保持X的形状以便后面可以做广播运算 mean = X.mean(dim=0, keepdim=True).mean(dim=2, keepdim=True).mean(dim=3, keepdim=True) var = ((X - mean) ** 2).mean(dim=0, keepdim=True).mean(dim=2, keepdim=True).mean(dim=3, keepdim=True) # 训练模式下用当前的均值和方差做标准化 X_hat = (X - mean) / torch.sqrt(var + eps) # 更新移动平均的均值和方差 moving_mean = momentum * moving_mean + (1.0 - momentum) * mean moving_var = momentum * moving_var + (1.0 - momentum) * var Y = gamma * X_hat + beta# 拉伸和偏移Y是X经过BN后的结果,和X是同型的 return Y, moving_mean, moving_var

2、LN—Layer Normalization
将输入的 feature map shape 记为 [ N , C , H , W ] [N, C, H, W] [N,C,H,W],其中 N 表示 batch size,即 N个样本;C 表示通道数;H、W 分别表示特征图的高度、宽度。针对BN不适用于深度不固定的网络(sequence长度不一致,如RNN),LN对深度网络的某一层的所有神经元的输入按以下公式进行 normalization 操作。
μ l = 1 H ∑ i = 1 H a i l \mu^l=\frac{1}{H}\sum_{i=1}^{H}a_i^l μl=H1?i=1∑H?ail?
σ l = 1 H ∑ i = 1 H ( a i l ? μ l ) 2 \sigma ^l = \sqrt{\frac{1}{H}\sum_{i=1}^{H}(a_i^l - \mu^l)^2} σl=H1?i=1∑H?(ail??μl)2 ?
LN 中同层神经元的输入拥有相同的均值和方差,不同的输入样本有不同的均值和方差。Layer Normalization (LN) 的一个优势是不需要批训练,在单条数据内部就能归一化。LN不依赖于batch size和输入sequence的长度,因此可以用于batch size为1和RNN中。LN用于RNN效果比较明显,但是在CNN上,效果不如BN。
3、IN—Instance Normalization
IN针对图像像素做normalization,最初用于图像的风格化迁移。在图像风格化中,生成结果主要依赖于某个图像实例,feature map 的各个 channel 的均值和方差会影响到最终生成图像的风格。所以对整个batch归一化不适合图像风格化中,因而对H、W做归一化。可以加速模型收敛,并且保持每个图像实例之间的独立。IN 对每个样本的 H、W 维度的数据求均值和标准差,保留 N 、C 维度,也就是说,它只在 channel 内部求均值和标准差,其公式如下:
μ t i = 1 H W ∑ l = 1 W ∑ m = 1 H x m i l i \mu_{t_i}=\frac{1}{HW}\sum_{l=1}^{W}\sum_{m=1}^{H}x_{m_il_i} μti??=HW1?l=1∑W?m=1∑H?xmi?li??
σ t i 2 = 1 H W ∑ l = 1 W ∑ m = 1 H ( x m i l i ? μ t i ) 2 \sigma_{t_i}^2 = \frac{1}{HW}\sum_{l=1}^{W}\sum_{m=1}^{H}(x_{m_il_i} - \mu_{t_i})^2 σti?2?=HW1?l=1∑W?m=1∑H?(xmi?li???μti??)2
x m i l j = x m i l j ? μ t i σ t i 2 + ε x_{m_il_j}=\frac{x_{m_il_j} - \mu_{t_i}}{\sqrt{\sigma_{t_i}^2+\varepsilon}} xmi?lj??=σti?2?+ε ?xmi?lj???μti???
4、GN—Group Normalization
GN是为了解决BN对较小的mini-batch size效果差的问题。GN适用于占用显存比较大的任务,例如图像分割。对这类任务,可能 batch size 只能是个位数,再大显存就不够用了,而当 batch size 是个位数时,BN 的表现很差,因为没办法通过几个样本的数据量,来近似总体的均值和标准差。GN 也是独立于 batch 的,它是 LN 和 IN 的折中。
GN的主要思想:在 channel 方向分组(group),然后每个 group 内做 Norm,计算( C / G ) × H × W (C / G)\times H \times W (C/G)×H×W的均值和方差,这样就与batch size无关,不受其约束。 具体方法:GN 计算均值和标准差时,把每一个样本 feature map 的 channel 分成 G 组,每组将有 C/G 个 channel,然后将这些 channel 中的元素求均值和标准差。各组 channel 用其对应的归一化参数独立地归一化。
μ n g ( x ) = 1 ( C / G ) H W ∑ ( c = g C / G ) ( g + 1 ) C / G ∑ h = 1 H ∑ w = 1 W x n c h w \mu_{n_g}(x)=\frac{1}{(C/G)HW}\sum_{(c=gC/G)}^{(g+1)C/G}\sum_{h=1}^{H}\sum_{w=1}^{W}x_{n_ch_w} μng??(x)=(C/G)HW1?(c=gC/G)∑(g+1)C/G?h=1∑H?w=1∑W?xnc?hw??
σ n g ( x ) = 1 ( C / G ) H W ∑ c = g C / G ( g + 1 ) C / G ∑ h = 1 H ∑ w = 1 W ( x n c h w ? μ n g ( x ) ) 2 + ε \sigma_{n_g}(x)=\sqrt{\frac{1}{(C/G)HW}\sum_{c=gC/G}^{(g+1)C/G}\sum_{h=1}^{H}\sum_{w=1}^{W}(x_{n_ch_w}-\mu_{n_g}(x))^2+\varepsilon} σng??(x)=(C/G)HW1?c=gC/G∑(g+1)C/G?h=1∑H?w=1∑W?(xnc?hw???μng??(x))2+ε ?
代码如下:
def GroupNorm(x, gamma, beta, G=16): # x_shape:[N, C, H, W] results = 0. eps = 1e-5 x = np.reshape(x, (x.shape[0], G, x.shape[1]/16, x.shape[2], x.shape[3]))x_mean = np.mean(x, axis=(2, 3, 4), keepdims=True) x_var = np.var(x, axis=(2, 3, 4), keepdims=True0) x_normalized = (x - x_mean) / np.sqrt(x_var + eps) results = gamma * x_normalized + beta return results

几种 normalize 方法的区别 几种归一化的区别
深度学习八股文
文章图片

1、BN是对一个 batch的每个通道的特征进行归一化,不改变通道数。即将不同样本的对应的通道特征进行相加求均值和标准差。操作的是所有样本的相同通道
2、LN是对一个batch 的每个样本的所有通道特征进行归一化,即将每个样本的所有通道上的特征相加求均值和标准差,不改变 batch-size 数。操作的是单个样本的所有通道
3、IN是对每个 batch 的每个样本的每个通道的特征进行归一化,即将每个样本的每个通道上的特征相加求均值和标准差。操作的是单个样本的单个通道
4、GN其实和LN相似,它先将一个 batch 的每个样本的所有通道特征进行分组(分成G组),然后求每组的均值和标准差,也可以说求每组的LN。操作的是单个样本的特定通道

2、Dropout
1、什么是 Dropout?
当训练一个深度神经网络时, 我们可以随机丢弃一部分神经元(同时丢弃其对应的连接边)来避免过拟合,这种方法就称为dropout(丢弃法)。
2、dropout为什么有用?
(1)集成的作用:dropout其实就是采用了机器学习里面的集成学习的思想,
  • 在 train 阶段,dropout的本质通过在学习过程中随机删除神经元,从而每一次都让不同的模型进行学习。比如,以概率 p=0.6 随机将神经元置 0,就相当于在10个神经元选4个神经元输出(4个神经元在工作,另外6神经元置0),这时我们就相当于训练了? 10 5 \complement _{10}^{5} ?105? 个模型,只是每个模型的参数量更少了(这也就是集成学习的思想)。
注意: 经过上面屏蔽掉某些神经元,使其激活值为0以后,我们还需要对向量进行缩放,也就是乘以 1/(1 - p)。如果在训练的时候,经过置 0 后,没有对挑选出来的向量进行缩放(rescale),那么在测试的时候,就需要对权重进行缩放。因为失活了一部分输出参与运算的数据变少了,这样得到线性累加值也就变小了,所以要进行缩放保持线性累加值和没有失活的时候是一样。否则会导致数值范围不一致。
  • 在测试时, 所有的神经元都是可以激活的, 这会造成训练和测试时网络的输出不一致,测试的时候该怎么办呢?测试的时候让每个模型投票来得到结果。如果在训练的过程中没有对数值范围进行调整(前面做了调整),预测模型的时候,每一个神经单元的权重参数要乘以概率 1-p 。比如,训练的时候,10个神经元置中6个置为0 (p=0.6,相当于训练时随机删除了6个神经元,只有4个神经元在工作),测试的时候是用10个神经元来投票,那么每个神经元的权重是 0.4(1 ? p = 0.4),操作的方法是将 dropout 层这10个神经元的值加起来乘以 0.4,即每个神经元的值都乘以0.4。注意,是所有神经元输出的值的和乘以0.4,比如 10个神经元每次只选一个神经元工作(以概率p=0.9将神经元置0),就相当于训练了10个模型,最后这10个神经元的结果都要输出,做法是把这10个神经元的值加起来乘以0.1(测试时),即相当于投票得出了结果。但是输出的个数不能少,该输出几个数还是几个数。
    (2)减少神经元之间复杂的共适应关系:即减少神经元之间的固定的依赖关系。由于Dropout每轮都会随机失活,导致神经元每次依赖的前一层的神经元都不一样,使得参数的学习不会依赖于固定关系的隐含节点,阻止了某些神经元的学习仅仅依赖于某些特定神经元才有效的现象,这样可以增强模型的泛化能力
总的来说,对于一个神经网络层y = f ( W ? X + b ) y=f(W \cdot X+b) y=f(W?X+b),我们可以引入一个mask函数使得y = f ( W ? m a s k ( X ) + b ) y = f(W \cdot mask(X) + b) y=f(W?mask(X)+b),设神经元的drop率为p,则mask函数可以表示为:
深度学习八股文
文章图片

一般来讲, 对于隐藏层的神经元, 其废弃率 p = 0.5 时效果最好, 这对大部分的网络和任务都比较有效. 当 p = 0.5 时, 在训练时有一半的神经元被丢弃, 只剩余一半的神经元是可以激活的, 随机生成的网络结构最具多样性,比如10个神经元随机删除5个,则可训练的模型有
? ? 10 5 \complement _{10}^{5} ?105?个,相当于取了最大值。 对于输入层的神经元, 其保留率通常设为更接近 1 的数, 使得输入变化不会太大。 对输入层神经元进行丢弃时, 相当于给数据增加噪声, 以此来提高网络的鲁棒性。
机器学习中经常使用集成学习。所谓集成学习,就是让多个模型单独进行学习,推理时再取多个模型的输出的平均值。用神经网络的语境来说,比如,
准备5个结构相同(或者类似)的网络,分别进行学习,测试时,以这 5 个网络的输出的平均值作为答案。实验告诉们,通过进行集成学习,神经网络的识
别精度可以提高好几个百分点,这个集成学习与Dropout 有密切的关系。这是因为可以将Dropout理解为,通过在学习过程中随机删除神经元,从而
每一次都让不同的模型进行学习。并且,推理时,通过对神经元的输出乘以删除比例(比如,0.5 等),可以取得模型的平均值。
3、dropout 的实现
# 手动实现 import numpy as np class Dropout: def __init__(self, dropout_ratio=0.5): self.dropout_ratio = dropout_ratio self.mask = None def forward(self, x, train_flg=True): if train_flg: # *为序列解包 self.mask = np.random.rand(*x.shape) > self.dropout_ratio# * 是解包符号 return x * self.mask else: return x * (1.0 - self.dropout_ratio) def backward(self, dout): return dout * self.mask

这里的要点是,每次正向传播时,掩蔽函数self.mask中都会以False的形式保存要删除的神经元(相当于概率p的伯努利分布)。self.mask会随机生成和x形状相同的数组,并将值比dropout_ratio大的元素设为True。反向传播时的行为和ReLU相同。也就是说,正向传播时传递了信号的神经元,反向传播时按原样传递信号;正向传播时没有传递信号的神经元,反向传播时信号将停在那里,梯度为0。
在pytorch中使用dropout,只需要一行torch.nn.Dropout(p=0.5)即可
4、dropout的反向传播
参考:dropout反向传播
感受野计算
1.神经网络的卷积核为什么是方形的,为什么不是奇数?
(1)有时候,我们需要使图片进行卷积前后图片大小保持不变,故需要进行 padding 操作。卷积操作使得图片大小保持不变的表达式如下: ( n ? k + 2 ? p ) / ( 2 ? s ) + 1 = n (n-k+2 * p) / (2 * s) +1=n (n?k+2?p)/(2?s)+1=n , n n n代表原图的大小, k k k 代表卷积核大小, p p p 代表 padding 大小。 运算得k = 2 p + 1 k=2p+1 k=2p+1 故卷积核选择奇数比较合适
(2)卷积运算包含大量矩阵运算和点积运算。卷积核是方的,可以用矩阵存储,处理起来就更方便。
  1. 卷积神经网络的特点
    (1)局部连接
    (2)权值共享
    (3)层次化表达:卷积网络的第三个特征是可以学到层次化的表达。卷积网络通过卷积层堆叠得到,每一层都是对前一层进行变换,提取的特征从低层次到高层次,逐渐变得抽象。
  2. 卷积的感受野问题
    感受野(Receptive Field),指的是一个特定的CNN特征(特征图上的某个点)在输入空间所受影响的区域,这个区域即该元素的感受野。
一个感受野可以用中心位置(center location)和大小(size)来表征。然而,对于一个CNN特征来说,感受野中的每个像素值(pixel)并不是同等重要。一个像素点越接近感受野中心,它对输出特征的计算所起作用越大。
感受野的计算问题 搞懂感受野的含义与计算
你知道如何计算CNN感受野吗?这里有一份详细指南
深度学习八股文
文章图片

在可视化CNN特征图的时候,我们经常采用上图左栏的方式,这种方式可以看到每个特征图所包含的特征数,但是很难知道每个特征的感受野的中心位置和大小,对于深度CNN,我们没有办法追踪到感受野信息。而右栏给出的是固定大小的CNN可视化方式,所有的特征图固定大小并保持与输入特征图大小一致,这可以解决前面的问题。每个特征被标记在其感受野所在的中心(从而定位出感受野中心位置)。由于一个特征图中所有的特征都有相同大小的感受野,我们可以简单地在每个特征周围画出一个边界框,从而获得感受野的大小。如下图所示:
深度学习八股文
文章图片

上图例子中输入特征图更大,为 7 × 7 7\times 7 7×7,采用的卷积参数如下:卷积核大小 k = 3 t i m e s 3 k = 3 times 3 k=3times3 ,padding大小 p = 1 p = 1 p=1 ,步长s = 2 s = 2 s=2。图的左栏和右栏分别给出了固定大小CNN特征图的3D和2D可视化。可以看出感受野大小增加迅速,以至于第二个特征层的中心特征的感受野已经覆盖了整个输入特征图。当采用的卷积其核大小为k k k,padding大小为p p p ,步长为s s s ,输出特征图的感受野可以按照如下公式计算:
感受野计算公式
为了计算CNN每一层的感受野,除了要知道特征图每个维度的特征数n n n, 还需要记录每一层的其他信息,包括当前层的感受野大小 r r r,当前层的feature map上两个相邻特征的距离 j j j,和左上角特征(第一个特征)的中心坐标 s t a r t start start。注意感受野(其实是特征图第一个特征的感受野)的中心坐标就等于这个特征的中心坐标
【深度学习八股文】 n o u t = n i n + 2 p ? k s + 1 n_{out}=\frac{n_{in}+2p-k}{s}+1 nout?=snin?+2p?k?+1
j o u t = j i n × s = ∏ i = 1 k ? 1 s i ( 因 为 第 一 层 一 般 j = 1 , 所 以 可 以 简 化 成 步 长 的 连 乘 形 式 ) j_{out}=j_{in} \times s =\prod_{i=1}^{k-1}s_i(因为第一层一般j=1,所以可以简化成步长的连乘形式) jout?=jin?×s=i=1∏k?1?si?(因为第一层一般j=1,所以可以简化成步长的连乘形式)
r o u t = r i n + ( k ? 1 ) × j i n = r i n + ( k ? 1 ) × ∏ i = 1 k ? 1 s i ( 将 上 式 和 本 式 子 结 合 后 的 形 式 ) r_{out}=r_{in} +(k-1)\times j_{in}=r_{in}+(k - 1)\times \prod_{i=1}^{k-1}s_i(将上式和本式子结合后的形式) rout?=rin?+(k?1)×jin?=rin?+(k?1)×i=1∏k?1?si?(将上式和本式子结合后的形式)
s t a r t o u t = s t a r t i n + ( k ? 1 2 ? p ) × j i n start_{out}=start_{in} +(\frac{k-1}{2}-p )\times j_{in} startout?=startin?+(2k?1??p)×jin?
  • 第一个式子根据输入特征图大小以及卷积参数计算输出特征图大小
  • 第二个式子计算输出特征图的特征间的间隔 j j j,其等于上一层的间隔值乘以卷积的步长,所以间隔值将是按照步长呈指数级增长
  • 第三个式子计算输出特征图的感受野大小,其等于前一层感受野大小加上 ( k ? 1 ) × j i n (k-1)\times j_{in} (k?1)×jin?,所以感受野是呈指数级增加
  • 第四个式子计算输出特征图的第一个特征感受野的中心坐标
由上面的式子看出,感受野的大小和感受野中心的计算都是递推公式。
某一层feature map(特性图)中某个位置的特征向量,是由前面某一层固定区域的输入计算出来的,那这个区域就是这个位置的感受野。经过多分枝的路径,按照感受野最大支路计算,shotcut不会改变感受野,ReLU, BNdropout 等元素级操作也不会影响感受野
感受野计算时有下面的几个情况需要说明
a)第一层卷积层的输出特征图像素的感受野的大小等于滤波器的大小;
b)深层卷积层的感受野大小和它之前所有层的滤波器大小和步长有关系;
c)计算感受野大小时,忽略了图像边缘的影响,即不考虑padding的大小。

各种卷积 可分离卷积 depthwise separable convolution
深度可分离卷积
深度可分离卷积 depthwise separable convolution,由 depthwise(DW)和 pointwise(PW)两个部分结合起来,用来提取特征feature map,相比常规的卷积操作,其参数数量和运算成本比较低。
1、普通卷积操作
对于一张 5×5 像素、三通道(shape为5×5×3),经过3×3卷积核的卷积层(假设输出通道数为4,则卷积核shape为3×3×3×4,最终输出4个Feature Map,如果有same padding则尺寸与输入层相同(5×5),如果没有则为尺寸变为3×3。
深度学习八股文
文章图片

卷积核一共 4 个 Filter,每个 Filter包含了 3 个 kernel,每个 kernel 的大小为 3 x 3。因此卷积层的参数数量可以用如下公式来计算:
N s t d = 4 × 3 × 3 × 3 = 108 N_std = 4 × 3 × 3 × 3 = 108 Ns?td=4×3×3×3=108
2、深度可分离卷积
  • 逐通道卷积
    Depthwise Convolution的一个卷积核负责一个通道,一个通道只被一个卷积核卷积。一张5×5像素、三通道彩色输入图片(shape为5×5×3),Depthwise Convolution首先经过第一次卷积运算,DW完全是在二维平面内进行。卷积核的数量与上一层的通道数相同(通道和卷积核一一对应)。所以一个三通道的图像经过运算后生成了3个Feature map(如果有same padding则尺寸与输入层相同为5×5),如下图所示。
    深度学习八股文
    文章图片
    其中一个Filter只包含一个大小为3×3的Kernel,卷积部分的参数个数计算如下:
    N d e p t h w i s e = 3 × 3 × 3 = 27 N_depthwise = 3 × 3 × 3 = 27 Nd?epthwise=3×3×3=27
    Depthwise Convolution完成后的Feature map数量与输入层的通道数相同,无法扩展Feature map。
  • 逐点卷积
    逐通道卷积运算对输入层的每个通道独立进行卷积运算,没有有效的利用不同通道在相同空间位置上的 feature 信息。因此需要 Pointwise Convolution 来将这些Feature map进行组合生成新的 Feature map。Pointwise Convolution的运算与常规卷积运算非常相似,它的卷积核的尺寸为 1×1×M,M为上一层的通道数。所以这里的卷积运算会将上一步的map在深度方向上进行加权组合,生成新的Feature map。有几个卷积核就有几个输出Feature map
    深度学习八股文
    文章图片

    由于采用的是1×1卷积的方式,此步中卷积涉及到的参数个数可以计算为:
    N p o i n t w i s e = 1 × 1 × 3 × 4 = 12 N_pointwise = 1 × 1 × 3 × 4 = 12 Np?ointwise=1×1×3×4=12
    经过Pointwise Convolution之后,同样输出了4张Feature map,与常规卷积的输出维度相同
3、普通卷积和深度可分离卷积的参数对比
常规卷积的参数个数为: N s t d = 4 × 3 × 3 × 3 = 108 N_std = 4 × 3 × 3 × 3 = 108 Ns?td=4×3×3×3=108
深度可分离卷积的参数由两部分相加得到:
N d e p t h w i s e = 3 × 3 × 3 = 27 , N p o i n t w i s e = 1 × 1 × 3 × 4 = 12 , N s e p a r a b l e = N d e p t h w i s e + N p o i n t w i s e = 39 N_depthwise = 3 × 3 × 3 = 27, N_pointwise = 1 × 1 × 3 × 4 = 12, N_separable = N_depthwise + N_pointwise = 39 Nd?epthwise=3×3×3=27,Np?ointwise=1×1×3×4=12,Ns?eparable=Nd?epthwise+Np?ointwise=39。
可以看出,相同的输入,同样是得到4张Feature map,Separable Convolution的参数个数是常规卷积的约1/3。因此,在参数量相同的前提下,采用Separable Convolution的神经网络层数可以做的更深。
反卷积
反卷积又称转置卷积、上采样
全卷积网络
空洞卷积 Dilated/Atrous Convolution
深度学习八股文
文章图片

Dilated Convolution with a 3 x 3 kernel and dilation rate 2
FLOPs的计算
FLOPS(即“每秒浮点运算次数”,可理解为计算速度)它常被用来估算电脑的执行效能,是一个衡量硬件性能的指标。
FLOPs,是floating point operations的缩写(s表复数),意指浮点运算数。理解为计算量。可以用来衡量算法/模型的复杂度。
卷积层的计算量:
1、1x1卷积核的作用
(1)降维和升维:比如Resnet中的11瓶颈结构就是用来改变维度的,而且可以节省计算量。
(2)跨通道信息交互:对于单通道feature map 用单核卷积即为乘以一个参数,而一般情况都是多核卷积多通道,实现多个feature map的线性组合
(3)可以实现与全连接层等价的效果,其实对于每一个位置的1
1卷积本质上都是对该位置上n个通道组成的n维vector的全连接操作。
(4)增加非线性特性
1x1卷积核,可以在保持 feature maps size不变的(即不损失分辨率)的前提下大幅增加非线性特性(利用后接的非线性激活函数)。
7、卷积代码,只实现了卷积的运算,没有实现stridepadding多输入通道操作。
def cov2d(X, K): h, w = K.shape# 卷积核尺寸 Y = torch.zeros(X.shape[0] - h + 1, X.shape[1] - w + 1) for i in range(Y.shape[0]): for j in range(Y.shape[1]): Y[i, j] = (X[i: i + h, j: j + w] * k).sum() return Y

模型训练时问题
  1. model.train()model.eval() 的区别
(1)model.train()启用 Batch NormalizationDropout。如果模型中有BN层(Batch Normalization)和 Dropout,需要在训练时添加model.train()model.train()是保证BN层能够用到每一批数据的均值和方差。对于Dropoutmodel.train()是随机取一部分网络连接来训练更新参数。
(2)model.eval()不启用 Batch NormalizationDropout。如果模型中有BN层(Batch Normalization)和Dropout,在测试时添加model.eval()model.eval()是保证BN层能够用全部训练数据的均值和方差,即测试过程中要保证BN层的均值和方差不变。对于Dropoutmodel.eval()是利用到了所有网络连接,即不进行随机舍弃神经元。训练完train样本后,生成的模型 model 要用来测试样本。在model(test)之前,需要加上model.eval(),否则的话,有输入数据,即使不训练,它也会改变权值。这是model中含有BN层和Dropout所带来的的性质。
关于Transformer的一些面试问题 1、transformer为什么需要用多头,而不用一头?
transformer为什么需要用多头
2、transformer为什么要使用Layer Nornalization?
Transformer里layer-normlization的作用
归一化方法:BN LayerNorm(LN)InstanceNorm(IN)GroupNorm(GN) SwitchableNorm(SN)
3、Layer Normalization原理介绍
4、BN的缺点:
  • 对batchsize的大小比较敏感,由于每次计算均值和方差是在一个batch上,所以如果batchsize太小,则计算的均值、方差不足以代表整个数据分布。
  • BN实际使用时需要计算并且保存某一层神经网络batch的均值和方差等统计信息,对于对一个固定深度的前向神经网络(DNN,CNN)使用BN,很方便;但对于RNN来说,sequence的长度是不一致的,换句话说RNN的深度不是固定的,不同的time-step需要保存不同的statics特征,可能存在一个特殊sequence比其他sequence长很多,这样training时,计算很麻烦。所以BN在RNN网络中效果不佳。Layer Normalization可以有效地解决上面的两个问题。
    深度学习八股文
    文章图片

    知乎上关于LN的解释
LN和BN不同点是归一化的维度是互相垂直的,如上图所示。在图1中N N N 表示样本轴,C C C 表示通道轴,F F F 是每个通道的特征数量。BN如右侧所示,它是取不同样本的同一个通道的特征做归一化;LN则是如左侧所示,它取的是同一个样本的不同通道做归一化。
总结就是BN是对batch中所有样本的某个通道求均值和方差,所以它归一化的是通道维度,如果通道数多的话,每个通道都可以求出一个均值和方差。LN是对同一个样本的不同通道之间做归一化。所以他不依赖batch-size的大小。
(3)注意力计算时为什么要除k \sqrt k k ??
注意力计算除 K \sqrt K K ? 的原因
transformer中的attention为什么scaled?
缩放具备分散注意力的作用;原始注意力值均聚集在得分最高的那个值,即 Q K T QK^T QKT 最大的值;而缩放后,注意力值就分散些,这样一般就获得更好的泛化能力。
残差连接的有效性详解 (1)网络性能退化问题。
一般认为神经网络的每一层分别对应于提取不同层次的特征信息,有低层,中层和高层,而网络越深的时候,提取到的不同层次的信息会越多,而不同层次间的层次信息的组合也会越多,表达出来的特征也更更好,所以要构建深层神经网络,但是随着网络层数的加深,网络的性能反而下降,这就是深层网络退化的现象,这种现象出现的根本原因就是梯度消失和梯度爆炸的问题。
(2)BN可以用来解决梯度消失/爆炸的问题,但是是在数据层面上的做法。
covariate shift(协方差偏移):这个现象指的是训练集数据分布与测试集数据分布不一致。
internal covariate shift:训练集和测试集输入分布的变化会给模型带来问题,一般而言数据分布差距不会太大,在输入时对数据做个标准化就基本可以解决这个问题,但是在很深的网络时这个问题就很严重。神经网络的隐藏层基于输入分布进行学习参数,之前层权值的变化,会导致之后的输入分布变化,隐藏层的输入分布总是在变,难以收敛。因为前面的层的结果会传递到后面的层,而且层次越多,前面的细微变化就会带来后面的巨大变化。梯度消失问题就是说反向求导的梯度结果无限趋于0,BN 将隐藏层的输出分布变成 0 均值,1方差的分布,解决了 internal covariate shift问题,也可以认为BN将隐藏层输出从饱和区拉到了非饱和区,对 sigmoid() 激活函数来说非饱和区梯度要大,所以可以加速网络的收敛,同时可以将网络层加深一些。所以BN实质是解决反向传播的梯度消失的问题,防止梯度消失,而且BN是在每个mini-batch上取平均,相当于加入了噪音,起到了一定的正则化作用。
(3)残差结构设计思想:残差网络的本质也是解决梯度消失/爆炸的问题,只不过是在网络结构层面的改变
残差网络的出现解决了构建深层神经网络时网络退化即梯度消失/爆炸的问题。残差结构主要设计有两个,快捷连接(shortcut connection)和恒等映射(identity mapping),快捷连接使得残差变得可能,而恒等映射使得网络变深,恒等映射主要有两个:跳跃连接和激活函数。
深度学习八股文
文章图片

实验证明残差块往往需要两层以上,单单一层的残差块 y = w 1 × x + x y=w_1 \times x + x y=w1?×x+x并不能起作用。实际中,考虑计算的成本,对残差块做了计算优化,即将两个¥ 3 x 3 3x3 3x3的卷积层替换为 1 x 1 + 3 x 3 + 1 x 1 1x1 + 3x3 + 1x1 1x1+3x3+1x1, 如下图。新结构中的中间 3 x 3 3x3 3x3的卷积层首先在一个降维 1 x 1 1x1 1x1卷积层下减少了计算,然后在另一个 1 x 1 1x1 1x1的卷积层下做了还原,既保持了精度又减少了计算量。
深度学习八股文
文章图片

ResNet 就是用这种跳跃结构来作为网络的基本结构。假如本来我们反向传播要优化的目标是 F ( x ) F(x) F(x),但通过这个结构就把优化的目标有 F ( x ) F(x) F(x)转化成 F ( x ) = H ( x ) ? x F(x)=H(x) - x F(x)=H(x)?x(因为残差后的输出为 H ( x ) = F ( x ) + x H(x)=F(x)+ x H(x)=F(x)+x)。这时候就不是把上面几层训练到一个等价映射,而是将其逼近于0,这样训练的难度比训练一个等价映射应该下降多了。
  • 为什么经过优化后就可以解决退化问题呢?
    深度学习八股文
    文章图片

    残差结构其实就是想办法让深层网络起码得和浅层网络作用差不多。例如,在一个网络中(假设有5层),如果前面四层已经达到一个最优的函数,那第五层就是没有必要的了,这时我们通过这种跳跃结构就可以保证网络层数更多(提取的信息更多)但是精度不会比浅层网络低。以上面的两层网络为例, z l z^l zl表示第 l l l层的输出,这种残差结构的输出为 z l + 1 = z l ? 1 + z l × w l + 1 + b l + 1 = z l ? 1 + ( z l ? 1 × w l + b l ) × w l + 1 + b l + 1 z^{l+1} = z^{l-1}+z^l\times w^{l+1}+b^{l+1} =z^{l-1}+(z^{l-1} \times w^l + b^l)\times w^{l+1}+b^{l+1} zl+1=zl?1+zl×wl+1+bl+1=zl?1+(zl?1×wl+bl)×wl+1+bl+1,所以,只需要将 w l , b l , w l + 1 , b l + 1 w^l,b^l,w^{l+1},b^{l+1} wl,bl,wl+1,bl+1优化为0即可实现恒等连接,即 z l + 1 = z l ? 1 z^{l+1} = z^{l-1} zl+1=zl?1。如果没有 z l ? 1 z^{l-1} zl?1跨层连接,则网络输出为 z l + 1 = z l × w l + 1 + b l + 1 = z l ? 1 + ( z l ? 1 × w l + b l ) × w l + 1 + b l + 1 z^{l+1} = z^l\times w^{l+1}+b^{l+1} =z^{l-1}+(z^{l-1} \times w^l + b^l)\times w^{l+1}+b^{l+1} zl+1=zl×wl+1+bl+1=zl?1+(zl?1×wl+bl)×wl+1+bl+1,要实现恒等连接的条件复杂很多,所以残差结构比较容易优化。通过改变结构,把训练目标进行转变,从而使得网络更容易优化。我们的优化目标就从一个等价映射将第4层变为逼近0了,逼近其他任何函数都会造成网络退化。通过这种方式就可以解决网络太深难训练的问题。
  • 上图两种残差结构的区别?
    上图两种结构分别针对ResNet34(左图)和ResNet50/101/152(右图),其目的主要就是为了降低参数的数目。左图是两个3x3,输出通道为64的卷积,参数数目:3 × 3 × 64 × 64 × 2 = 73728 3\times3\times64\times64\times2 =73728 3×3×64×64×2=73728,右图是第一个1x1的卷积把256维通道降到64维,然后在最后通过1x1卷积恢复,整体上用的参数数目: 1 × 1 × 256 × 64 + 3 × 3 × 64 × 64 + 1 × 1 × 64 ( 输 入 通 道 ) × 256 ( 输 出 通 道 ) = 69632 1\times1\times256\times64 + 3\times3\times64\times64 + 1\times1\times 64(输入通道)\times256(输出通道)= 69632 1×1×256×64+3×3×64×64+1×1×64(输入通道)×256(输出通道)=69632,右图的参数数量比左图少,因此,右图的主要目的就是为了减少参数量(不要和计算量混淆),从而减少计算量。
卷积、池化的计算量问题,FLOPs的计算,感受野的计算(重点) 卷积、池化计算公式 (1)卷积计算公式为: h = ( H ? k e r n e l + 2 × p a d ) s t r + 1 h = \frac{(H - kernel + 2\times pad)}{str} + 1 h=str(H?kernel+2×pad)?+1,当用卷积公式得到一个非整数的时候,torch会自动向下取整。
net = nn.Conv2d(3, 64, 3, 2, 0)# input_channel, out_channel, kernel_size, stride, padding x = torch.ones(1,3, 256, 256) y = net(x) y.shape# np.floor()向下取整。 >>>[1, 64, 127, 127],这里向下取整了

卷积的计算量
(2)池化计算公式为: h = ( H ? k e r n e l + 2 × p a d ) s t r + 1 h = \frac{(H - kernel + 2\times pad)}{str} + 1 h=str(H?kernel+2×pad)?+1,和卷积一样,只是基本上padding都会为0. 当用公式得到一个非整数的时候,torch会自动向下取整。
pool_layer = nn.MaxPool2d(2, 2, 0)# kernel_size, stride, padding=1 这里池化也设置了padding z = pool_layer(y)# y是上面例子的结果[1, 64, 127, 127] z.shape >>>[1, 64, 64, 64]# 也是向下取整的

深度学习中常用的激活函数 1、激活函数作用:如果不用激活函数,神经网络可以用一个通式来表达: y = w x + b y = wx +b y=wx+b,这就相当于是个单层模型,也就是说不用激活函数模型就没办法产生非线性决策边界,所以需要引入非线性元素,这就是激活函数的作用。激活函数需要满足的一些条件:**非线性连续可微的单调的:当激活函数是单调时,与单层模型相关的错误表面是凸的。平滑性:有单调导数的平滑函数已经被证明在某些情况下推广地更好.这些属性表明这些激活函数和Occam’s razor更一致。原点附近近似等于本身:当激活函数有这个属性,对于小的随机值初始化权重,神经网络将有效地学习.当激活函数没有这个属性,初始化权值必须使用特殊例子
  • Sigmoid函数S ( x ) = 1 1 + e ? x S(x)=\frac{1}{1 + e^{-x}} S(x)=1+e?x1?,该函数是将取值为[ ? ∞ , + ∞ ] [-\infty ,+\infty] [?∞,+∞] 的数映射到( 0 , 1 ) (0 ,1 ) (0,1)(开区间,不是闭区间)。不要和softmax操作搞混
    sigmoid函数图像如下图所示。sigmoid在 x = 0 x=0 x=0处导数最大,为 0.25,越到两端模型越容易出现梯度消失的情况。
    深度学习八股文
    文章图片

    优点:
    (1)函数具有单调递增,连续可导,输出范围有限,优化稳定,可以用于输出层,尽量不要用在隐藏层。
    (2)Sigmoid函数的倒数为S ( x ) ′ = S ( x ) ? ( 1 ? S ( x ) ) S(x)' = S(x) * (1 - S(x)) S(x)′=S(x)?(1?S(x)),函数及其导数形式简单.
    缺点:
    (1)该函数容易产生梯度消失,导致训练出现问题
    (2)由于该函数输出大于0,因此输出值不是以0为均值的,会造成偏移现象,导致后一层的神经元得到上一层输出的非0均值的数据作为输入,这将产生一个结果:每一层的线性映射部分对参数求偏导的结果都为正(或者负),这样在反向传播时,要么往正方向更新,要么往负方向更新,使得收敛速度慢。
    (3)函数及其导数含有指数,导致计算机运算的时间长,这也造成了收敛速度慢
  • Tanh函数
    Tanh函数也是一种常见的激活函数,它是sigmoid函数的变形。它的公式为: t a n h ( x ) = s i n h ( x ) / c o s h ( x ) = 2 × s i g m o i d ( 2 x ) ? 1 tanh(x)=sinh(x)/cosh(x)=2\times sigmoid(2x)-1 tanh(x)=sinh(x)/cosh(x)=2×sigmoid(2x)?1
    深度学习八股文
    文章图片

    从tanh函数的表达式或图像,我们知道tanh的值域[-1, 1],从而它解决了Sigmoid函数不是0均值输出问题。
    tanh函数的导函数图像如下:
    深度学习八股文
    文章图片

    tanh导函数的表达式或图像,知道其值域为[0,1],当线性变换结果大于3或者小于-3时,其导函数的值接近于0。
    在梯度消失方面,tanh函数的缺点同sigmoid函数的缺点一样,当该层线性变换的结果很大或很小时,梯度接近于0,会导致梯度很小,权重更新非常缓慢,即梯度消失。
Transformer、自注意力机制 深度学习八股文
文章图片

(1)自注意力机制的理解?
自注意力机制的公式如下:
A t t ( Q , K , V ) = s o f t m a x ( Q ? K T d k ) V Att(Q, K, V)=softmax(\frac{Q\cdot K^T}{\sqrt{d_k}})V Att(Q,K,V)=softmax(dk? ?Q?KT?)V
自注意力机制其实就是一种加权平均的形式,其实scaled dot-Product attention就是我们常用的使用点积进行相似度计算的attention,只是多除了一个( d k d_{k} dk?的代表每个头的维度)起到调节作用,使得内积不至于太大。先进行softmax计算出attention_score和其他单词的相似度并进行归一化处理形成概率,然后用概率乘以每个单词的V,加权得到attention
(2)为什么Transformer 要采用多头自注意力机制?为什么在进行多头注意力的时候需要对每个head进行降维?
多头注意力的拼接过程如下:
M u l t i H e a d ( Q , K , V ) = C o n c a t ( h a e d 1 , h e a d 2 , . . . , h e a d h ) ? W MultiHead(Q, K, V)=Concat(haed_1, head_2, ..., head_h)\cdot W MultiHead(Q,K,V)=Concat(haed1?,head2?,...,headh?)?W
多头可以使参数矩阵形成多个子空间,矩阵整体的size不变,只是改变了每个head对应的维度大小,这样做使矩阵对多方面信息进行学习,但是计算量和单个head差不多。降维是将原有的高维空间转化为多个低维空间并再最后进行拼接,形成同样维度的输出,借此丰富特性信息,降低了计算量。
多头注意力就是计算句子中所有单词的注意力,然后将所有值连起来,同时,通过降低维度减少损耗。
(3)为什么在进行softmax之前需要对attention进行scaled(为什么除以 d k \sqrt{d_k} dk? ?的平方根)?并使用公式推导进行讲解.
论文中解释是:向量的点积结果会很大,将softmax函数push到梯度很小的区域,scaled会缓解这种现象。
参考:transformer中的attention为什么scaled?
(3)位置编码:相对位置编码和绝对位置编码
因为self-attention是位置无关的,无论句子的顺序是什么样的,通过self-attention计算的token的hidden embedding都是一样的,这显然不符合人类的思维。因此要有一个办法能够在模型中表达出一个token的位置信息,transformer使用了固定的positional encoding来表示token在句子中的绝对位置信息。
(4)为什么Transformer 采用 Layer Norm? LayerNorm 在Transformer的位置是哪里?
多头注意力层和激活函数层之间。CV使用BN是认为channel维度的信息对cv方面有重要意义,如果对channel维度也归一化会造成不同通道信息一定的损失。而同理nlp领域认为句子长度不一致,并且各个batch的信息没什么关系,因此只考虑句子内信息的归一化,也就是LN。LN是为了解决梯度消失的问题,dropout是为了解决过拟合的问题。
(5)简单讲一下Transformer中的残差结构以及意义。
encoder和decoder的self-attention层和ffn层都有残差连接。反向传播的时候不会造成梯度消失
BN,LN, BN
优化器

    推荐阅读