数据操作(深度学习)
为了能够完成各种数据操作,我们需要某种方法来存储和操作数据。
通常,我们需要做两件重要的事:
(1)获取、存储数据;
(2)将数据读入计算机后对其进行处理
张量
n维数组,也叫张量(tensor)。与Numpy的ndarray
类似,但深度学习框架又比Numpy的ndarray
多一些重要功能:
- GPU支持加速计算,而NumPy仅支持CPU计算
- 张量类支持自动微分
创建张量
用 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 | x = torch.tensor([1.0, 2, 4, 8]) |
求幂
1 | torch.exp(x) |
连结多个张量
1 | X = torch.arange(12, dtype=torch.float32).reshape((3,4)) |
用逻辑运算符构建二元张量
1 | print(X == Y) |
对所有元素求和
1 | X.sum() |
广播机制
即使形状不同,我们仍然可以通过调用 广播机制(broadcasting mechanism)来执行按元素操作
- 通过适当复制元素来扩展一个或两个数组,以便在转换之后,两个张量具有相同的形状
- 对生成的数组执行按元素操作
1 | a = torch.arange(3).reshape((3, 1)) |
索引和切片
- 与任何Python数组一样:第一个元素的索引是0,最后一个元素索引是-1; 可以指定范围以包含第一个元素和最后一个之前的元素
- 左闭右开
选择最后一个元素
1 | X[-1] |
选择第二个和第三个元素
1 | X[1:3] |
通过指定索引来将元素写入矩阵
1 | X[1, 2] = 9 |
为多个元素赋值相同的值
[0:2, :]
:访问第1行和第2行,其中“:”代表沿轴1(列)的所有元素
1 | X[0:2, :] = 12 |
节省内存
- 运行一些操作可能会导致为新结果分配内存
- Python的
id()
函数给我们提供了内存中引用对象的确切地址
1 | print(id(Y)) |
这可能是不可取的,原因有两个:
- 首先,我们不想总是不必要地分配内存。在机器学习中,我们可能有数百兆的参数,并且在一秒内多次更新所有参数。通常情况下,我们希望原地执行这些更新;
- 如果不原地更新,其他引用仍然会指向旧的内存位置,这样我们的某些代码可能会无意中引用旧的参数。
执行原地操作
法一:创建一个新的矩阵Z
1 | Z = torch.zeros_like(Y) |
法二:自增自减
如果在后续计算中没有重复使用X
, 我们也可以使用X[:] = X + Y
或X += Y
来减少操作的内存开销
1 | print(id(X)) |
转换为其他Python对象
转换为NumPy张量
将深度学习框架定义的张量[转换为NumPy张量(
ndarray
)]很容易,反之也同样容易torch张量和numpy数组将共享它们的底层内存,就地操作更改一个张量也会同时更改另一个张量
1 | import numpy |
转换为Python标量
可以调用item
函数或Python的内置函数
1 | a = torch.tensor([3.5]) |
其他
如果在jupyter notebook中发现numpy无法使用,可能是因为numpy和pytorch版本不兼容:
关闭jupyter notebook,在虚拟环境中执行以下代码
1 | pip install numpy==1.26.4 |
- 更改1.26.4为和你的pytorch兼容的版本
- 这条命令会卸载原有的numpy,降低版本安装numpy
查阅文档
查找模块中的所有函数和类:
1 | import torch |
通常可以忽略以“__
”(双下划线)开始和结束的函数,它们是Python中的特殊对象, 或以单个“_
”(单下划线)开始的函数,它们通常是内部函数。根据剩余的函数名或属性名,我们可能会猜测这个模块提供了各种生成随机数的方法, 包括从均匀分布(uniform
)、正态分布(normal
)和多项分布(multinomial
)中采样。
查找特定函数和类的用法:
1 | help(torch.ones) |