深度学习之线性回归模型

发布于:2024-05-13 ⋅ 阅读:(143) ⋅ 点赞:(0)

看完了李沐老师的动手学深度中线性回归,对单层神经网络有了进一步的认识,针对老师上课的代码,我进行了复现并对代码进行了详细的注释。

# 线性回归从0开始实现

import random
import torch
from d2l import torch as d2l

# 根据带有噪声的线性模型构造一个人工数据集,使用线性模型参数w=[2,-3.4].T,b=4.2和噪声项epslion生成数据集及标签

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

    # 均值为0方差为1的正态随机数,样本大小为num_xampls(行数),列数与w的维度相同
    X = torch.normal(0,1,(num_examples,len(w)))

    # 真实值
    y = torch.matmul(X,w) + b 

    # 加入噪音
    y +=torch.normal(0,0.01,y.shape)

    # 返回特征和标签并把标签变为二维张量(1000,1)
    return X,y.reshape((-1,1))

true_w = torch.tensor([2,-3.4])
true_b = 4.2

# 生成真实特征和标签
features, labels = synthetic_data(true_w,true_b,1000)

# 散点图展示

d2l.set_figsize()

# detach将张量转变为array数组进行画散点图
d2l.plt.scatter(features[:,1].detach().numpy(),labels.detach().numpy(),1)

# 定义一个data_iter函数用于接收批量大小、特征矩阵和标签向量作为输入,生成batch_size的小批量

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即随机索引
        batch_indices = torch.tensor(indices[i:min(i+batch_size,num_examples)])

        # 返回随机特征和标签,注意不可以使用return
        yield features[batch_indices], labels[batch_indices]
        # return batch_indices

batch_size = 10

# 查看构造的数据
for X,y in data_iter(batch_size,features,labels):
    print(X,'\n',y)
    break

# 定义初始化参数

# 初始化权重:均值为0方差为1的正太随机数,由于需要计算梯度,因此将requires_grad设置为True
w = torch.normal(0,0.01,size=(2,1),requires_grad=True)

# 初始化偏置为0,由于也要计算梯度因此requires_grad也要设置为True
b = torch.zeros(1,requires_grad=True)


# 定义线性模型

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


# 定义优化算法,采用随机梯度下降法
# params表示一个张量列表,包含w和b,lr是学习率
def sgd(params,lr,batch_size):
    """小批量随机梯度下降"""

    # 表示更新的时候不参与梯度计算
    with torch.no_grad():
        for param in params:
            # 随机梯度下降法,注意要除以均值
            param -= lr * param.grad / batch_size
            # 将梯度设为0,确保下一次计算与上一次结果无关,理论可以看看前面的求导视频
            param.grad.zero_()

# 学习率
lr = 0.03

# 表示将数据扫三遍
num_epochs = 3

# 网络结构(线性模型)
net = linreg

# 损失函数
loss = squared_loss

for epoch in range(num_epochs):
    for X,y in data_iter(batch_size,features,labels):
        # 计算X和y的小批量损失
        l = loss(net(X,w,b),y)

        # 求和之后计算梯度
        l.sum().backward()

        # 梯度下降法更新参数
        sgd([w,b],lr,batch_size)
        
    # 使用最后得到的w,b去预测全部数据并计算与真实标签之间的误差
    with torch.no_grad():
        train_l = loss(net(features,w,b),labels)
        
        # 展示每一次的平均误差
        print(f'epoch {epoch + 1}, loss{float(train_l.mean()):f}')

# 计算真实参数与训练得到的参数之间的误差

print(f'w的估计误差:{true_w-w.reshape(true_w.shape)}')
print(f'b的估计误差:{true_b-b}')


网站公告

今日签到

点亮在社区的每一天
去签到