- 教程
- 文档
- 示例工程
【免费下载链接】website-archive
Archive of the Coding Train website (first version)
本篇技术文章基于 Coding Train ml5.js 入门教程(ML5 Beginners Guide)第 6.2 课「Save Neural Network Training Data」的文档页与其配套示例代码展开,讲解如何将 ml5.js 神经网络在浏览器中实时采集的训练数据保存为 JSON 文件、并在后续会话中重新载入继续训练。读完后,你将掌握model.saveData()/model.loadData()的完整工作流、训练数据落盘文件的实际 JSON 结构,以及数据持久化与模型持久化(第 6.3 课)的边界与选型思路。
课程定位:6.2 在 ml5.js 教程系列中的位置
本课文档页为 _learning/ml5/6.2-save-data.md,其 Jekyll frontmatter 记录了课程元信息:
title: "ml5.js: Save Neural Network Training Data" video_number: 6.2 date: 2019-12-05 video_id: q6cwxORPDo8 web_editor: 4fxtImOMz repository: ml5/6.2_save_data其中repository字段指向配套代码在仓库中的实际位置,即 learning/ml5/6.2_save_data/P5/ 目录。该系列围绕“用鼠标采集数据训练一个分类神经网络、把预测结果映射为音乐音符”这一贯穿性案例展开,各环节职责如下:
| 课程 | 目录 | 解决的问题 |
|---|---|---|
| 6.1 Train Your Own | learning/ml5/6.1_train_your_own/P5/ | 用model.addData()实时采集数据并训练、预测 |
| 6.2 Save Data(本课) | learning/ml5/6.2_save_data/P5/ | 用saveData()/loadData()把采集到的数据持久化为 JSON |
| 6.3 Save Model | learning/ml5/6.3_save_model/P5/ | 用model.save()/model.load()持久化已训练的模型权重 |
6.1 课的实现(见 6.1 的 sketch.js)中,所有样本只存在于内存:mousePressed里每次点击调用model.addData(inputs, target)把坐标与标签存入模型内部数据缓存。这个设计存在一个明显的短板——刷新页面即丢失全部已采集数据,需要反复手动标注。6.2 课正是针对这一痛点,在 6.1 的基础上增加了两个 API 调用:
- 按
s键时:model.saveData('mouse-notes'),把当前内存数据写成mouse-notes.json; setup()时:model.loadData('mouse-notes.json', dataLoaded),如果本地已有历史数据文件,加载完成后自动进入训练流程,免去重复采集。
完整示例走读
示例入口是 index.html,通过 CDN 引入 p5.js 1.4.1、p5.sound 与 ml5 0.4.2 三个依赖:
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.1/lib/p5.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/p5@1.4.1/lib/addons/p5.sound.min.js"></script> <script src="https://unpkg.com/ml5@0.4.2/dist/ml5.min.js"></script>主逻辑全部位于 sketch.js,围绕一个三状态状态机运行:collection(采集)→training(训练)→prediction(预测),由按键与鼠标事件驱动切换。
模型创建与配置项
setup()中创建网络实例,配置项完整如下(见 sketch.js 第 38–47 行):
let options = { inputs: ['x', 'y'], // 两个输入特征:鼠标 x、y 坐标 outputs: ['label'], // 输出标签:一个音符字母 task: 'classification', // 分类任务 debug: 'true', learningRate: 0.5 // 相比 6.1 新增的超参数 }; model = ml5.neuralNetwork(options); model.loadData('mouse-notes.json', dataLoaded);与 6.1 相比有两处关键变化:一是显式传入learningRate: 0.5控制训练步长;二是在建网后立即调用model.loadData('mouse-notes.json', dataLoaded)尝试载入历史数据。注意这里采用“尽力加载”策略——loadData是异步的,若文件不存在(首次运行),后续dataLoaded回调不会执行,sketch 会静默停留在collection状态等待手动采集,因此代码没有为“文件缺失”写单独的分支。
数据载入回调:自动进入训练
dataLoaded()回调(第 51–73 行)在历史数据就绪后被调用,做了三件事:
function dataLoaded() { console.log(model.data); let data = model.data.data.raw; // 读取原始样本数组 for (let i = 0; i < data.length; i++) { let inputs = data[i].xs; // {x, y} let target = data[i].ys; // {label} // 把历史数据画成“圆 + 标签”铺在画布上,方便检查 stroke(0); noFill(); ellipse(inputs.x, inputs.y, 24); fill(0); noStroke(); textAlign(CENTER, CENTER); text(target.label, inputs.x, inputs.y); } state = 'training'; model.normalizeData(); let options = { epochs: 200 }; model.train(options, whileTraining, finishedTraining); }可以看到 ml5 内部数据的访问结构是model.data.data.raw,每条样本形如{ xs: {...inputs}, ys: {...outputs} }——这正是后面 JSON 文件格式的来源。回调中先把历史数据全部可视化(用户能直观确认“载入成功、数据长什么样”),随即调用model.normalizeData()做特征归一化,再以epochs: 200启动训练;训练完成的回调finishedTraining()把状态机切到prediction。
保存数据的触发点:saveData
按键处理keyPressed()(第 75–89 行)集中了三个交互入口:
function keyPressed() { if (key == 't') { state = 'training'; model.normalizeData(); model.train({ epochs: 200 }, whileTraining, finishedTraining); } else if (key == 's') { model.saveData('mouse-notes'); // 保存当前内存中的训练数据 } else { targetLabel = key.toUpperCase(); // 字母键 = 切换要采集的标签 } }model.saveData('mouse-notes')只接收一个文件名参数(不含扩展名),调用后浏览器会触发下载/写入mouse-notes.json。这就是本课的核心 API:把model.addData()累积在内存里的样本一次性固化到磁盘。t键则允许在随时手动触发训练(采集阶段新增样本后重新训练)。
采集与预测
mousePressed()根据当前状态分发行为(第 100–124 行):
function mousePressed() { let inputs = { x: mouseX, y: mouseY }; if (state == 'collection') { model.addData({ x: mouseX, y: mouseY }, { label: targetLabel }); // 画标记并播放对应音符(p5.Oscillator + p5.Envelope 包络) } else if (state == 'prediction') { model.classify(inputs, gotResults); } }预测分支调用model.classify(),回调gotResults(error, results)校验错误、绘制results[0].label并把预测标签映射为音符播放。示例的“音频反馈”由 p5.sound 实现:p5.Oscillator正弦波叠加p5.Envelope(setADSR(0.05, 0.1, 0.5, 1)、setRange(1.2, 0)),七个字母对应 C–B 七个频率(notes对象中 A 为 440.0 Hz)。这部分与机器学习逻辑无关,只是给预测结果一个可听感的反馈。
训练数据落盘格式:mouse-notes.json 实测
仓库中已提交了一份真实运行产物 mouse-notes.json(约 23.7 KB),可直接用于验证saveData的输出格式。顶层结构是一个data数组:
{ "data": [ { "xs": { "x": 57, "y": 32 }, "ys": { "label": "C" } }, { "xs": { "x": 56, "y": 56 }, "ys": { "label": "C" } }, { "xs": { "x": 12, "y": 232 }, "ys": { "label": "A" } } ] }对这份文件做逐条统计,共包含386 条样本,各标签分布如下:
| 标签 | A | B | C | D | E | F | G |
|---|---|---|---|---|---|---|---|
| 样本数 | 68 | 56 | 55 | 43 | 53 | 64 | 47 |
每条记录与 6.2 示例中addData(inputs, target)的实参一一对应:xs是{x, y}两个输入特征(坐标值域在 400×400 画布内),ys是{label}分类目标。顶层包裹一层{"data": [...]}这一点,可以从仓库中另一课自带的 ml5 0.4.x 压缩库源码 7.3_pose_regression/P5/lib/ml5.min.js 得到印证——其中saveData的实现逻辑为:先取this.data.raw原始样本数组并包进{ data: ... }对象,序列化为 JSON 后通过saveBlob以text/plain类型写出,文件名为传入参数加.json后缀;若未传文件名,则会用“年-月-日_时-分-秒”的时间戳作为默认文件名。这解释了为什么mouse-notes.json的结构与model.data.data.raw的访问路径完全吻合:磁盘文件就是内存中 raw 数据数组的直接序列化。
运行与验证方式
运行步骤(以仓库中的文件为准,依赖版本与 index.html 一致:p5 1.4.1 + p5.sound + ml5 0.4.2):
- 在
learning/ml5/6.2_save_data/P5/目录下启动任意静态服务器(loadData需要以 HTTP 方式读取本地 JSON,直接双击index.html走file://协议时脚本读取文件的行为可能受限,从源码结构看按文件名加载会走网络请求路径,建议始终经静态服务运行); - 首次运行:画布为空,按字母键(C–G 均可,
keyPressed中取key.toUpperCase())设定标签,点击画布采集数据,每次点击会画出“圆 + 标签”并播放对应音符; - 按
s键调用model.saveData('mouse-notes'),得到mouse-notes.json(可替换/对照仓库中已提交的同名文件); - 按
t键启动训练,控制台打印 epoch 进度(whileTraining(epoch, loss));训练完成后进入prediction状态,点击画布即可看到分类预测结果与音符反馈; - 刷新页面再次运行:
setup()中的loadData会读回 JSON,dataLoaded回调把 386 条历史数据画满画布并自动训练、直接进入预测模式——这正是本课要达到的“刷新不丢数据”效果。
与 6.1 / 6.3 的对比:数据持久化 vs 模型持久化
- 相对 6.1:6.1 的 sketch.js 没有
saveData/loadData,也没有learningRate配置;6.2 仅新增“读盘 + 写盘”两处调用与自动训练流程,采集、训练、预测三大块的 API(addData/train/classify)保持不变。也就是说数据持久化对上层接口是透明的,改动面很小。 - 相对 6.3:6.3 的 sketch.js 演示的是模型权重的持久化,
model.save()/model.load()走的是 TensorFlow.js 的三件套格式,对应仓库中的 6.3_save_model/P5/model/ 目录(model.json、model_meta.json、model.weights.bin)。
两者定位不同:saveData保存的是训练样本,加载后仍可addData增补、normalizeData重训,适合数据仍在迭代积累的阶段;model.save保存的是训练产物,加载后直接进入推理,适合部署。同一系列后续课程(如 6.4 回归任务、7.3 姿态回归 等)中,loadData+ 批量载入 JSON 的模式被反复复用,可见“先落盘数据、再按需训练”是 ml5.js 自定义网络工作流的基础环节。
小结
model.saveData(filename)把内存中的训练样本(model.data.data.raw)序列化为{ "data": [ {xs, ys}, ... ] }结构的 JSON 文件,参数只传不含扩展名的文件名;model.loadData(filename, callback)在setup()中异步读回该文件,回调里可做数据可视化,并直接衔接normalizeData()+train()完成“载入即训练”的闭环;- 仓库中 mouse-notes.json(386 条样本、7 个标签)是可直接对照的真实产物,也是验证文件格式最可靠的依据;
- 数据持久化(6.2)与模型持久化(6.3,TensorFlow.js 三件套)解决不同阶段的问题,组合使用即构成“采集 → 存数据 → 训练 → 存模型 → 加载部署”的完整链路。
- 教程
- 文档
- 示例工程
【免费下载链接】website-archive
Archive of the Coding Train website (first version)
相关推荐
ml5.js NeuralNetwork 完全指南:在浏览器中训练分类与回归神经网络
ml5.js NeuralNetwork 完全指南:在浏览器中训练分类与回归神经网络 本篇技术指南基于 ml5 library 仓库中的官方参考文档 docs/
人工智能机器学习深度学习计算机视觉NLPSynaptic.js神经网络模型保存与加载终极指南:持久化训练成果
Synaptic.js神经网络模型保存与加载终极指南:持久化训练成果 Synaptic.js是一个强大的JavaScript神经网络库,支持Node.js和浏览
机器学习深度学习如何永久保存微信聊天记录?WeChatMsg完整指南帮你一键备份与分析
如何永久保存微信聊天记录?WeChatMsg完整指南帮你一键备份与分析 你是否曾因为手机内存不足而不得不删除珍贵的微信聊天记录?或者担心换手机后那些充满回忆的对
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考