线性回归算法笔记(1)

本文介绍了如何从头开始使用Python和PyTorch构建线性回归模型,包括数据生成、批量处理、模型定义、训练过程以及误差分析。作者通过实例展示了如何通过小批量随机梯度下降(SGD)优化模型参数以达到低误差。
摘要由CSDN通过智能技术生成

摘要:本实验从0开始,不使用pytorch的现成模型,直接搭建线性回归模型。

0、问题描述


假设特征向量为 w w w(设为 [ − 2 , − 3.4 ] T [-2,-3.4]^T [2,3.4]T), b = 4.2 b=4.2 b=4.2,样本为 X X X,输出为 y y y,同时加上一点噪声 ϵ \epsilon ϵ

y = X w + b + ϵ y=Xw+b+\epsilon y=Xw+b+ϵ

后续就是要通过对大量 X , y X,y X,y关系的学习探索 w , b w,b w,b的取值。

在这里插入图片描述

1、构建训练数据集


我们首先定义synthetic_data函数,用于生成一个 1 , 000 1,000 1,000行的数据集。由于我们知道模型参数的真实值,因此不设测试函数。

  • 生成数据的规则为:指定均值和方差,构建高斯分布随机数据。
  • pytorch在做矩阵乘法的时候,若不满足左矩阵列数=右矩阵行数,例如计算 X m , n w 1 , n X_{m,n}w_{1,n} Xm,nw1,n,会自动调节。
# 生成 y = Xw + b + 噪声
def synthetic_data(w, b, num_examples):
    # X为均值为0,标准差为1,num_examples*len(w)的矩阵,作为初始参数值
    X = torch.normal(0, 1, (num_examples, len(w)))
    print("X =", X.shape)
    print("w =", w.shape)
    # 矩阵乘法,输出标量
    # w为1*len(w)的向量
    y = torch.matmul(X, w) + b
    print("y =", y.shape)
    y += torch.normal(0, 0.01, y.shape)
    return X, y.reshape((-1, 1)) # -1 for auto

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

运行后,输出数据规模:

X = torch.Size([1000, 2])
w = torch.Size([2])
y = torch.Size([1000])

使用d2l库将训练数据进行可视化处理:

d2l.set_figsize()
d2l.plt.scatter(features[:,1].detach().numpy(), \
                labels.detach().numpy(),1)

输出如下:
在这里插入图片描述
可见,生成的数据符合线性分布。

2、批量化读取数据


定义data_iter函数,生成batch_size的小批量训练数据:

# 生成小批量数据
# 例如,batch_size = 10,则返回10组[w|y]样本
def data_iter(batch_size, features, labels):
    num_examples = len(features)
    indices = list(range(num_examples))
    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]
        
batch_size=10

for X,y in data_iter(batch_size,features,labels):
    print("X =", X, "\ny =", y)
    break # 仅输出一组数据

这个函数的作用是:使用yield断点,每调用一次,生成不同的、不重复的,规模为batch_size的特征矩阵和label向量,即为: X ∣ y X | y Xy

3、定义模型


包括模型参数初始化、定义模型等步骤

  • 模型参数初始化:由于本实验的模型仅有两个参数 w , b w,b w,b,因此通过高斯随机分布给出初始值。

  • 模型定义:所谓的模型model,其实就是一个函数,输入特征矩阵 X X X、参数 w , b w, b w,b,输出回归值 y y y,这个过程和BP算法的前向传播过程基本一致。

  • 损失函数:使用平方损失函数: l o s s = 1 2 ( y ∗ − y ) 2 loss=\frac{1}{2}(y^*-y)^2 loss=21(yy)2

  • 优化算法:使用SGD函数,小批量梯度下降算法。

# 初始化模型参数w, b
# 定义向量的时候 打开requires_grad开关
w = torch.normal(0, 0.01, size=(2,1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)
print('w =', w, '\nb =', b)

# 定义模型
def linreg(X, w, b):
    return torch.matmul(X, w) + b

# 定义优化算法-小批量随机梯度下降
def sgd(params, lr, batch_size):
    with torch.no_grad():
        for param in params:
            # print(f'param is {param}')
            param -= lr * param.grad / batch_size
            param.grad.zero_()

4、训练过程


  1. 设置学习率、训练轮数、模型和损失函数等;
  2. 对于每一轮训练而言:
    • 按照之前划分的batch_size,一批一批地读取训练集,对每个批次的数据:
      • 套用model计算回归值 y y y,与真实值 y ∗ y^* y对比计算损失;
      • 计算梯度;
      • 使用SGD优化算法更新参数 w , b w,b w,b
    • 将梯度追踪关闭,计算该epoch的整体平均损失,输出 m e a n [ 1 2 ( y ∗ − y ) 2 ] mean[\frac{1}{2}(y^*-y)^2] mean[21(yy)2](由于该步仅为了输出epoch的整体损失,故不参与梯度下降过程)
# 训练过程
lr = 0.03
num_epochs = 3
model = linreg
loss = squared_loss

for epoch in range(num_epochs):
    for X, y in data_iter(batch_size, features, labels):
        l = loss(model(X, w, b), y)
        l.sum().backward()
        sgd([w, b], lr, batch_size)
    with torch.no_grad():
        train_l = loss(model(features, w, b), labels)
        # print(train_l)
        print(f'epoch {epoch+1}, loss {float(train_l.mean()):f}')
        

输出如下:

epoch 1, loss 0.026238
epoch 2, loss 0.000093
epoch 3, loss 0.000046

5、比较模型误差


我们训练出了一个模型,也就是模型参数 w , b w,b w,b。和真实值做对比,输出误差:

print(f'err of w: {true_w - w.reshape(true_w.shape)}')
print(f'err of b: {true_b - b}')

本次训练, w w w的误差向量为 [ − 0.0005 , − 0.0003 ] T [-0.0005, -0.0003]^T [0.0005,0.0003]T b b b的误差为 0.0002 0.0002 0.0002,效果较好。

6、继续实验


你也可以调节超参数的值,重复实验以寻求最优解。此处就不赘述了。

⭐ 如果你看到这里了,不如点个免费的赞吧~

  • 21
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值