barin.js(十五)FeedForward实战教程 - 手写数字识别(MNIST 数据集)

ops/2024/12/21 10:09:03/

系列文章:

  • (一):brain.js概要介绍
  • (二):项目集成方式
  • (三):手把手教你配置和训练神经网络
  • (四):利用异步训练和交叉验证来优化和加速网络,提升性能
  • (五):不同神经网络对比,该如何选型?
  • (六):FNN实战教程 - 用户喜好预测
  • (七):Autoencoder实战教程 -自编码器的使用场景
  • (八):RNNTimeStep 实战教程 - 股票价格预测
  • (九):LSTMTimeStep 实战教程 - 未来股市指数预测
  • (十):GRUTimeStep 实战教程 - 指数预测以及对比
  • (十一):多变量时间序列股票数据预测实战-成交量、换手率和价格波动率
  • (十二):RNN实战教程 - 音乐乐谱生成
  • (十三)LTSM实战教程 - 从股票预测到文本生成
  • (十四)GRU实战教程 - 文本情感分析之有害内容检测

在本篇文章中,我将带你深入了解如何使用 brain.js 库中的 FeedForward 神经网络来实现手写数字识别任务。以经典的 MNIST 数据集为例,利用浏览器环境中的 CDN 引入 brain.js,并通过逐步实现数据准备、模型构建与训练、评估、优化等过程,帮助你掌握如何在浏览器中使用神经网络进行实际的机器学习任务。

一、什么是 FeedForward 网络?

FeedForward 网络是一种基本的前馈神经网络,它的主要特征是信息从输入层经过一系列隐藏层,最终传递到输出层。与递归神经网络(RNN)不同,FeedForward 网络没有回馈或循环连接,因此每个神经元的输出仅依赖于前一层的输出,而不依赖于自己的历史输出。

FeedForward 网络的工作原理:

  1. 输入层:接收并处理原始数据输入。
  2. 隐藏层:通过一组神经元对数据进行处理和转换,应用激活函数。
  3. 输出层:最终的预测结果,通常用于分类任务(例如数字 0-9)或回归任务(如预测房价)。

FeedForward 网络的优势:

  • 结构简单:层与层之间的连接方式清晰,易于理解和实现。
  • 灵活性高:可以根据问题需求调整隐藏层的数量和神经元数目。
  • 高效性:适合处理较小规模的问题,计算量较轻。

在本篇教程中,我们将使用 brain.js 提供的 NeuralNetwork 类来构建一个 FeedForward 神经网络,并用它来完成手写数字的识别任务。

二、环境和数据准备

环境设置

由于我们将在浏览器环境中进行实践,因此需要通过 CDN 引入 brain.js 库,而无需安装任何本地依赖。以下是引入 brain.js 的 HTML 文件模板:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>MNIST 手写数字识别 - FeedForward</title><!-- 引入 brain.js 库 --><script src="https://cdn.jsdelivr.net/npm/brain.js@2.0.0/dist/brain-browser.min.js"></script>
</head>
<body><h1>手写数字识别 - FeedForward 网络</h1><div id="output"></div>
</body>
</html>

数据准备

MNIST 数据集是一个包含手写数字的经典数据集,每个数字图像大小为 28x28 像素,标签为对应的数字(0-9)。由于浏览器环境下的计算能力有限,我们在这篇教程中将使用简化版本的 MNIST 数据集,数据将被处理为一维数组,方便喂给神经网络

数据预处理:
  1. 图像扁平化:将每张 28x28 的图像转换为 784 长度的向量。
  2. 归一化:将每个像素的灰度值(范围 0-255)转换为 0 到 1 之间的小数。
  3. 标签编码:将每个标签(数字)转化为 10 类数组,其中每个位置代表一个数字类别,数字对应位置为 1。

三、模型构建和训练

构建 FeedForward 网络

我们使用 brain.jsNeuralNetwork 类来构建前馈神经网络。在本示例中,输入层大小为 784(因为每张图片包含 784 个像素),输出层大小为 10(代表数字 0 到 9)。我们选择 2 层隐藏层,分别包含 128 和 64 个神经元。

javascript">// 创建一个 FeedForward 网络
const net = new brain.NeuralNetwork({hiddenLayers: [128, 64], // 两层隐藏层,分别有 128 和 64 个神经元activation: 'relu',      // 使用 ReLU 激活函数
});

训练模型

使用 MNIST 数据集中的训练数据进行训练,brain.js 会通过反向传播算法更新神经网络的权重和偏置,以使网络更好地拟合训练数据。以下是训练过程的代码:

javascript">// 模拟的训练数据 - 一般数据预处理后会通过类似下面的方式加载数据
const trainingData = [{ input: [/* 输入的784个像素值*/], output: [0, 0, 0, 1, 0, 0, 0, 0, 0, 0] }, // 输入图像和标签(0-9)// 更多数据...
];// 训练网络
net.train(trainingData, {iterations: 2000,  // 训练2000次errorThresh: 0.005, // 误差阈值log: true,          // 打印日志logPeriod: 100      // 每100次训练打印一次日志
});

模型评估

训练完成后,我们需要评估模型的性能。通过使用测试数据,我们可以计算模型的准确率,判断其在真实世界应用中的有效性。

javascript">// 测试数据
const testData = [{ input: [/* 测试数据的784个像素值*/], output: [0, 0, 0, 1, 0, 0, 0, 0, 0, 0] },// 更多测试数据...
];// 使用训练好的模型进行预测
testData.forEach(data => {const result = net.run(data.input); // 网络输出的结果console.log(`预测:${result}`);
});

四、模型应用

一旦模型训练完成,你就可以用它来对新的手写数字进行预测。给定一张新的手写数字图像,我们只需要将图像数据转化为与训练数据相同的格式(784 个像素值),然后通过 net.run() 方法获取模型的预测结果。

javascript">// 例如,对于一张新的图像
const testImage = [/* 一个28x28图像的784个像素值 */];
const prediction = net.run(testImage);
console.log("模型预测的结果:", prediction);

五、完整代码

以下是完整的 HTML 文件,其中包含了如何创建神经网络、训练模型、评估模型以及进行预测的完整示例:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>MNIST 手写数字识别 - FeedForward</title><script src="https://cdn.jsdelivr.net/npm/brain.js@2.0.0/dist/brain-browser.min.js"></script>
</head>
<body><h1>手写数字识别 - FeedForward 网络</h1><div id="output"></div><script>javascript">// 创建一个 FeedForward 网络const net = new brain.NeuralNetwork({hiddenLayers: [128, 64], activation: 'relu',      });// 模拟的训练数据const trainingData = [{ input: [/* 输入的784个像素值*/], output: [0, 0, 0, 1, 0, 0, 0, 0, 0, 0] }, // 训练数据// 更多训练数据...];// 训练网络net.train(trainingData, {iterations: 2000,errorThresh: 0.005,log: true,logPeriod: 100});// 测试数据const testData = [{ input: [/* 测试数据的784个像素值*/], output: [0, 0, 0, 1, 0, 0, 0, 0, 0, 0] },// 更多测试数据...];testData.forEach(data => {const result = net.run(data.input);console.log(`预测:${result}`);});</script>
</body>
</html>

六、优化策略和实践建议

  1. 增加训练数据:为了提高模型的准确度,尽量使用更多的训练数据。增加数据集的多样性,可以有效提高模型的泛化能力。
  2. 调整网络结构:可以通过增加更多的隐藏层或神经元,来提升模型的表现。然而,过多的层和神经元可能会导致过拟合,因此需要谨慎调节。
  3. 学习率调整:适当的学习率有助于加快收敛并避免过度震荡。可以通过交叉验证来选择最优的学习率。
  4. 数据增强:对于

图像数据,可以考虑通过旋转、平移、缩放等方式进行数据增强,增加模型的鲁棒性。

七、总结

在本篇文章中,我们使用 brain.js 实现了一个简单的前馈神经网络来进行手写数字识别任务。通过这一实践,大家不仅学会了如何在浏览器中使用神经网络,还掌握了数据预处理、模型训练与评估的基本流程。虽然 brain.js 比较适合较小规模的任务,但它仍然是一个非常方便的工具,适合入门学习和实验。

希望这篇教程能帮助你更好地理解神经网络的基础,并激发你在机器学习领域继续深入探索的兴趣!


http://www.ppmy.cn/ops/143729.html

相关文章

功能篇:springboot实现pdf加水印,5种方案

在Spring Boot应用中实现给PDF文件加水印&#xff0c;可以采用以下五种方案&#xff1a; ### 方案一&#xff1a;使用iText库 iText 是一个强大的Java PDF库&#xff0c;可以用来创建、修改和操作PDF文档。你可以使用它来添加文本或图像形式的水印。 **步骤&#xff1a;** 1. …

Face to face

1.西班牙添加5G volte 首先carrierconfig里使能 <boolean name"carrier_nr_available_bool" value"true" /> <boolean name"carrier_volte_available_bool" value"true" /> 其次 组件apn配置ims参数 2.印度j…

uniapp对接unipush 1.0 ios/android

简介 实现方法 是uniapp官网推荐的 unipush-v1 文档配置具体看 uni-app官网 配置好了之后 代码实现 前端代码 前端的主要任务是监听 监听到title content 创建消息推送 安卓 可以收到在线消息并且自动弹出消息 IOS 可以监听到在线消息但是需要手动推送 以下代码app初始…

mysql的事务和存储引擎+备份

mysql的事务和存储引擎备份 一. mysql的事务1.1 mysgl支持事务四种隔离级别1.2 事务控制语句1.3 行锁和死锁1.3.1 行锁1.3.2 死锁1.3.3 如何避免死锁的发生 二. msyql的备份和还原以及日志管理2.1 数据库备份的分类2.2 备份策略2.2.1 物理冷备份&#xff08;全量&#xff09;2.…

番外篇 Git 的原理与使用

PS&#xff1a;本篇是个长篇&#xff0c;但是阅读完&#xff0c;可以基本了解 Git 在实际开发中的绝大部分常用操作。 前言&#xff1a;什么是Git 我们在日常工作 / 学习时&#xff0c;对于某些文档 / 代码&#xff0c;可能会存在多个版本需要维护&#xff0c;但是随着版本的…

Mac iOS、Android、Flutter、React Native开发环境配置

1.安装XCode https://apps.apple.com/cn/app/xcode/id497799835?mt12 2.安装Android Studio https://developer.android.google.cn/studio 3.安装brew 参考地址&#xff1a;https://www.jianshu.com/p/22122a1d4474 /bin/zsh -c "$(curl -fsSL https://gitee.com/cunk…

abc 383 C (bfs 最短路 )D(唯一分解定理,欧拉筛)

C 题&#xff1a; 首先暴力的想&#xff0c;对于每一个加湿器的位置去 上下左右扩展是 nm 的复杂度 。最多会有 nm 个加湿器。所以复杂度到达了n^3 。肯定超时了。 我们可以发现 对于一个点 会标记很多次&#xff0c;这回导致超时。 可以采用类似 bfs 求最短路的形式&#xff…

《Vue3实战教程》13:Vue3侦听器

如果您有疑问&#xff0c;请观看视频教程《Vue3实战教程》 侦听器​ 基本示例​ 计算属性允许我们声明性地计算衍生值。然而在有些情况下&#xff0c;我们需要在状态变化时执行一些“副作用”&#xff1a;例如更改 DOM&#xff0c;或是根据异步操作的结果去修改另一处的状态。…