零基礎學習人工智慧—Python—Pytorch學習(四)

kiba518發表於2024-08-12

前言

接續上一篇的optimizer的學習。

optimizer

程式碼和上一篇文章的一樣,如下:

import torch
import numpy as np
import torch.nn as nn

X = torch.tensor([1, 2, 3, 4], dtype=torch.float32)
Y = torch.tensor([2, 4, 6, 8], dtype=torch.float32)
w2 = torch.tensor(0.0, requires_grad=True)
 
def forward(_x):
    return w2* _x


learning_rate = 0.01
n_iter = 100  # 迴圈次數
loss =nn.MSELoss()
optimizer =torch.optim.SGD([w2],lr=learning_rate)

 
for epoch in range(n_iter):
    y_pred = forward(X)# 
    l = loss(Y, y_pred) 
    l.backward() #執行完反向傳播後,w2裡就已經有w2.grad了
    optimizer.step() #optimizer初始化時就接收了w2,現在w2有了grad,就可以執行step進行最佳化了,最佳化時會使用w2的梯度grad屬性和學習率learning_rate
    optimizer.zero_grad() #梯度清零

   
    if epoch % 1 == 0:
        print(f'epoch {epoch+1}:w2= {w2:.3f} ,loss = {l:.8f}')
print(f'f(5)={forward(5):.3f}')

可以看到,我們這裡引用增加了一個import torch.nn as nn。
這裡只是簡單的使用了nn.MSELoss(),我們就不用手寫這個計算平均值的步驟了。
然後我們定義了一個optimizer,接收了兩個引數,一個是權重w2,一個是學習率learning_rate。
這裡我們的傳遞的是一個Tensors陣列,而不是w2。
上篇文章已經介紹的w是根據梯度x.grad生成的,所以,按理應該是一個跟x同型別的矩陣,這裡[w2]跟x不同型,但這裡他只是一個數,這是因為計算時,會自動把這種一個數的矩陣變形為跟x同型的矩陣。
正確的寫法應該是下面這樣。

import torch
import numpy as np
import torch.nn as nn

X = torch.tensor([1, 2, 3, 4], dtype=torch.float32)
Y = torch.tensor([2, 4, 6, 8], dtype=torch.float32)
w2 = torch.tensor([0.0,0.0,0.0,0.0], requires_grad=True)
def forward(_x):
    return w2* _x #如果w2不是1個元素或者4個元素,這裡就無法相乘
learning_rate = 0.01
n_iter = 100  # 迴圈次數
loss =nn.MSELoss()
optimizer =torch.optim.SGD([w2],lr=learning_rate)
for epoch in range(n_iter):
    y_pred = forward(X)# 
    l = loss(Y, y_pred) 
    l.backward()  
    optimizer.step() 
    optimizer.zero_grad() 
    if epoch % 1 == 0:
        print(f'epoch {epoch+1}:w21= {w2[0]:.3f} w22= {w2[1]:.3f}  ,loss = {l:.8f}')

思維邏輯重述

回憶一下前面將的青蛙例子,我們重新敘述一下這個計算邏輯,首先我們有個y,這個是我們的目標,然後有個x,這個是我們的輸入資料。然後透過w和b這倆引數,結合公式y=wx+b,一次一次的嘗試求出w和b,然後透過求出的w和b修正x,然後我們得到了一個新的矩陣——修正x;我們令y_predict=x修正矩陣,就形成了x透過變化得到了預測y,即y_predict。然後我們就可以比較y和y_predict了。

torch.nn簡介

torch.nn 是 PyTorch 的一個核心模組,專門用於構建和訓練神經網路。這個模組提供了各種類和函式,使你可以方便地定義神經網路模型、實現前向傳播和反向傳播、定義損失函式,以及進行引數最佳化等任務。

Linear

torch.nn.Linear的概念是PyTorch 中用於實現線性變換(全連線層)的模組。這裡我們先無視他的定義。
先看幾個變數的含義。
X.shape:返回的是一個 torch.Size 物件 形狀資訊分別是 行數(樣本數)和列數(特徵數),這裡特別注意樣本和特徵這倆詞,這是倆干擾我們學習非常狠的名詞,注意這個特徵並不是我們線性代數里透過計算得到的特徵值或特徵向量,他就是矩陣的列數量。
nn.Linear(input_size, output_size):這是例項化Linear,入參是倆數,分別叫做input_size, output_size,這倆引數的含義如下。

反人類的定義

input_size:是輸入特徵的數量,也就是每個輸入樣本的維度。
output_size:是輸出特徵的數量,也就是模型希望輸出的特徵維度。

正常定義

input_size:表示輸入資料 X 的列數。
output_size:表示模型預測輸出 y_predict 的列數。
注:這裡要把反人類的定義多看幾遍,因為,如果你學習人工智慧,你會在各種影片和文章中看到別人用反人類定義來描述操作與問題。如果不能很好的轉換這個理解,就只能等著被噁心吧。
這裡,我們可以稍微思考一下,就可以根據input_size和output_size的分別傳入推測出一個結論,那就是我們可以輸入3 * 3的矩陣x,然後利用torch.nn這個庫,輸出成4 * 4的矩陣,然後再和4 * 4矩陣y比較。
不過Linear的話,要求輸入和輸出矩陣的維度必須匹配,所以,這裡我們是不用這麼做的,不過稍微聯想一下即可得出結論,多層神經網路或其他層(如卷積層)肯定可以做這樣複雜的對映。
Linear使用程式碼如下:

import torch
import numpy as np
import torch.nn as nn

X = torch.tensor([[1], [2], [3], [4]], dtype=torch.float32)
Y = torch.tensor([[2], [4], [6], [8]], dtype=torch.float32)

n_samples, n_features = X.shape  # x是4行1列矩陣,這裡返回4和1
print("n_samples", n_samples, "n_features", n_features)
input_size = n_features
output_size = n_features
model = nn.Linear(input_size, output_size)

learning_rate = 0.01
n_iter = 100  # 迴圈次數
loss = nn.MSELoss()
[w, b]= model.parameters()
optimizer = torch.optim.SGD([w, b], lr=learning_rate)

for epoch in range(n_iter):
    y_pred = model(X)  # 這裡的 model(X) 呼叫的是 model 的 forward 方法
    l = loss(Y, y_pred)
    l.backward()
    optimizer.step()
    optimizer.zero_grad()
    if epoch % 1 == 0:
        [w, b] = model.parameters()
        print(f'epoch {epoch+1}:w2= {w[0][0].item():.3f} ,loss = {l:.8f}')

如上程式碼,我們使用model = nn.Linear(input_size, output_size)定義了一個線性模型物件。
然後使用 torch.optim.SGD時,傳入了model.parameters()的返回值。
model.parameters()的返回值就是w和b。model.parameters()在被呼叫後,會在內部建立一個w和一個b。
權重矩陣 w:形狀為 [output_size, input_size]。
偏置向量 b:形狀為 [output_size]。
然後我們使用model(x)呼叫這個例項,這裡Linear類裡應該是實現了__call__方法,所以類的例項可以像函式一樣被呼叫。
這裡我們傳遞了x,有了x它就可以前向傳播了,即,model(x)裡我們傳遞了x,同時觸發了前向傳播。
所以,model(x)的返回值是一個預測的y值。
然後我們使用我們透過nn.MSELoss()定義的[標量函式/損失函式]來進行計算標量。
然後這個標量就可以使用反向傳播了。
然後,我們就得到了模型引數w和b的值了。

nn.Module簡介

nn.Module 是 PyTorch 中所有神經網路模組的基類。所有的神經網路層(如線性層、卷積層、LSTM 等)都繼承自這個類。
透過繼承 nn.Module,可以定義自己的網路層或模型,並利用 PyTorch 的自動微分功能來進行訓練。
nn.Linear 是 nn.Module 的子類,是一個特定的神經網路層類,繼承自 nn.Module。它實現了一個最簡單的線性變換層,也叫全連線層。
透過繼承 nn.Module,nn.Linear 能夠利用 nn.Module 提供的所有功能,比如註冊引數、前向傳播、儲存和載入模型等。
結構如下:

# nn.Module
#    |
#    |-- nn.Linear
#    |-- nn.Conv2d
#    |-- nn.RNN
#    |-- (Other Modules)

下面自定義一個類,繼承Module實現Linear的程式碼:

X = torch.tensor([[1], [2], [3], [4]], dtype=torch.float32)  # 4行1列矩陣
Y = torch.tensor([[2], [4], [6], [8]], dtype=torch.float32)

n_samples, n_features = X.shape
print("n_samples", n_samples, "n_features", n_features)
input_size = n_features
output_size = n_features

# model = nn.Linear(input_size, output_size) 
class LinearRegression(nn.Module):
    def __init__(self, input_dim, output_dim):
        super(LinearRegression,self).__init__()
        # define layers
        self.lin = nn.Linear(input_dim, output_dim)
    def forward(self, x):return self.lin(x)
model =LinearRegression(input_size, output_size)

learning_rate = 0.01
n_iter = 100  # 迴圈次數
loss = nn.MSELoss()
[w, b]= model.parameters()

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

for epoch in range(n_iter):
    y_pred = model(X)
    l = loss(Y, y_pred)
    l.backward()
    optimizer.step()
    optimizer.zero_grad()  # 梯度清零

    if epoch % 1 == 0:
        [w, b] = model.parameters()
        print(f'epoch {epoch+1}:w2= {w[0][0].item():.3f} ,loss = {l:.8f}')

傳送門:
零基礎學習人工智慧—Python—Pytorch學習(一)
零基礎學習人工智慧—Python—Pytorch學習(二)
零基礎學習人工智慧—Python—Pytorch學習(三)
零基礎學習人工智慧—Python—Pytorch學習(四)
學習就先到這。


注:此文章為原創,任何形式的轉載都請聯絡作者獲得授權並註明出處!



若您覺得這篇文章還不錯,請點選下方的【推薦】,非常感謝!

https://www.cnblogs.com/kiba/p/18354543

相關文章