☰
用 saveData 与 loadData 持久化训练数据:ml5.js 神经网络课程示例详解
2026/10/13 1:57:42 网站建设 项目流程
  • 教程
  • 文档
  • 示例工程

【免费下载链接】website-archive

Archive of the Coding Train website (first version)

项目地址:https://gitcode.com/gh_mirrors/we/website-archive
点击查看免费下载

本篇技术文章基于 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 Ownlearning/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 Modellearning/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 条样本,各标签分布如下:

标签ABCDEFG
样本数68565543536447

每条记录与 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):

  1. 在learning/ml5/6.2_save_data/P5/目录下启动任意静态服务器(loadData需要以 HTTP 方式读取本地 JSON,直接双击index.html走file://协议时脚本读取文件的行为可能受限,从源码结构看按文件名加载会走网络请求路径,建议始终经静态服务运行);
  2. 首次运行:画布为空,按字母键(C–G 均可,keyPressed中取key.toUpperCase())设定标签,点击画布采集数据,每次点击会画出“圆 + 标签”并播放对应音符;
  3. 按s键调用model.saveData('mouse-notes'),得到mouse-notes.json(可替换/对照仓库中已提交的同名文件);
  4. 按t键启动训练,控制台打印 epoch 进度(whileTraining(epoch, loss));训练完成后进入prediction状态,点击画布即可看到分类预测结果与音符反馈;
  5. 刷新页面再次运行: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)

项目地址:https://gitcode.com/gh_mirrors/we/website-archive
点击查看免费下载

相关推荐

上一篇:Sunshine 从零上手:4 步把 PC 游戏串到客厅大屏
下一篇:三步查清韩国法院不动产拍卖公告:court-auction-notice-search 如何把 courtauction.go.kr 变成结构化数据

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

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

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

立即咨询