ncnn源码解析(五):执行器Extractor

前面大致总结了一下ncnn模型载入的流程,模型载入之后,就是新建一个Extractor,然后设置输入,获取输出:

    ncnn::Extractor ex = net.create_extractor();
    ex.set_num_threads(4);
 
    ex.input("data", in);
 
    ncnn::Mat out;
    ex.extract("detection_out", out);

        现在可以看一下Extractor的定义了:

class Extractor
{
public:
    // enable light mode
    // intermediate blob will be recycled when enabled
    // enabled by default
    // 设置light模式
    void set_light_mode(bool enable);

    // set thread count for this extractor
    // this will overwrite the global setting
    // default count is system depended
    // 设置线程数
    void set_num_threads(int num_threads);

    // set blob memory allocator
    // 设置blob的内存分配器
    void set_blob_allocator(Allocator* allocator);

    // set workspace memory allocator
    // 设置工作空间的内存分配器
    void set_workspace_allocator(Allocator* allocator);


#if NCNN_STRING
    // set input by blob name
    // return 0 if success
    // 设置网络输入:字符串layer名
    int input(const char* blob_name, const Mat& in);

    // get result by blob name
    // return 0 if success
    // 设置提取器的输入:得到对应输出
    int extract(const char* blob_name, Mat& feat);
#endif // NCNN_STRING

    // set input by blob index
    // return 0 if success
    // 设置int类型blob索引及输入
    int input(int blob_index, const Mat& in);

    // get result by blob index
    // return 0 if success
    // 设置int类型blob索引及输出
    int extract(int blob_index, Mat& feat);

protected:
    // 对外提供create_extractor接口
    friend Extractor Net::create_extractor() const;
    Extractor(const Net* net, int blob_count);

private:
    // 网络 
    const Net* net;
    // blob的mat
    std::vector<Mat> blob_mats;
    // 选项
    Option opt;

};

        将vulkan部分代码剔除掉,不难发现,Extractor里面就这么多内容,除了设置option的接口之外,就只剩下我们需要使用的几个接口函数了:

// 创建Extractor
Extractor Net::create_extractor() const
{
    return Extractor(this, blobs.size());
}

        内部调用了接口为,就是将blob_mat数组resize到网络的blob数目大小,然后设置了一下选项:

// 执行器
Extractor::Extractor(const Net* _net, int blob_count) : net(_net)
{
    blob_mats.resize(blob_count);
    opt = net->opt;
}

        然后就是input接口:

// 设置输入
int Extractor::input(const char* blob_name, const Mat& in)
{
    // 获取输入模块对应index
    int blob_index = net->find_blob_index_by_name(blob_name);
    if (blob_index == -1)
        return -1;

    // 调用直接用index的设置input方法
    return input(blob_index, in);
}

        内部调用的接口为:

// 输入为index的输入接口
int Extractor::input(int blob_index, const Mat& in)
{
    if (blob_index < 0 || blob_index >= (int)blob_mats.size())
        return -1;

    // 设置blob_index对应Mat
    blob_mats[blob_index] = in;

    return 0;
}

        这里就是设置输入对应blob值。

        最后一个接口就是extract接口:

// 将输入string类型name转换成对应的索引
int Extractor::extract(const char* blob_name, VkMat& feat, VkCompute& cmd)
{
    int blob_index = net->find_blob_index_by_name(blob_name);
    if (blob_index == -1)
        return -1;

    return extract(blob_index, feat, cmd);
}

        这里调用的接口为:

// 提取特征
int Extractor::extract(int blob_index, Mat& feat)
{
    if (blob_index < 0 || blob_index >= (int)blob_mats.size())
        return -1;

    int ret = 0;

    // 如果输出blob为空
    if (blob_mats[blob_index].dims == 0)
    {
        // 查找输出blob对应的生产者
        int layer_index = net->blobs[blob_index].producer;

        // 前向推理
        ret = net->forward_layer(layer_index, blob_mats, opt);
    }

    // 输出特征
    feat = blob_mats[blob_index];

    if (opt.use_packing_layout)
    {
        // 对特征进行unpack
        Mat bottom_blob_unpacked;
        convert_packing(feat, bottom_blob_unpacked, 1, opt);
        feat = bottom_blob_unpacked;
    }

    return ret;
}

        这里就是调用各层前向推理forward_layer方法来进行推理的,这个对应于特定层的推理过程,后面总结各个层的时候再说。

参考资料:

[1] https://github.com/Tencent/ncnn

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值