TensorRT/parsers/caffe/caffeParser/opParsers/parseConv.cpp源碼研讀

TensorRT/parsers/caffe/caffeParser/opParsers/parseConv.cpp

/* Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "opParsers.h"

using namespace nvinfer1;

namespace nvcaffeparser1
{
/*
獲取或隨機初始化權重及偏置量後,把它們記錄於mTmpAllocs中
然後為網路新增卷積層
*/
ILayer* parseConvolution(INetworkDefinition& network, const trtcaffe::LayerParameter& msg, CaffeWeightFactory& weightFactory, BlobNameToTensor& tensors)
{
    //卷積層的輸入及輸出個數均應為1
    if (!checkBlobs(msg, 1, 1))
    {
        return nullptr;
    }

    /*
    trtcaffe::ConvolutionParameter
    定義於TensorRT/parsers/caffe/proto/trtcaffe.proto
    */
    const trtcaffe::ConvolutionParameter& p = msg.convolution_param();
    int nbOutputs = p.num_output();

    int kernelH = p.has_kernel_h() ? p.kernel_h() : p.kernel_size(0);
    //如果未指定kernel_w,則默認它與kernel_h一致
    int kernelW = p.has_kernel_w() ? p.kernel_w() : p.kernel_size_size() > 1 ? p.kernel_size(1) : p.kernel_size(0);
    int C = parserutils::getCHW(tensors[msg.bottom(0)]->getDimensions()).c();
    // The group size for group conv
    int G = p.has_group() ? p.group() : 1;

    auto CbyG = float(C / G * nbOutputs);
    float std_dev = 1.0F / sqrtf((kernelW * kernelH * sqrtf(CbyG)));
    /*
    WeightType::kGENERIC,WeightType::kBIAS:
    types for convolution, deconv, fully connected
    分別代表權重及偏置量
    */
    /*
    CaffeWeightFactory::operator()
    定義於TensorRT/parsers/caffe/caffeWeightFactory/caffeWeightFactory.cpp
    獲取layerName層的第int(weightType)個blob(即權重或偏置量),
    如果沒有,則回傳長度為0的Null weights
    */
    /*
    CaffeWeightFactory::allocateWeights
    Weights CaffeWeightFactory::allocateWeights(int64_t elems, std::normal_distribution<float> distribution)
    定義於TensorRT/parsers/caffe/caffeWeightFactory/caffeWeightFactory.cpp
    分配getDataType()型別,elems大小的空間,用它來新建Weights物件後回傳
    採用normal distribution來隨機初始化
    */
    /*
    CaffeWeightFactory::getNullWeights
    定義於TensorRT/parsers/caffe/caffeWeightFactory/caffeWeightFactory.cpp
    回傳空的weight array
    */
    //獲取或隨機初始化權重及偏置量
    //權重張量(四維)的體積為kernelW * kernelH * CbyG
    Weights kernelWeights = weightFactory.isInitialized() ? weightFactory(msg.name(), WeightType::kGENERIC) : weightFactory.allocateWeights(kernelW * kernelH * CbyG, std::normal_distribution<float>(0.0F, std_dev));
    Weights biasWeights = !p.has_bias_term() || p.bias_term() ? (weightFactory.isInitialized() ? weightFactory(msg.name(), WeightType::kBIAS) : weightFactory.allocateWeights(nbOutputs)) : weightFactory.getNullWeights();

    /*
    CaffeWeightFactory::convert
    將weights裡的內容轉換為初始化時就設定好的mDataType型別,
    並將weights.values記錄於mTmpAllocs中
    */
    weightFactory.convert(kernelWeights);
    weightFactory.convert(biasWeights);
    auto inTensor = tensors[msg.bottom(0)];
    /*
    INetworkDefinition::addConvolution
    宣告於TensorRT/include/NvInfer.h
    TRT_DEPRECATED virtual IConvolutionLayer* addConvolution(ITensor& input, int nbOutputMaps, DimsHW kernelSize,
        Weights kernelWeights, Weights biasWeights) TRTNOEXCEPT = 0;
    */
    /*
    nvinfer1::DimsHW
    定義於TensorRT/include/NvInfer.h
    */
    auto layer = network.addConvolution(*inTensor, nbOutputs, DimsHW{kernelH, kernelW}, kernelWeights, biasWeights);

    if (layer)
    {
        //stride:默認為1
        int strideH = p.has_stride_h() ? p.stride_h() : p.stride_size() > 0 ? p.stride(0) : 1;
        int strideW = p.has_stride_w() ? p.stride_w() : p.stride_size() > 1 ? p.stride(1) : p.stride_size() > 0 ? p.stride(0) : 1;

        //pad:默認為0
        int padH = p.has_pad_h() ? p.pad_h() : p.pad_size() > 0 ? p.pad(0) : 0;
        int padW = p.has_pad_w() ? p.pad_w() : p.pad_size() > 1 ? p.pad(1) : p.pad_size() > 0 ? p.pad(0) : 0;

        //dilation:默認為1
        int dilationH = p.dilation_size() > 0 ? p.dilation(0) : 1;
        int dilationW = p.dilation_size() > 1 ? p.dilation(1) : p.dilation_size() > 0 ? p.dilation(0) : 1;

        /*
        宣告於TensorRT/include/NvInfer.h
        TRT_DEPRECATED virtual void setStride(DimsHW stride) TRTNOEXCEPT = 0;
        TRT_DEPRECATED virtual void setPadding(DimsHW padding) TRTNOEXCEPT = 0;
        virtual void setPaddingMode(PaddingMode paddingMode) TRTNOEXCEPT = 0;
        TRT_DEPRECATED virtual void setDilation(DimsHW dilation) TRTNOEXCEPT = 0;
        */
        layer->setStride(DimsHW{strideH, strideW});
        layer->setPadding(DimsHW{padH, padW});
        /*
        定義於TensorRT/include/NvInfer.h
        enum class PaddingMode : int
		{
		    kEXPLICIT_ROUND_DOWN = 0, //!< Use explicit padding, rounding output size down.
		    kEXPLICIT_ROUND_UP = 1,   //!< Use explicit padding, rounding output size up.
		    kSAME_UPPER = 2,          //!< Use SAME padding, with prePadding <= postPadding.
		    kSAME_LOWER = 3,          //!< Use SAME padding, with prePadding >= postPadding.
		    kCAFFE_ROUND_DOWN = 4,    //!< Use CAFFE padding, rounding output size down, uses prePadding value.
		    kCAFFE_ROUND_UP = 5       //!< Use CAFFE padding, rounding output size up, uses prePadding value.
		};
		*/
		layer->setPaddingMode(PaddingMode::kCAFFE_ROUND_DOWN);
        layer->setDilation(DimsHW{dilationH, dilationW});

		/*
		宣告於TensorRT/include/NvInfer.h
		virtual void setNbGroups(int nbGroups) TRTNOEXCEPT = 0;
		*/
        layer->setNbGroups(G);
    }
    return layer;
}
} //namespace nvcaffeparser1

std::normal_distribution

在函數parseConvolution中用到了std::normal_distribution

/**/std::normal_distribution<float>(0.0F, std_dev)/**/

關於std::normal_distribution,詳見C++ uniform_real_distribution及normal_distribution

weight initialization

auto CbyG = float(C / G * nbOutputs);
float std_dev = 1.0F / sqrtf((kernelW * kernelH * sqrtf(CbyG)));
Weights kernelWeights = weightFactory.isInitialized() ? weightFactory(msg.name(), WeightType::kGENERIC) : weightFactory.allocateWeights(kernelW * kernelH * CbyG, std::normal_distribution<float>(0.0F, std_dev));

找不到這裡初始化方式的出處?

參考連結

C++ uniform_real_distribution及normal_distribution

發佈了145 篇原創文章 · 獲贊 9 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章