小杰机器学习(seven)——PyTorch进行线性回归——模型定义、数据集加载、保存模型、加载模型、查看网络结构。

PyTorch是学术界最为推崇的深度框架。

1.模型定义

torch.nn下的容器

以上是PyTorch支持的所有容器类型。

1.1 Sequential

nn.Sequential()是pytorch的容器,按照顺序组合多个网络层,内部有forward方法,会定义前向传播的逻辑。

import torch
import numpy as np

# 1、散点输入
data = [[-0.5, 7.7], [1.8, 98.5], [0.9, 57.8], [0.4, 39.2], [-1.4, -15.7], [-1.4, -37.3], [-1.8, -49.1], [1.5, 75.6],
        [0.4, 34.0], [0.8, 62.3]]
# 转换为np数组
data = np.array(data)
data
# 提取每个点的x_data和y_data
x_data = data[:, 0]
y_data = data[:, 1]
print(x_data)
print(y_data)

# 将x_data 和 y_data 转换成tensor
x_train = torch.tensor(x_data, dtype=torch.float32)
y_train = torch.tensor(y_data, dtype=torch.float32)
print(x_train)
print(y_train)

# 2. 定义前向模型
import torch.nn as nn

# 方案1:顺序容器——支持多参数网络,本例非常简单,只有一层
model = nn.Sequential(
    nn.Linear(1, 1)  # 顺序容器的网络内容:线性,1输入1输出
)

# 3. 定义损失函数和优化器
criterion = nn.MSELoss()  # 均方误差
# 定义随机梯度下降的优化器
optimizer = torch.optim.SGD(
    model.parameters(),  # 模型参数
    lr=0.01  # 学习率
)

# unsqueeze可以增加维度,参数是增加的维度是哪一维度
print(x_train.unsqueeze(0))  # 一个样本点(行数),十个特征(列数)
print(x_train.unsqueeze(1))  # 十个样本点(行数),一个特征(列数)
# 4. 开始迭代
epochs = 500  # 迭代次数
for n in range(1, epochs + 1):
    # 4.1 前向传播
    y_pre = model(x_train.unsqueeze(1))  # 参数是n*m的输入矩阵
    # print(y_pre)  # 预测值
    # 计算损失函数
    loss = criterion(
        y_pre.squeeze(1),  # 参数1:预测值(移除第二维,恢复一维)
        y_train  # 参数2: 真实值
    )

    # 清空之前优化器重存储的梯度参数,以便于本次epoch重新进行反向传播
    optimizer.zero_grad()

    # 4.2 反向传播
    loss.backward()

    # 5. 显示频率设置
    if n == 1 or n % 10 == 0:
        # 遍历模型参数
        for name, param in model.named_parameters():
            # 如有,取出当前计算的梯度
            if param.grad is not None:
                print(f"梯度:{name}:{param.grad}")
            # 如有,取出当前计算的w和b
            if param.data is not None:
                print(f"w和b的值:{param.data}")
        # 每隔10次显示一次损失函数
        print(f"epoch:{n},loss:{loss}")
        print("-----------------------------------")

    # 更新参数,例如w新 = 学习率与w旧的计算
    optimizer.step()

1.2 ModuleList

nn.ModuleList() 和python的基础数据类型list类似,按照顺序,没有forward方法,不可以定义名字,可以用append加网络。

如果使用需要重写继承nn.Module

import torch
import numpy as np

# 1、散点输入
data = [[-0.5, 7.7], [1.8, 98.5], [0.9, 57.8], [0.4, 39.2], [-1.4, -15.7], [-1.4, -37.3], [-1.8, -49.1], [1.5, 75.6],
        [0.4, 34.0], [0.8, 62.3]]
# 转换为np数组
data = np.array(data)
data
# 提取每个点的x_data和y_data
x_data = data[:, 0]
y_data = data[:, 1]
print(x_data)
print(y_data)

# 将x_data 和 y_data 转换成tensor
x_train = torch.tensor(x_data, dtype=torch.float32)
y_train = torch.tensor(y_data, dtype=torch.float32)
print(x_train)
print(y_train)

# 2. 定义前向模型
import torch.nn as nn


# -------------------------------------------------------
# 方案2:继承nn.Module
class LinearModel(nn.Module):
    # 构造函数:初始化
    def __init__(self):
        # 调用父类的构造函数
        super(LinearModel, self).__init__()
        # ModuleList,支持多网络结构(本例只有一个网络层)
        self.layers = nn.ModuleList(
            [nn.Linear(1, 1)]  # 参数为多个网络层结构,使用list传入
        )

    def forward(self, x):
        """
        前向传播方法
        :param x: 输入张量
        :return: 网络层处理后的输出张量
        """
        # 遍历列表多个网络层
        for layer in self.layers:
            x = layer(x)
        return x


# 创建模型对象
model = LinearModel()
# -------------------------------------------------------


# 3. 定义损失函数和优化器
criterion = nn.MSELoss()  # 均方误差
# 定义随机梯度下降的优化器
optimizer = torch.optim.SGD(
    model.parameters(),  # 模型参数
    lr=0.01  # 学习率
)

# unsqueeze可以增加维度,参数是增加的维度是哪一维度
print(x_train.unsqueeze(0))  # 一个样本点(行数),十个特征(列数)
print(x_train.unsqueeze(1))  # 十个样本点(行数),一个特征(列数)
# 4. 开始迭代
epochs = 500  # 迭代次数
for n in range(1, epochs + 1):
    # 4.1 前向传播
    y_pre = model(x_train.unsqueeze(1))  # 参数是n*m的输入矩阵
    # print(y_pre)  # 预测值
    # 计算损失函数
    loss = criterion(
        y_pre.squeeze(1),  # 参数1:预测值(移除第二维,恢复一维)
        y_train  # 参数2: 真实值
    )

    # 清空之前优化器重存储的梯度参数,以便于本次epoch重新进行反向传播
    optimizer.zero_grad()

    # 4.2 反向传播
    loss.backward()

    # 5. 显示频率设置
    if n == 1 or n % 10 == 0:
        # 遍历模型参数
        for name, param in model.named_parameters():
            # 如有,取出当前计算的梯度
            if param.grad is not None:
                print(f"梯度:{name}:{param.grad}")
            # 如有,取出当前计算的w和b
            if param.data is not None:
                print(f"w和b的值:{param.data}")
        # 每隔10次显示一次损失函数
        print(f"epoch:{n},loss:{loss}")
        print("-----------------------------------")

    # 更新参数,例如w新 = 学习率与w旧的计算
    optimizer.step()

1.3 ModuleDict

nn.ModuleDict(),和dict类似,不按照顺序,没有forward方法,可以定义每层的名字

import torch
import numpy as np

# 1、散点输入
data = [[-0.5, 7.7], [1.8, 98.5], [0.9, 57.8], [0.4, 39.2], [-1.4, -15.7], [-1.4, -37.3], [-1.8, -49.1], [1.5, 75.6],
        [0.4, 34.0], [0.8, 62.3]]
# 转换为np数组
data = np.array(data)
data
# 提取每个点的x_data和y_data
x_data = data[:, 0]
y_data = data[:, 1]
print(x_data)
print(y_data)

# 将x_data 和 y_data 转换成tensor
x_train = torch.tensor(x_data, dtype=torch.float32)
y_train = torch.tensor(y_data, dtype=torch.float32)
print(x_train)
print(y_train)

# 2. 定义前向模型
import torch.nn as nn


# -------------------------------------------------------
# 方案3:
class LinearModel(nn.Module):
    # 构造函数:初始化
    def __init__(self):
        # 调用父类的构造函数
        super(LinearModel, self).__init__()
        # ModuleDict,支持多网络结构(本例只有一个网络层)
        self.layers = nn.ModuleDict(
            {"Linear1": nn.Linear(1, 1)}  # 参数为多个网络层结构,使用dict传入
        )

    def forward(self, x):
        """
        前向传播方法
        :param x: 输入张量
        :return: 网络层处理后的输出张量
        """
        # 遍历列表多个网络层
        for key in self.layers:
            x = self.layers[key](x)
        return x


# -------------------------------------------------------

# 创建模型对象
model = LinearModel()

# 3. 定义损失函数和优化器
criterion = nn.MSELoss()  # 均方误差
# 定义随机梯度下降的优化器
optimizer = torch.optim.SGD(
    model.parameters(),  # 模型参数
    lr=0.01  # 学习率
)

# unsqueeze可以增加维度,参数是增加的维度是哪一维度
print(x_train.unsqueeze(0))  # 一个样本点(行数),十个特征(列数)
print(x_train.unsqueeze(1))  # 十个样本点(行数),一个特征(列数)
# 4. 开始迭代
epochs = 500  # 迭代次数
for n in range(1, epochs + 1):
    # 4.1 前向传播
    y_pre = model(x_train.unsqueeze(1))  # 参数是n*m的输入矩阵
    # print(y_pre)  # 预测值
    # 计算损失函数
    loss = criterion(
        y_pre.squeeze(1),  # 参数1:预测值(移除第二维,恢复一维)
        y_train  # 参数2: 真实值
    )

    # 清空之前优化器重存储的梯度参数,以便于本次epoch重新进行反向传播
    optimizer.zero_grad()

    # 4.2 反向传播
    loss.backward()

    # 5. 显示频率设置
    if n == 1 or n % 10 == 0:
        # 遍历模型参数
        for name, param in model.named_parameters():
            # 如有,取出当前计算的梯度
            if param.grad is not None:
                print(f"梯度:{name}:{param.grad}")
            # 如有,取出当前计算的w和b
            if param.data is not None:
                print(f"w和b的值:{param.data}")
        # 每隔10次显示一次损失函数
        print(f"epoch:{n},loss:{loss}")
        print("-----------------------------------")

    # 更新参数,例如w新 = 学习率与w旧的计算
    optimizer.step()

1.4 手动编写

最常用的网络结构,直接重写继承nn.Module

import torch
import numpy as np

# 1、散点输入
data = [[-0.5, 7.7], [1.8, 98.5], [0.9, 57.8], [0.4, 39.2], [-1.4, -15.7], [-1.4, -37.3], [-1.8, -49.1], [1.5, 75.6],
        [0.4, 34.0], [0.8, 62.3]]
# 转换为np数组
data = np.array(data)
data
# 提取每个点的x_data和y_data
x_data = data[:, 0]
y_data = data[:, 1]
print(x_data)
print(y_data)

# 将x_data 和 y_data 转换成tensor
x_train = torch.tensor(x_data, dtype=torch.float32)
y_train = torch.tensor(y_data, dtype=torch.float32)
print(x_train)
print(y_train)

# 2. 定义前向模型
import torch.nn as nn


# -------------------------------------------------------
# 方案4:
class LinearModel(nn.Module):
    # 构造函数:初始化
    def __init__(self):
        # 调用父类的构造函数
        super(LinearModel, self).__init__()
        # ModuleDict,支持多网络结构(本例只有一个网络层)
        self.layer1 = nn.Linear(1, 1)
        # self.layer2 = nn.Linear(1, 1) # 如果是两个网络层是这样的

    def forward(self, x):
        """
        前向传播方法
        :param x: 输入张量
        :return: 网络层处理后的输出张量
        """
        # 多个网络层连接
        x = self.layer1(x)
        # x = self.layer2(x)
        return x


# -------------------------------------------------------

# 创建模型对象
model = LinearModel()

# 3. 定义损失函数和优化器
criterion = nn.MSELoss()  # 均方误差
# 定义随机梯度下降的优化器
optimizer = torch.optim.SGD(
    model.parameters(),  # 模型参数
    lr=0.01  # 学习率
)

# unsqueeze可以增加维度,参数是增加的维度是哪一维度
print(x_train.unsqueeze(0))  # 一个样本点(行数),十个特征(列数)
print(x_train.unsqueeze(1))  # 十个样本点(行数),一个特征(列数)
# 4. 开始迭代
epochs = 500  # 迭代次数
for n in range(1, epochs + 1):
    # 4.1 前向传播
    y_pre = model(x_train.unsqueeze(1))  # 参数是n*m的输入矩阵
    # print(y_pre)  # 预测值
    # 计算损失函数
    loss = criterion(
        y_pre.squeeze(1),  # 参数1:预测值(移除第二维,恢复一维)
        y_train  # 参数2: 真实值
    )

    # 清空之前优化器重存储的梯度参数,以便于本次epoch重新进行反向传播
    optimizer.zero_grad()

    # 4.2 反向传播
    loss.backward()

    # 5. 显示频率设置
    if n == 1 or n % 10 == 0:
        # 遍历模型参数
        for name, param in model.named_parameters():
            # 如有,取出当前计算的梯度
            if param.grad is not None:
                print(f"梯度:{name}:{param.grad}")
            # 如有,取出当前计算的w和b
            if param.data is not None:
                print(f"w和b的值:{param.data}")
        # 每隔10次显示一次损失函数
        print(f"epoch:{n},loss:{loss}")
        print("-----------------------------------")

    # 更新参数,例如w新 = 学习率与w旧的计算
    optmizer.step()

2. 数据集加载

pytroch文档中的数据集加载的API

应用场景或者作用:

数据集比较大的时候,无法一次性加载到内存中,就分批次进行加载。

import torch
import numpy as np

# 1、散点输入
data = [[-0.5, 7.7], [1.8, 98.5], [0.9, 57.8], [0.4, 39.2], [-1.4, -15.7], [-1.4, -37.3], [-1.8, -49.1], [1.5, 75.6],
        [0.4, 34.0], [0.8, 62.3]]
# 转换为np数组
data = np.array(data)
data
# 提取每个点的x_data和y_data
x_data = data[:, 0]
y_data = data[:, 1]
print(x_data)
print(y_data)

# 将x_data 和 y_data 转换成tensor
x_train = torch.tensor(x_data, dtype=torch.float32)
y_train = torch.tensor(y_data, dtype=torch.float32)
print(x_train)
print(y_train)

# --------------------------start--------------------------------
# 导入
from torch.utils.data import TensorDataset, DataLoader

# 使用TensorDataset对象封装张量
dataset = TensorDataset(
    x_train,  # 输入特征张量
    y_train  # 输出特征张量
)
print(dataset[0])  # 第一个样本的输入输出
print(dataset[1][0])  # 第二个样本的输入

# 使用DataLoader加载数据集
dataloader = DataLoader(
    dataset,  # 数据集
    batch_size=5,  # 一个批次五个数据
    shuffle=True  # 随机
)
# 观察dataloader内部数据
for data in dataloader:
    print(data)

# --------------------------end----------------------------


# 2. 定义前向模型
import torch.nn as nn


# 方案4:
class LinearModel(nn.Module):
    # 构造函数:初始化
    def __init__(self):
        # 调用父类的构造函数
        super(LinearModel, self).__init__()
        # ModuleDict,支持多网络结构(本例只有一个网络层)
        self.layer1 = nn.Linear(1, 1)
        # self.layer2 = nn.Linear(1, 1) # 如果是两个网络层是这样的

    def forward(self, x):
        """
        前向传播方法
        :param x: 输入张量
        :return: 网络层处理后的输出张量
        """
        # 多个网络层连接
        x = self.layer1(x)
        # x = self.layer2(x)
        return x


# 创建模型对象
model = LinearModel()

# 3. 定义损失函数和优化器
criterion = nn.MSELoss()  # 均方误差
# 定义随机梯度下降的优化器
optimizer = torch.optim.SGD(
    model.parameters(),  # 模型参数
    lr=0.01  # 学习率
)

# --------------------------start--------------------------------
# unsqueeze可以增加维度,参数是增加的维度是哪一维度
print(x_train.unsqueeze(0))  # 一个样本点(行数),十个特征(列数)
print(x_train.unsqueeze(1))  # 十个样本点(行数),一个特征(列数)
# 4. 开始迭代
epochs = 500  # 迭代次数(训练次数)
for n in range(1, epochs + 1):
    # 分不同的批次训练多次,最后求平均损失
    epoch_loss = 0  # 一个迭代的多个批次的损失函数和
    for batch_x, batch_y in dataloader:  # 每一个迭代(epoch)的批次
        # print(batch_x)
        # print(batch_y)
        # 预测
        y_pre = model(batch_x.unsqueeze(1))
        # 计算批损失
        batch_loss = criterion(
            y_pre.squeeze(1),  # 参数1:预测值(移除第二维,恢复一维)
            batch_y  # 参数2: 真实值
        )
        epoch_loss += batch_loss
        optimizer.zero_grad()  # 清空梯度
        batch_loss.backward()  # 反向传播
        optimizer.step()  # 更新参数
    # 计算当前epoch多个批次的平均损失值
    avg_loss = epoch_loss / len(dataloader)
    # 5. 显示频率设置
    if n == 1 or n % 10 == 0:
        # 遍历模型参数
        for name, param in model.named_parameters():
            # 如有,取出当前计算的梯度
            if param.grad is not None:
                print(f"梯度:{name}:{param.grad}")
            # 如有,取出当前计算的w和b
            if param.data is not None:
                print(f"w和b的值:{param.data}")
        # 每隔10次显示一次损失函数
        print(f"epoch:{n},loss:{avg_loss}")
        print("-----------------------------------")
# --------------------------end----------------------------
    # # 4.1 前向传播
    # y_pre = model(x_train.unsqueeze(1))  # 参数是n*m的输入矩阵
    # # print(y_pre)  # 预测值
    # # 计算损失函数
    # loss = criterion(
    #     y_pre.squeeze(1),  # 参数1:预测值(移除第二维,恢复一维)
    #     y_train  # 参数2: 真实值
    # )
    #
    # # 清空之前优化器重存储的梯度参数,以便于本次epoch重新进行反向传播
    # optimizer.zero_grad()
    #
    # # 4.2 反向传播
    # loss.backward()
    #
    # # 5. 显示频率设置
    # if n == 1 or n % 10 == 0:
    #     # 遍历模型参数
    #     for name, param in model.named_parameters():
    #         # 如有,取出当前计算的梯度
    #         if param.grad is not None:
    #             print(f"梯度:{name}:{param.grad}")
    #         # 如有,取出当前计算的w和b
    #         if param.data is not None:
    #             print(f"w和b的值:{param.data}")
    #     # 每隔10次显示一次损失函数
    #     print(f"epoch:{n},loss:{loss}")
    #     print("-----------------------------------")
    #
    # # 更新参数,例如w新 = 学习率与w旧的计算
    # optimizer.step()

3. 保存模型

模型保存的主要目的是为了避免重复训练提高效率,包括:

  • 避免重复训练:模型训练通常需要大量的时间和计算资源,尤其是对于复杂的模型和大规模的数据集。如果训练过程中断,保存的模型可以避免从头开始训练,从而节省时间和资源。
  • 提高效率:在迭代开发过程中,保存模型可以快速加载之前的训练状态,进行进一步的调整和优化,而无需重新训练整个模型。
  • 模型共享:保存的模型可以方便地共享给其他研究人员或部署到生产环境中,而无需重新训练。
  • 防止过拟合:在某些情况下,保存中间状态的模型可以帮助防止过拟合,因为可以从不同的训练阶段选择最佳模型。

有两种保存方式

  1. 保存模型的权重和其他参数
  2. 保存整个模型

3.1 方式1:保存模型的权重和其他参数

使用torch.save()保存,该函数将模型的状态字典保存到文件中,其中包括模型的权重和其他参数。

  • 参数1:model.state_dict()返回模型的状态字典,其中包含模型的所有参数。
  • 参数2:保存的路径

torch.save()函数将这个状态字典保存到名为model.pth的文件中 pth是pytorch的标准的一个模型文件。官方推荐这种保存方式。

3.2 方式2:保存整个模型

保存整个模型,包括其结构和参数,也使用torch.save()函数。

  • 参数1:模型对象。
  • 参数2:保存的路径

需要注意的是,保存整个模型可能会占用更多的磁盘空间,并且不如保存状态字典灵活,因为状态字典可以与不同的模型结构兼容。

3.3 代码

import torch
import numpy as np
from torch.utils.data import TensorDataset, DataLoader
import torch.nn as nn

# 1、散点输入
data = [[-0.5, 7.7], [1.8, 98.5], [0.9, 57.8], [0.4, 39.2], [-1.4, -15.7], [-1.4, -37.3], [-1.8, -49.1], [1.5, 75.6],
        [0.4, 34.0], [0.8, 62.3]]
# 转换为np数组
data = np.array(data)
data
# 提取每个点的x_data和y_data
x_data = data[:, 0]
y_data = data[:, 1]
print(x_data)
print(y_data)

# 将x_data 和 y_data 转换成tensor
x_train = torch.tensor(x_data, dtype=torch.float32)
y_train = torch.tensor(y_data, dtype=torch.float32)
print(x_train)
print(y_train)

# 使用TensorDataset对象封装张量
dataset = TensorDataset(
    x_train,  # 输入特征张量
    y_train  # 输出特征张量
)
print(dataset[0])  # 第一个样本的输入输出
print(dataset[1][0])  # 第二个样本的输入

# 使用DataLoader加载数据集
dataloader = DataLoader(
    dataset,  # 数据集
    batch_size=5,  # 一个批次五个数据
    shuffle=True  # 随机
)
# 观察dataloader内部数据
for data in dataloader:
    print(data)


# 2. 定义前向模型
# 方案4:
class LinearModel(nn.Module):
    # 构造函数:初始化
    def __init__(self):
        # 调用父类的构造函数
        super(LinearModel, self).__init__()
        # ModuleDict,支持多网络结构(本例只有一个网络层)
        self.layer1 = nn.Linear(1, 1)
        # self.layer2 = nn.Linear(1, 1) # 如果是两个网络层是这样的

    def forward(self, x):
        """
        前向传播方法
        :param x: 输入张量
        :return: 网络层处理后的输出张量
        """
        # 多个网络层连接
        x = self.layer1(x)
        # x = self.layer2(x)
        return x


# 创建模型对象
model = LinearModel()

# 3. 定义损失函数和优化器
criterion = nn.MSELoss()  # 均方误差
# 定义随机梯度下降的优化器
optimizer = torch.optim.SGD(
    model.parameters(),  # 模型参数
    lr=0.01  # 学习率
)

# unsqueeze可以增加维度,参数是增加的维度是哪一维度
print(x_train.unsqueeze(0))  # 一个样本点(行数),十个特征(列数)
print(x_train.unsqueeze(1))  # 十个样本点(行数),一个特征(列数)
# 4. 开始迭代
epochs = 500  # 迭代次数(训练次数)
for n in range(1, epochs + 1):
    # 分不同的批次训练多次,最后求平均损失
    epoch_loss = 0  # 一个迭代的多个批次的损失函数和
    for batch_x, batch_y in dataloader:  # 每一个迭代(epoch)的批次
        # print(batch_x)
        # print(batch_y)
        # 预测
        y_pre = model(batch_x.unsqueeze(1))
        # 计算批损失
        batch_loss = criterion(
            y_pre.squeeze(1),  # 参数1:预测值(移除第二维,恢复一维)
            batch_y  # 参数2: 真实值
        )
        epoch_loss += batch_loss
        optimizer.zero_grad()  # 清空梯度
        batch_loss.backward()  # 反向传播
        optimizer.step()  # 更新参数
    # 计算当前epoch多个批次的平均损失值
    avg_loss = epoch_loss / len(dataloader)
    # 5. 显示频率设置
    if n == 1 or n % 10 == 0:
        # 遍历模型参数
        for name, param in model.named_parameters():
            # 如有,取出当前计算的梯度
            if param.grad is not None:
                print(f"梯度:{name}:{param.grad}")
            # 如有,取出当前计算的w和b
            if param.data is not None:
                print(f"w和b的值:{param.data}")
        # 每隔10次显示一次损失函数
        print(f"epoch:{n},loss:{avg_loss}")
        print("-----------------------------------")

# --------------------------start-----------------------------
# 开始保存
torch.save(
    model.state_dict(),  # 保存什么内容:模型字典表示方式1
    'model.pth'  # 保存文件的名称
)

torch.save(
    model,  # 保存什么内容:整个模型表示方式2
    'entire_model.pth'  # 保存文件的名称
)

4. 加载模型

4.1 方式1:加载模型参数(对应保存方式1)

步骤:

  • 步骤1:复现模型对象
  • 步骤2:使用torch.load("model.pth")加载模型参数
  • 步骤3:使用model.load_state_dict(torch.load("model.pth"))将model和参数结合起来。
import torch
import torch.nn as nn


# 1. 复现模型对象
class LinearModel(nn.Module):
    def __init__(self):
        super(LinearModel, self).__init__()
        self.layer1 = nn.Linear(1, 1)

    def forward(self, x):
        x = self.layer1(x)
        return x


# 创建模型对象
model = LinearModel()

# 2. 先把模型的参数读出来
model_dict = torch.load('model.pth',
                        weights_only=True)  # 有这个参数可以提升安全性
# 3. 再把参数给模型
model.load_state_dict(model_dict)

# 让模型进入评估模式
model.eval()

# 使用之前训练500的结果对数据进行预测
x_test = torch.tensor(
    [[-0.5], [2.5], [1.25]],
    dtype=torch.float32
)

# 开始预测
with torch.no_grad():  # 评估模式下不需要再计算梯度了,可以提升预测速度
    y_prd = model(x_test)
    print(y_prd)
    for name, param in model.named_parameters():
        # 如有,取出当前计算的梯度
        if param.grad is not None:
            print(f"梯度:{name}:{param.grad}")
        # 如有,取出当前计算的w和b
        if param.data is not None:
            print(f"w和b的值:{param.data}")

4.2 方式2:加载整个模型(对应保存方式2)

步骤:

  • 步骤1:需要模型结构
  • 步骤2:使用torch.load("entire_model.pth")加载模型
import torch
import torch.nn as nn


# 1. 复现模型对象
class LinearModel(nn.Module):
    def __init__(self):
        super(LinearModel, self).__init__()
        self.layer1 = nn.Linear(1, 1)

    def forward(self, x):
        x = self.layer1(x)
        return x


# # 创建模型对象
# model = LinearModel() 不需要手动创建模型

# 2. 直接从文件读取模型
model = torch.load('entire_model.pth')  # 这种模式下不支持weights_only参数

# 让模型进入评估模式
model.eval()

# 使用之前训练500的结果对数据进行预测
x_test = torch.tensor(
    [[-0.5], [2.5], [1.25]],
    dtype=torch.float32
)

# 开始预测
with torch.no_grad():  # 评估模式下不需要再计算梯度了,可以提升预测速度
    y_prd = model(x_test)
    print(y_prd)
    for name, param in model.named_parameters():
        # 如有,取出当前计算的梯度
        if param.grad is not None:
            print(f"梯度:{name}:{param.grad}")
        # 如有,取出当前计算的w和b
        if param.data is not None:
            print(f"w和b的值:{param.data}")

5. 查看网络结构

5.1 方法1:print

print(model) 仅能打印出网络结构,不能检测模型搭建是否正确。

import torch
import torch.nn as nn


# 1. 复现模型对象
class LinearModel(nn.Module):
    def __init__(self):
        super(LinearModel, self).__init__()
        self.layer1 = nn.Linear(1, 1)
        self.layer2 = nn.Linear(2, 1)  # 第二个网络层是两个输入

    def forward(self, x):
        x = self.layer1(x)
        x = self.layer2(x)  # 错误:只给了一个输入
        return x


# 创建模型对象
model = LinearModel()

# 打印网络结构
print(model)

5.2 方法2:summary

torchsummary 主要用于查看模型结构,如果模型搭建错误会报错。

是单独的库,

python -m pip install torchsummary -i https://pypi.tuna.tsinghua.edu.cn/simple

import torch
import torch.nn as nn


# 1. 复现模型对象
class LinearModel(nn.Module):
    def __init__(self):
        super(LinearModel, self).__init__()
        self.layer1 = nn.Linear(1, 1)
        # self.layer2 = nn.Linear(2, 1)  # 第二个网络层是两个输入

    def forward(self, x):
        x = self.layer1(x)
        # x = self.layer2(x)  # 错误:只给了一个输入
        return x


# 创建模型对象
model = LinearModel()

# 导入summary
from torchsummary import summary

# 如果模型搭建错误,报错
summary(
    model,  # 模型
    input_size=(1,),  # 整个模型的输入
    device="cpu"  # 如果是cpu训练的,一定要写上cpu
)

5.3 方法:netron

直接启动

5.3.1 直接打开pth

缺点是无连线。

import torch
import numpy as np

# 2.定义前向模型
import torch.nn as nn


# 方案4:
class LinearModel(nn.Module):
    def __init__(self):
        super(LinearModel, self).__init__()
        self.layer1 = nn.Linear(1, 1)
        # ----------------本节开始-------------------
        # 【给第二个线性层】
        self.layer2 = nn.Linear(1, 1)

    def forward(self, x):
        x = self.layer1(x)
        # 【连接两个线性层】
        x = self.layer2(x)
        return x


model = LinearModel()

# 保存模型
torch.save(model,"netron_model.pth")

5.3.2 转换脚本以后保存

使用 torch.jit.script 先将模型转换为JIT脚本,再使用 torch.jit.save 保存模型;

什么是 JIT?

首先要知道 JIT 是一种概念,全称是 Just In Time Compilation,中文译为「即时编译」,是一种程序优化的方法。

import torch
import numpy as np

# 2.定义前向模型
import torch.nn as nn


# 方案4:
class LinearModel(nn.Module):
    def __init__(self):
        super(LinearModel, self).__init__()
        self.layer1 = nn.Linear(1, 1)
        # ----------------本节开始-------------------
        # 【给第二个线性层】
        self.layer2 = nn.Linear(1, 1)

    def forward(self, x):
        x = self.layer1(x)
        # 【连接两个线性层】
        x = self.layer2(x)
        return x


model = LinearModel()

# 【转换模型脚本】
script_model = torch.jit.script(model)
# 保存模型脚本
torch.jit.save(script_model, 'script_model.pth')
使用netron打开script_model.pth就可以看到连线了。

5.3.3 转换为ONNX保存

ONNX(Open Neural Network Exchange)是一个开放的深度学习模型交换格式,它允许在不同的深度学习框架之间共享、迁移和使用模型。ONNX的目标是提供一个通用的中间表示,使得各种深度学习框架(如PyTorch、TensorFlow、MXNet等)之间能够更轻松地交换模型,并且能够在不同框架之间进行模型的部署和推理。

安装:

python -m pip install onnx -i https://pypi.tuna.tsinghua.edu.cn/simple
import torch
import numpy as np

# 2.定义前向模型
import torch.nn as nn


# 方案4:
class LinearModel(nn.Module):
    def __init__(self):
        super(LinearModel, self).__init__()
        self.layer1 = nn.Linear(1, 1)
        # ----------------本节开始-------------------
        # 【给第二个线性层】
        self.layer2 = nn.Linear(1, 1)

    def forward(self, x):
        x = self.layer1(x)
        # 【连接两个线性层】
        x = self.layer2(x)
        return x


model = LinearModel()

# 【使用ONNX导出】
torch.onnx.export(
    model,  # 模型
    torch.rand(1, 1),  # 需要随机生成一个数据作为模型输入,第一个1表示batch_size,第二个1表示1维张量
    "model.onnx"  # 保存的文件名
)

5.4 方法4:TensorboardX

5.4.1 使用步骤

TensorboardX 这个工具使得 pytorch 框架也可以使用到 Tensorboard 的便捷功能,tensorboardX 可以记录和可视化模型训练过程中的指标以及模型结构。

如果没有安装,则手动安装:

python -m pip install TensorboardX -i https://pypi.tuna.tsinghua.edu.cn/simple
安装完成后可能会出现问题,出现各种问题留意错误信息。
import torch
import numpy as np

# 2.定义前向模型
import torch.nn as nn


# 方案4:
class LinearModel(nn.Module):
    def __init__(self):
        super(LinearModel, self).__init__()
        self.layer1 = nn.Linear(1, 1)
        self.layer2 = nn.Linear(1, 1)

    def forward(self, x):
        x = self.layer1(x)
        x = self.layer2(x)
        return x


model = LinearModel()

# 【导出TensorBoardX的logs(日志)】
from tensorboardX import SummaryWriter

# 创建一个日志文件夹存储日志
writer = SummaryWriter(log_dir='logs')
# 将模型结构(计算图)添加到SummaryWriter对象中
writer.add_graph(
    model,  # 模型
    torch.rand(1)  # 给一个随机的一维张量
)
writer.close()  # 关闭

使用TensorBoardX加载日志的操作步骤如下:

1. 打环境终端,定位到项目路径下(logs所在的文件夹)。

2. 执行命令

"D:\HQYJ\FS_AISIMS\tools\Python\python.exe" "D:\HQYJ\FS_AISIMS\tools\Python\Scripts\tensorboard.exe" --logdir=logs

上面的命令分为三部分:

  • Python使用的解释器

"D:\HQYJ\FS_AISIMS\tools\Python\python.exe"

  • TensorBoard执行文件

"D:\HQYJ\FS_AISIMS\tools\Python\Scripts\tensorboard.exe"

  • 日志文件夹名称

--logdir=logs

根据自己的电脑修改命令并执行。

3. 成功运行后,提示在浏览器中打开下面的地址:

5.4.2 问题解决

1. protobuf版本不匹配

主要是受到ONNX的影响,两边都用这个库,但版本不一样。因此需要重新设置protobuf的版本为最高3.20.x。

python -m pip uninstall protobuf
python -m pip install protobuf==3.20.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
2. tensorboard库缺失

只需要安装tensorboard库即可。

python -m pip install tensorboard -i https://pypi.tuna.tsinghua.edu.cn/simple
3. C盘权限问题

建议项目不要放在C盘下,访问权限较高。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值