ncnn源码学习(十):添加layer

给ncnn的网络添加layer分为两种情况:

1.模型转换之后,某些layer没有转换成功:

 如,shufflenetV2中,param文件只转换到了fc这一个layer:

这时需要添加一层softmax,可以先对param文件中转换成功的layer做推理,然后手动添加一个softmax层:

    ncnn::Extractor ex = shufflenetv2.create_extractor();
    ex.input("data", in);

    ncnn::Mat out;
    ex.extract("fc", out);
    // manually call softmax on the fc output
    // convert result into probability
    // skip if your model already has softmax operation
    {
        ncnn::Layer* softmax = ncnn::create_layer("Softmax");

        ncnn::ParamDict pd;
        softmax->load_param(pd);

        softmax->forward_inplace(out, shufflenetv2.opt);

        delete softmax;
    }

    out = out.reshape(out.w * out.h * out.c);

2.某些layer,ncnn不支持,需要进行自定义实现:

具体可以去看一下ncnn的wiki:

https://github.com/Tencent/ncnn/wiki/how-to-implement-custom-layer-step-by-step

参考资料:

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

[2] https://github.com/Tencent/ncnn/wiki/how-to-implement-custom-layer-step-by-step

<think>好的,我现在需要处理用户提到的关于ncnn库中的编译器警告C4251的问题。用户给出的错误信息是layer.h(158,22): warning C4251: 'ncnn::Layer::top_shapes': class 'std::vector<ncnn::Mat,std::allocator<ncnn::Mat>>' needs to have dll-interface to be used by clients of class 'ncnn::Layer'。首先,我要理解这个警告的含义以及产生的原因。 首先,C4251是微软Visual C++编译器的一个警告,通常出现在使用DLL导出类时,当类的成员变量使用了标准模板库(STL)的模板类,比如std::vector、std::string等。这是因为这些模板类在不同的DLL中可能有不同的实现或内存布局,如果导出的类中包含这样的成员,可能导致客户端在使用时出现兼容性问题,比如内存分配和释放的不一致,进而引发崩溃。 用户提到的错误发生在ncnn库的Layer类中的top_shapes成员变量,其类型是std::vector<ncnn::Mat>。问题在于,当ncnn库被编译为DLL时,Layer类被导出(通过__declspec(dllexport)),而top_shapes作为STL容器,其模板实例化并没有被显式导出,导致编译器发出警告。 接下来,我需要考虑如何解决这个问题。通常有几种方法可以处理这类警告: 1. **忽略警告**:如果确认代码在跨DLL边界使用时不会出现问题,可以通过编译器指令暂时禁用该警告。但这不是推荐的做法,尤其是对于库代码,因为可能影响用户。 2. **使用编译器指令抑制警告**:在代码中使用#pragma warning(disable: 4251)来禁用特定位置的警告。这需要确保只在必要的代码段中禁用,避免隐藏其他潜在问题。 3. **修改代码结构**:避免在导出的类中直接暴露STL容器作为公共成员。可以将这些成员设为私有,并通过访问函数提供访问,或者使用Pimpl(Pointer to Implementation)惯用法隐藏实现细节。 4. **显式导出模板实例化**:通过显式实例化并导出std::vector<ncnn::Mat>,但这可能比较复杂,因为STL的实现通常不允许这样做,尤其是在不同编译器或版本之间可能存在兼容性问题。 对于ncnn这样的开源库,可能需要查看其代码结构,确定是否已经有相关的处理措施。例如,在类定义周围可能已经有用于导出和导入的宏,如NCNN_EXPORT。如果top_shapes是公开成员变量,并且必须保留为public,那么可能需要使用编译器指令来抑制警告,或者重构代码。 另外,考虑到跨平台兼容性,ncnn库可能已经处理了不同平台的导出导入问题,但在Windows的DLL模型下,这个问题更为突出。因此,解决方案可能需要结合平台特定的预处理指令。 例如,在Layer类的头文件中,可能会有类似这样的结构: ```cpp class NCNN_EXPORT Layer { public: std::vector<Mat> top_shapes; // ... }; ``` 这里的NCNN_EXPORT在Windows下可能定义为__declspec(dllexport)或__declspec(dllimport)取决于编译情况。由于std::vector<Mat>未被导出,编译器产生警告。此时,可以在类定义周围添加#pragma warning(disable: 4251),或者在项目设置中全局禁用该警告,但后者不推荐。 更安全的做法是将top_shapes设为私有,并提供公共的访问方法,如: ```cpp class NCNN_EXPORT Layer { private: std::vector<Mat> top_shapes; public: const std::vector<Mat>& get_top_shapes() const { return top_shapes; } // ... }; ``` 这样,客户端代码通过引用访问,避免了直接导出STL成员的问题,但可能需要修改库的使用方式,影响较大。 另一种方法是在导出类时,使用编译器指令局部禁用警告: ```cpp #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif class NCNN_EXPORT Layer { public: std::vector<Mat> top_shapes; // ... }; #ifdef _MSC_VER #pragma warning(pop) #endif ``` 这种方法较为常见,尤其是在开源库中,因为改动较小,且能有效抑制警告,但需要确保这种用法不会导致实际的兼容性问题。 总结,处理这个警告的方法通常是在类导出时暂时禁用C4251警告,或者调整代码结构避免直接暴露STL成员。考虑到ncnn作为高性能推理库,可能更倾向于使用编译器指令来抑制警告,同时确保代码的正确性。</think>这个警告是使用微软VC++编译器时常见的DLL接口问题,我们来逐步分析原因和解决方案: **根本原因分析:** 1. 当DLL导出包含STL容器(如$std::vector$)的类时,不同模块(EXE/DLL)可能有不同的STL内存分配器实现 2. 编译器检测到`ncnn::Layer`类导出了`std::vector<ncnn::Mat>`类型的成员`top_shapes` 3. 可能引发的问题:跨DLL边界传递时出现内存分配/释放不一致,导致崩溃 **解决方案:** 1. **推荐方案 - 使用预编译头屏蔽警告(侵入性最小)** ```cpp // 在导出类的头文件头部添加 #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4251) #endif // 类定义... #ifdef _MSC_VER #pragma warning(pop) #endif ``` 2. **兼容性方案 - 修改成员可见性** ```cpp class NCNN_EXPORT Layer { protected: // 或 private std::vector<Mat> top_shapes; public: // 添加访问接口 const std::vector<Mat>& getTopShapes() const { return top_shapes; } }; ``` 3. **工程配置方案(适合项目维护者)** - 在VC++项目属性中设置:`属性 -> C/C++ -> 高级 -> 禁用特定警告` 填入`4251` **深原理说明:** - STL模板类本质是头文件实现,不同模块可能有不同的内存布局 - DLL接口规范要求:任何跨DLL传递的类型必须保证 - 类型尺寸一致($sizeof(T)$相同) - 内存管理一致性(同CRT版本) - 公式表示导出安全条件: $$ \forall t \in exported\_class\_members,\ type(t)\ is\_fully\_visible $$ **验证建议:** 1. 保持所有模块使用相同编译器版本和CRT 2. 避免跨DLL边界传递STL容器(改用指针或自定义容器) 3. 对必须导出的STL成员添加静态断言: ```cpp static_assert(sizeof(std::vector<ncnn::Mat>) == expected_size, "ABI mismatch!"); ``` 建议优先采用方案1,这是深度学习框架中处理此类问题的常见做法。NCNN自身代码中也大量使用这种模式处理平台兼容性问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值