JavaScript 也能做机器学习(1)

每当谈起机器学习、深度学习,大家自然就会想到 python c++ GPU tensorflow python 这些词。似乎距离前端人员比较遥远的事 ,今天我们就用 js 来实现一个简单分类的算法。

一切从简单开始,从一个分类问题开始吧。任务就是一个二分类的问题,通过既有的数据训练得到一个模型,然后用模型来对一个数据预测其属于哪一个类别,来了解是如何使用 javascript 进行机器学习。

const R = require('ramda');
randomPoints = R.range(0,5);
复制代码

这里引入了 ramda 库帮助生成随机数,实现起来很简单。

[ 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 之间的随机数,这里使用 map 方法来实现返回在某个区间的随机数、

[ -0.9515869798311445,
  -0.884506721474116,
  0.7849131001955243,
  -0.8271371680230728,
  0.6015755023017424,
复制代码

上面随机数,然后我们用这些随机数生成随机点,x 和 y 都是 -1 到 1 之间随机数

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

复制代码

我们将这些随机点通过 svg 以绘制在宽和高同为 400 的区域来显示,让你更直观地观察机器学习的过程。

// 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;
复制代码

并且将这些随机点显示出来,这些点散落在宽高都是 400 的个方形区域,然后绘制一条线,这条线就是我们随后拟合分割线,这条线将这些样本点分成了两个类别,位于线上部分是一个类别,位于线下面又是一个类别。

图

其实问题很简单,只要某一个点 y 坐标大于 x 坐标,或者 y 坐标小于 x 坐标属于另一个类别,如果某一个点 x 坐标大于 y 输入 1 否则 -1 也就是用 1 和 -1 表示两个类别

var team = point => point.x > point.y ? 1 : -1;
复制代码

接下来通过颜色来表示两个不同类别,类别为 -1 的点用蓝色来表示,而 1 则用红色点来表示。

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 函数通过简单逻辑(规则)对随机点进行分类,通过点的 x 和 y 值大小进行判断可以进行判断。

开始写模型

好接下来我们就开始构建 AI 来模拟机器学习过程。初始一个随机参数模型参数比较有意思是两个取值从 -1 到 1 的随机数,这里这样理解我们通过 x 和 y 之间比值来划分 ax + by

ax+by=0 a x + b y = 0

var randomWeights = ({
    x:rand(-1,1),
    y:rand(-1,1)
})
复制代码

这里 guess 函数会输出一个类别,也就是我们函数模型,这里有连个参数,或者叫做权重,权重负责根据 x 和 y 给出一个该点所属类别 1 * x + -1*y > 0 这个关系。

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 是权重,point 是输入,sum 为输入和权重乘积的和,这个神经元有两个输入 x 和 y(两个特征)然后输出为 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 是随机数,我们每次刷新会得到不同结果。

创建我们训练函数,训练接收 weights 和 point 输入,以及期望值 actualTeam 通过对比判断结果和期望值对比来反馈到训练,进行优化调整weight 获取正确计算模型

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()}`)
复制代码

上面代码可以简单测试我们计算结果和实际期望值的差距。

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 方法中,通过给定点来训练出权重,我们通过返回训练 weights 做为下一次参数传入到 train 不断调整 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;
}
复制代码

得到结果并不在我们weight(-1,1)取值范围内,

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;
复制代码

将我们训练好的结果 trainedWeights() 代替随机权重返回到图,我们发现图中点分布接近我们期望结果,蓝色和红色点大致都分布在线两侧。

图

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享