跳到主要内容

认识

2024年02月19日
柏拉文
越努力,越幸运

一、认识


TensorFlow.js 是一个开源的 JavaScript 实现的机器学习库(深度学习框架),允许在浏览器和 Node.js 环境中运行机器学习模型,执行训练和推理。Tensorflow 的核心是 计算图 Computational Graph。计算图将复杂的数学运算拆解成一系列节点和边: 节点(Node/Op, 代表具体的操作, 比如矩阵乘法、卷积、激活函数等; 边(Edge/Tensor, 代表在操作之间传递的数据,即张量。计算图的优势在于: 可以并行计算, 图中的各个节点间的依赖关系明确,便于调度到不同设备(如 CPUGPUTPU)并行计算; 可以优化执行, TensorFlow 可以对整个计算图进行静态优化(如常量折叠、操作融合),从而减少冗余计算和内存消耗; 可以跨平台部署, 构建好的计算图可以保存为 SavedModel,方便部署到不同平台(服务器、移动端、Web)。Tensorflow 执行模式为: Eager Execution(动态图模式)Graph Execution 静态图模式, TensorFlow 2.x 默认启用了 Eager Execution,这种模式下,操作在调用时立即执行,便于调试和开发。静态图模式下,先构建整个计算图,然后通过 Sessiontf.function 来执行。静态图便于在部署前进行全局优化。而且, 静态图模式可在训练时实现更高效的优化和并行调度,适合大规模数据训练。

Tensorflow 模型训练工作流:

  1. 数据加载与预处理: 1. 数据输入流水线, 利用 tf.data API 构建高效的数据流水线,从磁盘、数据库或其他数据源中加载数据; 2. 预处理操作, 包括数据清洗、归一化、数据增强(如图像旋转、翻转)、分割等,保证数据质量和模型泛化能力; 3. 批处理与预取, 通过 .batch()、.cache()、.prefetch() 等方法,减少 I/O 瓶颈,提升训练效率; 数据加载后转换成 TensorTensorTensorFlow 的基本数据结构(多维数组),它们在后续计算图中流动,成为各个节点的输入和输出。数据加载后以 Tensor 形式存在,贯穿整个计算图,确保数据在各层间顺畅传递。

  2. 初始化权重 WW 和偏置 bb: 权重(Weights 是连接不同神经元的参数, 决定输入数据的重要性, 训练过程中不断优化, 以最小化误差, 表示连接强度, 是训练过程中优化的关键参数; 偏置(Bias, 额外的可训练参数,提高模型的灵活性, 调整激活函数的输入, 提高灵活性。使用随机初始化(如 Xavier/GlorotHe 初始化)、常数初始化等方法,这些参数以 Tensor 形式存储,并被定义为可训练变量。权重偏置 作为计算图中的变量节点, 参与前向传播和反向传播, 并在训练过程中不断更新。

  3. 模型构建: 使用 tf.keras 构建模型,常见方式有 Sequential API 或函数式 API,构建包含全连接层、卷积层、池化层等的神经网络。模型的每一层都会在底层生成对应的计算图节点(Operation),各层之间的运算通过边(Tensor)连接,构成一个完整且优化的计算图。此外,可以利用模块化设计、共享权重等手段提高代码复用性和结构清晰度。

  4. 前向传播(Forward Propagation: 输入的 Tensor 依次通过每一层的运算(如矩阵乘法、加偏置、激活函数等),最终生成输出 Tensor。每个运算步骤都对应计算图中的一个节点,Tensor 从图的一端传递到另一端,完成前向传播计算。激活函数(如 SigmoidReLUSoftmax 等)引入非线性,使神经网络能够学习复杂的特征表示。(模型构建、前向传播、损失计算和反向传播等所有计算步骤均在计算图中进行,充分利用了图优化和自动微分机制)

  5. 计算损失(Loss Function: 将模型输出的预测 Tensor 与真实标签 Tensor 进行比较,计算误差。损失值也是以 Tensor 形式存在,并构成计算图的一部分。损失反映了模型预测结果与真实值之间的偏差,越小表示模型性能越好。损失函数有: 均方误差(MSE(用于回归)、交叉熵损失(Cross-Entropy Loss(用于分类)(模型构建、前向传播、损失计算和反向传播等所有计算步骤均在计算图中进行,充分利用了图优化和自动微分机制)

  6. 反向传播(Backpropagation)与更新参数: 利用 自动微分(Automatic Differentiation) 机制TensorFlow 通过 tf.GradientTape 自动记录前向传播过程,并利用链式法则计算各参数的梯度。每个参数(权重、偏置)的梯度均为 Tensor,表示该参数对损失函数的敏感度。根据计算出的梯度,通过优化器(如 梯度下降(GD)、随机梯度下降(SGD)、Adam)更新参数。在反向传播过程中,计算图会反向遍历,沿着各个边(Tensor)传递梯度,从而更新图中的变量节点。

  7. 重复训练直至模型收敛: 通过多个 Epoch 重复执行前向传播、损失计算和反向传播,每个 Epoch 中模型参数不断更新,损失逐渐降低 (通过不断迭代前向和反向传播,利用梯度下降类算法更新参数,最终使模型收敛到较优解)。动态图与静态图模式: Eager Execution(动态图模式)TensorFlow 2.x 默认开启,操作在调用时即时执行,便于调试和快速迭代; 静态图(tf.function:可以使用 @tf.function 装饰器将关键函数转换为静态计算图,TensorFlow 会对整个图进行全局优化,从而大幅提升运行效率。因此, 在开发过程中利用 Eager Execution 快速验证想法,而在正式训练中切换到静态图模式(tf.function)实现高性能训练。因此, 动态图与静态图模式 让开发既具备调试灵活性,又能达到高性能训练效果。

  8. 分布式训练与多设备支持: TensorFlow 提供了 tf.distribute.Strategy, 支持多设备(如 GPUTPU)和多机分布式训练。常用策略包括: MirroredStrategy, 适用于单机多 GPU 情况,将模型副本复制到每个 GPU,并在每个批次后同步更新; MultiWorkerMirroredStrategy, 适用于多机训练,协调各个机器上的设备进行同步更新。通过数据并行或模型并行, TensorFlow 能充分利用硬件资源,显著加速训练过程。分布式训练与多设备支持 则展示了 TensorFlow 在大规模训练场景下的扩展能力,为工业级应用提供了强有力的支撑。

  9. 模型评估与保存: 在训练结束后,使用测试集或验证集评估模型性能,计算准确率、精度、召回率等指标。将训练好的模型及其计算图和参数(Tensors)保存为 SavedModel 格式,方便后续部署到生产环境或跨平台应用(如 Web、移动端等)。保存的模型可用于在线推理或离线批量处理,利用 TensorFlow Serving 等工具实现高效部署。

Tensorflow 模型预测工作流:

  1. 模型部署与格式转换: 在训练完成后,我们通常会将模型保存为 SavedModel 格式,该格式不仅包含模型结构和参数,还保存了计算图,便于跨平台部署。然后转换为 Web 端支持的格式: 层级模型 Layers Model: 通过 tf.loadLayersModel(pathOrIOHandler, options?) 来加载。模型一般为: model.json 用于存储模型结构, .bin 用于存储模型权重; 计算图模型 Graph Model: TensorFlow.js 加载 TensorFlow(Python)导出的模型。通过 tf.loadGraphModel(modelUrl, options?) 来加载, 模型一般为: model.json 用于存储模型结构, .bin 用于存储模型权重。加载后的 model 通过 model.predict 来进行推理。其中, Graph Model 模型 通常会加快浏览器和 Node.js 的推理速度,这要归功于生成 Graph Model 的图形优化。转换后的 Graph Model 不支持进一步训练。

  2. 模型加载: 使用 TensorFlow.js 提供的加载方法,如 tf.loadGraphModel(加载 Graph 模型)或 tf.loadLayersModel(加载 Keras 模型)

  3. 数据采集与预处理: 数据可以来自用户上传、摄像头、文件输入或 API 接口。为了与训练时一致,需要对输入数据做归一化、尺寸调整、色彩空间转换等预处理操作。

  4. 模型推理: 将预处理后的 Tensor 作为输入传递给模型的 predict 方法,获取输出 Tensor

  5. 后处理与结果展示: 根据模型输出进行进一步处理,如阈值判断、分类标签映射或回归结果的反归一化; 将推理结果更新到页面上或通过其他方式反馈给用户。

  6. 性能优化与资源管理: 1. 模型加载, 基于 Service Worker 缓存 TensorFlow 模型文件和相关的 JavaScript 库,并控制缓存的版本, 可以保证在首次加载时从网络加载资源,并在后续加载时优先使用缓存资源,减少网络请求,提升性能和离线可用性,同时通过版本号控制确保更新后的资源被正确加载。2. 模型量化, 指将模型的权重和激活函数从浮点数(通常是32位浮点数)转换为较低精度的数值(如8位整数),以减少模型的大小和提高推理速度。通过 TensorFlow.js 支持的 模型量化(Quantization 技术,将模型大小压缩 50%-70%,降低推理计算负载。3. 模型分片, 将 model.json 中的 group1-shard1.bin 二进制权重文件分为多个小片,利用浏览器的并发请求能力,更快的加载模型, 这种方式减少单个文件的大小,提高并行加载能力和缓存效率。4. 采用 WebGL 后端加速, TensorFlow.js 利用 WebGL 后端,在浏览器中实现 GPU 加速,提升推理速度。5. 内存管理, 在推理过程中注意释放不再使用的 Tensor,避免内存泄露

二、语法


2.1 NPM

import * as tf from '@tensorflow/tfjs';

// Define a model for linear regression.
const model = tf.sequential();
model.add(tf.layers.dense({units: 1, inputShape: [1]}));

// Prepare the model for training: Specify the loss and the optimizer.
model.compile({loss: 'meanSquaredError', optimizer: 'sgd'});

// Generate some synthetic data for training.
const xs = tf.tensor2d([1, 2, 3, 4], [4, 1]);
const ys = tf.tensor2d([1, 3, 5, 7], [4, 1]);

// Train the model using the data.
model.fit(xs, ys).then(() => {
// Use the model to do inference on a data point the model hasn't seen before:
model.predict(tf.tensor2d([5], [1, 1])).print();
});

2.2 Script Tag

<html>
<head>
<!-- Load TensorFlow.js -->
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs/dist/tf.min.js"> </script>


<!-- Place your code in the script tag below. You can also use an external .js file -->
<script>
// Notice there is no 'import' statement. 'tf' is available on the index-page
// because of the script tag above.

// Define a model for linear regression.
const model = tf.sequential();
model.add(tf.layers.dense({units: 1, inputShape: [1]}));

// Prepare the model for training: Specify the loss and the optimizer.
model.compile({loss: 'meanSquaredError', optimizer: 'sgd'});

// Generate some synthetic data for training.
const xs = tf.tensor2d([1, 2, 3, 4], [4, 1]);
const ys = tf.tensor2d([1, 3, 5, 7], [4, 1]);

// Train the model using the data.
model.fit(xs, ys).then(() => {
// Use the model to do inference on a data point the model hasn't seen before:
// Open the browser devtools to see the output
model.predict(tf.tensor2d([5], [1, 1])).print();
});
</script>
</head>

<body>
</body>
</html>