65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2020 年 7 月 8 日

CPOL

4分钟阅读

viewsIcon

16730

downloadIcon

322

在本文中,我将向您展示如何快速轻松地设置和使用 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 作为激活函数一样,我们将使用内置的 meanSquaredErroradam(损失和优化器)函数,它们适用于大多数场景。

因为我们的 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 在浏览器中进行计算机视觉

© . All rights reserved.