【机器学习】自定义数据集 使用pytorch框架实现逻辑回归并保存模型,然后保存模型后再加载模型进行预测,对预测结果计算精确度和召回率及F1分数

news2025/2/3 2:15:38

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

1. 数据部分

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

2. 模型定义部分

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

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 方法中依次调用层进行前向传播,适合动态构建层序列。

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 以字典形式存储层,通过键名调用层,适合需要对层进行命名和灵活访问的场景。

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 方法中实现前向传播逻辑,是最常见和基础的定义模型方式。

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),它包含了模型的所有可学习参数(如权重和偏置)。这种方法的优点是文件体积小,便于共享和迁移,缺点是加载时需要先定义模型结构。

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 版本和库版本的限制。

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)时,在加载模型时需要先定义好与原模型相同结构的模型,再将保存的参数加载到该模型中。

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 函数即可加载整个模型。

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 模型。

五、计算pytorch模型预测结果的精确度

在机器学习任务中,计算预测结果的精确度(Accuracy)是评估模型性能的重要指标。对于回归任务,通常使用均方误差(MSE)平均绝对误差(MAE)R² 分数 来评估模型的性能;而对于分类任务,则使用准确率(Accuracy)精确率(Precision)召回率(Recall) 等指标。

以下是如何在 PyTorch 中计算预测结果的精确度(以回归任务为例):

1. 分类任务的精确度计算

对于分类任务,常用的评估指标是准确率(Accuracy),即预测正确的样本数占总样本数的比例。

代码实现

import torch

# 假设有真实标签和预测标签
y_true = torch.tensor([0, 1, 1, 0, 1, 0, 0, 1])  # 真实标签
y_pred = torch.tensor([0, 1, 0, 0, 1, 0, 1, 1])  # 预测标签

# 计算准确率
accuracy = (y_true == y_pred).float().mean()
print(f"准确率: {accuracy.item():.4f}")

 2. 回归任务的精确度计算

对于回归任务,常用的评估指标包括:

  • 均方误差(MSE):预测值与真实值之间差异的平方的平均值。

  • 平均绝对误差(MAE):预测值与真实值之间差异的绝对值的平均值。

  • R² 分数:表示模型对数据的拟合程度,取值范围为 [0, 1],越接近 1 表示模型越好。

代码实现

import torch
import torch.nn as nn

# 假设有真实值和预测值
y_true = torch.tensor([3.0, 5.0, 7.0, 9.0], dtype=torch.float32)
y_pred = torch.tensor([2.8, 5.1, 7.2, 8.9], dtype=torch.float32)

# 计算均方误差 (MSE)
mse = nn.MSELoss()(y_pred, y_true)
print(f"Mean Squared Error (MSE): {mse.item():.4f}")

# 计算平均绝对误差 (MAE)
mae = nn.L1Loss()(y_pred, y_true)
print(f"Mean Absolute Error (MAE): {mae.item():.4f}")

# 计算 R² 分数
def r2_score(y_true, y_pred):
    ss_total = torch.sum((y_true - torch.mean(y_true)) ** 2)
    ss_residual = torch.sum((y_true - y_pred) ** 2)
    r2 = 1 - (ss_residual / ss_total)
    return r2

r2 = r2_score(y_true, y_pred)
print(f"R²分数: {r2.item():.4f}")

六、计算pytorch模型预测结果的召回率

1. 召回率的定义

在分类任务中,召回率(Recall) 是一个重要的评估指标,用于衡量模型对正类样本的识别能力。召回率的定义是:

Recall= \frac{True Positives (TP)}{True Positives (TP)+False Negatives (FN)}

其中:

  • True Positives (TP):模型正确预测为正类的样本数。

  • False Negatives (FN):模型错误预测为负类的正类样本数。

2. 计算召回率的步骤

  1. 获取真实标签和预测标签

  • 真实标签(y_true):数据集中样本的真实类别。
  • 预测标签(y_pred):模型对样本的预测类别。
  1. 计算混淆矩阵

  • 通过比较 y_true 和 y_pred,计算混淆矩阵中的 TP 和 FN。
  1. 计算召回率

        使用公式 Recall= \frac{TP}{TP+FN} 计算召回率。

3. 二分类任务召回率代码

  • 对于二分类任务,召回率衡量模型对正类样本的识别能力。

import torch

# 假设有真实标签和预测标签
y_true = torch.tensor([0, 1, 1, 0, 1, 0, 0, 1])  # 真实标签
y_pred = torch.tensor([0, 1, 0, 0, 1, 0, 1, 1])  # 预测标签

# 计算混淆矩阵
def confusion_matrix(y_true, y_pred):
    TP = ((y_true == 1) & (y_pred == 1)).sum().item()  # 模型正确预测为正类的样本数
    FN = ((y_true == 1) & (y_pred == 0)).sum().item()  # 模型错误预测为负类的正类样本数
    FP = ((y_true == 0) & (y_pred == 1)).sum().item()  # 模型错误预测为正类的正类样本数
    TN = ((y_true == 0) & (y_pred == 0)).sum().item()  # 模型正确预测为负类的样本数
    return TP, FN, FP, TN

# 计算召回率
def recall_score(y_true, y_pred):
    TP, FN, _, _ = confusion_matrix(y_true, y_pred)
    if TP + FN == 0:
        return 0.0  # 避免除以零
    return TP / (TP + FN)

# 计算召回率
recall = recall_score(y_true, y_pred)
print(f"召回率: {recall:.4f}")

 4. 多分类任务召回率代码

  • 对于多分类任务,可以分别计算每个类别的召回率,然后取平均值。

import torch

# 假设有真实标签和预测标签(多分类任务)
y_true = torch.tensor([0, 1, 2, 0, 1, 2])  # 真实标签
y_pred = torch.tensor([0, 1, 0, 0, 1, 2])  # 预测标签

# 计算每个类别的召回率
def recall_score_multiclass(y_true, y_pred, num_classes):
    recall_scores = []
    for cls in range(num_classes):
        TP = ((y_true == cls) & (y_pred == cls)).sum().item()  # 模型正确预测为正类的样本数
        FN = ((y_true == cls) & (y_pred != cls)).sum().item()  # 模型错误预测为负类的正类样本数
        if TP + FN == 0:
            recall_scores.append(0.0)  # 避免除以零
        else:
            recall_scores.append(TP / (TP + FN))
    return recall_scores

# 计算召回率
num_classes = 3
recall_scores = recall_score_multiclass(y_true, y_pred, num_classes)
for cls, recall in enumerate(recall_scores):
    print(f"每个类别的召回率 {cls}: {recall:.4f}")

# 计算宏平均召回率
macro_recall = sum(recall_scores) / num_classes
print(f"宏平均召回率: {macro_recall:.4f}")

七、计算pytorch模型预测结果的F1分数

1. F1分数的定义

F1 分数(F1 Score) 是分类任务中常用的评估指标,结合了 精确率(Precision) 和 召回率(Recall) 的信息。F1 分数的定义是:

F1 Score= 2\times \frac{Precision\times ×Recall}{Precision+Recall}

其中:

  • 精确率(Precision):预测为正类的样本中,实际为正类的比例。

  • 召回率(Recall):实际为正类的样本中,预测为正类的比例。

F1 分数的取值范围为 [0, 1],越接近 1 表示模型性能越好。

2. 计算 F1 分数的步骤

  1. 获取真实标签和预测标签

  • 真实标签(y_true):数据集中样本的真实类别。
  • 预测标签(y_pred):模型对样本的预测类别。
  1. 计算混淆矩阵

  • 通过比较 y_true 和 y_pred,计算混淆矩阵中的 TP、FP 和 FN。
  1. 计算精确率和召回率

  • 精确率:

Precision=\frac{TP}{TP+FP}

  • 召回率:

Recall=\frac{TP}{TP+FN}

  1. 计算 F1 分数

  • 使用公式:

F1 Score= 2\times \frac{Precision\times ×Recall}{Precision+Recall}

3. 二分类任务F1分数代码

  • 对于二分类任务,F1 分数结合了精确率和召回率,是评估模型性能的重要指标。

import torch

# 假设有真实标签和预测标签
y_true = torch.tensor([0, 1, 1, 0, 1, 0, 0, 1])  # 真实标签
y_pred = torch.tensor([0, 1, 0, 0, 1, 0, 1, 1])  # 预测标签

# 计算混淆矩阵
def confusion_matrix(y_true, y_pred):
    TP = ((y_true == 1) & (y_pred == 1)).sum().item()  # 模型正确预测为正类的样本数
    FN = ((y_true == 1) & (y_pred == 0)).sum().item()  # 模型错误预测为负类的正类样本数
    FP = ((y_true == 0) & (y_pred == 1)).sum().item()  # 模型错误预测为正类的正类样本数
    TN = ((y_true == 0) & (y_pred == 0)).sum().item()  # 模型正确预测为负类的样本数
    return TP, FN, FP, TN

# 计算 F1 分数
def f1_score(y_true, y_pred):
    TP, FN, FP, _ = confusion_matrix(y_true, y_pred)
    
    # 计算精确率和召回率
    precision = TP / (TP + FP) if (TP + FP) > 0 else 0.0
    recall = TP / (TP + FN) if (TP + FN) > 0 else 0.0
    
    # 计算 F1 分数
    if precision + recall == 0:
        return 0.0  # 避免除以零
    f1 = 2 * (precision * recall) / (precision + recall)
    return f1

# 计算 F1 分数
f1 = f1_score(y_true, y_pred)
print(f"F1分数: {f1:.4f}")

4. 多分类任务F1分数代码

  • 对于多分类任务,可以分别计算每个类别的 F1 分数,然后取平均值。

import torch

# 假设有真实标签和预测标签(多分类任务)
y_true = torch.tensor([0, 1, 2, 0, 1, 2])  # 真实标签
y_pred = torch.tensor([0, 1, 0, 0, 1, 2])  # 预测标签

# 计算每个类别的 F1 分数
def f1_score_multiclass(y_true, y_pred, num_classes):
    f1_scores = []
    for cls in range(num_classes):
        TP = ((y_true == cls) & (y_pred == cls)).sum().item()  # 模型正确预测为正类的样本数
        FN = ((y_true == cls) & (y_pred != cls)).sum().item()  # 模型错误预测为负类的正类样本数
        FP = ((y_true != cls) & (y_pred == cls)).sum().item()  # 模型错误预测为正类的正类样本数
        
        # 计算精确率和召回率
        precision = TP / (TP + FP) if (TP + FP) > 0 else 0.0
        recall = TP / (TP + FN) if (TP + FN) > 0 else 0.0
        
        # 计算 F1 分数
        if precision + recall == 0:
            f1_scores.append(0.0)  # 避免除以零
        else:
            f1_scores.append(2 * (precision * recall) / (precision + recall))
    return f1_scores

# 计算 F1 分数
num_classes = 3
f1_scores = f1_score_multiclass(y_true, y_pred, num_classes)
for cls, f1 in enumerate(f1_scores):
    print(f"每个类别的F1分数 {cls}: {f1:.4f}")

# 计算宏平均 F1 分数
macro_f1 = sum(f1_scores) / num_classes
print(f"宏平均 F1 分数: {macro_f1:.4f}")

八、完整流程(使用直接继承 nn.Module逻辑回归,且仅保存模型的权重和其他参数,计算了二分类任务的精确度、召回率及F1分数)

1. 实现思路

① 自定义数据集

生成 100 个样本,每个样本有 2 个特征。

根据特征生成标签,使用简单的线性组合和阈值判断。

② 定义逻辑回归模型

使用 nn.Linear 定义一个线性层,并通过  实现逻辑回归。

③ 训练模型

使用二元交叉熵损失 (nn.BCELoss) 和随机梯度下降优化器 (optim.SGD) 训练模型。

④ 保存模型

使用 torch.save 保存模型参数。

⑤ 加载模型

使用 torch.load 加载模型参数。

⑥ 预测

加载模型后,使用新数据进行预测,并将概率转换为类别(0 或 1)。

⑦ 评估模型

计算模型的精确度、召回率和 F1 分数。

2. 代码示例

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())

# 计算精确度、召回率和 F1 分数
def evaluate_model(y_true, y_pred):
    # 计算混淆矩阵
    TP = ((y_true == 1) & (y_pred == 1)).sum().item()  # 模型正确预测为正类的样本数
    FN = ((y_true == 1) & (y_pred == 0)).sum().item()  # 模型错误预测为负类的正类样本数
    FP = ((y_true == 0) & (y_pred == 1)).sum().item()  # 模型错误预测为正类的正类样本数
    TN = ((y_true == 0) & (y_pred == 0)).sum().item()  # 模型正确预测为负类的样本数

    # 计算精确度、召回率和 F1 分数
    accuracy = (TP + TN) / (TP + TN + FP + FN) if (TP + TN + FP + FN) > 0 else 0.0
    precision = TP / (TP + FP) if (TP + FP) > 0 else 0.0
    recall = TP / (TP + FN) if (TP + FN) > 0 else 0.0
    f1 = 2 * (precision * recall) / (precision + recall) if (precision + recall) > 0 else 0.0

    return accuracy, precision, recall, f1

# 对训练集进行预测,计算评估指标
with torch.no_grad():
    train_predictions = loaded_model(X_tensor)
    train_predicted_labels = (train_predictions >= 0.5).float()

# 计算评估指标
accuracy, precision, recall, f1 = evaluate_model(y_tensor, train_predicted_labels)

# 输出结果
print("\n模型评估结果:")
print(f"精确度: {accuracy:.4f}")
print(f"精确率: {precision:.4f}")
print(f"召回率: {recall:.4f}")
print(f"F1分数: {f1:.4f}")

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() 将预测概率转换为标签。

⑦ 模型评估

  • 定义 evaluate_model 函数:

        计算混淆矩阵(TP、FN、FP、TN)。

        计算精确度、精确率、召回率和 F1 分数。

  • 对训练集进行预测并计算评估指标:

        train_predictions = loaded_model(X_tensor):计算训练集的预测概率。

        train_predicted_labels = (train_predictions >= 0.5).float():将预测概率转换为标签。

  • 输出评估结果:

        精确度(Accuracy):模型预测正确的样本比例。

        精确率(Precision):预测为正类的样本中,实际为正类的比例。

        召回率(Recall):实际为正类的样本中,预测为正类的比例。

        F1 分数(F1 Score):精确率和召回率的调和平均值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2291050.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring Boot - 数据库集成06 - 集成ElasticSearch

Spring boot 集成 ElasticSearch 文章目录 Spring boot 集成 ElasticSearch一:前置工作1:项目搭建和依赖导入2:客户端连接相关构建3:实体类相关注解配置说明 二:客户端client相关操作说明1:检索流程1.1&…

Java篇之继承

目录 一. 继承 1. 为什么需要继承 2. 继承的概念 3. 继承的语法 4. 访问父类成员 4.1 子类中访问父类的成员变量 4.2 子类中访问父类的成员方法 5. super关键字 6. super和this关键字 7. 子类构造方法 8. 代码块的执行顺序 9. protected访问修饰限定符 10. 继承方式…

ArkTS编程规范

文章目录 目标和适用范围规则来源章节概览代码风格编程实践 术语和定义总体原则命名类名、枚举名、命名空间名采用UpperCamelCase风格变量名、方法名、参数名采用lowerCamelCase风格常量名、枚举值名采用全部大写,单词间使用下划线隔开避免使用否定的布尔变量名&…

深度学习之“向量范数和距离度量”

在深度学习中,范数和向量距离是两个不同的概念。向量范数是一种函数,用于将一个实数或复数向量映射为一个值。虽然范数通常用于度量向量之间的距离,但是同样也有其它的一些表示距离的方式。 范数距离 范数是具有“长度”概念的函数。在向量…

基于Python的简单企业维修管理系统的设计与实现

以下是一个基于Python的简单企业维修管理系统的设计与实现,这里我们会使用Flask作为Web框架,SQLite作为数据库来存储相关信息。 1. 需求分析 企业维修管理系统主要功能包括: 维修工单的创建、查询、更新和删除。设备信息的管理。维修人员…

< OS 有关 > Android 手机 SSH 客户端 app: connectBot

connectBot 开源且功能齐全的SSH客户端,界面简洁,支持证书密钥。 下载量超 500万 方便在 Android 手机上,连接 SSH 服务器,去运行命令。 Fail2ban 12小时内抓获的 IP ~ ~ ~ ~ rootjpn:~# sudo fail2ban-client status sshd Status for the jail: sshd …

【算法设计与分析】实验7:复杂装载及0/1背包问题的回溯法设计与求解

目录 一、实验目的 二、实验环境 三、实验内容 四、核心代码 五、记录与处理 六、思考与总结 七、完整报告和成果文件提取链接 一、实验目的 针对复杂装载问题、及0/1背包问题开展分析、建模、评价,算法设计与优化,并进行编码实践。 理解复杂装载…

仿真设计|基于51单片机的温湿度、一氧化碳、甲醛检测报警系统

目录 具体实现功能 设计介绍 51单片机简介 资料内容 仿真实现(protues8.7) 程序(Keil5) 全部内容 资料获取 具体实现功能 (1)温湿度传感器、CO传感器、甲醛传感器实时检测温湿度值、CO值和甲醛值进…

使用vhd虚拟磁盘安装两个win10系统

使用vhd虚拟磁盘安装两个win10系统 前言vhd虚拟磁盘技术简介准备工具开始动手实践1.winX选择磁盘管理2.选择“操作”--“创建VHD”3.自定义一个位置,输入虚拟磁盘大小4.右键初始化磁盘5.选择GPT分区表格式6.右键新建简单卷7.给卷起个名字,用于区分8.打开…

深入理解Spring事务管理

一、事务基础概念 1.1 什么是事务? 事务(Transaction)是数据库操作的最小工作单元,具有ACID四大特性: 原子性(Atomicity):事务中的操作要么全部成功,要么全部失败 一致…

自制虚拟机(C/C++)(二、分析引导扇区,虚拟机读二进制文件img软盘)

先修复上一次的bug&#xff0c;添加新指令&#xff0c;并增加图形界面 #include <graphics.h> #include <conio.h> #include <windows.h> #include <commdlg.h> #include <iostream> #include <fstream> #include <sstream> #inclu…

ASP.NET Core 启动并提供静态文件

ASP.NET Core 启动并提供静态文件 即是单个可执行文件&#xff0c;它既运行 API 项目&#xff0c;也托管 前端项目&#xff08;通常是前端的发布文件&#xff09;。 这种方式一般是通过将 前端项目 的发布文件&#xff08;例如 HTML、CSS、JavaScript&#xff09;放入 Web AP…

4 [危机13小时追踪一场GitHub投毒事件]

事件概要 自北京时间 2024.12.4 晚间6点起&#xff0c; GitHub 上不断出现“幽灵仓库”&#xff0c;仓库中没有任何代码&#xff0c;只有诱导性的病毒文件。当天&#xff0c;他们成为了 GitHub 上 star 增速最快的仓库。超过 180 个虚假僵尸账户正在传播病毒&#xff0c;等待不…

变量和常量

一.变量 1.标准声明 var 变量名 变量类型 变量声明行末不需要分号 2..批量声明 package main import "fmt" func main(){var(a string b int c boold float32)}3.变量的初始化 var a int 10 var b float321.1 4.类型推导 var name"tom" var age18 fmt.Pr…

大模型概述(方便不懂技术的人入门)

1 大模型的价值 LLM模型对人类的作用&#xff0c;就是一个百科全书级的助手。有多么地百科全书&#xff0c;则用参数的量来描述&#xff0c; 一般地&#xff0c;大模型的参数越多&#xff0c;则该模型越好。例如&#xff0c;GPT-3有1750亿个参数&#xff0c;GPT-4可能有超过1万…

流浪 Linux: 外置 USB SSD 安装 ArchLinux

注: ArchLinux 系统为滚动更新, 变化很快, 所以本文中的安装方法可能很快就过时了, 仅供参考. 实际安装时建议去阅读官方文档. 最近, 突然 (也没有那么突然) 有了一大堆 PC: 4 个笔记本, 2 个台式主机 (M-ATX 主板), 1 个小主机 (迷你主机). 嗯, 多到用不过来. 但是, 窝又不能…

Hot100之子串

560和为K的子数组 题目 给你一个整数数组 nums 和一个整数 k &#xff0c;请你统计并返回 该数组中和为 k 的子数组的个数 。 子数组是数组中元素的连续非空序列 思路解析 ps&#xff1a;我们的presum【0】就是0&#xff0c;如果没有这个0的话我们的第一个元素就无法减去上…

网络工程师 (11)软件生命周期与开发模型

一、软件生命周期 前言 软件生命周期&#xff0c;也称为软件开发周期或软件开发生命周期&#xff0c;是指从软件项目的启动到软件不再被使用为止的整个期间。这个过程可以细分为多个阶段&#xff0c;每个阶段都有其特定的目标、任务和产出物。 1. 问题定义与需求分析 问题定义…

(三)QT——信号与槽机制——计数器程序

目录 前言 信号&#xff08;Signal&#xff09;与槽&#xff08;Slot&#xff09;的定义 一、系统自带的信号和槽 二、自定义信号和槽 三、信号和槽的扩展 四、Lambda 表达式 总结 前言 信号与槽机制是 Qt 中的一种重要的通信机制&#xff0c;用于不同对象之间的事件响…

hot100_21. 合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1&#xff1a; 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,4] 示例 2&#xff1a; 输入&#xff1a;l1 [], l2 [] 输出&#xff1a;[…