张量是一个多维数组,它是标量、向量和矩阵概念的推广。在深度学习中,张量被广泛用于表示数据和模型参数。
具体来说,张量的“张”可以理解为“维度”,张量的阶或维数称为秩。例如,零阶张量是一个标量,一阶张量是一个向量,二阶张量是一个矩阵,三阶及以上的张量则可以看作是高维数组。
在不同的上下文中,张量的意义可能会有所不同:
接下来我们看看张量的基础操作
在深度学习框架中,如TensorFlow或PyTorch,张量类型转换是一个常见的操作。这通常涉及到将一个张量的数据类型转换为另一个数据类型,以便满足特定的计算需求或优化内存使用。
TensorFlow
在TensorFlow中,你可以使用tf.cast
函数来转换张量的类型。tf.cast
函数接受两个参数:要转换的张量和目标数据类型。
import tensorflow as tf
# 创建一个张量
tensor = tf.constant([1.0, 2.0, 3.0], dtype=tf.float32)
# 将张量的类型从 float32 转换为 int32
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)
# 将张量的类型从 float32 转换为 int32
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数组
numpy_array = tensor.numpy()
print("Numpy array:", numpy_array)
numpy 转换为张量
import tensorflow as tf
import numpy as np
# 创建一个numpy数组
numpy_array = np.array([[1, 2], [3, 4]])
# 将numpy数组转换为张量
tensor = tf.convert_to_tensor(numpy_array)
print("Tensor:", tensor)
import torch
import numpy as np
# 创建一个numpy数组
numpy_array = np.array([[1, 2], [3, 4]])
# 将numpy数组转换为张量
tensor = torch.from_numpy(numpy_array)
print("Tensor:", tensor)
对于只有一个元素的张量,使用 item 方法将该值从张量中提取出来。
def test03():
# 当张量只包含一个元素时, 可以通过 item 函数提取出该值
data = torch.tensor([30,])
print(data.item())
data = torch.tensor(30)
print(data.item())
if __name__ == '__main__':
test03()
# 30
# 30
张量的拼接操作在神经网络搭建过程中是非常常用的方法,残差网络、注意力机制中都使用到了张量拼接。为了有效地进行张量操作,了解和熟悉这些基本操作是非常必要的,它们在实际的深度学习模型构建和数据处理中扮演着重要角色。
在进行张量拼接时,需要特别注意以下几点:
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)
# 按0维度拼接
new_data = torch.cat([data1, data2], dim=0)
print(new_data.shape)
print('-' * 50)
# 按1维度拼接
new_data = torch.cat([data1, data2], dim=1)
print(new_data.shape)
# 按2维度拼接
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])
# 使用 torch.stack() 函数将两个张量堆叠在一起
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
列的元素。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])
# tensor([0, 7, 6, 5, 9])
# tensor([0, 6, 6, 4])
列表索引
def test():
print(data[[0, 1], [1, 2]])
print(data[[[0], [1]], [1, 2]])
if __name__ == '__main__':
test()
# tensor([7, 3])
# tensor([[7, 6],
[8, 3]])
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
的元素。最后,我们将结果打印出来。
️这些就是张量的基础操作,下一节我们看看张量的其他性质~