JoyBeanRobber

导航

李沐动手学深度学习6——线性回归

李沐动手学深度学习,有视频、有中文电子书(含配套代码),推荐!

视频(B站搜一大堆):https://www.bilibili.com/video/BV1fsmyYnEfw?spm_id_from=333.788.videopod.episodes&vd_source=0199f117e2bdbb60970034d4f33ff67d

官网电子书:https://zh.d2l.ai/index.html

主要内容是:随机生成数据功能,批量读取数据功能,模型、损失、优化算法的定义,模型训练

以下是代码:

import random
import torch
import matplotlib.pyplot as plt


# 生成y=Xw+b+噪声
def synthetic_data(w, b, num_examples):

    X = torch.normal(0, 1, (num_examples, len(w)))
    y = torch.matmul(X, w) + b
    y += torch.normal(0, 0.01, y.shape)
    return X, y.reshape((-1, 1))


# 批量获取数据
def data_iter(batch_size, features, labels):
    num_examples = len(features)
    indices = list(range(num_examples))
    # 原地打乱可变序列,shuffle是洗牌的意思
    random.shuffle(indices)
    for i in range(0, num_examples, batch_size):
        batch_indices = torch.tensor(
            indices[i: min(i+batch_size, num_examples)]
        )
        # 返回一个迭代器
        yield features[batch_indices], labels[batch_indices]


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


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


# 定义优化算法:小批量随机梯度下降
def sgd(params, lr, batch_size):
    # no_grad是pytorch的用于禁用梯度计算的上下文管理器
    with torch.no_grad():
        for param in params:
            # 除以batch_size的意义在于:
            # 因为计算的损失是一个批量样本的总和,所以用批量大小来规范化步长,这样步长大小就不会取决于我们对批量大小的选择
            param -= lr * param.grad / batch_size
            param.grad.zero_()


if __name__=="__main__":
    true_w = torch.tensor([2, -3.4])
    true_b = 4.2
    features, labels = synthetic_data(true_w, true_b, 1000)
    print('features:', features[0], '\nlabel:', labels[0])

    # 查看数据
    fig, ax = plt.subplots(figsize=(12, 8))
    ax.scatter(features[:, 1].detach().numpy(), labels.detach().numpy(), s=10)
    plt.show()

    # 测试数据集批量读取函数
    batch_size = 10
    for X, y in data_iter(batch_size, features, labels):
        print(X, '\n', y)
        break

    # 初始化模型参数,w为一个0上下的小数值,b设为0
    # 若将权重全部初始化为0:所有神经元在反向传播时会获得相同的梯度更新,导致网络无法学习不同的特征
    # 若初始数值过大,会导致前向传播的输出值过大,经过激活函数(如Sigmoid、Tanh)后容易饱和,使梯度接近0
    w = torch.normal(0, 0.01, size=(2, 1), requires_grad=True)
    b = torch.zeros(1, requires_grad=True)

    lr = 0.03
    num_epochs = 3
    net = linreg
    loss = squared_loss

 

posted on 2025-04-19 15:58  欢乐豆掠夺者  阅读(65)  评论(0)    收藏  举报