张量
张量是一个多维数组,它是标量、向量和矩阵概念的推广。在深度学习中,张量被广泛用于表示数据和模型参数。
具体来说,张量的“张”可以理解为“维度”,张量的阶或维数称为秩。例如,零阶张量是一个标量,一阶张量是一个向量,二阶张量是一个矩阵,三阶及以上的张量则可以看作是高维数组。
在不同的上下文中,张量的意义可能会有所不同:
- 数据表示:在深度学习中,张量通常用于表示数据。例如,一幅RGB图像可以表示为一个三维张量,其中两个空间维度(高度和宽度)和一个颜色维度(红、绿和蓝)。
- 模型参数:神经网络的权重和偏置通常也以张量形式存储。
- 数学运算:在多线性代数中,张量用于描述涉及多个向量或矩阵的操作。
- 物理和工程:在物理学和工程学中,张量用于描述具有多个方向性质的现象,如应力和应变。
- 计算机科学:在计算机图形学中,张量用于表示变换矩阵和其他与几何相关的概念。
🤩🤩🤩接下来我们看看张量的基础操作🤩🤩🤩
张量类型转换
在深度学习框架中,如TensorFlow或PyTorch,张量类型转换是一个常见的操作。这通常涉及到将一个张量的数据类型转换为另一个数据类型,以便满足特定的计算需求或优化内存使用。
TensorFlow
在TensorFlow中,你可以使用tf.cast
函数来转换张量的类型。tf.cast
函数接受两个参数:要转换的张量和目标数据类型。
import tensorflow as tf tensor = tf.constant([1.0, 2.0, 3.0], dtype=tf.float32) int32_tensor = tf.cast(tensor, dtype=tf.int32) print("Original Tensor:", tensor) print("Casted Tensor:", int32_tensor)
PyTorch
在PyTorch中,张量类型转换可以通过调用to
方法并指定目标类型来完成。
import torch tensor = torch.tensor([1.0, 2.0, 3.0], dtype=torch.float32) int32_tensor = tensor.to(dtype=torch.int32) print("Original Tensor:", tensor) print("Casted Tensor:", int32_tensor)
我们创建了一个浮点类型的张量,并将其转换为整数类型。请注意,类型转换可能会导致数据丢失,例如,将浮点数转换为整数会截断小数部分。因此,在进行类型转换时,需要确保这种转换是你想要的。
张量转换为 numpy 数组
Tensor.numpy 函数可以将张量转换为 ndarray 数组,但是共享内存,可以使用 copy 函数避免共享。
import torch import numpy as np tensor = torch.tensor([[1, 2], [3, 4]]) numpy_array = tensor.numpy() print("Numpy array:", numpy_array)
numpy 转换为张量
- 使用 from_numpy 可以将 ndarray 数组转换为 Tensor,默认共享内存,使用 copy 函数避免共享。
- 使用 torch.tensor 可以将 ndarray 数组转换为 Tensor,默认不共享内存。
import tensorflow as tf import numpy as np numpy_array = np.array([[1, 2], [3, 4]]) tensor = tf.convert_to_tensor(numpy_array) print("Tensor:", tensor)
import torch import numpy as np numpy_array = np.array([[1, 2], [3, 4]]) tensor = torch.from_numpy(numpy_array) print("Tensor:", tensor)
标量张量和数字的转换
对于只有一个元素的张量,使用 item 方法将该值从张量中提取出来。
def test03(): data = torch.tensor([30,]) print(data.item()) data = torch.tensor(30) print(data.item()) if __name__ == '__main__': test03()
张量拼接操作
张量的拼接操作在神经网络搭建过程中是非常常用的方法,残差网络、注意力机制中都使用到了张量拼接。为了有效地进行张量操作,了解和熟悉这些基本操作是非常必要的,它们在实际的深度学习模型构建和数据处理中扮演着重要角色。
在进行张量拼接时,需要特别注意以下几点:
- 确保所有张量在非拼接轴上的尺寸是相同的。
- 当使用 torch.stack() 时,被堆叠的张量必须具有相同的形状。
- 拼接操作不会修改原始张量,而是返回一个新的张量。
torch.cat 函数可以将两个张量根据指定的维度拼接起来
import torch def func(): data1 = torch.randint(0, 10, [3, 5, 4]) data2 = torch.randint(0, 10, [3, 5, 4]) print(data1) print(data2) print('-' * 50) new_data = torch.cat([data1, data2], dim=0) print(new_data.shape) print('-' * 50) new_data = torch.cat([data1, data2], dim=1) print(new_data.shape) new_data = torch.cat([data1, data2], dim=2) print(new_data) if __name__ == '__main__': func()
torch.stack 函数可以将两个张量根据指定的维度叠加起来
torch.stack()
函数用于在新的维度上堆叠张量。它接受一个张量列表作为输入,并返回一个新的张量,其中每个输入张量都沿着新添加的维度进行堆叠。
import torch tensor1 = torch.tensor([1, 2, 3]) tensor2 = torch.tensor([4, 5, 6]) stacked_tensor = torch.stack((tensor1, tensor2)) print(stacked_tensor)
tensor([[1, 2, 3],
[4, 5, 6]])
张量索引操作
我们在操作张量时,经常需要去进行获取或者修改操作,掌握张量的花式索引操作是必须的一项能力。在深度学习框架中,张量索引操作通常用于访问和修改张量中的数据。以下是一些基本的张量索引操作:
- 基础索引:可以通过指定张量的维度和对应的索引值来获取张量中的特定元素。例如,对于一个二维张量 tensor,可以使用 tensor[i, j] 来获取第 i 行第 j 列的元素。
- 切片索引:可以用来选择张量的子张量。通过指定起始和终止索引以及步长,可以获取张量中的一部分。例如,t1[2:8] 将会返回从索引2到7的张量元素,形成一个新张量。如果指定步长为2,如 t1[2:8:2],则会隔一个元素取一个,返回索引为2、4、6的元素形成的新张量。
- 高级索引:包括布尔索引和掩码索引等。布尔索引允许根据一个布尔张量来选择数据,而掩码索引则使用一个具有相同形状的张量作为掩码来选择数据。
- 多维索引:对于多维张量,可以通过指定多个维度的索引来访问数据,例如 tensor[i, j, k] 将访问三维张量中第 i 层、第 j 行、第 k 列的元素。
- 负数步长:在Python的传统列表中,步长可以为负数,表示倒序排列。但在张量中,步长必须大于0,否则会报错。这意味着不能使用负数步长来逆序索引张量元素。
- 内存共享:与 numpy.ndarray 类似,张量的索引操作通常会返回与原张量共享内存的结果。这意味着如果你修改了返回的张量,原始张量也会受到影响。
在进行张量索引操作时,需要确保索引不超出张量的形状范围,否则会引发错误。此外,由于张量通常用于存储和处理大量数据,因此高效的索引操作对于性能至关重要。
import torch data = torch.randint(0, 10, [4, 5]) print(data) print('-' * 50)
tensor([[0, 7, 6, 5, 9],
[6, 8, 3, 1, 0],
[6, 3, 8, 7, 3],
[4, 9, 5, 3, 1]])
print(data[0]) print(data[:, 0])
列表索引
def test(): print(data[[0, 1], [1, 2]]) print(data[[[0], [1]], [1, 2]]) if __name__ == '__main__': test() [8, 3]])
- 范围索引:类似于Python的列表切片,张量也支持范围索引。这意味着你可以使用start:end:step的形式来获取张量的子集。例如,t[1:3]将返回张量t的第2到第3个元素。需要注意的是,步长step必须是正数,因为张量不支持负数步长。
- 布尔索引:布尔索引是使用一个与目标张量形状相同的布尔张量来选择元素。在布尔张量中,True值对应的位置元素会被选中并组成一个新的张量。例如,如果有一个张量t和一个相同形状的布尔张量b,那么t[b]将返回t中所有对应b中为True的元素。
import torch t = torch.tensor([1, 2, 3, 4, 5]) print(t[1:3]) # 输出 [2, 3] b = torch.tensor([True, False, True, False, True]) print(t[b]) # 输出 [1, 3, 5]
在上述代码中,我们首先创建了一个张量t
,然后使用范围索引获取了第2到第3个元素。接着,我们创建了一个与t
形状相同的布尔张量b
,并使用布尔索引选择了所有对应b
中为True
的元素。最后,我们将结果打印出来。
📦️这些就是张量的基础操作,下一节我们看看张量的其他性质~