Pytorch学习笔记(3)线性回归从零开始实现

该博客介绍了如何使用PyTorch构建一个带有噪声的线性数据集,然后通过随机梯度下降(SGD)进行模型训练。内容涵盖了数据生成、批处理读取、模型定义、损失函数计算、优化算法实现以及模型训练过程,最终展示训练后的模型参数与真实参数的误差。
摘要由CSDN通过智能技术生成

主要包括以下几个部分:构建数据集,读数据集,初始化参数,定义模型,定义损失函数,定义优化算法,训练模型。

1.构建数据集

构建一个带有噪声的线性模型的1000个样本的数据集,每个样本从标准正态分布中随机采样2个特征

我们使用线性模型参数w=[2,−3.4]、b=4.2和噪声项ϵ生成数据集及其标签:y=X*w+b+ϵ.

首先引入库

import random
import torch
def create_data(w, b, nums_example):
    X = torch.normal(0, 1, (nums_example, len(w))) #生成均值为0标准差为1的随机数,nums_examples个列数为len(w)的张量,这里X的size为1000*2
    y = torch.matmul(X, w) + b #X*w+b
    print("y_shape:", y.shape) # torch.Size([1000])
    y += torch.normal(0, 0.01, y.shape)  # 加入噪声
    return X, y.reshape(-1, 1)  # y从行向量转为列向量

torch.normal(a,b,c):表示生产一个均值为a,标准差为b,size为c的张量

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

features是根据真实参数构造的X,lables是构造的y

2.读取数据

def read_data(batch_size, features, lables):
    nums_example = len(features) # 等于1000
    indices = list(range(nums_example))  # 生成列表[0,1,2......999]
    random.shuffle(indices)  # 将序列的所有元素随机排序,就像洗一下牌
    for i in range(0, nums_example, batch_size):  
        index_tensor = torch.tensor(indices[i: min(i + batch_size, nums_example)]) # 将数据集切分成batch_size的大小,最后不够就不够当做一个batch
        yield features[index_tensor], lables[index_tensor]  # 通过索引访问向量
        
batch_size = 10
num = nums_example/batch_size
for X, y in read_data(batch_size, features, labels):
    print("X:", X, "\ny", y,"num",num) #x的size是10*2,y的size是10*1
    num = num - 1
    if(num == 0):
        break;

(1) **range()**常用于循环函数,range(start,end [,step])其中取左不取右,start可省略默认为0,step可省略默认为1

(2) **list()**将range()的值列表化

举例:print(list(range(1,5,2)))输出结果是 [1, 3]

(3) shuffle() 方法将序列的所有元素随机排序

用法是:random.shuffle (lst )lst可以是列表

3.初始化参数

随机初始化参数w,b初始化为0

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

4.定义模型

def net(X, w, b):
    return torch.matmul(X, w) + b

5.定义损失函数

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

6.定义优化算法

def sgd(params, batch_size, lr):
    with torch.no_grad():  # with torch.no_grad() 则主要是用于停止autograd模块的工作,
        for param in params:
            param -= lr * param.grad / batch_size # 这里用param = param - lr * param.grad / batch_size会导致导数丢失,下面的zero_()函数报错
            param.grad.zero_()  

上面的循环中要除以batch_size我想是因为算梯度的时候因为对损失函数的输出的张量要求和,而张量中有batch_size个标量,所以参数更新的时候要除一下。

7.训练模型

lr = 0.03
num_epochs = 3

for epoch in range(0, num_epochs):
    for X, y in read_data(batch_size, features, labels): # batch_size为10,features的size为10*2,labels的size为10*1
        f = loss(net(X, w, b), y)
        # 因为`f`形状是(`batch_size`, 1),而不是一个标量。`f`中的所有元素被加到一起,
        # 并以此计算关于[`w`, `b`]的梯度
        f.sum().backward()
        sgd([w, b], batch_size, lr)  # 使用参数的梯度更新参数
    with torch.no_grad():
        train_l = loss(net(features, w, b), labels)
        print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')

print("w误差 ", true_w - w, "\nb误差 ", true_b - b)

这里输出为:

epoch 1, loss 0.045103
epoch 2, loss 0.000178
epoch 3, loss 0.000053
w误差  tensor([[ 1.6487e-04, -5.3998e+00],
        [ 5.3994e+00, -6.4111e-04]], grad_fn=<SubBackward0>) 
b误差  tensor([-6.0081e-05], grad_fn=<RsubBackward1>)

整体代码如下:

import random
import torch

# 构建数据集
def create_data(w, b, nums_example):
    X = torch.normal(0, 1, (nums_example, len(w))) #生成均值为0标准差为1的随机数,nums_examples个列数为len(w)的张量,这里X的size为1000*2
    y = torch.matmul(X, w) + b #X*w+b
    print("y_shape:", y.shape) # torch.Size([1000])
    y += torch.normal(0, 0.01, y.shape)  # 加入噪声
    return X, y.reshape(-1, 1)  # y从行向量转为列向量

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

# 读数据集
def read_data(batch_size, features, lables):
    nums_example = len(features) # 等于1000
    indices = list(range(nums_example))  # 生成列表[0,1,2......999]
    random.shuffle(indices)  # 将序列的所有元素随机排序,就像洗一下牌
    for i in range(0, nums_example, batch_size):  
        index_tensor = torch.tensor(indices[i: min(i + batch_size, nums_example)]) # 将数据集切分成batch_size的大小,最后不够就不够当做一个batch
        yield features[index_tensor], lables[index_tensor]  # 通过索引访问向量
 
batch_size = 10
num = nums_example/batch_size
for X, y in read_data(batch_size, features, labels):
    print("X:", X, "\ny", y,"num",num) #x的size是10*2,y的size是10*1
    num = num - 1
    if(num == 0):
        break;
# 初始化参数       
w = torch.normal(0, 0.01, size=(2, 1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)
# 定义模型
def net(X, w, b):
    return torch.matmul(X, w) + b
# 定义损失函数
def loss(y_hat, y):
    return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2  # MSE均方损失函数
# 定义优化算法
def sgd(params, batch_size, lr):
    with torch.no_grad():  # with torch.no_grad() 则主要是用于停止autograd模块的工作,
        for param in params:
            param -= lr * param.grad / batch_size # 这里用param = param - lr * param.grad / batch_size会导致导数丢失,下面的zero_()函数报错
            param.grad.zero_()  
 
# 训练模型 
lr = 0.03
num_epochs = 3

for epoch in range(0, num_epochs):
    for X, y in read_data(batch_size, features, labels): # batch_size为10,features的size为10*2,labels的size为10*1
        f = loss(net(X, w, b), y)
        # 因为`f`形状是(`batch_size`, 1),而不是一个标量。`f`中的所有元素被加到一起,
        # 并以此计算关于[`w`, `b`]的梯度
        f.sum().backward()
        sgd([w, b], batch_size, lr)  # 使用参数的梯度更新参数
    with torch.no_grad():
        train_l = loss(net(features, w, b), labels)
        print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')

print("w误差 ", true_w - w, "\nb误差 ", true_b - b)
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值