【机器学习】使用pytorch框架实现逻辑回归并保存模型,然后保存模型后再加载模型进行预测

一、使用pytorch框架实现逻辑回归

1. 数据部分

  • 首先自定义了一个简单的数据集,特征 X 是 100 个随机样本,每个样本一个特征,目标值 y 基于线性关系并添加了噪声。
  • numpy 数组转换为 PyTorch 张量,方便后续在模型中使用。

2. 模型定义部分

方案 1 :使用 nn.Sequential 直接按顺序定义了一个线性层,简洁直观。

python 复制代码
import torch
import torch.nn as nn
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score

# 自定义数据集
X = np.random.rand(100, 1).astype(np.float32)
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)

# 转换为 PyTorch 张量
X_tensor = torch.from_numpy(X)
y_tensor = torch.from_numpy(y)

# 定义线性回归模型
model = nn.Sequential(
    nn.Linear(1, 1)
)

# 定义损失函数和优化器
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

# 训练模型
num_epochs = 1000
for epoch in range(num_epochs):
    # 前向传播
    outputs = model(X_tensor)
    loss = criterion(outputs, y_tensor)

    # 反向传播和优化
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if (epoch + 1) % 100 == 0:
        print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')

# 模型评估
with torch.no_grad():
    y_pred = model(X_tensor).numpy()

mse = mean_squared_error(y, y_pred)
r2 = r2_score(y, y_pred)
print(f"均方误差 (MSE): {mse}")
print(f"决定系数 (R²): {r2}")

# 输出模型的系数和截距
print("模型系数:", model[0].weight.item())
print("模型截距:", model[0].bias.item())

方案 2 :使用 nn.ModuleList 存储线性层,在 forward 方法中依次调用层进行前向传播,适合动态构建层序列。

python 复制代码
import torch
import torch.nn as nn
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score

# 自定义数据集
X = np.random.rand(100, 1).astype(np.float32)
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)

# 转换为 PyTorch 张量
X_tensor = torch.from_numpy(X)
y_tensor = torch.from_numpy(y)

# 定义线性回归模型
class LinearRegression(nn.Module):
    def __init__(self):
        super(LinearRegression, self).__init__()
        self.layers = nn.ModuleList([
            nn.Linear(1, 1)
        ])

    def forward(self, x):
        for layer in self.layers:
            x = layer(x)
        return x

model = LinearRegression()

# 定义损失函数和优化器
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

# 训练模型
num_epochs = 1000
for epoch in range(num_epochs):
    # 前向传播
    outputs = model(X_tensor)
    loss = criterion(outputs, y_tensor)

    # 反向传播和优化
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if (epoch + 1) % 100 == 0:
        print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')

# 模型评估
with torch.no_grad():
    y_pred = model(X_tensor).numpy()

mse = mean_squared_error(y, y_pred)
r2 = r2_score(y, y_pred)
print(f"均方误差 (MSE): {mse}")
print(f"决定系数 (R²): {r2}")

# 输出模型的系数和截距
print("模型系数:", model.layers[0].weight.item())
print("模型截距:", model.layers[0].bias.item())

方案 3 :使用 nn.ModuleDict 以字典形式存储层,通过键名调用层,适合需要对层进行命名和灵活访问的场景。

python 复制代码
import torch
import torch.nn as nn
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score

# 自定义数据集
X = np.random.rand(100, 1).astype(np.float32)
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)

# 转换为 PyTorch 张量
X_tensor = torch.from_numpy(X)
y_tensor = torch.from_numpy(y)

# 定义线性回归模型
class LinearRegression(nn.Module):
    def __init__(self):
        super(LinearRegression, self).__init__()
        self.layers = nn.ModuleDict({
            'linear': nn.Linear(1, 1)
        })

    def forward(self, x):
        x = self.layers['linear'](x)
        return x

model = LinearRegression()

# 定义损失函数和优化器
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

# 训练模型
num_epochs = 1000
for epoch in range(num_epochs):
    # 前向传播
    outputs = model(X_tensor)
    loss = criterion(outputs, y_tensor)

    # 反向传播和优化
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if (epoch + 1) % 100 == 0:
        print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')

# 模型评估
with torch.no_grad():
    y_pred = model(X_tensor).numpy()

mse = mean_squared_error(y, y_pred)
r2 = r2_score(y, y_pred)
print(f"均方误差 (MSE): {mse}")
print(f"决定系数 (R²): {r2}")

# 输出模型的系数和截距
print("模型系数:", model.layers['linear'].weight.item())
print("模型截距:", model.layers['linear'].bias.item())

方案 4 :直接继承 nn.Module,在 __init__ 方法中定义线性层,在 forward 方法中实现前向传播逻辑,是最常见和基础的定义模型方式。

python 复制代码
import torch
import torch.nn as nn
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score

# 自定义数据集
X = np.random.rand(100, 1).astype(np.float32)
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)

# 转换为 PyTorch 张量
X_tensor = torch.from_numpy(X)
y_tensor = torch.from_numpy(y)

# 定义线性回归模型
class LinearRegression(nn.Module):
    def __init__(self):
        super(LinearRegression, self).__init__()
        self.linear = nn.Linear(1, 1)

    def forward(self, x):
        return self.linear(x)

model = LinearRegression()

# 定义损失函数和优化器
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

# 训练模型
num_epochs = 1000
for epoch in range(num_epochs):
    # 前向传播
    outputs = model(X_tensor)
    loss = criterion(outputs, y_tensor)

    # 反向传播和优化
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if (epoch + 1) % 100 == 0:
        print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')

# 模型评估
with torch.no_grad():
    y_pred = model(X_tensor).numpy()

mse = mean_squared_error(y, y_pred)
r2 = r2_score(y, y_pred)
print(f"均方误差 (MSE): {mse}")
print(f"决定系数 (R²): {r2}")

# 输出模型的系数和截距
print("模型系数:", model.linear.weight.item())
print("模型截距:", model.linear.bias.item())

3. 训练和评估部分

  • 定义了均方误差损失函数 nn.MSELoss 和随机梯度下降优化器 torch.optim.SGD
  • 通过多个 epoch 进行训练,每个 epoch 包含前向传播、损失计算、反向传播和参数更新。
  • 训练结束后,在无梯度计算模式下进行预测,并使用 scikit-learn 的指标计算均方误差和决定系数评估模型性能,最后输出模型的系数和截距。

二、保存pytorch框架逻辑回归模型

在 PyTorch 中,有两种常见的保存模型的方式:保存模型的权重和其他参数,以及保存整个模型。下面将结合一个简单的逻辑回归模型示例,详细介绍这两种保存方式及对应的加载方法。

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

这种方式只保存模型的状态字典(state_dict),它包含了模型的所有可学习参数(如权重和偏置)。这种方法的优点是文件体积小,便于共享和迁移,缺点是加载时需要先定义模型结构。

python 复制代码
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np

# 自定义数据集
X = np.random.randn(100, 2).astype(np.float32)
y = (2 * X[:, 0] + 3 * X[:, 1] > 0).astype(np.float32).reshape(-1, 1)

X_tensor = torch.from_numpy(X)
y_tensor = torch.from_numpy(y)

# 定义逻辑回归模型
class LogisticRegression(nn.Module):
    def __init__(self, input_size):
        super(LogisticRegression, self).__init__()
        self.linear = nn.Linear(input_size, 1)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        out = self.linear(x)
        out = self.sigmoid(out)
        return out

# 初始化模型
input_size = 2
model = LogisticRegression(input_size)

# 定义损失函数和优化器
criterion = nn.BCELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)

# 训练模型
num_epochs = 1000
for epoch in range(num_epochs):
    outputs = model(X_tensor)
    loss = criterion(outputs, y_tensor)

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if (epoch + 1) % 100 == 0:
        print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')

# 保存模型的权重和其他参数
torch.save(model.state_dict(), 'model_weights.pth')

# 加载模型的权重和其他参数
loaded_model = LogisticRegression(input_size)
loaded_model.load_state_dict(torch.load('model_weights.pth'))
loaded_model.eval()

# 生成新数据进行预测
new_X = np.random.randn(10, 2).astype(np.float32)
new_X_tensor = torch.from_numpy(new_X)

with torch.no_grad():
    predictions = loaded_model(new_X_tensor)
    predicted_labels = (predictions >= 0.5).float()

print("预测概率:")
print(predictions.numpy())
print("预测标签:")
print(predicted_labels.numpy())

代码解释

  1. 模型训练:首先定义并训练一个逻辑回归模型。
  2. 保存模型 :使用 torch.save(model.state_dict(), 'model_weights.pth') 保存模型的状态字典到文件 model_weights.pth
  3. 加载模型 :先创建一个新的模型实例 loaded_model,然后使用 loaded_model.load_state_dict(torch.load('model_weights.pth')) 加载保存的状态字典。
  4. 预测:将模型设置为评估模式,生成新数据进行预测。

方式 2:保存整个模型

这种方式会保存整个模型对象,包括模型的结构和状态字典。优点是加载时不需要重新定义模型结构,缺点是文件体积较大,并且可能会受到 Python 版本和库版本的限制。

python 复制代码
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np

# 自定义数据集
X = np.random.randn(100, 2).astype(np.float32)
y = (2 * X[:, 0] + 3 * X[:, 1] > 0).astype(np.float32).reshape(-1, 1)

X_tensor = torch.from_numpy(X)
y_tensor = torch.from_numpy(y)

# 定义逻辑回归模型
class LogisticRegression(nn.Module):
    def __init__(self, input_size):
        super(LogisticRegression, self).__init__()
        self.linear = nn.Linear(input_size, 1)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        out = self.linear(x)
        out = self.sigmoid(out)
        return out

# 初始化模型
input_size = 2
model = LogisticRegression(input_size)

# 定义损失函数和优化器
criterion = nn.BCELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)

# 训练模型
num_epochs = 1000
for epoch in range(num_epochs):
    outputs = model(X_tensor)
    loss = criterion(outputs, y_tensor)

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if (epoch + 1) % 100 == 0:
        print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')

# 保存整个模型
torch.save(model, 'whole_model.pth')

# 加载整个模型
loaded_model = torch.load('whole_model.pth')
loaded_model.eval()

# 生成新数据进行预测
new_X = np.random.randn(10, 2).astype(np.float32)
new_X_tensor = torch.from_numpy(new_X)

with torch.no_grad():
    predictions = loaded_model(new_X_tensor)
    predicted_labels = (predictions >= 0.5).float()

print("预测概率:")
print(predictions.numpy())
print("预测标签:")
print(predicted_labels.numpy())

代码解释

  1. 模型训练:同样先定义并训练逻辑回归模型。
  2. 保存模型 :使用 torch.save(model, 'whole_model.pth') 保存整个模型对象到文件 whole_model.pth
  3. 加载模型 :使用 torch.load('whole_model.pth') 直接加载整个模型。
  4. 预测:将模型设置为评估模式,生成新数据进行预测。

通过以上两种方式,可以根据实际需求选择合适的模型保存和加载方法。

三、加载pytorch框架逻辑回归模型

以下将分别详细介绍在 PyTorch 中针对只保存模型参数和保存结构与参数这两种不同保存方式对应的模型加载方法,同时给出完整的代码示例。

方式 1:只保存模型参数的加载方式

当用户只保存了模型的参数(即 state_dict)时,在加载模型时需要先定义好与原模型相同结构的模型,再将保存的参数加载到该模型中。

python 复制代码
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np

# 自定义数据集
X = np.random.randn(100, 2).astype(np.float32)
y = (2 * X[:, 0] + 3 * X[:, 1] > 0).astype(np.float32).reshape(-1, 1)

X_tensor = torch.from_numpy(X)
y_tensor = torch.from_numpy(y)

# 定义逻辑回归模型
class LogisticRegression(nn.Module):
    def __init__(self, input_size):
        super(LogisticRegression, self).__init__()
        self.linear = nn.Linear(input_size, 1)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        out = self.linear(x)
        out = self.sigmoid(out)
        return out

# 初始化模型
input_size = 2
model = LogisticRegression(input_size)

# 定义损失函数和优化器
criterion = nn.BCELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)

# 训练模型
num_epochs = 1000
for epoch in range(num_epochs):
    outputs = model(X_tensor)
    loss = criterion(outputs, y_tensor)

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if (epoch + 1) % 100 == 0:
        print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')

# 保存模型的参数
torch.save(model.state_dict(), 'model_params.pth')

# 加载模型的参数
# 重新定义模型结构
loaded_model = LogisticRegression(input_size)
# 加载保存的参数
loaded_model.load_state_dict(torch.load('model_params.pth'))
# 将模型设置为评估模式
loaded_model.eval()

# 生成新数据进行预测
new_X = np.random.randn(10, 2).astype(np.float32)
new_X_tensor = torch.from_numpy(new_X)

# 进行预测
with torch.no_grad():
    predictions = loaded_model(new_X_tensor)
    predicted_labels = (predictions >= 0.5).float()

print("预测概率:")
print(predictions.numpy())
print("预测标签:")
print(predicted_labels.numpy())

代码解释

  1. 模型定义与训练:定义了一个简单的逻辑回归模型,并使用自定义数据集进行训练。
  2. 保存参数 :使用 torch.save(model.state_dict(), 'model_params.pth') 保存模型的参数。
  3. 加载参数
    • 重新定义与原模型相同结构的 loaded_model
    • 使用 loaded_model.load_state_dict(torch.load('model_params.pth')) 加载保存的参数。
  4. 预测:将模型设置为评估模式,生成新数据进行预测。

方式 2:保存结构和参数的模型加载方式

当保存了模型的结构和参数时,加载模型就相对简单,直接使用 torch.load 函数即可加载整个模型。

python 复制代码
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np

# 自定义数据集
X = np.random.randn(100, 2).astype(np.float32)
y = (2 * X[:, 0] + 3 * X[:, 1] > 0).astype(np.float32).reshape(-1, 1)

X_tensor = torch.from_numpy(X)
y_tensor = torch.from_numpy(y)

# 定义逻辑回归模型
class LogisticRegression(nn.Module):
    def __init__(self, input_size):
        super(LogisticRegression, self).__init__()
        self.linear = nn.Linear(input_size, 1)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        out = self.linear(x)
        out = self.sigmoid(out)
        return out

# 初始化模型
input_size = 2
model = LogisticRegression(input_size)

# 定义损失函数和优化器
criterion = nn.BCELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)

# 训练模型
num_epochs = 1000
for epoch in range(num_epochs):
    outputs = model(X_tensor)
    loss = criterion(outputs, y_tensor)

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if (epoch + 1) % 100 == 0:
        print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')

# 保存整个模型(结构和参数)
torch.save(model, 'whole_model.pth')

# 加载整个模型
loaded_model = torch.load('whole_model.pth')
# 将模型设置为评估模式
loaded_model.eval()

# 生成新数据进行预测
new_X = np.random.randn(10, 2).astype(np.float32)
new_X_tensor = torch.from_numpy(new_X)

# 进行预测
with torch.no_grad():
    predictions = loaded_model(new_X_tensor)
    predicted_labels = (predictions >= 0.5).float()

print("预测概率:")
print(predictions.numpy())
print("预测标签:")
print(predicted_labels.numpy())

代码解释

  1. 模型定义与训练:同样定义并训练逻辑回归模型。
  2. 保存整个模型 :使用 torch.save(model, 'whole_model.pth') 保存模型的结构和参数。
  3. 加载整个模型 :使用 torch.load('whole_model.pth') 直接加载整个模型。
  4. 预测:将模型设置为评估模式,生成新数据进行预测。

通过以上两种方式,可以根据不同的保存情况正确加载 PyTorch 模型。

四、完整流程(使用直接继承 nn.Module逻辑回归,且仅保存模型的权重和其他参数)

1. 实现思路

① 自定义数据集

生成符合特定分布的特征矩阵和对应的标签向量。

② 构建逻辑回归模型

定义一个简单的逻辑回归模型,这里使用直接继承 nn.Module逻辑回归。

③ 训练模型

使用生成的数据集对模型进行训练。

④ 保存模型

将训练好的模型保存到本地文件,这里仅保存模型的权重和其他参数。

⑤ 加载模型

从本地文件中加载保存的模型。

⑥ 模型预测

使用加载的模型对新数据进行预测。

2. 代码示例

python 复制代码
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np

# 自定义数据集
# 生成 100 个样本,每个样本有 2 个特征
X = np.random.randn(100, 2).astype(np.float32)
# 根据特征生成标签,使用简单的线性组合和阈值判断
y = (2 * X[:, 0] + 3 * X[:, 1] > 0).astype(np.float32).reshape(-1, 1)

# 将 numpy 数组转换为 PyTorch 张量
X_tensor = torch.from_numpy(X)
y_tensor = torch.from_numpy(y)

# 定义逻辑回归模型
class LogisticRegression(nn.Module):
    def __init__(self, input_size):
        super(LogisticRegression, self).__init__()
        self.linear = nn.Linear(input_size, 1)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        out = self.linear(x)
        out = self.sigmoid(out)
        return out

# 初始化模型
input_size = 2
model = LogisticRegression(input_size)

# 定义损失函数和优化器
criterion = nn.BCELoss()  # 二元交叉熵损失函数
optimizer = optim.SGD(model.parameters(), lr=0.01)

# 训练模型
num_epochs = 1000
for epoch in range(num_epochs):
    # 前向传播
    outputs = model(X_tensor)
    loss = criterion(outputs, y_tensor)

    # 反向传播和优化
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if (epoch + 1) % 100 == 0:
        print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')

# 保存模型
torch.save(model.state_dict(), 'logistic_regression_model.pth')

# 加载模型
loaded_model = LogisticRegression(input_size)
loaded_model.load_state_dict(torch.load('logistic_regression_model.pth'))
loaded_model.eval()

# 生成新数据进行预测
new_X = np.random.randn(10, 2).astype(np.float32)
new_X_tensor = torch.from_numpy(new_X)

# 使用加载的模型进行预测
with torch.no_grad():
    predictions = loaded_model(new_X_tensor)
    predicted_labels = (predictions >= 0.5).float()

print("预测概率:")
print(predictions.numpy())
print("预测标签:")
print(predicted_labels.numpy())

3. 代码解释

① 数据集生成

  • X = np.random.randn(100, 2).astype(np.float32):生成 100 个样本,每个样本有 2 个特征。
  • y = (2 * X[:, 0] + 3 * X[:, 1] > 0).astype(np.float32).reshape(-1, 1):根据特征的线性组合生成标签,大于 0 标记为 1,否则标记为 0。
  • X_tensor = torch.from_numpy(X)y_tensor = torch.from_numpy(y):将 numpy 数组转换为 PyTorch 张量。

② 模型定义

  • LogisticRegression 类继承自 nn.Module,包含一个线性层 nn.Linear 和一个 Sigmoid 激活函数 nn.Sigmoid
  • forward 方法定义了前向传播的逻辑。

③ 损失函数和优化器

  • criterion = nn.BCELoss():使用二元交叉熵损失函数,适用于二分类问题。
  • optimizer = optim.SGD(model.parameters(), lr=0.01):使用随机梯度下降优化器,学习率为 0.01。

④ 模型训练

  • 通过多次迭代进行前向传播、损失计算、反向传播和参数更新。
  • 每 100 个 epoch 打印一次损失值。

⑤模型保存

  • torch.save(model.state_dict(), 'logistic_regression_model.pth'):保存模型的参数到本地文件 logistic_regression_model.pth

⑥ 模型加载和预测

  1. loaded_model = LogisticRegression(input_size):创建一个新的模型实例。
  2. loaded_model.load_state_dict(torch.load('logistic_regression_model.pth')):加载保存的模型参数。
  3. loaded_model.eval():将模型设置为评估模式。
  4. 生成新数据 new_X 并转换为张量 new_X_tensor
  5. 使用 loaded_model 进行预测,通过 (predictions >= 0.5).float() 将预测概率转换为标签。
相关推荐
Erik_LinX7 分钟前
day1-->day7| 机器学习(吴恩达)学习笔记
笔记·学习·机器学习
查理零世43 分钟前
保姆级讲解 python之zip()方法实现矩阵行列转置
python·算法·矩阵
刀客1231 小时前
python3+TensorFlow 2.x(四)反向传播
人工智能·python·tensorflow
时间很奇妙!1 小时前
decison tree 决策树
算法·决策树·机器学习
liruiqiang051 小时前
机器学习 - 初学者需要弄懂的一些线性代数的概念
人工智能·线性代数·机器学习·线性回归
Icomi_1 小时前
【外文原版书阅读】《机器学习前置知识》1.线性代数的重要性,初识向量以及向量加法
c语言·c++·人工智能·深度学习·神经网络·机器学习·计算机视觉
sysu632 小时前
95.不同的二叉搜索树Ⅱ python
开发语言·数据结构·python·算法·leetcode·面试·深度优先
羊小猪~~2 小时前
深度学习项目--基于LSTM的糖尿病预测探究(pytorch实现)
人工智能·pytorch·rnn·深度学习·神经网络·机器学习·lstm
SsummerC2 小时前
【leetcode100】从前序与中序遍历序列构造二叉树
python·算法·leetcode
东来梁蕴秀2 小时前
大语言模型之prompt工程
人工智能·机器学习