Tensor 设定属性 .requires_grad
为 True
,那么在利用这个张量计算得到其他张量,对结果张量调用 .backward()
来计算所有的梯度时,梯度会保存到 .grad
中
如果不想张量被继续追踪求梯度,可以用 .detach()
或者用 with torch.no_grad()
包裹住代码,这种方法在评估模型的时候很常用,因为在评估模型时,我们并不需要计算可训练参数requires_grad=True
的梯度。
Function
类和 Tensor
类共同组成==计算图==(记录着计算过程的有向无环图),Tensor
有 .grad_fn
,这个属性可以得知某个张量是否是通过某些运算得到的
使用 标量.backward()
不需要向 .backward()
里面传入指定的求导变量,我们应该有意识地回避张量对张量求导,我们应该只允许标量对张量求导(求导结果是和自变量同形的张量),所以我们必要时要把张量通过将所有张量的元素加权求和的方式转换为标量
grad 在反向传播的过程中是累加的,所以每进行一次反向传播之前,都需要使用tensor.grad.data.zero()
把梯度清零
如果我们想要修改tensor
的数值,但是又不希望被autograd
记录(即不会影响反向传播),那么我么可以对tensor.data
进行操作
使用 data
包来读取数据, 由于 data
常用作变量名,我们将导入的data
模块用Data
代替
import torch.utils.data as Data
batch_size = 0
dataset = Data.TensorDataset(features, labels)
data_iter = Data.DataLoader(dataset, batch_size, shuffle=True)
for X, y in data_iter:
pass
用 torch.nn
模块,nn
就是neural networks,nn
的核心数据结构是 nn.Module
, nn.Module
既可以表示神经网络中的某个层,也可以表示多层的神经网络。在自定义网络/层的时候,常用的做法是集成 nn.Module
,自定义的网络/层中应该包含返回输出的 forward
方法
class LinearNet(nn.Module):
def __init__(self, n_feature):
super(LinearNet, self).__init__()
self.linear = nn.Linear(n_feature, 1)
# forward 定义前向传播
def forward(self, x):
y = self.linear(x)
return y
使用 nn.Sequential
搭建网络, Sequential
是一个有序的容器,网络层将按照在传入Sequential
的顺序依次被添加到计算图中。
# 写法一
net = nn.Sequential(
nn.Linear(num_inputs, 1)
# 此处还可以传入其他层
)
# 写法二
net = nn.Sequential()
net.add_module('linear', nn.Linear(num_inputs, 1))
# net.add_module ......
# 写法三
from collections import OrderedDict
net = nn.Sequential(OrderedDict([
('linear', nn.Linear(num_inputs, 1))
# ......
]))
print(net)
print(net[0])
注意:
torch.nn
仅支持输入一个batch的样本不支持单个样本输入,如果只有单个样本,可使用input.unsqueeze(0)
来添加一维。
可以通过net.parameters()
来查看模型所有的可学习参数,此函数将返回一个生成器。
for param in net.parameters():
print(param)
from torch.nn import init
init.normal_(net[0].weight, mean=0, std=0.01)
init.constant_(net[0].bias, val=0) # 也可以直接修改bias的data: net[0].bias.data.fill_(0)
loss = nn.MSELoss()
import torch.optim as optim
optimizer = optim.SGD(net.parameters(), lr=0.03)
print(optimizer)
我们还可以为不同子网络设置不同的学习率,这在finetune时经常用到。例:
optimizer =optim.SGD([
# 如果对某个参数不指定学习率,就使用最外层的默认学习率
{'params': net.subnet1.parameters()}, # lr=0.03
{'params': net.subnet2.parameters(), 'lr': 0.01}
], lr=0.03)
根据特定下标张量取出某个张量的对应值
y_hat = torch.tensor([[0.1, 0.3, 0.6], [0.3, 0.2, 0.5]])
y = torch.LongTensor([0, 2])
y_hat.gather(1, y.view(-1, 1))
import torch
torch.matmul(A, B) # 矩阵乘法
PyTorch 中,一般函数加下划线代表直接在原来的 Tensor 上修改
tensor.scatter_()
scatter_(input, dim, index, src)将src中数据根据index中的索引按照dim的方向填进input中
使用正则项,来约束模型的参数对应的权重,在优化器里面设置weight_decay
参数
optimizer_w = torch.optim.SGD(params=[net.weight], lr=lr, weight_decay=wd) # 对权重参数衰减
dropout
正相传播是指:对神经网络沿着从输入层到输出层的顺序,一次计算并存储模型的中间变量(包括输出)
反向传播
反向传播是计算神经网络参数梯度的方法
计算图
区别与前面使用构造 Sequential
实例来构建网络,使用 Moudule
类来构建网络更加灵活。
模型构建方法:
Moudle
类来构造模型使用 Moudle
的子类: Sequential
、ModuleList
和 ModuleDict
等
如:
net = nn.ModuleList([nn.Linear(784, 256), nn.ReLU()])
print(net.parameters())
print(net.named_parameters())