手搓逻辑回归

88 阅读2分钟

加载数据

import torch
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split

X ,y = load_breast_cancer(return_X_y=True)
#切分数据
X_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.2, random_state=0)

标准化

mu = X_train.mean(axis=0)
sigma = X_train.std(axis=0)
X_train = (X_train-mu)/sigma
X_test = (X_test-mu)/sigma

转张量

X_train = torch.tensor(data=X_train, dtype=torch.float32)
X_test = torch.tensor(data=X_test, dtype=torch.float32)
y_train = torch.tensor(data=y_train, dtype=torch.long)
y_test = torch.tensor(data=y_test, dtype=torch.long)

定义权重

w = torch.randn(302, requiers_grad=True)
b = torch.zeros(11, requiers_grad=True)

定义模型

def model(X):
    return X @ w + b

交叉熵

def get_cross_entropy(y_pred, y_true):
    #one hot
    y_true = torch.eye(2)[y_true]
    #softMax, 标签转模拟概率
    y_pred = torch.exp(y_pred)/torch.exp(y_pred).sum(dim=1, keepdim=True)
    #交叉熵
    cross_entropy = (y_true * torch.log(1/y_pred)).sum(dim=1)
    #
    cross_entropy =  cross_entropy.mean()
    return cross_entropy

开始训练

# 训练步数
steps = 200
# 学习率: 适当压缩偏导数,防止梯度爆炸
learning_rate = 1e-2

for step in range(steps):
    #正向传播
    y_pred = model(X_train)
    #计算交叉熵
    loss = get_cross_entropy(y_pred, y_train)
    #方向传播
    loss.backward()
    #梯度下降
    w.data -= learning_rate*w.grad
    b.data -= learning_rate*b.grad
    #清空梯度
    w.grad.zero_()
    b.grad.zero_()
    
    print(loss.item())

神经网络实现

improt torch
from torch import nn

#实例化模型
model = nn.Linear(in_features=30, out_features=2)

#定义学习次数, 以及优化器, 损失函数
steps = 1000
optimizer = torch.optim.SGD(params=model.parameters(), lr=1e-3)
loss_fn = nn.CrossEntropyLoss()

#开始训练
for step in range(steps):
    #正向传播
    y_pred = model(X_train)
    #计算损失
    loss = loss_fn(y_pred, y_train)
    #反向传播
    loss.backward()
    #优化一步
    optimizer.step()
    #清空梯度
    optimizer.zero_grad()

保存模型

#整体保存与加载(不推荐)
torch.save(model,f="model.lxh")
model = torch.load(f="model.lxh")


#只保存权重
torch.save(obj=model.state.dict(), f="model.pt")
model = nn.Linear(in_features=30, out_features=2)
model.load_state_dict(state_dict=torch.load(f="model.pt", weights_only=True))

推理流程

# 初始化模型
model = nn.Linear(in_features=30, out_features=2)
# 加载训练好的权重
model.load_state_dict(state_dict=torch.load(f="model.pt", weights_only=True))
def predict(X):
    # 类型校验
    if not isinstance(X, torch.Tensor):
        X = torch.tensor(data=X, dtype=torch.float32)
    # 数据结构判断 [batch_size, num_features]
    if X.ndim !=2 or X.size(1) != 30:
        raise ValueError("输入数据有误!!!")
    # 模型推理
    y_pred = model(X)
    y_pred = y_pred.argmax(dim=1)
    return y_pred
    
y_pred= predict(X_test)

#评估
(y_pred==y_test).to(dtype=torch.float32).mean()