0302-利用pytorch解決線性回歸問題


0302_利用pytorch解決線性回歸問題

pytorch完整教程目錄:https://www.cnblogs.com/nickchen121/p/14662511.html

一、引言

上一篇文章我們利用numpy解決了線性回歸問題,我們能感覺到他的麻煩之處,很多數學性的方法都需要我們自己親手去實現,這對於數學不好的同學來說,簡直就是災難,讓你數學又好並且碼代碼能力又強,臣妾做不到呀!因此我們說到,可以利用torch這個框架簡化其中的很多操作,接下來就讓我們提前體驗下torch的強大,由於直接上代碼,有些代碼可能你可能看不懂,但沒關系,能看懂torch的強大就行。

由於上一篇已經詳細的介紹了線性回歸模型的流程,我們這里就不再次羅嗦了,直接把線性回歸的5個步驟貼過來:

  1. 初始化未知變量\(w=b=0\)
  2. 得到損失函數\(loss = \frac{1}{N}\sum_{i=1}^N{(\hat{y_i}-y_i)}^2\)
  3. 利用梯度下降算法更新得到\(w', b'\)
  4. 重復步驟3,利用\(w', b'\)得到新的更優的\(w', b'\),直至\(w', b'\)收斂
  5. 最后得到函數模型\(f=w'*x+b'\)

但是這里為了體現torch的強大,我們使用了神經網絡全連接層的概念,但是用的是一層網絡,相信不會難倒你。有人很好奇,為什么我這樣做,我想說:如果不使用神經網絡,我為什么不用sklearn框架做個線性回歸給你體驗下框架的強大呢?三行代碼一套搞定。而且一層神經網絡可以看做是感知機模型,而感知機模型無非就是在線性回歸模型的基礎上加了一個sgn函數。

二、利用torch解決線性回歸問題

2.1 定義x和y

在下面的代碼中,我們定義的x和y都是ndarray數據的格式,所以在之后的處理之中需要通過torch的from_numpy()方法把ndarray格式的數據轉成tensor類型。

其中x為一維數組,例如:\[1,2,3,4,5,……\]

其中y假設\(y=2*x+3\)

import numpy as np

# torch里要求數據類型必須是float
x = np.arange(1, 12, dtype=np.float32).reshape(-1, 1)
y = 2 * x + 3

2.2 自定制線性回歸模型類

由於torch內部封裝了線性回歸算法,我們只需要繼承它給我們提供的模型類即可,然后通過Python中類的繼承做出一些靈活的改動。(如果你對繼承不熟悉,強烈推薦回爐重造Python)下面給出代碼:

import torch
import torch.nn as nn


# 繼承nn.module,實現前向傳播,線性回歸直接可以看做是全連接層
class LinearRegressionModel(nn.Module):
    def __init__(self, input_dim, output_dim):
        super().__init__()  # 繼承父類方法
        self.linear = nn.Linear(input_dim, output_dim)  # 定義全連接層,其中input_dim和output_dim是輸入和輸出數據的維數

    # 定義前向傳播算法
    def forward(self, inp):
        out = self.linear(inp)  # 輸入x后,通過全連接層得到輸入出結果out
        return out  # 返回被全連接層處理后的結果


# 定義線性回歸模型
regression_model = LinearRegressionModel(1, 1)  # x和y都是一維的

2.3 指定gpu或者cpu

# 可以通過to()或者cuda()使用GPU進行模型的訓練,需要將模型和數據都轉換到GPU上,也可以指定具體的GPU,如.cuda(1)
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
regression_model.to(device)

2.4 設置參數

epochs = 1000  # 訓練次數
learning_rate = 0.01  # 學習速率
optimizer = torch.optim.SGD(regression_model.parameters(), learning_rate)  # 優化器(未來會詳細介紹),這里使用隨機梯度下降算法(SGD)
criterion = nn.MSELoss()  # 使用均方誤差定義損失函數

2.5 訓練

for epoch in range(epochs):
    # 數據類型轉換
    inputs = torch.from_numpy(x).to(device)  # 由於x是ndarray數組,需要轉換成tensor類型,如果用gpu訓練,則會通過to函數把數據傳入gpu
    labels = torch.from_numpy(y).to(device)

    # 訓練
    optimizer.zero_grad()  # 每次求偏導都會清零,否則會進行疊加
    outputs = regression_model(inputs)  # 把輸入傳入定義的線性回歸模型中,進行前向傳播,得到預測結果
    loss = criterion(outputs, labels)  # 通過均方誤差評估預測誤差
    loss.backward()  # 反向傳播
    optimizer.step()  # 更新權重參數

    # 每50次循環打印一次結果
    if epoch % 50 == 0:
        print("epoch:", epoch, "loss:", loss.item())

predict = regression_model(torch.from_numpy(x).requires_grad_()).data.numpy()  # 通過訓練好的模型預測結果

2.6 保存模型

torch.save(regression_model.state_dict(), "model.pk1")  # 保存模型
result = regression_model.load_state_dict(torch.load("model.pk1"))  # 加載模型

三、代碼匯總

# author : 'nickchen121';
# date: 14/4/2021 20:11

import numpy as np

# torch里要求數據類型必須是float
x = np.arange(1, 12, dtype=np.float32).reshape(-1, 1)
y = 2 * x + 3

import torch
import torch.nn as nn


# 繼承nn.module,實現前向傳播,線性回歸直接可以看做是全連接層
class LinearRegressionModel(nn.Module):
    def __init__(self, input_dim, output_dim):
        super().__init__()  # 繼承父類方法
        self.linear = nn.Linear(input_dim, output_dim)  # 定義全連接層,其中input_dim和output_dim是輸入和輸出數據的維數

    # 定義前向傳播算法
    def forward(self, inp):
        out = self.linear(inp)  # 輸入x后,通過全連接層得到輸入出結果out
        return out  # 返回被全連接層處理后的結果


# 定義線性回歸模型
regression_model = LinearRegressionModel(1, 1)  # x和y都是一維的

# 可以通過to()或者cuda()使用GPU進行模型的訓練,需要將模型和數據都轉換到GPU上,也可以指定具體的GPU,如.cuda(1)
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
regression_model.to(device)

epochs = 1000  # 訓練次數
learning_rate = 0.01  # 學習速率
optimizer = torch.optim.SGD(regression_model.parameters(), learning_rate)  # 優化器,這里使用隨機梯度下降算法(SGD)
criterion = nn.MSELoss()  # 使用均方誤差定義損失函數

for epoch in range(epochs):
    # 數據類型轉換
    inputs = torch.from_numpy(x).to(device)  # 由於x是ndarray數組,需要轉換成tensor類型,如果用gpu訓練,則會通過to函數把數據傳入gpu
    labels = torch.from_numpy(y).to(device)

    # 訓練
    optimizer.zero_grad()  # 每次求偏導都會清零,否則會進行疊加
    outputs = regression_model(inputs)  # 把輸入傳入定義的線性回歸模型中,進行前向傳播
    loss = criterion(outputs, labels)  # 通過均方誤差評估預測誤差
    loss.backward()  # 反向傳播
    optimizer.step()  # 更新權重參數

    # 每50次循環打印一次結果
    if epoch % 50 == 0:
        print("epoch:", epoch, "loss:", loss.item())

predict = regression_model(torch.from_numpy(x).requires_grad_()).data.numpy()  # 通過訓練好的模型預測結果

# torch.save(regression_model.state_dict(), "model.pk1")  # 保存模型
# result = regression_model.load_state_dict(torch.load("model.pk1"))  # 加載模型

四、總結

本篇文章從torch的角度去解決了線性回歸問題,細節你可能不懂,但也可以發現它是非常簡單的,全程沒有讓你去實現優化器、去實現全連接層、去實現反向傳播,在這里你就不需要去實現一個數學公式。你需要做的僅僅是成為一個優秀的調包俠,並且努力成為一個偉大的調參師即可。

至於為什么直接上代碼,而不是先講解torch的基礎,一定是有深意的。站得高看得遠,先帶你領略下torch的用途及其強大,然后我們再慢慢的一步一步築基。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM