JavaScript 也能做機(jī)器學(xué)習(xí)(1)

每當(dāng)談起機(jī)器學(xué)習(xí)钠导、深度學(xué)習(xí)骡澈,大家自然就會(huì)想到 python c++ GPU tensorflow python 這些詞。似乎距離前端人員比較遙遠(yuǎn)的事 毅人,今天我們就用 js 來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單分類(lèi)的算法吭狡。

一切從簡(jiǎn)單開(kāi)始,從一個(gè)分類(lèi)問(wèn)題開(kāi)始吧丈莺。任務(wù)就是一個(gè)二分類(lèi)的問(wèn)題划煮,通過(guò)既有的數(shù)據(jù)訓(xùn)練得到一個(gè)模型,然后用模型來(lái)對(duì)一個(gè)數(shù)據(jù)預(yù)測(cè)其屬于哪一個(gè)類(lèi)別缔俄,來(lái)了解是如何使用 javascript 進(jìn)行機(jī)器學(xué)習(xí)弛秋。

const R = require('ramda');
randomPoints = R.range(0,5);

這里引入了 ramda 庫(kù)幫助生成隨機(jī)數(shù),實(shí)現(xiàn)起來(lái)很簡(jiǎn)單俐载。

[ 0, 1, 2, 3, 4 ] 
var rand = (high,low)=> Math.random()*(high - low) + low
randomPoints = R.range(0,100).map(_=> rand(-1,1));

生成在 -1 到 1 之間的隨機(jī)數(shù)蟹略,這里使用 map 方法來(lái)實(shí)現(xiàn)返回在某個(gè)區(qū)間的隨機(jī)數(shù)、

[ -0.9515869798311445,
  -0.884506721474116,
  0.7849131001955243,
  -0.8271371680230728,
  0.6015755023017424,

上面隨機(jī)數(shù)瞎疼,然后我們用這些隨機(jī)數(shù)生成隨機(jī)點(diǎn)科乎,x 和 y 都是 -1 到 1 之間隨機(jī)數(shù)

randomPoints = R.range(0,100).map(_=> (
    {
        x:rand(-1,1),
        y:rand(-1,1)
    }));

我們將這些隨機(jī)點(diǎn)通過(guò) svg 以繪制在寬和高同為 400 的區(qū)域來(lái)顯示,讓你更直觀(guān)地觀(guān)察機(jī)器學(xué)習(xí)的過(guò)程贼急。

// const R = require('ramda');

var rand = (high,low)=> Math.random()*(high - low) + low

const X_MAX = 400;
const Y_MAX = 400;

randomPoints = R.range(0,100).map(_=> (
    {
        x:rand(0,X_MAX),
        y:rand(0,Y_MAX)
    }));

    console.log(randomPoints)

var html=`
    <svg width="${X_MAX}" height="${Y_MAX}">
        ${randomPoints.map(point=>
            `<circle 
                cx="${point.x}"
                cy="${point.y}"
                r="5"
                />`
        )}
        <line x1="0" x2="${X_MAX}" y1="0" y2="${Y_MAX}" stroke="purple"/>
    </svg>
`;

document.getElementById("app").innerHTML = html;

并且將這些隨機(jī)點(diǎn)顯示出來(lái)茅茂,這些點(diǎn)散落在寬高都是 400 的個(gè)方形區(qū)域,然后繪制一條線(xiàn)太抓,這條線(xiàn)就是我們隨后擬合分割線(xiàn)空闲,這條線(xiàn)將這些樣本點(diǎn)分成了兩個(gè)類(lèi)別,位于線(xiàn)上部分是一個(gè)類(lèi)別走敌,位于線(xiàn)下面又是一個(gè)類(lèi)別碴倾。

其實(shí)問(wèn)題很簡(jiǎn)單,只要某一個(gè)點(diǎn) y 坐標(biāo)大于 x 坐標(biāo)掉丽,或者 y 坐標(biāo)小于 x 坐標(biāo)屬于另一個(gè)類(lèi)別跌榔,如果某一個(gè)點(diǎn) x 坐標(biāo)大于 y 輸入 1 否則 -1 也就是用 1 和 -1 表示兩個(gè)類(lèi)別

var team = point => point.x > point.y ? 1 : -1;

接下來(lái)通過(guò)顏色來(lái)表示兩個(gè)不同類(lèi)別,類(lèi)別為 -1 的點(diǎn)用藍(lán)色來(lái)表示捶障,而 1 則用紅色點(diǎn)來(lái)表示僧须。

var html=`
    <svg width="${X_MAX}" height="${Y_MAX}">
        ${randomPoints.map(point=>
            `<circle 
                cx="${point.x}"
                cy="${point.y}"
                r="5"
                fill="${team(point)===-1?'blue':'red'}"
                />`
        )}
        <line x1="0" x2="${X_MAX}" y1="0" y2="${Y_MAX}" stroke="purple"/>
    </svg>
`;

team 函數(shù)通過(guò)簡(jiǎn)單邏輯(規(guī)則)對(duì)隨機(jī)點(diǎn)進(jìn)行分類(lèi),通過(guò)點(diǎn)的 x 和 y 值大小進(jìn)行判斷可以進(jìn)行判斷项炼。

開(kāi)始寫(xiě)模型

好接下來(lái)我們就開(kāi)始構(gòu)建 AI 來(lái)模擬機(jī)器學(xué)習(xí)過(guò)程担平。初始一個(gè)隨機(jī)參數(shù)模型參數(shù)比較有意思是兩個(gè)取值從 -1 到 1 的隨機(jī)數(shù),這里這樣理解我們通過(guò) x 和 y 之間比值來(lái)劃分 ax + by

a x + b y = 0

var randomWeights = ({
    x:rand(-1,1),
    y:rand(-1,1)
})

這里 guess 函數(shù)會(huì)輸出一個(gè)類(lèi)別锭部,也就是我們函數(shù)模型暂论,這里有連個(gè)參數(shù),或者叫做權(quán)重拌禾,權(quán)重負(fù)責(zé)根據(jù) x 和 y 給出一個(gè)該點(diǎn)所屬類(lèi)別 1 * x + -1*y > 0 這個(gè)關(guān)系取胎。

var guess =(weights,point) => {
    const sum = 
        point.x * weights.x +
        point.y * weights.y
    const team = sum >= 0 ? 1 : -1
    return team
}

testGuess = guess(randomWeights,{x:300,y:400})

這里 weights 是權(quán)重,point 是輸入湃窍,sum 為輸入和權(quán)重乘積的和扼菠,這個(gè)神經(jīng)元有兩個(gè)輸入 x 和 y(兩個(gè)特征)然后輸出為 1 或 -1

var html=`
    <svg width="${X_MAX}" height="${Y_MAX}">
        ${randomPoints.map(point=>
            `<circle 
                cx="${point.x}"
                cy="${point.y}"
                r="5"
                fill="${guess(randomWeights,point)===-1?'blue':'red'}"
                />`
        )}
        <line x1="0" x2="${X_MAX}" y1="0" y2="${Y_MAX}" stroke="purple"/>
    </svg>
`;

以為 weight 是隨機(jī)數(shù)摄杂,我們每次刷新會(huì)得到不同結(jié)果。

創(chuàng)建我們訓(xùn)練函數(shù)循榆,訓(xùn)練接收 weights 和 point 輸入析恢,以及期望值 actualTeam 通過(guò)對(duì)比判斷結(jié)果和期望值對(duì)比來(lái)反饋到訓(xùn)練,進(jìn)行優(yōu)化調(diào)整weight 獲取正確計(jì)算模型

function train(weights,point, actualTeam){
    //loss

    //otimizer
}
function train(weights,point, actualTeam){
    //loss
    const guessResult = guess(weights,point) //1
    const error = actualTeam - guessResult;
    return error
    //otimizer
}
var testTrain = () => {
    const point = {x:200,y:400}
    return train(randomWeights,point,team(point))
}
console.log(`result ${testTrain()}`)

上面代碼可以簡(jiǎn)單測(cè)試我們計(jì)算結(jié)果和實(shí)際期望值的差距秧饮。

function train(weights,point, actualTeam){
    //loss
    const guessResult = guess(weights,point) //1
    const error = actualTeam - guessResult;
    return {
        x: weights.x + (point.x * error),
        y: weights.y + (point.y * error)
    }
    //otimizer
}

在 trainedWeights 方法中映挂,通過(guò)給定點(diǎn)來(lái)訓(xùn)練出權(quán)重,我們通過(guò)返回訓(xùn)練 weights 做為下一次參數(shù)傳入到 train 不斷調(diào)整 weight盗尸。

var trainedWeights =()=> {
    const p1 = {x:721, y:432}
    const p2 = {x:211, y:122}
    const p3 = {x:328, y:833}
    const p4 = {x:900, y:400}

    let trainedWeights;
    
   trainedWeights =  train(randomWeights,p1,team(p1))
   trainedWeights =  train(trainedWeights,p2,team(p2))
   trainedWeights =  train(trainedWeights,p3,team(p3))
   trainedWeights =  train(trainedWeights,p4,team(p4))

   return trainedWeights;
}

得到結(jié)果并不在我們weight(-1柑船,1)取值范圍內(nèi),

trainedWeights = 785.6063038318143,  -801.4601438564098
var html=`
    <svg width="${X_MAX}" height="${Y_MAX}">
        ${randomPoints.map(point=>
            `<circle 
                cx="${point.x}"
                cy="${point.y}"
                r="5"
                fill="${guess(trainedWeights(),point)===-1?'blue':'red'}"
                />`
        )}
        <line x1="0" x2="${X_MAX}" y1="0" y2="${Y_MAX}" stroke="purple"/>
    </svg>
`;

document.getElementById("app").innerHTML = html;

將我們訓(xùn)練好的結(jié)果 trainedWeights() 代替隨機(jī)權(quán)重返回到圖泼各,我們發(fā)現(xiàn)圖中點(diǎn)分布接近我們期望結(jié)果鞍时,藍(lán)色和紅色點(diǎn)大致都分布在線(xiàn)兩側(cè)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末扣蜻,一起剝皮案震驚了整個(gè)濱河市逆巍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌莽使,老刑警劉巖锐极,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異芳肌,居然都是意外死亡灵再,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)亿笤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)翎迁,“玉大人,你說(shuō)我怎么就攤上這事净薛⊥衾疲” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵罕拂,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我全陨,道長(zhǎng)爆班,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任辱姨,我火速辦了婚禮柿菩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘雨涛。我一直安慰自己枢舶,他們只是感情好懦胞,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著凉泄,像睡著了一般躏尉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上后众,一...
    開(kāi)封第一講書(shū)人閱讀 51,754評(píng)論 1 307
  • 那天胀糜,我揣著相機(jī)與錄音,去河邊找鬼蒂誉。 笑死教藻,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的右锨。 我是一名探鬼主播括堤,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼绍移!你這毒婦竟也來(lái)了悄窃?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤登夫,失蹤者是張志新(化名)和其女友劉穎广匙,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體恼策,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鸦致,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了涣楷。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片分唾。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖狮斗,靈堂內(nèi)的尸體忽然破棺而出绽乔,到底是詐尸還是另有隱情,我是刑警寧澤碳褒,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布折砸,位于F島的核電站,受9級(jí)特大地震影響沙峻,放射性物質(zhì)發(fā)生泄漏睦授。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一摔寨、第九天 我趴在偏房一處隱蔽的房頂上張望去枷。 院中可真熱鬧,春花似錦、人聲如沸删顶。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)逗余。三九已至特咆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間猎荠,已是汗流浹背坚弱。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留关摇,地道東北人荒叶。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像输虱,于是被迫代替她去往敵國(guó)和親些楣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容