☰
tiny-dnn v0.0.1 → v0.1.0 迁移指南:训练 API 的演进与升级实践
2026/10/10 2:35:03 网站建设 项目流程
  • 人工智能
  • 深度学习
  • 嵌入式

【免费下载链接】tiny-dnn

header only, dependency-free deep learning framework in C++14

项目地址:https://gitcode.com/gh_mirrors/ti/tiny-dnn
点击查看免费下载

导读

本文基于 docs/update_log/v0_0_1-to-v0_1_0.md 整理 tiny-dnn 从 v0.0.1 升级到 v0.1.0 时发生的三处核心训练 API 变更:损失函数与优化器从网络模板参数改为 train/fit 的实参、回归(fit)与分类(train)训练接口的正式分离、以及权重重新初始化的默认行为反转。读完本文,你将能够把 v0.0.1 时代的训练代码无缝迁移到 v0.1.0,并理解这些变更背后的源码设计逻辑。


一、升级背景:v0.1.0 为什么动训练 API

在 v0.0.1 中,tiny-dnn 的network是一个以损失函数类型和优化算法类型为模板参数的类,例如network<mse, adagrad>。这种设计的缺点是:损失函数与优化器在编译期被"焊死"进网络类型,同一个网络对象无法在运行期切换损失函数或优化器,组合爆炸也使得类型签名越来越复杂。

v0.1.0 改为network<sequential>/network<graph>只描述网络拓扑,损失函数(Error)与优化器(Optimizer)全部下沉为train/fit的模板参数与函数实参。从 tiny_dnn/network.h 的源码可以看到,network类模板如今只有一个NetType参数,而train/fit均为成员函数模板(template <typename Error, typename Optimizer>)。


二、变更一:损失函数与优化器从模板参数变为实参

v0.0.1 的旧写法

在 v0.0.1 中,损失函数与优化算法是network的模板参数,训练直接调用train:

// v0.0.1 network<mse, adagrad> net; net.train(x_data, y_label, n_batch, n_epoch);

v0.1.0 的新写法

从 v0.1.0 起,网络类型只保留拓扑信息,损失函数通过模板参数传入fit/train,优化器作为第一个实参传入:

// v0.1.0 network<sequential> net; adagrad opt; net.fit<mse>(opt, x_data, y_label, n_batch, n_epoch);

源码印证

在 tiny_dnn/network.h 中,类模板声明为template <typename NetType> class network,NetType仅用于区分sequential与graph两种拓扑(源码注释明确说明:sequential 表示无分支/合并的网络,graph 用于有分支/合并的网络)。而 tiny_dnn/network.h 给出的train简化重载签名如下:

template <typename Error, typename Optimizer> bool train(Optimizer &optimizer, const std::vector<vec_t> &inputs, const std::vector<label_t> &class_labels, size_t batch_size = 1, int epoch = 1);

可见损失类型Error是模板参数(如mse、cross_entropy),优化器Optimizer同时是模板参数和按引用传入的实参对象。

配套要点:

  • 损失函数定义在 tiny_dnn/lossfunctions/loss_function.h 中,v0.1.0 提供mse、absolute、absolute_eps、cross_entropy、cross_entropy_multiclass等实现。每个损失类静态实现f(损失值)与df(梯度)两个方法,例如mse的f返回均方误差、df返回2*(y-t)/n。
  • 优化器定义在 tiny_dnn/optimizers/optimizer.h 中,均继承自基类optimizer(virtual void update(const vec_t &dW, vec_t &W, bool parallelize) = 0;),并提供reset()用于训练前清理状态。内置实现包括adagrad(默认学习率 0.01)、RMSprop(默认学习率 0.0001、衰减 0.99)、adam(默认学习率 0.001、b1=0.9、b2=0.999)等。由于优化器现在是普通对象,你可以为同一网络在不同训练阶段传入不同优化器实例。

三、变更二:回归与分类训练接口正式分离(fit vs train)

v0.0.1 的痛点

在 v0.0.1 中,回归与分类共用同一个trainAPI,仅靠数据形状隐式区分:

// v0.0.1 net.train(x_data, y_data, n_batch, n_epoch); // 回归 net.train(x_data, y_label, n_batch, n_epoch); // 分类

v0.1.0 的分离

从 v0.1.0 起,两者被明确拆分为fit与train:

// v0.1.0 net.fit<mse>(opt, x_data, y_data, n_batch, n_epoch); // 回归:目标为连续输出向量 net.train<mse>(opt, x_data, y_label, n_batch, n_epoch); // 分类:目标为类别标签 id

源码印证

在 tiny_dnn/network.h 中,train的文档注释直接说明了二者差异:"The difference between train and fit method is how to specify desired output. This method takes label_t argument and convert to target vector automatically."(train 与 fit 的区别在于指定目标输出的方式:train 接收label_t标签并自动转换为目标向量)。

  • train(分类)接收std::vector<label_t> class_labels,要求标签从 0 开始编号(0-origin),且最后一层输出维度必须大于等于标签类别数(见 tiny_dnn/network.h)。它内部会把标签归一化后转交给fit完成实际训练。
  • fit(回归)接收与网络输入同形状的desired_outputs连续目标向量(见 tiny_dnn/network.h 的说明与std::vector<vec_t>/std::vector<tensor_t>两种写法示例)。
  • 为了兼容旧代码,tiny_dnn/network.h 中仍保留了一个接收std::vector<vec_t>目标的train重载,但其文档明确标注@deprecated use fit instead for regression task(已废弃,回归请改用 fit),并直接转发给fit实现。

实战示例:仓库中的 examples/sinus_fit/sinus_fit.cpp 即用net.fit<tiny_dnn::mse>(opt, X, sinusX, batch_size, epochs, ...)训练正弦函数拟合网络,正是回归任务的规范写法;而 examples/mnist/test.cpp 等分类示例则使用net.train<cross_entropy>(opt, ...)风格的分类接口。


四、变更三:权重重新初始化的默认行为反转

v0.0.1 的默认行为:自动重置权重

在 v0.0.1 中,train默认以reset_weights=true运行,这意味着即使你从磁盘加载了已训练好的模型,train也会在训练前自动把权重打乱重置,导致加载的权重白费:

// v0.0.1 std::ifstream is("model"); is >> net; net.train(x_data, y_data, n_batch, n_epoch); // 加载的权重被自动重置! net.train(x_data, y_data, n_batch, n_epoch); // 上次训练得到的参数再次丢失

v0.1.0 的默认行为:保留现有权重

从 v0.1.0 起,reset_weights的默认值改为false,训练默认保留当前网络权重,加载模型后可以接着上次的训练继续:

// v0.1.0 std::ifstream is("model"); is >> net; net.train<mse>(opt, x_data, y_data, n_batch, n_epoch); // 保留已加载的权重 net.train<mse>(opt, x_data, y_data, n_batch, n_epoch); // 从上一次训练状态继续 // 未加载模型直接训练时,权重会自动初始化 net2.train<mse>(opt, x_data, y_data, n_batch, n_epoch);

源码印证

在 tiny_dnn/network.h 的完整版train签名中,reset_weights参数的默认值正是false:

template <typename Error, typename Optimizer, typename OnBatchEnumerate, typename OnEpochEnumerate> bool train(Optimizer &optimizer, const std::vector<vec_t> &inputs, const std::vector<label_t> &class_labels, size_t batch_size, int epoch, OnBatchEnumerate on_batch_enumerate, OnEpochEnumerate on_epoch_enumerate, const bool reset_weights = false, const int n_threads = CNN_TASK_SIZE, const std::vector<vec_t> &t_cost = std::vector<vec_t>());

fit的完整版签名同样以const bool reset_weights = false为默认值(见 tiny_dnn/network.h)。训练循环最终会调用net_.setup(reset_weights)(见 tiny_dnn/network.h):setup(true)会重新初始化各层权重,setup(false)则保持已有参数。

此外,如果你确实想主动清零并重新初始化权重,v0.1.0 提供了显式接口void init_weight() { net_.setup(true); }(见 tiny_dnn/network.h),不再需要依赖训练时的隐式重置。

注:原文档中"v0.1.0"示例代码把train误写为trian,本文已按实际 API 更正为train。


五、迁移核对清单:从 v0.0.1 升级到 v0.1.0

升级现有代码时,请对照以下清单逐项检查:

检查项v0.0.1 写法v0.1.0 写法
网络类型声明network<mse, adagrad> net;network<sequential> net;(拓扑复杂用network<graph>)
优化器准备内嵌于网络类型adagrad opt;独立声明,传入训练函数
损失函数指定内嵌于网络类型作为train/fit的模板参数,如net.train<mse>(opt, ...)
回归训练net.train(x, y, ...)net.fit<mse>(opt, x, y, ...)
分类训练net.train(x, label, ...)net.train<mse>(opt, x, label, ...)
加载模型后继续训练默认重置权重,无法续训默认保留权重,可直接续训;需要重置时传true或调用init_weight()

容易踩的坑:

  1. 回归任务误用train:v0.1.0 中train期望label_t标签并自动转换为 one-hot 风格目标向量;回归请务必使用fit传入连续目标值(旧版train回归重载已被标记@deprecated)。
  2. 分类时输出维度不足:train要求最后一层输出维度 ≥ 标签类别数(标签从 0 编号),否则目标向量无法正确构造。
  3. 忘记传递优化器对象:v0.1.0 的train/fit第一参必须是一个优化器实例(如adagrad、RMSprop、adam),它按引用传入并在训练中被实际调用。
  4. 断点续训语义变化:v0.0.1 中加载模型后一训练就丢权重,v0.1.0 中默认续训——若你依赖旧的"自动重置"行为,请显式传reset_weights = true。

六、深入:train/fit 完整参数签名与扩展能力

v0.1.0 的训练接口除了上述核心参数外,还提供了一组进阶能力(均在 tiny_dnn/network.h 中定义),供需要细粒度控制的场景使用:

template <typename Error, typename Optimizer, typename OnBatchEnumerate, typename OnEpochEnumerate> bool fit(Optimizer &optimizer, const std::vector<T> &inputs, const std::vector<U> &desired_outputs, size_t batch_size, // 每个 minibatch 的样本数 int epoch, // 训练轮数 OnBatchEnumerate on_batch_enumerate, // 每个 minibatch 结束回调 OnEpochEnumerate on_epoch_enumerate, // 每个 epoch 结束回调 const bool reset_weights = false, // 是否重置权重 const int n_threads = CNN_TASK_SIZE, // 并行任务数 const std::vector<U> &t_cost = std::vector<U>()); // 各样本的自定义代价权重
  • 回调机制:on_batch_enumerate与on_epoch_enumerate让外部可以在每个 minibatch / 每个 epoch 结束时接管控制流(例如打印日志、记录中间模型、提前终止)。不关心回调时可传nop(默认重载已经替你填好)。
  • 并行训练:n_threads控制训练并行度,默认取CNN_TASK_SIZE;在 tiny_dnn/network.h 的train_once中可以看到,batch 大小为 1 时走单样本路径,否则走train_onebatch批量路径。
  • 自定义代价(t_cost):允许为每个训练样本指定不同的损失权重,缺省时所有样本代价相同。
  • 输入形状:fit既接受std::vector<vec_t>(普通向量列表),也接受std::vector<tensor_t>(tiny_dnn/network.h 的官方注释示例展示了两种写法),内部通过normalize_tensor统一为张量格式。

从源码结构看,train(分类)最终也是把label_t标签归一化后转调fit(见 tiny_dnn/network.h),因此fit是 v0.1.0 训练体系的真正核心实现,train只是它的分类语义包装层。


七、继续深入仓库

  • 迁移说明原文:docs/update_log/v0_0_1-to-v0_1_0.md(本文依据的官方变更记录)
  • 训练 API 完整实现:tiny_dnn/network.h
  • 损失函数清单:tiny_dnn/lossfunctions/loss_function.h
  • 优化器实现:tiny_dnn/optimizers/optimizer.h
  • 回归实战范例:examples/sinus_fit/sinus_fit.cpp
  • 分类实战范例:examples/mnist/test.cpp、examples/mnist/train.cpp
  • 官方入门教程:docs/getting_started/Getting-started.md
  • 人工智能
  • 深度学习
  • 嵌入式

【免费下载链接】tiny-dnn

header only, dependency-free deep learning framework in C++14

项目地址:https://gitcode.com/gh_mirrors/ti/tiny-dnn
点击查看免费下载

相关推荐

上一篇:Android性能优化实测:Uperf Game Turbo 五档CPU调频模式与安装配置全解
下一篇:Zotero 插件市场完整指南:三步把插件浏览、安装与更新搬进 Zotero

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询