1. 程式人生 > >關於SSD訓練時預設框輸出層輸出通道num_output的計算,

關於SSD訓練時預設框輸出層輸出通道num_output的計算,

關於SSD訓練時預設框輸出層輸出通道num_output的計算

2018年02月03日 21:00:40 閱讀數:2155

申明,本博文是為解決以下兩個問題而撰寫。

Check failed: num_priors_ * num_loc_classes_ * 4 == bottom[0]->channels() (264348 vs. 88116) Number of priors must match number of location predictions.

Check failed: num_priors_ * num_classes_ == bottom[1]->channels() (132174 vs. 99406) Number of priors must match number of confidence predictions.

我們針對小目標檢測時受到此方面的困擾,在閱讀原始碼後解決。特寫下此部落格,以供參考。具體原始碼,請仔細閱讀:src/caffe/layers/multibox_loss_layer.cpp

輸出通道主要涉及預設框產生層的置信輸出mbox_conf和位置輸出mbox_conf。對應prototxt檔案中的應該是以下部分,我們以conv4_3為例講解。

layer {
  name: "conv4_3_norm_mbox_loc"
  type: "Convolution"
  bottom: "conv4_3_norm"
  top: "conv4_3_norm_mbox_loc"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  convolution_param {
    num_output: 16
    pad: 1
    kernel_size: 3
    stride: 1
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
      value: 0
    }
  }
}
以上就是conv4_3層的在train.prototxt中的內容。我們主要講解num_output=16是怎麼計算來的,在原始SSD中conv4_3產生的每個特徵圖的中心點產生4個預設框,具體預設框的產生數量及方式請參看博主博文:點選開啟連結

這四個預設仍框分別對應x1,y1,x2,y2四個點,所以呢在產生位置損失時就會產生四個loc損失,所以一箇中心點的所產生的4個預設框就有4*4=16個位置資訊需要輸出,這就是16的來源。具體在multibox_loss_layer.cpp中的定義是:

template <typename Dtype>
void MultiBoxLossLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top) {
  LossLayer<Dtype>::Reshape(bottom, top);
  num_ = bottom[0]->num();
  num_priors_ = bottom[2]->height() / 4;
  num_gt_ = bottom[3]->height();
  CHECK_EQ(bottom[0]->num(), bottom[1]->num());
  CHECK_EQ(num_priors_ * loc_classes_ * 4, bottom[0]->channels())    //num_priors_就是指每個中心點產生的預設框個數,位置個數計算。
      << "Number of priors must match number of location predictions.";
  CHECK_EQ(num_priors_ * num_classes_, bottom[1]->channels())    //置信個數計算。
      << "Number of priors must match number of confidence predictions.";
}
其他5個預設框提取特徵層同樣的計算方法。

對於置信輸出通道,其在train.prototxt中的內容為:

layer {
  name: "conv4_3_norm_mbox_conf"
  type: "Convolution"
  bottom: "conv4_3_norm"
  top: "conv4_3_norm_mbox_conf"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  convolution_param {
    num_output: 64
    pad: 1
    kernel_size: 3
    stride: 1
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
      value: 0
    }
  }
}
置信conf的輸出計算方法不同與位置loc,一箇中心點會產生一個預設框,但是這個預設框到底是正樣本還是負樣本,這就涉及到正負的兩個置信,如果是負的,那它就是背景。所以這需要看你的類別,在原始SSD檢測VOC時,類別數為21,所以這裡的num_output應該=(你的類別數+1)*中心點產生的預設框的個數,這裡為21*4=64。它在multibox_loss_layer.cpp中的定義也在上面我們複製出來的程式碼中。

其他5個提取層也是如此計算。

注意的一點是以上是針對conv4_3的計算,而fc7、conv6_2、conv7_2,原始的SSD框架中這三層的每個中心點產生了6個預設框,例如fc7,他在train.prototxt中的內容是:

layer {
  name: "fc7_mbox_loc"
  type: "Convolution"
  bottom: "fc7"
  top: "fc7_mbox_loc"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  convolution_param {
    num_output: 24
    pad: 1
    kernel_size: 3
    stride: 1
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
      value: 0
    }
  }
}

這裡我們只列舉了位置loc,計算為4*6=24。置信輸出就應該是21*6=126了,大家應該知道怎麼計算了吧。

另外我們著重強調一點,關於flip引數的設定,這在我的博文關於ssd_pascal.py解讀中有講解:點選開啟連結

他是設定翻轉的,我們在關於預設框的產生一文中講到,ssd預設產生一大一小兩個正方形預設框,另外,每設定一個aspect_ratio則增加兩個長方形預設框,然而在prior_box_layer.cpp檔案中只有產生一個長方形預設框的計算公式如下:

        // rest of priors
        for (int r = 0; r < aspect_ratios_.size(); ++r) {
          float ar = aspect_ratios_[r];
          if (fabs(ar - 1.) < 1e-6) {
            continue;
          }
          box_width = min_size_ * sqrt(ar);
          box_height = min_size_ / sqrt(ar);
          // xmin
          top_data[idx++] = (center_x - box_width / 2.) / img_width;
          // ymin
          top_data[idx++] = (center_y - box_height / 2.) / img_height;
          // xmax
          top_data[idx++] = (center_x + box_width / 2.) / img_width;
          // ymax
          top_data[idx++] = (center_y + box_height / 2.) / img_height;
        }
比如我們在conv4_3計算出的min_size=30,max_size=60,而該層的aspect_ratio=2,那麼產生四個預設框,兩個正方形,兩個長方形。這裡只計算了一個長方形框的大小,最後計算的縱橫比為1:2,那麼2:1的縱橫比長方形哪裡去了呢?就是靠我們的flip來計算了,當我們設定flip=True時一個aspect_ratio才會產生兩個預設框,如果不設定或者為Flase那麼就只產生一個長方形預設框。比如conv4_3產生的預設框在train.prototxt中的內容如下:
layer {
  name: "conv4_3_norm_mbox_priorbox"   //注意在卷積層conv4_3後有一個norm層做歸一化。
  type: "PriorBox"
  bottom: "conv4_3_norm"
  bottom: "data"
  top: "conv4_3_norm_mbox_priorbox"
  prior_box_param {
    min_size: 32
    aspect_ratio: 2
    flip: true   //注意,如果沒有flip引數,則aspect_ratio=2只能產生一個縱橫比為1:2的預設框。
    clip: false
    variance: 0.1
    variance: 0.1
    variance: 0.2
    variance: 0.2
    step: 8
    offset: 0.5
  }
}
當然,這裡是我們專案中的設定,我們這裡只設置了min_size,因為我們只需要一個較小的正方形邊框就可以了,並不需要較大的正方形邊框,所以我們沒有設定max_size引數,故每個預設框產生特徵層只生成一個邊長為min_size的正方形預設框,剔除邊長為sqrt(min_size*max_size)的預設框。這裡我們設定了一個aspect_ratio=2,所以每個中心點產生3個預設框。這裡flip我吃了很大的虧。一直在報錯。

最後以上面的講解延伸到我們最近研究的小人臉檢測建構SFD,他最低層的預設框提取層是conv3_3,而並不是conv4_4,所以其在conv3_3後面也做了norm操作,另外他在conv3_3後面還添加了一個slice層,注意只在conv3_3後面新增,它在train.prototxt中的內容為:

layer {
  name: "conv3_3_norm_mbox_conf"
  type: "Convolution"
  bottom: "conv3_3_norm"
  top: "conv3_3_norm_mbox_conf"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  convolution_param {
    num_output: 8  //這裡=類別數*該層每個中心點產生的預設框個數+2,這個2是由於以下新增的slice層的作用導致的。其他的如4_3、5_3、fc7、6_2、7_2這幾層沒有加slice層的則不需要+2。
    pad: 1
    kernel_size: 3
    stride: 1
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
      value: 0
    }
  }
}
layer {
  name: "conv3_3_norm_mbox_conf_slice"
  type: "Slice"
  bottom: "conv3_3_norm_mbox_conf"
  top: "conv3_3_norm_mbox_conf1"
  top: "conv3_3_norm_mbox_conf2"
  top: "conv3_3_norm_mbox_conf3"
  top: "conv3_3_norm_mbox_conf4"
  slice_param {
    axis: 1
    slice_point: 1
    slice_point: 2
    slice_point: 3
  }
}
layer {
  name: "conv3_3_norm_mbox_conf_maxout"
  type: "Eltwise"
  bottom: "conv3_3_norm_mbox_conf1"
  bottom: "conv3_3_norm_mbox_conf2"
  bottom: "conv3_3_norm_mbox_conf3"
  top: "conv3_3_norm_mbox_conf_maxout"
  eltwise_param {
    operation: MAX
  }
}
layer {
  name: "conv3_3_norm_mbox_conf_out"
  type: "Concat"
  bottom: "conv3_3_norm_mbox_conf_maxout"
  bottom: "conv3_3_norm_mbox_conf4"
  top: "conv3_3_norm_mbox_conf_out"
  concat_param {
    axis: 1
  }
}
該層的具體作用,博主還沒有做仔細的解讀,但是其中slice層導致了conv3_3的置信conf輸出發生了變化,要在我們前面講的基礎上加上2,即我們在以上程式碼中所註釋的部分。

最後給大家附上有置信conf和位置loc輸出通道設定錯誤引起的error:

1.由置信引起的:

Check failed: num_priors_ * num_classes_ == bottom[1]->channels() (132174 vs. 99406) Number of priors must match number of confidence predictions.

其中括號裡的數字不必去糾結,這和你的資料有關。

2.由位置引起的:

Check failed: num_priors_ * num_loc_classes_ * 4 == bottom[0]->channels() (264348 vs. 88116) Number of priors must match number of location predictions.

博主水平有限,如有錯誤請多多指正,轉載請註明地址。謝謝!

相關推薦

關於SSD訓練預設輸出輸出通道num_output計算 關於SSD訓練預設輸出輸出通道num_output計算

原 關於SSD訓練時預設框輸出層輸出通道num_output的計算 2018年02月03日 21:00:40 xunan003 閱讀數:2155

關於SSD訓練預設輸出輸出通道num_output計算

申明,本博文是為解決以下兩個問題而撰寫。 Check failed: num_priors_ * num_loc_classes_ * 4 == bottom[0]->channels() (264348 vs. 88116) Number of priors mus

關於SSD訓練預設輸出輸出通道num_output計算

原 關於SSD訓練時預設框輸出層輸出通道num_output的計算 2018年02月03日 21:00:40 xunan003 閱讀數:21

機器學習備註:Yolo訓練輸出引數的解釋

舉例 比如某一次的輸出結果如下 訓練log中各引數的意義  5: 10.222071, 10.294983 avg loss, 0.000000 rate, 395.829699 seconds, 320 images Loaded: 0.000000 seconds R

pytorch在fintune將sequential中的輸出以vgg為例

pytorch將sequential中的層輸出,以vgg為例 有時候我們在fintune時發現pytorch把許多層都集合在一個sequential裡,但是我們希望能把中間層的結果引出來做下一步操作,於是我自己琢磨了一個方法,以vgg為例,有點僵硬哈! 首先

DeepLearning: 資料處理5:將caffe訓練螢幕輸出視覺化(matlab程式碼)

說明:必須再前一篇博文的基礎上使用本文中的程式碼。先將螢幕輸出儲存到文字中,然後在使用本文中的程式碼。。。同樣,這裡只是我的環境下調通的,根據個人,適當調整程式碼就行了。。。都是重複造輪子,沒啥技術含量。。。 % 根據caffe輸出文件,作出accurac

【easy】107. Binary Tree Level Order Traversal II 按輸出二叉樹

ini == nod otto cto velt tree 輸出 int 按層輸出二叉樹,廣度優先。 3 / 9 20 / 15 7 [ [15,7], [9,20], [3] ] /** * Definit

CNN輸出每一的卷積核即每一的權重矩陣和偏移量矩陣

var 圖像 cas 值轉換 auth git dom 轉換 訓練 分別是16個5*5的一通道的卷積核,以及16個偏移量。A2是轉置一下,為了輸出每一個卷積核,TensorFlow保存張量方法和人的理解有很大區別,A21 A31 A41 A51都是卷積核的權重矩陣偏移量

Python3 tkinter基礎 Entry get 點擊按鈕 將輸入中文字輸出到控制臺

char 一件事 進行 gui 思維 inf 思想 col pycharm ? python : 3.7.0 OS : Ubuntu 18.04.1 LTS

定義一個帶參的巨集使兩個引數的值互換並寫出程式輸入兩個數作為使用巨集的實參。輸出已交換後的兩個值。

import java.util.Scanner; public class Main {     public static void main(String[] args) {         Scanne

海思開發VOU(視訊輸出基本概念)

1:VOU層::模組主動從記憶體響應位置讀取視訊和圖形資料,並且通過相應的顯示裝置輸出 顯示裝置:高清裝置和標清裝置。DHDX和DSDX    注意:高清裝置可以同時繫結兩個視訊層。 視訊層:固定在每個裝置上面對應的視訊層 ,  可以動態繫結視訊層:PIP層。

LSTM 神經網路輸入輸出

今天終於弄明白,TensorFlow和Keras中LSTM神經網路的輸入輸出層到底應該怎麼設定和連線了。寫個備忘。 https://machinelearningmastery.com/how-to-develop-lstm-models-for-time-series-forecasting/ Stac

Softmax輸出損失函式及偏導數

softmax輸出層(m個輸入,n個輸出): Z=WX+B Z = WX+B (其中W為係數矩陣( n×m n\times m),B為n維偏置量,X為m維輸入向量,Z為n維向量) yj=ezj∑mj=1ezj y_j

keras獲取中間輸出

https://keras-cn.readthedocs.io/en/latest/for_beginners/FAQ/#intermediate_layer from keras import backend as K get_3rd_layer_output = K.function

Keras 獲取中間某一輸出

1.使用函式模型API,新建一個model,將輸入和輸出定義為原來的model的輸入和想要的那一層的輸出,然後重新進行predict. 1 #coding=utf-8 2 import seaborn as sbn 3 import pylab as plt 4 import theano

BP演算法總結+從輸入-隱-輸出的逐步手推

1 BP演算法總結   BP演算法:bp演算法實際上是在神經網路中尋找在合適條件下的最佳權重和bais。實際上是利用輸出後的誤差來估計輸出層前一層的誤差,再用這層誤差來估計更前一層誤差,如此獲取所有各層誤差估計。然後再來來調整各層的連線權值+bais,再用調整後的連線權值+

Bootstrap中模態巢狀滾動條問題

在使用Bootstrap中模態框過程中,如果出現多層巢狀的時候,如開啟模態框A,然後在A中開啟模態框B,在關閉B之後,如果A的內容比較多,滾動條會消失,而變為Body的滾動條,這是由於模態框自帶的遮罩的問題。網上有朋友給出的解決方案是在A增加overflow:auto的方法解決,但是這種方法會使得頁面出現兩個

CNN網路提取哪輸出作為最後提取的特徵為宜?

     在使用CNN提取特徵時,到底使用哪一層的輸出作為特徵呢?很多人會說:“當然是最後一個全連線層了!,這有什麼問題?”     這還真有問題!我相信有很多人和我一樣走入了一個誤區,認為最後一個全

獲取Keras模型中間輸出

使用Keras可以比較方便地搭建一些深度學習網路,獲取中間層輸出可以幫助理解它是如何執行的。這裡使用一個小型的Keras網路,對Caltech101資料集進行影象分類,並獲取中間層輸出結果,以及手工計算卷積層的輸出結果。修正:表示當前是訓練模式還是測試模式的引數K.learn

【機器學習】輸出的設計

神經網路可以用於分類和迴歸問題,但是最後在輸出時需要根據情況來設定輸出層的啟用函式。一般來說, 迴歸問題:恆等函式 分類問題:softmax函式 https://blog.csdn.net/u011240016/article/details/85121601