Javascript 機器學習的四個層次
Atwood定律說,凡是可以用Javascript實現的應用,最終都會用Javascript實現掉。作為最熱門的機器學習領域,服務端是Python的主場,但是到了手機端呢?Android和iOS里默認都沒有Python。但是有瀏覽器的地方就有js,現在還有個新場景 - 小程序。
除此之外,為了可以在不聯網情況下進行訓練的,也有支持本地框架比如React Native的。
可以說,只要有前端的地方,就有機器學習的框架在。
js唯一的問題在于,變化太快,每年都有很多新庫出現,但是也有不少老的庫宣布不維護了。但是,萬變不離其宗,工具本身雖然經常有變化,但是它們的類型是非常穩定的。
選擇機器學習工具的方法論
我們要寫機器學習算法,需要什么樣的工具呢?
機器學習工具可以分為以下四個層次:
層次一:直接服務于具體領域的框架
首先我們需要直接服務于具體領域的框架,比如處理CV的,NLP的,推薦算法之類的。
比如nlp.js,上一個版本發布在2020年10月。nlp.js的代碼寫起來是這樣的:
- const { NlpManager } = require('node-nlp');const manager = new NlpManager({ languages: ['en'], forceNER: true });// Adds the utterances and intents for the NLPmanager.addDocument('en', 'goodbye for now', 'greetings.bye');manager.addDocument('en', 'bye bye take care', 'greetings.bye');manager.addDocument('en', 'okay see you later', 'greetings.bye');manager.addDocument('en', 'bye for now', 'greetings.bye');manager.addDocument('en', 'i must go', 'greetings.bye');manager.addDocument('en', 'hello', 'greetings.hello');manager.addDocument('en', 'hi', 'greetings.hello');manager.addDocument('en', 'howdy', 'greetings.hello');// Train also the NLGmanager.addAnswer('en', 'greetings.bye', 'Till next time');manager.addAnswer('en', 'greetings.bye', 'see you soon!');manager.addAnswer('en', 'greetings.hello', 'Hey there!');manager.addAnswer('en', 'greetings.hello', 'Greetings!');// Train and save the model.(async() => { await manager.train(); manager.save(); const response = await manager.process('en', 'I should go now'); console.log(response);})();
運行起來很簡單,裝個庫就好:
npm install node-nlp
訓練的速度也很快:
- Epoch 1 loss 0.4629286907733636 time 1msEpoch 2 loss 0.2818764774939686 time 0msEpoch 3 loss 0.16872372018062168 time 0msEpoch 4 loss 0.11241683507408215 time 0ms...Epoch 31 loss 0.00004645272306535786 time 0ms
輸出的結果類似這樣:
- { locale: 'en', utterance: 'I should go now', settings: undefined, languageGuessed: false, localeIso2: 'en', language: 'English', nluAnswer: { classifications: [ [Object] ], entities: undefined, explanation: undefined }, classifications: [ { intent: 'greetings.bye', score: 1 } ], intent: 'greetings.bye', score: 1, domain: 'default', sourceEntities: [ { start: 12, end: 14, resolution: [Object], text: 'now', typeName: 'datetimeV2.datetime' } ], entities: [ { start: 12, end: 14, len: 3, accuracy: 0.95, sourceText: 'now', utteranceText: 'now', entity: 'datetime', resolution: [Object] } ], answers: [ { answer: 'Till next time', opts: undefined }, { answer: 'see you soon!', opts: undefined } ], answer: 'see you soon!', actions: [], sentiment: { score: 0.5, numWords: 4, numHits: 1, average: 0.125, type: 'senticon', locale: 'en', vote: 'positive' }}
層次二:深度學習框架
第二是我們的核心內容,深度學習框架。
說到Javascript深度學習,占統治地位的仍然是Tensorflow.js,我們來看個經典的強化學習的例子:
使用瀏覽器的local storage和indexdb作為存儲,邊訓練邊展示訓練效果的過程,很有前端的風范。
我們再看另一個大廠微軟的例子,支持webGL和wasm,基于瀏覽器不容易:
另外需要強調的是,用于前端的框架并不是簡單的把native或者python框架移植過來的,比如說它要處理兼容性的問題:
很多同學都對Tensorflow有一定了解,我們就手寫一個網頁,然后在其中調tf的API就好:
- <!DOCTYPE html><html> <head> <meta encoding="UTF-8"/> <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@3.0.0/dist/tf.min.js"></script> </head> <body> <div id="tf-display"></div> <script> let a = tf.tensor1d([1.0]); let d1 = document.getElementById("tf-display"); d1.innerText = a;</script> </body></html>
層次三:機器學習框架
第三是機器學習的框架。光了解深度學習還不夠,傳統的機器學習在更貼近業務的時候,可能效果更好,還節省算力資源。比如可以使用mljs庫,地址在:https://github.com/mljs/ml
比如我們想做個k-means聚類,可以使用mljs框架的ml-kmeans庫:
- const kmeans = require('ml-kmeans');let data = [[1, 1, 1], [1, 2, 1], [-1, -1, -1], [-1, -1, -1.5]];let centers = [[1, 2, 1], [-1, -1, -1]];let ans = kmeans(data, 2, { initialization: centers });console.log(ans);
裝個包就可以玩了:
npm i ml-kmeans
運行結果如下:
- KMeansResult { clusters: [ 0, 0, 1, 1 ], centroids: [ { centroid: [Array], error: 0.25, size: 2 }, { centroid: [Array], error: 0.0625, size: 2 } ], converged: true, iterations: 2, [Symbol(distance)]: [Function: squaredEuclidean]}
我們也可以直接在網頁中使用,比如我們寫個K近鄰的例子:
- <!DOCTYPE html><html> <head> <meta encoding="UTF-8" /> <script src="https://www.lactame.com/lib/ml/4.0.0/ml.min.js"></script> </head> <body> <div id="ml-display"></div> <script> const train_dataset = [ [0, 0, 0], [0, 1, 1], [1, 1, 0], [2, 2, 2], [1, 2, 2], [2, 1, 2], ]; const train_labels = [0, 0, 0, 1, 1, 1]; let knn = new ML.KNN(train_dataset, train_labels, { k: 2 }); // consider 2 nearest neighbors const test_dataset = [ [0.9, 0.9, 0.9], [1.1, 1.1, 1.1], [1.1, 1.1, 1.2], [1.2, 1.2, 1.2], ]; let ans = knn.predict(test_dataset); let d1 = document.getElementById("ml-display"); d1.innerText = ans;</script> </body></html>
最后我們再來個決策樹的例子
- const irisDataset = require('ml-dataset-iris');const DecisionTreeClassifier = require('ml-cart');const trainingSet = irisDataset.getNumbers();const predictions = irisDataset .getClasses() .map((elem) => irisDataset.getDistinctClasses().indexOf(elem));const options = { gainFunction: 'gini', maxDepth: 10, minNumSamples: 3,};const classifier = new DecisionTreeClassifier.DecisionTreeClassifier(options);classifier.train(trainingSet, predictions);const result = classifier.predict(trainingSet);console.log(result);
輸出結果如下:
- [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ... 50 more items]
層次四:數學和統計庫
第四個層次是數學和統計庫。做統計和數學計算,很多時候才是理解業務的最好手段。這個時候我們也不能空手上,也需要工具。
這方面的代表庫有stdlib: https://stdlib.io/雖然它名字和實際都是標準庫,但是為了數學和統計提供了很豐富的內容,比如150多個數學函數和35種統計分布。
我們先安裝一下做后面的實驗:
npm install @stdlib/stdlib
比如各種數學函數:
再比如各種隨機分布:
我們以正態分布為例,看看stdlib是如何描述分布的:
- const Normal = require( '@stdlib/stats/base/dists/normal' ).Normal;let dist1 = new Normal( 0, 1 );console.log(dist1);let m1 = dist1.mean;console.log(m1);let v1 = dist1.variance;console.log(v1);
構造Normal時的兩個參數是均值和方差。
輸出如下:
Normal { mu: [Getter/Setter], sigma: [Getter/Setter] }01
這個無良的標準庫竟然還支持50多種數據集,看個小例子,美國州首府的數據集:
- const capitals = require( '@stdlib/datasets/us-states-capitals' );const data_c = capitals();console.log(data_c);
輸出結果如下:
- [ 'Montgomery', 'Juneau', 'Phoenix', 'Little Rock', 'Sacramento', 'Denver', 'Hartford', 'Dover', 'Tallahassee', 'Atlanta', 'Honolulu', 'Boise', 'Springfield', 'Indianapolis', 'Des Moines', 'Topeka', 'Frankfort', 'Baton Rouge', 'Augusta', 'Annapolis', 'Boston', 'Lansing', 'Saint Paul', 'Jackson', 'Jefferson City', 'Helena', 'Lincoln', 'Carson City', 'Concord', 'Trenton', 'Santa Fe', 'Albany', 'Raleigh', 'Bismarck', 'Columbus', 'Oklahoma City', 'Salem', 'Harrisburg', 'Providence', 'Columbia', 'Pierre', 'Nashville', 'Austin', 'Salt Lake City', 'Montpelier', 'Richmond', 'Olympia', 'Charleston', 'Madison', 'Cheyenne']
總結
綜上,如果要做從0到1的業務,盡可能用第一層次的工具,這樣最有助于快速落地。但是如果是要做增量,尤其是困難的增長,第三第四層次是首選,因為更有助于深刻理解數據。