李哥深度学习 第二节下 简单线性表示

1. 导入库

import torch
import matplotlib.pyplot as plt  # 画图的
import random  # 随机

torch:PyTorch 库,用于张量操作和自动求导。

matplotlib.pyplot:用于绘制图形,比如散点图和拟合曲线。

random:用于随机打乱数据索引。

2. 数据生成函数

def create_data(w, b, data_num):  # 生成数据
    x = torch.normal(0, 1, (data_num, len(w)))  # 生成正态分布的输入数据
    y = torch.matmul(x, w) + b  # 计算目标值 y = x * w + b

    noise = torch.normal(0, 0.01, y.shape)  # 生成噪声
    y += noise  # 在目标值上添加噪声

    return x, y

功能:生成线性回归的模拟数据。

参数:

w:真实的权重向量。

b:真实的偏置值。

data_num:生成的数据数量。

实现细节:

x 是从均值为 0、标准差为 1 的正态分布中生成的随机数据,形状为 (data_num, len(w))。

y 是通过线性公式 y = x * w + b 计算得到的。

添加噪声是为了模拟真实数据中的随机误差。

3. 生成数据
 

num = 500
true_w = torch.tensor([8.1, 2, 2, 4])
true_b = 1.1

X, Y = create_data(true_w, true_b, num)

功能:调用 create_data 函数生成数据。

参数:

true_w:真实的权重向量 [8.1, 2, 2, 4]。

true_b:真实的偏置值 1.1。

num:生成 500 个数据点。

返回值:

X:输入数据,形状为 (500, 4)。

Y:目标值,形状为 (500,)。

4. 数据可视化

plt.scatter(X[:, 3], Y, 1)  # 绘制散点图
plt.show()

参数:

X[:, 3]:取 X 的所有行的第四列。必须单独取出某一列

Y:目标值。

1:点的大小。

5. 数据加载器

def data_provider(data, label, batchsize):  # 每次访问这个函数就能提供一批数据
    length = len(label)
    indices = list(range(length))
    random.shuffle(indices)  # 打乱索引

    for each in range(0, length, batchsize):
        get_indices = indices[each: each + batchsize]  # 获取当前批次的索引
        get_data = data[get_indices]  # 获取当前批次的数据
        get_label = label[get_indices]  # 获取当前批次的标签

        yield get_data, get_label  # 返回当前批次的数据和标签

功能:按批次提供数据,支持随机打乱。

参数:

data:输入数据。

label:目标值。

batchsize:批次大小。

实现细节:

使用 random.shuffle 打乱索引,确保每次迭代时数据的顺序是随机的。

使用 yield 返回当前批次的数据和标签,支持迭代。

6. 模型函数

def fun(x, w, b):
    pred_y = torch.matmul(x, w) + b  # 计算预测值 y = x * w + b
    return pred_y

功能:定义线性模型,计算预测值。

参数:

x:输入数据。

w:权重。

b:偏置。

返回值:预测值 pred_y

7. 损失函数

def maeLoss(pre_y, y):
    return torch.sum(abs(pre_y - y)) / len(y)  # 计算平均绝对误差

功能:计算预测值与真实值之间的平均绝对误差(MAE)。

参数:

pre_y:预测值。

y:真实值。

返回值:平均绝对误差。

8. 随机梯度下降(SGD)

def sgd(paras, lr):  # 随机梯度下降,更新梯度
    with torch.no_grad():  # 不计算梯度
        for para in paras:
            para -= para.grad * lr  # 更新参数
            para.grad.zero_()  # 梯度清零

功能:使用随机梯度下降法更新模型参数。

参数:

paras:需要更新的参数列表(如 w 和 b)。

lr:学习率。

实现细节:

(1)with torch.no_grad():确保在更新参数时不计算梯度。

为什么需要:

1.PyTorch 默认会跟踪所有涉及张量的操作,以便自动计算梯度。

2.在更新参数时,我们不需要计算梯度(因为更新参数是一个纯数学操作,不涉及反向传播)。

3.使用 torch.no_grad() 可以节省内存并提高效率。

(2)para -= para.grad * lr:根据梯度和学习率更新参数。

  注意   这里不能写成 para = para - para.grad * lr  

  • 随机梯度下降的更新公式为:

    para=para−lr×grad
  • 为什么用 -=-= 是原地操作,直接修改 para 的值,而不是创建一个新的张量。

(3)para.grad.zero_():将梯度清零,防止梯度累积。

为什么需要?

  • PyTorch 会累积梯度(即每次调用 .backward() 时,梯度会累加到 .grad 中)。

  • 如果不清零,下一次反向传播时,梯度会与之前的梯度累加,导致错误。

  • 因此,每次更新参数后,需要手动将梯度清零。

9. 初始化参数

lr = 0.001
w_0 = torch.normal(0, 0.01, true_w.shape, requires_grad=True)
b_0 = torch.tensor(0.01, requires_grad=True)
print(w_0, b_0)

功能:初始化模型参数。

参数:

w_0:权重,从均值为 0、标准差为 0.01 的正态分布中随机初始化。

b_0:偏置,初始化为 0.01。

requires_grad=True:表示需要计算梯度。

10. 训练模型

epochs = 50

for epoch in range(epochs):
    data_loss = 0
    for batch_x, batch_y in data_provider(X, Y, batchsize):
        pred_y = fun(batch_x, w_0, b_0)  # 计算预测值
        loss = maeLoss(pred_y, batch_y)  # 计算损失
        loss.backward()  # 反向传播,计算梯度
        sgd([w_0, b_0], lr)  # 更新参数
        data_loss += loss  # 累加损失  评估训练的好坏,要看loss值,将所有轮的loss加起来

    print("epoch %03d: loss: %.6f" % (epoch, data_loss))

功能:训练模型。

实现细节:

每个 epoch 遍历所有数据批次。

计算预测值、损失,并进行反向传播和参数更新。

打印每个 epoch 的损失值。

11. 输出结果

print("真实的函数值是", true_w, true_b)
print("训练得到的参数值是", w_0, b_0)

功能:输出真实参数值和训练得到的参数值。

12. 可视化拟合结果

idx = 0
plt.plot(X[:, idx].detach().numpy(), X[:, idx].detach().numpy() * w_0[idx].detach().numpy() + b_0.detach().numpy())
plt.scatter(X[:, idx], Y, 1)
plt.show()

功能:绘制拟合直线和数据点的散点图。

实现细节:

X[:, idx]:取 X 的第一列。

w_0[idx] b_0:训练得到的参数。

plt.plot:绘制拟合直线。

plt.scatter:绘制数据点。

注意:这里要加 .detach().numpy()

总结
这段代码实现了一个简单的线性回归模型,包括数据生成、模型定义、训练和结果可视化。通过随机梯度下降法优化模型参数,最终输出训练得到的参数值,并绘制拟合结果。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

melody6。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值