本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.
[译]来自 user-gold-cdn.xitu.io/2019/11/29/…
这篇文章解释了如何使用TensorFlow.js在浏览器中运行机器学习。 它涵盖了用于模型训练,传递学习和预测功能的TensorFlow.js API。这里呈现了一个APP demo, 它有助于预测业务报告执行的等待时间。
我已经实现了一个包含TensorFlow.js API使用情况的APP。 首先,我将向您介绍其功能,然后深入探讨实现细节。 该APP实现了业务报告执行时间预测用例(在JavaScript中),在我之前的文章 《使用Keras和TensorFlow进行报告时间执行预测》 中对此进行了解释。 对于模型训练,我使用了50个epochs (数据以10个为批处理),学习率设置为0.001。 神经网络基于两个处理层和一个输出层。 模型训练过程在浏览器中运行:
regressiontfjs-node.herokuapp.com/
训练模型可以预测业务报告执行的预期等待时间。实现是基于这本书中的解释和资料完成的- 《使用JavaScript进行深度学习》 和多元回归示例- 《Boston Housing》 。
功能性
首次打开APP时,需要对模型进行训练。训练模型后,它将被保存到本地 indexeddb
。重新打开浏览器后,该模型将从 indexeddb
中保持可用,您可以选择要重用它或训练新模型(以前保存的模型将被替换)。 训练过程完成后,它将打印一组显示模型情况的参数:
Baseline loss(基线损失):这是根据训练数据计算出的平均平方误差。平方根值:237秒。这意味着,如果我们始终假设预测的平均值,则错误范围将为237秒。
Average time(平均时间):为训练数据计算的平均时间
Final train-set loss(最终训练设定损失):训练期间计算出的损失
Final validation-set loss(最终验证集损失):通过验证训练期间计算出的损失
Test-set loss(测试集损失):针对训练数据针对训练数据计算出的损失
Prediction off by (sec)(预测偏差(秒)):测试集损失的平方根值。这表明模型出错能力。此模型训练得很好,只有4.5秒的错误,比基线损失要好
对以下数据运行预测功能-结果514秒:
将时隙更改为下午,预计时间将增加到573秒。 这意味着根据训练数据对模型进行了正确的训练,报告在下午的运行时间更长:
增加参数数量。 使用更多参数,可处理的数据更少-报告运行速度应更快。 模型通过预测来确认这一点,该预测将返回更快的时间:
让我们更改报告ID和参数数量。 观察预计时间:
现在,我们将进行转移学习,重新训练具有新目标的模型(在此示例中,出于简单原因,我仅使用一行数据,但我建议重新训练需要多行数据的模型)。 call训练方法-它应该运行的非常快。 测试集丢失可能比基于原始训练的情况更糟(此练习很好),因为我们使用的是之前的测试集数据,该数据与新目标没有直接关系。 新目标——400秒,报告ID = 1(假设特定用户时间与训练中的时间不同,并且该用户可以更新模型)。 重新训练(当我们在现有模型之上训练时——转移学习)的结果:
重新训练模型后,使用之前相同的参数运行后的预测——您将看到预测结果将被调整与我们用于重新训练的目标一致:
现在,将Report ID更改为最初使用的ID,并将报告参数的数量以及时隙更改为原始值。 您将看到,现在我们预测了相对更短的时间,这是由于最近的模型重新训练而将更短的时间设置为目标:
尝试更改参数并查看结果。
实操
APP结构非常简单。 所有逻辑均在 appController.js
中实现。 UI
在 index.html
中实现。 Web应用程序是通过 Oracle JavaScript
库— Oracle JET
实现的。 要在本地运行该应用程序,请执行以下两个步骤:
使用NPM安装 Oracle JET
: npm install -g @ oracle / ojet-cli
进入应用程序并运行: ojet restore
运行应用程序: ojet服务
appController.js
中定义了一个侦听器。 加载应用程序时,将调用此侦听器,并负责加载数据,将其转换为张量并计算基线。 数据通过帮助程序模块 data.js
加载。 我正在使用 Papaparse
库来解析 CSV
。 原始数据集基于四列:
我发现模型不能直接从这些数据中很好地训练。 报表ID和时段字段需要数据转换。 这些列是分类别的,并且需要通过创建尽可能多的新列进行转换,并保证存在唯一的分类值:
var features = results['data'].map(report => ({ report_params: parseFloat(report.report_params), report_1: parseFloat(report.report_id) === 1 ? 1 : 0, report_2: parseFloat(report.report_id) === 2 ? 1 : 0, report_3: parseFloat(report.report_id) === 3 ? 1 : 0, report_4: parseFloat(report.report_id) === 4 ? 1 : 0, report_5: parseFloat(report.report_id) === 5 ? 1 : 0, day_morning: parseFloat(report.day_part) === 1 ? 1 : 0, day_midday: parseFloat(report.day_part) === 2 ? 1 : 0, day_afternoon: parseFloat(report.day_part) === 3 ? 1 : 0, }));
这种数据转换有助于进行更精确的训练。 我正在使用1200行数据进行训练,并使用300行数据进行测试。 在将数据拆分为训练数据集和测试数据集之前,请确保先对其进行混洗。 我正在使用 helper
方法,该方法取自 Boston Housing
APP。 使用 TensorFlow.js
函数 tensor2d
将数据数组转换为张量:
tensors.rawTrainFeatures = tf.tensor2d(dataHelper.trainFeatures); tensors.trainTarget = tf.tensor2d(dataHelper.trainTarget); tensors.rawTestFeatures = tf.tensor2d(dataHelper.testFeatures); tensors.testTarget = tf.tensor2d(dataHelper.testTarget);
TensorFlow.js
模型由两个处理层和一个输出层构成,以返回预测值:
const model = tf.sequential(); model.add(tf.layers.dense({ inputShape: [dataHelper.trainFeatures[0].length], units: 25, activation: 'sigmoid', kernelInitializer: 'leCunNormal' })); model.add(tf.layers.dense({ units: 25, activation: 'sigmoid', kernelInitializer: 'leCunNormal' })); model.add(tf.layers.dense({ units: 1 }));
构建模型后,对其进行编译并运行拟合函数以训练模型。 我建议使用验证拆分选项,这样在训练过程中它将验证训练的质量
model.compile({ optimizer: tf.train.sgd(LEARNING_RATE), loss: 'meanSquaredError' }); await model.fit(tensors.trainFeatures, tensors.trainTarget, { batchSize: BATCH_SIZE, epochs: NUM_EPOCHS, shuffle: true, validationSplit: 0.2, callbacks: { onEpochEnd: async (epoch, logs) => {
函数拟合提供 onEpochEnd
回调,我们可以在其中记录训练进度并将数据推送到UI。 训练完成后,通过针对测试数据运行模型来评估模型。 从返回的数字中取平方根,这将基于当前模型训练在几秒钟内被容忍的错误(如果结果不能容忍,请尝试通过更改神经网络层的结构来重新训练模型,并尝试调整训练参数):
result = model.evaluate(tensors.testFeatures, tensors.testTarget, { batchSize: BATCH_SIZE }); testLoss = result.dataSync()[0];
最后保存模型。 有多个保存模型的选项,您甚至可以将其推送到服务器。 在此示例中,我将模型保存在浏览器本地的 indexeddb
中:
await model.save('indexeddb://report-exec-time-model');
训练模型后,我们可以运行预测功能。 我正在从 indexeddb
中的保存状态加载模型,构造输入张量并执行 TensorFlow.js
预测:
model = await tf.loadLayersModel('indexeddb://report-exec-time-model'); input = [{ report_id: parseFloat(self.reportIdP()), report_params: self.reportParamsP(), day_part: parseFloat(self.reportExecSlotP()) }]; convertInputToTensor(input); res = model.predict(tensors.inputFeatures); score = res.dataSync()[0];
最后一步——转移学习,使用附加数据对现有模型进行再训练(在这种情况下,数据形状相同,我们为新目标进行训练)。 为了使重新训练更有效率,我们必须冻结原始模型中的部分图层。 这样,先前训练的模型权重将不会受到影响,并且模型训练将运行得更快。 通常,您应该使用多个新元素进行培训,在这种情况下,出于简单原因,我会使用一个新条目进行培训。 可以通过将可训练属性设置为false来冻结模型层:
model = await tf.loadLayersModel('indexeddb://report-exec-time-model'); model.layers[0].trainable = false; model.compile({ loss: 'meanSquaredError', optimizer: tf.train.sgd(LEARNING_RATE) }); model.summary(); input = [{ report_id: parseFloat(self.reportId()), report_params: self.reportParams(), day_part: parseFloat(self.reportExecSlot()), exec_time: self.reportExecTime() }]; convertInputToTensor(input, 'Y');
在现有模型之上使用新数据运行函数拟合:
await model.fit(tensors.inputFeatures, tensors.inputTarget, { batchSize: BATCH_SIZE, epochs: NUM_EPOCHS, shuffle: true, callbacks: { onEpochEnd: async (epoch, logs) => {
Be First to Comment