1.pytorch基础
- 定义张量
points = torch.tensor([[1.0, 4.0], [2.0, 1.0], [3.0, 5.0]])
points, points.shape
输出:
tensor([[1., 4.],
[2., 1.],
[3., 5.]]), torch.Size([3, 2])
- 张量存储
points = torch.tensor([[1.0, 4.0], [2.0, 1.0], [3.0, 5.0]])
points.storage()
输出:
1.0
4.0
2.0
1.0
3.0
5.0
[torch.FloatStorage of size 6]
points = torch.tensor([[1.0, 4.0], [2.0, 1.0], [3.0, 5.0]])
points_storage = points.storage()
points_storage[0] = 2.0
points
输出:
tensor([[2., 4.],
[2., 1.],
[3., 5.]])
- 偏移与步长
points = torch.tensor([[1.0, 4.0], [2.0, 1.0], [3.0, 5.0]])
second_point = points[1]
second_point.storage_offset()
输出: 2
points.stride()
输出: (2, 1)
- 克隆
points = torch.tensor([[1.0, 4.0], [2.0, 1.0], [3.0, 5.0]])
second_point = points[1].clone() #重新复制一份
- 转置
points = torch.tensor([[1.0, 4.0], [2.0, 1.0], [3.0, 5.0]])
points
输出:
tensor([[1., 4.],
[2., 1.],
[3., 5.]])
points_t = points.t() #转置后新的张量还是使用原内存
points_t
输出:
tensor([[1., 2., 3.],
[4., 1., 5.]])
points.**is_contiguous**(), points_t.is_contiguous()
输出:
(True, False)
<- 转置后的张量内存显示不连续
- 数据类型
dtype参数的可能取值的列表:
torch.float32或torch.float
—— 32位浮点数
torch.float64或torch.double
—— 64位双精度浮点数
torch.float1
6或torch.half
—— 16位半精度浮点数
torch.int8
—— 带符号8位整数
torch.uint8
—— 无符号8位整数
torch.int16
或torch.short
—— 带符号16位整数
torch.int32
或torch.int
—— 带符号32位整数
torch.int64
或torch.long
—— 带符号64位整数
指定合适的dtype作为张量构造函数的参数,如下所示:
double_points = torch.ones(10, 2, dtype=torch.double)
short_points = torch.tensor([[1, 2], [3, 4]], dtype=torch.short)
你可以通过访问dtype属性来获得张量的数据类型:
short_points.dtype
输出:
torch.int16
您还可以使用相应的转换方法将张量创建函数的输出转换为正确的类型,例如
double_points = torch.zeros(10, 2).double()
short_points = torch.ones(10, 2).short()
或者用更方便的to方法:
double_points = torch.zeros(10, 2).to(torch.double)
short_points = torch.ones(10, 2).to(dtype=torch.short)
在实现内部,type和to执行相同的操作,即“检查类型如果需要就转换(check-and-convert-if-needed)”,但是to方法可以使用其他参数。
你始终可以使用type方法将一种类型的张量转换为另一种类型的张量:
points = torch.randn(10, 2)
short_points = points.type(torch.short)
- 索引张量
我们已经知道points[0]返回一个张量,该张量包含points第一行所表示二维点。如果你需要获取一个包含除第一个点之外的所有点的张量怎么办?如果是应用在标准Python列表上,那么上述任务就可以很简单地用区间索引来实现:
some_list = list(range(6))
some_list[:] # 所有元素
some_list[1:4] # 第1(含)到第4(不含)个元素
some_list[1:] # 第1(含)个之后所有元素
some_list[:4] # 第4(不含)个之前所有元素
some_list[:-1] # 最末尾(不含)元素之前所有元素
some_list[1:4:2] # 范围1(含)到4(不含),步长为2的元素
为了实现这个目标,你可以对PyTorch张量使用相同的表示,并且具有与NumPy和其他Python科学库一样的额外好处,即我们可以对张量的每个维使用区间索引:
points[1:] # 第1行及之后所有行,(默认)所有列
points[1:, :] # 第1行及之后所有行,所有列
points[1:, 0] # 第1行及之后所有行,仅第0列
除了使用区间索引外,PyTorch还具有更强大的索引方式,被称为高级索引(advanced indexing)。
- 与NumPy的互通性
尽管我们认为有使用NumPy的经验不是阅读本书的先决条件,但由于NumPy在Python数据科学生态系统中无处不在,我们强烈建议你熟悉NumPy。PyTorch张量可以方便地转换为NumPy数组,反之亦然。这样,你就可以使用围绕NumPy数组类型构建的更广泛的Python生态系统中的大量功能。
与NumPy数组的这种零拷贝互通性是由于(PyTorch的)存储是遵守Python缓冲协议的。
要从points张量创建NumPy数组,请调用
points = torch.ones(3, 4)
points_np = points.numpy()
points_np
输出:
array([[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]], dtype=float32)
它返回尺寸、形状和数值类型正确的NumPy多维数组。有趣的是,返回的数组与张量存储共享一个基础缓冲区。因此,只要数据位于CPU RAM中,numpy方法就可以几乎零花费地高效执行,并且修改得到的NumPy数组会导致原始张量发生变化。
如果在GPU上分配了张量,(调用numpy方法时)PyTorch会将张量的内容复制到在CPU上分配的NumPy数组中。
相反,你可以通过以下方式从NumPy数组创建PyTorch张量:
points = torch.from_numpy(points_np)
from_numpy使用相同的缓冲共享策略。
- 张量的保存与加载
下面展示怎样将points张量保存到ourpoints.t文件中:
torch.save(points, '../../data/chapter2/ourpoints.t')
或者,你也可以传递文件描述符代替文件名:
with open('../../data/chapter2/ourpoints.t','wb') as f:
torch.save(points, f)
将points加载回来也是一行类似代码:
points = torch.load('../../data/chapter2/ourpoints.t')
等价于
with open('../../data/chapter2/ourpoints.t','rb') as f:
points = torch.load(f)
- 将张量转移到GPU上运行
除了dtype之外,PyTorch张量还具有设备(device)的概念,这是在设置计算机上放张量(tensor)数据的位置。 通过为构造函数指定相应的参数,可以在GPU上创建张量:
points_gpu = torch.tensor([[1.0, 4.0], [2.0, 1.0], [3.0, 4.0]], device='cuda')
你可以使用to方法将在CPU上创建的张量(tensor)复制到GPU:
points_gpu = points.to(device='cuda')
这段代码返回一个具有相同数值数据的新张量,但存储在GPU的RAM中,而不是常规的系统RAM中。
现在数据已经存放在本地的GPU中,当在张量上运行数字运算时,你可以看见很好的加速效果。并且,这个新GPU支持的张量的类也更改为torch.cuda.FloatTensor(一开始输入的类型为torch.FloatTensor;torch.cuda.DoubleTensor等等也存在对应关系)。在大部分样例中,基于CPU和GPU的张量都公开面向用户相同的API,这使得与繁琐数字运算过程中无关的代码的编写更加容易。
如果你的机器拥有多个GPU,你可以通过传递从零开始的整数来确定张量分配给哪个GPU,该整数标志着机器上的GPU下标:
points_gpu = points.to(device='cuda:0')
此时,在GPU上执行对张量的任何操作,例如将所有元素乘以一个常数。
points = 2 * points # 在CPU上做乘法
points_gpu = 2 * points.to(device='cuda') # 在GPU上做乘法
请注意,当计算结果产生后,points_gpu的张量并不会返回到CPU。这里发生的是以下三个过程:
将points张量复制到GPU
在GPU上分配了一个新的张量,并用于存储乘法的结果
返回该GPU张量的句柄
因此,如果你还想向结果加上一个常量:
points_gpu = points_gpu + 4
加法仍然在GPU上执行,并且没有信息流到CPU(除非您打印或访问得到的张量)。 如果要将张量移回CPU,你需要为to方法提供一个cpu参数:
points_cpu = points_gpu.to(device='cpu')
你可以使用速记方法cpu和cuda代替to方法来实现相同的目标
points_gpu = points.cuda() # 默认为GPU0
points_gpu = points.cuda(0)
points_cpu = points_gpu.cpu()
值得一提的是,使用to方法时,可以通过提供device和dtype参数来同时更改位置和数据类型。
API: Pytorch API
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人