用 30 行 JavaScript 创建神经网络:Synaptic.js 实战与反向传播原理精读
发布时间:2026/10/1 2:45:31来源:尧图网络
文档技术博客教程【免费下载链接】weekly前端精读周刊。帮你理解最前沿、实用的技术。项目地址https://gitcode.com/GitHub_Trending/we/weekly点击查看免费下载导读本文以「前端精读周刊」第 33 期的经典译文与精读为基础讲解如何用 30 行 JavaScript 代码基于 Synaptic.js 构建一个能学会异或XOR运算的神经网络并深入拆解其中的神经元、权重、偏差、激活函数与反向传播原理。读完本文你将掌握Layer/Network/activate/propagate四个核心 API 的完整用法能亲手写出一段可运行的前端神经网络训练代码并从链式求导的角度真正理解反向传播到底如何修正权重与偏差。仓库中还提供了从 0 到 1 手写神经网络的系列文章机器学习简介、万能近似定理、神经网络架构设计、反向传播、完整实现神经网络可配合本篇文章由浅入深地学习。1 引言为什么用 30 行代码也能创造神经网络自从 AlphaGo 打败李世石之后深度学习逐渐进入大众视野人工智能越来越多地出现在人们的生活之中。很多人开始讨论程序员什么时候会被人工智能替代与其慌张不如在人工智能的潮流下不断学习相关技术武装自己才是硬道理。神经网络听起来很高深但它的最小可运行实现其实非常简洁。本文将介绍如何借助 Synaptic.js 创建简单的神经网络并解决经典的异或XOR运算问题。整段代码加上注释不超过 30 行却完整覆盖了神经网络最核心的前向传播激活 反向传播学习闭环。需要先说明的是本仓库readme.md是「前端精读周刊」的存档并不包含可运行的神经网络源码仓库中的 机器学习 系列文章与本文同源提供了从找函数哲学到完整手写神经网络的系统性推导本文会适时引用作为原理补充。2 神经网络中的神经元与突触2.1 神经元一个接受输入、返回输出的函数对神经网络有所了解的人都知道神经网络是模仿人脑神经系统构建的。在人脑神经系统中存在一种非常重要的细胞——神经元。在神经网络里你可以把神经元理解为一个函数它接受一些输入返回一些输出结果。其中Sigmoid 神经元是一种非常常用的神经元它以 Sigmoid 函数作为激活函数。Sigmoid 函数接受任意数值输出0到1之间的值其函数曲线呈平滑的 S 形。激活函数在神经网络中承担非线性变换的职责。仓库中的 万能近似定理 一文给出了更本质的解释通过叠加多条 Sigmoid、RELU 等启动函数激活函数理论上可以逼近任意形状的函数因此激活函数是神经网络具备万能近似能力的基础构件。2.2 一个具体的 Sigmoid 神经元例子我们可以看一个具体的Sigmoid 神经元例子最左边的1和0是输入层中的两个节点7和3是权重参数weight-2是偏差bias。神经元先对输入做加权求和1 × 7 0 × 3 (-2) 5得到一个隐藏层节点值5。加权求和1×7 0×3 (-2) 5接着把节点5输入到 Sigmoid 函数得到一个输出层节点值1即sigmoid(5)的结果约为0.9933取整后为1。从仓库 机器学习简介 的视角看这个神经元本质就是一个带有未知参数的函数骨架参数w权重与输入x相乘决定其影响程度参数b偏差做偏移调整最后通过激活函数做非线性变换。参数取不同的值神经元就对应不同的函数。2.3 突触把神经元连接成网络有了神经元把所有的神经元连接起来就构成了一个神经网络。神经元之间的箭头可以理解为一种突触synapse。下图中输入层的两个节点通过突触连接到隐藏层的三个节点隐藏层再连接到输出层的一个节点形成一个经典的两层隐藏层 输出层前馈网络。这种每一层的每个节点都与下一层的每个节点相连的结构称为全连接full connected。仓库 神经网络架构设计 中定义的Layer结构正是基于全连接假设。2.4 好的模型依赖正确的权重与偏差完成神经网络的构建后你可以用它来识别手写数字、判断垃圾邮件等。但正如上面的例子所示好的模型依赖于正确的权重和偏差的选择。在实际工作中每次完成训练后我们都会拿训练结果对测试样本进行预测得到算法的准确率然后尝试选择更好的权重和偏差期望达到更好的准确度。这个根据预测误差不断调整权重和偏差的学习过程称为反向传播Backpropagation。经过大量的学习最终才能得到更好的预测准确率。3 30 行代码实现用 Synaptic.js 训练神经网络识别 XOR3.1 准备引入 Synaptic.js本文代码基于 Synaptic.js一个可以在浏览器和 Node.js 中运行的 JavaScript 神经网络库通过window.synaptic全局对象或模块方式引入const { Layer, Network } window.synaptic;也可以按模块方式引用Layer、Network两个构造函数。Synaptic 的核心抽象正是本文要使用的三个概念Layer层、Network网络、project层之间的投射连接。3.2 搭建网络骨架首先创建三个层输入层 2 个节点、隐藏层 3 个节点、输出层 1 个节点并通过project方法把层与层连接起来var inputLayer new Layer(2); var hiddenLayer new Layer(3); var outputLayer new Layer(1); inputLayer.project(hiddenLayer); hiddenLayer.project(outputLayer); var myNetwork new Network({ input: inputLayer, hidden: [hiddenLayer], output: outputLayer });参数说明参数含义本示例取值input输入层2 个节点接收[x1, x2]二元输入hidden隐藏层数组[hiddenLayer]包含 1 层共 3 个节点output输出层1 个节点输出一个0~1之间的值project的作用是把上一层节点的输出通过突触连接到下一层节点连接建立后网络才具备前向传播的通道。这里隐藏层节点数量3 个属于超参数可以按需调整。3.3 训练循环激活 反向传播接下来是训练环节。XOR异或运算的真值表如下0 xor 0 0、0 xor 1 1、1 xor 0 1、1 xor 1 0。这是一个线性不可分问题单层感知机无法解决但含隐藏层的神经网络可以学会它。// train the network - learn XOR var learningRate .3; for (var i 0; i 20000; i) { // 0,0 0 myNetwork.activate([0,0]); myNetwork.propagate(learningRate, [0]); // 0,1 1 myNetwork.activate([0,1]); myNetwork.propagate(learningRate, [1]); // 1,0 1 myNetwork.activate([1,0]); myNetwork.propagate(learningRate, [1]); // 1,1 0 myNetwork.activate([1,1]); myNetwork.propagate(learningRate, [0]); }简单而言运行myNetwork.activate([0,0])时[0, 0]是输入值它对应的异或运算结果是false也就是0。这个过程是前向传播Synaptic 称之为激活网络activate。每次前向传播之后我们需要做一次反向传播来更新权重和偏差对应的代码是myNetwork.propagate(learningRate, [0])第一个参数learningRate学习率本例为0.3是告诉神经网络如何调整权重的常量控制每次参数更新的步长第二个参数[0]是这次输入对应的异或运算期望结果目标值与网络实际输出对比后计算出误差。学习率是训练中非常关键的超参数设置过大loss 会在最优点附近震荡无法收敛设置过小收敛速度极慢甚至训练不动。仓库 机器学习简介 中同样强调learningRate 需要用一些 magic 的方式寻找否则学习速率太大或者太小都 train 不起来。3.4 训练结果验证经过 20000 次学习每个 epoch 覆盖全部 4 组 XOR 样本得到如下输出console.log(myNetwork.activate([0,0])); - [0.015020775950893527] console.log(myNetwork.activate([0,1])); - [0.9815816381088985] console.log(myNetwork.activate([1,0])); - [0.9871822457132193] console.log(myNetwork.activate([1,1])); - [0.012950087641929467]对运算结果取最近的整数就可以得到正确的异或运算结果输入网络输出浮点取整期望[0,0]0.0150...00[0,1]0.9815...11[1,0]0.9871...11[1,1]0.0129...00可以看到网络输出虽然不会严格等于 0 或 1因为输出层经过 Sigmoid 激活值域在0~1之间但已经明显向正确的二值结果收敛四组样本全部判断正确。4 精读反向传播如何修正权重与偏差读原文的时候大家可能对反向传播如何修正权重和偏差有所疑问。作者给出的引文 A Step by Step Backpropagation Example 很详细地解释了整个过程。为了方便理解我们以上面的异或运算例子简单分析一下其中选取的激活函数是Logistic 函数即 Sigmoidσ(z) 1 / (1 e^(-z))4.1 前向传播算出当前误差当我们输入[0, 0]时选取一些任意的权重和偏差计算过程如下隐藏层节点h1 σ(w1·x1 w2·x2 b1)输出层节点output σ(w5·h1 w6·h2 b2)多隐藏节点情况下依此类推。为了方便后续推导可以用符号简单地描述h1和最终结果output的计算过程。计算得到输出o后通过平方误差函数计算误差loss (o - t)²其中o是网络实际输出ttarget是期望输出。在上面的运算中得到的output 0.73673目标值是对[0,0]取异或的值即target 0代入公式得到误差值loss (0.73673 - 0)² ≈ 0.2713854.2 反向传播用链式求导逐层回传误差到这里我们进行反向传播的过程也就是说需要确认新的参数w1, w2, w3, w4, w5, w6, b1, b2。以计算新的w5为例通过计算误差函数相对于w5的偏导来得到新的参数可以使用下面的链式求导∂loss/∂w5 ∂loss/∂output × ∂output/∂w5得到w5对应的偏导后通过下面的公式计算新的w5参数w5_new w5 - learningRate × ∂loss/∂w5其中0.3就是代码中设置的learningRate的值。重复相似的过程可以计算其他参数的值这里不再累述。4.3 反向传播的本质三种场景统一为链式法则仓库中的 反向传播 一文把反向传播归纳为三种可复用的计算场景正好是本文示例的源码级展开场景 1输出节点的值对 loss 的偏导。由 loss 函数定义直接得出。若采用均方误差loss (x - t)²则dloss/dx 2(x - t)它完全取决于训练样本的期望输出与实际输出是最容易得到的已知值。场景 2非输出节点的值对 loss 的偏导。利用场景 1 的结果沿网络反向用链式法则一步步跳转dloss/dx_i Σ_j (dloss/dx_j × dx_j/dx_i)其中dx_j/dx_i 激活函数导数(x_j) × w_ij。由于 Sigmoid 函数有一个巧妙的性质σ(z) σ(z)·(1-σ(z))其导数可以通过函数自身值简单算出这正是激活函数普遍使用 Sigmoid 的原因之一。场景 3已知某节点值对 loss 的偏导后求该节点任意参数对 loss 的偏导。例如dloss/db dloss/dx × dx/db其中dx/db 1dloss/dw_i dloss/dx × x_i前一节点输出值。当某节点由多个下游节点共同反向传播而来时链式法则采取加法关系并且从工程角度看dloss/dx_i与激活函数导数 × 系数等中间值会被反复使用需要缓存避免重复计算——这一点在仓库的 完整实现神经网络 中体现为每个神经元上挂载dlossByDx、dlossByDbAll、dlossByDwAll三个缓存字段并采用先反向逐层求导累加、再统一更新参数的批量梯度下降策略。5 从 30 行到手写神经网络仓库系列文章的学习路径30 行代码的最大价值在于展示了神经网络激活 反向传播的最小闭环。但如果只满足于调用库难免有囫囵吞枣之感。本仓库的 机器学习 系列恰好从找函数这一第一性原理出发带你徒手实现同样的能力机器学习简介: 寻找函数的艺术建立机器学习就是找函数的世界观给出 define model function → define loss function → optimization 的三部曲框架并用y 3x的最小例子演示梯度下降。万能近似定理: 逼近任何函数的理论解释为什么叠加多条激活函数可以逼近任意函数并推导出全连接神经网络与矩阵运算的关系这也是机器学习必须用 GPU 的原因。实现万能近似函数: 神经网络的架构设计用 TypeScript 设计NeuralNetwork类与Layer/Neural数据结构实现modelFunction与lossFunction。反向传播: 揭秘神经网络的学习机制把反向传播拆解为三种链式求导场景为手写optimization提供理论依据。完整实现神经网络: 实战演练基于反向传播完整实现optimization函数并验证单层单神经元网络可退化为y b wx、多层网络可拟合非线性函数。对照阅读可以发现Synaptic 的activate对应前向传播的modelFunctionpropagate对应反向传播的optimization而learningRate在手工实现中同样以学习率参数出现在参数更新公式w -gradient × learningRate中。理解了底层原理后再回头看这 30 行代码每一行都有了明确的含义。6 总结本文介绍了使用 Synaptic.js 创建简单神经网络解决异或运算问题的完整过程也对反向传播的原理进行了详细解释神经元 加权求和 偏差 激活函数权重决定输入的影响力偏差做偏移激活函数引入非线性网络 神经元分层全连接Layer.project()建立突触连接Network汇总三层结构训练 激活 反向传播的循环activate()前向传播计算输出propagate(learningRate, target)根据误差反向调整权重和偏差反向传播 链式求导从输出层误差出发逐层回传用偏导指引参数更新的方向与幅度。文中实现神经网络的代码非常简单包含注释也不超过 30 行但是只会代码会有点囫囵吞枣的感觉。建议读者参考仓库中的机器学习系列文章以及下面列出的资料深入理解算法原理再用 Synaptic.js 动手尝试改变隐藏层节点数、学习率等超参数观察训练效果的变化——这是理解调参如何影响模型最直观的方式。相关资料A Step by Step Backpropagation Example — by Matt MazurHackers Guide to Neural Nets — by Andrej KarpathyNeuralNetworksAndDeepLarning — by Michael NielsenSynaptic.js赞分享文档技术博客教程【免费下载链接】weekly前端精读周刊。帮你理解最前沿、实用的技术。项目地址https://gitcode.com/GitHub_Trending/we/weekly点击查看免费下载相关推荐解密handson-ml3神经网络反向传播原理终极指南解密handson ml3神经网络反向传播原理终极指南 handson ml3是一系列Jupyter笔记本通过Scikit Learn、Keras和Tens示例工程教程7天入门DeepLearningPython从0掌握前馈神经网络与反向传播算法7天入门DeepLearningPython从0掌握前馈神经网络与反向传播算法 DeepLearningPython 是一个专注于神经网络与深度学习的PythCANN/metadef获取可选输入偏移量GetOptionalInputOffseta nameZH CN_TOPIC_0000002486886264 /a 函数功能a namezh人工智能CANNAscend上一篇YouTube.js 解析器指南深入理解 Form 表单节点与 ToggleFormField 切换字段下一篇gitbook/openapi-parser 演进全解析解析流程、x-扩展属性与 MCP 集成创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网