ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

tiny-dnn 导入 Caffe 训练模型:caffe_converter 示例完整解析

tiny-dnn 导入 Caffe 训练模型:caffe_converter 示例完整解析 人工智能深度学习嵌入式【免费下载链接】tiny-dnnheader only, dependency-free deep learning framework in C14项目地址https://gitcode.com/gh_mirrors/ti/tiny-dnn点击查看免费下载导读tiny-dnn 是一个 header-only、无第三方依赖的 C14 深度学习框架但它的模型转换子系统是一个例外借助 examples/caffe_converter 示例tiny-dnn 可以解析 Caffe 的 prototxt 网络描述、读取.caffemodel二进制权重并在本框架内直接完成前向推理。读完本文你将掌握 tiny-dnn 转换 Caffe 模型的完整流程环境准备、通过protoc生成 protobuf 代码、编译转换器、按五个命令行参数完成一次真实的图像分类推理以及转换器的层类型支持范围与结构限制。一、转换器做什么从 Caffe 模型到 tiny-dnn 网络tiny-dnn 本身不提供训练 Caffe 模型的能力但它提供了读取 Caffe 训练产物的通道。examples/caffe_converter/caffe_converter.cpp是这一能力的完整落地示例核心调用只有两行auto net tiny_dnn::create_net_from_caffe_prototxt(model_file); // 解析网络结构 tiny_dnn::reload_weight_from_caffe_protobinary(trained_file, net.get()); // 加载权重这两行背后对应 tiny_dnn/io/caffe/layer_factory.h 中的四个公共接口接口作用输入格式create_net_from_caffe_prototxt从文本格式 prototxt 构建网络.prototxt纯文本create_net_from_caffe_protobinary从二进制 NetParameter 构建网络.caffemodel含结构reload_weight_from_caffe_protobinary把二进制权重注入已构建的网络.caffemodel二进制create_net_from_caffe_net统一入口根据 shape 推断输入尺寸并逐层转换caffe::NetParameter以create_net_from_caffe_prototxt为例其实现是先通过detail::read_proto_from_text用 protobuf 的TextFormat解析文本再交给create_net_from_caffe_netinline std::shared_ptrnetworksequential create_net_from_caffe_prototxt( const std::string caffeprototxt, const shape3d shape shape3d()) { caffe::NetParameter np; detail::read_proto_from_text(caffeprototxt, np); return create_net_from_caffe_net(np, shape); }输入尺寸的推导顺序值得注意见 layer_factory.h显式传入shape3d参数时优先使用否则读取已废弃的input_shape字段dim顺序为 N × C × H × W否则尝试Input层的input_param.shape都不存在则抛出nn_error(input_shape not found in caffemodel. must specify input shape explicitly)。这也是为什么 CaffeNet 的deploy.prototxt能被直接转换——它本身带input_shape。注意这个转换子系统是实验性的。在 tiny_dnn/tiny_dnn.h 中相关头文件被包裹在#ifdef CNN_USE_CAFFE_CONVERTER之下且注释明确写着 experimental / require google protobuf。二、环境准备Google protobuf 与 OpenCV原文档列出的前置依赖有两项Google protobuf转换器依赖 protobuf 的运行时与代码生成器protoc来解析 Caffe 的NetParameter消息OpenCV示例程序需要读取待分类的图像文件BGR 格式并参与均值图像的计算与预处理。在 CMakeLists.txt 中protobuf 是作为硬性依赖引入的find_package( Protobuf REQUIRED ) PROTOBUF_GENERATE_CPP( PROTO_SRC PROTO_HDR ${CMAKE_CURRENT_SOURCE_DIR}/../../tiny_dnn/io/caffe/caffe.proto ) add_executable( caffe_converter caffe_converter.cpp ${PROTO_SRC} ${PROTO_HDR} ) target_link_libraries( caffe_converter ${PROTOBUF_LIBRARY} )PROTOBUF_GENERATE_CPP会在构建时自动调用protoc生成caffe.pb.cc与caffe.pb.h因此使用 CMake 构建时无需手工执行protoc。三、构建步骤3.1 方式一手工protoc原文档做法原文档给出的手工流程分两步第一步进入 caffe 的 proto 定义目录并生成 C 代码cd tiny_dnn/io/caffe protoc caffe.proto --cpp_out./该命令会在tiny_dnn/io/caffe/下生成caffe.pb.cc与caffe.pb.h。caffe.prototiny_dnn/io/caffe/caffe.proto是 tiny-dnn 仓库内置的一份 Caffe 协议定义采用syntax proto2覆盖了NetParameter、LayerParameter、BlobProto、ConvolutionParameter、PoolingParameter、InnerProductParameter、BatchNormParameter等核心消息。值得注意的是它还保留了V1LayerParameter、V0LayerParameter等旧版本消息并在 layer_factory_impl.h 的caffe_layer_vector::upgradev1net中实现了 V1 → V2 的自动升级转换。第二步将生成的caffe.pb.cc与示例主文件一起编译并链接# 例如具体编译命令取决于你的编译器与包含路径 g -stdc11 \ tiny_dnn/io/caffe/caffe.pb.cc \ examples/caffe_converter/caffe_converter.cpp \ -I. -lprotobuf -lopencv_core -lopencv_imgproc -lopencv_imgcodecs \ -o caffe_converter.bin注意转换器的可执行文件名在原文档中约定为caffe_converter.bin。3.2 方式二CMake仓库为示例提供了独立的 CMakeLists.txt内部已封装protoc调用并对目标设置了 C11 标准CXX_STANDARD 11。与 tiny-dnn 主框架的 C14 要求不同转换器示例的最低标准是 C11。四、命令行用法与参数详解转换器是纯命令行工具原文档给出的调用格式为./caffe_converter.bin [model-file] [trained-file] [mean-file] [label-file] [img-file]五个位置参数在 caffe_converter.cpp 中按顺序依次读取参数含义在 CaffeNet 示例中的取值model-file网络结构文件prototxt 文本deploy.prototxttrained-file训练好的权重文件二进制bvlc_reference_caffenet.caffemodelmean-file均值文件binaryprotoimagenet_mean.binaryprotolabel-file类别标签文本文件每行一个标签synset_words.txtimg-file待分类的图像文件cat.jpg对应的完整命令原文档中的预训练 CaffeNet 分类示例./caffe_converter.bin\ deploy.prototxt\ bvlc_reference_caffenet.caffemodel\ imagenet_mean.binaryproto\ synset_words.txt\ cat.jpg主函数main不做参数校验直接按序取用argv[1..5]异常通过catch (const tiny_dnn::nn_error e)捕获并打印e.what()因此当网络结构不受支持、文件缺失或解析失败时错误信息会直接输出到标准输出。五、转换后的推理流程从图像到 Top-5 结果test()函数caffe_converter.cpp完整展示了转换之后的推理链路可分为四步5.1 加载网络与权重auto labels get_label_list(label_file); auto net tiny_dnn::create_net_from_caffe_prototxt(model_file); tiny_dnn::reload_weight_from_caffe_protobinary(trained_file, net.get());get_label_list逐行读取标签文件reload_weight_from_caffe_protobinary会根据 Caffe 层类型与 tiny-dnn 层类型的映射表layer_match逐层对齐并填充权重跳过不含权重的激活层ReLU、Sigmoid、TanH、Softmax、Dropout、LRN 等见 layer_factory_impl.h 的layer_has_weights。5.2 从网络推导输入尺寸int width (*net)[0]-in_data_shape()[0].width_; int height (*net)[0]-in_data_shape()[0].height_;输入图像的宽高直接取自 tiny-dnn 网络第一个层的输入数据形状in_data_shape无需在命令行重复指定——这也是读取网络结构后再做预处理的根本原因。5.3 读取均值文件并预处理图像compute_mean读取imagenet_mean.binaryprotoCaffe 的BlobProto二进制格式把其中保存的均值数据构造成 BGR 图像然后调用mean_imagetiny_dnn/util/image.h得到逐通道的均值图caffe::BlobProto blob; tiny_dnn::detail::read_proto_from_binary(mean_file, blob); auto data blob.mutable_data()-mutable_data(); tiny_dnn::imagefloat original(data, blob.width(), blob.height(), tiny_dnn::image_type::bgr); return mean_image(original);preprocess完成与 Caffe 分类流程一致的预处理先用resize_image把图像缩放到网络输入尺寸再通过subtract_scalar逐像素减去均值若均值文件为空则直接使用缩放后的像素tiny_dnn::imagefloat resized resize_image(img, width, height); if (!mean.empty()) { tiny_dnn::imagefloat normalized subtract_scalar(resized, mean); *dst normalized.to_vec(); } else { *dst resized.to_vec(); }需要特别指出Caffe 官方cpp_classification的预处理顺序是先减均值、再缩放而此示例的实现是先缩放、再减均值resize_image在subtract_scalar之前调用且没有执行scale缩放系数。如果你期望与 Caffe 官方流程得到完全一致的数值需要留意这一差异。5.4 前向推理与 Top-5 输出auto result net-predict(vec);推理耗时通过clock()统计并打印Elapsed time(s)。结果向量经过partial_sort取前 5 个最大值再用find反查其类别下标最终按标签,置信度的格式输出goldfish, 0.9xxx tench, 0.0xxx ...该输出形式与 Caffe 官方分类示例的 Top-5 展示风格一致便于直接对比转换前后两个框架的预测一致性。六、支持的层类型与转换规则转换器并非全量支持 Caffe 的所有层。从 layer_factory_impl.h 的layer_supported可以确认tiny-dnn 转换器只接受以下 15 种 Caffe 层类型类别支持的 Caffe 层类型tiny-dnn 落点卷积族Convolution、Deconvolutionconv/deconv全连接InnerProductfully-connected池化PoolingMAX / AVEmax-pool/ave-pool归一化LRN、BatchNormlrn/batch-norm激活ReLU、ELU、Sigmoid、TanH、Softmax对应激活层损失SoftmaxWithLoss、SigmoidCrossEntropyLoss转为激活层推理时丢弃损失语义随机化Dropoutdropout测试阶段逐元素运算Powerpower对应关系由create()分发函数与layer_match映射表共同决定其中Pooling会根据pooling_param.pool是MAX还是AVE分别创建最大池化层或平均池化层。layer_skippedlayer_factory_impl.h则会直接跳过以下层Data、EuclideanLoss、Input、HDF5Data、Split、Accuracy。这些层要么是数据装载层要么是只在训练/评估阶段才需要的辅助层对纯推理结构无贡献。caffe_layer_vectorlayer_factory_impl.h负责把 Caffe 的层图解析为单链通过bottom/top名称建立层间连接关系寻找无prev的根节点后沿next指针展开成线性序列并完成旧版 V1 prototxt 到 V2 的自动升级。该结构决定了转换器只支持线性流水线。权重加载的细节同样值得关注全连接层权重按w[i * dst_out_size o] weights.data(curr)进行转置填充layer_factory_impl.h并在层尺寸不匹配时抛出nn_error(layer size mismatch!)卷积层权重支持group分组卷积通过core::connection_table记录连接关系layer_factory_impl.h平均池化层在 tiny-dnn 中是可训练参数的转换时会把权重填为1 / (pool_size_w * pool_size_h)、偏置置 0并调用set_trainable(false)layer_factory_impl.hBatchNorm 层读取 3 个 blob均值、方差、缩放因子并按scale_factor 1 / blob2.data(0)还原真实统计量layer_factory_impl.h支持从 prototxt 中读取xavier、constant、gaussian三种权重初始化器create_filler但权重存在时优先加载权重。转换正确性的自动化验证仓库在 test/test_caffe_converter.h 中提供了针对该转换器的单元测试用内嵌的 prototxt 文本JSON 字符串形式直接调用create_net_from_json其内部复用create_net_from_caffe_prototxt。其中rectangle_input测试验证了非方形输入40×24下 conv→fc 结构的形状推导lenet测试完整覆盖 LeNet 结构逐层断言输入输出形状与层类型例如conv1 28x28x1 → 24x24x20、pool1 24x24x20 → 12x12x20、fc 4*4*50 → 500最终网络深度为 8conv→max-pool→conv→max-pool→fc→relu→fc→softmax。这些测试是理解哪些 prototxt 写法能被正确解析、各层输出形状如何计算的绝佳参考。七、限制与适用范围原文档末尾明确了一条核心限制tiny-dnns converter only supports single input/single output network without branch.结合源码可以展开为三条约束仅支持单输入/单输出caffe_layer_vector通过单一根节点沿next线性展开top多于一个或bottom多于一个的层无法被线性化不支持分支结构如Split、Concat、Eltwise、Slice、Reshape等多路拓扑层不在layer_supported列表内遇到未支持的层类型会抛出nn_error(error: tiny-dnn does not support this layer type: type)仅限推理场景SoftmaxWithLoss、SigmoidCrossEntropyLoss等损失层被转换为纯激活层转换器定位是导入训练产物做前向预测而非复刻 Caffe 训练过程。此外还有几个实操层面的注意点卷积/池化的 padding 只接受validpad0或samepad(kernel-1)/2两种情况其余 pad 值会报nn_error(conv:not supported padding size)非方形卷积核kernel_w ! kernel_h同样不受支持。八、快速上手的完整步骤清单综合以上内容将 Caffe 模型导入 tiny-dnn 并完成一次推理的完整流程如下准备依赖安装 Google protobuf含protoc与 OpenCV生成 protobuf 代码cd tiny_dnn/io/caffe protoc caffe.proto --cpp_out./或直接使用 CMake 构建见 CMakeLists.txt编译链接编译caffe.pb.cc与 caffe_converter.cpp链接 protobuf 与 OpenCV输出可执行文件caffe_converter.bin准备五个文件deploy.prototxt网络结构、*.caffemodel权重、mean.binaryproto均值、labels.txt标签、待分类图片运行按[model-file] [trained-file] [mean-file] [label-file] [img-file]顺序传入五个参数解读输出程序打印推理耗时Elapsed time(s)随后输出置信度最高的 5 个类别及其分值。只要网络是单输入单输出、无分支的线性结构且层类型落在上文的 15 种支持列表内该工具即可把 Caffe 训练成果无缝迁移到 tiny-dnn 的推理体系中。赞分享人工智能深度学习嵌入式【免费下载链接】tiny-dnnheader only, dependency-free deep learning framework in C14项目地址https://gitcode.com/gh_mirrors/ti/tiny-dnn点击查看免费下载相关推荐终极指南如何在tiny-dnn中轻松导入Caffe模型终极指南如何在tiny dnn中轻松导入Caffe模型 想要将现有的Caffe模型快速迁移到轻量级的tiny dnn框架中吗 本教程将手把手教你完成Ca人工智能深度学习嵌入式英灵神殿游戏增强模组怎么选ValheimPlus 用 3 个场景让建造与联机一步到位英灵神殿游戏增强模组怎么选ValheimPlus 用 3 个场景让建造与联机一步到位 凌晨一点你又一次拆掉那面歪了三度的墙。45 度旋转、说满就满的背包、联游戏开发Chainer 的 Caffe 模型互操作CaffeFunction 导入预训练模型与 export() 导出 Caffe 格式Chainer 的 Caffe 模型互操作CaffeFunction 导入预训练模型与 export 导出 Caffe 格式 本文围绕 Chainer 官方参深度学习机器学习上一篇3分钟上手DBeaver数据透视表让查询结果自动高亮关键业务数据下一篇cli3/cli扩展兼容性测试自动化验证不同Spotify版本支持创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进