A-深度學習面試題

嵌入式視覺發表於2022-11-22

目錄

一,濾波器與卷積核

在只有一個通道的情況下,“卷積核”(“kernel”)就相當於濾波器(“filter”),這兩個概念是可以互換的。一個 “Kernel” 更傾向於是 2D 的權重矩陣。而 “filter” 則是指多個 kernel 堆疊的 3D 結構。如果是一個 2Dfilter,那麼兩者就是一樣的。但是一個3D filter,在大多數深度學習的卷積中,它是包含 kernel 的。每個卷積核都是獨一無二的,主要在於強調輸入通道的不同方面

二,卷積層和池化輸出大小計算

不管是 TensorFlowKerasCaffe 還是 Pytorch,其卷積層和池化層的引數預設值可能有所不同,但是最終的卷積輸出大小計算公式是一樣的。

2.1,CNN 中術語解釋

卷積層主要引數有下面這麼幾個:

  • 卷積核 Kernal 大小(在 Tensorflow/keras 框架中也稱為filter);
  • 填充 Padding
  • 滑動步長 Stride
  • 輸出通道數 Channels

2.2,卷積輸出大小計算(簡化型)

1,在 Pytorch 框架中,圖片(feature map)經卷積 Conv2D輸出大小計算公式如下:\(\left \lfloor N = \frac{W-F+2P}{S}+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,這兩種情況可直接得出卷積前後特徵圖尺寸不變。

注意不同的深度學習框架,卷積/池化函式的輸出 shape 計算會有和上述公式有所不同,我給出的公式是簡化版,適合面試題計算,實際框架的計算比這複雜,因為引數更多。

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),在記憶體中的儲存如下圖:

opencv矩陣儲存格式

四,Pytorch 、Keras 的池化層函式理解

注意:對於 Pytorch、Keras 的卷積層和池化層函式,其 padding 引數值都預設為不填充畫素,預設值為 0valid

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 \frac{W_{in} + 2 * \text{padding}[0] - \text{dilation}[0] \times (\text{kernel\_size}[0] - 1) - 1}{\text{stride[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,計算輸出訊號大小的時候,公式會使用向上取整。

Pytorch 中池化層預設ceil mode = false,而 Caffe 只實現了 ceil mode= 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 \frac{W_{in} + 2 \times \text{padding}[0] - \text{dilation}[0] \times (\text{kernel\_size}[0] - 1) - 1}{\text{stride}[0]} + 1\right\rfloor \]

Pytorch/Caffe 框架輸入輸出資料的尺寸都是 ((N, C, H, W)),常規卷積的卷積核權重 shape 都為(C_out, C_in, kernel_height, kernel_width),常規卷積是這樣,但是分組卷積的卷積核權重 shape 為(C_out, C_in/g, kernel_height, kernel_width)和 DW 卷積的卷積核 權重shape 為(C_in, 1, kernel_height, kernel_width)。

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} = y_{i}^{'} = \frac{e^{yi}}{\sum_{j=1}^{n}e^{yj}} \]

七,交叉熵損失函式

交叉熵刻畫了兩個機率分佈之間的距離,它是分類問題中使用比較廣泛的一種損失函式,交叉熵一般會與 softmax 迴歸一起使用,公式如下:

\[L = -\sum_{c=1}^{M}y_{c}log(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,感受野大小計算

計算感受野時,我們需要知道:

參考 感受野(receptive file)計算

  • 第一層卷積層的輸出特徵影像素的感受野的大小等於濾波器的大小;
  • 深層卷積層的感受野大小和它之前所有層的濾波器大小和步長有關係;
  • 計算感受野大小時,忽略了影像邊緣的影響。

感受野的計算方式有兩種:自底向上和自頂向下(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\) 各個元素平方和的 \(\frac{1}{2}\) 次方,\(L2\) 範數又稱 Euclidean 範數或 Frobenius 範數
  • \(L_{p}\) 範數: 為向量 \(x\) 各個元素絕對值 \(p\) 次方和的 \(1/p\) 次方。\(L_{p}\) 範數定義為: \(||x||_{p} = (\sum_{i=1}^{n} |x_i|^{p})^\frac{1}{p}\)

在支援向量機學習過程中,\(L1\) 範數實際是一種對於成本函式求解最優的過程,因此,\(L1\) 範數正則化透過向成本函式中新增 \(L1\) 範數,使得學習得到的結果滿足稀疏化,從而方便人類提取特徵。

\(L1\) 範數可以使權值引數稀疏,方便特徵提取。 \(L2\) 範數可以防止過擬合,提升模型的泛化能力。

參考資料學習

  1. 淺談L0,L1,L2範數及其應用
  2. 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 演算法中的鏈式求導逐層傳遞逐層增大,最後趨於無窮,導致某些層無法收斂;

在反向傳播過程中需要對啟用函式進行求導,如果導數大於 1,那麼隨著網路層數的增加,梯度更新將會朝著指數爆炸的方式增加這就是梯度爆炸。同樣如果導數小於 1,那麼隨著網路層數的增加梯度更新資訊會朝著指數衰減的方式減少這就是梯度消失。

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

出現梯度消失和梯度爆炸的問題主要是因為引數初始化不當以及啟用函式選擇不當造成的。其根本原因在於反向傳播訓練法則,屬於先天不足。當訓練較多層數的模型時,一般會出現梯度消失問題(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個3*3卷積層

(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)=\frac{1}{1+exp(-x)}\)

ReLU啟用函式公式如下:

\[f(x) = max(x, 0) = \begin{cases} x, & \text{if $x$ $\geq$ 0} \\ 0, & \text{if $x$ < 0} \end{cases}\]

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,記得關掉。

dropou直觀展示

27.1,dropout具體工作流程

以 標準神經網路為例,正常的流程是:我們首先把輸入資料x透過網路前向傳播,然後把誤差反向傳播一決定如何更新引數讓網路進行學習。使用dropout之後,過程變成如下:

1,首先隨機(臨時)刪掉網路中一半的隱藏神經元,輸入輸出神經元保持不變(圖3中虛線為部分臨時被刪除的神經元);

2,然後把輸入x透過修改後的網路進行前向傳播計算,然後把得到的損失結果透過修改的網路反向傳播。一小批訓練樣本執行完這個過程後,在沒有被刪除的神經元上按照隨機梯度下降法更新對應的引數(w,b);

3,然後重複這一過程:

  • 恢復被刪掉的神經元(此時被刪除的神經元保持原樣沒有更新w引數,而沒有被刪除的神經元已經有所更新);
  • 從隱藏層神經元中隨機選擇一個一半大小的子集臨時刪除掉(同時備份被刪除神經元的引數);
  • 對一小批訓練樣本,先前向傳播然後反向傳播損失並根據隨機梯度下降法更新引數(w,b) (沒有被刪除的那一部分引數得到更新,刪除的神經元引數保持被刪除前的結果)。

27.2,dropout在神經網路中的應用

(1). 在訓練模型階段

不可避免的,在訓練網路中的每個單元都要新增一道機率流程,標準網路和帶有dropout網路的比較圖如下所示:

dropout在訓練階段

(2). 在測試模型階段

預測模型的時候,輸入是當前輸入,每個神經單元的權重引數要乘以機率p。

dropout在測試模型時

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特徵

參考資料

HOG特徵檢測-簡述

二十九,啟用函式

29.1,啟用函式的作用

  • 啟用函式實現去線性化。啟用函式的引入是為了增加整個網路的表達能力(引入非線性因素),否則若干線形層的堆疊仍然只能起到線性對映的作用,無法形成複雜的函式。如果將每一個神經元(也就是神經網路的節點)的輸出透過一個非線性函式,那麼整個神經網路的模型也就不再是線性的了,這個非線性函式就是啟用函式。
  • 啟用函式可以把當前特徵空間透過一定的線性對映轉換到另一個空間,讓資料能夠更好的被分類。
  • 啟用函式對模型學習、理解非常複雜和非線性的函式具有重要作用。

29.2,常見的啟用函式

啟用函式也稱非線性對映函式,常見的啟用函式有:ReLU 函式、sigmoid 函式、tanh 函式等,其計算公式如下:

  • ReLU函式:\(f(x)=max(x,0)\)
  • sigmoid函式:\(f(x)=\frac{1}{1+e^{-x}}\)
  • tanh函式:\(f(x)=\frac{1+e^{-2x}}{1+e^{-2x}}=\frac{2}{1+e^{-2x}}-1 = 2sigmoid(2x)-1\)

29.3,啟用函式理解及函式梯度圖

  1. Sigmoid 啟用函式,可用作分類任務的輸出層。可以看出經過sigmoid啟用函式後,模型輸出的值域被壓縮到 0到1 區間(這和機率的取值範圍一致),這正是分類任務中sigmoid很受歡迎的原因。

sigmoid啟用函式及梯度圖

  1. tanh(x) 型函式是在 sigmoid 型函式基礎上為解決均值問題提出的啟用函式。tanh 的形狀和 sigmoid 類似,只不過tanh將“擠壓”輸入至區間(-1, 1)。至於梯度,它有一個大得多的峰值1.0(同樣位於z = 0處),但它下降得更快,當|x|的值到達 3 時就已經接近零了。這是所謂梯度消失(vanishing gradients)問題背後的原因,會導致網路的訓練進展變慢。

tanh函式及梯度圖

  1. ReLU 處理了sigmoid、tanh中常見的梯度消失問題,同時也是計算梯度最快的激勵函式。但是,ReLU函式也有自身缺陷,即在 x < 0 時,梯度便為 y。換句話說,對於小於 y 的這部分卷積結果響應,它們一旦變為負值將再無法影響網路訓練——這種現象被稱作“死區"。

Relu函式及梯度圖

三十,卷積層和池化層有什麼區別

  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 原資料集的數目 ,這種方法常常用於資料集很小的時候
  2. 線上增強 : 這種增強的方法用於,獲得 batch 資料之後,然後對這個batch的資料進行增強,如旋轉、平移、翻折等相應的變化,由於有些資料集不能接受線性級別的增長,這種方法長用於大的資料集,很多機器學習框架已經支援了這種資料增強方式,並且可以使用GPU最佳化計算。
    `

Reference

深度學習中的資料增強

三十四,ROI Pooling替換為ROI Align的效果,及各自原理

faster rcnnroi pooling 替換為 roi align 效果有所提升。

ROI Pooling原理

RPN 生成的 ROI 區域大小是對應與輸入影像大小(每個roi區域大小各不相同),為了能夠共享權重,所以需要將這些 ROI 對映回特徵圖上,並固定大小。ROI Pooling操作過程如下圖:

roi pooling

ROI Pooling 具體操作如下:

  1. Conv layers 使用的是 VGG16feat_stride=32(即表示,經過網路層後圖片縮小為原圖的 1/32),原圖 \(800\times 800\),最後一層特徵圖 feature map 大小: \(25\times 25\)
  2. 假定原圖中有一 region proposal,大小為 \(665\times 665\),這樣,對映到特徵圖中的大小:\(665/32=20.78\),即大小為 \(20.78\times 20.78\),原始碼中,在計算的時候會進行取整操作,於是,進行所謂的第一次量化,即對映的特徵圖大小為20*20;
  3. 假定 pooled_w=7、pooled_h=7,即 pooling 後固定成 \(7\times 7\) 大小的特徵圖,所以,將上面在 feature map上對映的 \(20\times 20\)region proposal 劃分成 49個同等大小的小區域,每個小區域的大小 \(20/7=2.86\),,即 \(2.86\times 2.86\),此時,進行第二次量化,故小區域大小變成 \(2\times 2\)
  4. 每個 \(2\times 2\) 的小區域裡,取出其中最大的畫素值,作為這一個區域的‘代表’,這樣,49 個小區域就輸出 49 個畫素值,組成 \(7\times 7\) 大小的 feature map

所以,透過上面可以看出,經過兩次量化,即將浮點數取整,原本在特徵圖上對映的 \(20\times 20\) 大小的 region proposal,偏差成大小為 \(7\times 7\) 的,這樣的畫素偏差勢必會對後層的迴歸定位產生影響。所以,產生了後面的替代方案: RoiAlign

ROI Align原理

ROI Align 的工作原理如下圖。

roi align

ROI Align 是在 Mask RCNN 中使用以便使生成的候選框region proposal 對映產生固定大小的 feature map 時提出的,根據上圖,有著類似的對映:

  1. Conv layers 使用的是 VGG16feat_stride=32 (即表示,經過網路層後圖片縮小為原圖的1/32),原圖 \(800\times 800\),最後一層特徵圖feature map大小: \(25*\times 25\);
  2. 假定原圖中有一region proposal,大小為 \(665*\times 665\),這樣,對映到特徵圖中的大小:\(665/32=20.78\),即大小為 \(20.78\times 20.78\),此時,沒有像 RoiPooling 那樣就行取整操作,保留浮點數;
  3. 假定 pooled_w=7,pooled_h=7,即 pooling 後固定成 \(7\times 7\) 大小的特徵圖,所以,將在 feature map 上對映的 \(20.78\times 20.78\)region proposal 劃分成 49 個同等大小的小區域,每個小區域的大小 \(20.78/7=2.97\),即 \(2.97\times 2.97\);
  4. 假定取樣點數為 4,即表示,對於每個 \(2.97\times 2.97\) 的小區域,平分四份,每一份取其中心點位置,而中心點位置的畫素,採用雙線性插值法進行計算,這樣,就會得到四個點的畫素值,如下圖:

roi align雙線性插值

上圖中,四個紅色叉叉‘×’的畫素值是透過雙線性插值演算法計算得到的。

最後,取四個畫素值中最大值作為這個小區域(即:\(2.97\times 2.97\) 大小的區域)的畫素值,如此類推,同樣是 49 個小區域得到 49 個畫素值,組成 \(7\times 7\) 大小的 feature map

RoiPooling 和 RoiAlign 總結

總結:知道了 RoiPoolingRoiAlign 實現原理,在以後的專案中可以根據實際情況進行方案的選擇;對於檢測圖片中大目標物體時,兩種方案的差別不大,而如果是圖片中有較多小目標物體需要檢測,則優先選擇 RoiAlign,更精準些。

Reference

RoIPooling、RoIAlign筆記

三十五,CNN的反向傳播演算法推導

三十六,Focal Loss 公式

為了解決正負樣本不平衡的問題,我們通常會在交叉熵損失的前面加上一個引數 \(\alpha\) ,即:

\[CE = \left\{\begin{matrix} -\alpha log(p), & if \quad y=1\\ -(1-\alpha)log(1-p), & if\quad y=0 \end{matrix}\right. \]

儘管 \(\alpha\) 平衡了正負樣本,但對難易樣本的不平衡沒有任何幫助。因此,Focal Loss 被提出來了,即:

\[CE = \left\{\begin{matrix} -\alpha (1-p)^\gamma log(p), & if \quad y=1\\ -(1-\alpha) p^\gamma log(1-p), & if\quad y=0 \end{matrix}\right. \]

實驗表明 \(\gamma\)2, \(\alpha\)0.25 的時候效果最佳。

  • Focal loss 成功地解決了在單階段目標檢測時,正負樣本區域極不平衡而目標檢測 loss 易被大批次負樣本所左右的問題。
  • RetinaNet 達到更高的精度的原因不是網路結構的創新,而是損失函式的創新!

三十七,快速回答

37.1,為什麼 Faster RCNN、Mask RCNN 需要使用 ROI Pooling、ROI Align?

為了使得最後面的兩個全連線層能夠共享 conv layers(VGG/ResNet) 權重。在所有的 RoIs 都被 pooling 成(512×7×7)的feature map後,將它 reshape 成一個一維的向量,就可以利用 VGG16 的預訓練的權重來初始化前兩層全連線。

37.2,softmax公式

\[softmax(y)_{i} = \frac{e^{y_{i}}}{\sum_{j=1}^{n}e^{y_j}} \]

softmax公式

37.3,上取樣方法總結

上取樣大致被總結成了三個類別:

  1. 基於線性插值的上取樣:最近鄰演算法(nearest)、雙線性插值演算法(bilinear)、雙三次插值演算法(bicubic)等,這是傳統影像處理方法。
  2. 基於深度學習的上取樣(轉置卷積,也叫反摺積 Conv2dTranspose2d等)
  3. Unpooling 的方法(簡單的補零或者擴充操作)

計算效果:最近鄰插值演算法 < 雙線性插值 < 雙三次插值。計算速度:最近鄰插值演算法 > 雙線性插值 > 雙三次插值

37.4,移動端深度學習框架知道哪些,用過哪些?

知名的有TensorFlow Lite、小米MACE、騰訊的 ncnn 等,目前都沒有用過。

37.5,如何提升網路的泛化能力

和防止模型過擬合的方法類似,另外還有模型融合方法。

37.6,BN演算法,為什麼要在後面加伽馬和貝塔,不加可以嗎?

最後的 scale and shift 操作則是為了讓因訓練所需而“刻意”加入的BN能夠有可能還原最初的輸入。不加也可以。

37.7,驗證集和測試集的作用

  • 驗證集是在訓練過程中用於檢驗模型的訓練情況,從而確定合適的超引數
  • 測試集是在模型訓練結束之後,測試模型的泛化能力

三十八,交叉驗證的理解和作用

參考知乎文章 N折交叉驗證的作用(如何使用交叉驗證),我的理解之後補充。

三十九,介紹一下NMS和IOU的原理

NMS全稱是非極大值抑制,顧名思義就是抑制不是極大值的元素。在目標檢測任務中,通常在解析模型輸出的預測框時,預測目標框會非常的多,其中有很多重複的框定位到了同一個目標,NMS 的作用就是用來除去這些重複框,從而獲得真正的目標框。而 NMS 的過程則用到了 IOU,IOU 是一種用於衡量真實和預測之間相關度的標準,相關度越高,該值就越高。IOU 的計算是兩個區域重疊的部分除以兩個區域的集合部分,簡單的來說就是交集除以並集。

在 NMS 中,首先對預測框的置信度進行排序,依次取置信度最大的預測框與後面的框進行 IOU 比較,當 IOU 大於某個閾值時,可以認為兩個預測框框到了同一個目標,而置信度較低的那個將會被剔除,依次進行比較,最終得到所有的預測框。

Reference

  1. 《Batch Normalization Accelerating Deep Network Training by Reducing Internal Covariate Shift》閱讀筆記與實現
  2. 詳解機器學習中的梯度消失、爆炸原因及其解決方法
  3. N折交叉驗證的作用(如何使用交叉驗證)
  4. 5分鐘理解Focal Loss與GHM——解決樣本不平衡利器
  5. 深度學習CV崗位面試問題總結(目標檢測篇)

相關文章