《动手深度学习》 线性回归从零开始实现实例


作者:Linux猿

简介:CSDN博客专家,华为云享专家,Linux、C/C++、云计算、物联网、面试、刷题、算法尽管咨询我,关注我,有问题私聊!

欢迎小伙伴们点赞、收藏⭐、留言


本文是《动手深度学习》线性回归从零开始实现实例的实现和分析。

一、代码实现

实现代码如下所示。

# random 模块 调用 random() 方法返回随机生成的一个实数,值在[0,1)范围内
import random
# 机器学习框架 pythorch,类似于 TensorFlow 和 Keras
import torch
# 线性回归函数 y = Xw + b + e(噪音)

'''
一系列封装的函数
'''
# 批量获取数据函数
def synthetic_data(w, b, num_examples):  #@save
    # 生成 y=Xw+b+噪声
    '''
    返回一个张量,张量里面的随机数是从相互独立的正态分布中随机生成的
    参与 1: 均值
    参与 2: 标准差
    参数 3: 张量的大小 [num_examples, len(w)]
    '''
    X = torch.normal(0, 1, (num_examples, len(w)))
    # torch.matmul 两个张量元素相乘
    y = torch.matmul(X, w) + b
    # 加上噪声
    y += torch.normal(0, 0.01, y.shape)
    return X, y.reshape((-1, 1))

# 随机批量取数据函数
def data_iter(batch_size, features, labels):
    num_examples = len(features)
    # 生成存储值 0 ~ num_examples 值的列表,不重复
    indices = list(range(num_examples))
    # 在原列表 indices 中随机打乱所有元素
    random.shuffle(indices)
    # range() 第三个参数是步长
    for i in range(0, num_examples, batch_size):
        batch_indices = torch.tensor(
            indices[i: min(i + batch_size, num_examples)])
        # yield 相当于不断的 return 的作用
        yield features[batch_indices], labels[batch_indices]

# 计算预测值,网络模型
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

# 梯度更新
def sgd(params, lr, batch_size):
    # 小批量随机梯度下降
    with torch.no_grad():
        for param in params:
            param -= lr * param.grad / batch_size
            param.grad.zero_() # 清除 param 的梯度值为 0


'''
1. 生成数据集
包含 1000 条数据,每条 [x1, x2]
'''
# 用于生成数据临时的 true_w 和 true_b
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
# features: [1000, 2], labels: [1000, 1]

'''
2. 初始化 w 和 b
w: 2 x 1, b: [0]
'''
# requires_grad 在计算中保留梯度信息
w = torch.normal(0, 0.01, size=(2,1), requires_grad=True)
# 初始化张量为全零
b = torch.zeros(1, requires_grad=True)

'''
3. 开始训练
'''
# 设置超参数 学习率
lr = 0.03
# 设置超参数 训练批次/迭代周期
num_epochs = 3
# 设置超参数 每次训练的数据量
batch_size = 10

# 重命名函数
net = linreg
loss = squared_loss

for epoch in range(num_epochs): # num_epochs 个迭代周期
    for X, y in data_iter(batch_size, features, labels): # 每次随机取 10 条数据一起训练
        l = loss(net(X, w, b), y)  # X 和 y 的小批量损失,计算损失
        l.sum().backward() # 损失求和后,根据构建的计算图,计算关于[w,b]的梯度,反向传播算法一定要是一个标量才能进行计算,所以进行 sum 操作后 backward
        sgd([w, b], lr, batch_size)  # 使用参数的梯度更新参数
    # 不自动求导
    with torch.no_grad():
        train_l = loss(net(features, w, b), labels) # 使用更新后的 [w, b] 计算所有训练数据的 loss
        print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}') # 通过 mean 函数取平均值

'''
with torch.no_grad():
在使用 pytorch 时,并不是所有的操作都需要进行计算图的生成(计算过程的构建,以便梯度反向传播等操作)。
而对于 tensor 的计算操作,默认是要进行计算图的构建的,在这种情况下,可以使用 with torch.no_grad():,
强制之后的内容不进行计算图构建。
'''

二、实现解析

2.1 参数和超参数

参数是需要通过训练来得到的结果,最常见的就是神经网络的权重 W 和 b。训练模型的目的就是要找到一套好的模型参数,用于预测未知的结果。这些参数我们是不用调的,是模型来训练的过程中自动更新生成的。

超参数是我们控制我们模型结构、功能、效率等的 调节旋钮,常见超参数:

(1)learning rate(学习率)

(2)epochs(迭代次数,也可称为 num of iterations)

(3)num of hidden layers(隐层数目)

(4)num of hidden layer units(隐层的单元数/神经元数)

(5)activation function(激活函数)

(6)batch-size(用mini-batch SGD的时候每个批量的大小)

(7)optimizer(选择什么优化器,如SGD、RMSProp、Adam)

(8)用诸如RMSProp、Adam优化器的时候涉及到的β1,β2等等

2.2 模型训练

整体的模型训练思路如下所示。

1. 数据集生成,包括:训练数据、测试数据;

2. 初始化参数 w 和 b;

3. 训练模型,设置超参数,开始训练模型;

参考链接:

深度学习中的超参数调节(learning rate、epochs、batch-size...) - 知乎

loss.sum().backward()中对于sum()的理解


感觉有帮助记得「一键三连支持下哦!有问题可在评论区留言,感谢大家的一路支持!猿哥将持续输出「优质文章回馈大家!


你可能感兴趣的:(动手深度学习实例,线性回归,AI算法,动手深度学习,深度学习实例)