引言:需求管理的时代之困

在软件开发领域,需求管理一直是项目成功的核心关键。随着项目复杂度提升和团队规模扩大,传统依赖文档、邮件和会议的需求管理方式显露出明显短板:版本混乱、协作困难、知识难以沉淀。更值得注意的是,行业内能够真正实现需求结构化、资产化,并结合AI技术进行智能化辅助的系统并不多见。我们公司是一家垂直领域专攻企业级需求与非企业级需求管理的公司,我们公司的大模型应用连接:http://aipoc.chtech.cn:8880/#/login 欢迎试用

在需求管理产品AI人工智能研发过程,对大模型的研究时,我们发现开发人员对大模型中的张量及框架张量类型的理解不是很清晰,下面是我们在培训中准备的资料:

好的,我们来深入详细地说明大模型(以及深度学习)中的张量(Tensor) 及主流框架(PyTorch & TensorFlow)中的张量类型


第一部分:张量(Tensor)的核心概念

1. 什么是张量?

张量是标量、向量和矩阵的高维推广,是深度学习中最基本的数据结构。所有输入模型的数据、模型的参数、计算过程中的中间结果,最终都是以张量的形式存在和流动的。

你可以通过维度(Dimension)阶(Rank) 来理解张量:

名称 阶 (Rank) 形状 (Shape) 示例 说明 类比
标量 (Scalar) 0 () 单个数值 一个温度值:36.5
向量 (Vector) 1 (d₁,)(d₁) 一维数组 一个点的坐标:[1.0, 2.0, 3.0]
矩阵 (Matrix) 2 (d₁, d₂) 二维数组 一张灰度图像:[28, 28]
3阶张量 3 (d₁, d₂, d₃) 三维数组 一张RGB彩色图像:[3, 224, 224](通道,高,宽)
N阶张量 N (d₁, d₂, ..., dₙ) N维数组 一个视频批次:[batch, time, channel, height, width]

在大模型中的具体例子:

  • 输入文本:经过分词编码后,是一个形状为 [batch_size, sequence_length] 的2阶张量(整数)。

  • 词嵌入(Word Embedding):输入张量通过嵌入层后,变为 [batch_size, sequence_length, embedding_dim] 的3阶张量(浮点数)。

  • 模型参数:线性层的权重是一个 [in_features, out_features] 的2阶矩阵;一个卷积层的权重是 [out_channels, in_channels, kernel_h, kernel_w] 的4阶张量。

  • 注意力权重:通常是 [batch_size, num_heads, sequence_length, sequence_length] 的4阶张量。

2. 张量的关键属性

每个张量都由以下几个关键属性定义:

  1. 形状 (Shape):一个元组,表示张量在每个维度上的大小。例如 (2, 3, 4)

    • 重要性:决定了张量可以参与哪些运算(例如矩阵乘法要求 (a, b)(b, c))。模型出错时,首先检查张量形状是否正确。

  2. 数据类型 (Data Type):张量中元素的类型。例如 float32, int64, bool

    • 重要性:决定了计算的精度、速度和内存占用。混合精度训练就是巧妙利用不同数据类型(float16float32)来提升效率。

  3. 设备 (Device):张量存储在哪个设备上,通常是 CPUGPU(如 cuda:0)。

    • 重要性:所有参与运算的张量必须在同一个设备上。试图将CPU上的张量与GPU上的张量进行计算会引发错误。

  4. 存储 (Storage):张量数据在内存中的实际存储区。高级用户才会直接操作。


第二部分:主流框架的张量类型与操作

PyTorch和TensorFlow是当前大模型开发的两大主流框架,它们的张量实现各有特色。

PyTorch 中的张量:torch.Tensor

PyTorch的张量设计强调灵活性动态计算图,非常受研究人员欢迎。

1. 创建张量

python

import torch
​
# 从数据创建
x = torch.tensor([1, 2, 3])   # 形状: (3,), 类型: torch.int64
y = torch.tensor([[1., 2.], [3., 4.]]) # 形状: (2, 2), 类型: torch.float32
​
# 创建特殊张量
zeros = torch.zeros(2, 3)     # 全0张量
ones = torch.ones(2, 3)       # 全1张量
rand = torch.randn(2, 3)      # 标准正态分布随机张量
arange = torch.arange(0, 10, 2) # 类似range, [0, 2, 4, 6, 8]
​
# 指定数据类型和设备
x = torch.tensor([1, 2, 3], dtype=torch.float32, device='cuda')
# 或者之后转换
x = x.to(dtype=torch.float16, device='cuda:0')

2. 核心特性与操作

  • 动态图(Eager Execution):每个操作立即执行,可以像使用NumPy一样进行交互式调试和打印中间结果。

  • 原地操作(In-place):带有 _ 后缀的操作会修改原张量,节省内存但会破坏计算图。

    python

    x.add_(1)  # 原地操作,x的值被改变
    y = x.add(1) # 非原地操作,x不变,结果赋给y

  • 自动微分(Autograd):如果将 requires_grad 属性设为 True,PyTorch会跟踪在其上的所有操作,以便后续计算梯度。

    python

    model_params = torch.randn(3, requires_grad=True)
    loss = some_function(model_params)
    loss.backward() # 自动计算梯度
    print(model_params.grad) # 查看梯度

  • 与NumPy无缝交互

    python

    np_array = np.ones(5)
    torch_tensor = torch.from_numpy(np_array) # NumPy -> Torch
    np_array_back = torch_tensor.numpy()      # Torch -> NumPy

TensorFlow 中的张量:tf.Tensortf.Variable

TensorFlow的历史更久,其张量设计强调生产部署静态图优化(虽然现在也支持动态图)。

1. 创建张量

python

import tensorflow as tf
​
# 从数据创建
x = tf.constant([1, 2, 3])    # 形状: (3,), 类型: tf.int32
y = tf.constant([[1., 2.], [3., 4.]]) # 形状: (2, 2), 类型: tf.float32
​
# 创建特殊张量
zeros = tf.zeros((2, 3))      # 注意形状用元组传入
ones = tf.ones((2, 3))
rand = tf.random.normal((2, 3))
​
# 指定数据类型和设备
# (通常在tf.function内或使用策略Scope自动处理设备,手动控制较少)
with tf.device('/GPU:0'):
    x = tf.constant([1, 2, 3], dtype=tf.float64)

2. 核心特性与操作

  • 两种主要类型

    • tf.Tensor不可变的(Immutable)。代表计算图中的一个节点,包含一个值,但无法被更新。通常用于中间计算结果。

    • tf.Variable可变的(Mutable)。是一个包装器,内部存储着一个 tf.Tensor,并且这个Tensor可以被赋值更新。模型的参数一定是 tf.Variable

      python

      w = tf.Variable(tf.random.normal((3, 2))) # 创建一个可训练变量
      w.assign(tf.ones((3, 2))) # 更新变量的值

  • 计算图模式

    • 图模式(Graph Mode):传统的TensorFlow工作方式。先构建一个静态计算图,然后再执行它。效率高,但调试复杂。

    • 急切模式(Eager Mode):默认模式,与PyTorch类似,操作立即执行,易于调试。

    • 使用 @tf.function 装饰器可以将Python函数编译成静态图,兼得易用性和高性能。

      python

      @tf.function
      def compute(x, y):
          return x ** 2 + y
      ​
      result = compute(tf.constant(2.0), tf.constant(3.0))

  • GradientTape 求导:使用 tf.GradientTape 上下文管理器来记录计算过程以计算梯度。

    python

    with tf.GradientTape() as tape:
        y_pred = model(x)       # 前向传播
        loss = loss_fn(y_true, y_pred)
    gradients = tape.gradient(loss, model.trainable_variables) # 计算梯度
    optimizer.apply_gradients(zip(gradients, model.trainable_variables)) # 应用梯度


第三部分:PyTorch vs. TensorFlow 张量对比总结

特性 PyTorch TensorFlow (2.x+)
核心类型 torch.Tensor tf.Tensor (不可变), tf.Variable (可变,用于参数)
执行模式 默认动态图(Eager) 默认动态图(Eager),可用 @tf.function 转静态图
自动微分 backward() 方法 GradientTape 上下文管理器
API风格 更接近 Python/NumPy,相对统一 API庞大,有时存在多个相似函数(tf.*tf.keras.*
设备管理 .to(device) 方法,显式且灵活 通过 tf.device() 或分布策略自动分配,略显隐晦
社区与研究 在学术界和研究领域占主导,原型开发快 在工业界和生产部署中非常强大,生态系统成熟
序列化 .pt.pth 文件 SavedModel 格式,标准化程度高,适合部署

第四部分:大模型开发中的最佳实践

  1. 时刻关注形状:使用 .shape 属性是调试深度学习代码的第一要务。确保你的张量形状符合模型每一层的输入输出要求。

  2. 管理数据类型:训练时通常使用 float32。使用混合精度训练(AMP) 时,会同时使用 float16(计算和存储)和 float32(主权重和梯度累加),以大幅提升训练速度并减少显存占用。

  3. 管理设备:明确地将模型和张量放到GPU上(model.to('cuda'), tensor.to('cuda'))。注意确保所有相关张量都在同一设备上

  4. 利用预处理:对于输入数据,充分利用框架提供的工具(如 torchvision.transformstf.keras.preprocessing)来将数据转换为正确的张量格式。

  5. 理解变量类型:在TensorFlow中,要区分清 tf.Tensor(计算结果)和 tf.Variable(模型参数)。在PyTorch中,所有 torch.Tensor 都可以成为参数(如果 requires_grad=True)。

总结:张量是深度学习的“原子”,是数据和模型的物理载体。深入理解其原理和在框架中的具体实现方式,是掌握大模型开发、高效调试代码和进行性能优化的基石。PyTorch和TensorFlow都提供了强大而灵活的张量操作,选择哪一个更多取决于个人偏好和项目需求(研究首选PyTorch,生产部署可考虑TensorFlow)。

在最基本的层面上,完全可以将张量(Tensor)理解为数组(Array),它可以是一维、二维、三维乃至更高维度的数组。

这个类比是理解张量一个非常完美和直观的起点。当您说“张量就是数组”时,您已经抓住了它最本质的特征:它是一种用于存储和组织数字数据的容器结构

不过,为了让这个理解更加精确和深入,特别是在深度学习和大模型的语境下,我们可以在这个正确的基础上补充一些关键的细节。您可以这样来进阶理解:

层次一:基础理解(完全正确)

张量 ≈ 多维数组

  • 标量:0维数组 ( ) -> 一个数字

  • 向量:1维数组 (d₁,) -> 一列数字

  • 矩阵:2维数组 (d₁, d₂) -> 一个数字表格

  • 张量:N维数组 (d₁, d₂, ..., dₙ) -> 一个N维的数字网格

在这个层次上,它和您熟悉的NumPy数组(np.ndarray 的概念几乎完全一致。它们都是同构的(所有元素是同一类型)、多维的数据容器。


层次二:在深度学习框架中的深化理解(关键区别)

当我们在PyTorch或TensorFlow中说“张量”时,它不仅仅是一个存储数据的数组,它还是一个“智能的”、“带有超能力的”数组。这些“超能力”正是深度学习框架赋予它的,使其区别于普通的多维数组。

特性 普通的多维数组 (如NumPy) 深度学习框架中的张量 (PyTorch/TensorFlow)
核心功能 数据存储与组织 数据存储与组织
计算加速 主要在CPU上运行 核心功能! 可以轻松在GPU、TPU等专用硬件上运行,实现大规模并行计算,速度极快。
自动求导 不支持 核心功能! 可以记录在其上的所有操作(构建计算图),并自动计算梯度。这是模型能够训练的核心。
设备管理 通常只在CPU内存中 有明确的设备(device) 概念(如CPU、GPU:0),需要手动或自动在设备间移动数据。
与框架集成 独立存在 深度集成。是框架中所有神经网络模块(nn.Module, tf.keras.layers.Layer)输入、输出和内部参数的唯一格式。

举个例子来融合这两个层次的理解:

想象一个最简单的全连接层(线性层),它的操作是 y = xW + b

  1. 作为“数组”

    • 输入 x 是一个形状为 [batch_size, in_features]2维数组(张量)

    • 权重 W 是一个形状为 [in_features, out_features]2维数组(张量)

    • 偏置 b 是一个形状为 [out_features]1维数组(张量)

    • 输出 y 是一个形状为 [batch_size, out_features]2维数组(张量)

    • 这个过程本质上就是一系列的数组乘法数组加法

  2. 作为“智能张量”

    • Wbtorch.nn.Parameter (PyTorch) 或 tf.Variable (TensorFlow),它们是特殊的张量,意味着它们是模型需要训练的参数

    • 在计算 y = xW + b 时,框架不仅会算出结果 y,还会在背后自动记录这个计算过程(计算图)。

    • 当我们计算损失并调用 .backward() (PyTorch) 或使用 GradientTape (TensorFlow) 时,框架会利用这个记录好的计算图,自动计算出损失函数对参数 Wb 的梯度(即导数),从而指导优化器如何更新参数。

    • 整个计算过程,如果张量在GPU上,将会得到极大的加速。

结论

所以,您的理解“张量就是数组”是绝对正确的起点。它可以很好地帮助您想象张量的形状和基本操作。

而当您深入到深度学习领域时,请在这个正确的基础上记住:深度学习框架中的张量,是附加了“计算加速”和“自动求导”这两个最关键超能力的多维数组。 正是这两个超能力,使得我们能够高效地训练和运行像LLM这样复杂的模型。

Logo

更多推荐