大厂必考深度学习算法面试题总结(代码片段)

author author     2023-01-06     258

关键词:

目录

一,滤波器与卷积核

在只有一个通道的情况下,“卷积核”(“kernel”)就相当于滤波器(“filter”),这两个概念是可以互换的。一个 “Kernel” 更倾向于是 2D 的权重矩阵。而 “filter” 则是指多个 kernel 堆叠的 3D 结构。如果是一个 2Dfilter,那么两者就是一样的。但是一个3D filter,在大多数深度学习的卷积中,它是包含 kernel 的。每个卷积核都是独一无二的,主要在于强调输入通道的不同方面

二,卷积层和池化输出大小计算

2.1,CNN 中术语解释

卷积层主要参数有下面这么几个:

  • 卷积核 Kernal 大小(在 Tensorflow/keras 框架中也称为filter);
  • 填充 Padding
  • 滑动步长 Stride
  • 输出通道数 Channels

2.2,卷积输出大小计算(简化型)

1,在 Pytorch 框架中,图片(feature map)经卷积 Conv2D输出大小计算公式如下:$\\left \\lfloor N = \\fracW-F+2PS+1 \\right \\rfloor$,其中 $\\lfloor \\rfloor$ 是向下取整符号,用于结果不是整数时进行向下取整(PytorchConv2d 卷积函数的默认参数 ceil_mode = False,即默认向下取整, dilation = 1)。

  • 输入图片大小 W×W(默认输入尺寸为正方形)
  • Filter 大小 F×F
  • 步长 S
  • padding的像素数 P
  • 输出特征图大小 N×N

2,特征图经反卷积(也叫转置卷积) keras-Conv2DTransposepytorch-ConvTranspose2d) 后得到的特征图大小计算方式:$out = (in - 1) *s -2p + k$,还有另外一个写法:$W = (N - 1)*S - 2P + F$,可由卷积输出大小计算公式反推得到。$in$ 是输入大小, $k$ 是卷积核大小, $s$ 是滑动步长, padding 的像素数 $p$,$out$ 是输出大小。

反卷积也称为转置卷积,一般主要用来还原 feature map 的尺寸大小,在 cnn 可视化,fcn 中达到 pixel classification,以及 gan 中从特征生成图像都需要用到反卷积的操作。反卷积输出结果计算实例。例如,输入:2x2, 卷积核大小:4x4, 滑动步长:3,填充像素为 0, 输出:7x7 ,其计算过程就是, (2 - 1) * 3 + 4 = 7

3,池化层如果设置为不填充像素(对于 Pytorch,设置参数padding = 0,对于 Keras/TensorFlow,设置参数padding="valid"),池化得到的特征图大小计算方式: $N=(W-F)/S+1$,这里公式表示的是除法结果向下取整再加 1

总结:对于Pytorchtensorflow 的卷积和池化函数,卷积函数 padding 参数值默认为 0/"valid"(即不填充),但在实际设计的卷积神经网络中,卷积层一般会填充像素(same),池化层一般不填充像素(valid),输出 shape 计算是向下取整。注意:当 stride1 的时候,kernel3padding1 或者 kernel5padding2,这两种情况可直接得出卷积前后特征图尺寸不变。

2.3,理解边界效应与填充 padding

如果希望输出特征图的空间维度Keras/TensorFlow 设置卷积层的过程中可以设置 padding 参数值为 “valid” 或 “same”“valid” 代表只进行有效的卷积,对边界数据不处理。“same” 代表 TensorFlow 会自动对原图像进行补零(表示卷积核可以停留在图像边缘),也就是自动设置 padding 值让输出与输入形状相同。

参考资料

三,深度学习框架的张量形状格式

  • 图像张量的形状有两种约定,通道在前channel-first)和通道在后channel-last)的约定,常用深度学习框架使用的数据张量形状总结如下:

    • Pytorch/Caffe: (N, C, H, W);
    • TensorFlow/Keras: (N, H, W, C)。
  • 举例理解就是Pytorch 的卷积层和池化层的输入 shape 格式为 (N, C, H, W)Keras 的卷积层和池化层的输入 shape 格式为 (N, H, W, C)

值得注意的是 OpenCV 读取图像后返回的矩阵 shape 的格式是 (H, W, C)格式。当 OpenCV 读取的图像为彩色图像时,返回的多通道的 BGR 格式的矩阵(HWC),在内存中的存储如下图:

四,Pytorch 、Keras 的池化层函数理解

4.1,torch.nn.MaxPool2d

class torch.nn.MaxPool2d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False)

二维池化层,默认输入的尺度是(N, C_in,H,W),输出尺度(N,C_out,H_out,W_out)。池化层输出尺度的 Width 默认计算公式如下(ceil_mode= True 时是向上取整,Height 计算同理):

$$\\left\\lfloor \\fracW_in + 2 * \\textpadding[0] - \\textdilation[0] \\times (\\textkernel_size[0] - 1) - 1\\textstride[0] + 1 \\right\\rfloor$$

主要参数解释

  • kernel_size(int or tuple):max pooling 的窗口大小。
  • stride(int or tuple, optional):max pooling的窗口移动的步长。默认值是kernel_size`。
  • padding(int or tuple, optional):默认值为 0,即不填充像素。输入的每一条边补充 0 的层数。
  • dilation:滑动窗中各元素之间的距离。
  • ceil_mode:默认值为 False,即上述公式默认向下取整,如果设为 True,计算输出信号大小的时候,公式会使用向上取整。

示例代码:

import torch
import torch.nn as nn
import torch.autograd as autograd
# 大小为3,步幅为2的正方形窗口池
m = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
# pool of non-square window
input = autograd.Variable(torch.randn(20, 16, 50, 32))
output = m(input)
print(output.shape)  # torch.Size([20, 16, 25, 16])

4.2,keras.layers.MaxPooling2D

keras.layers.MaxPooling2D(pool_size=(2, 2), strides=None, padding=valid, data_format=None)

对于 2D 空间数据的最大池化。默认输入尺寸是 (batch_size, rows, cols, channels)/(N, H, W, C_in)4D 张量,默认输出尺寸是 (batch_size, pooled_rows, pooled_cols, channels)4D 张量。

  • padding = valid:池化层输出的特征图大小为:$N=(W-F)/S+1$,这里表示的是向下取整再加 1
  • padding = same: 池化层输出的特征图大小为 $N = W/S$,这里表示向上取整

主要参数解释:

  • pool_size: 整数,或者 2 个整数表示的元组, 沿(垂直,水平)方向缩小比例的因数。(2,2)会把输入张量的两个维度都缩小一半。 如果只使用一个整数,那么两个维度都会使用同样的窗口长度。
  • strides: 整数,2 个整数表示的元组,或者是 None。 表示步长值。 如果是 None,那么默认值是 pool_size
  • padding: "valid" 或者 "same"(区分大小写)。
  • data_format: 字符串,channels_last (默认)或 channels_first 之一。 表示输入各维度的顺序。 channels_last 代表尺寸是 (batch, height, width, channels) 的输入张量, 而 channels_first 代表尺寸是 (batch, channels, height, width) 的输入张量。 默认值根据 Keras 配置文件 ~/.keras/keras.json 中的 image_data_format 值来设置。如果还没有设置过,那么默认值就是 "channels_last"

五,Pytorch 和 Keras 的卷积层函数理解

5.1,torch.nn.Conv2d

class torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)

二维卷积层, 输入的尺度是(N, C_in, H, W),输出尺度(N,C_out,H_out,W_out)。卷积层输出尺度的 Weight 计算公式如下(Height 同理):

$$\\left\\lfloor \\fracW_in + 2 \\times \\textpadding[0] - \\textdilation[0] \\times (\\textkernel_size[0] - 1) - 1\\textstride[0] + 1\\right\\rfloor$$

kernel_size, stride, padding, dilation 参数可以是以下两种形式( Maxpool2D 也一样):

  • a single int:同样的参数值被应用与 heightwidth 两个维度。
  • a tuple of two ints:第一个 int 值应用于 height 维度,第二个 int 值应用于 width 维度,也就是说卷积输出后的 heightwidth 值是不同的,要分别计算。

主要参数解释:

  • in_channels(int) – 输入信号的通道。
  • out_channels(int) – 卷积产生的通道。
  • kerner_size(int or tuple) - 卷积核的尺寸。
  • stride(int or tuple, optional) - 卷积步长,默认值为 1
  • padding(int or tuple, optional) - 输入的每一条边补充 0 的层数,默认不填充。
  • dilation(int or tuple, optional) – 卷积核元素之间的间距,默认取值 1
  • groups(int, optional) – 从输入通道到输出通道的阻塞连接数。
  • bias(bool, optional) - 如果 bias=True,添加偏置。

示例代码:

###### Pytorch卷积层输出大小验证
import torch
import torch.nn as nn
import torch.autograd as autograd
# With square kernels and equal stride
# output_shape: height = (50-3)/2+1 = 24.5,卷积向下取整,所以 height=24.
m = nn.Conv2d(16, 33, 3, stride=2)
# # non-square kernels and unequal stride and with padding
# m = nn.Conv2d(16, 33, (3, 5), stride=(2, 1), padding=(4, 2))  # 输出shape: torch.Size([20, 33, 28, 100])
# # non-square kernels and unequal stride and with padding and dilation
# m = nn.Conv2d(16, 33, (3, 5), stride=(2, 1), padding=(4, 2), dilation=(3, 1))  # 输出shape: torch.Size([20, 33, 26, 100])
input = autograd.Variable(torch.randn(20, 16, 50, 100))
output = m(input)

print(output.shape)  # 输出shape: torch.Size([20, 16, 24, 49])

5.2,keras.layers.Conv2D

keras.layers.Conv2D(filters, kernel_size, strides=(1, 1), padding=valid, data_format=None, dilation_rate=(1, 1), activation=None, use_bias=True, kernel_initializer=glorot_uniform, bias_initializer=zeros, kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None, kernel_constraint=None, bias_constraint=None)

2D 卷积层 (例如对图像的空间卷积)。输入输出尺寸格式要求和池化层函数一样。输入尺寸:(N, H, W, C),卷积核尺寸:(K, K, C_in, C_out)。

当使用该层作为模型第一层时,需要提供 input_shape 参数(整数元组,不包含 batch 轴),例如,input_shape=(128, 128, 3) 表示 128x128RGB 图像,在 data_format="channels_last" 时。

主要参数解释:

  • filters: 整数,输出空间的维度 (即卷积中滤波器的输出数量)。
  • kernel_size: 一个整数,或者 2 个整数表示的元组或列表,指明 2D 卷积窗口的宽度和高度。 可以是一个整数,为所有空间维度指定相同的值
  • strides: 一个整数,或者 2 个整数表示的元组或列表,指明卷积核模板沿宽度和高度方向的移动步长。 可以是一个整数,为所有空间维度指定相同的值。 指定任何 stride 值 != 1 与指定 dilation_rate 值 != 1 两者不兼容,默认取值 1,即代表会不遗漏的滑过输入图片(Feature Map)的每一个点。
  • padding: "valid""same" (大小写敏感),默认valid,这里的 "same" 代表给边界加上 Padding 让卷积的输出和输入保持同样("same")的尺寸(即填充像素)。
  • data_format: 字符串, channels_last (默认)channels_first 之一,表示输入中维度的顺序。 channels_last 对应输入尺寸为 (batch_size, height, width, channels), channels_first 对应输入尺寸为 (batch_size, channels, height, width)。 它默认为从 Keras 配置文件 ~/.keras/keras.json 中 找到的 image_data_format 值。 如果你从未设置它,将使用 channels_last
  • dilation_rate: 一个整数或 2 个整数的元组或列表, 指定膨胀卷积(空洞卷积 dilated convolution)的膨胀率。 可以是一个整数,为所有空间维度指定相同的值。 当前,指定任何 dilation_rate 值 != 1 与 指定 stride 值 != 1 两者不兼容。

5.3,总结

PytorchConv2d 函数不要求提供 输入数据的大小 (H,W),但是要提供输入深度,KerasConv2d 函数第一层要求提供 input_shape 参数 (H,W, C),其他层不需要。

六,softmax 回归

分类问题中,直接使用输出层的输出有两个问题:

  • 神经网络输出层的输出值的范围不确定,我们难以直观上判断这些值的意义
  • 由于真实标签是离散值,这些离散值与不确定范围的输出值之间的误差难以衡量

softmax 回归解决了以上两个问题,它将输出值变换为值为正且和为 1 的概率分布,公式如下: $$ softmax(y)i = yi^ = \\frace^yi\\sum_j=1^ne^yj $$

七,交叉熵损失函数

交叉熵刻画了两个概率分布之间的距离,它是分类问题中使用比较广泛的一种损失函数,交叉熵一般会与 softmax 回归一起使用,公式如下:

$$L = -\\sum_c=1^My_clog(p_c)或者H(p,q)=-\\sum p(x)logq(x)$$

  • $p$ ——代表正确答案;
  • $q$ ——代表预测值;
  • $M$ ——类别的数量;
  • $y_c$ ——指示变量( 01),如果该类别和样本的类别相同就是 1,否则是 0
  • $p_c$ ——对于观测样本属于类别 $c$ 的预测概率。

7.1,为什么交叉熵可以用作代价函数

从数学上来理解就是,为了让学到的模型分布更接近真实数据的分布,我们需要最小化模型数据分布与训练数据之间的 KL 散度,而因为训练数据的分布是固定的,因此最小化 KL 散度等价于最小化交叉熵,而且交叉熵计算更简单,所以机器/深度学习中常用交叉熵 cross-entroy 作为分类问题的损失函数。

7.2,优化算法理解

AdamAdaGradRMSProp优化算法具有自适应性。

八,感受野理解

感受野理解(Receptive Field)是指后一层神经元在前一层神经元的感受空间,也可以定义为卷积神经网络中每层的特征图(Feature Map)上的像素点在原始图像中映射的区域大小,即如下图所示:

注意:感受野在 CNN 中是呈指数级增加的。小卷积核(如 3*3)通过多层叠加可取得与大卷积核(如 7*7)同等规模的感受野,此外采用小卷积核有两个优势:

  1. 小卷积核需多层叠加,加深了网络深度进而增强了网络容量(model capacity)和复杂度(model complexity)。
  2. 增强了网络容量的同时减少了参数个数。

8.1,感受野大小计算

计算感受野时,我们需要知道:

  • 第一层卷积层的输出特征图像素的感受野的大小等于滤波器的大小;
  • 深层卷积层的感受野大小和它之前所有层的滤波器大小和步长有关系;
  • 计算感受野大小时,忽略了图像边缘的影响。

感受野的计算方式有两种:自底向上和自顶向下(top to down),这里只讲解后者。正常卷积(且不带 padding)感受野计算公式如下:

$$F(i, j-1) = (F(i, j)-1)*stride + kernel_size$$

其中 $F(i, j)$ 表示第 i 层对第 j 层的局部感受野,所以这个公式是从上层向下层计算感受野的。仔细看这个公式会发现和反卷积输出大小计算公式一模一样,实际上感受野计算公式就是 feature_map 计算公式的反向推导。

以下 Python 代码可以实现计算 Alexnet zf-5VGG16 网络每层输出 feature map 的感受野大小,卷积核大小和输入图像尺寸默认定义好了,代码如下:

# !/usr/bin/env python

# [filter size, stride, padding]
net_struct = alexnet: net:[[11,4,0],[3,2,0],[5,1,2],[3,2,0],[3,1,1],[3,1,1],[3,1,1],[3,2,0]],
                   name:[conv1,pool1,conv2,pool2,conv3,conv4,conv5,pool5],
       vgg16: net:[[3,1,1],[3,1,1],[2,2,0],[3,1,1],[3,1,1],[2,2,0],[3,1,1],[3,1,1],[3,1,1],
                        [2,2,0],[3,1,1],[3,1,1],[3,1,1],[2,2,0],[3,1,1],[3,1,1],[3,1,1],[2,2,0]],
                 name:[conv1_1,conv1_2,pool1,conv2_1,conv2_2,pool2,conv3_1,conv3_2,
                         conv3_3, pool3,conv4_1,conv4_2,conv4_3,pool4,conv5_1,conv5_2,conv5_3,pool5],
       zf-5:net: [[7,2,3],[3,2,1],[5,2,2],[3,2,1],[3,1,1],[3,1,1],[3,1,1]],
               name: [conv1,pool1,conv2,pool2,conv3,conv4,conv5]


def outFromIn(isz, net, layernum):
    """
    计算feature map大小
    """
    totstride = 1
    insize = isz
    # for layer in range(layernum):
    fsize, stride, pad = net[layernum]
    outsize = (insize - fsize + 2*pad) / stride + 1
    insize = outsize
    totstride = totstride * stride
    return outsize, totstride

def inFromOut(net, layernum):
    """
    计算感受野receptive file大小
    """
    RF = 1
    for layer in reversed(range(layernum)):  # reversed 函数返回一个反向的迭代器
        fsize, stride, pad = net[layer]
        RF = ((RF -1)* stride) + fsize
    return RF

if __name__ == __main__:
    imsize = 224
    feature_size = imsize
    print ("layer output sizes given image = %dx%d" % (imsize, imsize))
    
    for net in net_struct.keys():
        feature_size = imsize
        print (************net structrue name is %s**************% net)
        for i in range(len(net_struct[net][net])):
            feature_size, stride = outFromIn(feature_size, net_struct[net][net], i)
            rf = inFromOut(net_struct[net][net], i+1)
            print ("Layer Name = %s, Output size = %3d, Stride = % 3d, RF size = %3d" % (net_struct[net][name][i], feature_size, stride, rf))

程序输出结果如下:

layer output sizes given image = 224x224
************net structrue name is alexnet**************
Layer Name = conv1, Output size =  54, Stride =   4, RF size =  11
Layer Name = pool1, Output size =  26, Stride =   2, RF size =  19
Layer Name = conv2, Output size =  26, Stride =   1, RF size =  51
Layer Name = pool2, Output size =  12, Stride =   2, RF size =  67
Layer Name = conv3, Output size =  12, Stride =   1, RF size =  99
Layer Name = conv4, Output size =  12, Stride =   1, RF size = 131
Layer Name = conv5, Output size =  12, Stride =   1, RF size = 163
Layer Name = pool5, Output size =   5, Stride =   2, RF size = 195
************net structrue name is vgg16**************
Layer Name = conv1_1, Output size = 224, Stride =   1, RF size =   3
Layer Name = conv1_2, Output size = 224, Stride =   1, RF size =   5
Layer Name = pool1, Output size = 112, Stride =   2, RF size =   6
Layer Name = conv2_1, Output size = 112, Stride =   1, RF size =  10
Layer Name = conv2_2, Output size = 112, Stride =   1, RF size =  14
Layer Name = pool2, Output size =  56, Stride =   2, RF size =  16
Layer Name = conv3_1, Output size =  56, Stride =   1, RF size =  24
Layer Name = conv3_2, Output size =  56, Stride =   1, RF size =  32
Layer Name = conv3_3, Output size =  56, Stride =   1, RF size =  40
Layer Name = pool3, Output size =  28, Stride =   2, RF size =  44
Layer Name = conv4_1, Output size =  28, Stride =   1, RF size =  60
Layer Name = conv4_2, Output size =  28, Stride =   1, RF size =  76
Layer Name = conv4_3, Output size =  28, Stride =   1, RF size =  92
Layer Name = pool4, Output size =  14, Stride =   2, RF size = 100
Layer Name = conv5_1, Output size =  14, Stride =   1, RF size = 132
Layer Name = conv5_2, Output size =  14, Stride =   1, RF size = 164
Layer Name = conv5_3, Output size =  14, Stride =   1, RF size = 196
Layer Name = pool5, Output size =   7, Stride =   2, RF size = 212
************net structrue name is zf-5**************
Layer Name = conv1, Output size = 112, Stride =   2, RF size =   7
Layer Name = pool1, Output size =  56, Stride =   2, RF size =  11
Layer Name = conv2, Output size =  28, Stride =   2, RF size =  27
Layer Name = pool2, Output size =  14, Stride =   2, RF size =  43
Layer Name = conv3, Output size =  14, Stride =   1, RF size =  75
Layer Name = conv4, Output size =  14, Stride =   1, RF size = 107
Layer Name = conv5, Output size =  14, Stride =   1, RF size = 139

九,卷积和池化操作的作用

卷积层和池化层的理解可参考魏秀参的《解析卷积神经网络》书籍,卷积(convolution )操作的作用如下:

  1. 局部感知,参数共享 的特点大大降低了网络参数,保证了网络的稀疏性。
  2. 通过卷积核的组合以及随着网络后续操作的进行,卷积操作可获取图像不同区域的不同类型特征;模型靠近底部的层提取的是局部的、高度通用的特征图,而更靠近顶部的层提取的是更加抽象的语义特征。

池化/汇合(pooling )操作作用如下:

  1. 特征不变性(feature invariant)。汇合操作使模型更关注是否存在某些特征而不是特征具体的位置可看作是一种很强的先验,使特征学习包含某种程度自由度,能容忍一些特征微小的位移。
  2. 特征降维。由于汇合操作的降采样作用,汇合结果中的一个元素对应于原输入数据的一个子区域(sub-region),因此汇合相当于在空间范围内做了维度约减(spatially dimension reduction),从而使模型可以抽取更广范围的特征。同时减小了下一层输入大小,进而减小计算量和参数个数。
  3. 在一定程度上能防止过拟合(overfitting),更方便优化。

参考资料

魏秀参-《解析卷积神经网络》

十,卷积层与全连接层的区别

  • 卷积层学习到的是局部模式(对于图像,学到的就是在输入图像的二维小窗口中发现的模式)
  • 全连接层学习到的是全局模式(全局模式就算设计所有像素)

十一,CNN 权值共享问题

首先权值共享就是滤波器共享,滤波器的参数是固定的,即是用相同的滤波器去扫一遍图像,提取一次特征特征,得到feature map。在卷积网络中,学好了一个滤波器,就相当于掌握了一种特征,这个滤波器在图像中滑动,进行特征提取,然后所有进行这样操作的区域都会被采集到这种特征,就好比上面的水平线。

十二,CNN 结构特点

典型的用于分类的CNN主要由卷积层+激活函数+池化层组成,最后用全连接层输出。卷积层负责提取图像中的局部特征;池化层用来大幅降低参数量级(降维);全连接层类似传统神经网络的部分,用来输出想要的结果。

CNN 具有局部连接、权值共享、池化操作(简单说就是下采样)和多层次结构的特点。

  • 局部连接使网络可以提取数据的局部特征。
  • 权值共享大大降低了网络的训练难度,一个Filter只提取一个特征,在整个图片(或者语音/文本) 中进行卷积。
  • 池化操作与多层次结构一起,实现了数据的降维,将低层次的局部特征组合成为较高层次的特征,从而对整个图片进行表示。
  • 卷积神经网络学到的模式具有平移不变性(translation invariant),且可以学到模式的空间层次结构。

Reference

(二)计算机视觉四大基本任务(分类、定位、检测、分割

十三,深度特征的层次性

卷积操作可获取图像区域不同类型特征,而汇合等操作可对这些特征进行融合和抽象,随着若干卷积、汇合等操作的堆叠,各层得到的深度特征逐渐从泛化特征(如边缘、纹理等)过渡到高层语义表示(躯干、头部等模式)。

十四,什么样的数据集不适合深度学习

  • 数据集太小,数据样本不足时,深度学习相对其它机器学习算法,没有明显优势。
  • 数据集没有局部相关特性,目前深度学习表现比较好的领域主要是图像/语音/自然语言处理等领域,这些领域的一个共性是局部相关性。图像中像素组成物体,语音信号中音位组合成单词,文本数据中单词组合成句子,这些特征元素的组合一旦被打乱,表示的含义同时也被改变。对于没有这样的局部相关性的数据集,不适于使用深度学习算法进行处理。举个例子:预测一个人的健康状况,相关的参数会有年龄、职业、收入、家庭状况等各种元素,将这些元素打乱,并不会影响相关的结果。

十五,什么造成梯度消失问题

  • 神经网络的训练中,通过改变神经元的权重,使网络的输出值尽可能逼近标签以降低误差值,训练普遍使用BP算法,核心思想是,计算出输出与标签间的损失函数值,然后计算其相对于每个神经元的梯度,进行权值的迭代。
  • 梯度消失会造成权值更新缓慢,模型训练难度增加。造成梯度消失的一个原因是,许多激活函数将输出值挤压在很小的区间内,在激活函数两端较大范围的定义域内梯度为0,造成学习停止。

十六,Overfitting 和 Underfitting 问题

16.1,过拟合问题怎么解决

首先所谓过拟合,指的是一个模型过于复杂之后,它可以很好地“记忆”每一个训练数据中随机噪音的部分而忘记了去“训练”数据中的通用趋势。训练好后的模型过拟合具体表现在:模型在训练数据上损失函数较小,预测准确率较高;但是在测试数据上损失函数比较大,预测准确率较低。解决办法如下:

  • 数据增强, 增加数据多样性;
  • 正则化策略:如 Parameter Norm Penalties(参数范数惩罚), L1, L2正则化;
  • dropout;
  • 模型融合, 比如Bagging 和其他集成方法;
  • BN ,batch normalization;
  • Early Stopping(提前终止训练)。

16.2,如何判断深度学习模型是否过拟合

  1. 首先将训练数据划分为训练集和验证集,80% 用于训练集,20% 用于验证集(训练集和验证集一定不能相交);训练都时候每隔一定 Epoch 比较验证集但指标和训练集是否一致,如果不一致,并且变坏了,那么意味着过拟合。
  2. 用学习曲线 learning curve 来判别过拟合,参考此博客

16.3,欠拟合怎么解决

underfitting 欠拟合的表现就是模型不收敛,原因有很多种,这里以神经网络拟合能力不足问题给出以下参考解决方法:

  • 寻找最优的权重初始化方案:如 He正态分布初始化 he_normal,深度学习框架都内置了很多权重初始化方法;
  • 使用适当的激活函数:卷积层的输出使用的激活函数一般为 ReLu,循环神经网络中的循环层使用的激活函数一般为 tanh,或者 ReLu
  • 选择合适的优化器和学习速率:SGD 优化器速度慢但是会达到最优.

16.4,如何判断模型是否欠拟合

神级网络欠拟合的特征就是模型训练了足够长但时间后, loss 值依然很大甚至与初始值没有太大区别,且精度很低,测试集亦如此。根据我的总结,原因一般有以下几种:

  • 神经网络的拟合能力不足;
  • 网络配置的问题;
  • 数据集配置的问题;
  • 训练方法出错(初学者经常碰到,原因千奇百怪)。

十七,L1 和 L2 区别

L1 范数(L1 norm)是指向量中各个元素绝对值之和,也有个美称叫“稀疏规则算子”(Lasso regularization)。 比如 向量 A=[1,-1,3], 那么 A 的 L1 范数为 |1|+|-1|+|3|。简单总结一下就是:

  • L1 范数: 为向量 x 各个元素绝对值之和。
  • L2 范数: 为向量 x 各个元素平方和的 1/2 次方,L2 范数又称 Euclidean 范数或 Frobenius 范数
  • Lp 范数: 为向量 x 各个元素绝对值 $p$ 次方和的 $1/p$ 次方.

在支持向量机学习过程中,L1 范数实际是一种对于成本函数求解最优的过程,因此,L1 范数正则化通过向成本函数中添加 L1 范数,使得学习得到的结果满足稀疏化,从而方便人类提取特征。

L1 范数可以使权值参数稀疏,方便特征提取。 L2 范数可以防止过拟合,提升模型的泛化能力。

十八,TensorFlow计算图概念

Tensorflow 是一个通过计算图的形式来表述计算的编程系统,计算图也叫数据流图,可以把计算图看做是一种有向图,Tensorflow 中的每一个计算都是计算图上的一个节点,而节点之间的边描述了计算之间的依赖关系。

十九,BN(批归一化)的作用

在神经网络中间层也进行归一化处理,使训练效果更好的方法,就是批归一化Batch Normalization(BN)。

(1). 可以使用更高的学习率。如果每层的 scale 不一致,实际上每层需要的学习率是不一样的,同一层不同维度的 scale 往往也需要不同大小的学习率,通常需要使用最小的那个学习率才能保证损失函数有效下降,Batch Normalization 将每层、每维的 scale 保持一致,那么我们就可以直接使用较高的学习率进行优化。

(2). 移除或使用较低的 dropout。 dropout 是常用的防止 overfitting 的方法,而导致 overfitting 的位置往往在数据边界处,如果初始化权重就已经落在数据内部,overfitting现象就可以得到一定的缓解。论文中最后的模型分别使用10%、5%和0%的dropout训练模型,与之前的 40%-50% 相比,可以大大提高训练速度。

(3). 降低 L2 权重衰减系数。 还是一样的问题,边界处的局部最优往往有几维的权重(斜率)较大,使用 L2 衰减可以缓解这一问题,现在用了 Batch Normalization,就可以把这个值降低了,论文中降低为原来的 5 倍。

(4). 代替Local Response Normalization层。 由于使用了一种 Normalization,再使用 LRN 就显得没那么必要了。而且 LRN 实际上也没那么 work。

(5). Batch Normalization调整了数据的分布,不考虑激活函数,它让每一层的输出归一化到了均值为0方差为1的分布,这保证了梯度的有效性,可以解决反向传播过程中的梯度问题。目前大部分资料都这样解释,比如 BN 的原始论文认为的缓解了 Internal Covariate Shift(ICS) 问题。

关于训练阶段和推理阶段 BN 的不同可以参考 Batch Normalization详解

二十,什么是梯度消失和爆炸

  • 梯度消失是指在深度学习训练的过程中,梯度随着 BP 算法中的链式求导逐层传递逐层减小,最后趋近于0,导致对某些层的训练失效;
  • 梯度爆炸与梯度消失相反,梯度随着 BP 算法中的链式求导逐层传递逐层增大,最后趋于无穷,导致某些层无法收敛;

梯度消失和梯度爆炸产生的原因

出现梯度消失和梯度爆炸的问题主要是因为参数初始化不当以及激活函数选择不当造成的。其根本原因在于反向传播训练法则,属于先天不足。当训练较多层数的模型时,一般会出现梯度消失问题(gradient vanishing problem)和梯度爆炸问题(gradient exploding problem)。注意在反向传播中,当网络模型层数较多时,梯度消失和梯度爆炸是不可避免的。

深度神经网络中的梯度不稳定性,根本原因在于前面层上的梯度是来自于后面层上梯度的乘积。当存在过多的层次时,就出现了内在本质上的不稳定场景。前面的层比后面的层梯度变化更小,故变化更慢,故引起了梯度消失问题。前面层比后面层梯度变化更快,故引起梯度爆炸问题。

如何解决梯度消失和梯度爆炸问题

常用的有以下几个方案:

  • 预训练模型 + 微调
  • 梯度剪切 + 正则化
  • relu、leakrelu 等激活函数
  • BN 批归一化
  • 参数标准初始化函数如 xavier
  • CNN 中的残差结构
  • LSTM 结构

二十一,RNN循环神经网络理解

循环神经网络(recurrent neural network, RNN), 主要应用在语音识别、语言模型、机器翻译以及时序分析等问题上。 在经典应用中,卷积神经网络在不同的空间位置共享参数,循环神经网络是在不同的时间位置共享参数,从而能够使用有限的参数处理任意长度的序列。

RNN 可以看做作是同一神经网络结构在时间序列上被复制多次的结果,这个被复制多次的结构称为循环体,如何设计循环体的网络结构是 RNN 解决实际问题的关键。RNN 的输入有两个部分,一部分为上一时刻的状态,另一部分为当前时刻的输入样本。

二十二,训练过程中模型不收敛,是否说明这个模型无效,导致模型不收敛的原因

不一定。导致模型不收敛的原因有很多种可能,常见的有以下几种:

  • 没有对数据做归一化。
  • 没有检查过你的结果。这里的结果包括预处理结果和最终的训练测试结果。
  • 忘了做数据预处理。
  • 忘了使用正则化。
  • Batch Size 设的太大。
  • 学习率设的不对。
  • 最后一层的激活函数用的不对。
  • 网络存在坏梯度。比如 ReLu 对负值的梯度为 0,反向传播时,0 梯度就是不传播。
  • 参数初始化错误。
  • 网络太深。隐藏层神经元数量错误。
  • 更多回答,参考此链接

二十三,VGG 使用 2 个 3*3 卷积的优势

(1). 减少网络层参数。用两个 3*3 卷积比用 1 个 5*5 卷积拥有更少的参数量,只有后者的 2∗3∗3/5∗5=0.72。但是起到的效果是一样的,两个 3×3 的卷积层串联相当于一个 5×5 的卷积层,感受野的大小都是 5×5,即 1 个像素会跟周围 5×5 的像素产生关联。把下图当成动态图看,很容易看到两个 3×3 卷积层堆叠(没有空间池化)有 5×5 的有效感受野。

(2). 更多的非线性变换。2 个 3×3 卷积层拥有比 1 个 5×5 卷积层更多的非线性变换(前者可以使用两次 ReLU 激活函数,而后者只有一次),使得卷积神经网络对特征的学习能力更强。

paper中给出的相关解释:三个这样的层具有 7×7 的有效感受野。那么我们获得了什么?例如通过使用三个 3×3 卷积层的堆叠来替换单个 7×7 层。首先,我们结合了三个非线性修正层,而不是单一的,这使得决策函数更具判别性。其次,我们减少参数的数量:假设三层 3×3 卷积堆叠的输入和输出有 C 个通道,堆叠卷积层的参数为 3×(3×3C) = 27C 个权重;同时,单个 7×7 卷积层将需要 7×7×C = 49C 个参数,即参数多 81%。这可以看作是对 7×7 卷积滤波器进行正则化,迫使它们通过 3×3 滤波器(在它们之间注入非线性)进行分解。

此回答可以参考 TensorFlow 实战 p110,网上很多回答都说的不全

23.1,1*1 卷积的主要作用

  • 降维( dimension reductionality )。比如,一张500 * 500且厚度depth为100 的图片在20个filter上做1*1的卷积,那么结果的大小为500*500*20。
  • 加入非线性。卷积层之后经过激励层,1*1的卷积在前一层的学习表示上添加了非线性激励( non-linear activation ),提升网络的表达能力;

二十四,Relu比Sigmoid效果好在哪里?

Sigmoid 函数公式如下: $\\sigma (x)=\\frac11+exp(-x)$

ReLU激活函数公式如下: $$f(x) = max(x, 0) = \\begincases x, & \\textif $x$ $\\geq$ 0 \\ 0, & \\textif $x$ < 0 \\endcases$$

ReLU 的输出要么是 0, 要么是输入本身。虽然方程简单,但实际上效果更好。在网上看了很多版本的解释,有从程序实例分析也有从数学上分析,我找了个相对比较直白的回答,如下:

  1. ReLU 函数计算简单,可以减少很多计算量。反向传播求误差梯度时,涉及除法,计算量相对较大,采用 ReLU 激活函数,可以节省很多计算量;
  2. 避免梯度消失问题。对于深层网络,sigmoid 函数反向传播时,很容易就会出现梯度消失问题(在sigmoid接近饱和区时,变换太缓慢,导数趋于 0,这种情况会造成信息丢失),从而无法完成深层网络的训练。
  3. 可以缓解过拟合问题的发生。ReLU 会使一部分神经元的输出为 0,这样就造成了网络的稀疏性,并且减少了参数的相互依存关系,缓解了过拟合问题的发生。
  4. 相比 sigmoid 型函数,ReLU 函数有助于随机梯度下降方法收敛。

参考链接

ReLU为什么比Sigmoid效果好

二十五,神经网络中权值共享的理解

权值(权重)共享这个词是由 LeNet5 模型提出来的。以 CNN 为例,在对一张图偏进行卷积的过程中,使用的是同一个卷积核的参数。 比如一个 3×3×1 的卷积核,这个卷积核内 9 个的参数被整张图共享,而不会因为图像内位置的不同而改变卷积核内的权系数。说的再直白一些,就是用一个卷积核不改变其内权系数的情况下卷积处理整张图片(当然CNN中每一层不会只有一个卷积核的,这样说只是为了方便解释而已)。

参考资料

如何理解CNN中的权值共享

二十六,对 fine-tuning(微调模型的理解),为什么要修改最后几层神经网络权值?

使用预训练模型的好处,在于利用训练好的SOTA模型权重去做特征提取,可以节省我们训练模型和调参的时间。

至于为什么只微调最后几层神经网络权重,是因为:

(1). CNN 中更靠近底部的层(定义模型时先添加到模型中的层)编码的是更加通用的可复用特征,而更靠近顶部的层(最后添加到模型中的层)编码的是更专业业化的特征。微调这些更专业化的特征更加有用,它更代表了新数据集上的有用特征。 (2). 训练的参数越多,过拟合的风险越大。很多SOTA模型拥有超过千万的参数,在一个不大的数据集上训练这么多参数是有过拟合风险的,除非你的数据集像Imagenet那样大。

参考资料

Python深度学习p127.

二十七,什么是 dropout?

  • dropout可以防止过拟合,dropout简单来说就是:我们在前向传播的时候,让某个神经元的激活值以一定的概率 p 停止工作,这样可以使模型的泛化性更强,因为它不会依赖某些局部的特征。
  • dropout效果跟bagging效果类似(bagging是减少方差variance,而boosting是减少偏差bias)
  • 加入dropout会使神经网络训练时间边长,模型预测时不需要dropout,记得关掉。

27.1,dropout具体工作流程

以 标准神经网络为例,正常的流程是:我们首先把输入数据x通过网络前向传播,然后把误差反向传播一决定如何更新参数让网络进行学习。使用dropout之后,过程变成如下:

1,首先随机(临时)删掉网络中一半的隐藏神经元,输入输出神经元保持不变(图3中虚线为部分临时被删除的神经元);

2,然后把输入x通过修改后的网络进行前向传播计算,然后把得到的损失结果通过修改的网络反向传播。一小批训练样本执行完这个过程后,在没有被删除的神经元上按照随机梯度下降法更新对应的参数(w,b);

3,然后重复这一过程:

  • 恢复被删掉的神经元(此时被删除的神经元保持原样没有更新w参数,而没有被删除的神经元已经有所更新);
  • 从隐藏层神经元中随机选择一个一半大小的子集临时删除掉(同时备份被删除神经元的参数);
  • 对一小批训练样本,先前向传播然后反向传播损失并根据随机梯度下降法更新参数(w,b) (没有被删除的那一部分参数得到更新,删除的神经元参数保持被删除前的结果)。

27.2,dropout在神经网络中的应用

(1). 在训练模型阶段

不可避免的,在训练网络中的每个单元都要添加一道概率流程,标准网络和带有dropout网络的比较图如下所示:

(2). 在测试模型阶段

预测模型的时候,输入是当前输入,每个神经单元的权重参数要乘以概率p。

27.3,如何选择dropout 的概率

input 的 dropout 概率推荐是 0.8, hidden layer 推荐是0.5, 但是也可以在一定的区间上取值。(All dropout nets use p = 0.5 for hidden units and p = 0.8 for input units.)

参考资料

  1. [Dropout:A Simple Way to Prevent Neural Networks from Overfitting]
  2. 深度学习中Dropout原理解析

二十八,HOG 算法原理描述

方向梯度直方图(Histogram of Oriented Gradient, HOG)特征是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子。它通过计算和统计图像局部区域的梯度方向直方图来构成特征。在深度学习取得成功之前,Hog特征结合SVM分类器被广泛应用于图像识别中,在行人检测中获得了较大的成功。

HOG特征原理

HOG 的核心思想是所检测的局部物体外形能够被光强梯度或边缘方向的分布所描述。通过将整幅图像分割成小的连接区域(称为cells),每个 cell 生成一个方向梯度直方图或者 cell 中pixel 的边缘方向,这些直方图的组合可表示(所检测目标的目标)描述子。

为改善准确率,局部直方图可以通过计算图像中一个较大区域(称为block)的光强作为 measure 被对比标准化,然后用这个值(measure)归一化这个 block 中的所有 cells 。这个归一化过程完成了更好的照射/阴影不变性。与其他描述子相比,HOG 得到的描述子保持了几何和光学转化不变性(除非物体方向改变)。因此HOG描述子尤其适合人的检测。

HOG 特征提取方法就是将一个image:

  1. 灰度化(将图像看做一个x,y,z(灰度)的三维图像)
  2. 划分成小 cells(2*2)
  3. 计算每个 cell 中每个 pixel 的 gradient(即 orientation)
  4. 统计每个 cell 的梯度直方图(不同梯度的个数),即可形成每个 cell 的 descriptor。

HOG特征检测步骤

总结:颜色空间归一化——>梯度计算——>梯度方向直方图——>重叠块直方图归一化———>HOG特征

参考资料

HOG特征检测-简述

二十九,激活函数

29.1,激活函数的作用

  • 激活函数实现去线性化。激活函数的引入是为了增加整个网络的表达能力(引入非线性因素),否则若干线形层的堆叠仍然只能起到线性映射的作用,无法形成复杂的函数。如果将每一个神经元(也就是神经网络的节点)的输出通过一个非线性函数,那么整个神经网络的模型也就不再是线性的了,这个非线性函数就是激活函数。
  • 激活函数可以把当前特征空间通过一定的线性映射转换到另一个空间,让数据能够更好的被分类。
  • 激活函数对模型学习、理解非常复杂和非线性的函数具有重要作用。

29.2,常见的激活函数

激活函数也称非线性映射函数,常见的激活函数有:ReLU 函数、sigmoid 函数、tanh 函数等,其计算公式如下:

  • ReLU函数:$f(x)=max(x,0)$
  • sigmoid函数:$f(x)=\\frac11+e^-x$
  • tanh函数:$f(x)=\\frac1+e^-2x1+e^-2x=\\frac21+e^-2x-1 = 2sigmoid(2x)-1$

29.3,激活函数理解及函数梯度图

  1. Sigmoid 激活函数,可用作分类任务的输出层。可以看出经过sigmoid激活函数后,模型输出的值域被压缩到 0到1 区间(这和概率的取值范围一致),这正是分类任务中sigmoid很受欢迎的原因。

  1. tanh(x) 型函数是在 sigmoid 型函数基础上为解决均值问题提出的激活函数。tanh 的形状和 sigmoid 类似,只不过tanh将“挤压”输入至区间(-1, 1)。至于梯度,它有一个大得多的峰值1.0(同样位于z = 0处),但它下降得更快,当|x|的值到达 3 时就已经接近零了。这是所谓梯度消失(vanishing gradients)问题背后的原因,会导致网络的训练进展变慢。

  1. ReLU 处理了sigmoid、tanh中常见的梯度消失问题,同时也是计算梯度最快的激励函数。但是,ReLU函数也有自身缺陷,即在 x < 0 时,梯度便为 y。换句话说,对于小于 y 的这部分卷积结果响应,它们一旦变为负值将再无法影响网络训练——这种现象被称作“死区"。

三十,卷积层和池化层有什么区别

  1. 卷积层有参数,池化层没有参数
  2. 经过卷积层节点矩阵深度会改变。池化层不会改变节点矩阵的深度,但是它可以缩小节点矩阵的大小。

三十一,卷积层和池化层参数量计算

参考 神经网络模型复杂度分析 文章。

三十二,神经网络为什么用交叉熵损失函数

判断一个输出向量和期望的向量有多接近,交叉熵(cross entroy)是常用的评判方法之一。交叉熵刻画了两个概率分布之间的距离,是分类问题中使用比较广泛的一种损失函数。给定两个概率分布 pq ,通过 q 来表示 p 的交叉熵公式为:$H(p,q)=−∑p(x)logq(x)$

三十三,数据增强方法有哪些

常用数据增强方法:

  • 翻转:Fliplr,Flipud。不同于旋转180度,这是类似镜面的翻折,跟人在镜子中的映射类似,常用水平、上下镜面翻转。
  • 旋转:rotate。顺时针/逆时针旋转,最好旋转 90-180 度,否则会出现边缘缺失或者超出问题,如旋转 45 度。
  • 缩放:zoom。图像可以被放大或缩小,imgaug库可用Scal函数实现。
  • 裁剪:crop。一般叫随机裁剪,操作步骤是:随机从图像中选择一部分,然后降这部分图像裁剪出来,然后调整为原图像的大小。根本上理解,图像crop就是指从图像中移除不需要的信息,只保留需要的部分
  • 平移:translation。平移是将图像沿着x或者y方向(或者两个方向)移动。我们在平移的时候需对背景进行假设,比如说假设为黑色等等,因为平移的时候有一部分图像是空的,由于图片中的物体可能出现在任意的位置,所以说平移增强方法十分有用。
  • 放射变换:Affine。包含:平移(Translation)、旋转(Rotation)、放缩(zoom)、错切(shear)。
  • 添加噪声:过拟合通常发生在神经网络学习高频特征的时候,为消除高频特征的过拟合,可以随机加入噪声数据来消除这些高频特征。imgaug 图像增强库使用 GaussianBlur函数。
  • 亮度、对比度增强:这是图像色彩进行增强的操作
  • 锐化:Sharpen。imgaug库使用Sharpen函数。

33.1,离线数据增强和在线数据增强有什么区别?

数据增强分两类,一类是离线增强,一类是在线增强

  1. 离线增强 : 直接对硬盘上的数据集进行处理,并保存增强后的数据集文件。数据的数目会变成增强因子 x 原数据集的数目 ,

    2022年最新的android面试大厂必考174题(附带详细答案)(代码片段)

    ...的个人能力能不能满足公司的晋升标准?如果想跳槽大厂的话面试要求有哪些?这应该是你目前比较迷茫的一部 查看详情

    大厂面试预备篇——《两万字mysql基础总结》❤️建议收藏(代码片段)

    ❤️一条独家专栏⭐️搞技术,进大厂,聊人生📚《大厂面试突击》——面试10多家中大厂的万字总结📚《技术专家修炼》——高薪必备,企业真实场景📚《leetcode300题》——每天一道算法题,进大厂... 查看详情

    深度学习----算法岗面试题(代码片段)

    ●神经网络为啥用交叉熵。参考回答:通过神经网络解决多分类问题时,最常用的一种方式就是在最后一层设置n个输出节点,无论在浅层神经网络还是在CNN中都是如此,比如,在AlexNet中最后的输出层有1000个节点,而即便是ResNet... 查看详情

    5个必考的大厂sql面试题(代码片段)

    ...L几乎是每个数据岗的必备题目,下面分享几个常见的大厂SQL习题。(1)找出连续7天登陆,连续30天登陆的用户(小红书笔试,电信云面试),最大连续登陆天数的问题--窗口函数(2)求连... 查看详情

    蓝桥集训(附加面试题)第八天(代码片段)

    ...这里有大量专业性的算法题比如(动态规划21天,大厂特训28天等等)欢迎大家一起学习。链接:传送门目录标题导读Java蓝桥集训面试题点击直接资料领取导读在刚刚结束的每日算法&面试题,大厂特训二十... 查看详情

    100道大厂面试题总结,可以测试自己能考多少分(代码片段)

    作者:小傅哥博客:https://bugstack.cn沉淀、分享、成长,让自己和他人都能有所收获!😄一、前言:什么是面试?你的技术广度在哪?你的技术深度在哪?其实我知道面试本身就一场对你能力质... 查看详情

    100道大厂面试题总结,可以测试自己能考多少分(代码片段)

    作者:小傅哥博客:https://bugstack.cn沉淀、分享、成长,让自己和他人都能有所收获!😄一、前言:什么是面试?你的技术广度在哪?你的技术深度在哪?其实我知道面试本身就一场对你能力质... 查看详情

    100道大厂面试题总结,可以测试自己能考多少分(代码片段)

    作者:小傅哥博客:https://bugstack.cn沉淀、分享、成长,让自己和他人都能有所收获!😄一、前言:什么是面试?你的技术广度在哪?你的技术深度在哪?其实我知道面试本身就一场对你能力质... 查看详情

    深度学习面试题33:rnn的梯度更新(bptt)(代码片段)

    目录  定义网络  梯度反向传播  梯度更新  面试时的变相问法  参考资料BPTT(back-propagationthroughtime)算法是常用的训练RNN的方法,其实本质还是BP算法,只不过RNN处理时间序列数据,所以要基于时间反向传播,故叫随... 查看详情

    数据结构和算法面试常见题必考以及前端面试题(代码片段)

    1.数据结构和算法1.1反转单向链表publicclassNodepublicintvalue;publicNodenext;publicNodereverseList(Nodehead)Nodepre=null;Nodenext=null;while(head!=null)next=head.next;head.next=pre;pre=head;head=head.nextreturnpre;1.2在顺序表中插入和删除一个结点... 查看详情

    每日算法&面试题,大厂特训十四天——第二天(双指针)(代码片段)

    目录标题导读算法特训十四天面试题点击直接资料领取导读肥友们为了更好的去帮助新同学适应算法和面试题,最近我们开始进行专项突击一步一步来。上一期我们完成了动态规划二十一天现在我们进行下一项对各类算法进... 查看详情

    五万字,57道hadoop大厂高频面试题,每一字都细心打磨,强烈建议收藏!(代码片段)

    ...数据资料,结合自身的学习和工作经历,总结了大厂高频面试题,里面涵盖几乎所有我见到的大数据面试题目。《大厂高频面试题系列》目前已总结4篇文章,且在持续更新中✍。文中用最直白的语言解释了Hadoop、... 查看详情

    看完这篇文章保你面试稳操胜券——(必考题)javascript篇(代码片段)

    ...xtcolorblue欢迎各位小伙伴:欢迎各位小伙伴:✨进大厂收藏这一系列就够了,全方位搜集总结,为大家归纳出这篇面试宝典,面试途中祝你一臂之力!,共分为四个系列✨包含Vue40道经典面试题\\textcolorg... 查看详情

    ❤️五万字❤️离职后一天4面,总结了204道高频java面试题,已拿阿里offer(建议收藏)(代码片段)

    ❤️一条独家专栏⭐️搞技术,进大厂,聊人生📚《大厂面试突击》——面试10多家中大厂的万字总结📚《技术专家修炼》——高薪必备,企业真实场景📚《leetcode300题》——每天一道算法题,进大厂... 查看详情

    每日算法&面试题,大厂特训十四天——第三天(双指针)(代码片段)

    目录标题导读算法特训十四天面试题热心分享导读肥友们为了更好的去帮助新同学适应算法和面试题,最近我们开始进行专项突击一步一步来。上一期我们完成了动态规划二十一天现在我们进行下一项对各类算法进行十四天... 查看详情

    每日算法&面试题,大厂特训二十八天——第十二天(数组)(代码片段)

    目录标题导读算法特训二十八天面试题点击直接资料领取导读肥友们为了更好的去帮助新同学适应算法和面试题,最近我们开始进行专项突击一步一步来。上一期我们完成了动态规划二十一天现在我们进行下一项对各类算法... 查看详情

    深度学习-----算法岗面试题

    ●深度学习了解多少,有看过底层代码吗?caffe,tf? ●除了GMM-HMM,你了解深度学习在语音识别中的应用吗?参考回答:讲了我用的过DNN-HMM,以及与GMM-HMM的联系与区别;然后RNN+CTC,这里我只是了解,大概讲了一下CTC损失的原... 查看详情

    vue原理面试题(代码片段)

    一、大厂必考原理1.组件化和MVVM2.响应式原理3.vdom和diff算法4.模板编译5.组件渲染过程6.前端路由1.组件化基础=>(MVVM模型) 传统组件,知识静态渲染,更新依赖于操作DOM数据驱动视图-VueMVVMMVVM是Model-View-ViewMo... 查看详情