目前神经网络方面用得最广的无疑是Python,但搭建Python的环境还是一个问题,因为本身Python就有版本2和版本3的区分,又有各个依赖包(所以,需要使用conda配置各个Python环境)。但JavaScript则不存在这个问题,只需要有node和浏览器就可以进行学习和使用。
而且随着技术的发展,未来智能是要嵌入到各个设备、并且需要即时响应的,比如网页浏览,如果可以直接在网页上完成神经网络的训练,一方面提高响应速度,另一方面又降低了服务器的消耗。所以,学习使用js搭建小型的神经网络很有必要。
今天我们使用开源js库——synaptic.js来搭建一个简单的神经网络——解决异或问题(XOR)的神经网络。
神经网络基础知识
首先温习一下神经网络的基础知识。神经网络的基础单元是神经元。
神经元就像是一个函数,又称激活函数,输入数据,然后给出输出结果。神经元有很多类型,我们使用sigmoid神经元,亦即一个特定的函数。下图即sigmoid函数:
。
此函数可以将x值映射到0和1之间。
神经元模型如下:
输入乘以权重就是神经元的总输入X,然后总输入经过sigmoid函数后,得到输出Y,即sigmoid(X)=Y
,这样,就将输入映射到了0和1之间。
神经元通过突触相互连接,从输入到输出,逐层相连后即可形成神经网络:
权重的计算
突触的权重一般是先给定一个初始值,然后开始正向进行神经元计算,一直到输出结果,然后根据误差,开始反向传播(backpropagation),进行误差调整和偏差值调整。因为本篇文章的重点是神经网络在JavaScript中的应用,就不展开了,可自行查阅BP反向传播算法资料。
XOR神经网络实现
了解了基本知识后,我们开始写代码吧,为了方便大家快速学习,我这里使用CDN引入Synaptic,所以大家只需要创建一个html文件,然后把下面的代码复制粘贴进去即可。代码如下:
<!DOCTYPE html>
<html>
<head>
<title>XOR神经网络实现</title>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/synaptic/1.1.0/synaptic.js"></script>
<script>
const { Network, Layer } = window.synaptic;
// 创建神经网络层
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
});
// 神经网络训练
var train = [[0,0], [0,1], [1,0], [1,1]]; // 训练数据
var labels = [0, 1, 1, 0]; // 标签
var learningRate = 0.1; // 学习率
// 将训练数据10000次
for (var i = 0; i < 10000; i++) {
for(var j = 0; j < train.length; j++) {
myNetwork.activate(train[j]);
myNetwork.propagate(learningRate, [labels[j]]);
}
}
// 测试输出
for(var j = 0; j < train.length; j++) {
console.log(train[j] + "-> predict: " + myNetwork.activate(train[j]) + "; label:"+labels[j]);
}
</script>
</body>
</html>
输出结果:
0,0-> predict: 0.0005624499128064958; label:0
test.html:39 0,1-> predict: 0.9970162975810412; label:1
test.html:39 1,0-> predict: 0.9971341382083764; label:1
test.html:39 1,1-> predict: 0.004872445055285009; label:0
符合预期。
代码解析
其实,如果大家对神经网络了解的话,可以看出,Synaptic的代码是非常简洁的。下面,我分三部分描述代码:创建神经网络层、搭建神经网络、神经网络训练。
创建神经网络层
const { Network, Layer } = window.synaptic;
// 创建神经网络层
var inputLayer = new Layer(2); // 输入层
var hiddenLayer = new Layer(3); // 隐含层
var outputLayer = new Layer(1); // 输出层
第一行代码是从synaptic中获取Network类和Layer类。然后我们声明了神经网络的三个层,这是比较经典的全连接神经网络,第一个为输入层,异或运算需要两个输入,所以是两个神经元;第二个为隐含层,初学者可以把隐含层看做是黑盒,用于提高精确性;第三个为输出层,此即异或运算的输出结果。
神经网络的搭建
代码如下:
// 搭建神经网络
inputLayer.project(hiddenLayer);
hiddenLayer.project(outputLayer);
var myNetwork = new Network({
input: inputLayer,
hidden: [hiddenLayer],
output: outputLayer
});
代码很直观,就是把三个层先关联起来,然后创建一个神经网络,Synaptic的api还是很友好的。
神经网络的训练
// 神经网络训练
var train = [[0,0], [0,1], [1,0], [1,1]]; // 训练数据
var labels = [0, 1, 1, 0]; // 标签
var learningRate = 0.1; // 学习率
// 将训练数据10000次
for (var i = 0; i < 10000; i++) {
for(var j = 0; j < train.length; j++) {
myNetwork.activate(train[j]);
myNetwork.propagate(learningRate, [labels[j]]);
}
}
首先是确定训练数据,learningRate
是一个常数,告诉网络每次应该调整多少权重。在训练的时候,首先正向预测,然后传入真实值反向传播,调整权重。不断的重试重试重试,10000
次后,权重就调节得差不多了。
最后的结果也符合预期,[0,0]
的输出结果是0.0005
,即输出0
。