1.2 张量 (Tensors)


文档摘要

1.2 张量 (Tensors) PyTorch 张量 (Tensors):深度学习的基石 1.2.1 张量的概念:从标量到多维数组 在数学和计算机科学中,张量是一个广义的概念,可以用来描述各种不同维度的数据。在PyTorch中,张量可以被视为多维数组,它是NumPy数组的扩展,并且能够在GPU上运行以加速计算。 为了更好地理解张量,我们可以从简单的概念开始逐步深入: 标量 (Scalar):0维张量。它仅仅是一个单独的数值,例如 , , 。你可以把它想象成一个点。 向量 (Vector):1维张量。它是一组有序排列的数值,例如 。你可以把它想象成一条线段。 矩阵 (Matrix):2维张量。它是一个由行和列组成的数值表格,例如 。你可以把它想象成一个平面。

1.2 张量 (Tensors)

PyTorch 张量 (Tensors):深度学习的基石

1.2.1 张量的概念:从标量到多维数组

在数学和计算机科学中,张量是一个广义的概念,可以用来描述各种不同维度的数据。在PyTorch中,张量可以被视为多维数组,它是NumPy数组的扩展,并且能够在GPU上运行以加速计算。

为了更好地理解张量,我们可以从简单的概念开始逐步深入:

  • 标量 (Scalar):0维张量。它仅仅是一个单独的数值,例如 32.5-1。你可以把它想象成一个点。

  • 向量 (Vector):1维张量。它是一组有序排列的数值,例如 [1, 2, 3]。你可以把它想象成一条线段。

  • 矩阵 (Matrix):2维张量。它是一个由行和列组成的数值表格,例如 [[1, 2], [3, 4]]。你可以把它想象成一个平面。

  • 更高维度的张量:3维及以上的张量。它们可以被视为多维数据立方体,例如表示彩色图像的张量 (高度 x 宽度 x 通道数)。

用 Mermaid 图可以更直观地展示张量的维度关系:

核心思想: 张量是一个统一的数据结构,可以表示从最简单的标量到复杂的多维数据。在深度学习中,无论是输入数据、模型参数还是中间计算结果,都以张量的形式存在。

1.2.2 PyTorch 张量的优势:

PyTorch 张量之所以成为深度学习的首选数据结构,是因为它拥有以下关键优势:

  • GPU 加速:PyTorch 张量可以轻松地在 GPU 上进行计算。GPU 的并行处理能力能够显著加速深度学习模型的训练和推理过程。

  • 自动求导 (Autograd):PyTorch 的 autograd 模块可以自动追踪张量的计算历史,并计算梯度。这对于实现反向传播算法至关重要,而反向传播是深度学习模型训练的核心。

  • 与 NumPy 的无缝集成:PyTorch 张量可以与 NumPy 数组相互转换,方便用户在 PyTorch 和 NumPy 之间进行数据处理和模型开发。

  • 动态图机制:PyTorch 采用动态图机制,允许在运行时定义和修改计算图,提供了更大的灵活性和调试便利性。

  • 丰富的操作和函数库:PyTorch 提供了大量的张量操作和函数,涵盖了线性代数、数学运算、统计分析等各个领域,方便用户进行各种数据处理和模型构建。

1.2.3 张量的创建:多种方式构建你的数据容器

PyTorch 提供了多种方法来创建张量,满足不同的需求。以下是一些常用的创建方式:

1. 从 Python 列表或 NumPy 数组创建:

这是最直接的创建张量的方式。你可以将 Python 列表或 NumPy 数组直接转换为 PyTorch 张量。

import torch import numpy as np # 从 Python 列表创建张量 list_data = [[1, 2], [3, 4]] tensor_from_list = torch.Tensor(list_data) # 注意:torch.Tensor 是 torch.FloatTensor 的别名 print("从列表创建张量:\n", tensor_from_list) # 从 NumPy 数组创建张量 numpy_array = np.array([[5, 6], [7, 8]]) tensor_from_numpy = torch.from_numpy(numpy_array) print("\n从 NumPy 数组创建张量:\n", tensor_from_numpy) # torch.tensor() 更推荐的方式,可以指定数据类型 tensor_from_list_dtype = torch.tensor(list_data, dtype=torch.float64) print("\n从列表创建指定数据类型的张量:\n", tensor_from_list_dtype)

代码详解:

  • torch.Tensor(data)注意torch.Tensortorch.FloatTensor 的别名,默认创建单精度浮点型张量。 它会尝试推断输入数据的数据类型。

  • torch.from_numpy(ndarray): 将 NumPy 数组转换为 PyTorch 张量。 注意torch.from_numpy() 创建的张量与 NumPy 数组共享内存,修改其中一个会影响另一个。

  • torch.tensor(data, dtype=dtype)推荐使用torch.tensor() 是更通用的张量创建函数,可以明确指定数据类型 dtype,例如 torch.float32torch.float64torch.int64 等。

2. 创建特定形状和数值的张量:

PyTorch 提供了许多函数来创建具有特定形状和初始值的张量,例如全零张量、全一张量、随机数张量等。

# 创建全零张量 zeros_tensor = torch.zeros((3, 4)) # 形状为 (3, 4) print("\n全零张量:\n", zeros_tensor) # 创建全一张量 ones_tensor = torch.ones(5) # 形状为 (5,) (一维张量) print("\n全一张量:\n", ones_tensor) # 创建指定数值填充的张量 fill_tensor = torch.full((2, 3), fill_value=7) # 形状为 (2, 3),所有元素填充为 7 print("\n指定数值填充的张量:\n", fill_tensor) # 创建单位矩阵 (对角线为 1,其余为 0) eye_tensor = torch.eye(3) # 形状为 (3, 3) print("\n单位矩阵:\n", eye_tensor) # 创建随机数张量 (均匀分布) rand_tensor = torch.rand((2, 2)) # 0 到 1 之间的均匀分布随机数 print("\n均匀分布随机数张量:\n", rand_tensor) # 创建随机数张量 (标准正态分布) randn_tensor = torch.randn((3, 3)) # 均值为 0,标准差为 1 的正态分布随机数 print("\n正态分布随机数张量:\n", randn_tensor) # 创建指定范围的整数序列张量 arange_tensor = torch.arange(start=0, end=10, step=2) # 从 0 到 10 (不包含 10),步长为 2 print("\n整数序列张量:\n", arange_tensor) # 创建指定数量的均匀间隔数值张量 linspace_tensor = torch.linspace(start=0, end=1, steps=5) # 从 0 到 1,均匀间隔 5 个数 print("\n均匀间隔数值张量:\n", linspace_tensor)

代码详解:

  • torch.zeros(shape): 创建指定形状的全零张量。

  • torch.ones(shape): 创建指定形状的全一张量。

  • torch.full(shape, fill_value): 创建指定形状并用 fill_value 填充的张量。

  • torch.eye(n): 创建 n x n 的单位矩阵。

  • torch.rand(shape): 创建形状为 shape,元素服从 [0, 1) 均匀分布的随机数张量。

  • torch.randn(shape): 创建形状为 shape,元素服从标准正态分布 (均值为 0,标准差为 1) 的随机数张量。

  • torch.arange(start, end, step): 创建从 startend (不包含 end),步长为 step 的整数序列张量。

  • torch.linspace(start, end, steps): 创建从 startend (包含 end),均匀间隔 steps 个数值的张量。

3. 从已有的张量创建新张量:

你可以基于已有的张量来创建新的张量,例如复制形状、数据类型等。

original_tensor = torch.randn((2, 3)) print("\n原始张量:\n", original_tensor) # 创建与 original_tensor 形状相同的全零张量 zeros_like_tensor = torch.zeros_like(original_tensor) print("\n形状相同的全零张量:\n", zeros_like_tensor) # 创建与 original_tensor 形状和数据类型相同的全一张量 ones_like_tensor = torch.ones_like(original_tensor) print("\n形状和数据类型相同的全一张量:\n", ones_like_tensor) # 创建与 original_tensor 形状和数据类型相同的随机数张量 rand_like_tensor = torch.rand_like(original_tensor) print("\n形状和数据类型相同的随机数张量:\n", rand_like_tensor)

代码详解:

  • torch.zeros_like(tensor): 创建与 tensor 形状相同的全零张量。

  • torch.ones_like(tensor): 创建与 tensor 形状和数据类型相同的全一张量。

  • torch.rand_like(tensor): 创建与 tensor 形状和数据类型相同的随机数张量。

1.2.4 张量的属性:了解张量的内在信息

每个 PyTorch 张量都包含一些重要的属性,这些属性描述了张量的形状、数据类型、存储设备等信息。理解这些属性对于有效地使用张量至关重要。

常用的张量属性包括:

  • dtype: 张量的数据类型。例如 torch.float32, torch.int64, torch.bool 等。

  • shape: 张量的形状 (各维度的大小)。返回一个 torch.Size 对象,可以像元组一样访问。

  • device: 张量存储的设备,可以是 CPU (cpu) 或 GPU (cuda:0, cuda:1 等)。

  • ndim: 张量的维度数量 (秩)。

  • numel(): 张量中元素的总数。

  • requires_grad: 布尔值,指示是否需要对张量进行梯度计算 (用于自动求导)。

  • grad: 存储张量的梯度 (只有当 requires_grad=True 时才会被计算和存储)。

tensor_example = torch.randn((2, 3), dtype=torch.float64) print("\n示例张量:\n", tensor_example) print("\n数据类型 (dtype):", tensor_example.dtype) print("形状 (shape):", tensor_example.shape) print("设备 (device):", tensor_example.device) print("维度数量 (ndim):", tensor_example.ndim) print("元素总数 (numel()):", tensor_example.numel()) print("是否需要梯度计算 (requires_grad):", tensor_example.requires_grad) # 默认 False

代码详解:

  • 可以通过访问张量的属性来获取这些信息,例如 tensor.dtypetensor.shape 等。

  • 可以使用 tensor.to(device) 方法将张量移动到不同的设备 (CPU 或 GPU)。

  • 可以使用 tensor.requires_grad_(True) 方法设置张量需要梯度计算。

1.2.5 张量的基本操作:数据处理的强大工具

PyTorch 提供了丰富的张量操作,涵盖了数学运算、线性代数、形状变换、索引切片等各个方面。这些操作是构建深度学习模型的基础。

1. 数学运算:

张量支持基本的数学运算,例如加法、减法、乘法、除法、指数、对数、三角函数等。这些运算可以是元素级的,也可以是矩阵运算。

tensor_a = torch.tensor([[1, 2], [3, 4]], dtype=torch.float32) tensor_b = torch.tensor([[5, 6], [7, 8]], dtype=torch.float32) # 元素级加法 add_tensor = tensor_a + tensor_b # 或 torch.add(tensor_a, tensor_b) print("\n元素级加法:\n", add_tensor) # 元素级乘法 mul_tensor = tensor_a * tensor_b # 或 torch.mul(tensor_a, tensor_b) print("\n元素级乘法:\n", mul_tensor) # 矩阵乘法 matmul_tensor = torch.matmul(tensor_a, tensor_b) # 或 tensor_a @ tensor_b print("\n矩阵乘法:\n", matmul_tensor) # 指数运算 exp_tensor = torch.exp(tensor_a) print("\n指数运算:\n", exp_tensor) # 平方根运算 sqrt_tensor = torch.sqrt(tensor_b) print("\n平方根运算:\n", sqrt_tensor)

代码详解:

  • PyTorch 支持运算符重载,可以直接使用 +, -, *, / 等运算符进行元素级运算。

  • torch.matmul(tensor1, tensor2)@ 运算符执行矩阵乘法。

  • PyTorch 提供了大量的数学函数,例如 torch.exp(), torch.log(), torch.sin(), torch.cos(), torch.sqrt() 等,可以进行各种数学运算。

2. 形状变换:

张量的形状变换是数据处理中常见的操作。PyTorch 提供了多种函数来改变张量的形状,例如 reshape, view, transpose, permute, flatten 等。

reshape_tensor = torch.arange(12) # 创建 0 到 11 的一维张量 print("\n原始张量:\n", reshape_tensor) # 改变形状为 (3, 4) reshaped_tensor = reshape_tensor.reshape((3, 4)) # 或 torch.reshape(reshape_tensor, (3, 4)) print("\nreshape 后的张量:\n", reshaped_tensor) # view() 返回一个view,共享内存,修改会互相影响 view_tensor = reshape_tensor.view((4, 3)) # 或 reshape_tensor.view(4, 3) print("\nview 后的张量:\n", view_tensor) # 转置 (交换维度) transpose_tensor = reshaped_tensor.T # 或 reshaped_tensor.transpose(0, 1) print("\n转置后的张量:\n", transpose_tensor) # 展平张量 (变为一维) flatten_tensor = reshaped_tensor.flatten() # 或 torch.flatten(reshaped_tensor) print("\n展平后的张量:\n", flatten_tensor)

代码详解:

  • tensor.reshape(shape)torch.reshape(tensor, shape): 返回一个具有新形状的张量。如果新形状与原始形状元素总数不一致,则会报错。

  • tensor.view(shape): 返回一个具有新形状的张量,共享内存view() 操作要求张量在内存中是连续的,否则可能需要先调用 tensor.contiguous() 方法使其连续。 reshape() 通常更灵活。

  • tensor.Ttensor.transpose(dim1, dim2): 转置张量,交换指定的维度。 tensor.T 只适用于 2D 张量 (矩阵) 的转置。

  • tensor.flatten()torch.flatten(tensor): 将张量展平为一维。

Mermaid 图示 Reshape 操作:

3. 索引和切片:

张量的索引和切片操作类似于 Python 列表和 NumPy 数组,可以访问和修改张量的特定元素或子区域。

index_tensor = torch.arange(10) print("\n索引张量:\n", index_tensor) # 索引单个元素 first_element = index_tensor[0] print("\n第一个元素:", first_element) # 切片 slice_tensor = index_tensor[2:5] # 获取索引 2, 3, 4 的元素 print("\n切片:\n", slice_tensor) matrix_tensor = torch.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) print("\n矩阵张量:\n", matrix_tensor) # 索引特定行和列的元素 element_2_3 = matrix_tensor[1, 2] # 第二行,第三列的元素 (索引从 0 开始) print("\n第二行第三列的元素:", element_2_3) # 切片获取子矩阵 sub_matrix = matrix_tensor[:2, 1:] # 前两行,第二列及之后的列 print("\n子矩阵:\n", sub_matrix) # 使用布尔索引 bool_index = matrix_tensor > 5 print("\n布尔索引:\n", bool_index) masked_tensor = matrix_tensor[bool_index] # 获取大于 5 的元素 print("\nmasked tensor:\n", masked_tensor)

代码详解:

  • 张量的索引和切片语法与 Python 列表和 NumPy 数组类似,使用方括号 [] 进行索引,可以使用整数索引、切片、布尔索引等。

  • 多维张量可以使用逗号分隔的索引来访问特定位置的元素,例如 tensor[row_index, col_index, ...].

  • 切片操作可以使用 : 来指定范围,例如 tensor[start:end:step].

  • 布尔索引可以使用布尔张量来选择满足条件的元素。

4. 连接和分割:

PyTorch 提供了函数来连接和分割张量,例如 cat, stack, chunk, split 等。

tensor_c = torch.tensor([[9, 10]]) tensor_d = torch.tensor([[11, 12]]) # 沿维度 0 (行) 连接 cat_row_tensor = torch.cat((tensor_c, tensor_d), dim=0) print("\n沿维度 0 连接:\n", cat_row_tensor) # 沿维度 1 (列) 连接 cat_col_tensor = torch.cat((tensor_c, tensor_d), dim=1) print("\n沿维度 1 连接:\n", cat_col_tensor) # stack() 在新的维度上堆叠 stack_tensor = torch.stack((tensor_c, tensor_d), dim=0) print("\nstack 后的张量 (dim=0):\n", stack_tensor) # 维度变为 (2, 1, 2) 如果 tensor_c, tensor_d 是 (1, 2) # chunk() 沿维度分割成指定数量的块 chunk_tensors = torch.chunk(cat_row_tensor, chunks=2, dim=0) # 沿维度 0 分割成 2 块 print("\nchunk 后的张量:\n", chunk_tensors) # split() 沿维度分割成指定大小的块 split_tensors = torch.split(cat_row_tensor, split_size_or_sections=1, dim=0) # 沿维度 0 分割,每块大小为 1 print("\nsplit 后的张量:\n", split_tensors)

代码详解:

  • torch.cat(tensors, dim): 沿指定维度 dim 连接多个张量。

  • torch.stack(tensors, dim): 在新的维度 dim 上堆叠多个张量。 stack() 要求所有输入张量的形状相同。

  • torch.chunk(tensor, chunks, dim): 沿指定维度 dim 将张量分割成 chunks 个块。如果不能整除,最后一块会小一些。

  • torch.split(tensor, split_size_or_sections, dim): 沿指定维度 dim 将张量分割成多个块。 split_size_or_sections 可以是每个块的大小,也可以是块大小的列表。

Mermaid 图示 Concatenate 操作:

5. 归约操作:

归约操作是对张量进行聚合计算,例如求和、求平均值、求最大值、求最小值等。可以沿所有维度或指定维度进行归约。

reduce_tensor = torch.randn((2, 3)) print("\n归约张量:\n", reduce_tensor) # 求和 (所有元素) sum_all = torch.sum(reduce_tensor) print("\n所有元素求和:", sum_all) # 沿维度 0 (行) 求和 sum_dim0 = torch.sum(reduce_tensor, dim=0) print("\n沿维度 0 求和:\n", sum_dim0) # 沿维度 1 (列) 求平均值 mean_dim1 = torch.mean(reduce_tensor, dim=1) print("\n沿维度 1 求平均值:\n", mean_dim1) # 求最大值和最大值索引 max_values, max_indices = torch.max(reduce_tensor, dim=1) print("\n沿维度 1 最大值:", max_values) print("沿维度 1 最大值索引:", max_indices)

代码详解:

  • torch.sum(tensor, dim=None): 对张量求和。如果 dim=None,则对所有元素求和;否则,沿指定维度求和。

  • torch.mean(tensor, dim=None): 对张量求平均值。用法与 torch.sum() 类似。

  • torch.max(tensor, dim=None): 求张量的最大值。如果 dim=None,则返回所有元素的最大值;否则,沿指定维度返回最大值和最大值索引。

  • torch.min(tensor, dim=None): 求张量的最小值。用法与 torch.max() 类似。

  • PyTorch 还提供了 torch.std(), torch.var(), torch.prod() 等其他归约操作。

1.2.6 张量与 NumPy 的互操作性:无缝衔接

PyTorch 张量和 NumPy 数组可以方便地相互转换,这使得在 PyTorch 中使用 NumPy 的工具和库变得非常容易,也方便了从 NumPy 迁移到 PyTorch。

numpy_array_example = np.array([[13, 14], [15, 16]]) print("\nNumPy 数组:\n", numpy_array_example) # NumPy 数组转换为 PyTorch 张量 tensor_from_numpy_example = torch.from_numpy(numpy_array_example) print("\n从 NumPy 数组转换的张量:\n", tensor_from_numpy_example) # PyTorch 张量转换为 NumPy 数组 numpy_from_tensor_example = tensor_from_numpy_example.numpy() print("\n从张量转换的 NumPy 数组:\n", numpy_from_tensor_example) # 修改 NumPy 数组,会影响共享内存的张量 (torch.from_numpy 创建的张量) numpy_array_example[0, 0] = 99 print("\n修改 NumPy 数组后,张量变为:\n", tensor_from_numpy_example)

代码详解:

  • torch.from_numpy(ndarray): 将 NumPy 数组 ndarray 转换为 PyTorch 张量。 重要提示: torch.from_numpy() 创建的张量与 NumPy 数组 共享内存,修改其中一个会影响另一个。

  • tensor.numpy(): 将 PyTorch 张量 tensor 转换为 NumPy 数组。 同样,如果张量在 CPU 上,转换后的 NumPy 数组会与张量 共享内存

1.2.7 张量在深度学习中的应用:数据表示和模型构建

张量是深度学习的基石,它们在深度学习中扮演着至关重要的角色:

  • 数据表示: 深度学习模型处理的各种数据,例如图像、文本、音频等,都需要转换为张量才能被模型所接受。

    • 图像: 可以表示为 3 维张量 (高度 x 宽度 x 通道数)。例如,彩色图像通常是 (高度 x 宽度 x 3) 的张量,其中 3 个通道分别代表红色、绿色和蓝色。

    • 文本: 可以表示为多种形式的张量,例如:

      • 字符级张量: 每个字符用一个索引表示,文本序列转换为索引序列的张量。

      • 词级张量: 每个词用一个索引表示,文本序列转换为索引序列的张量。

      • 词嵌入张量: 每个词用一个向量表示 (词嵌入),文本序列转换为向量序列的张量。

    • 音频: 可以表示为 1 维或 2 维张量,例如时域波形或频谱图。

  • 模型参数: 神经网络模型的权重 (weights) 和偏置 (biases) 都以张量的形式存储。模型训练的过程就是不断调整这些参数张量的数值,以优化模型的性能。

  • 中间计算: 神经网络模型在进行前向传播和反向传播计算时,中间的激活值、梯度等也都以张量的形式存在。

示例:图像数据表示为张量

假设我们有一张 28x28 像素的灰度图像。我们可以将其表示为一个形状为 (1, 28, 28)(28, 28) 的张量 (如果只有一个样本,可以省略批次维度)。 如果是彩色图像 (RGB),则可以表示为 (3, 28, 28)(28, 28, 3) 的张量,取决于通道优先还是通道最后的约定。

# 假设加载了一张 28x28 的灰度图像 (例如使用 PIL 库) # image = ... (假设 image 是一个 PIL Image 对象) # 转换为 NumPy 数组 # numpy_image = np.array(image) # 假设 numpy_image 是 (28, 28) 的 NumPy 数组 # 转换为 PyTorch 张量 image_tensor = torch.from_numpy(numpy_image).float() # 转换为 float 类型,深度学习中常用 # 添加批次维度 (假设批次大小为 1) image_tensor = image_tensor.unsqueeze(0) # 在维度 0 (最前面) 添加一个维度 print("\n图像张量形状:", image_tensor.shape) # 输出: torch.Size([1, 28, 28])

代码详解:

  • tensor.unsqueeze(dim): 在指定维度 dim 插入一个新的维度,维度大小为 1。 常用于添加批次维度。

1.2.8 总结:掌握张量,迈向 PyTorch 精通之路

张量是 PyTorch 的核心数据结构,理解和熟练掌握张量的创建、属性和操作是学习 PyTorch 和深度学习的关键一步。 本篇文章详细介绍了 PyTorch 张量的概念、优势、创建方式、属性、基本操作以及在深度学习中的应用。

通过代码实践和 Mermaid 图示,我们希望你能够对 PyTorch 张量有一个更深入的理解。 掌握张量,你将能够更好地理解和构建复杂的深度学习模型,并为进一步探索 PyTorch 的强大功能打下坚实的基础。 继续深入学习 PyTorch 的其他模块,例如 autograd、神经网络模块 nn、优化器 optim 等,你将逐步成为一名 PyTorch 专家。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U