欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

pytorch入门——边学边练03逻辑回归

程序员文章站 2022-03-04 13:00:57
...

访问本站观看效果更佳

写在前面

我们来探讨一下逻辑回归的问题吧!顺便把前面的知识点再整合一次!完整代码参见logistic_regression

什么是逻辑回归

我们先想想逻辑回归问题是什么样的一个问题。简单的说,Logistic Regression是一个解决0/1分类问题的方法。那么再往深处想一想,Logistics Regression的数学模型是什么?为什么我们可以实现0,1分类?逻辑回归(Logistic Regression)与线性回归(Linear Regression)都是一种广义线性模型(generalized linear model)。逻辑回归假设因变量 y 服从伯努利分布,而线性回归假设因变量 y 服从高斯分布。 因此与线性回归有很多相同之处,去除Sigmoid映射函数的话,逻辑回归算法就是一个线性回归。可以说,逻辑回归是以线性回归为理论支持的,但是逻辑回归通过Sigmoid函数引入了非线性因素,因此可以轻松处理0/1分类问题。
既然与线性如此相似,那么我们是否可以继续套用上一节使用的模型呢?似乎是可行的。

设定待解决的问题

深度学习最经典的hello world问题是什么?我说mnist手写分类问题,恐怕没几个人会反对吧!可是用逻辑回归解决mnist问题可行吗?当然是可行的。上文提到逻辑回归模型是一个广义线性模型,即使输入是图像矩阵,也是可行的。再说下输出,一个Sigmod函数可以输出0,1,那么处理多分类问题时,我们多设置几个Sigmod函数不就可以了吗?所以我们的大体思路就是nn.Linear加上几个Sigmod函数,开始动手吧~

具体实现

一如既往我们先导入所需要的包

import torch
import torch.nn as nn
import torchvision
import torchvision.transforms as transforms

设定一下超参数

# Hyper-parameters 
input_size = 784
num_classes = 10
num_epochs = 5
batch_size = 100
learning_rate = 0.001

加载数据,还是利用我们先前使用过的方法DataLoader,然后再去遍历每个batch

# MNIST dataset (images and labels)
train_dataset = torchvision.datasets.MNIST(root='../../data', 
                                           train=True, 
                                           transform=transforms.ToTensor(),
                                           download=True)

test_dataset = torchvision.datasets.MNIST(root='../../data', 
                                          train=False, 
                                          transform=transforms.ToTensor())

# Data loader (input pipeline)
train_loader = torch.utils.data.DataLoader(dataset=train_dataset, 
                                           batch_size=batch_size, 
                                           shuffle=True)

test_loader = torch.utils.data.DataLoader(dataset=test_dataset, 
                                          batch_size=batch_size, 
                                          shuffle=False)

下面我们来定制模型,前面说过我们就用线性模型解决问题,所以就像前两节讲的一样使用一个nn.Linear就足够了

# Logistic regression model
model = nn.Linear(input_size, num_classes)

接着需要设置Loss,注意前面的章节里,计算损失大多是利用MSE Loss(公式见复杂一些的例子),本节利用的是CrossEntropyLoss交叉熵函数。一般处理分类问题我们使用交叉熵函数,而处理回归问题我们使用MSE及与之类似的函数。在后面的章节里,会专门讲解信息熵在计算Loss时的应用,因为篇幅较长在此暂时跳过。

# Loss and optimizer
# nn.CrossEntropyLoss() computes softmax internally
criterion = nn.CrossEntropyLoss()  
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)  

我们来训练模型,各位读者是否还记得前面讲过的如何单步求导,如何设置多轮次的训练模型?我们再写一遍,和上一节中的代码是非常类似的。

# Train the model
total_step = len(train_loader)
for epoch in range(num_epochs):
    for i, (images, labels) in enumerate(train_loader):
        # Reshape images to (batch_size, input_size)
        images = images.reshape(-1, 28*28)
        
        # Forward pass
        outputs = model(images)
        loss = criterion(outputs, labels)
        
        # Backward and optimize
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        if (i+1) % 100 == 0:
            print ('Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}' 
                   .format(epoch+1, num_epochs, i+1, total_step, loss.item()))

mnist数据集含有60000个训练样本,这里batch设置为了100,所以total_step也就是600。我们读取数据后为了使图像矩阵的大小和我们预设的nn.Linear输入一致,需要加一个reshape操作,-1是指自动调节剩余维度,在本例也就是图像通道数。
images送进model吧!然后计算损失,再反向传播,使Loss逐渐减小。

Epoch [1/5], Step [100/600], Loss: 2.1771
Epoch [1/5], Step [200/600], Loss: 2.1135
Epoch [1/5], Step [300/600], Loss: 1.9930
Epoch [1/5], Step [400/600], Loss: 1.9215
Epoch [1/5], Step [500/600], Loss: 1.8631
Epoch [1/5], Step [600/600], Loss: 1.8200
Epoch [2/5], Step [100/600], Loss: 1.7647
Epoch [2/5], Step [200/600], Loss: 1.6751
Epoch [2/5], Step [300/600], Loss: 1.5775
Epoch [2/5], Step [400/600], Loss: 1.5787
Epoch [2/5], Step [500/600], Loss: 1.5148
Epoch [2/5], Step [600/600], Loss: 1.5332
Epoch [3/5], Step [100/600], Loss: 1.4024
Epoch [3/5], Step [200/600], Loss: 1.3784
Epoch [3/5], Step [300/600], Loss: 1.4034
Epoch [3/5], Step [400/600], Loss: 1.2751
Epoch [3/5], Step [500/600], Loss: 1.2699
Epoch [3/5], Step [600/600], Loss: 1.2829
Epoch [4/5], Step [100/600], Loss: 1.2370
Epoch [4/5], Step [200/600], Loss: 1.2452
Epoch [4/5], Step [300/600], Loss: 1.1577
Epoch [4/5], Step [400/600], Loss: 1.1664
Epoch [4/5], Step [500/600], Loss: 1.0990
Epoch [4/5], Step [600/600], Loss: 1.0721
Epoch [5/5], Step [100/600], Loss: 1.0359
Epoch [5/5], Step [200/600], Loss: 1.0466
Epoch [5/5], Step [300/600], Loss: 1.0024
Epoch [5/5], Step [400/600], Loss: 0.9867
Epoch [5/5], Step [500/600], Loss: 1.0728
Epoch [5/5], Step [600/600], Loss: 0.9967

我们看到最后结果就开始抖动了,说明Linear的表达能力还是不够啊,那么模型正确率有多少呢?

# Test the model
# In test phase, we don't need to compute gradients (for memory efficiency)
with torch.no_grad():
    correct = 0
    total = 0
    for images, labels in test_loader:
        images = images.reshape(-1, 28*28)
        outputs = model(images)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum()

    print('Accuracy of the model on the 10000 test images: {} %'.format(100 * correct / total))

结果如下

Accuracy of the model on the 10000 test images: 83 %

最后别忘了保存一下模型

# Save the model checkpoint
torch.save(model.state_dict(), 'model.ckpt')

小结

今天我们用一个逻辑回归模型进行了mnist模型的测试,其实主要区别就在**函数上,其它方面和我们之前了解的差别不大。然后我们发现光用线性函数似乎是不够的,所以我们需要更好的结构。敬请期待后续的教程吧!

相关标签: pytorch