《动手学深度学习 Pytorch版》 3.3 线性回归的简洁实现

import numpy as np
import torch
from torch.utils import data
from d2l import torch as d2l

from torch import nn  # nn 是神经网络(Neural Networks)的缩写

3.3.1 生成数据集

true_w = torch.tensor([2, -3.4])  # 与上一节类似 生成数据集
true_b = 4.2
features, labels = d2l.synthetic_data(true_w, true_b, 1000)

3.3.2 读取数据集

# 调用现有 API 读取数据,其中 is_train 表示是否打乱数据
def load_array(data_arrays, batch_size, is_train=True):  #@save
    """构造一个PyTorch数据迭代器"""
    dataset = data.TensorDataset(*data_arrays)
    return data.DataLoader(dataset, batch_size, shuffle=is_train)
batch_size = 10
data_iter = load_array((features, labels), batch_size)  # 构造迭代器

next(iter(data_iter))  # 调用 next 函数从迭代器获取第一项
[tensor([[-0.5500,  0.3406],
         [-0.1213,  0.0385],
         [ 1.0384, -0.4336],
         [-0.6411, -0.5833],
         [ 0.9083, -0.2935],
         [-1.5141, -1.2149],
         [ 3.8181, -0.4858],
         [ 1.4873,  0.4429],
         [-0.9654, -1.1355],
         [ 1.2120, -0.8451]]),
 tensor([[ 1.9365],
         [ 3.8387],
         [ 7.7771],
         [ 4.8915],
         [ 7.0209],
         [ 5.2958],
         [13.4798],
         [ 5.6838],
         [ 6.1303],
         [ 9.5189]])]

3.3.3 定义模型

标准的深度学习模型可以试图框架预先定义好的层,我们可以只关注模型的构建而非层的实现细节。

我们定义的模型 net 是 Sequential 类的实例,Sequential 类可以将多个层串在一起,即将数据传入第一层,再将第一层的输出作为第二层输入,以此类推。本模型只用了一层,实际上使用不到 Sequential 类,在此只是熟悉以下标准流程。

net = nn.Sequential(nn.Linear(2, 1))

3.3.4 初始化模型参数

通过 net[0] 选择网络中的第一层,然后使用 weight.data 和 bias.data 访问参数,直接使用预定义的方法 normal_ 和 fill_ 重写参数。

net[0].weight.data.normal_(0, 0.01)
net[0].bias.data.fill_(0)
tensor([0.])

3.3.5 定义损失函数

均方误差使用的是 MSELoss 类,也称为平方 L 2 L_2 L2 范数。默认情况下,它返回所以样本损失的平均值。

loss = nn.MSELoss()

3.3.6 定义优化算法

PyTorch 在 optim 模块中实现了小批量随机梯度下降算法的许多变体。可通过 net.parameters() 从模型获得优化参数以实例化一个 SGD 实例。

trainer = torch.optim.SGD(net.parameters(), lr=0.03)

3.3.7 训练

num_epochs = 3

for epoch in range(num_epochs):
    for X, y in data_iter:
        l = loss(net(X), y)
        trainer.zero_grad()  # 梯度归零
        l.backward()  # 反向传播
        trainer.step()  # 更新模型参数
    l = loss(net(features), labels)
    print(f'epoch {epoch + 1}, loss {l:f}')
epoch 1, loss 0.000116
epoch 2, loss 0.000115
epoch 3, loss 0.000115
w = net[0].weight.data
print('w 的误差估计:', true_w - w.reshape(true_w.shape))
b = net[0].bias.data
print('b 的估计误差:', true_b - b)
w 的误差估计: tensor([-5.7220e-06, -6.5851e-04])
b 的估计误差: tensor([-0.0003])

练习

(1)如果将小批量的总损失替换为小批量损失的平均值,需要如何更改学习率?

不是默认就是损失的均值吗?

如果是均值,则梯度会多一个系数 1 b a t c h _ s i z e \frac{1}{batch\_size} batch_size1,所以为了抵消该系数应该使 l r × b a t c h _ s i z e lr\times batch\_size lr×batch_size

ps:所以说上一节那个 sgd 除一个 batch_size 可能是因为最后传的是总损失,在优化器里除个 batch_size 模拟框架实现的 SGD 默认传均值的样子。感觉多此一举,怪怪的。


(2)查看深度学习框架文档,它们提供了哪些损失函数和初始化方法?用胡伯尔损失代替原损失,即
l ( y , y ′ ) = { ∣ y − y ′ ∣ − σ 2 , 若 ∣ y − y ′ ∣ > σ 1 2 σ ( y − y ′ ) 2 , 其他情况 \begin{equation} l(y,y')=\left\{ \begin{aligned} & |y-y'|-\frac{\sigma}{2} &&, 若|y-y'|>\sigma\\ & \frac{1}{2\sigma}(y-y')^2 &&, 其他情况 \end{aligned} \right. \end{equation} l(y,y)= yy2σ2σ1(yy)2,yy>σ,其他情况

dir(nn)
['AdaptiveAvgPool1d',
 'AdaptiveAvgPool2d',
 'AdaptiveAvgPool3d',
 'AdaptiveLogSoftmaxWithLoss',
 'AdaptiveMaxPool1d',
 'AdaptiveMaxPool2d',
 'AdaptiveMaxPool3d',
 'AlphaDropout',
 'AvgPool1d',
 'AvgPool2d',
 'AvgPool3d',
 'BCELoss',
 'BCEWithLogitsLoss',
 'BatchNorm1d',
 'BatchNorm2d',
 'BatchNorm3d',
 'Bilinear',
 'CELU',
 'CTCLoss',
 'ChannelShuffle',
 'ConstantPad1d',
 'ConstantPad2d',
 'ConstantPad3d',
 'Container',
 'Conv1d',
 'Conv2d',
 'Conv3d',
 'ConvTranspose1d',
 'ConvTranspose2d',
 'ConvTranspose3d',
 'CosineEmbeddingLoss',
 'CosineSimilarity',
 'CrossEntropyLoss',
 'CrossMapLRN2d',
 'DataParallel',
 'Dropout',
 'Dropout1d',
 'Dropout2d',
 'Dropout3d',
 'ELU',
 'Embedding',
 'EmbeddingBag',
 'FeatureAlphaDropout',
 'Flatten',
 'Fold',
 'FractionalMaxPool2d',
 'FractionalMaxPool3d',
 'GELU',
 'GLU',
 'GRU',
 'GRUCell',
 'GaussianNLLLoss',
 'GroupNorm',
 'Hardshrink',
 'Hardsigmoid',
 'Hardswish',
 'Hardtanh',
 'HingeEmbeddingLoss',
 'HuberLoss',
 'Identity',
 'InstanceNorm1d',
 'InstanceNorm2d',
 'InstanceNorm3d',
 'KLDivLoss',
 'L1Loss',
 'LPPool1d',
 'LPPool2d',
 'LSTM',
 'LSTMCell',
 'LayerNorm',
 'LazyBatchNorm1d',
 'LazyBatchNorm2d',
 'LazyBatchNorm3d',
 'LazyConv1d',
 'LazyConv2d',
 'LazyConv3d',
 'LazyConvTranspose1d',
 'LazyConvTranspose2d',
 'LazyConvTranspose3d',
 'LazyInstanceNorm1d',
 'LazyInstanceNorm2d',
 'LazyInstanceNorm3d',
 'LazyLinear',
 'LeakyReLU',
 'Linear',
 'LocalResponseNorm',
 'LogSigmoid',
 'LogSoftmax',
 'MSELoss',
 'MarginRankingLoss',
 'MaxPool1d',
 'MaxPool2d',
 'MaxPool3d',
 'MaxUnpool1d',
 'MaxUnpool2d',
 'MaxUnpool3d',
 'Mish',
 'Module',
 'ModuleDict',
 'ModuleList',
 'MultiLabelMarginLoss',
 'MultiLabelSoftMarginLoss',
 'MultiMarginLoss',
 'MultiheadAttention',
 'NLLLoss',
 'NLLLoss2d',
 'PReLU',
 'PairwiseDistance',
 'Parameter',
 'ParameterDict',
 'ParameterList',
 'PixelShuffle',
 'PixelUnshuffle',
 'PoissonNLLLoss',
 'RNN',
 'RNNBase',
 'RNNCell',
 'RNNCellBase',
 'RReLU',
 'ReLU',
 'ReLU6',
 'ReflectionPad1d',
 'ReflectionPad2d',
 'ReflectionPad3d',
 'ReplicationPad1d',
 'ReplicationPad2d',
 'ReplicationPad3d',
 'SELU',
 'Sequential',
 'SiLU',
 'Sigmoid',
 'SmoothL1Loss',
 'SoftMarginLoss',
 'Softmax',
 'Softmax2d',
 'Softmin',
 'Softplus',
 'Softshrink',
 'Softsign',
 'SyncBatchNorm',
 'Tanh',
 'Tanhshrink',
 'Threshold',
 'Transformer',
 'TransformerDecoder',
 'TransformerDecoderLayer',
 'TransformerEncoder',
 'TransformerEncoderLayer',
 'TripletMarginLoss',
 'TripletMarginWithDistanceLoss',
 'Unflatten',
 'Unfold',
 'UninitializedBuffer',
 'UninitializedParameter',
 'Upsample',
 'UpsamplingBilinear2d',
 'UpsamplingNearest2d',
 'ZeroPad2d',
 '__builtins__',
 '__cached__',
 '__doc__',
 '__file__',
 '__loader__',
 '__name__',
 '__package__',
 '__path__',
 '__spec__',
 '_reduction',
 'common_types',
 'factory_kwargs',
 'functional',
 'grad',
 'init',
 'intrinsic',
 'modules',
 'parallel',
 'parameter',
 'qat',
 'quantizable',
 'quantized',
 'utils']
loss = nn.SmoothL1Loss()

num_epochs = 3

for epoch in range(num_epochs):
    for X, y in data_iter:
        l = loss(net(X), y)
        trainer.zero_grad()  # 梯度归零
        l.backward()  # 反向传播
        trainer.step()  # 更新模型参数
    l = loss(net(features), labels)
    print(f'epoch {epoch + 1}, loss {l:f}')

w = net[0].weight.data
print('w 的误差估计:', true_w - w.reshape(true_w.shape))
b = net[0].bias.data
print('b 的估计误差:', true_b - b)
epoch 1, loss 0.000057
epoch 2, loss 0.000057
epoch 3, loss 0.000057
w 的误差估计: tensor([0.0005, 0.0001])
b 的估计误差: tensor([-0.0001])

(3)如何访问线性回归的梯度?

net[0].weight.grad, net[0].bias.grad
(tensor([[0.0064, 0.0048]]), tensor([-0.0056]))

你可能感兴趣的:(《动手学深度学习,Pytorch版》学习笔记,深度学习,pytorch,线性回归)