动手学深度学习01 线性回归从零实现

1、导入库

# 设置图片画在网页上
%matplotlib inline
import random
import torch
from d2l import torch as d2l

2、人工模拟数据

# 定义一个方法,生成人造数据集
def synthetic_data(w, b, num_examples):
    """生成 y = Xw + b + 噪声"""
#     返回一个随机的张量
#      normal(均值,标准差,可选的输出张量)
    X = torch.normal(0, 1, (num_examples, len(w)))
#     matul 返回两个矩阵的乘积
    y = torch.matmul(X, w) + b
#     加入噪音
    y += torch.normal(0, 0.01, y.shape)
#     把X 和 y 弄成列向量返回
    return X, y.reshape((-1, 1))

true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)

3、查看数据

# 查看训练样本的样子
print('features:', features[0], '\nlabel:', labels[0])

# 输出数据集图像
# 设置图表大小
d2l.set_figsize()
# 等于matplotlib的scatter,用来绘制散点图
# detach保留数值,去除梯度
d2l.plt.scatter(features[:,1].detach().numpy(), labels.detach().numpy(), 1)

image
如图所示是人工生成的数据集,可以明显看出呈线性分布。

4、读取数据

# 定义一个方法实现每次读取一个小批量
def data_iter(batch_size, features, labels):
    num_examples = len(features)
    inices = list(range(num_examples))
#     打乱顺序,使读取样本随机,没有特定顺序
    random.shuffle(inices)
#     遍历数组,每次读取batch_size长度的数据
    for i in range(0, num_examples, batch_size):
        batch_indices = torch.tensor(inices[i:min(i + batch_size,num_examples)])
        yield features[batch_indices],labels[batch_indices]

# 步长
batch_size = 10
for X,y in data_iter(batch_size, features, labels):
#     打印 一次 小批量的样本, 样本大小与batch
    print(X, '\n' , y)
    break


5、定义参数和模型

# 定义初始化模型参数
w = torch.normal(0, 0.01, size=(2, 1), requires_grad=True)
# 置零
b = torch.zeros(1, requires_grad=True)

# 定义模型
def linreg(X, w, b):
    """线性回归模型, Xw+偏差"""
    return torch.matmul(X,w) + b

6、定义损失函数和优化算法

# 定义损失函数
def squared_loss(y_hat, y):
    """均方损失"""
    return (y_hat - y.reshape(y_hat.shape))**2 / 2

# 定义优化算法
# params 是传进来的list 数据 , lr是学习率, batch_size是步长
# 因为我们计算的损失是一个批量样本的总和,所以我们用批量大小(batch_size)来归一化步长,这样步长大小就不会取决于我们对批量大小的选择
def sgd(params, lr, batch_size):
    """小批量随机梯度下降"""
    with torch.no_grad():
        for param in params:
            param-= lr * param.grad / batch_size
#             torch不会自动把梯度归零,手动归零,使下一次用到梯度就不会和上一次相关
            param.grad.zero_()

7、开始训练过程

# 开始训练
# 定义超参数
# 学习率 太大会不收敛, 太小会下降太慢需要更多轮次的训练
lr = 0.03
# 扫描轮次
num_epochs = 3
# 训练模型
net = linreg
# 损失
loss = squared_loss

for epoch in range(num_epochs):
    for X, y in data_iter(batch_size, features, labels):
        l = loss(net(X, w, b), y) # X 和 y 的小批量损失
#         因为 l 形状是(batch_size, l),而不是一个标量.l 中的所有元素被加到 y
#         并计算[w,b]的梯度
        l.sum().backward()
        sgd([w,b], lr, batch_size)# 使用参数的梯度更新
    with torch.no_grad():
        train_l = loss(net(features, w, b), labels)
        print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')
posted @ 2022-06-16 14:57  酸奶面包  阅读(58)  评论(0编辑  收藏  举报