线性回归 实现

目录

线性规划从零开始

线性回归pytorch


说明:本文参考了Dive-into-DL-PyTorch的学习笔记这本书

线性规划从零开始

1.导入开发过程中需要的包

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

print(torch.__version__)
torch.set_default_tensor_type('torch.FloatTensor')

2.生成数据集

训练数据集是人工构造的,样本数是1000,特征数是2。样本数是随机生成的。true_w是该模型的真实权重,true_b是真实偏差

其中使用了一个随机噪声项,该噪声项服从均值为0,标准差为0.01的正态分布。其代表了数据集中无意义的干扰。

num_inputs = 2
num_examples = 1000
true_w = [2, -3.4]
true_b = 4.2
features = torch.randn(num_examples, num_inputs)
labels = true_w[0] * features[:, 0] + true_w[1] * features[:, 1] + true_b
labels += torch.tensor(np.random.normal(0, 0.01, size=labels.size()), dtype=torch.float)

print(features[0], labels[0])
 

 

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

# # 在../d2lzh_pytorch里面添加上面两个函数后就可以这样导入
# import sys
# sys.path.append("..")
# from d2lzh_pytorch import * 

set_figsize()
plt.scatter(features[:, 1].numpy(), labels.numpy(), 1);

线性回归 实现_第1张图片

3.读取数据

在训练模型的时候,我们需要遍历数据集并不断读取小批量数据样本。这里我们定义一个函数:它每次返回 batch_size (批量大小)个随机样本的特征和标签。 让我们读取第一个小批量数据样本并打印。每个批量的特征形状为 (10, 2) ,分别对应批量大小和输入个 数;标签形状为批量大小。
# 本函数已保存在d2lzh包中方便以后使用
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)


batch_size = 10

for X, y in data_iter(batch_size, features, labels):
    print(X, '\n', y)
    break

线性回归 实现_第2张图片

4.初始化模型参数

将权重初始化成均值为 0 、标准差为 0.01 的正态随机数,偏差则初始化成 0
之后的模型训练中,需要对这些参数求梯度来迭代参数的值,因此我们要让它们的 requires_grad=True 。
w = torch.tensor(np.random.normal(0, 0.01, (num_inputs, 1)), dtype=torch.float)
b = torch.zeros(1)

w.requires_grad_(requires_grad=True)
b.requires_grad_(requires_grad=True) 

5.定义模型

使用 mm 函数做矩阵乘法。
def linreg(X, w, b):  # 本函数已保存在d2lzh包中方便以后使用
    return torch.mm(X, w) + b

6.定义损失函数 

def squared_loss(y_hat, y):  # 本函数已保存在pytorch_d2lzh包中方便以后使用
    return (y_hat - y.view(y_hat.size())) ** 2 / 2

7.定义优化算法 

sgd 函数实现了 小批量随机梯度下降算法。它通过不断迭代模型参数来优化损失 函数。这里自动求梯度模块计算得来的梯度是一个批量样本的梯度和。我们将它除以批量大小来得到平 均值。
def sgd(params, lr, batch_size):  # 本函数已保存在d2lzh_pytorch包中方便以后使用
    for param in params:
        param.data -= lr * param.grad / batch_size # 注意这里更改param时用的param.data

8.训练模型 

在训练中,我们将多次迭代模型参数。在每次迭代中,我们根据当前读取的小批量数据样本(特征 X 和 标签 y ),通过调用反向函数 backward 计算小批量随机梯度,并调用优化算法 sgd 迭代模型参数。由于我们之前设批量大小 batch_size 10 ,每个小批量的损失 l 的形状为 (10, 1) 。回忆一下自动求梯度一节。由于变量 l 并不是一个标量,所以我们可以调用 .sum() 将其求和得到一个标量,再运行l.backward() 得到该变量有关模型参数的梯度。注意在每次更新完参数后不要忘了将参数的梯度清
零。在一个迭代周期(epoch )中,我们将完整遍历一遍 data_iter 函数,并对训练数据集中所有样本都使用一次(假设样本数能够被批量大小整除)。这里的迭代周期个数 num_epochs 和学习率 lr 都是超参数,分别设3 0.03 。在实践中,大多超参数都需要通过反复试错来不断调节。虽然迭代周期数设得越大模型可能越有效,但是训练时间可能过长。
lr = 0.03
num_epochs = 3
net = linreg
loss = squared_loss

for epoch in range(num_epochs):  # 训练模型一共需要num_epochs个迭代周期
    # 在每一个迭代周期中,会使用训练数据集中所有样本一次(假设样本数能够被批量大小整除)。X
    # 和y分别是小批量样本的特征和标签
    for X, y in data_iter(batch_size, features, labels):
        l = loss(net(X, w, b), y).sum()  # l是有关小批量X和y的损失
        l.backward()  # 小批量的损失对模型参数求梯度
        sgd([w, b], lr, batch_size)  # 使用小批量随机梯度下降迭代模型参数
        
        # 不要忘了梯度清零
        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)

线性回归 实现_第3张图片

线性回归pytorch

1.导入具体的包

import torch
from torch import nn
import numpy as np
torch.manual_seed(1)

print(torch.__version__)
torch.set_default_tensor_type('torch.FloatTensor')

2.生成数据集

  人工构造训练数据集,样本数是1000,特征数是2。true_w是真实权重,true_b是真实偏差。进行随机构造特征值。

  此外真实值中包含噪声项,该噪声项服从均值为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 = true_w[0] * features[:, 0] + true_w[1] * features[:, 1] + true_b
labels += torch.tensor(np.random.normal(0, 0.01, size=labels.size()), dtype=torch.float)

3.读取数据

PyTorch提供了 data 包来读取数据。由于 data 常用作变量名,我们将导入的 data 模块用 Data 代替。

在每一次迭代中,我们将随机读取包含10个数据样本的小批量。

import torch.utils.data as Data

batch_size = 10

# 将训练数据的特征和标签组合
dataset = Data.TensorDataset(features, labels)

# 把 dataset 放入 DataLoader
data_iter = Data.DataLoader(
    dataset=dataset,      # torch TensorDataset format
    batch_size=batch_size,      # mini batch size
    shuffle=True,               # 要不要打乱数据 (打乱比较好)
    num_workers=2,              # 多线程来读数据
)

for X, y in data_iter:
    print(X, '\n', y)
    break

线性回归 实现_第4张图片

4.定义模型

在pytorch官网上找到nn.Linear的解释如下:

线性回归 实现_第5张图片

class LinearNet(nn.Module):
    def __init__(self, n_feature):
        super(LinearNet, self).__init__()
        self.linear = nn.Linear(n_feature, 1)

    def forward(self, x):
        y = self.linear(x)
        return y
    
net = LinearNet(num_inputs)
print(net) # 使用print可以打印出网络的结构

 

用 nn.Sequential 来更加方便地搭建网络, Sequential 是一个有序的容器,网络层将按照在传入 Sequential 的顺序依次被添加到计算图中。由于在这个里面只添加了一个线性网络Linear,因此容器的个数为1,下标为0。

net = nn.Sequential(
    nn.Linear(num_inputs, 1)
    # 此处还可以传入其他层
    )


print(net)
print(net[0])

 

for param in net.parameters():
    print(param)

5.初始化模型参数

通过 init.normal_ ()将权重参数每个元素初始化为随机采样于均值为0、标准差为0.01的正态分布。偏差会初始化为零。

from torch.nn import init

init.normal_(net[0].weight, mean=0.0, std=0.01)
init.constant_(net[0].bias, val=0.0)  # 也可以直接修改bias的data: net[0].bias.data.fill_(0)

 

for param in net.parameters():
    print(param)

6.定义损失函数

loss = nn.MSELoss()

7.定义优化算法

import torch.optim as optim

optimizer = optim.SGD(net.parameters(), lr=0.03)
print(optimizer)

线性回归 实现_第6张图片

8.训练模型

我们通过调用 optim 实例的 step 函数来迭代模型参数。按照小批量随机梯度下降的定义,我们在 step 函数中指明批量大小,从而对批量中样本梯度求平均。

num_epochs = 3
for epoch in range(1, num_epochs + 1):
    for X, y in data_iter:
        output = net(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()))

 

dense = net[0]
print(true_w, dense.weight.data)
print(true_b, dense.bias.data)

 

你可能感兴趣的:(机器学习)