Tensor基础
pytorch中的数据以tensor的形式存在,类似于numpy中的ndarrays。可以更好地利用GPU加速运算。
torch.empty(): 定义了一个未被初始化的张量,会被随机初始化为内存中的值。
torch.random() 定义一个值为随机数的张量。
torch.zeros(行数,列数,dtype=torch.long) 定义一个值为0的张量
torch.tensor([1,2,3,4]) 根据给出的数据定义一个张量
还可以从已有的张量(x)中定义一个新的张量,如果不进行指定会复用输入张量的属性(如dtype)
x = x.new_ones(5, 3, dtype=torch.double) # new_* methods take in sizes print(x) x = torch.randn_like(x, dtype=torch.float) # override dtype! print(x) # result has the same size
x.size() 会输入一个张量大小的元组,支持所有元组的操作。
加法操作:
x+y 或 torch.add(x,y,output=...),指定output参数则将结果赋给该参数
y.add_(x) ,y本身的值会改变
操作后加上下划线“_”表示进行的是in-place操作,会改变本身的值。例如 x.copy_(y), x.t_()
可以像numpy一样对张量进行索引。
resize/reshape:
使用 torch.view() 函数,会根据指定参数从原张量中按顺序取元素重组。
x = torch.randn(4, 4) y = x.view(16) z = x.view(-1, 8) #-1表示该维根据另一维计算得到。
.item() 可以以数字的形式取出只有一个元素的张量
张量各种操作参考:https://pytorch.org/docs/stable/torch.html
与numpy转换
使用 .numpy() 可以得到一个张量对应的numpy数组。
使用torch.from_numpy() 可以得到numpy数组对应的张量。
并且如果是在CPU中,张量和numpy数组共享同一个内存,改变一个的值会影响另一个。
在CPU中除了CharTensor之外,所有Tensor都支持与NumPy的互相转换。
CUDA Tensor
if torch.cuda.is_available(): device = torch.device("cuda") # a CUDA device object y = torch.ones_like(x, device=device) # directly create a tensor on GPU x = x.to(device) # or just use strings ``.to("cuda")`` z = x + y print(z) print(z.to("cpu", torch.double)) # ``.to`` can also change dtype together!
Autograd
官方文档:https://pytorch.org/docs/stable/autograd.html#function
Tensor类的属性 .requires_grad 如果被设置为 True (默认为 False ),所有对这个tensor的操作都会被记录下来。在调用 .backward() 函数时,梯度就会被自动计算。计算后的梯度会被累加到属性 .grad 中。如果需要清零梯度,可以使用 .zero_grad()
只有标量可以使用 .backward()求梯度,如果不是标量可以在该函数中传入一个矩阵进行点积得到标量。
所有非用户定义的(通过操作产生的)tensor都会有一个 grad_fn 属性,记录定义这个tensor的Function的引用(由用户定义的为None)。
如果某些操作不需要算入求梯度的步骤中,可以使用 with torch.no_grad(): 或是使用 .detach() 得到一个新的tensor
torch.nn
官方文档:https://pytorch.org/docs/stable/nn.html
自定义的神经网络需要继承nn.Module类, __init__ 函数中定义网络的结构, forward() 函数中定义输入到输出的计算过程。
训练一个神经网络的步骤为:
- 定义包含可学习参数(或权重)的神经网络
- 在数据集或输入上进行迭代
- 通过网络处理输入
- 计算损失
- 将梯度传播回网络的参数
- 更新网络的权重,通常是使用
weight = weight - learning_rate * gradient
通过 .parameters() 可以得到网络中的参数,属于nn.Parameter类。
nn package中自带了许多损失函数,可以直接进行调用,网络的输出结果和目标结果作为参数。
当对损失值(loss)调用 .backward() 网络中所有 requires_grad=True 的tensor都会关于loss计算梯度并累加到 grad 参数中。
反向传播时先清零梯度,调用loss的 .backward() 函数
torch.optim 中预先定义了许多优化函数用于权重的更新,定义好优化函数后每次更新时调用 .step() 函数
# create your optimizer optimizer = optim.SGD(net.parameters(), lr=0.01) # in your training loop: optimizer.zero_grad() # zero the gradient buffers output = net(input) loss = criterion(output, target) loss.backward() optimizer.step() # Does the update
可以为不同层指定不同的学习参数
optim.SGD([ {'params': model.base.parameters()}, {'params': model.classifier.parameters(), 'lr': 1e-3} ], lr=1e-2, momentum=0.9)
数据读取
针对计算机视觉,pytorch还提供了 torchvision 包,其中 torchvision.datasets 中还包含了众多常用的数据集如 Imagenet, CIFAR10, MNIST等
数据集中的图片都是取值为$[0,1]$类型为PIL Image 的图片。
可以使用 torchvision.transforms 包含对数据的多种操作, .Compose() 函数则是用于将多个transform组合。
读取数据集举例:
transform = transforms.Compose( [transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
#表示第一步将数据集中数据转为tensor,第二步进行规范化。第一个参数表示(R,G,B)的均值,第二个参数为方差 trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform) trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True, num_workers=2) testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform) testloader = torch.utils.data.DataLoader(testset, batch_size=4, shuffle=False, num_workers=2) classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
pytorch中有两种类型的数据集,map-style和Iterable-style。
Iterable-style的数据集可以调用 iter(dataset)
会返回一个读数据库的数据流。
Map-style的数据集可以使用 torch.utils.data.Sampler 类指定数据读取时的下标序列。
collate_fn 函数在automatic batching关闭时,传入的参数是单个数据,功能是将其从numpy数组形式转为tensor。如果在automatic batching开启时,会添加一维存储class信息。