如何用30行JavaScript代碼編寫神經網絡異或運算器
配置環(huán)境、安裝合適的庫、下載數據集……有時候學習深度學習的前期工作很讓人沮喪,如果只是為了試試現在人人都談的深度學習,做這些麻煩事似乎很不值當。但好在我們也有一些更簡單的方法可以體驗深度學習。近日,編程學習平臺 Scrimba 聯(lián)合創(chuàng)始人 Per Harald Borgen 在 Medium 上發(fā)文介紹了一種僅用 30 行 JavaScript 代碼就創(chuàng)建出了一個神經網絡的教程,而且使用的工具也只有 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 創(chuàng)建和訓練神經網絡。
- // 創(chuàng)建網絡const { Layer, Network } = window.synaptic;var inputLayer = new Layer(2);var hiddenLayer = new Layer(3);var outputLayer = new Layer(1);
- inputLayer.project(hiddenLayer);
- hiddenLayer.project(outputLayer);varmyNetwork = newNetwork({
- input: inputLayer,
- hidden: [hiddenLayer],
- output: outputLayer
- });// 訓練網絡——學習異或運算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]);
- }// 測試網絡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]
我們將創(chuàng)建一個最簡單的神經網絡:一個可以執(zhí)行異或運算的網絡。上面就是這個網絡的全部代碼,但在我們深入解讀這些代碼之前,首先我們先了解一下神經網絡的基礎知識。
神經元和突觸
神經網絡的基本構造模塊是神經元。神經元就像是一個函數,有幾個輸入,然后可以得到一個輸出。神經元的種類有很多。我們的網絡將使用 sigmoid 神經元,它可以輸入任何數字并將其壓縮到 0 到 1 之間。下圖就是一個 sigmoid 神經元。它的輸入是 5,輸出是 1。箭頭被稱為突觸,可以將該神經元與網絡中的其它層連接到一起。
所以,紅色的數字 5 是哪里來的?它是左邊的三個突觸的和,讓我們來剖析一下。
在最左邊我們可以看到兩個值和一個所謂偏置(bias)值。這兩個值是 1 和 0,用綠色表示。偏置值是 -2,用棕色表示。
首先,這兩個輸入與它們的權重(weight)相乘,即藍色的數字 7 和 3。***我們將這兩個值與偏置加到一起就得到了紅色的 5。這就是這個人工神經元的輸入。
因為這是一個 sigmoid 神經元,會將任何值壓縮到 0 到 1 之間,那么這個輸出可以被壓縮成 1。
如果你將這些神經元連接成一個網絡,你就得到了一個神經網絡。通過突觸彼此相連的神經元可以向前傳播輸入,從而得到輸出,如下圖所示:
訓練神經網絡的目的是讓它能夠進行泛化,比如識別手寫的數字或垃圾郵件。實現很好的泛化涉及為整個網絡找到合適的權重和偏置值,就像我們上面案例中的藍色和棕色數字。
當訓練一個神經網絡時,你只需要向其展示大量樣本(比如手寫數字),然后讓其預測正確的答案即可。
在每次預測之后,你要計算這個預測的錯誤程度,并調整其權重和偏置值讓該網絡在下一輪預測時能更正確一點。這個學習過程被稱為反向傳播(backpropagation)。如此反復幾千次,你的網絡很快就擅長泛化了。
本教程不會解釋反向傳播的具體技術細節(jié),但如果你有興趣了解,可以參閱下面的文章:
- 反向傳播的一步步示例:http://mattmazur.com/2015/03/17/a-step-by-step-backpropagation-example/
- 神經網絡黑客指南:http://karpathy.github.io/neuralnets/
- 神經網絡和深度學習:http://neuralnetworksanddeeplearning.com/chap1.html
代碼
現在你已經了解了基本的知識,就開始寫代碼吧!首先我們需要創(chuàng)建層。我們可以使用 synaptic 中的 new Layer() 函數。傳遞給該函數的數字表示每層應該有多少個神經元。
如果你不知道層是什么,可以看看上面提到的交互式教程。
- const{Layer,Network}=window.synaptic;varinputLayer =newLayer(2);varhiddenLayer =newLayer(3);varoutputLayer =newLayer(1);
接下來,我們將這些層連接到一起,并實例化一個新網絡,如下:
- );
- hiddenLayer.project(outputLayer);varmyNetwork =newNetwork({
- input:inputLayer,
- hidden:[hiddenLayer],
- output:outputLayer
- });
所以,這就是一個「2 層-3 層-1 層」的網絡,可以可視化為下圖的形式:
現在訓練這個網絡:
- // train the network - learn XORvar 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]);
- }
這里我們運行該網絡 20000 次。每一次我們都前向和反向傳播 4 次,為該網絡輸入 4 組可能的輸入:[0,0] [0,1] [1,0] [1,1]。
首先我們執(zhí)行 myNetwork.activate([0,0]),其中 [0,0] 是我們發(fā)送給該網絡的數據點。這是前向傳播,也稱為激活這個網絡。在每次前向傳播之后,我們需要執(zhí)行反向傳播,這時候網絡會更新自己的權重和偏置。
反向傳播是通過這行代碼完成的:myNetwork.propagate(learningRate, [0]),其中 learningRate 是一個常數,給出了網絡每次應該調整的權重的量。第二個參數 0 是給定輸入 [0,0] 對應的正確輸出。
然后,該網絡將自己的預測與正確的標簽進行比較,從而了解自己的正確程度有多少。
然后網絡使用這個比較為基礎來校正自己的權重和偏置值,這樣讓自己的下一次猜測更加正確一點。
這個過程如此反復 20000 次之后,我們可以使用所有四種可能的輸入來檢查網絡的學習情況:
- ->[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]
如果我們將這些值四舍五入到最近的整數,我們就得到了正確的異或運算結果。
這樣就完成了。盡管這僅僅只碰到了神經網絡的表皮,但也足以幫助你進一步探索 Synaptic 和繼續(xù)學習了。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專欄機構“機器之心”的原創(chuàng)譯文,微信公眾號“機器之心( id: almosthuman2014)”】