PyTorch中的data包提供了读取数据的方法

    • TensorDataset(tensor, tensor,…)方法可以将任意个tensor整合起来,方便之后迭代使用,一般可以将特征集与结果集关联起来。
    • DataLoader(dataset, batch_size)方法就相当于之前的data_iter()函数,功能相同,用于数据的迭代。
      1. # 将训练数据的特征和标签组合
      2. dataset = data.TensorDataset(features, labels)
      3. # 随机读取小批量
      4. data_iter = data.DataLoader(dataset, batch_size, shuffle=True)

      torch.nn是neural networks(神经网络)的缩写。顾名思义,该模块定义了大量神经网络的层。之前我们已经用过了autograd,而nn就是利用autograd来定义模型。nn的核心数据结构是Module,它是一个抽象概念,既可以表示神经网络中的某个层(layer),也可以表示一个包含很多层的神经网络。在实际使用中,最常见的做法是继承nn.Module,撰写自己的网络/层。一个nn.Module实例应该包含一些层以及返回输出的前向传播(forward)方法。下面先来看看如何用nn.Module实现一个线性回归模型。

    Linear类的构造函数为:Linear(in_features: int, out_features: int, bias: bool = True),in表示输入特征数量,out表示输出特征数量,bias表示是否包含偏置项。nn.Linear()一般用于设置网络中的全连接层。

    1. class LinearNet(nn.Module):
    2. def __init__(self, n_feature):
    3. super(LinearNet, self).__init__()
    4. # Linear类的构造函数
    5. self.linear = nn.Linear(n_feature, 1)
    6. # 对应前文中的linear_regression(w,x,b)方法,用于计算经过模型后输出的值
    7. def forward(self, x):
    8. y = self.linear(x)
    9. return y
    10. net = LinearNet(num_inputs)
    11. print(net) # 使用print可以打印出网络的结构
    12. 输出如下:
    13. LinearNet(
    14. (linear): Linear(in_features=2, out_features=1, bias=True)
    15. )

    nn.Sequential是一个有序的容器,神经网络模块将按照在传入构造器的顺序依次被添加到计算图中执行,同时以神经网络模块为元素的有序字典也可以作为传入参数,非常好用。
    三种用法如下:

    1. # 写法一
    2. net = nn.Sequential(
    3. nn.Linear(num_inputs, 1)
    4. # 此处还可以传入其他层
    5. )
    6. # 写法二
    7. net = nn.Sequential()
    8. net.add_module('linear', nn.Linear(num_inputs, 1))
    9. # net.add_module ......
    10. # 写法三
    11. from collections import OrderedDict
    12. net = nn.Sequential(OrderedDict([
    13. ('linear', nn.Linear(num_inputs, 1))
    14. # ......
    15. ]))
    16. print(net)
    17. print(net[0])
    18. 输出:
    19. Sequential(
    20. (linear): Linear(in_features=2, out_features=1, bias=True)
    21. )
    22. Linear(in_features=2, out_features=1, bias=True)

    net.parameters()用于查看所有可学习参数

    1. for param in net.parameters():
    2. print(param)
    3. 结果:
    4. Parameter containing:
    5. tensor([[-0.0277, 0.2771]], requires_grad=True)
    6. Parameter containing:
    7. tensor([0.3395], requires_grad=True)

    若将取消线性回归中的偏置项,可以发现parameter的结果少了一个,其实就是少了偏置项。相似地,若把num_inputs设为1,那么参数w也会相应减少。

    1. # 将偏置项置为False
    2. net = nn.Sequential(OrderedDict([
    3. ('linear', nn.Linear(num_inputs, 1, False))
    4. ]))
    5. for param in net.parameters():
    6. print(param)
    7. 结果:
    8. Parameter containing:
    9. tensor([[-0.6295, 0.5504]], requires_grad=True)

    作为一个单层神经网络,线性回归输出层中的神经元和输入层中各个输入完全连接。因此,线性回归的输出层又叫全连接层。

    init包提供了许多初始化参数的方法

    • 其中normal_(tensor, mean=0., std=1.)方法,功能与之前的w = torch.normal()类似。
    • constant_(tensor, val)方法可以直接指定初始化参数的值,因此这里的偏置项被初始化为0 ```python from torch.nn import init

    init.normal(net[0].weight, mean=0, std=0.01) init.constant(net[0].bias, val=0)

    1. > 注:如果这里的`net`是用类定义的,那么上面代码会报错,`net[0].weight`应改为`net.linear.weight``bias`亦然。因为`net[0]`这样根据下标访问子模块的写法只有当`net`是个`ModuleList`或者`Sequential`实例时才可以。
    2. MSELoss表示均方损失函数。损失函数可看作特殊的层,它们也是nn.Module的子类
    3. ```python
    4. loss = nn.MSELoss()

    定义优化算法

    • torch.optim包提供了很多优化算法,这里我们使用SGD(小批量随机梯度下降)作为优化算法 ```python import torch.optim as optim

    optimizer = optim.SGD(net.parameters(), lr=0.03) print(optimizer)

    1. - 还可以为不同子网络设置不同的学习率:
    2. ```python
    3. optimizer = optim.SGD([
    4. # 如果对某个参数不指定学习率,就使用最外层的默认学习率
    5. {'params': net.subnet1.parameters()}, # lr=0.03
    6. {'params': net.subnet2.parameters(), 'lr': 0.01}
    7. ], lr=0.03)
    • 调整学习率

      • 一种是修改optimizer.param_groups中对应的学习率
      • 另一种是更简单也是较为推荐的做法——新建优化器,由于optimizer十分轻量级,构建开销很小,故而可以构建新的optimizer。
      • 后者对于使用动量的优化器(如Adam),会丢失动量等状态信息,可能会造成损失函数的收敛出现震荡等情况。
        1. # 调整学习率
        2. for param_group in optimizer.param_groups:
        3. param_group['lr'] *= 0.1 # 学习率为之前的0.1倍
        训练模型:
    • 之所以这里y是列向量,是由之前labels的维数决定的,在上文中此处:

      • dataset = data.TensorDataset(features, labels)
      • data_iter = data.DataLoader(dataset, batch_size, shuffle=True)
    • view(-1,1)可以将张量转为列向量,值得牢记
      1. num_epoch = 3
      2. for epoch in range(1, num_epoch + 1):
      3. for X, y in data_iter:
      4. output = net(X)
      5. l = loss(output, y.view(-1, 1)) # 由于这里y是列向量,所以不加view(-1,1)也没关系,因为它的目的是将张量转为列向量
      6. optimizer.zero_grad()
      7. l.backward()
      8. optimizer.step()
      9. print('epoch %d, loss: %f' % (epoch, l.item()))
      完整代码: ```python import torch from IPython import display from matplotlib import pyplot as plt import torch.utils.data as data from torch import nn from collections import OrderedDict from torch.nn import init import torch.optim as optim

    def use_svg_display():

    1. # 用矢量图显示
    2. display.set_matplotlib_formats('svg')

    def set_fig_size(fig_size=(3.5, 2.5)): use_svg_display()

    1. # 设置图的尺寸
    2. plt.rcParams['figure.figsize'] = fig_size

    class LinearNet(nn.Module): def init(self, nfeature): super(LinearNet, self)._init() self.linear = nn.Linear(n_feature, 1)

    1. def forward(self, x):
    2. y = self.linear(x)
    3. return y

    if name == “main“: num_inputs = 2 num_examples = 1000 w_true = torch.Tensor([[2], [-3.4]]) b_true = 4.2 features = torch.randn(num_examples, num_inputs, dtype=torch.float32) labels = torch.mm(features, w_true) + b_true labels += torch.normal(mean=0.0, std=0.01, size=labels.size()) w = torch.normal(mean=0.0, std=0.01, size=[2, 1], dtype=torch.float32, requires_grad=True) b = torch.zeros(1, dtype=torch.float32, requires_grad=True) set_fig_size() plt.scatter(features[:, 1], labels, 1) plt.show()

    1. batch_size = 10
    2. dataset = data.TensorDataset(features, labels)
    3. data_iter = data.DataLoader(dataset, batch_size, shuffle=True)
    4. net = nn.Sequential(OrderedDict([
    5. ('linear', nn.Linear(num_inputs, 1))
    6. ]))
    7. for param in net.parameters():
    8. print(param)
    9. init.normal_(net[0].weight, mean=0, std=0.01)
    10. init.constant_(net[0].bias, val=0)
    11. loss = nn.MSELoss()
    12. optimizer = optim.SGD(net.parameters(), lr=0.03)
    13. print(optimizer)
    14. num_epoch = 3
    15. for epoch in range(1, num_epoch + 1):
    16. for X, y in data_iter:
    17. output = net(X)
    18. l = loss(output, y.view(-1, 1)) # 由于这里y是列向量,所以不加view(-1,1)也没关系,因为它的目的是将张量转为列向量
    19. optimizer.zero_grad()
    20. l.backward()
    21. optimizer.step()
    22. print('epoch %d, loss: %f' % (epoch, l.item()))

    ```