【机器学习】自定义数据集 使用paddlepaddle框架实现逻辑回归并保存模型,然后保存模型后再加载模型进行预测
一、使用paddlepaddle框架实现逻辑回归
1. 数据部分:
- 首先自定义了一个简单的数据集,特征
X
是 100 个随机样本,每个样本一个特征,目标值y
基于线性关系并添加了噪声。 - 将
numpy
数转换为Paddlepaddle张量,方便后续在模型中使用。
2. 模型定义部分:
方案 1:使用 nn.Sequential
组网
代码解释
① 数据生成与转换:
- 生成自定义的特征矩阵
X
和目标值向量y
,并添加高斯噪声模拟真实数据。 - 使用
paddle.to_tensor
将numpy
数组转换为 PaddlePaddle 张量。
② 模型组网:
- 使用
nn.Sequential
快速构建线性回归模型,只包含一个nn.Linear
层。
③ 损失函数和优化器:
- 选择均方误差损失函数
nn.MSELoss
和随机梯度下降优化器paddle.optimizer.SGD
。
④ 模型训练:
- 进行多个轮次的训练,在每个轮次中进行前向传播、损失计算、反向传播和参数更新。
- 记录每一轮的损失值,用于后续绘制损失曲线。
⑤ 损失曲线绘制:
- 使用
matplotlib
绘制训练损失随轮次的变化曲线,直观展示模型的训练过程。
⑥ 模型评估:
- 在无梯度计算的模式下进行预测,计算预测结果的均方误差和决定系数。
⑦ 输出模型参数:
- 获取模型的系数和截距并输出。
import paddle
import paddle.nn as nn
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score
import matplotlib.pyplot as plt
# 自定义数据集
# 生成 100 个样本,每个样本有 1 个特征
X = np.random.rand(100, 1).astype(np.float32)
# 根据特征生成目标值,添加一些噪声
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)
# 将 numpy 数组转换为 PaddlePaddle 张量
X = paddle.to_tensor(X)
y = paddle.to_tensor(y)
# 使用 nn.Sequential 组网
model = nn.Sequential(
nn.Linear(1, 1)
)
# 定义损失函数和优化器
criterion = nn.MSELoss()
optimizer = paddle.optimizer.SGD(learning_rate=0.01, parameters=model.parameters())
# 训练模型
num_epochs = 1000
losses = []
for epoch in range(num_epochs):
# 前向传播
outputs = model(X)
loss = criterion(outputs, y)
losses.append(loss.numpy()[0])
# 反向传播和优化
optimizer.clear_grad()
loss.backward()
optimizer.step()
if (epoch + 1) % 100 == 0:
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.numpy()[0]:.4f}')
# 绘制训练损失曲线
plt.plot(range(num_epochs), losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Training Loss')
plt.show()
# 模型评估
with paddle.no_grad():
y_pred = model(X).numpy()
mse = mean_squared_error(y.numpy(), y_pred)
r2 = r2_score(y.numpy(), y_pred)
print(f"均方误差 (MSE): {mse}")
print(f"决定系数 (R²): {r2}")
# 输出模型的系数和截距
weights = model[0].weight.numpy()[0][0]
bias = model[0].bias.numpy()[0]
print(f"模型系数: {weights}")
print(f"模型截距: {bias}")
方案 2:单独定义,使用类的方式 class nn.Layer
组网
代码解释
此方案与方案 1 的主要区别在于模型的组网方式,具体如下:
模型组网:
① 定义一个继承自 nn.Layer
的自定义模型类 LinearRegression
。
② 在 __init__
方法中初始化 nn.Linear
层。
③ 在 forward
方法中定义前向传播逻辑。
后续步骤:
损失函数、优化器的选择,模型训练、评估以及参数输出等步骤与方案 1 基本相同。
import paddle
import paddle.nn as nn
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score
import matplotlib.pyplot as plt
# 自定义数据集
# 生成 100 个样本,每个样本有 1 个特征
X = np.random.rand(100, 1).astype(np.float32)
# 根据特征生成目标值,添加一些噪声
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)
# 将 numpy 数组转换为 PaddlePaddle 张量
X = paddle.to_tensor(X)
y = paddle.to_tensor(y)
# 自定义模型类,继承自 nn.Layer
class LinearRegression(nn.Layer):
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 = paddle.optimizer.SGD(learning_rate=0.01, parameters=model.parameters())
# 训练模型
num_epochs = 1000
losses = []
for epoch in range(num_epochs):
# 前向传播
outputs = model(X)
loss = criterion(outputs, y)
losses.append(loss.numpy()[0])
# 反向传播和优化
optimizer.clear_grad()
loss.backward()
optimizer.step()
if (epoch + 1) % 100 == 0:
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.numpy()[0]:.4f}')
# 绘制训练损失曲线
plt.plot(range(num_epochs), losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Training Loss')
plt.show()
# 模型评估
with paddle.no_grad():
y_pred = model(X).numpy()
mse = mean_squared_error(y.numpy(), y_pred)
r2 = r2_score(y.numpy(), y_pred)
print(f"均方误差 (MSE): {mse}")
print(f"决定系数 (R²): {r2}")
# 输出模型的系数和截距
weights = model.linear.weight.numpy()[0][0]
bias = model.linear.bias.numpy()[0]
print(f"模型系数: {weights}")
print(f"模型截距: {bias}")
3. 训练和评估部分:
- 使用
train_losses
列表记录每一轮训练的损失值,方便后续绘制训练损失曲线,直观观察模型的训练过程。 - 将数据集按 80:20 的比例划分为训练集和测试集,以更准确地评估模型的泛化能力。
- 使用
scikit-learn
中的mean_squared_error
和r2_score
计算测试集的均方误差和决定系数。
二、保存paddlepaddle框架逻辑回归模型
以下将分别详细介绍使用 PaddlePaddle 框架通过基础 API、fit
方法以及 paddle.Model
类这三种方式来保存模型,同时会给出完整的代码示例和相应的解释。
方式 1:基础 API 保存
基础 API 保存主要是保存模型的参数(state_dict
),也可以保存检查点信息。下面是一个逻辑回归模型的完整示例:
import paddle
import paddle.nn as nn
import numpy as np
# 自定义数据集
X = np.random.randn(1000, 2).astype(np.float32)
y = (2 * X[:, 0] + 3 * X[:, 1] > 0).astype(np.float32).reshape(-1, 1)
X = paddle.to_tensor(X)
y = paddle.to_tensor(y)
# 定义逻辑回归模型
class LogisticRegression(nn.Layer):
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 = paddle.optimizer.Adam(parameters=model.parameters(), learning_rate=0.01)
# 训练模型
num_epochs = 100
for epoch in range(num_epochs):
outputs = model(X)
loss = criterion(outputs, y)
optimizer.clear_grad()
loss.backward()
optimizer.step()
if (epoch + 1) % 10 == 0:
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.numpy()[0]:.4f}')
# 保存模型的参数
paddle.save(model.state_dict(), './基础API/model.pdparams')
# 保存检查点信息
final_checkpoint = {
'epoch': num_epochs,
'model_state_dict': model.state_dict(),
'optimizer_state_dict': optimizer.state_dict(),
'loss': loss.numpy()[0]
}
paddle.save(final_checkpoint, "./基础API/final_checkpoint.pkl")
代码解释
- 数据与模型定义:生成自定义数据集,定义逻辑回归模型,并进行训练。
- 保存模型参数:使用
paddle.save(model.state_dict(), './基础API/model.pdparams')
保存模型的参数,这些参数可以在后续加载到相同结构的模型中。 - 保存检查点信息:创建一个包含训练轮数、模型参数、优化器状态和损失值的字典
final_checkpoint
,使用paddle.save
将其保存为final_checkpoint.pkl
文件,方便后续恢复训练。
方式 2:训练 fit
进行保存
fit
方法是 PaddlePaddle 提供的一种方便的训练接口,在训练过程中可以设置保存模型的参数。
import paddle
import paddle.nn as nn
import numpy as np
from paddle.io import TensorDataset, DataLoader
# 自定义数据集
X = np.random.randn(1000, 2).astype(np.float32)
y = (2 * X[:, 0] + 3 * X[:, 1] > 0).astype(np.float32).reshape(-1, 1)
X = paddle.to_tensor(X)
y = paddle.to_tensor(y)
# 创建数据集和数据加载器
dataset = TensorDataset([X, y])
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
# 定义逻辑回归模型
class LogisticRegression(nn.Layer):
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 = paddle.optimizer.Adam(parameters=model.parameters(), learning_rate=0.01)
# 使用 fit 方法进行训练并保存模型
paddle.Model(model).fit(
dataloader,
epochs=100,
optimizer=optimizer,
loss=criterion,
save_dir='./fit保存模型',
save_freq=10
)
代码解释
- 数据处理:将自定义数据集封装成
TensorDataset
,并使用DataLoader
进行批量加载。 - 模型定义与配置:定义逻辑回归模型,设置损失函数和优化器。
- 使用
fit
方法训练并保存:使用paddle.Model(model).fit
方法进行训练,save_dir
参数指定保存模型的目录,save_freq
参数指定每多少个轮次保存一次模型。
方式 3:利用 paddle.Model
类进行保存
paddle.Model
类提供了更高级的封装,方便进行模型的训练、评估和保存。
import paddle
import paddle.nn as nn
import numpy as np
from paddle.io import TensorDataset, DataLoader
# 自定义数据集
X = np.random.randn(1000, 2).astype(np.float32)
y = (2 * X[:, 0] + 3 * X[:, 1] > 0).astype(np.float32).reshape(-1, 1)
X = paddle.to_tensor(X)
y = paddle.to_tensor(y)
# 创建数据集和数据加载器
dataset = TensorDataset([X, y])
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
# 定义逻辑回归模型
class LogisticRegression(nn.Layer):
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 = paddle.optimizer.Adam(parameters=model.parameters(), learning_rate=0.01)
# 创建 paddle.Model 实例
paddle_model = paddle.Model(model)
paddle_model.prepare(optimizer, criterion)
# 训练模型
paddle_model.fit(dataloader, epochs=100)
# 保存模型
paddle_model.save('./paddle_Model保存模型/final_model')
代码解释
- 数据处理:同方式 2,将数据集封装成
TensorDataset
并使用DataLoader
加载。 - 模型定义与配置:定义逻辑回归模型,设置损失函数和优化器。
- 创建
paddle.Model
实例:使用paddle.Model(model)
创建实例,并使用prepare
方法配置优化器和损失函数。 - 训练并保存模型:使用
fit
方法进行训练,训练完成后使用paddle_model.save
保存模型。
通过以上三种方式,可以根据实际的需求选择合适的方法来保存 PaddlePaddle 模型。
三、加载paddlepaddle框架逻辑回归模型
以下为PaddlePaddle 中使用基础 API 和高级 API 加载模型的具体方法,将结合前面保存模型的示例,给出完整的代码实现和解释。
方式 1:基础 API 模型的加载
当使用基础 API 保存模型参数和检查点信息后,可按如下步骤加载:
import paddle
import paddle.nn as nn
import numpy as np
# 定义逻辑回归模型
class LogisticRegression(nn.Layer):
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)
# 定义优化器
optimizer = paddle.optimizer.Adam(parameters=model.parameters(), learning_rate=0.01)
# 加载模型参数
model_state_dict = paddle.load('./基础API/model.pdparams')
# 加载优化器状态(如果之前保存了)
# 这里假设之前保存了优化器状态到 optimizer.pdopt 文件
optimizer_state_dict = paddle.load('./基础API/optimizer.pdopt')
# 加载检查点信息
final_checkpoint_state_dict = paddle.load('./基础API/final_checkpoint.pkl')
print(final_checkpoint_state_dict)
# 将模型和参数联系起来
model.set_state_dict(model_state_dict)
# 恢复优化器状态(如果需要)
optimizer.set_state_dict(optimizer_state_dict)
# 生成新数据进行预测
new_X = np.random.randn(100, 2).astype(np.float32)
new_X = paddle.to_tensor(new_X)
# 使用加载的模型进行预测
model.eval()
with paddle.no_grad():
predictions = model(new_X)
predicted_labels = (predictions >= 0.5).astype(paddle.float32).numpy()
print("预测标签:", predicted_labels)
代码解释
- 模型定义与初始化:定义逻辑回归模型并初始化。
- 加载参数与状态:
paddle.load('./基础API/model.pdparams')
:加载模型的参数。paddle.load('./基础API/optimizer.pdopt')
:加载优化器的状态(如果之前保存了)。paddle.load('./基础API/final_checkpoint.pkl')
:加载检查点信息。
- 参数关联:
model.set_state_dict(model_state_dict)
:将加载的模型参数应用到模型上。optimizer.set_state_dict(optimizer_state_dict)
:恢复优化器的状态(如果需要继续训练)。
- 模型预测:生成新数据,将模型设置为评估模式,进行预测并输出结果。
方式 2:高级 API 加载
使用 paddle.Model
封装模型并保存后,可按如下步骤加载:
import paddle
import paddle.nn as nn
import numpy as np
from paddle.io import TensorDataset, DataLoader
# 定义逻辑回归模型
class LogisticRegression(nn.Layer):
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)
# 使用 paddle.Model 进行封装
paddle_model = paddle.Model(model)
# 准备模型
paddle_model.prepare(optimizer=paddle.optimizer.SGD(learning_rate=0.01, parameters=model.parameters()),
loss=nn.BCELoss(),
metrics=paddle.metric.Accuracy())
# 高级 API 模型的加载
paddle_model.load("./高层API1/final")
# 生成新数据进行预测
new_X = np.random.randn(100, 2).astype(np.float32)
new_y = (2 * new_X[:, 0] + 3 * new_X[:, 1] > 0).astype(np.float32).reshape(-1, 1)
new_X = paddle.to_tensor(new_X)
new_y = paddle.to_tensor(new_y)
# 创建数据集和数据加载器
new_dataset = TensorDataset([new_X, new_y])
new_dataloader = DataLoader(new_dataset, batch_size=32, shuffle=False)
# 评估模型
result = paddle_model.evaluate(new_dataloader, verbose=1)
print("评估结果:", result)
代码解释
- 模型定义与封装:定义逻辑回归模型,使用
paddle.Model(model)
进行封装。 - 模型准备:使用
prepare
方法配置优化器、损失函数和评估指标。 - 加载模型:使用
paddle_model.load("./高层API1/final")
加载之前保存的模型。 - 数据准备:生成新数据,封装成
TensorDataset
并使用DataLoader
加载。 - 模型评估:使用
paddle_model.evaluate
对加载的模型进行评估,并输出评估结果。
通过以上两种方式,可以根据之前保存模型的方式,选择合适的方法加载 PaddlePaddle 模型。
四、完整流程(使用类的方式 class nn.Layer
组网,且仅使用基础 API 保存与加载)
1. 实现思路
① 自定义数据集:
生成符合特定分布的特征矩阵和对应的标签向量。
② 构建逻辑回归模型:
定义一个简单的逻辑回归模型,这里使用类的方式 class nn.Layer
组网。
③ 训练模型:
使用生成的数据集对模型进行训练。
④ 保存模型:
将训练好的模型保存到本地文件。
⑤ 加载模型:
从本地文件中加载保存的模型。
⑥ 模型预测:
使用加载的模型对新数据进行预测。
2. 代码示例
import paddle
import paddle.nn as nn
import numpy as np
from sklearn.metrics import accuracy_score
# 自定义数据集
# 生成 1000 个样本,每个样本有 2 个特征
X = np.random.randn(1000, 2).astype(np.float32)
# 根据特征生成标签
y = (2 * X[:, 0] + 3 * X[:, 1] > 0).astype(np.float32).reshape(-1, 1)
# 将 numpy 数组转换为 PaddlePaddle 张量
X = paddle.to_tensor(X)
y = paddle.to_tensor(y)
# 定义逻辑回归模型
class LogisticRegression(nn.Layer):
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 = paddle.optimizer.Adam(parameters=model.parameters(), learning_rate=0.01)
# 训练模型
num_epochs = 100
for epoch in range(num_epochs):
# 前向传播
outputs = model(X)
loss = criterion(outputs, y)
# 反向传播和优化
optimizer.clear_grad()
loss.backward()
optimizer.step()
if (epoch + 1) % 10 == 0:
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.numpy()[0]:.4f}')
# 保存模型
paddle.save(model.state_dict(), 'logistic_regression_model.pdparams')
# 加载模型
loaded_model = LogisticRegression(input_size)
loaded_model.set_state_dict(paddle.load('logistic_regression_model.pdparams'))
loaded_model.eval()
# 生成新数据进行预测
new_X = np.random.randn(100, 2).astype(np.float32)
new_X = paddle.to_tensor(new_X)
# 使用加载的模型进行预测
with paddle.no_grad():
predictions = loaded_model(new_X)
predicted_labels = (predictions >= 0.5).astype(paddle.float32).numpy()
# 生成新数据对应的真实标签
true_labels = (2 * new_X.numpy()[:, 0] + 3 * new_X.numpy()[:, 1] > 0).astype(np.float32).reshape(-1, 1)
# 计算准确率
accuracy = accuracy_score(true_labels, predicted_labels)
print(f"预测准确率: {accuracy}")
3. 代码解释
① 数据集生成:
X = np.random.randn(1000, 2).astype(np.float32)
:生成 1000 个样本,每个样本有 2 个特征。y = (2 * X[:, 0] + 3 * X[:, 1] > 0).astype(np.float32).reshape(-1, 1)
:根据特征的线性组合生成标签,大于 0 标记为 1,否则标记为 0。X = paddle.to_tensor(X)
和y = paddle.to_tensor(y)
:将numpy
数组转换为 PaddlePaddle 张量。
② 模型定义:
LogisticRegression
类继承自nn.Layer
,包含一个线性层nn.Linear
和一个 Sigmoid 激活函数nn.Sigmoid
。forward
方法定义了前向传播的逻辑。
③ 损失函数和优化器:
criterion = nn.BCELoss()
:使用二元交叉熵损失函数,适用于二分类问题。optimizer = paddle.optimizer.Adam(parameters=model.parameters(), learning_rate=0.01)
:使用 Adam 优化器,学习率为 0.01。
④ 模型训练:
- 通过多次迭代进行前向传播、损失计算、反向传播和参数更新。
- 每 10 个 epoch 打印一次损失值。
⑤ 模型保存:
paddle.save(model.state_dict(), 'logistic_regression_model.pdparams')
:保存模型的参数到本地文件logistic_regression_model.pdparams
。
⑥ 模型加载和预测:
loaded_model = LogisticRegression(input_size)
:创建一个新的模型实例。loaded_model.set_state_dict(paddle.load('logistic_regression_model.pdparams'))
:加载保存的模型参数。loaded_model.eval()
:将模型设置为评估模式。- 生成新数据
new_X
并转换为张量。 - 使用
loaded_model
进行预测,通过(predictions >= 0.5).astype(paddle.float32).numpy()
将预测概率转换为标签。
⑦ 准确率计算:
- 生成新数据对应的真实标签
true_labels
。 - 使用
accuracy_score
计算预测准确率。