CV深度学习面试问题记录

Posted by kevin on June 30, 2020

preface

这是在牛客网上根据大家的面经收集过来的题目,并以自己的理解来作出回答,也查阅了很多博客和资料。水平有限,不一定是正确的,欢迎指正,铁子们要找工作的时候可以看看

图像细粒度分类是什么

不同于普通的分类任务,图像细粒度分类是指的对同一个大类别进行更加细致的分类,例如哈士奇与柯基。

RPN是怎么做的

过拟合欠拟合是啥,怎么解决?

过拟合

过拟合是指训练误差和测试误差之间的差距太大。模型在训练集上表现很好,但在测试集上却表现很差,也就是泛化能力差。引起的原因有 ①训练数据集样本单一,样本不足 ②训练数据中噪声干扰过大 ③模型过于复杂。

防止过拟合的几种方法:

  1. 增加更多的训练集或者数据增强(根本上解决问题)
  2. 采用更简单点的模型(奥卡姆剃刀准则,简单的就是正确的)
  3. 正则化(L1,L2,Dropout)
  4. 可以减少不必要的特征或使用较少的特征组合

欠拟合

欠拟合是指模型不能在训练集上获得足够低的误差。换句换说,就是模型复杂度低,模型在训练集上就表现很差,没法学习到数据背后的规律。

欠拟合基本上都会发生在训练刚开始的时候,经过不断训练之后欠拟合应该不怎么考虑了。欠拟合可以通过使用非线性模型来改善,也就是使用一个更强的模型,并且可以增加训练特征

ResNet为啥能够解决梯度消失?怎么做的,能推导吗?

深度学习里面PCA的作用

PCA 用于降低维度,消除数据的冗余,减少一些不必要的特征。常用步骤如下(设有 m 条 n 维数据):

  1. 将原始数据按照列组成 m 行 n 列矩阵 X
  2. 将 X 的每一列(代表一个属性字段)进行零均值化(去中心化)减去这一列的均值得到特征中心化后的矩阵 $B = X_i - \mu_i$
  3. 求出协方差矩阵 $C = (X_i - \mu_i)*(X_i - \mu_i)^T$
  4. 求出矩阵 C 的特征值($det A-\lambda I =0$)和特征向量,按照特征值的大小将对应的特征向量从左往右排列,取前 k 个最大的特征值对应的特征向量组成矩阵 P
  5. Y = PX 即为降维到 k 维后的数据,即从 n 维降到了 k 维,保留了原本的大部分信息

reference:

王兴政老师的PPT

https://blog.csdn.net/Virtual_Func/article/details/51273985

YOLOv3的框是怎么聚出来的?

YOLOv3 的框是作者通过对自己的训练集的 bbox 聚类聚出来的,本质上就是一个 kmeans 算法,原理如下:

  1. 随机选取 k 个类别的中心点,代表各个聚类
  2. 计算所有样本到这几个中心点的距离,将每个样本归为距离最小的类别
  3. 更新每个类别的中心点(计算均值)
  4. 重新进行步骤 2 ,直到类的中心点不再改变

kmeans.png

YOLOv3 的 kmeans 想法不能直接用 w 和 h 来作为聚类计算距离的标准,因为 bbox 有大有小,不应该让 bbox 的尺寸影响聚类结果,因此,YOLOv3 的聚类使用了 IOU 思想来作为距离的度量 \(d(bbox, centroid) = 1 - IOU(bbox, centroid)\) 也就是说 IOU 越大的话,表示 bbox 和 box_cluster 就越类似,于是将 bbox 划归为 box_cluster

在 AlexeyAB 大佬改进的 darknet 中实现了这个过程,具体就是加载所有训练集中的 bbox 的 w 和 h,随机选择 k 个作为 centroids,然后用所有样本去和这 k 个 centroids 做 IOU 得出距离,并将样本归为距离最小的 cluster,然后更新 centroids 重复上面的步骤,直到 centroids 不再更新

reference:

https://github.com/AlexeyAB/darknet/blob/master/scripts/gen_anchors.py

https://www.cnblogs.com/sdu20112013/p/10937717.html

YOLO和SSD的本质区别?

R-CNN系列和SSD本质有啥不一样吗?

SSD的致命缺点?如何改进

需要人工设置prior box的min_size,max_size和aspect_ratio值。网络中prior box的基础大小和形状不能直接通过学习获得,而是需要手工设置。而网络中每一层feature使用的prior box大小和形状恰好都不一样,导致调试过程非常依赖经验。 虽然采用了pyramdial feature hierarchy的思路,但是对小目标的recall依然一般,并没有达到碾压Faster RCNN的级别。作者认为,这是由于SSD使用conv4_3低级feature去检测小目标,而低级特征卷积层数少,存在特征提取不充分的问题。 ———————————————— 版权声明:本文为CSDN博主「一个新新的小白」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_31511955/article/details/80597211

怎么解决梯度消失和梯度弥散

YOLOv1到YOLOv3的发展历程以及解决的问题

常见的Loss,回归的,分类的,Focal Loss

Focal Loss

reference: https://www.cnblogs.com/king-lps/p/9497836.html

L1、L2范数是什么,区别呢?

范数是具有 “长度” 概念的函数。在向量空间内,为所有的向量的赋予非零的增长度或者大小。不同的范数,所求的向量的长度或者大小是不同的。举个例子,2 维空间中,向量 (3,4) 的长度是 5,那么 5 就是这个向量的一个范数的值,更确切的说,是欧式范数或者L2范数的值。

更一般的情况下,对于一个 p- 范数,如果 $x = [x_1, x_2, x_3, …, x_n]^T$, 那么向量 x 的 p- 范数就是 $$ \begin{equation}

  x   _p = ( x_1 ^p+ x_2 ^p+…+ x_n ^p)^{1/p}

\end{equation} \(那么 L1 范数就是 p 为 1 的时候,也就是向量内所有元素的绝对值之和:\) \begin{equation}

  x   _p = ( x_1 + x_2 +…+ x_n )

\end{equation} \(L2 范数就是向量内所有元素的平方相加然后再开方:\) \begin{equation}

  x   _p = ( x_1 ^2+ x_2 ^2+…+ x_n ^2)^{1/2}

\end{equation} $$ 特别的,L0 范数是指向量中非零元素的个数!


在深度学习中,常常会在最后的 loss 函数中加一个正则项,将模型的权重 W 作为参数传入范数中,为的就是防止模型参数过大,这样可以防止过拟合发生。

reference:

https://zhuanlan.zhihu.com/p/28023308

https://www.cnblogs.com/LXP-Never/p/10918704.html(解释得挺好的,借鉴了下面这篇文章)

http://www.chioka.in/differences-between-l1-and-l2-as-loss-function-and-regularization/#

https://wangjie-users.github.io/2018/11/28/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3L1%E3%80%81L2%E8%8C%83%E6%95%B0/

pooling layer怎么反向传播

池化层没有可以训练的参数,因此在卷积神经网络的训练中,池化层只需要将误差传递到上一层,并不需要做梯度的计算。要追求一个原则,那就是梯度之和不变。

  • average pooling

直接将梯度平均分到对应的多个像素中,可以保证梯度之和是不变的

average

  • max pooling

max pooling要记录下最大值像素的index,然后在反向传播时将梯度传递给值最大的一个像素,其他像素不接受梯度,也就是为0

max

reference: https://blog.csdn.net/qq_21190081/article/details/72871704

手撸IOU计算公式

就是一个点,要记得加上 1 ,不然是错的!

def bb_intersection_over_union(boxA, boxB):
    boxA = [int(x) for x in boxA]
    boxB = [int(x) for x in boxB]

    xA = max(boxA[0], boxB[0])
    yA = max(boxA[1], boxB[1])
    xB = min(boxA[2], boxB[2])
    yB = min(boxA[3], boxB[3])
	
    # 要加上 1 ,因为像素是一个点,并不是一个矩形
    interArea = max(0, xB - xA + 1) * max(0, yB - yA + 1)

    boxAArea = (boxA[2] - boxA[0] + 1) * (boxA[3] - boxA[1] + 1)
    boxBArea = (boxB[2] - boxB[0] + 1) * (boxB[3] - boxB[1] + 1)
    
    iou = interArea / float(boxAArea + boxBArea - interArea)

    return iou

MobileNet在特征提取上有什么不同

MobileNet 用的是深度可分离卷积(Depthwise separable convolution),将传统的卷积分成了 Depthwise convolution 和 Pointwise convolution,也就是先对每个通道进行单独的卷积,不把这些特征组合在一起,然后用 Pointwise convolution 也就是一个 1* 1 卷积核将通道特征组合在一起,这样可以大大减少模型的参数量以及运算量,适合运用于嵌入式设备等对延时和性能要求较高的场景中。

下面就是深度可分离卷积的两个步骤,假设输入的 input 是 $D_F$ * $D_F$ * $M$,我们要的输出为 $D_F$ * $D_F$ * $N$,$D_K$ 为卷积核的大小

Depthwise separable convolution

用了深度可分离卷积所需要的运算量和普通卷积的计算量如下,在 MobileNet 中,卷积核的尺寸 $D_K$ 为 3 * 3,因此这样的计算量相当于减少了 9 倍

computation

NMS 怎样实现的

在目标检测中,常会利用非极大值抑制算法 (NMS) 对生成的大量候选框进行后处理 (post processing) ,去除冗余的候选框,得到最具代表性的结果,以加快目标检测的效率。

NMS 算法的主要流程如下所示:

根据候选框的类别分类概率做排序:A<B<C<D<E<F

  1. 先标记最大概率矩形框 F 是我们要保留下来的;
  2. 从最大概率矩形框 F 开始,分别判断 A~E 与 F 的重叠度 IOU(两框的交并比)是否大于某个设定的阈值,假设 B、D 与 F 的重叠度超过阈值,那么就扔掉 B、D;
  3. 从剩下的矩形框 A、C、E 中,选择概率最大的 E,标记为要保留下来的,然后判读 E 与 A、C 的重叠度,扔掉重叠度超过设定阈值的矩形框

就这样一直重复下去,直到剩下的矩形框没有了,标记完所有要保留下来的矩形框

import numpy as np

def py_nms(dets, thresh):
    """Pure Python NMS baseline."""
    #x1、y1、x2、y2、以及score赋值
    x1 = dets[:, 0]
    y1 = dets[:, 1]
    x2 = dets[:, 2]
    y2 = dets[:, 3]
    scores = dets[:, 4]

    #每一个候选框的面积
    areas = (x2 - x1 + 1) * (y2 - y1 + 1)
    #order是按照score降序排序的
    order = scores.argsort()[::-1]

    keep = []
    while order.size > 0:
        i = order[0]
        keep.append(i)
        #计算当前概率最大矩形框与其他矩形框的相交框的坐标,会用到numpy的broadcast机制,得到的是向量
        xx1 = np.maximum(x1[i], x1[order[1:]])
        yy1 = np.maximum(y1[i], y1[order[1:]])
        xx2 = np.minimum(x2[i], x2[order[1:]])
        yy2 = np.minimum(y2[i], y2[order[1:]])

        #计算相交框的面积,注意矩形框不相交时w或h算出来会是负数,用0代替
        w = np.maximum(0.0, xx2 - xx1 + 1)
        h = np.maximum(0.0, yy2 - yy1 + 1)
        inter = w * h
        #计算重叠度IOU:重叠面积/(面积1+面积2-重叠面积)
        ovr = inter / (areas[i] + areas[order[1:]] - inter)

        #找到重叠度不高于阈值的矩形框索引
        inds = np.where(ovr <= thresh)[0]
        #将order序列更新,由于前面得到的矩形框索引要比矩形框在原order序列中的索引小1,所以要把这个1加回来
        order = order[inds + 1]
    return keep

# test
if __name__ == "__main__":
    dets = np.array([[30, 20, 230, 200, 1], 
                     [50, 50, 260, 220, 0.9],
                     [210, 30, 420, 5, 0.8],
                     [430, 280, 460, 360, 0.7]])
    thresh = 0.35
    keep_dets = py_nms(dets, thresh)
    print(keep_dets)
    print(dets[keep_dets])

reference:

https://github.com/kuaikuaikim/DFace/

https://blog.csdn.net/Blateyang/article/details/79113030

为什么用smooth L1 loss,和L1 loss、L2 loss有啥区别?

关于数据集的一些碎碎的知识点

COCO

coco2017 有 118287 张训练集,5000 张验证集,40670 张测试集

目标检测中有些代码在训练时会将模型的 BN 层给冻结,这是为什么?

目标检测中一般会用到在 ImageNet 上预训练好的分类器权重,别人的 batch_size 很大,所以对 BN 层应该训练出了一个比较不错的参数(γ 和 β),而目标检测的 batch_size 可能没有那么大,可能 minibatch 不足以反映出样本整体的分布,训练出来的参数不一定有别人好,所以冻结住 BN 说不定会使模型表现更好

    def freeze_bn(self):
        '''Freeze BatchNorm layers.'''
        for layer in self.modules():
            if isinstance(layer, nn.BatchNorm2d):
                layer.eval()

It’s a common practice to freeze BN while training object detection models. This is done because you usually start from some Imagenet pre-trained weights which were trained with large BS (like 256 or larger) while in object detection BS is much smaller. You don’t want to ruin good pretrained statistics so freezing BN is a good idea

https://github.com/yhenon/pytorch-retinanet/issues/151