pytorch学习:逻辑回归代码

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xckkcxxck/article/details/82314372
# -*- coding: utf-8 -*-
"""
Created on Sun Sep  2 09:50:01 2018

@author: www
"""

import torch
from torch.autograd import Variable
import numpy as np
import matplotlib.pyplot as plt

#设定随机种子
torch.manual_seed(250)

#读入数据
with open(r'E:\data\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]

#标准化,这里只是除以了每一列的最大值
max_0 = max(i[0] for i in data)
max_1 = max(i[1] for i in data)
data = [(i[0]/max_0, i[1]/max_1, 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')

#将数据转化为Tensor类型
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函数,在pytorch中已经有写好的sigmoid函数,可以直接调用
def sigmoid(x):
     return 1/(1+np.exp(-x))

x_data = Variable(x_data)
y_data = Variable(y_data)

#直接进行调用
import torch.nn.functional as F
w = Variable(torch.randn(2,1), requires_grad=True)
b = Variable(torch.zeros(1), requires_grad=True)

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

#画出参数更新之前的分类效果
w0 = w[0].data[0]
w1 = w[1].data[0]
b0 = b.data[0]

plot_x = np.arange(0.2, 1, 0.01, dtype='float32')
plot_x = torch.from_numpy(plot_x)
plot_y = (-w0 * plot_x - b0)/w1

plt.plot(plot_x.numpy(), plot_y.numpy(), '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')

#自己写一个损失函数
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
#注:这里使用了clamp函数,因为后面log是不能有0的。

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)

#==============================================================================
# 上面的参数更新方式其实是繁琐的重复操作,如果我们的参数很多,比如有 100 个,那么我们需要写 100 行来更新参数,
# 为了方便,我们可以写成一个函数来更新,其实 PyTorch 已经为我们封装了一个函数来做这件事,这就是 PyTorch 中
# 的优化器 torch.optim
# 使用 torch.optim 需要另外一个数据类型,就是 nn.Parameter,这个本质上和 Variable 是一样的,只不过
#  nn.Parameter 默认是要求梯度的,而 Variable 默认是不求梯度的
#==============================================================================
#使用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.data[0], acc))
during = time.time() - start
print()
print('During Time: {:.3f} s'.format(during))


#可以看到使用优化器之后更新参数非常简单,只需要在自动求导之前使用optimizer.zero_grad() 来归 0 
#梯度,然后使用 optimizer.step()来更新参数就可以了,非常简便

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

plot_x = np.arange(0.2, 1, 0.01, dtype='float32')
plot_x = torch.from_numpy(plot_x)
plot_y = (-w0 * plot_x - b0)/w1

plt.plot(plot_x.numpy(), plot_y.numpy(), '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')


#使用自带的loss
criterion = nn.BCEWithLogitsLoss() # 将 sigmoid 和 loss 写在一层,有更快的速度、更好的稳定性

w = nn.Parameter(torch.randn(2, 1))
b = nn.Parameter(torch.zeros(1))

def logistic_reg(x):
    return torch.mm(x, w) + b

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

# 同样进行 1000 次更新

start = time.time()
for e in range(1000):
    # 前向传播
    y_pred = logistic_reg(x_data)
    loss = criterion(y_pred, y_data)
    # 反向传播
    optimizer.zero_grad()
    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.data[0], acc))

during = time.time() - start
print()
print('During Time: {:.3f} s'.format(during))














     

猜你喜欢

转载自blog.csdn.net/xckkcxxck/article/details/82314372