# 基于 Pytorch 的线性回归简介实现

主要内容:借助 Pytorch 框架,结合 d2l 面向对象设计,完成线性回归的简洁实现

# 准备

1
2
3
4
import numpy as np
import torch
from torch import nn
from d2l import torch as d2l

torch.nn 包含了常用的神经网络层

# 模型定义 d2l.Module

# 参数及其初始化

1
2
3
4
5
6
7
class LinearRegression(d2l.Module):
def __init__(self, lr):
super().__init__()
self.save_hyperparameters()
self.net = nn.LazyLinear(1)
self.net.weight.data.normal_(0, 0.01) # 正态分布
self.net.bias.data.fill_(0)

torch.nn.LazyLinear 是一种线性层,只需指定 输出维度

.data.normal_ 及 .data.fill_ 完成参数的初始化

# 前向传播过程

1
2
3
@d2l.add_to_class(LinearRegression)
def forward(self, X):
return self.net(X)

net 是一个 nn.LazyLinear 对象,直接调用 nn.LazyLinear () 会执行前向传播过程(__call__() 中实现),即进行神经网络的计算

# 损失函数

1
2
3
4
@d2l.add_to_class(LinearRegression)
def loss(self, y_hat, y):
fn = nn.MSELoss()
return fn(y_hat, y)

nn.MSELoss () 是 Pytorch 自带的平方损失

# 指定优化器

1
2
3
@d2l.add_to_class(LinearRegression)
def configure_optimizers(self):
return torch.optim.SGD(self.parameters(), self.lr)

LinearRegression.parameters () 储存参数

torch.optim.SGD 即随机梯度下降 调用方法为 SGD (params(一个包含参数的列表), lr(学习率))

# 数据准备 d2l.DataModule

Class SyntheticRegressionData 已在 3.3 实现,并且保存在 d2l 包中,可直接调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class SyntheticRegressionData(d2l.DataModule):
"""Synthetic data for linear regression.

Defined in :numref:`sec_synthetic-regression-data`"""
def __init__(self, w, b, noise=0.01, num_train=1000, num_val=1000,
batch_size=32):
super().__init__()
self.save_hyperparameters()
n = num_train + num_val
self.X = d2l.randn(n, len(w))
noise = d2l.randn(n, 1) * noise
self.y = d2l.matmul(self.X, d2l.reshape(w, (-1, 1))) + b + noise

def get_dataloader(self, train):
"""Defined in :numref:`sec_synthetic-regression-data`"""
i = slice(0, self.num_train) if train else slice(self.num_train, None)
return self.get_tensorloader((self.X, self.y), train, i)

# 训练器 d2l.Trainer

一般需要根据实际情况,自定义 fit_epoch (), prepare_batch () 等方法

3.4 中已根据线性回归的需要给出了一个简单实现,且保存在 d2l 包中,可直接调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def fit_epoch(self):
"""Defined in :numref:`sec_linear_scratch`"""
self.model.train() # 训练模式
for batch in self.train_dataloader:
loss = self.model.training_step(self.prepare_batch(batch))
self.optim.zero_grad() # 清零梯度
with torch.no_grad():
loss.backward()
if self.gradient_clip_val > 0: # To be discussed later
self.clip_gradients(self.gradient_clip_val, self.model)
self.optim.step()
self.train_batch_idx += 1
if self.val_dataloader is None:
return
self.model.eval() # 评估模式
for batch in self.val_dataloader:
with torch.no_grad(): # 验证过程无需计算梯度
self.model.validation_step(self.prepare_batch(batch))
self.val_batch_idx += 1

# 训练

1
2
3
4
model = LinearRegression(lr=0.03)
data = d2l.SyntheticRegressionData(w=torch.tensor([2, -3.4]), b=4.2)
trainer = d2l.Trainer(max_epochs=10)
trainer.fit(model, data)

[end]

2024/2/5

mofianger

代码引自 en.d2l.ai

参考:3.5. Concise Implementation of Linear Regression — Dive into Deep Learning 1.0.3 documentation (d2l.ai)