常见面试问题

1. 分割小物体有什么经验?

语义分割主要遇到的问题是低分辨率和语义信息不足等
(1). 可以融合不同层的语义信息(MLFGAN就是融合多层信息防止细微但鉴别性很强的物体在下采样时丢失,比如帽子,脸以及衣服logo等)
(2). 还可以利用多尺度分辨率的上采样模块,有几种思路:

  • 一方面是构建图像金字塔但resize这种基于双线性或双曲线插值的全局语义信息不够,可以借助超分来对图像做自适应的“插值”工作,更加具有全局语义信息,比如AIN-PCSR就做了这种超分工作来提升图像分辨率,从而更适应ReID这种图像分辨率很低的任务,不过我们做的更复杂,包括特征级的监督保证更多的语义信息以及步进的生成策略使得生成过程和生成 结果更加稳定,收敛更快。
  • 另外一方面可以借鉴目标检测里的方法在特征图上做金字塔,常见的思路有三种,一种是每层特征图做一个损失的监督(和多层融合有区别,多层融合是特征图按通道叠一块用一个损失监督,这里是每个特征图用一个损失监督),另一种是FPN结构,利用高层的特征图反卷积并与融合底层结果融合到一起生成更高分辨率上的分割或检测结果,并在每一层上做监督。如下所示:
    在这里插入图片描述
    最后一种是分割领域的一篇论文PSPNet,做了一种金字塔池化,其本质是用了不同stride的全局池化,这样就得到了不同大小的感受野的特征图,然后做特征融合,也对小物体有一定的帮助。
  • 不过以上方法都还存在一些问题。这个问题可以从网络结构的内在出发,单一网络的结构融合了非常多的不同类型的信息:颜色、形状以及纹理信息。这些信息被融合在一起处理,可能会导致对识别重要的信息不够的突出。因此还有一种思路是加入了一个单独的分支用来学习边缘信息来提升了小物体和细物体的分割效果,一般可以考虑两种思路来做边缘,分别是注意力和残差结构,当然也可以设计一些手工特征,因为边缘处一般会发生一个突变,可以考虑傅里叶变换和拉普拉斯变换之类的策略。
  • 最后从网络结构出发的话,由于小物体主要是担心下采样时分辨率下降问题,而下降主要发生在池化中,因此可以利用卷积层或者空洞卷积这些代替池化。

2. Focal Loss

2.1 OHEM

2.2 FL

目标检测存在的问题:

  • 正例的BB很少,负例的BB和大量背景BB很多----正负样本类别不均衡
  • 很容易判别的容易样本很多,难以判别的困难样本很少----难易样本不均衡

基础分类损失为Softmax,形式为:
在这里插入图片描述
为了改进正负样本不均衡问题,将CE损失改进为Balance CE损失,即对正负类别分别进行一个系数进行加权,形式如下:
在这里插入图片描述
其中 α ∈ [ 0 , 1 ] \alpha \in [0, 1] α[0,1]

一般正例较少,负例较多,因此CE中 y = 1 y=1 y=1部分损失较小,而 y = 0 y=0 y=0部分损失较大,于是加入 α \alpha α y = 1 y=1 y=1加权使得这部分损失变大一些,而利用 1 − α 1-\alpha 1α y = 0 y=0 y=0加权使得这部分损失变小一些,于是网络也就更加关注那些正样本。

但这并不能解决全部问题。根据正、负、难、易,样本一共可以分为以下四类:
在这里插入图片描述
其中易分样本(即置信度高的样本)对模型的提升效果非常小,模型应该主要关注与那些难分样本(这个假设是有问题的,是GHM的主要改进对象,而Focal loss之前的Online Hard Example Mining (OHEM)就是把难样本捞出来组成一个集合,然后用他们专门训练网络,也就能让网络关注到这些难样本),而Focal Loss则是改进为:
在这里插入图片描述
其中 γ > 1 \gamma>1 γ>1,以下假设 γ = 2 \gamma=2 γ=2

  • 对于正易样本,上式第一项 p p p很接近于1,比如0.9,CE损失很接近0,为0.1,而FL后这一项由前面的加权项 ( 1 − p ) γ (1-p)^\gamma (1p)γ让结果比CE更接近0,为0.001,比CE缩小了100倍;
  • 对于难易样本,上式第二项 p p p很接近于0,比如0.1,CE损失不怎么接近0,为2.3,而FL后这一项由前面的加权项 p γ p^\gamma pγ让结果比CE更接近0,为0.023,比CE损失缩小了100倍;
  • 对于正难样本,上式第一项 p p p不怎么接近1,比如0.1,这导致CE损失不怎么接近0,为2.3,而FL中 ( 1 − p ) γ (1-p)^\gamma (1p)γ加权让这一项也降低了不少,为1.863,虽然也拉低了,但是只比CE缩小了1.24倍(为CE的0.81)。
  • 对于负难样本,上式第二项 p p p不怎么接近0,比如0.9,这导致CE损失很接近0,为0.1,而FL中 p γ p^\gamma pγ加权让这一项也降低了不少,为0.081,虽然也拉低了,但是只比CE缩小了1.24倍(为CE的0.81)。
    在这里插入图片描述
    代码实现:
def py_sigmoid_focal_loss(pred, target, weight=None, gamma=2.0, alpha=0.25, reduction='mean', avg_factor=None):
    pred_sigmoid = pred.sigmoid()
    target = target.type_as(pred)
    pt = (1 - pred_sigmoid) * target + pred_sigmoid * (1 - target)
    focal_weight = (alpha * target + (1 - alpha) * (1 - target)) * pt.pow(gamma)
    loss = F.binary_cross_entropy_with_logits(pred, target, reduction='none') * focal_weight
    loss = weight_reduce_loss(loss, weight, reduction, avg_factor)
    return loss

在这里插入图片描述

2.3 GHM

GHM(gradient harmonizing mechanism)
Focal Loss存在什么问题呢?
首先,让模型过多关注那些特别难分的样本肯定是存在问题的,样本中有离群点(outliers),可能模型已经收敛了但是这些离群点还是会被判断错误,让模型去关注这样的样本,怎么可能是最好的呢?
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
看下图梯度模长与样本数量的关系:
在这里插入图片描述
可以看到,梯度模长接近于0的样本数量最多,随着梯度模长的增长,样本数量迅速减少,但是在梯度模长接近于1时,样本数量也挺多。

GHM的想法是,我们确实不应该过多关注易分样本,但是特别难分的样本(outliers,离群点)也不该关注啊!这些离群点的梯度模长d要比一般的样本大很多,如果模型被迫去关注这些样本,反而有可能降低模型的准确度!况且,这些样本的数量也很多!

**那怎么同时衰减易分样本和特别难分的样本呢?太简单了,谁的数量多衰减谁呗!**那怎么衰减数量多的呢?简单啊,定义一个变量,让这个变量能衡量出一定梯度范围内的样本数量——这不就是物理上密度的概念吗?
后续略。

参考链接

3. Batch Norm & Instance Norm

  • 到底做了什么?为什么需要这么个操作?
    模型训练的过程中参数随着梯度下降在不断更新。一方面,当底层网络中参数发生微弱变化时,随着网络层数的加深而被放大;另一方面,参数的变化导致每一层的输入分布会发生改变,进而上层的网络需要不停地去适应这些分布变化,使得模型训练变得非常困难。上述这一现象叫做Internal Covariate Shift (ICS)
ICS严重吗?会导致什么问题?

前面提到过了,会导致两个问题,分别是:(1) 后层网络需要不停调整来适应前层输入数据分布的变化,导致网络学习速度的变慢;(2) 网络的训练过程容易陷入梯度饱和区,减缓网络收敛速度(这个问题一方面可以使用ReLU代替Sigmoid,tanh这些激活来改进,另一方面做Norm也有帮助)

ICS问题需要被解决,那有什么方法?

ICS产生的原因是由于参数更新带来的网络中每一层输入值分布的改变,并且随着网络层数的加深而变得更加严重,因此我们可以通过固定每一层网络输入值的分布来对减缓ICS问题。两种思路:
(1) 白化(Whitening)
: 机器学习里面常用的一种规范化数据分布的方法,主要是PCA白化与ZCA白化。白化是对输入数据分布进行变换,进而达到以下两个目的:1) 使得输入特征分布具有相同的均值与方差。其中PCA白化保证了所有特征分布均值为0,方差为1;而ZCA白化则保证了所有特征分布均值为0,方差相同;2) 去除特征之间的相关性。通过白化操作,我们可以减缓ICS的问题,进而固定了每一层网络输入分布,加速网络训练过程的收敛。但白化有一定的缺陷,主要有以下两个问题:1) 白化过程计算成本太高,并且在每一轮训练中的每一层我们都需要做如此高成本计算的白化操作;2) 白化过程由于改变了网络每一层的分布,因而改变了网络层中本身数据的表达能力, 底层网络学习到的参数信息会被白化操作丢失掉
(2) Batch Norm

怎么想到Batch Norm的呢?

我们在做神经网络训练前,对输入的像素进行标准化处理,有效降低模型的训练难度。受此启发,作者想到,既然输入层可以加标准化有好处,那么网络里的隐层为什么不可以标准化?于是通过对每层加权和进行标准化来改变输入的分布,使得分布达到白化类似的norm效果,然后再通过缩放平移来“适度还原”,防止底层学到的信息被改变分布的操作给毁了这样,做到了既不过分破坏输入信息,又抑制了各batch之间各位置点像素分布的剧烈变化带来的学习难度

  • 那到底什么是Batch Norm?怎么实现的?
    其核心公式为:
    在这里插入图片描述可以注意到里面有四个参数,分别是 μ B , σ B 2 , γ , β \mu_B, \sigma_B^2, \gamma, \beta μB,σB2,γ,β。前两者是统计量,从每个batch数据中获取,是均值和方差,用于将上一层的输入变换成标准正态分布,从而缓解了输入引起分布变化的危害。后两者是scale和shift参数,加入的目的是前面的分布变换操作将输入提取的很多信息可能丢失掉了,于是使用这两项做一定程度的还原,这样就把这些信息拿回来了一些。下面两张图分别表示没有BN和加了BN的网络结构变化:
    在这里插入图片描述
    在这里插入图片描述
  • BN实现的效果是什么呢?
    在这里插入图片描述
    BN首先把输入标准化为一个标准正态分布。但这样是否太暴力了?如果所有输入样本被层层改分布,相当于输入信息都损失掉了,网络是没法训练的。所以需要第二步对标准正态分布再进行一定程度的还原操作,即缩放平移。最终使得这个数值分布,兼顾保留有效信息、加速梯度训练。

结论

  • 只要损失函数有需要, γ , β \gamma, \beta γ,β那个公式赋予了BN层还原原始分别的能力,而且上限是完全还原;
  • 具体对每一层还原多少,则是由损失函数对每一层这两个系数 γ , β \gamma, \beta γ,β的梯度来决定;
  • 损失通过梯度来控制还原的程度,较好利于减少损失,就多还原;较少利于减少损失,就少还原(让网络自己学习还原多少)。
  • BN的训练和测试有什么差异?

问题一:可导吗?能否反向传播?
答:可以。链式法则,每个部分都可导,总体也可导,且求出各部分的导数用链式法则合并即可(串联相乘并联相加)得到最终的导数(五项,分别是对 γ , β , x i \gamma, \beta, x_i γ,β,xi的导数用于更新他们,而 x i x_i xi还进一步传到前面的网络中更新上一层的权重W和b,还有两个导数是对 μ , σ \mu, \sigma μ,σ的导数,但不用来更新他们,因为他们是统计量,下次的结果有下次的输入计算而来),整个过程如下所示:
在这里插入图片描述
问题二:参数的初始化和更新?
分别由W,b, μ , σ , γ , β \mu,\sigma,\gamma, \beta μσγ,β六个参数,其中W和b其实是BN前面接的Conv的参数,估计也一起说:其中W与经典网络的初始化相同,初始化用标准正态分布(即Xavier方法),更新用梯度下降。b则直接省略掉,这是因为b的作用完全被BN中的shift参数 β \beta β取代了。 μ , σ \mu,\sigma μσ初始化取决于统计量,仅更新梯度,但不更新值本身。 γ , β \gamma, \beta γ,β初始化为1、0,更新用梯度下降。至于将要变成什么值,起多大作用,那就交给后续的训练。即采用梯度下降进行更新。
问题三:测试时和训练时参数有什么不同?
γ , β \gamma, \beta γ,β是在整个训练集上训练出来的,与W一样,训练结束就可获得。但 μ , σ \mu,\sigma μσ是依据一个mini-batch的统计得到,因为评估时只有一条样本,batch_size相当于是1,在只有1个向量的数据组上进行标准化后,成了一个全0向量,这可咋办?
其实这就涉及训练和测试时BN的差异了,其实W,b, γ , β \gamma, \beta γ,β四个参数的差异仅仅就是测试时固定下来不更新,但 μ , σ \mu,\sigma μσ一直没有用梯度更新过,而在测试的时候又不能用样本自己的统计量赋值,就只能用训练集的统计量了,当然必须是整个训练集的统计量。于是就有两种方法:
(1) 简单平均法:即把每个mini-batch的均值和方差都保存下来,然后训练完了求均值的均值,方差的均值即可。
(2) 移动指数平均(ExponentialMoving Average):这其实是对均值的近似。即引入一个动量(惯性)来保留上一个mini-batch的均值和方差,再利用下面的公式进行更新:x’ = (1-momentum) * x + momentum * x’’
目前使用较多的是后者,因为在训练时mini-batch不大时,容易有噪声造成统计量不准,用这种方式也能稍微缓解。

在这里插入图片描述

  • 那Batch Norm到底为什么有效呢?又有什么效果呢?
    答:BN改善了损失的平滑性

有人做了实验,结论是:BN的加入使得损失函数曲面变得平滑,而平滑的损失函数进行梯度下降法变得非常容易(可参见下图)。
在这里插入图片描述
显然,对于左侧的损失函数,梯度下降将是异常困难;而对于右侧,即经过平滑的损失函数,将大大提升训练效率

  • Batch Norm的常见提问?
  • BN层的位置能不能调整?如果能调整哪个位置更好?
    。位置并不限于ReLU之前。也有测试表明,BN放在上一层ReLU之后,效果更好。
  • 在训练时为什么不直接使用整个训练集的均值/方差?
    使用 BN 的目的就是为了保证每批数据的分布稳定,使用全局统计量反而违背了这个初衷
  • 在预测时为什么不直接使用整个训练集的均值/方差?
    完全可以。由于神经网络的训练数据量一般很大,所以内存装不下,因此才用指数滑动平均方法去近似值来近似代替整个训练集的均值和方差,好处是不占内存,计算方便,但其结果不如整个训练集的均值/方差那么准确。
  • batch_size的配置
    不适合batch_size较小的学习任务。因为batch_size太小,每一个step里前向计算中所统计的本batch上的方差和均值,噪音声量大,与总体方差和总体均值相差太大。前向计算已经不准了,反向传播的误差就更大了。尤其是最极端的在线学习(batch_size=1),原因为无法获得总体统计量。
  • 对学习率有何影响?
    由于BN对损失函数的平滑作用,因此可以采用较大的学习率
  • BN是正则化吗?
    在深度学习中,正则化一般是指为避免过拟合而限制模型参数规模的做法。即正则化=简化BN能够平滑损失函数的曲面,显然属于正则化。不过,除了在过拟合时起正则作用,在欠拟合状况下,BN也能提升收敛速度
  • 与Dropout的有何异同?
    BN由于平滑了损失函数的梯度函数,不仅使得模型训练精度提升了,而且收敛速度也提升了Dropout是一种集成策略,只能提升模型训练精度。因此BN更受欢迎。
  • 能否和Dropout混合使用?
    虽然混合使用较麻烦,但是可以。不过现在主流模型已经全面倒戈BNDropout之前最常用的场合是全连接层,也被全局池化日渐取代。既生瑜何生亮。
  • BN可以用在哪些层?
    所有的层。从第一个隐藏层到输出层,均可使用,而且全部加BN效果往往最好。
  • BN可以用在哪些类型的网络?
    MLP、CNN均ok,几乎成了这类网络的必选项。RNN网络不ok,因为无论训练和测试阶段,每个batch上的输入序列的长度都不确定,均值和方差的统计非常困难。
  • BN的缺点
    在训练时前向传播的时间将增大。(但是迭代次数变少了,总的时间反而少了)
  • BN和IN的异同?
    (1) BN和IN其实本质上是同一个东西,只是IN统计单张图片一个channel的feature map(HW)的均值和方差,但是BN统计一个batch的所有图片的一个channel的feature map(HW)的均值和方差。但是**为什么IN还会被单独提出,而且在Style Transfer的这个任务中大放异彩呢?**简言之,这背后的逻辑链是这样的: 1)通过调整BN统计量,或学习的参数beta和gamma,BN可以用来做domain adaptation。 2)而Style Transfer是一个把每张图片当成一个domain的domain adaptation问题。
    (2) 各自适用场景
    BN适用于判别模型中,比如图片分类模型。因为BN注重对每个batch进行归一化,从而保证数据分布的一致性,而判别模型的结果正是取决于数据整体分布但是BN对batchsize的大小比较敏感,由于每次计算均值和方差是在一个batch上,所以如果batchsize太小,则计算的均值、方差不足以代表整个数据分布(例如有多卡同步的BN)IN适用于生成模型中,比如图片风格迁移。因为图片生成的结果主要依赖于某个图像实例,所以对整个batch归一化不适合图像风格化中,在风格迁移中使用IN不仅可以加速模型收敛,并且可以保持每个图像实例之间的独立。

BN,LN,IN,GN从学术化上解释差异:
BatchNorm:batch方向做归一化,算NHW的均值,对小batchsize效果不好;BN主要缺点是对batchsize的大小比较敏感,由于每次计算均值和方差是在一个batch上,所以如果batchsize太小,则计算的均值、方差不足以代表整个数据分布
LayerNorm:channel方向做归一化,算CHW的均值,主要对RNN作用明显;
InstanceNorm:一个channel内做归一化,算H*W的均值,用在风格化迁移;因为在图像风格化中,生成结果主要依赖于某个图像实例,所以对整个batch归一化不适合图像风格化中,因而对HW做归一化。可以加速模型收敛,并且保持每个图像实例之间的独立。
GroupNorm:将channel方向分group,然后每个group内做归一化,算(C//G)HW的均值;这样与batchsize无关,不受其约束。
SwitchableNorm是将BN、LN、IN结合,赋予权重,让网络自己去学习归一化层应该使用什么方法。
在这里插入图片描述

4. ArcFace

传统的是softmax损失,但center loss用mnist上的实验证明了其分类结果呈现辐射状的角分类特点,而靠近角中心的类间样本距离很小,而类内靠近角中心的样本和偏离角中心(辐射外围)的样本之间距离很大,这样很容易误分,即鉴别性不够强,尤其是很多类别的分类任务的时候。于是就有一些改进,但多数集中在联合损失,比如center loss约束类内样本距离,triplet loss在BN前优化pull类内样本push类间样本。另一思路则是改善softmax损失本身,改进思路如下所示:
(1) 传统softmax损失为:
在这里插入图片描述
其中 f = w x + b f=wx+b f=wx+b
(2) 把权重进行归一化,这样可以实模长和方向不再耦合,收敛更快,效果更好,于是有 f = w x + b = ∣ w ∣ ∗ ∣ x ∣ ∗ c o s θ + ∣ b ∣ = ∣ x ∣ c o s θ f=wx+b=|w|*|x|*cos\theta+|b|=|x|cos\theta f=wx+b=wxcosθ+b=xcosθ。得到结果为:
在这里插入图片描述
即为W-Norm Softmax损失(注意x其实就是特征f)。

(3) 这里开始就出现了思想变化了,作者实验证明了其实样本都是围绕在权重w的周围,因此把w尽量分开,softmax的效果也就会得到提升。而w在这里已经变成了 c o s θ cos\theta cosθ,于是目的就是让样本属于某一类的空间分布更紧凑,采取的方法是降低样本属于这一类的置信度/概率,这样损失就会变大,再去优化的话就能让模型提取到更有鉴别性的特征。具体做法是,施加一个margin的约束,类似triplet和SVM那种,让不同类别之间尽量分开,这里添加的是角度 θ \theta θ的乘法margin,即从 c o s θ cos\theta cosθ变为 c o s m θ cosm\theta cosmθ,那为什么能压低属于某一类的概率呢?因为最少二分类,即 θ \theta θ在0~pi区间,而这个区间内cos是单间的,因此会压低概率。损失也就变为:
在这里插入图片描述
此即为SphereFace或A-Softmax(两家公司同时提出,名字不同,公式相同)。

(4) 如果只对权重归一化而特征不归一化,那导致结果几乎不受权重影响,该层网络的训练也就失去了意义,比如x的范围是0-1000,w是0-1,那x随便变化一点都比w从0变为1带来的影响大。于是对特征也做归一化,得到F-Norm SphereFace:
在这里插入图片描述
其实就是上面(3)中的 ∣ ∣ x ∣ ∣ ||x|| ∣∣x∣∣变成了归一化为s了。
(5) 上面也有问题,这个 c o s m θ cosm\theta cosmθ在反向求导时要用倍角公式,太浪费时间了,于是作者改成:
在这里插入图片描述
也就是 c o s m θ cosm\theta cosmθ变为 c o s θ − m cos\theta - m cosθm,同样压低了属于某一类的概率,提高损失,然后来优化它,但这个梯度和 c o s θ cos\theta cosθ是一样的,计算更简单。记为AM-Softmax损失,也叫CosineFace,其实就是增加了余弦margin

(6) ArcFace (后因重名修改为InsightFace),其出发点是:AM-Softmax优化的是余弦距离,没有直接优化角度距离来得直接,来得效果好(即余弦margin没有角度margin香)。于是将 c o s θ cos\theta cosθ改会 c o s ( θ + m ) cos(\theta+m) cos(θ+m),这样既可以压低概率,又能计算梯度简单,即角度加法margin。损失为:
在这里插入图片描述
(7)对比:
在这里插入图片描述
在这里插入图片描述

5. L1正则和L2正则

L1正则和L2正则都可以缓解过拟合,前者使用了拉普拉斯分布先验,后者则使用高斯分布先验。前者会使得得到稀疏解,很多参数为0,从而实现特征选择;后者则是整体参数会降低一些,但不像L1那么稀疏,而是比较平滑。

产生稀疏解的原因?
在这里插入图片描述
L1更容易在尖角处和损失等高线碰撞(最突出)。L1更适合特征之间有关联的情况,从而稀疏化其中的一部分,实现特征选择,而L2更适合特征之间没有关联的情况,进行整体压低而又不压低到0(球形并凸出都差不多,很难碰到w=0的情况)

6. Dropout

在每次训练的时候使用dropout,每个神经元有一定的概率被移除,这样本身可以算是将网络做的简单了一些,此外还可以使得一个神经元的训练不依赖于另外一个神经元,同样也就使得特征之间的协同作用被减弱,即通过阻止某些特征的协同作用来缓解。不过采用dropout会使得训练时间大大延长,而BN基本也可以视为一种正则,还能加速收敛,目前用的更多,dropout则更多的慢慢被pooling层取代。

7. 优化器

(1) SGD:抽取一个小批量(独立同分布)的样本,通过计算他们的平均梯度均值。
缺点:学习率太小则收敛速度很慢,但太大损失函数可能在极小值附近震荡甚至偏离,需要手动调学习率;容易被困在鞍点。优点:收敛结果非常好。
(2) Momentum(动量): 其实就是加入惯性保持历史梯度的更新方向。因此要是当前时刻的梯度与历史时刻相似,这种趋势就会加强;要是不同则被减弱。
(3) AdaGrad:设置全局学习率之后,每次通过全局学习率逐参数的除以历史梯度平方和的平方根,使得每个参数的学习率不同。即优点:可以实现学习率自适应减小。缺点:学习率可能会过早、过量的减少。
(4) RMSProp:相比于AdaGrad的改进是改变梯度累积为指数衰减的移动平均以丢弃遥远的过去历史,增加了一个衰减系数来控制历史信息的获取多少。
(5) Adam:可以看作修正后的Momentum+ RMSProp算法,收敛很快。

8. 抖音推荐

在这里插入图片描述

发布后的推荐流程

先是审核机制,然后是:
(1) 冷启动
抖音的推荐算法机制是著名的信息流漏斗算法,也是今日头条的核心算法。通过审核后,**第一步叫冷启动流量池曝光,比如你今天上传一个视频,通过双重审核的作品,系统将会分配给你一个初始流量池:200-300在线用户(也可能有上千个曝光)。**不论你是不是大号,只要你有能力产出优质内容,就有机会跟大号竞争。然后根据用户反馈进行数据加权决定是利用热门视频带动的二轮推荐,还是停止推荐,推荐一段时间后权重进行衰减。
(2) 数据加权
抖音会根据前面冷启动给的曝光数据,结合你账号分值来分析是否给你加权,比如完播率、点赞、关注、评论、转发、转粉、游览深度等,然后会挑选比较靠前的视频如前10%,再增加曝光(比如1万次曝光)。常用特征包括:
在这里插入图片描述
淘宝和拼多多这些可能还需要考虑商品价格,用户购买力以及商铺广告之类的信息。
(3) 加大推荐
这一步会给数据好的短视频进行更大的加权,并且会在第三步强化人群标签分发,让内容分发的更精准,这类似猜你喜欢的打标,视频是有标签的,用户也是有标签的,两者之间会做标签匹配。常用标签有:
在这里插入图片描述
(4) 进入精品推荐池
进入精品推荐池,大规模曝光,一旦进入精品推荐后,人群标签就被弱化了,就像当年温婉的视频,几乎每个抖音用户都会刷到温婉的视频。

延后“引爆”

不少抖音运营者会发现,有些内容发布的当天、一周甚至一个月内都数据平平,但突然有一天就火了,为什么?两种原因:第一种是被戏称为“挖坟”的机制(b站叫考古)。是指抖音会重新挖掘数据库里的“优质老内容”,并给它更多的曝光。这些老作品之所以能被“引爆”,首当其冲是它的内容够好,其次是你的账号已经发布了很多足够垂直的内容,标签变得更清晰,系统能够匹配给你更精准的用户。优质内容+精准用户,老作品重新火爆起来就不意外了。第二种是“爆款效应”,即你的某一个作品在获得大量曝光(几百万,甚至千万级)时,会带来巨量用户进入你的个人主页,去翻看你之前的作品。如果你的某一个作品,能够获得足够多的关注(转评赞),系统将会把这些视频重新放入推荐池。很多垂直内容的创作者,往往都是因为某一个视频的“火爆”,直接把其他几个优质视频“点燃”,形成多点开花,全盘爆炸引流的盛况。

流量触顶

抖音作品经过双重审核、初始推荐、叠加推荐层层引爆之后,通常会给账号带来大量的曝光、互动和粉丝。而这种高推荐曝光的时间,一般不会超过一周。之后,爆款视频乃至整个账号会迅速冷却下来,甚至后续之后发布的一些作品也很难有较高的推荐量。为什么?因为抖音每天的日活是有上限的,也就是说总的推荐量是基本固定的:一方面,跟你内容相关标签的人群基本完成推荐,其他非精准标签人群反馈效果差,所以停止推荐;另一方面,抖音也不希望某个账号迅速火起来,而是通过一轮轮考验,考验你的内容再创新能力和持续输出优质内容的能力。

9. python基础

(1) del和update的区别
del删除字典元素,update更新/合并字典
(2) python2和3中range的区别
python2返回的是list,但python3返回的是迭代器,可以节省内存
(3) python内建数据类型
int, bool, str, list, tuple, dict, set
(4) 面向对象中__new__和__init__区别
__init__是初始化方法,创建对象后,就立刻被默认调用,可接收参数;__new__至少要有一个参数cls,代表当前类,此参数在实例化时由Python解释器自动识别 ;__new__必须要有返回值,返回实例化出来的实例;__init__有一个参数self,就是__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值 ;如果__new__创建的是当前类的实例,会自动调用__init__函数。
(5) 如何查看类中方法
help(), dir(),.__doc__方法, .__all__方法。
(6) python实现乘方的几种方式:

  • 列表生成式 [x * x for x in range(1, 11)]
  • 使用列表推导式
    [x2 for x in range(1,21)]
    [(lambda x:x2)(x) for x in range(1,21)]
  • 使用map函数
    def cube(x): return x**2
    list(map(cube,range(1,21)))
  • 使用map+lambda
    list(map(lambda x:x*x,range(1,21)))

(7) python元组与数组的区别
元组不可以随意增加或者删除元素,数组可以。
(8) python三个点是什么意思?
它是省略所有的冒号来用省略号代替,大家看这个a[:, :, None]和a[…, None]的输出是一样的,就是因为…代替了前面两个冒号,即一般用在不知道前面有多少个冒号的情况。

10. RCNN系列

11. YOLO系列

知乎专业详细介绍,下面是简要介绍:
(1) YOLO v.s Faster R-CNN

  • YOLO没有显式region proposal的生成过程,Faster R-CNN中尽管RPN与fast rcnn共享卷积层,但是在模型训练过程中,需要反复训练RPN网络和fast rcnn网络。相对于R-CNN系列的"看两眼"(候选框提取与分类),YOLO只需要Look Once。
  • YOLO统一为一个回归问题,而R-CNN将检测结果分为两部分求解:物体类别(分类问题),物体位置即bounding box(回归问题)。

(2) YOLO v1

  • 核心思想:将整张图片作为网络的输入,直接在输出层对BBox的位置和类别进行回归。
  • 实现方法:将一幅图像分成SxS个网格(grid cell),如果某个object的中心落在这个网格中,则这个网格就负责预测这个object。
    在这里插入图片描述
  • 每个网络需要预测B个BBox的位置信息和confidence(置信度)信息,一个BBox对应着四个位置信息和一个confidence信息。confidence代表了所预测的box中含有object的置信度和这个box预测的有多准两重信息:
    在这里插入图片描述其中如如果有object落在一个grid cell里,第一项取1,否则取0。 第二项是预测的bounding box和实际的groundtruth之间的IoU值。
  • 每个bounding box要预测(x, y, w, h)和confidence共5个值,每个网格还要预测一个类别信息,记为C类。则SxS个网格,每个网格要预测B个BBox还要预测C个categories。输出就是S x S x (5*B+C)的一个tensor。(注意:class信息是针对每个网格的,confidence信息是针对每个bounding box的。)
    举例说明: 在PASCAL VOC中,图像输入为448x448,取S=7,B=2,一共有20个类别(C=20)。则输出就是7x7x30的一个tensor。网络结构为:
    在这里插入图片描述
  • 在test的时候,每个网格预测的class信息和BBox预测的confidence信息相乘,就得到每个BBox的class-specific confidence score:
    在这里插入图片描述
    等式左边第一项就是每个网格预测的类别信息,第二三项就是每个bounding box预测的confidence。这个乘积即encode了预测的box属于某一类的概率,也有该box准确度的信息。
  • 得到每个box的class-specific confidence score以后,设置阈值,滤掉得分低的boxes,对保留的boxes进行NMS处理,就得到最终的检测结果。
  • 损失函数:在实现中,最主要的就是怎么设计损失函数,让这个三个方面得到很好的平衡。作者简单粗暴的全部采用了sum-squared error loss来做这件事。这种做法存在以下几个问题:第一,8维的localization error和20维的classification error同等重要显然是不合理的;第二,如果一个网格中没有object(一幅图中这种网格很多),那么就会将这些网格中的box的confidence push到0,相比于较少的有object的网格,这种做法是overpowering的,这会导致网络不稳定甚至发散。解决办法:更重视8维的坐标预测,给这些损失前面赋予更大的loss weight。对没有object的box的confidence loss,赋予小的loss weight。有object的box的confidence loss和类别的loss的loss weight正常取1。对不同大小的box预测中,相比于大box预测偏一点,小box预测偏一点肯定更不能被忍受的。而sum-square error loss中对同样的偏移loss是一样。为了缓和这个问题,作者用了一个比较取巧的办法,就是将box的width和height取平方根代替原本的height和width。这个参考下面的图很容易理解,小box的横轴值较小,发生偏移时,反应到y轴上相比大box要大。(也是个近似逼近方式):
    在这里插入图片描述
    (注意这里只是缓解,并没有解决这个问题)一个网格预测多个box,希望的是每个box predictor专门负责预测某个object。具体做法就是看当前预测的box与ground truth box中哪个IoU大,就负责哪个。这种做法称作box predictor的specialization。最后整个的损失函数如下所示:
    在这里插入图片描述
    这个损失函数中:只有当某个网格中有object的时候才对classification error进行惩罚。只有当某个box predictor对某个ground truth box负责的时候,才会对box的coordinate error进行惩罚,而对哪个ground truth box负责就看其预测值和ground truth box的IoU是不是在那个cell的所有box中最大。
  • 其他细节,例如使用激活函数使用leak RELU,模型用ImageNet预训练等等
  • 简单的概括就是:

1> 给个一个输入图像,首先将图像得到的特征图划分成7*7的网格
2> 对于每个网格,我们都预测2个边框(包括每个边框是目标的置信度以及每个边框区域在多个类别上的概率)
3> 根据上一步可以预测出 7 ∗ 7 ∗ 2 7*7*2 772个目标窗口,然后根据阈值去除可能性比较低的目标窗口,最后NMS去除冗余窗口即可

  • 优点:快速,pipline简单.;背景误检率低;通用性强。YOLO对于艺术类作品中的物体检测同样适用。它对非自然图像物体的检测率远远高于DPM和RCNN系列检测方法。
  • 缺点:由于输出层为全连接层,因此在检测时,YOLO训练模型只支持与训练图像相同的输入分辨率;虽然每个格子可以预测B个bounding box,但是最终只选择只选择IOU最高的bounding box作为物体检测输出,即每个格子最多只预测出一个物体。当物体占画面比例较小,如图像中包含畜群或鸟群时,每个格子包含多个物体,但却只能检测出其中一个。这是YOLO方法的一个缺陷;YOLO loss函数中,大物体IOU误差和小物体IOU误差对网络训练中loss贡献值接近(虽然采用求平方根方式,但没有根本解决问题)。因此,对于小物体,小的IOU误差也会对网络优化过程造成很大的影响,从而降低了物体检测的定位准确性。

(3) YOLO v2
对比v1的改进有:
在这里插入图片描述
从上到下分别是:

  • 每个卷积层后加BN:缓解梯度消失和爆炸,降低对一些超参数(比如学习率、网络参数的大小范围、激活函数的选择)的敏感性,还起到一定的正则效果(YOLO2不再使用dropout),从而能够获得更好的收敛速度和收敛效果。
  • High resolution classifier(高分辨率图像分类器):这种pixel-level的任务中分辨率肯定影响识别。因为目标检测训练集小,所以都是先ImageNet预训练然后目标检测数据集Fine-tuning,但这引出的另一个问题是,分类样本的分辨率不是很高( 224 ∗ 224 224*224 224224),而检测分辨率更大 448 ∗ 448 448*448 448448,这样切换对模型性能有一定影响。所以YOLO2在采用 224224 图像进行分类模型预训练后,再采用 448448 的高分辨率样本对分类模型进行微调(10个epoch),使网络特征逐渐适应 448448 的分辨率。然后再使用 448448 的检测样本进行训练,缓解了分辨率突然切换造成的影响。
  • Convolution with anchor boxes(使用先验框):大大提升召回,略微降低mAP。YOLOV1有全连接层,从而能直接预测BBox的坐标值。 Faster R-CNN的方法只用卷积层与Region Proposal Network来预测Anchor Box的偏移值与置信度,而不是直接预测坐标值。作者发现通过预测偏移量而不是坐标值能够简化问题,让神经网络学习起来更容易。于是anchor真香警告。即在每个grid余弦设定不同位置和多种尺度的9个anchor,去掉了全连接层而使用Anchor Boxes来预测偏移量。
  • Dimension clusters(聚类提取先验框的尺度信息):用什么anchor聚类后说了算,而不是手动选
  • Direct location prediction(约束预测边框的位置):训练早期由于要学习的参数没有范围限制因此预测不稳,限制后就好得多。
  • Fine-Grained Features(passthrough层检测细粒度特征):即
    在这里插入图片描述
    拆分过程为:
    在这里插入图片描述
  • Multi-ScaleTraining(多尺度图像训练):图像金字塔
  • hi-res detector(高分辨率图像的对象检测):没有全连接
  • Hierarchical classification(分层分类):提出一种在分类数据集和检测数据集上联合训练的机制。使用检测数据集的图片去学习检测相关的信息,例如bounding box 坐标预测,是否包含物体以及属于各个物体的概率。使用仅有类别标签的分类数据集图片去扩展可以检测的种类。

YOLOv2相对v1版本,预测更准确(Better),速度更快(Faster),识别对象更多(Stronger)。其中识别更多对象也就是扩展到能够检测9000种不同对象,称之为YOLO9000。

(4) YOLO v3
YOLO v3的模型比之前的模型复杂了不少,可以通过改变模型结构的大小来权衡速度与精度。
改进:

  • 引入FPN进行多尺度预测。
  • 更好的基础分类网络(darknet-53, 类似于ResNet引入残差结构)。
  • 分类器不在使用Softmax,分类损失采用binary cross-entropy loss(二分类交叉损失熵)。原因有二:softmax使得每个框分配一个类别(score最大的一个),而对于Open Images这种数据集,目标可能有重叠的类别标签,因此softmax不适用于多标签分类,而比较适合one-hot;Softmax可被独立的多个logistic分类器替代,且准确率不会下降。
    (5) YOLO v4
    在这里插入图片描述
    (6) YOLO v4
    模型更小(速度更快),精度不变,但创新很少

12. DeepLab系列

(1) DeepLab v1: DNN + CRF后处理
在这里插入图片描述
(2) DeepLab v2:
为了感受野需要做下采样,比如max pool,对小物体很不友好,可能逐步下降过程中就没了,于是作者提出空洞卷积代替池化,这样特征图不变小但感受野还能上去。即:
在这里插入图片描述
此外,做成多尺度,即空洞空间卷积池化金字塔(atrous spatial pyramid pooling (ASPP))对所给定的输入以不同采样率的空洞卷积并行采样,相当于以多个比例捕捉图像的上下文,对多尺度输入更友好。
(3) DeepLab v3:
修改了空洞空间金字塔池化模块,但是 CRF不再使用。整个结构为:
在这里插入图片描述
a是图像金字塔再融合,b是FCN和UNet这种先下采样再上采样,c是本文即不同层用不同空洞卷积,d是PSPnet结构。改进后的 ASPP 比原来多了个 1*1 的 conv 和 global avg pool,其实思想可能来自Inception和PSPnet,然后就是空洞卷积层后加BN和ReLU这种常用的技术。
(4) DeepLab v3+
在这里插入图片描述
UNet和FCN这种Encoder-Decoder结构真香,不过直接从低分特征图32X到原图跨度太大,要慢慢来,于是一层一层的恢复,类似于我们论文中的步进超分思想。然后就是对Xception结构进行了一些修改。

13. 常用C/C++语法

(1) Static关键字
用来控制变量的存储方式和可见性。在函数内部定义的变量会在程序执行到其定义处时,编译器为它在栈上分配空间,而该空间在此函数执行结束时会释放掉,因此如果想此变量的值保存至下一次调用时,如何实现? 简单,即全局变量,但定义全局变量破坏了此变量的访问范围(使得在此函数/类中定义的变量,不仅仅只受此函数/类控制)。而static 关键字很好的解决这个问题,静态数据存储在全局(静态)存储区,可以节省内存,因为它是所有对象所公有的,即对多个对象来说,静态数据成员只存储一处,供所有对象共用。静态数据成员的值对每个对象都是一样,但它的值是可以更新的。只要对静态数据成员的值更新一次,保证所有对象存取更新后的相同的值,这样可以提高时间效率。在 C/C++ 中static的特点:

  • static在修饰变量的时候,static 修饰的静态局部变量只执行一次初始化,而且延长了局部变量的生命周期,直到程序运行结束以后才释放
  • static 修饰全局变量/函数的时候,则这个全局变量/函数只能在本文件中访问不能在其它文件中访问,即便是 extern 外部声明也不可以,其它文件中可以定义相同名字的变量,不会发生冲突。static 修饰的变量存放在全局数据区的静态变量区,包括全局静态变量和局部静态变量,都在全局数据区分配内存,不过局部静态变量的作用域不是全局的,而是局部的初始化时的默认初始化值为 0(普通变量是随机初始化)
  • 不想被释放的时候,可以使用static修饰。比如修饰函数中存放在栈空间的数组。如果不想让这个数组在函数调用结束释放可以使用 static 修饰。
  • 考虑到数据安全性(当程序想要使用全局变量的时候应该先考虑使用 static)。

注:全局变量是不显式用 static 修饰的全局变量,全局变量默认是有外部链接性的,作用域是整个工程,在一个文件内定义的全局变量,在另一个文件中,通过 extern 全局变量名的声明,就可以使用全局变量,而全局静态变量是显式用 static 修饰的全局变量,作用域是声明此变量所在的文件,其他的文件即使用 extern 声明也不能使用。
在这里插入图片描述
`
总结:

  • 不能通过类名来调用类的非静态成员函数,但可以通过类名调用静态成员函数,而类对象可以调用两者。即Point::init()是错的,Point::output()是对的,Point point; point.init()和point.output()都正确。
  • 静态成员函数中不能引用非静态成员。因为前者在实例化对象之前就被创建在全局存储区,而后者只有在对象被实例化之后才能被创建。但注意反过来调用是可以的。
  • 类的静态成员变量必须先初始化再使用(不是很懂,不应该默认初始化为0吗?)。即下图是错的(需要在main前加上int Point::m_nPointCount = 0;即可,输出为1)
    在这里插入图片描述
    static关键字的参考链接

(2) new-delete和malloc-free的用法区别
每个程序在执行时都会占用一块可用的内存空间,用于存放动态分配的对象,此内存空间称为自由存储区(new)或堆(malloc)。它们之间的区别如下:

  • 属性:new/delete是C++关键字,需要编译器支持。malloc/free是库函数,需要头文件支持c
  • 参数:使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算。而malloc则需要显式地指出所需内存的尺寸。
  • 返回类型:new操作符内存分配成功时,返回的是对象类型的指针,无须进行类型转换。而malloc内存分配成功则是返回void * ,需要通过强制类型转换成我们需要的类型。
  • 分配失败:new内存分配失败时,会抛出bac_alloc异常。malloc分配内存失败时返回NULL。
  • 自定义类型:new会先调用operator new函数,申请足够的内存(底层是malloc实现)。然后调用构造函数初始化成员变量,最后返回自定义类型指针。delete先调用析构函数,然后调用operator delete函数释放内存(底层是free实现)。malloc/free是库函数,只能动态地申请和释放内存,无法强制要求其做自定义类型对象构造和析构工作。
  • 重载:C++允许重载new/delete操作符,特别的,布局new的就不需要为对象分配内存,而是指定了一个地址作为内存起始区域,new在这段内存上为对象调用构造函数完成初始化工作,并返回此地址。而malloc不允许重载。
  • 内存区域:new操作符从自由存储区(free store)上为对象动态分配内存空间,而malloc函数从堆上动态分配内存。

PS:在C++中,内存区有5个,分别是堆、栈、自由存储区、全局/静态存储区、常量存储区;在C中,C内存区有堆、栈、全局/静态存储区、常量存储区;

new和malloc区别的相应参考链接

(3) C++多态,继承
继承的作用是代码重用,多态是为了接口重用。

  • 继承:用类派生从一个类继承另一个类,派生类继承基类的成员。
  • 多态:编译或运行时决定使用基类中定义的函数还是使用派生类中定义的函数。‘一个接口,多种方法’。多态又分为静态多态和动态多态。静态多态是指在编译期间就可以确定函数调用的地址,并生成代码。静态多态往往通过函数重载来实现,调用速度快,效率高但缺乏灵活性。动态多态则需要在运行的时候才可以确定函数调用的地址。动态多态通过虚函数来实现,虚函数允许通过派生类重新定义成员函数而派生类重新定义基类的做法称为覆盖或者重写。

(4) 虚函数
成员函数分为静态成员函数和非静态成员函数,非静态成员函数分为普通函数和虚函数。

14. 反卷积

反卷积又叫做转置卷积,其实就是在将普通卷积核转换为稀疏矩阵C,然后在正向传播的时候左乘这个稀疏矩阵C的转置,反向传播的时候左乘这个稀疏矩阵C。

  • 卷积和正常卷积的区别:
    正常卷积:正向传播时左乘C,反向传播时左乘C的转置
    反卷积:正向传播时左乘C的转置,反向传播时左乘C
  • 反卷积的用途
    最终目的是实现上采样,具体的可以是UNet那种解码得到分割结果,GAN / AE那种进行图像上采样,卷积层结果的可视化
    在这里插入图片描述

15. 模型压缩的主要方法有哪些?

(1)从模型结构上来说分为:模型剪枝,模型蒸馏,NAS自动学习模型结构等。
(2)模型参数量化上包括数值精度量化到FP16等。

注:模型剪枝的例子很多出现在轻量化网络上面,比如mobilenet v3里面出现的group conv,更改网络末端计算量大的层,减少网络头部的卷积核的数量,再如深度分离卷积等。模型蒸馏就是迁移学习。

16. 使用深度卷积网络做图像分类如果训练一个拥有1000万个类的模型会碰到什么问题?

  • 内存/显存不够:训练周期很久难以遇到某一特定类的图像,可能会导致训练跑偏
  • 模型收敛速度:softmax角分类特点导致训练大分类时样本间区分度不够,从而训练崩溃

17. 深度学习中为什么不用二阶导去优化?

Hessian矩阵是n*n, 在高维情况下这个矩阵非常大,计算和存储都是问题。

18. 在机器学习中为什么经常使用梯度下降而不使用牛顿法?

  • 牛顿法的目标函数是二阶导数,在高维的情况下这个矩阵非常大,计算和储存都是问题。
  • 在小批量的情况下,牛顿法对噪声的估计太大。
  • 在目标函数非凸的情况下,牛顿法易受到鞍点和极大值点的吸引。

19. 深度机器学习中的mini-batch的大小对学习效果有何影响?

  • mini-batch太小会导致容易受到噪声干扰,造成震荡,从而收敛变慢
  • mini-batch太大内存利用率提高了,但是内存容量可能撑不住了,会导致精度降低,泛化性不好。

20. dropout的原理,为什么可以防止过拟合?

dropout的原理就是在网络前向传播的时候,让神经元的激活值以一定的概率变为零(训练有,测试无),这样可以使模型的泛化性能更强。其有作用的原因如下:

  • dropout其实相当于基于平均的ensemble:ensemble有两种方式,基于平均的ensemble和基于投票的ensemble。对于网络中的部分神经元进行概率暂时舍弃,这样相当于训练了多个网络。
  • dropout还取消了神经元之间的共适应关系,使得网络的输出不依赖于网络中的某些隐含节点的固定作用,使模型的鲁棒性更好。
  • dropout直接去掉了一些神经元,也就是相当于减少了模型的复杂度,从而降低过拟合

代码实现:

def dropout(x,p):
    if p<0 or p>1:
        raise Exception('The p must be in interval [0,1]')
    retrain_prob = 1-p
    sample = np.random.binomial(n=1,p=retrain_prob,size=x.shape)
    x *=sample
    x /=retrain_prob
    return x

21. 为什么SSD对小目标检测效果不好:

  • 小目标对应的anchor(4-6)比较少,其对应的feature map上的pixel难以得到训练,这也是为什么SSD在augmentation之后精确度上涨(因为crop之后小目标就变为大目标)
  • 要检测小目标需要足够大的feature map来提供精确特征,同时也需要足够的语义信息来与背景作区分

22. 空洞卷积及其优缺点

pooling操作虽然能增大感受野,但是会丢失一些空间信息。而空洞卷积在卷积核中插入权重为0的值,因此每次卷积中会skip掉一些像素点,从而不会像pooling那样丢失空间信息,但却增大了卷积输出每个点的感受野。在图像需要全局信息或者需要较长sequence依赖的语音序列问题上有着较广泛的应用。

23. L1损失,L2损失和Smooth L1损失

  • L1损失函数
    即最小化绝对误差(Least Abosulote Error),LAE就是最小化真实值 y i y_i yi和预测值 f ( x i ) f(x_i) f(xi)之间差值 D L 1 D_{L_1} DL1绝对值的和,有:
    在这里插入图片描述
    这里的 D L 1 D_{L_1} DL1其实就是平均绝对误差(MAE)。使用L1损失函数也就是 m i n D L 1 minD_{L_1} minDL1

特点:在零点不可导,因此导数不连续,于是可能存在多个解,当数据集有一个微小的变化时(噪声点)都会导致损失波动较大(L2把损失平方了,较小的损失越平方越小),从而导致解的波动很大,因此解不稳定;但L1损失不像L2那样对误差平方,因此L1对异常值比较鲁棒(较大的变化),会趋向于产生少量的特征,而其他的特征都是0,产生稀疏权重矩阵,服从拉普拉斯分布。而优点是无论对于什么样的输入值,都有着稳定的梯度,不会导致梯度爆炸问题,具有较为稳健性的解,做正则可以防止过拟合。

  • L2损失函数
    使用L2损失函数也被叫做最小化平方误差(Least Square Error),LSE就是最小化真实值 y i y_i yi和预测值 f ( x i ) f(x_i) f(xi)之间差值 D L 2 D_{L_2} DL2平方的和,有:
    在这里插入图片描述
    这里的 D L 2 D_{L_2} DL2其实就是平均绝对误差(MAE),使用L2损失函数也就是 m i n D L 2 minD_{L_2} minDL2

特点:​ L2损失的梯度为 2 ( y i − f ( x i ) ) 2(y_i-f(x_i)) 2(yif(xi)),容易造成梯度爆炸;L2对误差进行平方,因此对异常值(变化较大)和离群点(远离中心)比较敏感,会导致结果不理想;L2损失服从高斯分布,得到的结果比较平滑,不会很sharp;L2处处可到,存在解析解,做正则可以防止过拟合。L2会选择更多的特征,这些特征都会接近于0但不为0。

代码实现:

import numpy as np
#定义L1损失函数
def L1_loss(y_true,y_pre): 
    return np.sum(np.abs(y_true-y_pre))
#定义L2损失函数
def L2_loss(y_true,y_pre):
    return np.sum(np.square(y_true-y_pre))

#假设我们得到了真实值和预测值
y_true = np.array([1,2,3,4,5,6,7,8,9])
y_pre  = np.array([1.2,2.3,3.5,4.3,4.6,5.6,6.1,7.1,8.8])

#定义函数
print('L1 loss is {}'.format(L1_loss(y_true,y_pre))) # L1 loss is 4.1000000000000005
print('L2 loss is {}'.format(L2_loss(y_true,y_pre))) # L2 loss is 2.450000000000001

再讨论几个问题:

  • 为什么参数越小代表模型越简单?
    越是复杂的模型,越是尝试对所有样本进行拟合,包括异常点。这就会造成在较小的区间中产生较大的波动,这个较大的波动也会反映在这个区间的导数比较大。只有较大的参数才可能产生较大的导数。因此参数越小,模型就越简单。
  • 实现参数的稀疏有什么好处?
    因为参数的稀疏,在一定程度上实现了特征的选择。一般而言,大部分特征对模型是没有贡献的。这些没有用的特征虽然可以减少训练集上的误差,但是对测试集的样本,反而会产生干扰。稀疏参数的引入,可以将那些无用的特征的权重置为0。
  • L1范数和L2范数为什么可以避免过拟合?
    加入正则化项就是在原来目标函数的基础上加入了约束。当目标函数的等高线和L1,L2范数函数第一次相交时,得到最优解。
  • smooth L1损失
    在这里插入图片描述
    图像为:
    在这里插入图片描述

分析: 其实红绿曲线就是L1,而smooth L1就是把x<1的结果从L1变成了蓝色的L2损失,因为小于1的部分是变化比较小的微小变化不像L1那样敏感,而是像L2那样压低敏感度,而x>1的部分则是利用L1对异常点和离群值不敏感的优点。

L1对误差<1的小波点敏感(缺),对误差>1的异常值和离群点不敏感(优)
L2对误差<1的小波点不敏感(优),对误差>1的异常值和离群点敏感(缺)
smooth L1则是误差<1的部分取L2的优点,误差>1的部分取L1的优点

梯度:误差>1部分的梯度不是L2那种的 2 ( x i − f ( x i ) ) 2(x_i-f(x_i)) 2(xif(xi)),不会造成梯度爆炸,防止训练时跑飞。

24. 简述一下数据增强的方法

主要分为离线增强和在线增强的方法。

  • 离线增强是指数据集在本地进行处理。
  • 在线增强:翻转(水平,垂直),旋转,缩放,裁剪,平移,添加噪声,颜色抖动,随机擦除,mix-up等。

25.超参数搜索方法

  • 随机搜索:
  • 网格搜索:在所有候选的参数选择中,通过循环遍历,尝试每一种可能性,表现最好的参数就是最终的结果。
  • 贝叶斯优化:贝叶斯优化其实就是在函数方程不知的情况下根据已有的采样点预估函数最大值的一个算法。该算法假设函数符合高斯过程(GP)。

26. 如何理解卷积、池化等、全连接层等操作

  • 卷积的作用:相当于滤波器,提取图片不同的特征,整合输入的像素和像素间的关系,生成feature_map输出
  • 激活函数的作用:引入非线性因素,充分组合特征
  • 池化的作用:减少特征维度大小,使特征更加可控,减少参数个数,从而控制过拟合程度,增加网络对略微变换后的图像的鲁棒性;达到一种不变性,包括translation,rotation,scale等;会造成梯度稀疏,丢失信息,GAN网络中通常使用带步长的卷积,进行下采样来替代pooling。
  • 全连接的作用:对提取到的特征进行分类和回归。
  • 1x1大小的卷积核:通过控制卷积核个数实现升维或者降维,从而减少模型参数;对不同特征进行归一化操作(BN),增加非线性(relu);用于不同channel上特征的融合

27. 常见激活函数特点

激活函数分为两类,饱和激活函数和不饱和激活函数。

  • 饱和激活函数的代表是sigmoid,tanh。特点是:收敛慢,容易梯度消失。

  • 非饱和激活函数的特点是:收敛快,抑制梯度消失,抑制过拟合, 如ReLU,leakyReLU,ELU

  • sigmoid:计算量大。梯度消失,会改变原始数据分布。

  • tanh:计算量大,梯度消失比sigmoid好点

  • relu:计算简单,有效防止了梯度消失和梯度爆炸,会出现神经元死亡。

  • leakrelu:解决了神经元死亡的问题,但是多了一个参数a

  • ELU:避免dying神经元,并且处处连续,从而加速SGD,但是计算比较复杂

激活函数需要满足的性质:
非线性,几乎处处可导, 单调性(保证单层网络是凸函数),f(x) ≈ x防止梯度消失和爆炸,输出范围有限能使梯度优化更稳定(不然会使结果受权重影响小)

28. 训练过程中,若一个模型不收敛,那么是否说明这个模型无效?导致模型不收敛的原因有哪些?

  • 并不能说明这个模型无效,导致模型不收敛的原因可能有数据分类的标注不准确;
  • 样本的信息量太大导致模型不足以fit整个样本空间;
  • 学习率设置的太大容易产生震荡,太小会导致不收敛;
  • 可能复杂的分类任务用了简单的模型;
  • 数据没有进行归一化的操作。

29. python读取图像可以用什么库,pytorch和tensorflow怎么增加图像的纬度?

  • Python可以用opencv,pillow和skimage库来读取图片并处理。
  • pytorch可以用unsequeeze(0),tensorflow可以用expand dim来增加维度。

30. BP

信号前向传播,误差反向传播,通过不断调节网络的权重,使得网络的最终输出与期望输出尽可能接近。前项过程中通过与正确的标签计算损失,反向传递损失,更新参数,优化至最后的参数。

31. KL散度

KL散度又叫做相对熵,如下:
在这里插入图片描述
通常说的softmax损失叫做交叉熵,如下:
在这里插入图片描述
而熵是一个定值,如下:
在这里插入图片描述
它们之间的关系有:交叉熵 = 熵 + 相对熵。而熵是一个定值常数,因此优化交叉熵和优化KL散度其实没有什么区别。

32. Finetune

Finetune就是通过修改预训练网络模型结构(如修改模型类别输出个数等)选择性的载入预训练网络模型的权重(载入除最后的全连接层之前的所有层)再用自己的数据集重新训练模型,可以达到缓解过拟合的目的。Finetune的实践建议:

  • 预训练模型的限制,不能随意修改模型的网络架构,但是可以输入任意的图片。
  • 学习率:与重新训练相比,finetune需要使用更小的学习率。

33. 感受野的计算

第一个feature_map的感受野默认为1,感受野的计算公式: r = r ∗ s t r i d e + ( k − 1 ) r=r*stride+(k-1) r=rstride+(k1),这里 r r r是上一层的感受野,stride是步长, k k k是kernel_size。全局stride等于所有stride的累乘。全局padding:
在这里插入图片描述

34. 卷积后输出特征图大小

在这里插入图片描述
W 2 , H 2 W_2,H_2 W2H2是输出宽和高, W 1 , H 1 W_1,H_1 W1H1是输入宽和高。

35. 简述一下GooleNet的Inception模块的原理?

对输入图像用多个不同尺寸的卷积核,池化操作进行同时处理,让网络自己学习哪个的结果更重要,然后将输出结果进行通道拼接。

36. 简述一下SVM和函数的原理

核函数将数据映射到更高维的空间后处理,但是不用这种显式的映射,而是现将两个向量做内积,然后再用核函数做映射。这样做等价于先做映射,再做内积,而且避免了高维空间复杂的内积运算。

37. 为什么mobileNet在理论上速度很快,工程上并没有特别大的提升?

mobileNet虽然在计算量上减少了很多,但是由于深度可分离卷积的操作,使得网络的层数增加了很多,而我们的GPU计算是并行数据处理,假设GPU内存足够大的话所以GPU计算速度的瓶颈是是网络的层数。

38. 多任务学习中loss权重的设置

最naive的方法,先都设置为1然后训一段时间之后看loss的收敛情况,然后调整权重使得这些loss传回去的梯度都在一个数量级上

39. SGD、Momentum、Adagard、RMSProp、Adam

SGD可以看做是mini-batch梯度下降,而Momentum则是利用惯性的思想,记录了上一次的梯度信息,避免更新方向出现大的偏差导致更新出错;AdaGrad则是记录历史梯度信息,然后更新权重的时候除以该历史梯度值,达到自动调节学习率的目的(不同权重使用不同大小的学习率),所以Adagrad对低频的参数有较大的更新,对高频的参数有较小的更新,对于稀疏的数据的表现很好,缺点是Adagrad的学习率会不断收缩,最终变得非常小。而RMSProp算法就在AdaGrad基础上引入了衰减因子,即很久远的梯度不要一直记得那么清楚,进行exp衰减。Adam则是Momentum+RMSProp,大多数情况下Adam都可以取得比较好的效果,收敛也更快。但SGD在有比较好的初始化条件下,也可以更快的收敛,且SGD的可以收敛得更好。

40. loss的问题:

  • 训练过程中loss为负数:
    【原因】输入的训练数据没有归一化造成
    【解决方法】把输入数值通过下面的函数过滤一遍,进行归一化
    i n p u t d a t a = ( i n p u t d a t a − i n p u t d a t a . m i n ( ) ) / ( i n p u t d a t a . m a x ( ) − i n p u t d a t a . m i n ( ) ) inputdata = (inputdata-inputdata.min()) / (inputdata.max()-inputdata.min()) inputdata=(inputdatainputdata.min())/(inputdata.max()inputdata.min())
  • 怎么看loss和acc的变化?
    train loss 不断下降,test loss不断下降,说明网络仍在学习;
    train loss 不断下降,test loss趋于不变,说明网络过拟合;
    train loss 趋于不变,test loss不断下降,说明数据集100%有问题;
    train loss 趋于不变,test loss趋于不变,说明学习遇到瓶颈,需要减小学习率或批量数目;
    train loss 不断上升,test loss不断上升,说明网络结构设计不当,训练超参数设置不当,数据集经过清洗等问题。
  • 初始学习率设置的问题:
    可以从0.0001到0.1每次扩大10倍试验,直到验证集上的loss增大,一般为0.01-0.1左右。mmdetection上面有自己的学习率设置方式,一般为0.125 * batch_size * gpus。
  • 样本不平衡问题:
    样本不平衡呈现长尾分布,解决方案:上采样增强,下采样增强,训练动态加权采样,稀少数据专家模型,在线硬负挖掘(处理难易样本),Focal Local(正负样本均衡和难易样本平衡)等

41. 最小化均方误差和基于高斯分布的极大似然估计

其实这两个是一样的,公式推导一下就知道了。推导过程

42. 过拟合和欠拟合

【表现】

  • 过拟合就是训练集上表现好但是验证集上表现不好。
  • 欠拟合就是训练集上loss不降低,学习能力弱。

【产生原因】

  • 过拟合产生的原因:模型太复杂,样本噪声多,决策树容易过拟合,iou阈值过高,训练集迭代次数太多。
  • 欠拟合:模型复杂度低,数据不纯净。

【解决方案】

  • 过拟合:L1 / L2正则化,Dropout,earlystoping(早停),数据增广,BN,Finetuning
  • 欠拟合:增加模型复杂度,数据预处理

43. 梯度消失和梯度爆炸的原因和解决方案

需要解决非常复杂的问题时,能需要训练一个非常深的DNN,可能需要几十层或者上百层,每层包含数百个神经元,通过成千上万个连接进行连接,我们会遇到以下问题:首先,梯度消失或梯度爆炸;其次,训练缓慢;第三,训练参数大于训练集的风险。

【产生原因】

  • 梯度消失: 早期没有激活函数如多层感知机,拟合能力不够,因此加入了如Sigmoid激活函数,不过Sigmoid在很大或很小的输入时梯度趋于0会导致梯度消失,其输出在0-1之间,梯度在0-0.25之间,即每过一层Sigmoid梯度变成原来的四分之一,从而导致梯度消失。Tanh好了一些,梯度时0-1,最好的结果是梯度不消失,但只有每层都是1的时候才可能,因此还是会梯度消失。
  • 梯度爆炸:其实之前说的梯度是激活的梯度,但实际还有NN的梯度,如果最后整体梯度大于1,最后后面的梯度乘到前面会指数爆炸,越来越大,不过一般不会发生

【解决方案】

  • 梯度消失:预训练(例如He初始化) + 微调,非饱和的激活函数(如 ReLU,LeakyReLU,ELU),BN,残差结构,LSTM(记录了前几次的残存记忆),更快的优化器或适度增大学习率(在梯度消失之前就达到最优)
  • 梯度爆炸:梯度截断或权重正则(L1和L2)

44. 分布式训练

  • 同步模式训练存在木桶效应,需要各个设备的计算能力要均衡,而且要求集群的通信也要均衡
  • 异步模式理论上存在缺陷,容易发生梯度失效问题,但因为mini-batch随机梯度下降本身就是梯度下降的一个近似解法,且即使是梯度下降也无法保证全局最优。

在实际应用中,在相同时间内使用异步模式训练的模型不一定比同步模式差。所以这两种训练模式在实践中都有非常广泛的应用。

45. pytorch与tensorflow的区别

  • 两者都基于图,但为什么要用图?
    节省资源、高效运算:我们只需要运算需要的依赖项,不需要的不进行运算;把整个运算分解成子环节,方便自动求导; 对分布式运算友好,计算工作可以分给多个GPU、CPU,或者多个设备运算。很多机器学习的模型,本身就是适用组织成图的格式
  • 静态图和动态图
    Tensorflow1.0:静态图,难以调试;更适合大规模部署,特别是需要跨平台和嵌入式部署的情况,因此TF在实际生产中仍起主导作用。Tensorflow2.0:动态图,python自带调试的工具。Pytorch:动态图。Tensorflow相比于Pytorch的序列化与部署支持的更加广泛
  • 支持语言
    tensorflow:支持C++ 和 python 编程;pytorch:支持python编程
  • 支持硬件
    tensorflow:CPU、 GPU、 移动设备;pytorch:CPU 、GPU
  • 灵活性
    tensorflow:静态计算图,数据参数在CPU与GPU之间迁移麻烦,调试麻烦;pytorch:动态计算图,数据参数在CPU与GPU之间迁移十分灵活,调试简便
  • 学习难易
    tensorflow:社区庞大,bug基本能找到解决办法。学习难度中等,使用一般,新手容易掉坑。官网发布的文档详细。pytorch:社区正在扩大,部分bug查不到解决方案。学习难度低,使用简单,新手入门容易。官网发布的文档正在扩充。
  • 同等条件下计算速度
    tensorflow 在CPU上运行速度比 pytorch 快;tensorflow 在GPU上运行速度和 pytorch 差不多
  • 依赖库
    tensorflow:支持更多库函数,比如图像数据预处理方式会更多;pytorch:正在扩充,未来和tensorflow应该差别不大
  • 数据加载
    tensorflow:API设计庞大,使用有技巧,但有时候不能直接把数据加载进TensorFlow;pytorch:API整体设计粗糙,但加载数据的API设计很友好。加载数据的接口由一个数据集、一个取样器和一个数据加载器构成。
  • 设备管理
    tensorflow:不需要手动调整,简单;pytorch:需要明确启用的设备

46. 目标检测比赛中提高map的方法

  • anchor_ratio和anchor_scale的设置。
    根据模型感受野,anchor的长宽比,图片的长宽比来确定上面这两个数字。
    链接1 链接2
  • HRNet作为backbone来应对iou要求极高的检测
  • 粗检测+细检测来应对目标数量极其稀少的检测。
  • 训练采样的方式:
    a、在线加权采样(按照类别数量比例加权, 按照图片类别丰富程度加权);
    b、OHEM等基于loss的采样
  • 正常数据的使用
    a、图片拼接(先用rpn训练一下正常图片与带目标的图片的拼接图片,然后把上一步中训练出来的模型初始化一下新的rpn用来训练只带目标的图片)
    b、抠图+粘贴(也就是常说的填鸭法)
    c、做差、通道拼接
  • 整体算法
    包括四个部分(Backbone、Substructure、Head、Post-processing)
    在这里插入图片描述
  • 训练loss函数的选择(Focalloss等)
  • cascade模型的话注意iou阈值的选取
  • 类别不平衡的问题
    a、针对前景背景不平衡可以采用focalloss,CHM,OHEM等
    b、针对类别不平衡可以采用上采样,下采样等
  • 数据增强
    mmdetection+ablu、mixup、填鸭式
  • syncbn多卡BN同步一般效果会比较好
  • 学习率的设置,一般使用的是StepLrSchedule,可以尝试CosineLrSchedule
  • 多尺度测试
  • soft_nms
  • 减小confidence_threshold

47. 如何解决不收敛的问题。

a、loss出现nan,是否loss函数的使用不正确。
b、loss震荡,检查数据是否归一化,调整学习率,查看是否有梯度回传,使用大的模型。

48. 机器学习部分算法的总结

(1) KNN:计算你要预测的点的周围最近的K个点,然后取这k个点中最多的类定义为你要预测的这个点所属的类型。
(2) 朴素贝叶斯:如下图,又因为特征之间发生的概率是独立的,所以叫做朴素贝叶斯。
在这里插入图片描述
(3) 感知机:感知机对应于输入空间中将实例划分为两类的分离超平面。感知机旨在求出该超平面,为求得超平面导入了基于误分类的损失函数(0-1损失),利用梯度下降法对损失函数进行最优化。
(4) SVM:支持向量机有三个部分的内容,线性可分支持向量机,软间隔支持向量机,核函数。SVM的目标就是找到最大间隔超平面。
(5) 逻辑回归
在这里插入图片描述

49. SVM解决多分类问题

可以采用多个二分类组合的方式。例如:1对1,1对多,多对多等。

50. K-means中初始类中心怎么确定?

随机选择K个样本作为类中心,将样本随机划分成K个簇然后计算类中心。可以多次随机选取平均以减少随机初始化可能选择不好的问题。

51. 偏差和方差

偏差描述的是网络的真实输出和期望输出之间的差距,方差描述的是训练模型中各个预测结果之间的差异。所以:低偏差(高方差)说明拟合程度好,但是过拟合风险较高;低方差(高偏差)说明拟合程度差,欠拟合,有很大的误差。当模型较为复杂的时候。偏差变小,方差变大。(模型复杂容易导致过拟合)

52. padding中same和vaild的区别?

valid不padding,same则用0进行padding,具体padding多少要看实际情况,其本质是使得卷积输入的W和输出的W_out之间满足W_out = W / S 。

  • VALID: W_out = (W – F + 1) / S (结果向上取整)
  • SAME: W_out = W / S (结果向上取整)

其实就是 ( W − F + 2 P ) / S + 1 (W-F+2P) / S + 1 (WF+2P)/S+1,两者差别在于P是否为0,而卷积这里的除法一律向下取整,pool向上取整。上面两个公式向上取整是因为+1舍去了。

53. F1 score,F2 score,F0.5 score

F1 score的含义就是认为召回率和准确率一样重要,F2就是认为召回率比准确率重要2倍。F-score公式如下:
在这里插入图片描述
β = 1 \beta=1 β=1时,成为F1-Score,这时召回率和精确率都很重要,权重相同。当有些情况下我们认为精确率更为重要,那就调整 β \beta β的值小于 1 ,比如F0.5-Score;如果我们认为召回率更加重要,那就调整 β的值大于1,比如F2-Score。

54. 维数灾难?

当特征数量较少时,增加特征可以提高算法的精度,但是当向量的维数增加到一定的数量之后,再增加特征,算法的精度反而会下降。

55. Hinge Loss的核心思想是什么?

合页损失的损失函数为 L = m a x ( 0 , 1 − y ∗ y ^ ) L=max(0, 1-y*\hat{y}) L=max(0,1yy^),可以看得出来以SVM为模型的话,距离支持向量越远,其损失越大。

56. SVM为什么要求对偶问题?为什么对偶问题与原问题等价?

原问题不易求解,含有大量不易处理的不等式约束。原问题满足slater条件,强对偶成立,因此原问题与对偶问题成立。
slater条件,KKT条件,对偶问题参考链接

57. 简述一下常用的网络模型训练技巧

  • 增大batch_size同时增大学习率,若初始学习率为0.1,则学习率变化为0.1*batch_szie/256
  • lr warm up
  • residual的BN中尺度学习参数初始化为0
  • no bias decay
  • 降低精度 float16
  • cos退火 学习率
  • label smoothing
  • 知识蒸馏
  • mix_up cutout 随机裁剪,数据增强等

58. softmax的推导

在这里插入图片描述

59. pytorch的函数

  • DataLoader()加载数据
  • 初始化权重和bais
  • optim 优化方式,学习率学习方式
  • 损失函数 torch.nn.
  • Conv,pool,relu,dropout,FC等
  • 反向传播 loss.backword
  • 保存模型 torch.save 加载模型 torch.load

60. 交叉熵

真实概率 ∗ l o g ( 1 / 预测概率) 真实概率 * log(1 / 预测概率) 真实概率log1/预测概率)

61. 神经网络中使用sigmoid激活函数怎么实现非线性性?

首先sigmoid是一个非线性的激活函数,神经网络的非线性是通过非线性的激活函数和多层网络的融合叠加实现的。

62. K-means算法不知道有多少个聚类中心怎么办?

  • 手肘法:计算每个聚类的均方误差和,画出曲线图,拐点处即为。
  • 计算每个聚类的 gap = 类内距离/类间距离
  • 随机采样进行聚类。

63. 逻辑回归相对于线性回归怎么实现分类?

在线性回归的基础上做sigmoid。
在这里插入图片描述

64. BFS,DFS的实现步骤?

  • 广度优先搜索算法的搜索步骤一般是:(1)从队列头取出一个结点,检查它按照扩展规则是否能够扩展,如果能则产生一个新结点。(2)检查新生成的结点,看它是否已在队列中存在,如果新结点已经在队列中出现过,就放弃这个结点,然后回到第(1)步。否则,如果新结点未曾在队列中出现过,则将它加入到队列尾。(3)检查新结点是否目标结点。如果新结点是目标结点,则搜索成功,程序结束;若新结点不是目标结点,则回到第(1)步,再从队列头取出结点进行扩展。最终可能产生两种结果:找到目标结点,或扩展完所有结点而没有找到目标结点。
  • 深度优先搜索的步骤是:
    递归栈

65. hashmap和hash冲突

  • hashmap:就是通过hash函数映射到数组的某一位置。
  • hash冲突(解决方案):HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表(当前entry的next指向null),那么查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表(地址冲突了),对于添加操作,其时间复杂度为O(n),首先遍历链表,存在即覆盖,否则新增;对于查找操作来讲,仍需遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好。

66. 简单介绍一下LR?

参考链接

67. 如何提高模型检测的召回率(查得全)

增加数据集,数据增广,降低iou阈值(放入更快的框),模型融合。

68. LSTM与GRU

在这里插入图片描述

69. 马氏距离

在这里插入图片描述

70. SGD与ADAM

Adam是一阶动量和二阶动量的组合共同决定。SGD的话就是简单地梯度更新。Adam会出现不收敛和错过全局最优解的现象,所以比较好的方案是采用Adam+SGD的方案。

71. python的内存管理机制

引入计数,垃圾回收,内存池机制
变量名通过引用对象获取对象的类型和值。只要调用这个引用,引用计数就会增加,引用计数为0的时候就会启动垃圾回收机制。容器对象说明了两个对象通过赋值语句进行调用的时候是指向同一块内存空间的,所以其中一个变量增加另一个变量也会增加。内存池机制以256k为界限,大内存使用malloc进行内存分配,小内存使用内存池进行分配。

72. static存放变量在哪里?

一般程序的由new产生的动态数据存放在堆区,函数内部的自动变量存放在栈区。自动变量一般会随着函数的退出而释放空间,静态数据(即使是函数内部的静态局部变量)也存放在全局数据区。全局数据区的数据并不会因为函数的退出而释放空间。

73. linux静态库,动态库

  • 静态库的扩展名是.a
    这类库的名字一般是libxxx.a,xxx为库的名字。利用静态函数库编译成的文件比较大,因为整个函数库的所有数据都会被整合进目标代码中,他的优点就显而易见了,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去了。当然这也会成为他的缺点,因为如果静态函数库改变了,那么你的程序必须重新编译
  • 动态库的扩展名是.so
    这类库的名字一般是libxxx.M.N.so,同样的xxx为库的名字,M是库的主版本号,N是库的副版本号。当然也可以不要版本号,但名字必须有。相对于静态函数库,动态函数库在编译的时候并没有被编译进目标代码中,你的程序执行到相关函数时才调用该函数库里的相应函数,因此动态函数库所产生的可执行文件比较小。由于函数库没有被整合进你的程序,而是程序运行时动态的申请并调用,所以程序的运行环境中必须提供相应的库。动态函数库的改变并不影响你的程序,所以动态函数库的升级比较方便。Linux系统有几个重要的目录存放相应的函数库,如/lib,/usr/lib。

当要使用静态的程序库时,连接器会找出程序所需的函数,然后将它们拷贝到执行文件,由于这种拷贝是完整的,所以一旦连接成功,静态程序库也就不再需要了。然而,对动态库而言,就不是这样。动态库会在执行程序内留下一个标记指明当程序执行时,首先必须载入这个库。由于动态库节省空间,linux下进行连接的缺省操作是首先连接动态库,也就是说,如果同时存在静态和动态库,不特别指定的话,将与动态库相连接。

74. pytorch中model.children()和model.modules()的区别

两者得到的都是迭代器,用*list()转换一下得到输出

举例:

m = nn.Sequential(nn.Linear(2,2),                   
                  nn.ReLU(),
                  nn.Sequential(nn.Sigmoid(), 
                                nn.ReLU())) 

*list(m.children())返回的是:

[Linear(in_features=2, out_features=2), ReLU(), Sequential((0): Sigmoid()   (1): ReLU() )] 

一共3个元素:linear,relu,sequential
*list(m.modules())返回的是:

[Sequential((0): Linear(in_features=2, out_features=2)   
            (1): ReLU()   
            (2): Sequential((0): Sigmoid()     
                            (1): ReLU())), 
 Linear(in_features=2, out_features=2), 
 ReLU(), 
 Sequential((0): Sigmoid()   
            (1): ReLU() ), 
 Sigmoid(), 
 ReLU()] 

一共包括6个元素:整体的一个sequential,里面的一个linear,一个relu,一个子sequential,以及sequential里的sigmoid和relu。
用list举例就是:
a=[1,2,[3,4]]
children返回
1,2,[3,4]
modules返回
[1,2,[3,4]], 1, 2, [3,4], 3, 4
前者一般用的多,后者可以理解为一层一层拨开你的心

75. pytorch, caffe以及tensorflow的输入数据格式

pytorch和caffe都是NCHW,而tensorflow默认是NHWC,也有NCHW
为什么呢?因为NCHW计算时需要的存储更多,适合GPU运算,正好利用了GPU内存带宽较大并且并行性强的特点,其访存与计算的控制逻辑相对简单(对cuDNN的计算更友好)。而NHWC更适合多核CPU运算(当然GPU也可以算,但没NCHW模式在GPU下的快),CPU的内存带宽相对较小,每个像素计算的时延较低,临时空间也很小,有时计算机采取异步的方式边读边算来减小访存时间,因此计算控制灵活且复杂。因此,深度学习以cuDNN为底层的pytoch和caffe框架默认使用了 “NCHW” 格式,而Tensorflow采用了"NHWC",据说是由于早期主要使用CPU加速,这也解释了为何面向移动端部署的TFLite只采用了"NHWC" 格式。
在这里插入图片描述
对于非1*1的卷积,需要算的是max pooling类似的操作,因此也是对NCHW更友好,而网络中这种层才是大多数,因次也会更快。

  • 为什么都将N放在第一位呢?
    因为N不参与运算,算的是CHW,而N只是for循环遍历,只不过多核并行这个for会小一点,平均分配下去。

参考链接

76.常用端口

telnet:23
http:80
https:443,
DNS:53
mysql:3306
sql server:1433
oracle:1521
DB:50000
Postgre SQL:5432

77 如何处理类别不平衡问题

在这里插入图片描述

参考链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值