目录
1、数据准备
#导包
import torch
from torch import nn
import matplotlib.pyplot as plt
# %matplotlib inline
import numpy as np
from torch.distributions import MultivariateNormal
# 设置两组不同的均值向量和协方差矩阵
# torch.eye()主要是为了生成对角线全是1,其余部分全0的二维数组
mu1 = -3 * torch.ones(2)
mu2 = 3 * torch.ones(2)
sigma1 = torch.eye(2) * 0.5
sigma2 = torch.eye(2) * 2
# 各从两个多元高斯分布中生成100个样本
# 此处定义的多元高斯是二维的
m1 = MultivariateNormal(mu1, sigma1)
m2 = MultivariateNormal(mu2, sigma2)
x1 = m1.sample((100,))
x2 = m2.sample((100,))
#设置正负样本的标签
y = torch.zeros((200, 1))
y[100:] = 1
# 组合、打乱样本
x = torch.cat([x1, x2], dim=0)
# np.random.permutation():1、产生一个随机序列 2、对一个随机序列x进行随机排序 3、如果x是一个多维数组,它只会按照第一个索引洗牌
idx = np.random.permutation(len(x))
x = x[idx]
y = y[idx]
# # 绘制样本
plt.scatter(x1.numpy()[:,0], x1.numpy()[:,1])
plt.scatter(x2.numpy()[:,0], x2.numpy()[:,1])
plt.show()
结果:
从图中可以看出右上角的簇样本分布稀疏,而左下角分布紧凑。可以自行调整9-10行代码的参数,观察其变化。
2、线性方程
# 线性方程
# D_in为输入的特征数,D_out为输出的特征数
D_in, D_out = 2, 1
linear = nn.Linear(D_in, D_out, bias=True)
output = linear(x)
print(x.shape, linear.weight.shape, linear.bias.shape, output.shape)
def my_linear(x, w, b):
return torch.mm(x, w.t()) + b
torch.sum((output - my_linear(x, linear.weight, linear.bias)))
3、激活函数、损失函数
# 激活函数
sigmoid = nn.Sigmoid()
scores = sigmoid(output)
def my_sigmoid(x):
x = 1/(1 + torch.exp(-x))
return x
# 通过PyTorch验证我们的试验结果
torch.sum(scores - my_sigmoid(output))
# 损失函数
# Logistic回归使用交叉熵作为损失函数
loss = nn.BCELoss()
loss(scores, y)
# 下面自定义了二值交叉熵函数,将my_loss和PyTorch的BCELoss进行比较
def my_loss(x, y):
loss = - torch.mean(torch.log(x) * y + torch.log(1 - x) * (1 - y))
return loss
loss(scores, y) - my_loss(my_sigmoid(output), y)
4、利用nn.Module来实现Logistic回归
以上是我们使用的torch.nn包中的线性模型nn.Linear、激活函数,损失函数,它们都继承自nn.Module类。而在PyTorch中,我们继承nn.Module来构建我们自己的模型。接下来我们用nn.Module来实现Logistic回归。
import torch.nn as nn
class LogisticRegression(nn.Module):
def __init__(self, D_in):
super(LogisticRegression, self).__init__()
self.linear = nn.Linear(D_in, 1)
self.sigmoid = nn.Sigmoid()
# forward方法是必须被子类覆写的,在forward内部应当定义每次调用模型时执行的计算
def forward(self, x):
x = self.linear(x)
x = self.sigmoid(x)
return x
#nn.Module类的主要作用就是接收Tensor然后计算并返回结果
lr_model = LogisticRegression(2)
loss = nn.BCELoss()
# print(loss(lr_model(x), y))
# 优化算法
'''
Logistic回归通常采用梯度下降法优化目标函数。
PyTorch的torch.optim包实现了大多数常用算法
'''
from torch import optim
optimizer = optim.SGD(lr_model.parameters(), lr=0.03)
'''
构建完优化器,就可以迭代地对模型进行训练,有两个步骤:
1、调用损失函数的backward方法计算模型的梯度
2、调用优化器的step方法更新模型的参数
需要注意的是,应当提前调用优化器zero_grad方法清空参数的梯度
'''
batch_size = 10
iters = 10
# for input, target in dataset:
for _ in range(iters):
for i in range(int(len(x)/batch_size)):
input = x[i*batch_size:(i+1)*batch_size]
target = y[i*batch_size:(i+1)*batch_size]
optimizer.zero_grad()
output = lr_model(input)
l = loss(output, target)
l.backward()
optimizer.step()
# 优化算法
'''
Logistic回归模型的判决边界在高维空间的一个超平面,而我们的数据集是二维,所以判决边界只是平面内的一条直线,
在线的一侧被预测为正类,另一侧则被预测为父类。
draw_decision_boundary函数接收线性模型的参数w和b,以及数据集x。
绘制判决边界只需要计算一些数据在线模型的映射值,然后调用plt.plot绘制线条即可。
'''
pred_neg = (output <= 0.5).view(-1)
pred_pos = (output > 0.5).view(-1)
plt.scatter(x[pred_neg, 0], x[pred_neg, 1])
plt.scatter(x[pred_neg, 0], x[pred_pos, 1])
w = lr_model.linear.weight[0]
b = lr_model.linear.bias[0]
def draw_decision_boundary(w, b, x0):
x1 = (-b - w[0] * x0) / w[1]
plt.plot(x0.detach().numpy(), x1.detach().numpy(), 'r')
plt.show()
draw_decision_boundary(w, b, torch.linspace(x.min(), x.max(), 50))