Pytorch 基础篇 之 tensor基本语法(1)
目录
一,认识张量
# 辅助函数, 用来做一些格式化输出
def describe(x):
print("Type: {}".format(x.type()))
print("Shape/size: {}".format(x.shape))
print("Values: \n{}".format(x))
简单生成一个张量,并利用函数查看其格式
1.1 张量生成
import torch
describe(torch.Tensor(2, 3))# 随机生成的,方便测试
describe(torch.ones(2, 3))
describe(torch.rand(2, 3)) # uniform random
describe(torch.randn(2, 3)) # random normal
x = torch.Tensor([[1, 2, 3],
[4, 5, 6]])
describe(x) #也可以手动写张量
1.2 张量格式和尺寸
可能到这里还没显示出张量type的重要性,事实上,熟悉数字图像处理之类课程的朋友应该了解图片和torch之间经常存在从numpy向量到tensor张量的格式转变环节,pytorch也封装了这种方法。
import numpy as np
npy = np.random.rand(2, 3)
describe(torch.from_numpy(npy))
类似的,更多类型转换如下
下面介绍arange(),View(),sum(),transpose()函数的使用
1.3 张量运算
在创建了张量之后,可以像处理传统编程语言类型(如“+”、“-”、“* ”和“/”)那样对它们进行操作。除了操作符,我们还可以使用.add()
之类的函数
1.4 索引,切片,链结
pytorch也支持更复杂的索引和切片操作的函数,这部分比较复杂,可以选择性阅读
下面就是一系列链结操作了,注意辨析cat()和stack()方法的不同
1.5 计算图
PyTorch 张量类封装了数据(张量本身)和一系列操作,如代数操作、索引操作和整形操作。然而当 requires_grad 布尔标志被设置为 True 的张量,记账操作启用,pytorch可以追踪的梯度张量以及梯度函数
import torch
x = torch.ones(2, 2, requires_grad=True)
describe(x)
print(x.grad is None)
Type: torch.FloatTensor
Shape/size: torch.Size([2, 2])
Values:
tensor([[1., 1.],
[1., 1.]], requires_grad=True)
True
y = (x + 2) * (x + 5) + 3 # 点乘3*6+3=21
describe(y)
print(x.grad is None)
Type: torch.FloatTensor
Shape/size: torch.Size([2, 2])
Values:
tensor([[21., 21.],
[21., 21.]], grad_fn=<AddBackward0>)
True
z = y.mean()
describe(z)
z.backward()
# x2 + 7x ---> 2x+7
print(x.grad is None)
Type: torch.FloatTensor
Shape/size: torch.Size([])
Values:
21.0
# 假设 x 是一个需要计算梯度的张量
x = torch.tensor([1.0, 2.0], requires_grad=True)
# 进行一些操作,假设 x2 是 x 的一个变换
x2 = x + 7
# 计算 x2 的平均值
z = x2.mean()
# 反向传播,计算梯度
z.backward()
# 检查 x 的梯度
print(x.grad is None) # 应该输出 False,因为 x 有梯度信息
print(x.grad) # 输出 x 的梯度信息
False
tensor([0.5000, 0.5000])
当使用requires_grad=True
创建张量时,需要 PyTorch 来管理计算梯度的 bookkeeping 信息。首先,PyTorch 将跟踪向前传递的值。然后,在计算结束时,使用单个标量来计算向后传递。反向传递是通过对一个张量使用 backward() 方法来初始化的,这个张量是由一个损失函数的求值得到的。向后传递为参与向前传递的张量对象计算梯度值。
一般来说,梯度是一个值,它表示函数输出相对于函数输入的斜率。在计算图形设置中,模型中的每个参数都存在梯度,可以认为是该参数对误差信号的贡献。在 PyTorch 中,可以使用.grad
成员变量访问计算图中节点的梯度。优化器使用.grad
变量更新参数的值。
到目前为止,我们一直在 CPU 内存上分配张量。在做线性代数运算时,首先需要分配GPU内存上的张量。对 gpu 的访问是通过一个名为 CUDA 的专门 API 进行的。CUDA API 是由 NVIDIA 创建的,并且仅限于在 NVIDIA gpu 上使用。PyTorch 提供的 CUDA 张量对象在使用中与常规 cpu 张量没有区别,除了内部分配的方式不同,使用时需要将cpu上的张量转移到gpu上。
1.6 gpu上的张量
PyTorch 创建 CUDA 非常容易,它可以将张量从 CPU 传输到 GPU,同时维护其底层类型。PyTorch 中的首选方法是与设备无关,并编写在 GPU 或 CPU 上都能工作的代码。在下面的代码片段中,我们首先使用torch.cuda.is_available()
检查 GPU 是否可用,然后使用torch.device
检索设备名。然后,实例化所有未来的张量,并使用.to(device)
方法将其移动到目标设备。
import torch
print (torch.cuda.is_available())
True
# preferred method: device agnostic tensor instantiation
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print (device)
cuda
x = torch.rand(3, 3).to(device)
describe(x)
Type: torch.cuda.FloatTensor
Shape/size: torch.Size([3, 3])
Values:
tensor([[0.5758, 0.3527, 0.4333],
[0.6156, 0.9461, 0.0713],
[0.4473, 0.8831, 0.2117]], device=‘cuda:0’)
要对 CUDA 和非 CUDA 对象进行操作,我们需要确保它们在同一设备上(cpu or gpu)。如果我们不这样做,计算就会中断,如下面的代码片段所示。
将cpu张量和gpu的混在一起计算
y = torch.rand(3, 3)
x + y
# true dude
RuntimeError Traceback (most recent call last)
in
1 y = torch.rand(3, 3)
----> 2 x + y
RuntimeError: expected type torch.cuda.FloatTensor but got torch.FloatTensor
但是,我们将张量都移动到cpu上后,计算就可照常进行了
cpu_device = torch.device("cpu")
y = y.to(cpu_device)
x = x.to(cpu_device)
x + y
tensor([[0.6273, 0.8465, 0.6007],
[0.9960, 1.3771, 0.8768],
[1.0754, 1.8308, 0.9686]])
二,写在最后
这个blog也是我在探索这样琐碎的代码片段用什么手段呈现效果比较好的产物,综合来看还是最后的看着顺眼点(我承认中间贴图是犯懒)。虽然训练网络的时候可能不会用到手写tensor这种很细枝末节的东西,但是对于实际实验中,出现关于tensor的报错,一些可能出现的基础报错类型,在熟悉了tensor的格式后也能更快的定位问题,我想还是有一定学习价值的。