Bootstrap

【pytorch-05】:基本组件使用

PyTorch构建线性回归

前面我们使用手动的方式来构建了一个简单的线性回归模型,如果碰到一些较大的网络设计,手动构建过于繁琐。所以,我们需要学会使用 PyTorch 的各个组件来搭建网络。接下来,我们使用 PyTorch 提供的接口来定义线性回归。

使用 PyTorch 的 nn.MSELoss() 代替自定义的平方损失函数
使用 PyTorch 的 data.DataLoader 代替自定义的数据加载器
使用 PyTorch 的 optim.SGD 代替自定义的优化器
使用 PyTorch 的 nn.Linear 代替自定义的假设函数

1 pytorch基本组件的使用

1.1 损失函数

  • 损失函数存储在nn模块中,nn.MSELoss()为平方损失函数
  • 损失函数对象内部实现了__call__方法,所以可以将对象像函数一样进行调用,传入预测值和真实值进行计算
import torch
import torch.nn as nn
import torch.optim as optim


# 1. 损失函数
def test01():

    # 初始化平方损失函数对象
    criterion = nn.MSELoss()

    # 该类内部重写 __call__ 方法,所以对象可以当做函数来使用
    y_pred = torch.randn(3, 5, requires_grad=True)
    y_true = torch.randn(3, 5)
    # 计算损失
    loss = criterion(y_pred, y_true)
    print(loss)

1.2 假设函数

nn.Linear()线性层(线性模型),参数

  • in_features - 输入数据的特征个数
  • out_features - 输出数据的特征个数
  • nn.Linear()也实现了__call__方法,可以像函数一样进行调用
# 2. 假设函数
def test02():

    # 输入数据的特征必须要有10个
    # 输出数据的特征有5个
    model = nn.Linear(in_features=10, out_features=5)
    # 输入数据
    inputs = torch.randn(4, 10)
    # nn.Linear 实现了 __call__ 方法,可以直接把对象当做函数一样去使用
    y_pred = model(inputs)
    print(y_pred.shape)  # 4,5

1.3 优化方法

import torch.optim as optim
optim.SGD() - 梯度下降法

  • SGD进行参数优化的时候,需要得到模型的训练参数和梯度,model.parameters()可以得到模型训练参数,传入到SGD中
  • SGD更新权重,需要用到学习率 lr
  • backward函数计算梯度之前,需要进行梯度清0,采用optimizer.zeros_grad()
# 3. 优化方法
def test03():
    
    model = nn.Linear(in_features=10, out_features=5)
    # 优化方法: 更新模型参数
    optimizer = optim.SGD(model.parameters(), lr=1e-3)

    # 在 backward 函数调用之前,需要进行梯度清零
    optimizer.zeros_grad()
    # 此处省略了 backward() 函数调用,假设该函数调用完毕
    # 更新模型参数
    optimizer.step()

1.4 数据加载器

1.4.1 自定义数据对象构建

在拿到特征数据和目标数据之后,为了使用pytorch中的DataLoader(),需要先进行构建数据对象
1 自定义数据类,在类中实现 __init__,__len__,__getitem__方法
2 实例化数据类,传入x,y得到数据对象
3 将数据对象传入到DataLoader中,就可以使用pytorch中的数据加载器
自定义数据对象适合于复杂数据类型或需要对数据进行处理的数据使用

import torch
from torch.utils.data import Dataset
from torch.utils.data import DataLoader
from torch.utils.data import TensorDataset


# 1. 数据类构建
class SampleDataset(Dataset):
    
    def __init__(self, x, y):
        """初始化"""
        self.x = x
        self.y = y
        self.len = len(y)

    def __len__(self):
        """返回数据的总量"""
        return self.len
    
    def __getitem__(self, idx):
        """根据索引返回一条样本"""
        # 将 idx 限定在合理的范围内
        idx = min(max(idx, 0), self.len - 1)

        return self.x[idx], self.y[idx]
def test01():

    # 构建包含100个样本的数据集,每个样本有8个特征
    x = torch.randn(100, 8)
    y = torch.randint(0, 2, [x.size(0),])

    # 构建数据加载器的步骤:1. 构建数据类 2. 构建数据加载器
    sample_dataset = SampleDataset(x, y)
    print(sample_dataset[0])

1.4.2 简单数据对象构建

  • 如果数据只需要按照index进行取值,不需要进行处理,可以使用TensorDataset来构建数据对象
from torch.utils.data import TensorDataset

def test03():

    x = torch.randn(100, 8)
    y = torch.randint(0, 2, [x.size(0), ])
    sample_dataset = TensorDataset(x, y)

1.4.3 DataLoader使用

1.导入DataLoader
from torch.utils.data import DataLoade
2.构建数据对象
3.将数据对象传入到DataLoader中设置参数

  • batch_size
  • shuffle = True 表示打乱顺序
# 2. 数据加载器的使用
def test02():

    # 1. 先构建数据对象
    x = torch.randn(100, 8)
    y = torch.randint(0, 2, [x.size(0), ])
    sample_dataset = SampleDataset(x, y)

    # 2. 使用 DataLoader 构建数据加载器
    dataloader = DataLoader(sample_dataset, batch_size=4, shuffle=True)

    for x, y in dataloader:
        print(x)
        print(y)
        break

# 3. 简单的数据类型构建方法
def test03():

    x = torch.randn(100, 8)
    y = torch.randint(0, 2, [x.size(0), ])
    sample_dataset = TensorDataset(x, y)
    dataloader = DataLoader(sample_dataset, batch_size=4, shuffle=True)

    for x, y in dataloader:
        print(x)
        print(y)
        break

2. 线性回归案例

import torch
from torch.utils.data import TensorDataset
from torch.utils.data import DataLoader
import torch.nn as nn
import torch.optim as optim
from sklearn.datasets import make_regression
import matplotlib.pyplot as plt


# 1.构建数据集
def create_dataset():

    x, y, coef = make_regression(n_samples=100,
                                 n_features=1,
                                 noise=10,
                                 coef=True,
                                 bias=14.5,
                                 random_state=0)

    # 将构建数据转换为张量类型
    x = torch.tensor(x)
    y = torch.tensor(y)

    return x, y, coef


def train():

    # 构建数据集
    x, y, coef = create_dataset()
    # 构建数据集对象
    dataset = TensorDataset(x, y)
    # 构建数据加载器
    dataloader = DataLoader(dataset, batch_size=16, shuffle=True)
    # 构建模型
    model = nn.Linear(in_features=1, out_features=1)
    # 构建损失函数
    criterion = nn.MSELoss()
    # 优化方法
    optimizer = optim.SGD(model.parameters(), lr=1e-2)
    # 初始化训练参数
    epochs = 100

    for _ in range(epochs):

        for train_x, train_y in dataloader:

            # 将一个batch的训练数据送入模型
            y_pred = model(train_x.type(torch.float32))
            # 计算损失值
            loss = criterion(y_pred, train_y.reshape(-1, 1).type(torch.float32))
            # 梯度清零
            optimizer.zero_grad()
            # 自动微分(反向传播)
            loss.backward()
            # 更新参数
            optimizer.step()


    # 绘制拟合直线
    plt.scatter(x, y)
    x = torch.linspace(x.min(), x.max(), 1000)
    y1 = torch.tensor([v * model.weight + model.bias for v in x])
    y2 = torch.tensor([v * coef + 14.5 for v in x])

    plt.plot(x, y1, label='训练')
    plt.plot(x, y1, label='真实')
    plt.grid()
    plt.legend()
    plt.show()


if __name__ == '__main__':
    train()
;