如何用30行JavaScript代码编写神经网络异或运算器

开发 开发工具
本文介绍了一种仅用 30 行 JavaScript 代码就创建出了一个神经网络的教程,而且使用的工具只有 Node.js、Synaptic.js 和浏览器。

配置环境、安装合适的库、下载数据集……有时候学习深度学习的前期工作很让人沮丧,如果只是为了试试现在人人都谈的深度学习,做这些麻烦事似乎很不值当。但好在我们也有一些更简单的方法可以体验深度学习。近日,编程学习平台 Scrimba 联合创始人 Per Harald Borgen 在 Medium 上发文介绍了一种仅用 30 行 JavaScript 代码就创建出了一个神经网络的教程,而且使用的工具也只有 Node.js、Synaptic.js 和浏览器而已。另外,作者还做了一个交互式 Scrimba 教程,也许能帮你理解其中的复杂概念。

  • Synaptic.js:https://synaptic.juancazala.com
  • Node.js:https://nodejs.org
  • Scrimba 教程:https://scrimba.com/casts/cast-1980

Synaptic.js 让你可以使用 Node.js 和浏览器做深度学习。在这篇文章中,我将介绍如何使用 Synaptic.js 创建和训练神经网络。

  1. // 创建网络const { Layer, Network } = window.synaptic;var inputLayer = new Layer(2);var hiddenLayer = new Layer(3);var outputLayer = new Layer(1); 
  2. inputLayer.project(hiddenLayer); 
  3. hiddenLayer.project(outputLayer);varmyNetwork = newNetwork({ 
  4. input: inputLayer, 
  5. hidden: [hiddenLayer], 
  6. output: outputLayer 
  7. });// 训练网络——学习异或运算var learningRate = .3;for (var i = 0; i < 20000; i++) 
  8. { // 0,0 => 0 
  9. myNetwork.activate([0,0]); 
  10. myNetwork.propagate(learningRate, [0]); // 0,1 => 1 
  11. myNetwork.activate([0,1]); 
  12. myNetwork.propagate(learningRate, [1]); // 1,0 => 1 
  13. myNetwork.activate([1,0]); 
  14. myNetwork.propagate(learningRate, [1]); // 1,1 => 0 
  15. myNetwork.activate([1,1]); 
  16. myNetwork.propagate(learningRate, [0]); 
  17. }// 测试网络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] 

我们将创建一个最简单的神经网络:一个可以执行异或运算的网络。上面就是这个网络的全部代码,但在我们深入解读这些代码之前,首先我们先了解一下神经网络的基础知识。

神经元和突触

神经网络的基本构造模块是神经元。神经元就像是一个函数,有几个输入,然后可以得到一个输出。神经元的种类有很多。我们的网络将使用 sigmoid 神经元,它可以输入任何数字并将其压缩到 0 到 1 之间。下图就是一个 sigmoid 神经元。它的输入是 5,输出是 1。箭头被称为突触,可以将该神经元与网络中的其它层连接到一起。

 sigmoid 神经元

所以,红色的数字 5 是哪里来的?它是左边的三个突触的和,让我们来剖析一下。

在最左边我们可以看到两个值和一个所谓偏置(bias)值。这两个值是 1 和 0,用绿色表示。偏置值是 -2,用棕色表示。

首先,这两个输入与它们的权重(weight)相乘,即蓝色的数字 7 和 3。***我们将这两个值与偏置加到一起就得到了红色的 5。这就是这个人工神经元的输入。

因为这是一个 sigmoid 神经元,会将任何值压缩到 0 到 1 之间,那么这个输出可以被压缩成 1。

如果你将这些神经元连接成一个网络,你就得到了一个神经网络。通过突触彼此相连的神经元可以向前传播输入,从而得到输出,如下图所示:

训练神经网络的目的是让它能够进行泛化,比如识别手写的数字或垃圾邮件。实现很好的泛化涉及为整个网络找到合适的权重和偏置值,就像我们上面案例中的蓝色和棕色数字。

当训练一个神经网络时,你只需要向其展示大量样本(比如手写数字),然后让其预测正确的答案即可。

在每次预测之后,你要计算这个预测的错误程度,并调整其权重和偏置值让该网络在下一轮预测时能更正确一点。这个学习过程被称为反向传播(backpropagation)。如此反复几千次,你的网络很快就擅长泛化了。

本教程不会解释反向传播的具体技术细节,但如果你有兴趣了解,可以参阅下面的文章:

  • 反向传播的一步步示例:http://mattmazur.com/2015/03/17/a-step-by-step-backpropagation-example/
  • 神经网络黑客指南:http://karpathy.github.io/neuralnets/
  • 神经网络和深度学习:http://neuralnetworksanddeeplearning.com/chap1.html

代码

现在你已经了解了基本的知识,就开始写代码吧!首先我们需要创建层。我们可以使用 synaptic 中的 new Layer() 函数。传递给该函数的数字表示每层应该有多少个神经元。

如果你不知道层是什么,可以看看上面提到的交互式教程。

  1. const{Layer,Network}=window.synaptic;varinputLayer =newLayer(2);varhiddenLayer =newLayer(3);varoutputLayer =newLayer(1); 

接下来,我们将这些层连接到一起,并实例化一个新网络,如下:

  1. ); 
  2. hiddenLayer.project(outputLayer);varmyNetwork =newNetwork({ 
  3. input:inputLayer, 
  4. hidden:[hiddenLayer], 
  5. output:outputLayer 
  6. }); 

所以,这就是一个「2 层-3 层-1 层」的网络,可以可视化为下图的形式:

现在训练这个网络:

  1. // train the network - learn XORvar learningRate = .3;for (var i = 0; i < 20000; i++) { // 0,0 => 0 
  2. myNetwork.activate([0,0]); 
  3. myNetwork.propagate(learningRate,[0]);// 0,1 => 1 
  4. myNetwork.activate([0,1]); 
  5. myNetwork.propagate(learningRate,[1]);// 1,0 => 1 
  6. myNetwork.activate([1,0]); 
  7. myNetwork.propagate(learningRate,[1]);// 1,1 => 0 
  8. myNetwork.activate([1,1]); 
  9. myNetwork.propagate(learningRate,[0]); 

这里我们运行该网络 20000 次。每一次我们都前向和反向传播 4 次,为该网络输入 4 组可能的输入:[0,0] [0,1] [1,0] [1,1]。

首先我们执行 myNetwork.activate([0,0]),其中 [0,0] 是我们发送给该网络的数据点。这是前向传播,也称为激活这个网络。在每次前向传播之后,我们需要执行反向传播,这时候网络会更新自己的权重和偏置。

反向传播是通过这行代码完成的:myNetwork.propagate(learningRate, [0]),其中 learningRate 是一个常数,给出了网络每次应该调整的权重的量。第二个参数 0 是给定输入 [0,0] 对应的正确输出。

然后,该网络将自己的预测与正确的标签进行比较,从而了解自己的正确程度有多少。

然后网络使用这个比较为基础来校正自己的权重和偏置值,这样让自己的下一次猜测更加正确一点。

这个过程如此反复 20000 次之后,我们可以使用所有四种可能的输入来检查网络的学习情况:

  1. ->[0.015020775950893527]console.log(myNetwork.activate([0,1])); 
  2. ->[0.9815816381088985]console.log(myNetwork.activate([1,0])); 
  3. ->[0.9871822457132193]console.log(myNetwork.activate([1,1])); 
  4. ->[0.012950087641929467] 

如果我们将这些值四舍五入到最近的整数,我们就得到了正确的异或运算结果。

这样就完成了。尽管这仅仅只碰到了神经网络的表皮,但也足以帮助你进一步探索 Synaptic 和继续学习了。https://github.com/cazala/synaptic/wiki 这里还包含了更多好教程。

原文:

https://medium.freecodecamp.org/how-to-create-a-neural-network-in-javascript-in-only-30-lines-of-code-343dafc50d49

【本文是51CTO专栏机构“机器之心”的原创译文,微信公众号“机器之心( id: almosthuman2014)”】

 

戳这里,看该作者更多好文

责任编辑:赵宁宁 来源: 51CTO专栏
相关推荐

2017-09-18 08:08:33

JavaScript神经网络代码

2017-09-15 13:35:11

JavaScript神经网络

2009-06-11 16:11:26

Java运算器一则运算

2017-04-26 08:31:10

神经网络自然语言PyTorch

2019-10-28 08:00:00

Keras神经网络人工智能

2019-07-25 08:20:37

代码开发神经网络

2018-02-05 08:58:36

Python神经网络识别图像

2019-05-05 09:46:01

Python代码神经网络

2022-05-18 16:06:15

位运算异或运算

2024-06-28 08:15:02

2024-06-11 08:19:34

2020-04-20 13:45:32

神经网络模型代码

2021-11-10 09:57:02

异或运算应用

2017-06-19 15:12:30

Uber神经网络事件预测

2018-06-19 08:35:51

情感分析数据集代码

2017-06-11 23:38:43

进化图像神经网络

2017-07-27 10:46:44

神经网络机器学习强化学习

2020-08-06 10:11:13

神经网络机器学习算法

2022-05-23 15:02:19

异或运算面试真题

2022-06-07 09:30:35

JavaScript变量名参数
点赞
收藏

51CTO技术栈公众号