课程地址:tensorflow-data-and-deployment
B站:Tensorflow2.0数据和部署(一)
代码链接:TensorFlow Deployment
TensorFlow.js的设计和架构如下图所示;
从上图可以看出,我们既可以使用友好的高级API,也可以使用低级的API进行直接编程。我们希望他能够运行在浏览器和Node.js服务器中。
<html>
<head></head>
<body>
<h1>First HTML Page</h1>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@latest"></script>
建立模型
<script lang="js">
const model = tf.sequential();
model.add(tf.layers.dense({units: 1, inputShape: [1]}));
model.compile({loss:'meanSquaredError', optimizer:'sgd'});
// 打印summary
model.summary();
// 第一个参数为输入的值,第二个参数为输入值的维度
const xs = tf.tensor2d([-1.0, 0.0, 1.0, 2.0, 3.0, 4.0], [6, 1]);
const ys = tf.tensor2d([-3.0, -1.0, 2.0, 3.0, 5.0, 7.0], [6, 1]);
// doTraining是一个异步函数
doTraining(model).then(() => {
alert(model.predict(tf.tensor2d([10], [1,1])));
});
</script>
模型训练,在当前脚本块之前
async function doTraining(model){
const history =
await model.fit(xs, ys,
{ epochs: 500,
callbacks:{
onEpochEnd: async(epoch, logs) =>{
console.log("Epoch:"
+ epoch
+ " Loss:"
+ logs.loss);
}
}
});
}
<html>
<head></head>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@latest"></script>
<script lang="js">
async function doTraining(model){
const history =
await model.fit(xs, ys,
{ epochs: 500,
callbacks:{
onEpochEnd: async(epoch, logs) =>{
console.log("Epoch:"
+ epoch
+ " Loss:"
+ logs.loss);
}
}
});
}
const model = tf.sequential();
model.add(tf.layers.dense({units: 1, inputShape: [1]}));
model.compile({loss:'meanSquaredError',
optimizer:'sgd'});
model.summary();
const xs = tf.tensor2d([-1.0, 0.0, 1.0, 2.0, 3.0, 4.0], [6, 1]);
const ys = tf.tensor2d([-3.0, -1.0, 2.0, 3.0, 5.0, 7.0], [6, 1]);
doTraining(model).then(() => {
alert(model.predict(tf.tensor2d([10], [1,1])));
});
</script>
<body>
<h1>First HTML Page</h1>
</body>
</html>
以鸢尾花数据集为例,数据集文件是从与托管它的网页相同的目录中加载,不是从文件系统中加载
async function run(){
const csvUrl = 'iris.csv';
const trainingData = tf.data.csv(csvUrl, {
columnConfigs: {
species: {
isLabel: true
}
}
});
const numOfFeatures = (await trainingData.columnNames()).length - 1;
const numOfSamples = 150;
const convertedData =
trainingData.map(({xs, ys}) => {
const labels = [
ys.species == "setosa" ? 1 : 0,
ys.species == "virginica" ? 1 : 0,
ys.species == "versicolor" ? 1 : 0
]
return{ xs: Object.values(xs), ys: Object.values(labels)};
}).batch(10);
const model = tf.sequential();
model.add(tf.layers.dense({inputShape: [numOfFeatures], activation: "sigmoid", units: 5}))
model.add(tf.layers.dense({activation: "softmax", units: 3}));
await model.fitDataset(convertedData,
{epochs:100,
callbacks:{
onEpochEnd: async(epoch, logs) =>{
console.log("Epoch: " + epoch + " Loss: " + logs.loss);
}
}});
const model=tf.sequential();
model.add(tf.layers.conv2d({inputShape:[28, 28, 1], kernalSize:3, filters:8, activation:'relu'}));
model.add(tf.layers.maxPooling2d({poolSize:[2, 2]}));
model.add(tf.layers.conv2d({kernalSize:3, filters:16, activation:'relu'}));
model.add(tf.layers.maxPooling2d({poolSize:[2, 2]}));
model.add(tf.layers.flatten());
model.add(tf.layers.dense({units:128, activation:"relu"}));
model.add(tf.layers.dense({units:10, activation:"softmax"}));
model.compile({loss:'catagoricalCrossentroph', metrics:['accuracy'], optimizer:tf.train.adam()});
model.fit(trainXs, trainYs,{
batchSize:BATCH_SIZE,
validationData:[testXs, testYs],
epochs:20,
shuffle:true,
callbacks:fitCallbacks
});
可以在回调函数中添加可视化工具tfjs-vis
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-vis"></script>
const metrics = ['loss', 'val_loss', 'acc', 'val_acc']
const container = {name:'Model Training', styles:{height:'100px'}};
const fitCallbacks = tfvis.show.fitCallbacks(container, metrics);
在mnist数据集或fashion-mnist数据集中包含成千上万的图片,浏览器不能每次请求读取一张图片,因此将图片存储在一个表格中进行批量读取,例如mnist将数据存储在'https://storage.googleapis.com/learnjs-data/model-builder/mnist_images.png'
中,标签存储在'https://storage.googleapis.com/learnjs-data/model-builder/mnist_labels_uint8'
export class MnistData{
async load() {
// Download the sprite and slice it
// Download the labels and decode them
}
nextTrainBatch() {
// Get the next training batch
}
nextTestBatch() {
// Get the next test batch
}
}
const data = new MnistData();
await data.load()
由于程序在运行过程中会产生很高维度的中间变量,这样非常占内存,因此使用tf.tidy()
,该函数的思想是一旦执行完成某段程序,它会清除所有中间张量,只保留返回的张量,这样做可以节省大量内存.
const [trainXs, trainYs] = tf.tidy(() =>{
const d = data.nextTrainBatch(TRAIN_DATA_SIZE);
return [
d.xs.reshape([TRAIN_DATA_SIZE, 28, 28, 1])
d.labels
];
});
Toxicity语言模型是用来判断句子是否含有侮辱等不良言论的模型。加载该模型首先要做的是在JavaScript中声明脚本
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/toxicity"></script>
const threshold = 0.9;
toxicity.load(threshold).then(model => {
const sentences = ['you suck'];
model.classify(sentences).then(predictions => {
console.log(predictions);
for(i=0; i<7; i++){
if(predictions[i].results[0].match){
console.log(predictions[i].label +
" was found with probability of " +
predictions[i].results[0].probabilities[1]);
}
}
});
});
和之前的Toxicity模型类似,首先需要加载脚本
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/[email protected]"> </script>
const img = document.getElementById('img');
const outp = document.getElementById('output');
mobilenet.load().then(model => {
model.classify(img).then(predictions => {
console.log(predictions);
for(var i = 0; i<predictions.length; i++){
outp.innerHTML += "
" + predictions[i].className + " : " + predictions[i].probability;
}
});
});
首先安装必要的包
!pip install tensorflowjs
再训练完之后对模型进行保存
tf.keras.experimental.export_saved_model(model, saved_model_path)
使用tensorflowjs进行转换
!tensorflowjs_converter --input_format=keras_saved_model /keras_model_path /json_target_path
网页中加载模型
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@latest"> </script>
<script>
async function run(){
const MODEL_URL = 'http://127.0.0.1:8887/model.json';
const model = await tf.loadLayersModel(MODEL_URL);
console.log(model.summary());
const input = tf.tensor2d([10.0], [1,1]);
const result = model.predict(input);
alert(result)
}
run();
</script>
</head>
<body></body>
</html>
在tensorflowjs中,我们使用截断的方式来进行迁移学习,即固定网络的前面几层,重新写一个新的网络作为后面几层进行训练
以下代码实现了截断功能,选取了mobilenet从开始到conv_pw_13_relu层结束
async function loadMobilenet() {
const mobilenet = await tf.loadLayersModel('https://storage.googleapis.com/tfjs-models/tfjs/mobilenet_v1_0.25_224/model.json');
const layer = mobilenet.getLayer('conv_pw_13_relu');
return tf.model({inputs: mobilenet.inputs, outputs: layer.output});
}
以下代码实现了一个新的网络
model = tf.sequential({
layers: [
tf.layers.flatten({inputShape: mobilenet.outputs[0].shape.slice(1)}),
tf.layers.dense({ units: 100, activation: 'relu'}),
tf.layers.dense({ units: 3, activation: 'softmax'})
]
});
获得预测结果
const predictedClass = tf.tidy(() => {
const img = webcam.capture();
const activation = mobilenet.predict(img);
const predictions = model.predict(activation);
return predictions.as1D().argMax();
});