【机器学习】006_线性回归模型Part.4_从零实现线性回归模型

从零到有,用基础的函数与算法实现一个线性回归模型

1. 构造人造数据集。

使用线性模型参数 w = [2,-3.4]^{T}, b = 4.2 和噪声项 \varepsilon 生成数据集及其标签:

import random
import torch
from d2l import torch as d2l

# 构造人造数据集
# 假设给定了w, b和数据个数n
def synthetic_data(w, b, num_examples):
    # 生成 y = Xw + b + 噪声
    # X是均值为0,方差为1,n行w列(w的元素数)的张量
    X = torch.normal(0, 1, (num_examples, len(w)))
    # y等于X乘以w再加b
    y = torch.matmul(X, w) + b
    # 引入噪音
    y += torch.normal(0, 0.01, y.shape)
    # 将X,y作为列向量返回
    return X, y.reshape((-1, 1))

# 定义真实的w和真实的b
true_w = torch.tensor([2, -3.4])
true_b = 4.2
# 通过函数生成特征与标注
features, labels = synthetic_data(true_w, true_b, 1000)

2. 数据集的呈现。

features 中的每一行都包含一个二维数据样本,labels 中的每一行都包含一维标签值(标量)。

3. 生成小批量数据集。

(1) 首先,函数 data_iter 接受三个参数:batch_size(批次大小)、features(特征数据)和labels(标签数据)。

(2) 根据特征数据计算样本数,然后创建一个包含所有样本索引的列表 indices。

(3) 接下来,使用random.shuffle函数对样本索引进行随机打乱,以实现随机读取样本的目的。

(4) 然后,使用for循环以batch_size为步长遍历样本索引列表。在每次迭代中,生成一个批次的样本索引batch_indices,使用torch.tensor将其转换为张量。

(5) 最后,使用生成的批次样本索引batch_indices从特征数据和标签数据中获取对应的批次数据,并通过yield语句返回。

def data_iter(batch_size, features, labels):
    num_examples = len(features)
    indices = list(range(num_examples))
    # 样本随机读取,没有特定吮吸
    random.shuffle(indices)
    # 使用for循环将批次一个个分成多份
    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]

4. 初始化模型

输入维度为2,因此初始化w为长度=2的向量,初始化为均值=0,方差为0.01的正态分布。定义梯度下降为True,后续利用梯度下降算法优化w的值。

初始化b为数值为0的标量,定义梯度下降为True,后续利用梯度下降优化b的值。

w = torch.normal(0, 0.01, size=(2,1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)

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

5. 定义损失函数

# 定义损失函数
# y_hat为预测值,y为真实值
def squared_loss(y_hat, y):
    # 均方损失
    return (y_hat - y.reshape(y_hat.shape))**2 / 2
    # 这里没有做均值,直接进行了相加

6. 定义优化算法

# 定义优化算法
# params是包含w和b的list参数,lr是学习率,batch_size是批量数
def sgd(params, lr, batch_size):
    # 小批量随机梯度下降
    # 在更新参数时不会进行梯度计算和记录。因为我们只关心参数的更新,而不需要计算梯度
    with torch.no_grad():
        for param in params:
              # 这里除以batch_size是因为上面的损失函数没有做均值
              param -= lr * param.grad / batch_size
              # 手动将梯度设置为0
              param.grad.zero_()

7. 训练过程

# 训练过程
# 手动设置学习率
lr = 1
# 将数据扫三遍
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, 1), 而不是一个标量。
        # 对损失做求和,求和后调用backward计算损失对模型参数的梯度
        l.sum().backward()
        # 梯度算法更新w和b的值
        sgd([w, b], lr, batch_size)
        # 注意的问题:batch_size可能无法被样本数量整除,在梯度算法里可能会多除
    with torch.no_grad():
        # 将整个数据的预测与labels传入loss,做损失对比,进行模型预测的评估
        train_1 = loss(net(features, w, b), labels)
        print(f'epoch {epoch+1}, loss {float(train_1.mean()):f}')
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值