为了能够完成各种数据操作,我们需要某种方法来存储和操作数据。

通常,我们需要做两件重要的事:

(1)获取、存储数据;

(2)将数据读入计算机后对其进行处理

张量

n维数组,也叫张量(tensor)。与Numpy的ndarray类似,但深度学习框架又比Numpy的ndarray多一些重要功能:

  1. GPU支持加速计算,而NumPy仅支持CPU计算
  2. 张量类支持自动微分

创建张量

arange 创建一个行向量 x:包含以0开始的前12个整数,它们默认创建为整数。也可指定创建类型为浮点数。

1
x = torch.arange(12)

访问张量形状

1
x.shape

张量中元素总数

1
x.numel()

改变张量形状

1
X = x.reshape(3, 4)

可以以通过-1来调用此自动计算出维度的功能:

x.reshape(-1, 4)x.reshape(3, -1)来取代上面的代码

初始化张量

使用全0、全1、其他常量,或者从特定分布中随机采样的数字

  • 全0

    1
    torch.zeros((2, 3, 4))
  • 全1

    1
    torch.ones((2, 3, 4))
  • 均值为0、标准差为1的标准高斯分布(正态分布)中随机采样

    1
    torch.randn(3, 4)

包含数值的Python列表(或嵌套列表),为所需张量中的每个元素赋予确定值

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

运算符

常见标准运算符

+-*/**

1
2
3
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 # **运算符是求幂运算

求幂

1
torch.exp(x)

连结多个张量

1
2
3
4
5
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]])
print(X)
print(Y)
torch.cat((X, Y), dim=0), torch.cat((X, Y), dim=1)

用逻辑运算符构建二元张量

1
print(X == Y)

对所有元素求和

1
X.sum()

广播机制

即使形状不同,我们仍然可以通过调用 广播机制(broadcasting mechanism)来执行按元素操作

  1. 通过适当复制元素来扩展一个或两个数组,以便在转换之后,两个张量具有相同的形状
  2. 对生成的数组执行按元素操作
1
2
3
4
5
a = torch.arange(3).reshape((3, 1))
b = torch.arange(2).reshape((1, 2))
a, b

a + b

索引和切片

  • 与任何Python数组一样:第一个元素的索引是0,最后一个元素索引是-1; 可以指定范围以包含第一个元素和最后一个之前的元素
  • 左闭右开

选择最后一个元素

1
X[-1]

选择第二个和第三个元素

1
X[1:3]

通过指定索引来将元素写入矩阵

1
2
X[1, 2] = 9
X

为多个元素赋值相同的值

[0:2, :]:访问第1行和第2行,其中“:”代表沿轴1(列)的所有元素

1
2
X[0:2, :] = 12
X

节省内存

  • 运行一些操作可能会导致为新结果分配内存
  • Python的id()函数给我们提供了内存中引用对象的确切地址
1
2
3
4
5
6
print(id(Y))
before = id(Y)
Y = Y + X
print(id(Y))
id(Y) == before
// False

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

  1. 首先,我们不想总是不必要地分配内存。在机器学习中,我们可能有数百兆的参数,并且在一秒内多次更新所有参数。通常情况下,我们希望原地执行这些更新;
  2. 如果不原地更新,其他引用仍然会指向旧的内存位置,这样我们的某些代码可能会无意中引用旧的参数。

执行原地操作

法一:创建一个新的矩阵Z

1
2
3
4
Z = torch.zeros_like(Y)
print('id(Z):', id(Z))
Z[:] = X + Y
print('id(Z):', id(Z))

法二:自增自减

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

1
2
3
4
5
print(id(X))
before = id(X)
X += Y
print(id(X))
id(X) == before

转换为其他Python对象

转换为NumPy张量

  • 将深度学习框架定义的张量[转换为NumPy张量(ndarray]很容易,反之也同样容易

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

1
2
3
4
5
6
7
import numpy
print(numpy.__version__)
print(torch.__version__)

A = X.numpy()
B = torch.tensor(A)
type(A), type(B)

转换为Python标量

可以调用item函数或Python的内置函数

1
2
a = torch.tensor([3.5])
a, a.item(), float(a), int(a)

其他

如果在jupyter notebook中发现numpy无法使用,可能是因为numpy和pytorch版本不兼容:

关闭jupyter notebook,在虚拟环境中执行以下代码

1
pip install numpy==1.26.4
  • 更改1.26.4为和你的pytorch兼容的版本
  • 这条命令会卸载原有的numpy,降低版本安装numpy

查阅文档

查找模块中的所有函数和类:

1
2
3
4
5
import torch

print(dir(torch.distributions))

# ['AbsTransform', 'AffineTransform', 'Bernoulli', 'Beta', 'Binomial', 'CatTransform', 'Categorical', 'Cauchy', 'Chi2', 'ComposeTransform', 'ContinuousBernoulli', 'CorrCholeskyTransform', 'CumulativeDistributionTransform', 'Dirichlet', 'Distribution', 'ExpTransform', 'Exponential', 'ExponentialFamily', 'FisherSnedecor', 'Gamma', 'Geometric', 'Gumbel', 'HalfCauchy', 'HalfNormal', 'Independent', 'IndependentTransform', 'Kumaraswamy', 'LKJCholesky', 'Laplace', 'LogNormal', 'LogisticNormal', 'LowRankMultivariateNormal', 'LowerCholeskyTransform', 'MixtureSameFamily', 'Multinomial', 'MultivariateNormal', 'NegativeBinomial', 'Normal', 'OneHotCategorical', 'OneHotCategoricalStraightThrough', 'Pareto', 'Poisson', 'PowerTransform', 'RelaxedBernoulli', 'RelaxedOneHotCategorical', 'ReshapeTransform', 'SigmoidTransform', 'SoftmaxTransform', 'SoftplusTransform', 'StackTransform', 'StickBreakingTransform', 'StudentT', 'TanhTransform', 'Transform', 'TransformedDistribution', 'Uniform', 'VonMises', 'Weibull', 'Wishart', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'bernoulli', 'beta', 'biject_to', 'binomial', 'categorical', 'cauchy', 'chi2', 'constraint_registry', 'constraints', 'continuous_bernoulli', 'dirichlet', 'distribution', 'exp_family', 'exponential', 'fishersnedecor', 'gamma', 'geometric', 'gumbel', 'half_cauchy', 'half_normal', 'identity_transform', 'independent', 'kl', 'kl_divergence', 'kumaraswamy', 'laplace', 'lkj_cholesky', 'log_normal', 'logistic_normal', 'lowrank_multivariate_normal', 'mixture_same_family', 'multinomial', 'multivariate_normal', 'negative_binomial', 'normal', 'one_hot_categorical', 'pareto', 'poisson', 'register_kl', 'relaxed_bernoulli', 'relaxed_categorical', 'studentT', 'transform_to', 'transformed_distribution', 'transforms', 'uniform', 'utils', 'von_mises', 'weibull', 'wishart']

通常可以忽略以“__”(双下划线)开始和结束的函数,它们是Python中的特殊对象, 或以单个“_”(单下划线)开始的函数,它们通常是内部函数。根据剩余的函数名或属性名,我们可能会猜测这个模块提供了各种生成随机数的方法, 包括从均匀分布(uniform)、正态分布(normal)和多项分布(multinomial)中采样。

查找特定函数和类的用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
help(torch.ones)

'''
Help on built-in function ones in module torch:

ones(...)
ones(*size, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) -> Tensor

Returns a tensor filled with the scalar value `1`, with the shape defined
by the variable argument :attr:`size`.

Args:
size (int...): a sequence of integers defining the shape of the output tensor.
Can be a variable number of arguments or a collection like a list or tuple.

Keyword arguments:
out (Tensor, optional): the output tensor.
dtype (:class:`torch.dtype`, optional): the desired data type of returned tensor.
Default: if ``None``, uses a global default (see :func:`torch.set_default_tensor_type`).
layout (:class:`torch.layout`, optional): the desired layout of returned Tensor.
Default: ``torch.strided``.
device (:class:`torch.device`, optional): the desired device of returned tensor.
Default: if ``None``, uses the current device for the default tensor type
(see :func:`torch.set_default_tensor_type`). :attr:`device` will be the CPU
for CPU tensor types and the current CUDA device for CUDA tensor types.
requires_grad (bool, optional): If autograd should record operations on the
returned tensor. Default: ``False``.

Example::

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

>>> torch.ones(5)
tensor([ 1., 1., 1., 1., 1.])
'''