前言
又到了被催進度的時候,然而自己的進度卻是一片空白,之前應付了一週的開題現在發現有很多地方根本就不合理,導師自然不能幫到你什麼,所以一切到頭來還是要自己去折騰。
內容
說實話要是都和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>