日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

caffe卷积层代码阅读笔记

發布時間:2025/3/21 编程问答 52 豆豆
生活随笔 收集整理的這篇文章主要介紹了 caffe卷积层代码阅读笔记 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載自:http://blog.csdn.net/tangwei2014/article/details/47730797

卷積的實現思想:

  • 通過im2col將image轉為一個matrix,將卷積操作轉為矩陣乘法運算
  • 通過調用GEMM完成運算操作
  • 下面兩個圖是我在知乎中發現的,“盜”用一下,確實很好,能幫助理解。?
    ?

參數剖析

  • 配置參數:(從配置文件得來)?
    kernel_h_ pad_h_ hole_h_ stride_h_?
    kernel_w_ pad_w_ hole_w_ stride_w_?
    is_1x1_:上面8個參數都為1時,該參數為true

  • 和輸入有關的參數:(從bottom得來)?
    num_?
    channels_?
    height_?
    width_

  • 和卷積核有關的參數:(前兩個參數從配置文件得來)?
    num_output_?
    group_?
    this->blobs_[0].reset(new Blob(num_output_, channels_ / group_, kernel_h_, kernel_w_));?
    this->blobs_[1].reset(new Blob(1, 1, 1, num_output_));?
    this->param_propagate_down_

  • 和輸出有關的參數:(計算得來)?
    const int kernel_h_eff = kernel_h_ + (kernel_h_ - 1) * (hole_h_ - 1);?
    const int kernel_w_eff = kernel_w_ + (kernel_w_ - 1) * (hole_w_ - 1);?
    height_out_ = (height_ + 2 * pad_h_ - kernel_h_eff) / stride_h_ + 1;?
    width_out_ = (width_ + 2 * pad_w_ - kernel_w_eff) / stride_w_ + 1;

  • 和矩陣運算有關的參數:(計算得來)?
    M_ = num_output_ / group_;?
    K_ = channels_ * kernel_h_ * kernel_w_ / group_;?
    N_ = height_out_ * width_out_;?
    col_buffer_.Reshape(1, channels_*kernel_h_*kernel_w_, height_out_, width_out_);// is_1x1_為false的時候用?
    bias_multiplier_.Reshape(1, 1, 1, N_); //全部為1

輸入大小:(num_, channels_, height_, width_)?
輸出大小:(num_, num_output_, height_out_, width_out_)

重點函數剖析

  • 函數一:?
    im2col_cpu(bottom_data + bottom[i]->offset(n),?
    1, channels_, height_, width_,?
    kernel_h_, kernel_w_, pad_h_, pad_w_,?
    stride_h_, stride_w_, hole_h_, hole_w_,?
    col_buff);

    該函數的目的是:根據配置參數,將一幅(1, channels_, height_, width_)的輸入feature map expand成 (1, channels_*kernel_h_*kernel_w_, height_out_, width_out_)大小的矩陣。

    具體的實現方法是:?
    內部主要有兩套索引?
    一套是在輸入圖像上的索引,分別是:c_im(channels), h_im(height), w_im(width)?
    另一套是在輸出的col_buff上的,分別是:c(channels_col), h(height_col), w(width_col)

    循環變量來自輸出的col_buff的維數,根據輸出的位置計算對應在輸入圖像上的位置(col2imh函數和im2col函數是一個道理,兩套坐標反著來就行)。把索引的代碼整合出來,對著源代碼看,很容易懂:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> kernel_h_eff = kernel_h + (kernel_h - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) * (hole_h - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>);<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> kernel_w_eff = kernel_w + (kernel_w - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) * (hole_w - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>);<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> height_col = (height + <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span> * pad_h - kernel_h_eff) / stride_h + <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> width_col = (width + <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span> * pad_w - kernel_w_eff) / stride_w + <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> channels_col = channels * kernel_h * kernel_w;<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> w_offset = (c % kernel_w) * hole_w;<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> h_offset = ((c / kernel_w) % kernel_h) * hole_h;<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> c_im = c / kernel_w / kernel_h;<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> h_im = h * stride_h + h_offset - pad_h;<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> w_im = w * stride_w + w_offset - pad_w;</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>
  • 函數二:

    caffe_cpu_gemm(CblasNoTrans, CblasNoTrans, M_, N_, K_,?
    (Dtype)1., weight + weight_offset * g, col_buff + col_offset * g,?
    (Dtype)0., top_data + top[i]->offset(n) + top_offset * g);

    該函數的目的是:?
    將(num_output_/group_, channels_ /group_, kernel_h_, kernel_w_)卷積核看成一個(num_output_/group_, channels_*kernel_h_*kernel_w_/group_)的矩陣A,即大小為M_x K_。

    將(1, channels_*kernel_h_*kernel_w_, height_out_, width_out_)的col_buff看成group_個(channels_*kernel_h_*kernel_w_/group_, height_out_*width_out_)的矩陣B,即大小為K_x N_。

    兩者相乘再加上偏置項,就能得到卷積的結果。

    解釋caffe_cpu_gemm函數:?
    其實其內部包了一個cblas_sgemm函數。?
    void cblas_sgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,?
    const enum CBLAS_TRANSPOSE TransB, const int M, const int N,?
    const int K, const float alpha, const float *A,?
    const int lda, const float *B, const int ldb,?
    const float beta, float *C, const int ldc)

    得到的結果是:?
    C = alpha*op( A )*op( B ) + beta*C

    const enum CBLAS_ORDER Order,這是指的數據的存儲形式,在CBLAS的函數中無論一維還是二維數據都是用一維數組存儲,這就要涉及是行主序還是列主序,在C語言中數組是用 行主序,fortran中是列主序。如果是習慣于是用行主序,所以這個參數是用CblasRowMajor,如果是列主序的話就是 CblasColMajor。?
    const int M,矩陣A的行,矩陣C的行?
    const int N,矩陣B的列,矩陣C的列?
    const int K,矩陣A的列,矩陣B的行


總結

以上是生活随笔為你收集整理的caffe卷积层代码阅读笔记的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。