ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Synaptic 层(Layer)API 完全指南:project、gate、activate 与 propagate 实战详解

Synaptic 层(Layer)API 完全指南:project、gate、activate 与 propagate 实战详解 机器学习深度学习【免费下载链接】synapticarchitecture-free neural network library for node.js and the browser项目地址https://gitcode.com/gh_mirrors/sy/synaptic点击查看免费下载Synaptic 是一个面向 Node.js 与浏览器的架构无关architecture-free神经网络库其核心抽象并非单个神经元而是层Layer——一组可整体激活、训练与互联的神经元集合。本文以 wiki/Zh-TW/layers.md 为主线结合 src/Layer.js、src/LayerConnection.js、src/Neuron.js 的源码实现系统讲解 Layer 的创建、project连接、gate门控、activate激活、propagate反向传播以及set批量配置等完整 API并给出可直接运行的实战代码。读完本文你将能够不借助任何高层架构如 Perceptron、LSTM 等预置类直接用 Layer 手工搭建并训练一个多层神经网络。Layer 是什么为什么用层而不是单个神经元在 Synaptic 中单个神经元Neuron虽然功能完整但用它搭建网络意味着要手动管理每个连接对象代码冗长且易错。层Layer本质上就是一组神经元的集合它可以做几乎和神经元一样的工作但把编程过程大幅简化你面对的不再是几十上百个神经元个体而是一个可以整体激活、整体训练、批量投射连接的抽象单元。从源码看Layer 的构造函数非常直观src/Layer.js#L25-L35constructor(size) { this.size size | 0; // 层中神经元数量 this.list []; // 神经元数组 this.connectedTo []; // 记录该层投射出去的所有 LayerConnection while (size--) { var neuron new Neuron(); this.list.push(neuron); } }也就是说new Layer(5)内部会创建 5 个默认的 Neuron默认压缩函数为LOGISTIC偏置初始化为Math.random() * .2 - .1见 src/Neuron.js#L58-L60。因此 Layer 的大小即该层神经元个数它也是所有activate、propagate输入输出数组长度的硬性约束。创建一个层创建层只需指定大小该层中的神经元数量var myLayer new Layer(5);project在层与层之间建立连接project方法负责把一个层投射连接到另一个层是搭建网络拓扑的核心操作。你必须提供目标层以及连接类型Layer.connectionTypevar A new Layer(5); var B new Layer(3); A.project(B, Layer.connectionType.ALL_TO_ALL); // A 层中的所有神经元现在都在与 B 层中的所有神经元建立连接。层也可以自我连接自连接这在构建递归结构时非常有用A.project(A, Layer.connectionType.ONE_TO_ONE);三种连接类型connectionType连接类型行为说明适用场景与约束Layer.connectionType.ALL_TO_ALL把 A 层的每一个神经元连接到 B 层的每一个神经元标准前馈层间连接最常用Layer.connectionType.ONE_TO_ONE把 A 层的第 i 个神经元连接到 B 层的第 i 个神经元两层层大小必须相同常用于逐元素配对Layer.connectionType.ALL_TO_ELSE把每个神经元连接到同一层中除自身外的所有其他神经元仅在自我连接中有意义若用于不同层之间效果等同于ALL_TO_ALL注意默认连接类型当连接两个不同层时默认类型是Layer.connectionType.ALL_TO_ALL当一个层连接到它自己时如myLayer.project(myLayer)默认类型是Layer.connectionType.ONE_TO_ONE。这一默认逻辑并非写在project里而是实现在LayerConnection的构造函数中src/LayerConnection.js#L17-L23if (typeof this.type undefined) { if (fromLayer toLayer) this.type Layer.connectionType.ONE_TO_ONE; else this.type Layer.connectionType.ALL_TO_ALL; }project 的返回值与约束project方法返回一个LayerConnection对象该对象可以被另一层用gate方法门控。从源码看src/Layer.js#L81-L93project还支持两个额外细节如果目标是一个Network而非 Layer它会自动把连接指向该网络的输入层layer.layers.input因此你可以直接把一个 Layer 投射到整个网络上如果目标既不是 Layer 也不是 Network会抛出Invalid argument, you can only project connections to LAYERS and NETWORKS!错误若两层之间已经存在连接project不会重复创建而是直接返回已有的LayerConnection通过connected()检测。LayerConnection内部会依据连接类型逐条建立神经元级连接src/LayerConnection.js#L25-L49ALL_TO_ALL与ALL_TO_ELSE走双重循环后者跳过自身连接ONE_TO_ONE走按索引配对的单循环并将连接记录在connections哈希与list数组中同时推入fromLayer.connectedTo。源码佐证ALL_TO_ELSE 在 LSTM 中的实战用法ALL_TO_ELSE并非冷门选项Synaptic 内置的 LSTM 架构在开启hiddenToHidden选项时正是用它在记忆单元之间建立隐藏层到隐藏层的循环连接src/architectures/LSTM.js#L86-L87if (option.hiddenToHidden) memoryCell.project(memoryCell, Layer.connectionType.ALL_TO_ELSE);这印证了文档中自我连接 ALL_TO_ELSE的典型用途让每个神经元接收同一层其他所有神经元除自己的信号形成丰富的递归上下文。gate用一层门控另一段连接gate方法让一个层可以屏蔽门控两个其他层之间的连接或某个层的自连接。被门控的连接会受门控层神经元激活值的影响——在 Synaptic 中门控神经元的激活值会作为被门控连接输出的增益gain乘数参与前向计算与反向传播。基本用法var A new Layer(5); var B new Layer(3); var connection A.project(B); var C new Layer(4); C.gate(connection, Layer.gateType.INPUT_GATE); // now C gates the connection between A and B (input gate)三种门类型gateType门类型行为说明尺寸约束Layer.gateType.INPUT_GATEC 层门控 A→B 连接时C 的所有神经元成为 B 的输入连接门C 与 B 的大小必须相同Layer.gateType.OUTPUT_GATEC 层门控 A→B 连接时C 的所有神经元来自 A 的输出连接门C 与 A 的大小必须相同Layer.gateType.ONE_TO_ONEC 的每个神经元分别门控 A→B 的一条连接对门控自连接层尤其有用A、B、C 大小必须相同实际约束为门控层与连接数相同注意gateType中INPUT_GATE/OUTPUT_GATE对应源码中的Layer.gateType.INPUT/Layer.gateType.OUTPUT常量值分别为INPUT、OUTPUT、ONE TO ONE见 src/Layer.js#L13-L18文档写法与源码常量名略有差异二者等价。gate 的源码级行为从 src/Layer.js#L96-L135 可以看到三种门控在神经元层面做了什么INPUT_GATE遍历connection.to目标层的每个神经元找出该神经元所有输入连接中属于本LayerConnection的那些让门控层的对应神经元调用neuron.gate(connection)逐个门控OUTPUT_GATE遍历connection.from源层的每个神经元找出其projected连接中属于本LayerConnection的那些进行门控ONE_TO_ONE按索引把门控层的第 i 个神经元与连接列表中的第 i 条连接一一对应门控。最后无论哪种类型都会把门控记录推入连接的gatedfrom数组便于后续查询与梯度计算。在神经元层面gate()会把连接登记进该神经元的gated连接表、建立 extended trace扩展资格迹与 influences 记录并设置connection.gater thissrc/Neuron.js#L239-L262之后该神经元的激活值会直接写入被门控连接的gainsrc/Neuron.js#L129-L132。源码佐证LSTM 中的三路门控文档中的三种 gateType 正是 LSTM 架构的核心机制。在 src/architectures/LSTM.js#L106-L110 中inputGate.gate(input, Layer.gateType.INPUT); // 输入门 forgetGate.gate(self, Layer.gateType.ONE_TO_ONE); // 遗忘门门控自连接 outputGate.gate(output, Layer.gateType.OUTPUT); // 输出门 if (previous ! null) inputGate.gate(cell, Layer.gateType.INPUT); // 对前序记忆块的输入门控可见INPUT_GATE、OUTPUT_GATE、ONE_TO_ONE三种类型正好覆盖了 LSTM 输入门、输出门与遗忘门门控记忆单元自连接的全部需求这也解释了为什么文档强调ONE_TO_ONE门控对于门控自连接层是有用的。activate激活整层神经元当一个层被激活时它会按顺序激活该层中的所有神经元并返回一个包含各神经元输出值的数组。对于输入层你需要传入一个激活值数组作为参数对于其他层直接调用即可它们会基于已建立的连接自动计算var A new Layer(5); var B new Layer(3); A.project(B); A.activate([1,0,1,0,1]); // [1,0,1,0,1] B.activate(); // [0.3280457, 0.83243247, 0.5320423]源码实现src/Layer.js#L38-L59显示传入input时会对每个神经元调用neuron.activate(input[id])未传入时调用neuron.activate()两种情况都会把结果压入activations数组并返回。有一个关键约束输入数组长度必须等于层大小否则抛出INPUT size and LAYER size must be the same to activate!错误。此外当神经元以外部输入方式激活时src/Neuron.js#L64-L71激活值直接取输入值且偏置会被置 0——也就是说输入层的激活完全由环境输入决定不经过压缩函数。propagate通过反向传播训练层在激活之后你可以教这个层正确的输出应该是什么——这就是训练。Synaptic 使用反向传播误差完成这一过程。调用propagate必须提供两个参数学习率rate和目标值数组元素在 0 到 1 之间长度必须等于层大小。一个完整的训练示例下面的例子训练 B 层当 A 层激活[1,0,1,0,1]时B 层输出[0,0]var A new Layer(5); var B new Layer(2); A.project(B); var learningRate .3; for (var i 0; i 20000; i) { // when A activates [1, 0, 1, 0, 1] A.activate([1,0,1,0,1]); // train B to activate [0,0] B.activate(); B.propagate(learningRate, [0,0]); } // test it A.activate([1,0,1,0,1]); B.activate(); // [0.004606949693864496, 0.004606763721459169]经过 2 万次迭代B 层的输出从随机初始值收敛到接近 0约0.0046说明网络已经学会了将[1,0,1,0,1]映射到[0,0]。propagate 的源码级原理从源码看Layer 的propagate只是把误差传播委托给层内每个神经元src/Layer.js#L62-L78若传入target逐神经元调用neuron.propagate(rate, target[id])且目标数组长度必须等于层大小否则抛出TARGET size and LAYER size must be the same to propagate!错误若未传入target该层被当作隐藏层调用neuron.propagate(rate)此时误差通过反向传播从后续层累积而来无论哪种情况遍历方向都是从列表尾部到头部id 0递减以保证同层内传播顺序的一致性。神经元层面的反向传播src/Neuron.js#L138-L203遵循经典公式输出神经元的误差责任responsibility直接取自环境目标与当前激活之差target - activation隐藏神经元则累加所有投射连接传来的responsibility * gain * weight与所有被门控连接经扩展资格迹extended trace算出的贡献。最后按学习率更新每个输入连接的权重input.weight rate * gradient并调整偏置bias rate * error.responsibility。这些公式在源码中以Eq. 10、Eq. 21、Eq. 22、Eq. 23、Eq. 24等注释标注对应 Synaptic 论文中的推导。set批量设置压缩函数与偏置set方法允许你一次性配置层中所有神经元的属性包括压缩函数squash与偏置biasmyLayer.set({ squash: Neuron.squash.TANH, bias: 0 })从源码src/Layer.js#L205-L218看set还支持label选项会为每个神经元生成label _ neuron.ID形式的标签并且它返回this因此可以链式调用——LSTM 架构中就用new Layer(size).set({ bias: 1 })来批量初始化门控层的偏置src/architectures/LSTM.js#L49-L58。Neuron 内置的压缩函数定义在 src/Neuron.js#L6-L30共五种压缩函数公式前向 / 导数典型用途Neuron.squash.LOGISTIC1 / (1 exp(-x))/fx * (1 - fx)默认压缩函数输出范围 (0,1)适合二分类输出Neuron.squash.TANHtanh(x)/1 - tanh²(x)输出范围 (-1,1)收敛通常更快Neuron.squash.IDENTITYx/1线性输出适合回归任务Neuron.squash.HLIMx 0 ? 1 : 0/1硬限幅阶跃式激活Neuron.squash.RELUx 0 ? x : 0/x 0 ? 1 : 0整流线性单元深度网络常用注意set中bias的赋值用的是if (options.bias)判断src/Layer.js#L214-L215即bias: 0实际上不会改变神经元偏置因为 0 是 falsy若要显式设置偏置为 0应使用bias: 0.0之外的非零值或直接逐神经元设置。这是当前版本源码的一个实现细节使用set({ bias: ... })时建议传入非零值如 LSTM 中传入1。neurons获取层内神经元列表neurons()方法以激活顺序返回层中所有神经元的数组var neuronList myLayer.neurons();源码实现极简src/Layer.js#L194-L196直接返回内部维护的this.list数组。因为 Layer 构造时就是按顺序push神经元的所以数组顺序即激活顺序这与activate的输出数组一一对应。你可以遍历该数组直接访问每个神经元的activation、bias、connections等属性做细粒度的检查或定制。从 Layer 到网络衔接与综合实战Layer 是 Synaptic 一切高级架构的基石。当多个 Layer 通过project/gate连接后可以用Network把它们封装成整体进行统一的activate/propagate训练Network 的实现可参见 src/Network.js也可以直接用 src/architectures/Perceptron.js、src/architectures/LSTM.js 等预置架构快速搭建网络——而这些架构内部正是 Layer 与本文所述 API 的组合src/architect.js 负责统一导出。综合实战手写一个两层前馈网络把本文所有 API 串起来你可以不依赖任何预置架构手工构建并训练一个两层前馈网络// 引入浏览器环境可直接用全局 Synaptic 对象 var Layer synaptic.Layer; var Neuron synaptic.Neuron; var Network synaptic.Network; // 1. 定义拓扑2 个输入 → 3 个隐藏 → 1 个输出 var inputLayer new Layer(2); var hiddenLayer new Layer(3).set({ squash: Neuron.squash.TANH }); var outputLayer new Layer(1).set({ squash: Neuron.squash.LOGISTIC }); // 2. 建立连接默认为 ALL_TO_ALL inputLayer.project(hiddenLayer); hiddenLayer.project(outputLayer); // 3. 封装为网络 var myNetwork new Network({ input: inputLayer, hidden: [hiddenLayer], output: outputLayer }); // 4. 训练学习 XOR异或 var learningRate .3; for (var i 0; i 20000; i) { // XOR 真值表四个样本轮流训练 var samples [ { input: [0,0], output: [0] }, { input: [0,1], output: [1] }, { input: [1,0], output: [1] }, { input: [1,1], output: [0] } ]; var sample samples[i % 4]; myNetwork.activate(sample.input); myNetwork.propagate(learningRate, sample.output); } // 5. 验证 console.log(myNetwork.activate([0,1])); // 接近 [1] console.log(myNetwork.activate([1,1])); // 接近 [0]这个例子完整展示了 Layer 的创建含set批量配置压缩函数、project连接、以及经 Network 封装的activate/propagate训练闭环。类似的 Layer project 用法也出现在仓库测试中如 test/synaptic.js 中对new Layer(2)、new Layer(1)并inputLayer.project(outputLayer)的线性回归训练验证可作为对照参考。小结Synaptic 的 Layer API 由五个核心方法构成一个完整闭环project定义层间/自连接拓扑三种connectionType覆盖全连接、逐元素连接与排除自身连接gate用第三个层门控已有连接三种gateType对应 LSTM 输入门、输出门与遗忘门的实现activate整层前向计算返回输出数组propagate反向传播误差逐轮调整权重与偏置set / neurons批量配置神经元属性与获取神经元列表。理解这五个方法你就掌握了 Synaptic 手工构建任意神经网络的全部底层能力——这正是 LSTM、Perceptron 等预置架构的构成基础。相关实现与测试可继续深入 src/Layer.js、src/LayerConnection.js、src/Neuron.js 与 test/synaptic.js 阅读。赞分享机器学习深度学习【免费下载链接】synapticarchitecture-free neural network library for node.js and the browser项目地址https://gitcode.com/gh_mirrors/sy/synaptic点击查看免费下载相关推荐synaptic 中的 Layer层完全指南project / gate / activate / propagate 实战详解synaptic 中的 Layer层完全指南project / gate / activate / propagate 实战详解 本篇技术指南以 syna机器学习深度学习TensorSpace Layer API完全指南从输入层到输出层的全方位解析TensorSpace Layer API完全指南从输入层到输出层的全方位解析 TensorSpace Layer API是构建神经网络3D可视化模型的核心工数据可视化深度学习3D渲染AI 可解释性GrapesJS Layer Manager 完全指南API、事件与自定义图层树实现GrapesJS Layer Manager 完全指南API、事件与自定义图层树实现 Layer Manager图层管理器是 GrapesJS 中将组件前端低代码UI组件上一篇解锁iOS应用宝库命令行直达App Store下载神器下一篇Mu 开源项目教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表