张量计算和操作

发布时间:2024年01月24日

一、数据操作

1、基础

import torch

x = torch.arange(12)
# x:tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])

x.shape
# torch.Size([12])

x.numel()
# 12

x = x.reshape(3, 4)
# tensor([[ 0, 1, 2, 3],
#         [ 4, 5, 6, 7],
#         [ 8, 9, 10, 11]])

torch.zeros((2, 3, 4))
# tensor([[[0., 0., 0., 0.],
#          [0., 0., 0., 0.],
#          [0., 0., 0., 0.]],
#         [[0., 0., 0., 0.],
#          [0., 0., 0., 0.],
#          [0., 0., 0., 0.]]])

torch.ones((2, 3, 4))
# tensor([[[1., 1., 1., 1.],
#          [1., 1., 1., 1.],
#          [1., 1., 1., 1.]],
#         [[1., 1., 1., 1.],
#          [1., 1., 1., 1.],
#          [1., 1., 1., 1.]]])

# 从某个特定的概率分布中随机采样来得到张量中每个元素的值。
# 随机初始化参数的值。
torch.randn(3, 4)
# tensor([[-0.0135, 0.0665, 0.0912, 0.3212],
#         [ 1.4653, 0.1843, -1.6995, -0.3036],
#         [ 1.7646, 1.0450, 0.2457, -0.7732]])

torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
# tensor([[2, 1, 4, 3],
#         [1, 2, 3, 4],
#         [4, 3, 2, 1]])

2、运算符

在相同形状的两个张量上执行按元素操作

import torch

+-*/**运算
x = torch.tensor([1.0, 2, 4, 8])
y = torch.tensor([2, 2, 2, 2])
x + y, x - y, x * y, x / y, x ** y # **运算符是求幂运算
#(tensor([ 3., 4., 6., 10.]),
# tensor([-1., 0., 2., 6.]),
# tensor([ 2., 4., 8., 16.]),
# tensor([0.5000, 1.0000, 2.0000, 4.0000]),
# tensor([ 1., 4., 16., 64.]))

计算e^x
torch.exp(x)
#tensor([2.7183e+00, 7.3891e+00, 5.4598e+01, 2.9810e+03])

张量连结,端对端地叠形成一个更大的张量
X = torch.arange(12, dtype=torch.float32).reshape((3,4))
Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])

torch.cat((X, Y), dim=0)
# tensor([[ 0., 1., 2., 3.],
#         [ 4., 5., 6., 7.],
#         [ 8., 9., 10., 11.],
#         [ 2., 1., 4., 3.],
#         [ 1., 2., 3., 4.],
#         [ 4., 3., 2., 1.]])

torch.cat((X, Y), dim=1)
# tensor([[ 0., 1., 2., 3., 2., 1., 4., 3.],
#         [ 4., 5., 6., 7., 1., 2., 3., 4.],
#         [ 8., 9., 10., 11., 4., 3., 2., 1.]])

通过逻辑运算符构建二元张量
X == Y
# tensor([[False, True, False, True],
#         [False, False, False, False],
#         [False, False, False, False]])

对张量中的所有元素进行求和,会产生一个单元素张量。
X.sum()
# tensor(66.)

3、广播机制

在不同形状的两个张量上执行操作

1. 通过适当复制元素来扩展一个或两个数组,以便在转换之后,两个张量具有相同的形状;

2. 对生成的数组执行按元素操作。

import torch

a = torch.arange(3)
#tensor([0, 1, 2])
a = torch.arange(3).reshape((3, 1))
#tensor([[0],
#        [1],
#        [2]])

b = torch.arange(2)
#tensor([0, 1])
b = torch.arange(2).reshape((1, 2))
#tensor([[0, 1]])

a和b分别是3×1和1×2矩阵,如果让它们相加,它们的形状不匹配,可以将两个矩阵广播为一个更大的3×2矩阵。
矩阵a将复制列,矩阵b将复制行(这个过程程序自动执行),然后再按元素相加。
a
# tensor([[0, 0],
#         [1, 1],
#         [2, 2]])
b
# tensor([[0, 1],
#         [0, 1],
#         [0, 1]])
a+b
# tensor([[0, 1],
#         [1, 2],
#         [2, 3]])

4、索引和切片

张量中的元素可以通过索引访问

第一个元素 的索引是0,最后一个元素索引是‐1;

可以指定范围以包含第一个元素和最后一个之前的元素。

import torch

X = torch.arange(12, dtype=torch.float32).reshape((3,4))
print(X)
# tensor([[ 0.,  1.,  2.,  3.],
#         [ 4.,  5.,  6.,  7.],
#         [ 8.,  9., 10., 11.]])

print(X[-1])
# tensor([ 8.,  9., 10., 11.])

print(X[1:3])
# tensor([[ 4.,  5.,  6.,  7.],
#         [ 8.,  9., 10., 11.]])

X[1, 2] = 9
print(X)
# tensor([[ 0.,  1.,  2.,  3.],
#         [ 4.,  5.,  9.,  7.],
#         [ 8.,  9., 10., 11.]])

X[0:2, :] = 12
print(X)
# tensor([[12., 12., 12., 12.],
#         [12., 12., 12., 12.],
#         [ 8.,  9., 10., 11.]])

5、节省内存

运行一些操作可能会导致为新结果分配内存。

例如,如果我们用Y = X + Y,我们将取消引用Y指向的张量, 而是指向新分配的内存处的张量。

import torch

X = torch.arange(12, dtype=torch.float32).reshape((3,4))
Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])

#Python的id()函数提供了内存中引用对象的确切地址。
before = id(Y)
Y = Y + X

print(id(Y) == before)
# False

这可能是不可取的,原因有两个:

(1)首先,我们不想总是不必要地分配内存。在机器学习中,我们可能有数百兆的参数,并且在一秒内多次更新所有参数。通常情况下,我们希望原地执行这些更新;

(2)如果我们不原地更新,其他引用仍然会指向旧的内存位置,这样我们的某些代码可能会无意中引用旧的参数。

执行原地操作非常简单,使用切片表示法将操作的结果分配给先前分配的数组。

例如Z[:] = <expression>

import torch

X = torch.arange(12, dtype=torch.float32).reshape((3,4))
Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
Z = torch.zeros_like(Y) #创建一个新的矩阵Z,其形状与X/Y相同

print('id(Z):', id(Z))
# id(Z): 140070288237104

Z[:] = X + Y
print('id(Z):', id(Z))
# id(Z): 140070288237104

如果在后续计算中没有重复使用X,可以使用X[:] = X + Y或X += Y来减少操作的内存开销。

import torch

X = torch.arange(12, dtype=torch.float32).reshape((3,4))
Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])

before = id(X)
X += Y

print(id(X) == before)
# True

6、转换为其他Python对象

张量tensor转换为数组张量numpy很容易,反之也同样容易。

torch张量和numpy数组将共享它们的底层内存,就地操作更改一个张量也会同时更改另一个张量。

import torch

X = torch.arange(12, dtype=torch.float32).reshape((3,4))
# tensor([[ 0.,  1.,  2.,  3.],
#         [ 4.,  5.,  6.,  7.],
#         [ 8.,  9., 10., 11.]])

tensor转numpy
A = X.numpy()
# array([[ 0.,  1.,  2.,  3.],
#        [ 4.,  5.,  6.,  7.],
#        [ 8.,  9., 10., 11.]], dtype=float32)

numpy转tensor
B = torch.tensor(A)
# tensor([[ 0.,  1.,  2.,  3.],
#         [ 4.,  5.,  6.,  7.],
#         [ 8.,  9., 10., 11.]])

print(type(A))
# <class 'numpy.ndarray'>

print(type(B))
# <class 'torch.Tensor'>

两者之间的区别

  • PyTorch Tensors:PyTorch 中的 tensor 是这个深度学习框架的基础数据结构,可以在GPU上运行以加速计算。
  • NumPy Arrays:NumPy 的 ndarray 是 Python 中用于科学计算的一个基本库的核心组件。它们被广泛用于各种数值计算任务,并且通常在 CPU 上运行。
  • PyTorch tensors 支持自动微分,这对于训练神经网络来说是非常重要的。而 NumPy arrays 没有内建的自动微分功能。
文章来源:https://blog.csdn.net/weixin_43409127/article/details/135816139
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。