Pytorch学习笔记(四)--Logistic 回归模型

前请提要
Pytorch学习笔记(一)--Tensor和Variable
Pytorch学习笔记(二)--autograd and dynamic-graph
Pytorch学习笔记(三)--linear regression andgradient descend(线性回归和梯度下降)

一.logistic模型

logistic模型是一种广义回归模型,但是他更多的用于分类问题.
logistic回归会对y作用一个logistic函数,将其变为一种概率的结果,logistic函数也称为sigmoid函数

f(x) = 1 / (1 + e^(-x))

函数图像如下:
在这里插入图片描述
可以看到 Sigmoid 函数的范围是在 0 ~ 1 之间,所以任何一个值经过了 Sigmoid 函数的作用,都会变成 0 ~ 1 之间的一个值,这个值可以形象地理解为一个概率,比如对于二分类问题,这个值越小就表示属于第一类,这个值越大就表示属于第二类。

二.损失函数

在之前的模型中用loss函数来衡量误差,对于分类问题的loss如下
loss=−(y∗log(y’)+(1−y)∗log(1−y’))

Logistic 回归使用了 Sigmoid 函数将结果变到 0 ~ 1 之间,对于任意输入一个数据,经过 Sigmoid 之后的结果我们记为 y’ ,表示这个数据点属于第二类的概率,那么其属于第一类的概率就是 1−y’ 。如果这个数据点属于第二类,我们希望 y’ 越大越好,也就是越靠近 1 越好,如果这个数据属于第一类,那么我们希望 1−y’ 越大越好,也就是 y’ 越小越好,越靠近 0 越好,所以我们可以这样设计我们的 loss 函数

其中 y 表示真实的 label,只能取 {0, 1} 这两个值,因为 y’ 表示经过 Logistic 回归预测之后的结果,是一个 0 ~ 1 之间的小数。如果 y 是 0,表示该数据属于第一类,我们希望 y’ 越小越好,上面的 loss 函数变为

loss=−(log(1−y’))

在训练模型的时候我们希望最小化 loss 函数,根据 log 函数的单调性,也就是最小化 y’ ,与我们的要求是一致的。

而如果 y 是 1,表示该数据属于第二类,我们希望 y’ 越大越好,同时上面的 loss 函数变为

loss=−(log(y’))

三.代码与实现

在本次过程中解决了书中源代码报错的问题

w0 = w[0].data[0]
w1 = w[1].data[0]
b0 = b.data[0]

用如上代码替换时候w0是tensor类型,无法跟plot_x数据类型为data的相乘,pytorch进行了改版,将Variable类型与Tensor合并,有问题要多看官方文件,超链接如下
pytorch官网说明

1.从已知文件data.txt.中读入数据,画出点的图像

import torch
from torch.autograd import Variable
import numpy as np
import matplotlib.pyplot as plt
#%matplotlib inline
torch.manual_seed(2017)

# 从 data.txt 中读入点
with open('./data.txt', 'r') as f:
    data_list = [i.split('\n')[0].split(',') for i in f.readlines()]
    data = [(float(i[0]), float(i[1]), float(i[2])) for i in data_list]

# 标准化
x0_max = max([i[0] for i in data])
x1_max = max([i[1] for i in data])
data = [(i[0]/x0_max, i[1]/x1_max, i[2]) for i in data]

x0 = list(filter(lambda x: x[-1] == 0.0, data)) # 选择第一类的点
x1 = list(filter(lambda x: x[-1] == 1.0, data)) # 选择第二类的点

plot_x0 = [i[0] for i in x0]
plot_y0 = [i[1] for i in x0]
plot_x1 = [i[0] for i in x1]
plot_y1 = [i[1] for i in x1]

plt.plot(plot_x0, plot_y0, 'ro', label='x_0')
plt.plot(plot_x1, plot_y1, 'bo', label='x_1')
plt.legend(loc='best')
plt.show()

在这里插入图片描述
2.画出参数更新前的结果

np_data = np.array(data, dtype='float32') # 转换成 numpy array
x_data = torch.from_numpy(np_data[:, 0:2]) # 转换成 Tensor, 大小是 [100, 2]
y_data = torch.from_numpy(np_data[:, -1]).unsqueeze(1) # 转换成 Tensor,大小是 [100, 1]

# 定义 sigmoid 函数
def sigmoid(x):
    return 1 / (1 + np.exp(-x))

x_data = torch.tensor(x_data)
y_data = torch.tensor(y_data)

import torch.nn.functional as F

# 定义 logistic 回归模型
w = torch.randn((2, 1), requires_grad=True)
b = torch.zeros((1), requires_grad=True)

def logistic_regression(x):
    return F.sigmoid(torch.mm(x, w) + b)

# 画出参数更新之前的结果
w0 = w[0].item()
w1 = w[1].item()
b0 = b.item()

plot_x = np.arange(0.2, 1, 0.01)
plot_y = (-w0 * plot_x - b0) / w1

plt.plot(plot_x, plot_y, 'g', label='cutting line')
plt.plot(plot_x0, plot_y0, 'ro', label='x_0')
plt.plot(plot_x1, plot_y1, 'bo', label='x_1')
plt.legend(loc='best')


plt.show()

在这里插入图片描述

4.更新1000次

# 计算loss
def binary_loss(y_pred, y):
    logits = (y * y_pred.clamp(1e-12).log() + (1 - y) * (1 - y_pred).clamp(1e-12).log()).mean()
    return -logits

y_pred = logistic_regression(x_data)
loss = binary_loss(y_pred, y_data)
print(loss)

# 自动求导并更新参数
loss.backward()
w.data = w.data - 0.1 * w.grad.data
b.data = b.data - 0.1 * b.grad.data

# 算出一次更新之后的loss
y_pred = logistic_regression(x_data)
loss = binary_loss(y_pred, y_data)
print(loss)

# 使用 torch.optim 更新参数
from torch import nn
w = nn.Parameter(torch.randn(2, 1))
b = nn.Parameter(torch.zeros(1))

def logistic_regression(x):
    return F.sigmoid(torch.mm(x, w) + b)

optimizer = torch.optim.SGD([w, b], lr=1.)

# 进行 1000 次更新
import time

start = time.time()
for e in range(1000):
    # 前向传播
    y_pred = logistic_regression(x_data)
    loss = binary_loss(y_pred, y_data) # 计算 loss
    # 反向传播
    optimizer.zero_grad() # 使用优化器将梯度归 0
    loss.backward()
    optimizer.step() # 使用优化器来更新参数
    # 计算正确率
    mask = y_pred.ge(0.5).float()
    acc = (mask == y_data).sum().item() / y_data.shape[0]
    if (e + 1) % 200 == 0:
        print('epoch: {}, Loss: {:.5f}, Acc: {:.5f}'.format(e+1, loss.item(), acc))
during = time.time() - start
print()
print('During Time: {:.3f} s'.format(during))

# 画出更新之后的结果
w0 = w[0].item()
w1 = w[1].item()
b0 = b.item()

plot_x = np.arange(0.2, 1, 0.01)
plot_y = (-w0 * plot_x - b0) / w1

plt.plot(plot_x, plot_y, 'g', label='cutting line')
plt.plot(plot_x0, plot_y0, 'ro', label='x_0')
plt.plot(plot_x1, plot_y1, 'bo', label='x_1')
plt.legend(loc='best')
plt.show()

在这里插入图片描述

epoch: 200, Loss: 0.39730, Acc: 0.92000
epoch: 400, Loss: 0.32458, Acc: 0.92000
epoch: 600, Loss: 0.29065, Acc: 0.91000
epoch: 800, Loss: 0.27077, Acc: 0.91000
epoch: 1000, Loss: 0.25765, Acc: 0.90000

尝试过更高次数的更新但是效果甚微

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值