前言
又到了被催进度的时候,然而自己的进度却是一片空白,之前应付了一周的开题现在发现有很多地方根本就不合理,导师自然不能帮到你什么,所以一切到头来还是要自己去折腾。
内容
说实话要是都和Three.js相关的内容其实还好做,偏偏里面还涉及启发式算法和神经网络拟合的问题,这就很麻爪了,而且还不知道到底要不要上神经网络。
目前的问题主要有三大块,首先就是博弈支付矩阵的建立,其次是启发式算法的求解,最后是动画的完善。
不过导师想看结果,还是要从动画下手,他给出的建议是做几个场景,有一说一场景是比较好实现的,比如拦截,对战,追踪。
然鹅,实在不想动脑子去想这些动画怎么实现,于是先从简单的做起,学学tensorflow.js吧。
介绍
去年的这时候我开始接触Python的机器学习教程,甚至写了好多学习笔记:
不过那时候没有想走JS的路,虽然接触到了tensorflow,但是掌握的属实一般,tensorflow.js是去年年中接触到的概念,彼时正好处在转型前端的时候,瞬间对这个熟悉的概念产生了兴趣,不过好景不长,庞大的前端体系还是让我对学习这个东西分身乏术。
天道好轮回,想靠JS水毕设,终究还是逃不开他。
一句话介绍tfjs,就是方便前端上手机器学习,这里那线性回归和逻辑回归简单两大基础Demo介绍下tfjs。
线性回归
import { tensor, sequential, layers, losses, train } from "@tensorflow/tfjs";
import { render, show } from "@tensorflow/tfjs-vis";
window.onload = async () => {
const height = [154, 160, 175, 181, 188];
const weight = [46, 44, 56, 72, 70];
render.scatterplot(
{ name: "h-w-data" },
{ values: height.map((x, i) => ({ x, y: weight[i] })) },
{ xAxisDomain: [140, 200], yAxisDomain: [40, 80] }
);
function press(val) {
return tensor(val)
.sub(Math.min(...val))
.div(Math.max(...val) - Math.min(...val));
}
const inputs = press(height),
labels = press(weight);
const model = sequential();
model.add(layers.dense({ units: 1, inputShape: [1] }));
model.compile({ loss: losses.meanSquaredError, optimizer: train.sgd(0.2) });
await model.fit(inputs, labels, {
batchSize: 5,
epochs: 200,
callbacks: show.fitCallbacks({ name: "train-process" }, ["loss"]),
});
const outputs = model.predict(tensor([169]).sub(154).div(34));
outputs.mul(28).add(44).print();
};
上面是一段线性回归的demo,先看看引入的库,一个是tfjs,不用多说,另一个是tfjs配套的可视化库。
首先准备了所谓的训练集,由height和wight组成,接着画个散点图,这里指定x座标为高,y为重量。然后做了个归一化操作,原因这里就不细讲了。
接着我们使用连续模型sequential,添加一层全连接层。使用均方误差和SGD优化,batch设为5,epoch为200,然后画出loss训练的过程,最后预测169的label。
逻辑回归
import { tensor, sequential, layers, losses, train } from "@tensorflow/tfjs";
import { render, show } from "@tensorflow/tfjs-vis";
import { getData } from "./data";
window.onload = async () => {
const data = getData(400);
render.scatterplot(
{ name: "logistic" },
{
values: [
data.filter((p) => p.label === 1),
data.filter((p) => p.label === 0),
],
}
);
const model = sequential();
model.add(
layers.dense({
units: 1,
inputShape: [2],
activation: "sigmoid",
})
);
model.compile({
loss: losses.logLoss,
optimizer: train.adam(0.1),
});
const inputs = tensor(data.map((p) => [p.x, p.y]));
const labels = tensor(data.map((p) => p.label));
await model.fit(inputs, labels, {
batchSize: 40,
epochs: 20,
callbacks: show.fitCallbacks(
{
name: "train-process",
},
["loss"]
),
});
window.fn = (form) => {
const pred = model.predict(tensor([[+form.x.value, +form.y.value]]));
pred.print();
return false;
};
};
首先抓四百数据,结构如下:
{
x:number,
y:number,
label:number
}
接着也打出来:
其他训练步骤类似,只不过选择的优化器和损失函数变化了。
最后写了段html实现传值:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script src="./app.js"></script>
<form action="" onsubmit="return fn(this)">
x: <input type="text" name="x" /> y: <input type="text" name="y" />
<button type="submit">预测</button>
</form>
</body>
</html>