通过这个示例,可以了解逻辑回归模型的基本原理和训练过程,同时可以通过修改和优化代码来进一步探索机器学习模型的训练和调优方法。
步骤:
- 生成了一个模拟的二分类数据集:通过随机生成包含两个特征的数据
data_x
,并基于一定规则生成对应的二分类标签数据data_y
。 - 创建了一个手动实现的逻辑回归模型
LogisticRegressionManually
,其中包括:- 初始化函数
__init__
:初始化模型的权重参数w
和偏置参数b
。 - 前向传播函数
forward
:计算给定输入数据的预测值。 - 损失函数
loss_func
:定义了交叉熵损失函数,用于评估模型的预测性能。 - 训练函数
train
:在每个epoch中,遍历数据集的每个样本,计算预测值、损失值、梯度,并利用梯度下降法更新模型参数。
- 初始化函数
- 实例化
LogisticRegressionManually
类,然后调用train
方法对模型进行训练。 - 在训练过程中,打印每个epoch的损失值。
演示:
# 生成模拟的二分类数据集,其中X数据是随机生成的,Y数据根据一定规则生成。
import torch
import torch.nn.functional as F
n_items = 1000
n_features = 2
learning_rate = 0.001
epochs = 100
# 置了随机种子,以确保每次运行代码时生成的随机数相同,从而使结果具有可重现性。
torch.manual_seed(123)
# 生成了一个大小为(1000, 2)的张量data_x,其中包含1000个样本,每个样本具有2个特征。这里使用torch.randn生成标准正态分布的随机数作为数据,并将数据类型转换为float。
data_x = torch.randn(size=(n_items, n_features)).float()
# 成了标签数据data_y,通过对第一个特征乘以0.5和第二个特征乘以1.5的差值进行判断,如果差值大于0就将标签设为1,否则为0。这样生成了一个二分类标签数据集,同样将数据类型转换为float。
data_y = torch.where(torch.subtract(data_x[:, 0]*0.5, data_x[:, 1]*1.5) > 0, 1., 0.).float()
# print(data_x)
# print(data_y)
# 在每个epoch中,遍历数据集的每个样本,计算预测值、损失值、梯度,利用梯度下降法更新模型参数。通过这种方式训练模型可以逐渐优化模型参数,以达到更好的预测效果。
class LogisticRegressionManually(object):
# 初始化函数__init__
def __init__(self):
# w是一个大小为(n_features, 1)的张量,用于存储权重参数,并且设置了requires_grad=True表示需要计算梯度;
self.w = torch.randn(size=(n_features, 1), requires_grad=True)
# b是一个大小为(1, 1)的张量,用于存储偏置参数,并且设置了requires_grad=True
self.b = torch.zeros(size=(1, 1), requires_grad=True)
# 前向传播函数forward
def forward(self, x):
# 过矩阵乘法计算预测值y_hat:将参数w转置后与输入数据x相乘,并加上偏置b后通过F.sigmoid函数进行激活,最终返回激活后的预测值。
y_hat = F.sigmoid(torch.matmul(self.w.transpose(0, 1), x) + self.b)
return y_hat
# 损失函数loss_func
@staticmethod
def loss_func(y_hat, y):
# 定义了交叉熵损失函数。通过计算实际标签y和预测值y_hat之间的交叉熵损失来评估模型的预测性能。
return -(torch.log(y_hat)*y + (1-y)*torch.log(1-y_hat))
# 训练函数train
def train(self):
# 在每个epoch中,遍历数据集中的每个样本
for epoch in range(epochs):
for step in range(n_items):
# 利用模型的前向传播函数forward计算当前样本的预测值y_hat。
y_hat = self.forward(data_x[step])
# 获取当前样本的真实标签y
y = data_y[step]
# 调用损失函数loss_func计算预测值与真实标签之间的损失。
loss = self.loss_func(y_hat, y)
# 利用反向传播计算损失对模型参数的梯度
loss.backward()
# 进入torch.no_grad()上下文管理器,保证在该范围内的操作不会被记录用于自动微分。
with torch.no_grad():
# 更新权重参数w和偏置参数b,通过梯度下降法更新参数,learning_rate是学习率。
self.w.data -= learning_rate * self.w.grad
self.b.data -= learning_rate * self.b.grad
# 清零梯度,以便进行下一次参数更新时重新计算梯度。
self.w.grad.data.zero_()
self.b.grad.data.zero_()
print("Epoch: %03d, Loss: %.3f" % (epoch, loss.item()))
lrm = LogisticRegressionManually()
lrm.train()
结果: