深度学习之 6 线性回归实现

本文是接着上一篇深度学习之 5 基本数据处理与计算操作_水w的博客-CSDN博客

目录

线性回归实现

 1、手动实现线性回归

(1)导入本次实验所需的包或模块,其中matplotlib包可用于作图,用来显示生成的数据的二维图。

(2)生成数据:

(3)读取数据:

(4)构建模型:

(5)损失函数和优化算法:

(6)模型训练:

2、利用torch.nn实现线性回归

(3)读取数据:

(4)构建模型:

(5)模型参数初始化:

(6)损失函数和优化:

(7)模型训练:


线性回归实现

线性回归 :是机器学习和统计学中最基础和广泛应用的模型,是一种对自变量和因变量之间关系进行建模的回归分析。 从机器学习的角度来看,自变量就是样本的特征向量 x ∈ 𝑅𝑑(每一维对应一个自变量),因变量是标签 y ,这里 y ∈ 𝑅 是 连续值。假设空间是一组参数化的线性函数 𝑓(x); 𝑤, 𝑏 = 𝑥𝑤𝑇 + 𝑏, 其中,权重向量 𝒘 和偏置 𝒃 是线性回归需要学习的参数, 函数 𝑓(x); 𝑤, 𝑏 ∊ 𝑅 称为 线性模型

 1、手动实现线性回归

使用Tensor 和 autograd来实现一个线性回归,具体的步骤有:
        • 生成和读取数据集
        • 构建模型
        • 初始化模型参数
        • 定义损失函数和优化算法
        • 训练模型

(1)导入本次实验所需的包或模块,其中matplotlib包可用于作图,用来显示生成的数据的二维图。

import torch
from IPython import display
from matplotlib import pyplot as plt
import numpy as np
import random

(2)生成数据:

 其中,噪声项𝜀服从均值0、标准差为0.01的正态分布。噪声代表了数据中无意义的干扰。

num_inputs = 2 # 样本特征个数
num_examples = 1000 # 训练数据集样本数
true_w = [2, -3.4] # 使用线性回归模型的真实权重
true_b = 4.2 # 使用线性回归模型的真实偏差
# 生成特征
features = torch.tensor(np.random.normal(0, 1, (num_examples, num_inputs)), dtype=torch.float)
# labels对应我们的y=xwT + b,此时还没有引入噪声
labels = true_w[0] * features[:, 0] + true_w[1] * features[:, 1] + true_b
# 引入噪声,此时labels对应y=xwT + b + 噪声
labels += torch.tensor(np.random.normal(0, 0.01, size=labels.size()), dtype=torch.float)



'''◼使用 𝐮𝐬𝐞_𝐬𝐯𝐠_𝐩𝐚𝐥𝐲() 和 𝐬𝐞𝐭_𝐟𝐢𝐠𝐬𝐢𝐳𝐞() 两个函数来可视化所生成的数据:'''
def use_svg_display():
    # 用矢量图显示
    display.set_matplotlib_formats('svg')

def set_figsize(figsize=(3.5, 2.5)):
    use_svg_display()
    # 设置图的尺寸
    plt.rcParams['figure.figsize'] = figsize
set_figsize()
plt.scatter(features[:, 1].numpy(), labels.numpy(), 1); # 输入特征,生成散点图

(3)读取数据:

 在模型训练的时候,需要遍历数据集并不断读取小批量的数据样本。这里本实验定义一个函数 𝐝𝐚𝐭𝐚_𝐢𝐭𝐞𝐫() 它每次返回 𝒃𝒂𝒕𝒄𝒉_𝒔𝒊𝒛𝒆 (批量大小)个随机样本的特征和标签。

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):
    j = torch.LongTensor(indices[i: min(i + batch_size, num_examples)]) # 最后一次可能不足一个batch
    yield features.index_select(0, j), labels.index_select(0, j)

(4)构建模型:

'''◼ 在构建模型之前,需要将权重和偏置初始化。本实验将权重初始化成均值为0、标准差为0.01的正态随机数,偏置初始化为0。'''
w = torch.tensor(np.random.normal(0, 0.01, (num_inputs, 1)), dtype=torch.float32)
b = torch.zeros(1, dtype=torch.float32)

'''◼ 在后面的模型训练中,需要对这些参数求梯度来迭代参数的值,因此要设置requires_grad = True'''
w.requires_grad_(requires_grad=True)
b.requires_grad_(requires_grad=True)


'''◼ 下面使用 𝐦𝐦() 函数做矩阵乘法,来实现线性回归的模型。'''
def linreg(X, w, b):
    return torch.mm(X, w) + b

(5)损失函数和优化算法:

'''◼ 本实验使用平方损失来定义线性回归的损失函数。在实现中,我们需要把真实值 𝑦 变形成预测值 𝑦_ℎ𝑎𝑡 形状。以下的函数返回的结果和𝑦_ℎ𝑎𝑡的形状相同。'''
def squared_loss(y_hat, y): 
    # 计算预测值和真实值之间的差值的平方再/2
    return (y_hat - y.view(y_hat.size())) ** 2 / 2


'''◼ 以下的 sgd 函数实现了小批量随机梯度下降算法。它通过不断迭代模型参数来优化损失函数。这里自动求梯度模块计算得到的梯度是一个批量样本的梯度和。我们将它除以批量大小来得到平均值。'''
def sgd(params, lr, batch_size):
    '''lr:学习率'''
    # 求出损失函数之后,需要对我们原来的参数来进行优化
    for param in params: # 对于每一个参数,我们通过下面这个表达式进行更改
        param.data -= lr * param.grad / batch_size   
        # 注意这里更改param时用的param.data

(6)模型训练:

'''◼ 在训练过程中,模型将会多次迭代更新参数。
在每次迭代中,根据当前读取的小批量数据样本(特征 x 和标签 y),通过调用反向函数backward计算小批量随机梯度,并调用优化算法𝐬𝐠𝐝迭代模型参数。'''
lr = 0.03  # 学习率
num_epochs = 3  # 会进行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): # x和y分别是小批量样本的特征和标签
l = loss(net(X, w, b), y).sum() # 将数值X传入到我们定义好的网络net里,对他求损失,并对所有的损失进行求和。l是有关小批量X和y的损失
l.backward() # 小批量的损失对模型参数求梯度
sgd([w, b], lr, batch_size) # 使用小批量随机梯度下降迭代模型参数,对参数w,b进行优化
w.grad.data.zero_() # ***因为梯度是叠加的,所以需要对求得的梯度进行梯度清零。如果没有这个清零操作,我们可能最后训练出来的结果是不正确的
b.grad.data.zero_()
train_l = loss(net(features, w, b), labels)
# 输出每一轮的损失是多少,直观感受模型的效果
print('epoch %d, loss %f' % (epoch + 1, train_l.mean().item())) 



'''◼ 训练完成后,打印出学到的参数和用来生成训练集的真实参数,通过比较发现它们之间非常接近。'''
print(true_w, '\n', w)
print(true_b, '\n', b)


'''◼ 输出的结果:'''
[2, -3.4] 
tensor([[ 2.0000], [-3.3996]], requires_grad=True) 
4.2 
tensor([4.1995], requires_grad=True)

2、利用torch.nn实现线性回归

𝐭𝐨𝐫𝐜𝐡. 𝐧𝐧 模块是Pytorch为神经网络设计的模块化接口, 该模块定义了大量的神经网络层。
𝐧𝐧 利用 𝐚𝐮𝐭𝐨𝐠𝐫𝐚𝐝 来定义模型,其核心数据结构是 𝐌𝐨𝐝𝐮𝐥𝐞
下表给出了部分 𝐧𝐧 中所包含模块(其它模块可查阅官方API):

(3)读取数据:

'''◼ PyTorch提供了 𝐝𝐚𝐭𝐚 库来读取数据。由于data常用作变量名,这里将导入的 𝐝𝐚𝐭𝐚 模块用 𝐃𝐚𝐭𝐚 代替。
对前面的读取数据部分可以使用 𝐝𝐚𝐭𝐚 库来处理。在每一次迭代中,使用 𝐃𝐚𝐭𝐚 随机读取包含10个数据
样本的小批量。'''
lr = 0.03  # 学习率
import torch.utils.data as Data
batch_size = 10  # 以多大读取小批量的数据
# 将训练数据的特征和标签组合
dataset = Data.TensorDataset(features, labels)

# 把 dataset 放入 DataLoader,传入参数,通过DataLoader来读取我们的数据
data_iter = Data.DataLoader(
dataset=dataset, # 传入我们的数据集,torch TensorDataset format
batch_size=batch_size, # 小批量的数据大小
shuffle=True, # 是否打乱数据 (训练集一般需要进行打乱)
num_workers=2, # 多线程来读数据,注意在Windows下需要设置为0 
)

(4)构建模型:

'''◼ 构建模型的过程中,最常见的方法就是继承 𝐧𝐧. 𝐌𝐨𝐝𝐮𝐥𝐞,然后构建自己的网络。一个 𝐧𝐧. 𝐌𝐨𝐝𝐮𝐥𝐞 实例需要包含一些层以及返回输出的前向传播方法。下面利用 𝐧𝐧. 𝐌𝐨𝐝𝐮𝐥𝐞 构建一个线性回归模型。'''
class LinearNet(nn.Module):
    def __init__(self, n_feature):
        super(LinearNet, self).__init__()
        self.linear = nn.Linear(n_feature, 1)  # 线性变换

    # forward 定义前向传播
    def forward(self, x):
        y = self.linear(x)
        return y

# 构建模型
net =LinearNet(num_inputs)




'''除了继承 𝐧𝐧. 𝐌𝐨𝐮𝐝𝐥𝐞 来构建线性回归模型,还可以利用 𝐧𝐧. 𝐒𝐞𝐪𝐮𝐞𝐧𝐭𝐢𝐚𝐥 结合 𝐧𝐧. 𝐋𝐢𝐧𝐞𝐚𝐫来搭建模型'''
#写法一:直接按层写进去
net = nn.Sequential(
    nn.Linear(num_inputs, 1)
    # 此处可以添加其它层
)

# 写法二:刚开始并没有定义具体的层是什么,后续再添加层
net = nn.Sequential()
net.add_module('linear', nn.Linear(num_inputs, 1))
net.add_module………

# 写法三:
from collections import OrderedDict
net = nn.Sequential(OrderedDict([
    ('linear', nn.Linear(num_inputs, 1))
    # ……
]))

(5)模型参数初始化:

'''◼ 在使用定义的模型net之前,需要对模型中的一些参数进行初始化。Pytorch在init模块中提供了许多初始化参数的方法。
我们可以调用𝐢𝐧𝐢𝐭. 𝐧𝐨𝐫𝐦𝐚𝐥模块通过正态分布对线性回归中的权重和偏差进行初始化。将参数中的每个元素随机初始化为了均值为0,标准差为0.01的正态分布,同时将偏差初始化为零'''
from torch.nn import init
init.normal_(net[0].weight, mean=0, std=0.01)
init.constant_(net[0].bias, val=0) #也可以直接修改bias的data:net[0].bias.data.fill_(0)

(6)损失函数和优化:

'''◼ Pytorch在 𝑡𝑜𝑟𝑐ℎ. 𝑛𝑛 中提供了各种损失函数,这些损失函数实现为 𝐧𝐧. 𝐌𝐨𝐝𝐮𝐥𝐞 的子类,可以将这些损失函数作为一种特殊的层。'''
loss = nn.MSELoss()



'''◼ Pytorch在 𝐭𝐨𝐫𝐜𝐡. 𝐨𝐩𝐭𝐢𝐦 模块中提供了诸如 𝑺𝑮𝑫 , 𝑨𝒅𝒂𝒎 和 𝑹𝑴𝑺𝑷𝒓𝒐𝒐𝒑 等优化算法。本例将使用小批量随机梯度下降算法进行优化。'''
import torch.optim as optim
optimizer = optim.SGD(net.parameters(), lr=0.03) #梯度下降的学习率指定为0.03

# 可以为不同的子网络设置不同学习率
optimizer =optim.SGD([
    # 如果不指定学习率,则用默认的最外层学习率
    {'params': net.subnet1.parameters()}, # lr=0.03
    {'params': net.subnet2.parameters(), 'lr': 0.01}
], lr=0.03)

(7)模型训练:

'''◼ 训练模型时,可以调用 𝐨𝐩𝐭𝐢𝐦 中的 𝐬𝐭𝐞𝐩() 函数来迭代模型参数。'''
num_epochs = 3
for epoch in range(1, num_epochs + 1):
for X, y in data_iter:
output = net(X) # 把数据X传入到我们刚才定义好的一个网络
l = loss(output, y.view(-1, 1)) # 进行损失计算
optimizer.zero_grad() # 进行梯度清零,等价于net.zero_grad()
l.backward() # 求出梯度
optimizer.step()
print('epoch %d, loss: %f' % (epoch, l.item())) # 结果的展示


'''◼ 部分输出如下所示'''
epoch 1, loss: 0.000457
epoch 2, loss: 0.000081
epoch 3, loss: 0.000198

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

水w

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值