1. 程式人生 > >pytorch入門——邊學邊練03邏輯迴歸

pytorch入門——邊學邊練03邏輯迴歸

訪問本站觀看效果更佳

寫在前面

我們來探討一下邏輯迴歸的問題吧!順便把前面的知識點再整合一次!完整程式碼參見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模型的測試,其實主要區別就在啟用函式上,其它方面和我們之前瞭解的差別不大。然後我們發現光用線性函式似乎是不夠的,所以我們需要更好的結構。敬請期待後續的教程吧!