tiny-dnn 实战:用 LeNet-5 完成 MNIST 手写数字识别(训练 + 预测全流程)

发布时间:2026/10/10 5:07:29
tiny-dnn 实战:用 LeNet-5 完成 MNIST 手写数字识别(训练 + 预测全流程) 人工智能深度学习嵌入式【免费下载链接】tiny-dnnheader only, dependency-free deep learning framework in C14项目地址https://gitcode.com/gh_mirrors/ti/tiny-dnn点击查看免费下载本篇技术指南以 tiny-dnn 官方 MNIST 示例为主线带你用纯 C14、仅头文件的方式从零构建一个 LeNet-5 卷积网络完成手写数字数据集的加载、训练、回调监控、模型保存/加载以及推理预测的完整闭环。读完本文你将掌握networksequential的层叠式构图、connection_table稀疏连接表的使用、MNIST idx 数据解析、train/test/predict的调用方式并能把训练好的模型复用到命令行 OCR 工具中。背景为什么选择 LeNet-5MNIST 是深度学习领域最经典的手写数字数据集每张图片为 28×28 的灰度图像素值范围为 [0, 255]共 10 个类别09。LeNet-5 由 Y. LeCun 于 1998 年提出[LeCun1998]见文末参考文献其卷积层C→ 子采样层S→ 全连接层F的经典结构被证明在手写数字识别上非常有效也是理解 CNN 原理的最佳入门模型。tiny-dnn 示例在标准 LeNet-5 基础上做了一处简化将最后一层的 RBF径向基层替换为普通的全连接层fully_connected_layer(120, 10, true)这样既保持了网络容量又让模型更易训练与序列化。完整示例代码见 examples/mnist/train.cpp 与 examples/mnist/test.cpp。构建模型network operator 的链式构图tiny-dnn 采用operator从输入到输出逐层叠加的方式构造网络。首先需要指定优化器学习算法再依次添加各层// specify loss-function and learning strategy networksequential nn; adagrad optimizer; nn convolutional_layer(32, 32, 5, 1, 6, // C1, 132x32-in, 628x28-out padding::valid, true, 1, 1, backend_type) tanh_layer(28, 28, 6) average_pooling_layer(28, 28, 6, 2) // S2, 628x28-in, 614x14-out tanh_layer(14, 14, 6) convolutional_layer(14, 14, 5, 6, 16, // C3, 614x14-in, 1610x10-out connection_table(tbl, 6, 16), padding::valid, true, 1, 1, backend_type) tanh_layer(10, 10, 16) average_pooling_layer(10, 10, 16, 2) // S4, 1610x10-in, 165x5-out tanh_layer(5, 5, 16) convolutional_layer(5, 5, 5, 16, 120, // C5, 165x5-in, 1201x1-out padding::valid, true, 1, 1, backend_type) tanh_layer(1, 1, 120) fully_connected_layer(120, 10, true, // F6, 120-in, 10-out backend_type) tanh_layer(10);各层尺寸与 LeNet-5 对应关系如下注释中的C为卷积、S为子采样、F为全连接层输入输出说明C1 卷积132×32628×285×5 卷积核valid 填充S2 平均池化628×28614×142×2 下采样C3 卷积614×141610×10使用稀疏连接表tblS4 平均池化1610×10165×52×2 下采样C5 卷积165×51201×15×5 卷积核F6 全连接12010输出 10 类得分输出激活1010tanh 激活注意convolutional_layer构造参数依次为(输入宽, 输入高, 核宽/核高, 输入通道数, 输出通道数, padding, 是否带偏置, 步长, 步长, backend_type)。示例中选用padding::valid即不做补零因此 32×32 经 5×5 卷积后得到 28×28与注释吻合。稀疏连接表 connection_table复刻 LeNet 的 S2→C3 稀疏性原版 LeNet-5 在 S2 与 C3 之间采用了**部分连接sparsity**策略C3 的每个特征图只连接到 S2 特征图的一个子集使各特征图获得不同的输入组合从而让它们成为互补的特征提取器。tiny-dnn 通过connection_table结构支持这一特性其构造参数是一个bool表与输入/输出特征图数量// connection table, see Table 1 in [LeCun1998] #define O true #define X false static const bool tbl[] { O, X, X, X, O, O, O, X, X, O, O, O, O, X, O, O, O, O, X, X, X, O, O, O, X, X, O, O, O, O, X, O, O, O, O, X, X, X, O, O, O, X, X, O, X, O, O, O, X, O, O, O, X, X, O, O, O, O, X, X, O, X, O, O, X, X, O, O, O, X, X, O, O, O, O, X, O, O, X, O, X, X, X, O, O, O, X, X, O, O, O, O, X, O, O, O }; #undef O #undef X表中每一行代表 C3 的一个输出特征图共 16 行每一列代表 S2 的一个输入特征图共 6 列true表示该输入参与此输出的计算。将该表传入 C3 卷积层convolutional_layer(14, 14, 5, 6, 16, connection_table(tbl, 6, 16), // 6 个输入特征图、16 个输出特征图 padding::valid, true, 1, 1, backend_type)connection_table结构定义于 tiny_dnn/core/params/conv_params.h与卷积参数一起构成conv_params底层实现会依据该表决定前向与反向传播中实际参与计算的连接从而在保持结构稀疏的同时减少不必要的计算量。关于 backend_type示例代码中通过core::default_engine()选择计算后端注释明确说明默认使用backend_t::tiny_dnn纯 C 实现除非以-DUSE_AVXON编译且设备支持 AVX 指令集才会切换到 AVX 后端。更完整的命令行版本examples/mnist/train.cpp 当前实现支持通过--backend_type参数在internal、nnpack、libdnn、avx、opencl之间选择。加载数据集parse_mnist_images / parse_mnist_labelstiny-dnn 原生支持 MNIST 的 idx 二进制格式因此加载数据只需调用两个解析函数// load MNIST dataset std::vectorlabel_t train_labels, test_labels; std::vectorvec_t train_images, test_images; parse_mnist_labels(data_dir_path /train-labels.idx1-ubyte, train_labels); parse_mnist_images(data_dir_path /train-images.idx3-ubyte, train_images, -1.0, 1.0, 2, 2); parse_mnist_labels(data_dir_path /t10k-labels.idx1-ubyte, test_labels); parse_mnist_images(data_dir_path /t10k-images.idx3-ubyte, test_images, -1.0, 1.0, 2, 2);关键点数据集预处理。原始 MNIST 图片是 28×28、居中、像素值 [0,255] 的灰度图。上述调用将像素值线性缩放到 [-1.0, 1.0]并各增加 2px 边框使每张图片变为 32×32——这正是网络第一层convolutional_layer(32, 32, ...)输入为 1024 个值的原因。边框填充值为scale_min即 -1.0可视为一种简单的零填充式预处理。从源码实现看tiny_dnn/io/mnist_parser.hparse_mnist_images的签名与行为如下parse_mnist_images(const std::string image_file, std::vectorvec_t *images, float_t scale_min, // 输出最小值如 -1.0 float_t scale_max, // 输出最大值如 1.0 int x_padding, // 左右边框宽度 int y_padding); // 上下边框宽度内部实现值得说明的几点端序处理MNIST 数据为大端big-endian格式解析器读取magic_number、num_items、num_rows、num_cols头部后在小端机器上调用reverse_endian进行字节序反转tiny_dnn/io/mnist_parser.h合法性校验标签文件要求magic_number 0x00000801、图像文件要求magic_number 0x00000803否则抛出nn_error同时检查x_padding/y_padding非负、scale_max scale_min缩放公式每个像素按pixel/255 * (scale_max - scale_min) scale_min映射输出尺寸为(W2*x_padding) × (H2*y_padding)边框像素填scale_min。仓库根目录的 data/ 目录已内置了 MNIST 原始四件套文件train-images.idx3-ubyte、train-labels.idx1-ubyte、t10k-images.idx3-ubyte、t10k-labels.idx1-ubyte运行示例时可直接将其路径作为数据目录参数传入。训练过程与回调机制逐 epoch 监控准确率tiny-dnn 的network::train接受回调函数方便在每个 epoch 结束时查看测试集识别率、训练耗时与进度条。由于回调使用 C11 lambda 按引用捕获可以直接访问网络、测试数据等局部变量progress_display disp(static_castunsigned long(train_images.size())); timer t; int minibatch_size 10; int num_epochs 30; optimizer.alpha * static_casttiny_dnn::float_t(std::sqrt(minibatch_size)); // create callback auto on_enumerate_epoch [](){ std::cout t.elapsed() s elapsed. std::endl; tiny_dnn::result res nn.test(test_images, test_labels); std::cout res.num_success / res.num_total std::endl; disp.restart(static_castunsigned long(train_images.size())); t.restart(); }; auto on_enumerate_minibatch [](){ disp minibatch_size; }; // training nn.trainmse(optimizer, train_images, train_labels, minibatch_size, num_epochs, on_enumerate_minibatch, on_enumerate_epoch);逐项拆解optimizer.alpha * sqrt(minibatch_size)将 AdaGrad 学习率按小批量大小的平方根缩放这是 SGD 类优化器常见的学习率补偿技巧更完整的 examples/mnist/train.cpp 中将其限制为min(4, sqrt(minibatch)*learning_rate)防止学习率过大on_enumerate_epoch每完成一个 epoch 打印耗时并用nn.test(test_images, test_labels)在测试集上统计识别率返回result含num_success/num_total随后重置进度条与计时器on_enumerate_minibatch每处理一个小批量就推进进度条nn.trainmse模板参数mse指定损失函数为均方误差损失函数定义于 tiny_dnn/lossfunctions/loss_function.h。训练结束后nn.test(...).print_detail(std::cout)会输出每个类别的详细混淆统计。当前 examples/mnist/train.cpp 的完整版还通过命令行参数暴露了--data_path、--learning_rate、--epochs、--minibatch_size、--backend_type五个配置项并对参数做了合法性校验学习率须大于 0、epochs 须大于 0、minibatch_size 须在 (0, 60000] 区间、data_path必填运行方式./example_mnist_train --data_path ../data --learning_rate 1 --epochs 30 --minibatch_size 16 --backend_type internal模型保存与加载一行代码的二进制序列化训练完成后使用network::save(filename)将整个模型网络结构 训练好的权重写入二进制文件推理阶段用network::load(filename)恢复nn.save(LeNet-model); nn.load(LeNet-model);对应的成员函数声明位于 tiny_dnn/network.h底层通过 Cereal 序列化库实现仓库内嵌于 cereal/保存后会在当前目录生成LeNet-model二进制文件。示例注释提到预训练权重也可从外部下载但请以本仓库 examples/mnist/readme.md 原文为准自行核对来源更稳妥的做法是直接运行示例训练并保存自己的模型。提示由于每个输入图片为 32×32 共 1024 个值网络第一层维度必须与之匹配保存/加载时模型结构与训练时完全一致否则load会失败。把模型用起来CUI 手写数字 OCR 工具examples/mnist/test.cpp演示了如何使用已保存的模型进行推理并输出前 3 名候选类别及其置信度。核心流程分三步第一步加载模型。networksequential nn; nn.load(dictionary);第二步图片预处理。将任意灰度图缩放到 32×32并把像素值映射到 [-1.0, 1.0]void convert_image(const std::string imagefilename, double minv, double maxv, int w, int h, vec_t data) { image img(imagefilename, image_type::grayscale); image resized resize_image(img, w, h); // mnist dataset is white on black, so negate required std::transform(resized.begin(), resized.end(), std::back_inserter(data), { return (255 - c) * (maxv - minv) / 255.0 minv; }); }这里有一个容易踩的坑MNIST 是黑底白字而普通扫描/截图往往是白底黑字因此 lambda 中用(255 - c)做了像素反色negate再缩放到 [-1.0, 1.0]。第三步推理并排序输出auto res nn.predict(data); vectorpairdouble, int scores; // rescale tanh 输出到 0-100 的置信度 for (int i 0; i 10; i) scores.emplace_back(rescaletanh(res[i]), i); sort(scores.begin(), scores.end(), greaterpairdouble, int()); for (int i 0; i 3; i) cout scores[i].second , scores[i].first endl;由于输出层激活函数是 tanh其输出范围在 [-1, 1]rescale模板函数将其映射到 0100 的百分比区间便于理解与展示。对一张4的手写图片文档中给出的典型输出为4,78.1403 7,33.5718 8,14.0017即网络以约 78.14% 的置信度判定该图为数字 4。文档同时提示置信度在不同机器上可能略有差异。可视化层输出与卷积核该工具还顺带演示了 tiny-dnn 的可视化能力遍历每一层调用output_to_image()保存为layer_i.png并对第一层卷积调用weight_to_image()保存滤波器形状到weights.png。这些图片可用于观察网络学到了什么样的特征滤波器、各层的激活模式如何逐层抽象——第一张图是 C1 层的 6 个学习到的 5×5 卷积核其余是各层输出特征图。构建与运行CMake 集成方式MNIST 三个示例训练、测试、量化训练由 examples/CMakeLists.txt 统一注册为可执行目标example_mnist_train← examples/mnist/train.cppexample_mnist_test← examples/mnist/test.cppexample_mnist_quantized_train← examples/mnist/quantized.cpp注意这三者均位于if(USE_SERIALIZER)分支内即构建时需要启用序列化选项USE_SERIALIZER因为save/load依赖 Cereal 序列化库。example_mnist_quantized_train提供了量化版本quantized_convolutional_layer、quantized_fully_connected_layer见 tiny_dnn/layers/quantized_convolutional_layer.h展示了以 8-bit 整数运算做量化的同类 LeNet 训练流程可作为部署低精度模型的延伸参考。运行顺序建议# 1. 训练并保存模型数据目录指向仓库根目录下的 data/ ./example_mnist_train ../data # 2. 用一张手写数字图片做 OCR 推理 ./example_mnist_test your_digit_image.bmp训练脚本main中的用法提示为path_to_data (example:../data)即从examples/目录执行时数据目录用../data对应仓库根目录的 data/ 数据集。小结通过本文你已经走通了 tiny-dnn 上手 MNIST 的全部关键路径构图用operator链式叠加卷积、池化、全连接与激活层复刻 LeNet-5稀疏连接用connection_table复现 S2→C3 的部分连接结构数据装载用parse_mnist_images/parse_mnist_labels处理 idx 格式并完成缩放与扩边训练监控通过 epoch/minibatch 回调实时观测损失收敛与测试准确率序列化save/load实现模型持久化推理落地用predict 反色预处理构建可用的 OCR 工具并可视化层输出与卷积核。这套流程同样适用于把 tiny-dnn 集成到其他图像识别场景只需替换数据解析与预处理保持网络输入尺寸与预处理一致即可。相关数据格式说明可进一步查阅 tiny_dnn/io/mnist_parser.h 的注释与仓库内的数据文件。参考文献[LeCun1998]LeCun, Yann, et al. Gradient-based learning applied to document recognition.Proceedings of the IEEE86.11 (1998): 2278-2324.LeNet-5 原始论文连接表 Table 1 与本文档的网络结构均来源于此。赞分享人工智能深度学习嵌入式【免费下载链接】tiny-dnnheader only, dependency-free deep learning framework in C14项目地址https://gitcode.com/gh_mirrors/ti/tiny-dnn点击查看免费下载相关推荐ReactNativeOne双平台适配技巧Android与iOS兼容性处理方案ReactNativeOne双平台适配技巧Android与iOS兼容性处理方案 ReactNativeOne作为基于React Native开发的高仿「ONEfwupd完全指南10分钟学会Linux固件更新fwupd完全指南10分钟学会Linux固件更新 fwupd是一个系统守护进程允许会话软件更新固件是Linux系统中管理和更新设备固件的重要工具。通过fw物联网Caffe 实战在 MNIST 上训练 LeNet 手写数字识别模型从数据准备到训练部署全流程Caffe 实战在 MNIST 上训练 LeNet 手写数字识别模型从数据准备到训练部署全流程 本文以 Caffe 官方 MNIST 示例为线索完整讲解深度学习计算机视觉上一篇推荐开源项目PostgreSQL 分区管理器 — pg_partman下一篇开源项目推荐Open Event - 全方位的活动管理平台创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询