深度學習面試的一些知識

https://www.nowcoder.com/discuss/205843?type=2

1.IOU計算

求出左上角的最大值,右下角的最小值。

 

IOU代碼和NMS代碼

# -*- coding: utf-8 -*-
#
# This is the python code for calculating bbox IoU,
# By running the script, we can get the IoU score between pred / gt bboxes
#
# Author: hzhumeng01 2018-10-19
# copyright @ netease, AI group

from __future__ import print_function, absolute_import
import numpy as np

def get_IoU(pred_bbox, gt_bbox):
    """
    return iou score between pred / gt bboxes
    :param pred_bbox: predict bbox coordinate
    :param gt_bbox: ground truth bbox coordinate
    :return: iou score
    """

    # bbox should be valid, actually we should add more judgements, just ignore here...
    # assert ((abs(pred_bbox[2] - pred_bbox[0]) > 0) and
    #         (abs(pred_bbox[3] - pred_bbox[1]) > 0))
    # assert ((abs(gt_bbox[2] - gt_bbox[0]) > 0) and
    #         (abs(gt_bbox[3] - gt_bbox[1]) > 0))

    # -----0---- get coordinates of inters
    ixmin = max(pred_bbox[0], gt_bbox[0])
    iymin = max(pred_bbox[1], gt_bbox[1])
    ixmax = min(pred_bbox[2], gt_bbox[2])
    iymax = min(pred_bbox[3], gt_bbox[3])
    iw = np.maximum(ixmax - ixmin + 1., 0.)
    ih = np.maximum(iymax - iymin + 1., 0.)

    # -----1----- intersection
    inters = iw * ih

    # -----2----- union, uni = S1 + S2 - inters
    uni = ((pred_bbox[2] - pred_bbox[0] + 1.) * (pred_bbox[3] - pred_bbox[1] + 1.) +
           (gt_bbox[2] - gt_bbox[0] + 1.) * (gt_bbox[3] - gt_bbox[1] + 1.) -
           inters)

    # -----3----- iou
    overlaps = inters / uni

    return overlaps


def get_max_IoU(pred_bboxes, gt_bbox):
    """
    given 1 gt bbox, >1 pred bboxes, return max iou score for the given gt bbox and pred_bboxes
    :param pred_bbox: predict bboxes coordinates, we need to find the max iou score with gt bbox for these pred bboxes
    :param gt_bbox: ground truth bbox coordinate
    :return: max iou score
    """

    # bbox should be valid, actually we should add more judgements, just ignore here...
    # assert ((abs(gt_bbox[2] - gt_bbox[0]) > 0) and
    #         (abs(gt_bbox[3] - gt_bbox[1]) > 0))

    if pred_bboxes.shape[0] > 0:
        # -----0---- get coordinates of inters, but with multiple predict bboxes
        ixmin = np.maximum(pred_bboxes[:, 0], gt_bbox[0])
        iymin = np.maximum(pred_bboxes[:, 1], gt_bbox[1])
        ixmax = np.minimum(pred_bboxes[:, 2], gt_bbox[2])
        iymax = np.minimum(pred_bboxes[:, 3], gt_bbox[3])
        iw = np.maximum(ixmax - ixmin + 1., 0.)
        ih = np.maximum(iymax - iymin + 1., 0.)

        # -----1----- intersection
        inters = iw * ih

        # -----2----- union, uni = S1 + S2 - inters
        uni = ((gt_bbox[2] - gt_bbox[0] + 1.) * (gt_bbox[3] - gt_bbox[1] + 1.) +
               (pred_bboxes[:, 2] - pred_bboxes[:, 0] + 1.) * (pred_bboxes[:, 3] - pred_bboxes[:, 1] + 1.) -
               inters)

        # -----3----- iou, get max score and max iou index
        overlaps = inters / uni
        ovmax = np.max(overlaps)
        jmax = np.argmax(overlaps)

    return overlaps, ovmax, jmax

if __name__ == "__main__":

    # test1
    pred_bbox = np.array([50, 50, 90, 100])   # top-left: <50, 50>, bottom-down: <90, 100>, <x-axis, y-axis>
    gt_bbox = np.array([70, 80, 120, 150])
    print (get_IoU(pred_bbox, gt_bbox))
    
    # test2
    pred_bboxes = np.array([[15, 18, 47, 60],
                          [50, 50, 90, 100],
                          [70, 80, 120, 145],
                          [130, 160, 250, 280],
                          [25.6, 66.1, 113.3, 147.8]])
    gt_bbox = np.array([70, 80, 120, 150])
    print (get_max_IoU(pred_bboxes, gt_bbox))

代碼解析

若不相交得到的結果中,必有ixmax < ixmin、iymax - iymin其一成立,此時iw、ih就爲0了;

nms代碼

https://blog.csdn.net/a1103688841/article/details/89711120

import numpy as np

boxes = np.array([[100, 100, 210, 210, 0.72],
                  [250, 250, 420, 420, 0.8],
                  [220, 220, 320, 330, 0.92],
                  [100, 100, 210, 210, 0.72],
                  [230, 240, 325, 330, 0.81],
                  [220, 230, 315, 340, 0.9]])


def py_cpu_nms(dets, thresh):
    x1 = dets[:, 0]
    y1 = dets[:, 1]
    x2 = dets[:, 2]
    y2 = dets[:, 3]
    areas = (y2 - y1 + 1) * (x2 - x1 + 1)
    scores = dets[:, 4]
    keep = []
    # index = scores.argsort()[::-1]
    index = np.argsort(scores)[::-1]
    while index.size > 0:
        i = index[0]  # every time the first is the biggst, and add it directly
        keep.append(i)

        x11 = np.maximum(x1[i], x1[index[1:]])  # calculate the points of overlap
        y11 = np.maximum(y1[i], y1[index[1:]])
        x22 = np.minimum(x2[i], x2[index[1:]])
        y22 = np.minimum(y2[i], y2[index[1:]])

        w = np.maximum(0, x22 - x11 + 1)  # the weights of overlap
        h = np.maximum(0, y22 - y11 + 1)  # the height of overlap

        overlaps = w * h
        ious = overlaps / (areas[i] + areas[index[1:]] - overlaps)

        idx = np.where(ious <= thresh)[0]
        index = index[idx + 1]  # because index start from 1

    return keep

res = py_cpu_nms(boxes, 0.5)
print(res)

 

 

>>> import numpy as np
>>> index = np.array([1, 2])
>>> a = np.array([2, 3, 4, 5])
>>> c = a[index]
>>> c
array([3, 4])

np.where

 當數組是一維數組時,返回的值是一維的索引,所以只有一組索引數組

#-*-coding:utf-8-*-
import numpy as np
 
a = np.arange(8)               #array([0, 1, 2, 3, 4, 5, 6, 7])
index = np.where(a > 4)        #(array([5, 6, 7], dtype=int64),)
print(index[0])                #[5 6 7]

 

2. CNN反向傳播細節,怎麼過全聯接層、池化層、卷積層

  1. 通過鏈式法則得到每個參數的偏導,乘以LR,就是每個參數的增量,每個參數減去增量就是變後的值。
  2. max pooling: 下一層的梯度會原封不動地傳到上一層最大值所在位置的神經元,其他位置的梯度爲0;average pooling: 下一層的梯度會平均地分配到上一層的對應相連區塊的所有神經元。

 

3、優化器算法介紹

https://blog.csdn.net/pursuit_zhangyu/article/details/100067391

4. CNN多分類損失函數 softmax

https://blog.csdn.net/lvchunyang66/article/details/80076959

https://blog.csdn.net/u014380165/article/details/77284921

分類loss函數

交叉熵

以識別手寫數字爲例,0~9共十個類別。識別數字1,神經網絡的輸出結果越接近[0,1,0,0,0,0,0,0,0,0]越好。交叉上是最好的評判方法之一。交叉熵刻畫了兩個概率分佈之間的距離,它是分類問題中使用比較廣的一種損失函數。


p代表正確答案,q代表的是預測值。交叉熵值越小,兩個概率分佈越接近。

KL散度

KL散度,有時候也叫KL距離,一般被用於計算兩個分佈之間的不同。

https://www.zhihu.com/question/65288314/answer/244557337

 

softmax

softmax函數的作用,它是將Softmax將神經網絡的輸出變成了一個概率分佈,這樣子可以計算它和GT的距離。

舉個例子:假設網絡的輸出=[1,2,3],那麼經過softmax層後就會得到[0.09,0.24,0.67],這三個數字表示這個樣本屬於第1,2,3類的概率分別是0.09,0.24,0.67。

softmax loss函數

cross entropy loss函數

迴歸loss函數

 

 

5、smooth L1爲什麼更有效

https://www.zhihu.com/question/58200555/answer/621174180

6.過擬合的解決辦法

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

  • 增加原始數據集
  • 使用數據增強
  • 正則化
  • Dropout
  • 訓練次數少一點

正則化

解釋一

regularizer英文名字

向你的模型加入某些規則,加入先驗,縮小解空間,減小求出錯誤解的可能性。

解釋二

https://www.jianshu.com/p/c9bb6f89cfcc

原因1:來自知乎上一種比較直觀和簡單的理解, 模型過於複雜是因爲模型嘗試去兼顧各個測試數據點, 導致模型函數如下圖,處於一種動盪的狀態, 每個點的到時在某些很小的區間裏,函數值的變化很劇烈。這就意味着函數在某些小區間裏的導數值(絕對值)非常大,由於自變量值可大可小,所以只有係數足夠大,才能保證導數值很大。

而加入正則能抑制係數過大的問題。如下公式, 是嶺迴歸的計算公式。

如果發生過擬合, 參數θ一般是比較大的值, 加入懲罰項後, 只要控制λ的大小,當λ很大時,θ1到θn就會很小,即達到了約束數量龐大的特徵的目的。

上面的紅字可以使用代碼(9.Regression.zip/9.3.ElasticNet.py)解釋

https://github.com/zhudaoruyi/ChinaHadoop-ML-V    


 

 

7.目標檢測的指標:識別精度,識別速度,定位精度

https://www.zhihu.com/question/41540197 

詳細說一下mAP, 閾值怎麼設定

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

      mAP: mean Average Precision, 即各類別AP的平均值,每個類別的AP指的是根據recall和precision繪製一條曲線下面的面積。AP曲線包括精準率Precision: TP / (TP + FP),召回率Recall: TP / (TP + FN)。精確率是針對我們預測結果而言的,它表示的是預測爲正的樣本中有多少是對的。那麼預測爲正就有兩種可能了,一種就是把正類預測爲正類(TP),另一種就是把負類預測爲正類(FP)。而召回率是針對我們原來的樣本而言的,它表示的是樣本中的正例有多少被預測正確了。

接下來是要統計出每個類別的統計出TP,FP,FN個數就可以了。

拿單張圖片來說吧,首先遍歷圖片中ground truth對象,然後提取我們要計算的某類別的gt objects,之後讀取我們通過檢測器檢測出的這種類別的檢測框(其他類別的先不管),接着過濾掉置信度分數低於置信度閾值的框(也有的未設置信度閾值),將剩下的檢測框按置信度分數從高到低排序,最先判斷置信度分數最高的檢測框與gt bbox的iou是否大於iou閾值,若iou大於設定的iou閾值即判斷爲TP,將此gt_bbox標記爲已檢測(後續的同一個GT的多餘檢測框都視爲FP,這就是爲什麼先要按照置信度分數從高到低排序,置信度分數最高的檢測框最先去與iou閾值比較,若大於iou閾值,視爲TP,後續的同一個gt對象的檢測框都視爲FP),iou小於閾值的,直接規劃到FP中去。

 

對於一個二分問題,可將實例(case)分成正類(positive)或負類(negative)。如果進行預測,會出現四種情況,即:實例是正類並且也被預測成正類,即爲真正類TP(True positive),實例是負類被預測成正類,稱之爲假正類FP(False positive),實例是負類被預測成負類,稱之爲真負類TN(True negative),實例是正類被預測成負類,稱之爲假負類FN(false negative)。列表如下表所示,其中1代表正類,0代表負類。

                                    

 

8.ROC曲線

AUC是指曲線下面積,一般用於ROC(受試者工作特性曲線)圍成的面積。

ROC是根據TPR、FPR進行繪製的。通過閾值的改變,得到敏感度和特異度畫出ROC曲線。

(1)真正類率(True Postive Rate)TPR: TP/(TP+FN),代表分類器預測的正類中實際正實例佔所有正實例的比例。Sensitivity(敏感度)和recall一樣

(2)負正類率(False Postive Rate)FPR: FP/(FP+TN),代表分類器預測的正類中實際負實例佔所有負實例的比例。1-Specificity(特異度)

 

9.ResNet介紹

  ResNet 主要的創新在殘差網絡,其實這個網絡的提出本質上還是要解決層次比較深的時候無法訓練的問題。這種借鑑了Highway Network思想的網絡相當於旁邊專門開個通道使得輸入可以直達輸出,而優化的目標由原來的擬合輸出H(x)變成輸出和輸入的差H(x)-x,其中H(X)是某一層原始的的期望映射輸出,x是輸入。

代碼

class Res2d(nn.Module):
    def __init__(self, n_in, n_out, stride = 1):
        super(PostRes2d, self).__init__()
        self.conv1 = nn.Conv2d(n_in, n_out, kernel_size = 3, stride = stride, padding = 1)
        self.bn1 = nn.BatchNorm2d(n_out)
        self.relu = nn.ReLU(inplace = True)
        self.conv2 = nn.Conv2d(n_out, n_out, kernel_size = 3, padding = 1)
        self.bn2 = nn.BatchNorm2d(n_out)
 
        if stride != 1 or n_out != n_in:
            self.shortcut = nn.Sequential(
                nn.Conv2d(n_in, n_out, kernel_size = 1, stride = stride),
                nn.BatchNorm2d(n_out))
        else:
            self.shortcut = None
 
    def forward(self, x):
        residual = x
        if self.shortcut is not None:
            residual = self.shortcut(x)
        out = self.conv1(x)
        out = self.bn1(out)
        out = self.relu(out)
        out = self.conv2(out)
        out = self.bn2(out)
        
        out += residual
        out = self.relu(out)
        return out
​

 

10. 爲什麼會出現梯度消失和梯度爆炸

誤差\delta ^{l}大於1,那麼層數增多的時候,最終的求出的梯度更新將以指數形式增加,即發生梯度爆炸,如果此部分小於1,那麼隨着層數增多,求出的梯度更新信息將會以指數形式衰減,即發生了梯度消失

梯度消失/爆炸是什麼?(反向傳播中由於鏈式求導法則的連乘,如果乘數都比較小趨於0,最終傳遞到網絡輸入層的梯度會變得很小(梯度消失),如果乘數都很大,最終的梯度也會變得很大(梯度爆炸),其實二者都是因爲網絡太深導致權值更新不穩定,本質上是因爲梯度反向傳播中的連乘效應)

BP反向傳播

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

 

深度學習相關

普通卷的參數量如何計算?

1.卷積後尺寸計算
out_height=(in_height+2pad-filter_height)/strides[1]+1
out_width=(in_width+2pad-filter_width)/strides[2] +1

 

如果換成depthwise conv呢?

大小爲3*3,padding=0,stride=1的卷積核在經過2次計算後感受野爲多少?

減小過擬合的方法有哪些?

YOLO v3的loss函數(講錯了,當時一緊張就講成了Faster RCNN的loss函數,腦子發熱了,難受~

smooth L1函數的作用爲什麼效果更好?

 

 

11.難例挖掘和在線難例挖掘

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

online hard negative mining顧名思義:negative,即負樣本,其次是hard,說明是困難樣本,也就是說在對負樣本分類時候,loss比較大(label與prediction相差較大)的那些樣本,也可以說是容易將負樣本看成正樣本的那些樣本。

hard negative mining就是多找一些hard negative加入負樣本集,進行訓練,這樣會比easy negative組成的負樣本集效果更好。

hard negative mining思路在目標檢測中的訓練過程,簡單來說有以下三個步驟
1、目標檢測中如何根據有標籤的數據劃分正負訓練集?
用帶標籤的圖像隨機生成圖像塊,iou大於某一個閾值的圖像塊做爲正樣本,否則爲負樣本。但一般負樣本遠遠多於正樣本,爲避免訓練出來的模型會偏向預測爲負例,需要保持樣本均衡,所以初始負樣本訓練集需要選擇負樣本集的子集,一般正:負=1:3。
2、有了正負訓練集就可以訓練神經網絡了。經過訓練後,就可以用這個訓練出的模型預測其餘的負樣本了(就是沒有加入訓練集的那些負樣本)。模型在預測一張圖像塊後會給出其屬於正負的概率,在這裏設置一個閾值,預測爲正的概率大於這個閾值,就可以把這個圖像塊加入復樣本訓練集了。
3.正樣本訓練集不變,負樣本訓練集除了初始的那些,還有新加入的。拿着這個新的訓練集,就可以開始新的一輪訓練了。(這裏運用瞭解決樣本不平衡欠採樣的方法之一)
跳到第二步(這個過程是重複的)

 


12、softmax交叉熵函數求導

 

 

14、L1、L2範數,L1趨向於0,但L2不會,爲什麼?

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

https://blog.csdn.net/jinping_shi/article/details/52433975

發生過擬合的時候參數會變得非常的大,參數變大才能更加attention細節。通過限制參數不要太大就可以防止過擬合,如何讓模型更加關注參數的大小,需要在loss函數中加入\alpha \left \| w \right \|_{1}\alpha \left \| w \right \|_{2}來抑制參數過大,即L1正則項,L2正則項。

他們都是可以防止過擬合,降低模型複雜度。L1 會產生稀疏的特徵,L2 會產生更多地特徵但是都會接近於0。L1在特徵選擇時候非常有用,而L2就只是一種規則化而已。

爲什麼L1使權重稀疏,L2使權重平滑?

從梯度疊加的角度考慮:因爲目標函數是損失項和正則項的和,梯度也是兩者的和。對於正則項來說,無論L1還是L2,都是希望權重變爲0的。但是L1求導後是常量,它一般比損失項的絕對值大,因此參數更新的方向和L1正則項的方向是一致的,最後會變成0;而L2是平方,求導後是權重的固定比例, 每次減去的是一個逐漸變小的數,因此在原點附近的時候參數更新的方向不一定是最小化參數的絕對值了,那麼最小值點就不會在原點。

從解空間形狀角度考慮:假設二維情況,L2正則項約束的解空間是圓形,L1正則項約束的解空間是多邊形,最優解是約束的解空間形狀和原來目標函數等高線的交點。顯然,多邊形的解空間更容易在尖角處取得,也就是在座標軸上取得,而圓形則不容易在座標軸上與等高線相切。

L1 會產生稀疏的特徵的其他解釋

https://www.jianshu.com/p/475d2c3197d2

角度一:數學公式

這個角度從權值的更新公式來看權值的收斂結果。

首先來看看L1和L2的梯度(導數的反方向):

 

所以(不失一般性,我們假定:wi等於不爲0的某個正的浮點數,學習速率η 爲0.5):

L1的權值更新公式爲wi= wi- η * 1  = wi- 0.5 * 1,也就是說權值每次更新都固定減少一個特定的值(比如0.5),那麼經過若干次迭代之後,權值就有可能減少到0。

L2的權值更新公式爲wi= wi- η * wi= wi- 0.5 * wi,也就是說權值每次都等於上一次的1/2,那麼,雖然權值不斷變小,但是因爲每次都等於上一次的一半,所以很快會收斂到較小的值但不爲0。

L1能產生等於0的權值,即能夠剔除某些特徵在模型中的作用(特徵選擇),即產生稀疏的效果。

L2可以得迅速得到比較小的權值,但是難以收斂到0,所以產生的不是稀疏而是平滑的效果。

角度二:幾何空間

這個角度從幾何位置關係來看權值的取值情況。

直接來看下面這張圖:

 

高維我們無法想象,簡化到2維的情形,如上圖所示。其中,左邊是L1圖示,右邊是L2圖示,左邊的方形線上是L1中w1/w2取值區間,右邊得圓形線上是L2中w1/w2的取值區間,綠色的圓圈表示w1/w2取不同值時整個正則化項的值的等高線(凸函數),從等高線和w1/w2取值區間的交點可以看到,L1中兩個權值傾向於一個較大另一個爲0,L2中兩個權值傾向於均爲非零的較小數。這也就是L1稀疏,L2平滑的效果。


假設原先損失函數是C0,那麼在L2和L1正則條件下對參數求導分別是:

 

 

可以想象用梯度下降的方法,當w小於1的時候,L2正則項的懲罰效果越來越小,L1正則項懲罰效果依然很大,L1可以懲罰到0,而L2很難。

15、激活函數有哪些

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

1.Sigmoid

sigmoid函數也稱爲Logistic函數,因爲Sigmoid函數可以從Logistic迴歸(LR)中推理得到,也是LR模型指定的激活函數。具體推理參考:Datartisan:機器學習系列-廣義線性模型

sigmod函數的取值範圍在(0, 1)之間,可以將網絡的輸出映射在這一範圍,方便分析。

Sigmoid公式及導數:

 

Sigmoid及其導數曲線:

Sigmoid作爲激活函數的特點:

優點:平滑、易於求導。

缺點:

  1. 激活函數計算量大(在正向傳播和反向傳播中都包含冪運算和除法);
  2. 反向傳播求誤差梯度時,求導涉及除法;
  3. Sigmoid導數取值範圍是[0, 0.25],由於神經網絡反向傳播時的“鏈式反應”,很容易就會出現梯度消失的情況。例如對於一個10層的網絡, 根據0.25^{10}\approx 0.000000954,第10層的誤差相對第一層卷積的參數W_{1}的梯度將是一個非常小的值,這就是所謂的“梯度消失”。
  4. Sigmoid的輸出不是0均值(即zero-centered);這會導致後一層的神經元將得到上一層輸出的非0均值的信號作爲輸入,隨着網絡的加深,會改變數據的原始分佈。

2. tanh

tanh爲雙曲正切函數,其英文讀作Hyperbolic Tangent。tanh和 sigmoid 相似,都屬於飽和激活函數,區別在於輸出值範圍由 (0,1) 變爲了 (-1,1),可以把 tanh 函數看做是 sigmoid 向下平移和拉伸後的結果。

 

從公式2中,可以更加清晰看出tanh與sigmoid函數的關係(平移+拉伸)。

tanh及其導數曲線:

tanh作爲激活函數的特點:

相比Sigmoid函數,

  1. tanh的輸出範圍時(-1, 1),解決了Sigmoid函數的不是zero-centered輸出問題;
  2. 冪運算的問題仍然存在;
  3. tanh導數範圍在(0, 1)之間,相比sigmoid的(0, 0.25),梯度消失(gradient vanishing)問題會得到緩解,但仍然還會存在。

3.ReLU

Relu(Rectified Linear Unit)——修正線性單元函數:該函數形式比較簡單,

公式:relu=max(0, x)

ReLU及其導數曲線:

從上圖可知,ReLU的有效導數是常數1,解決了深層網絡中出現的梯度消失問題,也就使得深層網絡可訓練。同時ReLU又是非線性函數,所謂非線性,就是一階導數不爲常數;對ReLU求導,在輸入值分別爲正和爲負的情況下,導數是不同的,即ReLU的導數不是常數,所以ReLU是非線性的(只是不同於Sigmoid和tanh,relu的非線性不是光滑的)。

ReLU在x>0下,導數爲常數1的特點:

導數爲常數1的好處就是在“鏈式反應”中不會出現梯度消失,但梯度下降的強度就完全取決於權值的乘積,這樣就可能會出現梯度爆炸問題。解決這類問題:一是控制權值,讓它們在(0,1)範圍內;二是做梯度裁剪,控制梯度下降強度,如ReLU(x)=min(6, max(0,x))

ReLU在x<0下,輸出置爲0的特點:

描述該特徵前,需要明確深度學習的目標:深度學習是根據大批量樣本數據,從錯綜複雜的數據關係中,找到關鍵信息(關鍵特徵)。換句話說,就是把密集矩陣轉化爲稀疏矩陣,保留數據的關鍵信息,去除噪音,這樣的模型就有了魯棒性。ReLU將x<0的輸出置爲0,就是一個去噪音,稀疏矩陣的過程。而且在訓練過程中,這種稀疏性是動態調節的,網絡會自動調整稀疏比例,保證矩陣有最優的有效特徵。

但是ReLU 強制將x<0部分的輸出置爲0(置爲0就是屏蔽該特徵),可能會導致模型無法學習到有效特徵,所以如果學習率設置的太大,就可能會導致網絡的大部分神經元處於‘dead’狀態,所以使用ReLU的網絡,學習率不能設置太大。

ReLU作爲激活函數的特點:

  • 相比Sigmoid和tanh,ReLU摒棄了複雜的計算,提高了運算速度。
  • 解決了梯度消失問題,收斂速度快於Sigmoid和tanh函數,但要防範ReLU的梯度爆炸
  • 容易得到更好的模型,但也要防止訓練中出現模型‘Dead’情況。

4. Leaky ReLU, PReLU(Parametric Relu), RReLU(Random ReLU)

 

ReLU及其變體圖像:

 

16、數據不均衡怎麼處理*-

1.通過調整樣本權重來平衡模型在不同樣本上的表現

2.採用代價敏感算法以提升模型在少數樣本上的表現

3.通過採樣技術平衡樣本分佈

 

18、感受野

https://www.jianshu.com/p/9997c6f5c01e

在卷積神經網絡中,感受野(Receptive Field)的定義是卷積神經網絡每一層輸出的特徵圖(feature map)上每個像素點在原始圖像上映射的區域大小,這裏的原始圖像是指網絡的輸入圖像,是經過預處理(如resize,warp,crop)後的圖像。

神經元之所以無法對原始圖像的所有信息進行感知,是因爲在卷積神經網絡中普遍使用卷積層和pooling層,在層與層之間均爲局部連接。

神經元感受野的值越大表示其能接觸到的原始圖像範圍就越大,也意味着它可能蘊含更爲全局,語義層次更高的特徵;相反,值越小則表示其所包含的特徵越趨向局部和細節。因此感受野的值可以用來大致判斷每一層的抽象層次.

 

 

19、梯度法和牛頓法的區別?

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

 

20、目標檢測的數據增強方法

1. 隨機裁剪 (對標記的Boxes進行處理)

2. 隨機變換亮度

3. 隨機變換通道

4. 隨機變換對比度

5. 隨機變換飽和度

 

21、爲什麼需要onehot編碼?

首先onehot應用在分類問題對label的編碼中,它的特點是使得各個類別之間距離相等。如果不使用onehot而是直接使用0, 1,2這樣的數值來代替類別,那麼不同類之間的距離就不同了,那麼這個問題就 變成了迴歸的問題。另外因爲one-hot中一個維度對應一個特徵的關係,特徵選擇後可以直接降低one-hot編碼的維度。

但是需要注意的是,有些分類問題中不同類別之間的距離是不同的,這時直接使用onehot是不妥的,可以在計算損失時按照不同距離之間的比例關係,給不同類別之間賦予不同的權重。

 

22、BN,LN,IN,GN,WN,WS

Batch Normalization

  • BN有效的原因:首先是歸一化使得模型每一層的輸出值變得穩定,易於訓練;其次在歸一化過程中使用的均值和標準差是在mini-batch上計算的,它們相對整個數據集的均值標準差,具有一定的噪聲,這就使得BN有輕微的正則化效果。
  • BN中 \gamma\beta的作用:因爲我們不知道每一層做歸一化是不是一定會更好,也不知需要歸一化到什麼程度,所以設置這兩個參數讓模型自己去學到合適的歸一化。
  • 需要注意的是,在batch_size很小時,BN的效果會變得很差。因爲均值和標準差的噪聲太大了。
  • 訓練時和測試時的不同點:測試時用的均值和方差是全部訓練數據的均值和方差。

BN、LN、IN、GN、WN、WS是如何歸一化的?

  • BN (Batch Normalization):對其求均值和方差時,將在 N、H、W上操作,而保留通道 C 的維度。具體來說,就是把第1個樣本的第1個通道,加上第2個樣本第1個通道 ...... 加上第 N 個樣本第1個通道,求平均,得到通道 1 的均值(注意是除以 N×H×W 而不是單純除以 N,最後得到的是一個代表這個 batch 第1個通道平均值的數字,而不是一個 H×W 的矩陣)。
  • LN (Layer Normalization): 對每個樣本的 C、H、W 維度上的數據求均值和標準差,保留 N 維度。適合訓練數據長度不同的 RNN 模型。
  • IN (Instance Normalization):對每個樣本的 H、W 維度的數據求均值和標準差,保留 N 、C 維度,也就是說,它只在 channel 內部求均值和標準差。在GAN中應用較多,因爲生成器生成的某張圖和其他圖是無關的,因此只需要使用自己的統計量進行歸一化。但是用GAN做圖像修補的時候IN可能效果不好,因爲待修補的圖片自身可能有大量的全黑或全白等異常像素,自己的統計量受異常值影響大。另外,圖像風格遷移時用目標風格圖片對應 channel 的均值和標準差“去歸一化”,以期獲得目標圖片的風格。
  • GN (Group Normalization) :計算均值和標準差時,把每一個樣本 feature map 的 channel 分成 G 組,每組將有 C/G 個 channel,然後將這些 channel 中的元素求均值和標準差。各組 channel 用其對應的歸一化參數獨立地歸一化。多用於檢測分割等佔用顯存較大的任務。
  • WN (Weight Normalization):思路是對每個神經元的weight vector進行權重g與方向v的分解,在BP過程中分別對g與v進行更新從而加速了收斂的速度。由於這個操作是定義在神經元層面,所以WN相對於BN也具有更大的適用範圍。
  • WS(Weight Standardization):對權重進行歸一化。

代碼:

# BN
import numpy as np
def batch_norm(x, gamma, beta):
    # x_shape:[N, C, H, W]
    results = 0.
    eps = 1e-5

    x_mean = np.mean(x, axis=(0, 2, 3), keepdims=True)
    x_var = np.var(x, axis=(0, 2, 3), keepdims=True)
    x_normalized = (x - x_mean) / np.sqrt(x_var + eps)
    results = gamma * x_normalized + beta
    return results

# GN 
import numpy as np
def group_norm(x, gamma, beta, G=16):
    # x_shape:[N, C, H, W]
    results = 0.
    eps = 1e-5
    x = np.reshape(x, (x.shape[0], G, x.shape[1]//G, x.shape[2], x.shape[3]))

    x_mean = np.mean(x, axis=(2, 3, 4), keepdims=True)
    x_var = np.var(x, axis=(2, 3, 4), keepdims=True)
    x_normalized = (x - x_mean) / np.sqrt(x_var + eps)
    results = gamma * x_normalized + beta
    return results

 

 

 

 

5.防止梯度消失的方法

  • 預訓練加微調

  • 梯度剪切、權重正則(針對梯度爆炸)

  • 使用不同的激活函數

  • 使用batchnorm

  • 使用殘差結構

  • 使用LSTM網絡

 

 

23. 檢測任務中可以提高點的方法

data-augment方法

使用FPN

換loss函數,使用focal loss函數

圖像金字塔,作爲輸入

 

24. 目標檢測——深度學習下的小目標檢測(檢測難的原因和Tricks)

https://www.cnblogs.com/E-Dreamer-Blogs/p/11442927.html

(1)小目標在原圖中尺寸比較小,通用目標檢測模型中,一般的基礎骨幹神經網絡(VGG系列和Resnet系列)都有幾次下采樣處理,導致小目標在特徵圖的尺寸基本上只有個位數的像素大小,導致設計的目標檢測分類器對小目標的分類效果差。

tricks

(1) data-augmentation.簡單粗暴,比如將圖像放大,利用 image pyramid多尺度檢測,最後將檢測結果融合.缺點是操作複雜,計算量大,實際情況中不實用;

(2) 特徵融合方法:FPN這些,多尺度feature map預測,feature stride可以從更小的開始;

 (3)設置更小更稠密的anchor,設計anchor match strategy等,參考S3FD;

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

2. 針對同一張圖片裏面包含小目標數量少的問題,在圖片內用分割的Mask摳出小目標圖片再使用複製粘貼的方法(當然,也加上了一些旋轉和縮放,另外要注意不要遮擋到別的目標)。

25、空洞卷積

https://www.jianshu.com/p/f743bd9041b3

Dilated/Atrous Convolution(中文叫做空洞卷積或者膨脹卷積) 或者是 Convolution with holes 從字面上就很好理解,是在標準的 convolution map 裏注入空洞,以此來增加 reception field。相比原來的正常convolution,dilated convolution 多了一個 hyper-parameter 稱之爲 dilation rate 指的是kernel的間隔數量(e.g. 正常的 convolution 是 dilatation rate 1)。

 

 

 

Deep CNN 對於其他任務還有一些致命性的缺陷。較爲著名的是 up-sampling 和 pooling layer 的設計。
主要問題有:

  • Up-sampling / pooling layer (e.g. bilinear interpolation) is deterministic. (參數不可學習)
  • 內部數據結構丟失;空間層級化信息丟失。
  • 小物體信息無法重建 (假設有四個pooling layer 則 任何小於 2^4 = 16 pixel 的物體信息將理論上無法重建。)
    在這樣問題的存在下,語義分割問題一直處在瓶頸期無法再明顯提高精度, 而 dilated convolution 的設計就良好的避免了這些問題。


26、特徵選擇

 



27. 爲什麼將數據歸一化

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

1)歸一化後加快了梯度下降求最優解的速度

藍色的圈圈圖代表的是兩個特徵的等高線。其中左圖兩個特徵X1和X2的區間相差非常大,X1區間是[0,2000],X2區間是[1,5],其所形成的等高線非常尖。當使用梯度下降法尋求最優解時,很有可能走“之字型”路線(垂直等高線走),從而導致需要迭代很多次才能收斂;

而右圖對兩個原始特徵進行了歸一化,其對應的等高線顯得很圓,在梯度下降進行求解時能較快的收斂。

因此如果機器學習模型使用梯度下降法求最優解時,歸一化往往非常有必要,否則很難收斂甚至不能收斂。

28. DNN和CNN的區別

CNN是局部感受野和參數共享,

  • kernel通過在feature map上移動得到局部信息,隨着不斷的下采樣下去,感受野不斷變大,起初可能只是得到了鼻子、耳朵的信息,後面得到的就是人臉的信息了。
  • 同一個卷積核在feature map內參數是共享的,圖像通過卷積操作後仍然保留原先的位置關係。對於一張1000*1000的像素圖片來說,全連接模型的隱層節點都有10w個輸入,也就有對應的10w個權重參數。若使用9*9的卷積核進行卷積操作的話,每個節點的輸入是81,對應100個權值,數量級大大減少

 

29. pytorch代碼

#-*-coding:utf-8-*-
import torch
import torch.nn as nn
import torch.optim as optim


class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        #layer1
        self.conv1 = nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, padding=1)
        self.bn1 = nn.BatchNorm2d(32)
        self.relu1 = nn.ReLU()
        self.maxpool1 = nn.MaxPool2d(2)

        #layer2
        self.conv2 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, padding=1)
        self.bn2 = nn.BatchNorm2d(64)
        self.relu2 = nn.ReLU()
        self.maxpool2 = nn.MaxPool2d(2)


        #layer3
        self.conv3 = nn.Conv2d(in_channels=64, out_channels=32, kernel_size=3, padding=1)
        self.bn3 = nn.BatchNorm2d(32)
        self.relu3 = nn.ReLU()
        self.maxpool3 = nn.MaxPool2d(2)

        #layer4
        self.layer4 = nn.Sequential(
            nn.Conv2d(32, 32, 3),
            nn.BatchNorm2d(32),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )

        #fc
        self.fc1 = nn.Linear(30752, 1024)
        self.fc2 = nn.Linear(1024, 2)
        self.sigmoid = nn.Sigmoid()


    def forward(self, input):
        in_size = input.size(0)
        # layer1
        out = self.conv1(input)
        out = self.bn1(out)
        out = self.relu1(out)
        out = self.maxpool1(out)

        # layer2
        out = self.conv2(out)
        out = self.bn2(out)
        out = self.relu2(out)
        out = self.maxpool2(out)

        # layer3
        out = self.conv3(out)
        out = self.bn3(out)
        out = self.relu3(out)
        out = self.maxpool3(out)

        # layer4
        out = self.layer4(out)

        # 展開
        out = out.view(in_size, -1)

        out = self.fc1(out)
        out = self.fc2(out)
        out = self.sigmoid(out)
        return out


model = Net()
model = nn.DataParallel(model, device_ids=[0])

optimizer = optim.Adam(model.parameters(), lr=1e-2)

input = torch.ones(1, 3, 512, 512)
out = model(input)
print(out.shape)
# 數據預處理
transform = transforms.Compose([
    transforms.Resize(size=(150, 150)),
    transforms.ToTensor(),
    transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
])
 
 
 
class MyDataset(Dataset):
 
 
    def __init__(self, root_dir, transform=None):
 
        # os.listdir函數讀取路徑下所以文件的文件名,並組成一個列表並返回
 
        self.file = os.listdir(root_dir)
 
        self.root_dir = root_dir
 
        self.transform = transform
 
    def __len__(self):
        return len(self.file)  # 返回這給列表的大小
 
    def __getitem__(self, index):
        # 將傳入路徑和文件名組成一個新的地址,這個數據就是單個數據的具體地址,方便之後以地址讀取該數據
        img_name = os.path.join(self.root_dir, self.file[index])
        # 從文件名中獲取標籤(我的數據標籤在文件名中,比如一張狗的圖片名:cat.4.jpg,4是序號,cat是
        # 標籤)
        if img_name[13:16] == 'dog':
            label = 0
        else:
            label = 1
        # 根據上面獲得的具體地址,讀取這張圖片
        image = Image.open(img_name)
 
        # 對圖片進行處理
        image = self.transform(image)
        # print(image.shape)
 
        # numpy的三個維度順序爲:H * W * C
        # 而torch的張量維度順序:C * H * W ,所以模型要處理它必須轉換成torch的形式
 
        # 返回數據和標籤
        return image, label
 
dataset_train = MyDataset(root_dir='kaggle/train/', transform=transform)
dataset_test = MyDataset(root_dir='kaggle/test1/', transform=transform)
 
# 導入數據
train_loader = torch.utils.data.DataLoader(dataset_train, batch_size=BATCH_SIZE, shuffle=True)
# test_loader = torch.utils.data.DataLoader(dataset_test, batch_size=BATCH_SIZE, shuffle=True)
 
 
# 定義網絡
class ConvNet(nn.Module):
    def __init__(self):
        super(ConvNet, self).__init__()
        self.conv1 = nn.Conv2d(3, 32, 3)
        self.max_pool1 = nn.MaxPool2d(2)
        self.conv2 = nn.Conv2d(32, 64, 3)
        self.max_pool2 = nn.MaxPool2d(2)
        self.conv3 = nn.Conv2d(64, 128, 3)
        self.max_pool3 = nn.MaxPool2d(2)
        self.conv4 = nn.Conv2d(128, 128, 3)
        self.max_pool4 = nn.MaxPool2d(2)
        self.fc1 = nn.Linear(6272, 512)
        self.fc2 = nn.Linear(512, 1)
 
    def forward(self, x):
        in_size = x.size(0)
        x = self.conv1(x)
        x = F.relu(x)
        x = self.max_pool1(x)
        x = self.conv2(x)
        x = F.relu(x)
        x = self.max_pool2(x)
        x = self.conv3(x)
        x = F.relu(x)
        x = self.max_pool3(x)
        x = self.conv4(x)
        x = F.relu(x)
        x = self.max_pool4(x)
        # 展開
        x = x.view(in_size, -1)
        x = self.fc1(x)
        x = F.relu(x)
        x = self.fc2(x)
        x = torch.sigmoid(x)
        return x
 
 
# 實例化模型並且移動到GPU
model = ConvNet().to(DEVICE)
# 選擇簡單暴力的Adam優化器,學習率調低
optimizer = optim.Adam(model.parameters(), lr=1e-4)
 
 
# 定義訓練過程
def train(model, device, train_loader, optimizer, epoch):
    model.train()
    for batch_idx, (data, target) in enumerate(train_loader):
        # print(data.shape)
        # print(target.shape)
        # print(target)
 
        data, target = data.to(device), target.to(device).float().reshape(50, 1)
        optimizer.zero_grad()
        output = model(data)
        loss = F.binary_cross_entropy(output, target)
        loss.backward()
        optimizer.step()
        if (batch_idx + 1) % 10 == 0:
            print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                epoch, (batch_idx + 1) * len(data), len(train_loader.dataset),
                       100. * (batch_idx + 1) / len(train_loader), loss.item()))

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章