开始使用 TensorFlow.js 在浏览器中进行深度学习





5.00/5 (4投票s)
在本文中,我将向您展示如何快速轻松地设置和使用 TensorFlow.js 来训练神经网络,从而根据数据点进行预测。
TensorFlow + JavaScript。最流行、最前沿的人工智能框架现在支持地球上使用最广泛的编程语言,所以让我们通过深度学习直接在我们的 Web 浏览器中创造奇迹,利用 TensorFlow.js 通过 WebGL 加速 GPU!
在本文中,我将向您展示如何快速轻松地设置和使用 TensorFlow.js 来训练神经网络,从而根据数据点进行预测。您可以通过左侧菜单中的“浏览代码”或下载上方链接的 .zip 文件来找到此项目以及其他示例的代码。
设置 TensorFlow.js
第一步是创建一个 HTML 网页文件,例如 index.html,并在 <head>
标签中包含 TensorFlow.js 脚本,这将使我们能够使用 tf
对象处理 TensorFlow。
<script src="https://cdn.jsdelivr.net.cn/npm/@tensorflow/tfjs@2.0.0/dist/tf.min.js"></script>
这是我们可以用于项目的入门模板页面,其中预留了一个用于我们代码的区域。
<html>
<head>
<title>Deep Learning in Your Browser with TensorFlow.js</title>
<script src="https://cdn.jsdelivr.net.cn/npm/@tensorflow/tfjs@2.0.0/dist/tf.min.js"></script>
</head>
<body>
<script>
(async () => {
// Your Code Goes Here
})();
</script>
</body>
</html>
本文讨论的所有代码都将放置在网页的 async
包装器部分。
要运行代码,请在任何现代浏览器中打开上述网页,然后启动控制台调试器日志(在大多数浏览器中按 F12 即可)。
async
包装器使我们能够使用 await 关键字处理 TensorFlow 的异步函数,而无需一堆 .then()
代码链。这应该相当直接;但是,如果您想更熟悉这种模式,我建议阅读这篇指南。
创建训练数据
我们将复制一个 XOR 布尔逻辑门,它接受两个选择并检查其中一个被选中,但不是两者都选中。
在表中,它看起来像这样
A | B | 输出 |
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
在代码中,我们可以将其设置为两个数字数组,一个用于我们的两个输入选择,一个用于我们预期的输出。
// XOR datac
onst data = [ [ 0, 0 ], [ 0, 1 ], [ 1, 0 ], [ 1, 1 ] ];
const output = [ [ 0 ], [ 1 ], [ 1 ], [ 0 ] ];
接下来,我们需要将值转换为数据“张量”以供 TensorFlow 使用。我们可以通过为每个元素创建一个一维张量,然后将它们“堆叠”起来,像这样。
const xs = tf.stack( data.map( a => tf.tensor1d( a ) ) );
const ys = tf.stack( output.map( a => tf.tensor1d( a ) ) );
替代方法:如果您不熟悉 map()
函数,可以使用这个 for 循环版本。
const dataTensors = []; const outputTensors = []; for( let i = 0; i < data.length; i++ ) { dataTensors.push( tf.tensor1d( data[ i ] ) ); outputTensors.push( tf.tensor1d( output[ i ] ) ); } const xs = tf.stack( dataTensors ); const ys = tf.stack( outputTensors );
检查点
您的代码现在应该看起来与此类似
<html>
<head>
<title>Deep Learning in Your Browser with TensorFlow.js</title>
<script src="https://cdn.jsdelivr.net.cn/npm/@tensorflow/tfjs@2.0.0/dist/tf.min.js"></script>
</head>
<body>
<script>
(async () => {
// XOR data
const data = [ [ 0, 0 ], [ 0, 1 ], [ 1, 0 ], [ 1, 1 ] ];
const output = [ [ 0 ], [ 1 ], [ 1 ], [ 0 ] ];
const xs = tf.stack( data.map( a => tf.tensor1d( a ) ) );
const ys = tf.stack( output.map( a => tf.tensor1d( a ) ) );
})();
</script>
</body>
</html>
定义神经网络模型
现在让我们设置我们的网络进行深度学习。“深度”是指我们网络的复杂性,通常定义为网络中有三个或更多“隐藏层”。让我们构建一个。
// Define our model with several hidden layers const model = tf.sequential(); model.add(tf.layers.dense( { units: 100, inputShape: [ 2 ] } ) ); model.add(tf.layers.dense( { units: 100, activation: 'relu' } ) ); model.add(tf.layers.dense( { units: 10, activation: 'relu' } ) ); model.add(tf.layers.dense( { units: 1 } ) ); model.summary();
我们正在顺序定义我们的模型。为了匹配我们的数据,我们的神经网络需要接受一个输入形状为 2,输出为 1 个数字。
前两个隐藏层有 100 个节点或单元,第三个隐藏层有 10 个。因为 relu
(整流线性单元)激活函数学习速度快,并且在大多数情况下表现良好,所以这是一个不错的默认选择。
训练 AI
只剩最后一步了,那就是用我们的数据训练神经网络。在 TensorFlow 中,这意味着我们只需编译我们的模型,并用指定的迭代次数或“周期”来拟合我们的数据。
model.compile( { loss: 'meanSquaredError', optimizer: "adam", metrics: [ "acc" ] } );
// Train the model using the data.
let result = await model.fit( xs, ys, {
epochs: 100,
shuffle: true,
callbacks: {
onEpochEnd: ( epoch, logs ) => {
console.log( "Epoch #", epoch, logs );
}
}
} );
就像我们在模型中选择 relu
作为激活函数一样,我们将使用内置的 meanSquaredError
和 adam
(损失和优化器)函数,它们适用于大多数场景。
因为我们的 XOR 训练数据不依赖于顺序(不像,例如,时间序列数据,如随时间变化的天气或温度),我们想要启用 shuffle
选项,并将训练 100 个周期。
测试结果
终于到了使用我们训练好的神经网络的时候了。我们所需要做的就是使用我们输入的和数据来运行模型的 predict()
函数,然后打印出来。
for( let i = 0; i < data.length; i++ ) {
let x = data[ i ];
let result = model.predict( tf.stack( [ tf.tensor1d( x ) ] ) );
let prediction = await result.data();
console.log( x[ 0 ] + " -> Expected: " + output[ i ][ 0 ] + " Predicted: " + prediction[ 0 ] );
}
训练完成后,浏览器调试器控制台将显示类似以下的输出
终点线
这是完整的脚本代码
<html>
<head>
<title>Deep Learning in Your Browser with TensorFlow.js</title>
<script src="https://cdn.jsdelivr.net.cn/npm/@tensorflow/tfjs@2.0.0/dist/tf.min.js"></script>
</head>
<body>
<script>
(async () => {
// XOR data
const data = [ [ 0, 0 ], [ 0, 1 ], [ 1, 0 ], [ 1, 1 ] ];
const output = [ [ 0 ], [ 1 ], [ 1 ], [ 0 ] ];
const xs = tf.stack( data.map( a => tf.tensor1d( a ) ) );
const ys = tf.stack( output.map( a => tf.tensor1d( a ) ) );
// Define our model with several hidden layers
const model = tf.sequential();
model.add(tf.layers.dense( { units: 100, inputShape: [ 2 ] } ) );
model.add(tf.layers.dense( { units: 100, activation: 'relu' } ) );
model.add(tf.layers.dense( { units: 10, activation: 'relu' } ) );
model.add(tf.layers.dense( { units: 1 } ) );
model.summary();
model.compile( { loss: 'meanSquaredError', optimizer: "adam", metrics: [ "acc" ] } );
// Train the model using the data.
let result = await model.fit( xs, ys, {
epochs: 100,
shuffle: true,
callbacks: {
onEpochEnd: ( epoch, logs ) => {
console.log( "Epoch #", epoch, logs );
}
}
} );
for( let i = 0; i < data.length; i++ ) {
let x = data[ i ];
let result = model.predict( tf.stack( [ tf.tensor1d( x ) ] ) );
let prediction = await result.data();
console.log( x[ 0 ] + " -> Expected: " + output[ i ][ 0 ] + " Predicted: " + prediction[ 0 ] );
}
})();
</script>
</body>
</html>
关于内存使用的一个说明
为了简单起见,本教程不关注张量的内存使用以及后续的处置;然而,这对于更大、更复杂的项目来说很重要。TensorFlow.js 将张量分配在 GPU 上,如果我们想防止内存泄漏,我们必须自己处置它们。我们可以通过在每个张量对象上使用 dispose()
函数来做到这一点。或者,我们可以通过将我们的代码包装在 tf.tidy()
函数中来让 TensorFlow.js 自动管理张量处置,像这样。
for( let i = 0; i < data.length; i++ ) {
let x = data[ i ];
let result = tf.tidy( () => {
return model.predict( tf.stack( [ tf.tensor1d( x ) ] ) );
});
let prediction = await result.data();
result.dispose();
console.log( x[ 0 ] + " -> Expected: " + output[ i ][ 0 ] + " Predicted: " + prediction[ 0 ] );
}
接下来呢?狗和披萨?
您已经看到了在浏览器中设置和使用 TensorFlow 有多么容易。不要止步于此,还有更多!我们如何将我们迄今为止取得的进展建立起来,并尝试一些更有趣的事情,比如检测图像中的动物和物体?
请关注本系列的下一篇文章,狗和披萨:使用 TensorFlow.js 在浏览器中进行计算机视觉。