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

kiba518發表於2024-08-09

前言

這篇文章主要兩個內容。
一,把上一篇關於requires_grad的內容補充一下。
二,介紹一下線性迴歸。

關閉張量計算

關閉張量計算。這個相對簡單,閱讀下面程式碼即可。

print("============關閉require_grad==============")
x = torch.randn(3, requires_grad=True)
print(x)
x.requires_grad_(False)  # 關閉x的張量計算

print("關閉x的張量計算後的x:", x)  # 沒有requires_grad屬性了

x = torch.randn(3, requires_grad=True)
print("新的帶張量計算的x:", x)
y = x.detach()  # 去出x的張量附加屬性,返回普通張量
print("y沒有張量屬性:", y)
print("x還有張量屬性:", x)
print("============區域內去除x的張量附加屬性==============")
with torch.no_grad():
    y = x+2
    print("y沒有張量屬性:", y)
print("x還有張量屬性:", x)

一個有趣的例子

程式碼1如下,程式碼可以正常執行。

x = torch.tensor(1.0)
y = torch.tensor(2.0)
w = torch.tensor(1.0, requires_grad=True)
y_hat = w*x
loss = (y_hat-y)**2
print(loss)
loss.backward()
print(w.grad)

程式碼2如下,下面程式碼不能執行。

x = torch.tensor([1.0,2.0])
y = torch.tensor([1.0,2.0])
w = torch.tensor([1.0,2.0],requires_grad=True)
y_hat = w*x
loss =(y_hat-y)**2
print(loss)
loss.backward()
print(w.grad)

這是因為程式碼1的loss是個值,是個標量,所以它可以執行backward。
而程式碼2的loss是個向量,他不能執行backward。

線性迴歸 linear regression

很多影片或文章都說,深度學習要先理解線性迴歸。然後,大家一翻線性迴歸的影片,又是一堆。
其實,完全不用看那些課程,不用耽誤那些時間。而且,你耽誤了那些時間,也未必能理解。
線性迴歸是要學,但不用刷影片學,其實簡單幾句話就能講明白的。只是沒人好好講而已,似乎都等著我們花費非常多的時間自己研究,自己開悟。

線性迴歸快速理解

首先理解線性是什麼。
A=2,B=4,我們肉眼識別B是A的2倍,所以,我們就可以說A和B有關係,是什麼關係呢?就是線性關係;線性就是這個意思,就說倆數有關係。
我們現在有了線性這個詞了,今後遇到倆數有倍數關係,我們就直接說倆數有線性關係,這樣就高大上了。
上篇文章提過,名詞是我們學習阻礙,線性這個名詞就是具體體現了。
迴歸就是我們找到B是A的2倍的過程。簡單來說,線性迴歸就是找到一個數,這個數指明瞭A和B的關係。
找A和B關係,用函式表示,就是y=wx+b;A帶入x,B帶入y。肉眼推測結果w=2,b=0。
現在把A和B換成倆矩陣,然後w也就是一個矩陣,b還是一個常數。當我們求出w和b時,就是求出了A和B的線性關係。
到此,我們不用去看三四十個線性迴歸的影片,就已經對線性迴歸有概念了。

程式碼

我們直接看程式碼,x是特徵值,y是目標值。
例如我們有一個青蛙A的圖片,他的矩陣就是y,然後找一個青蛙B的圖片,x就是青蛙B的矩陣。
然後透過線性迴歸算出,青蛙B與青蛙A的線性關係(w和b)。
這裡輸入特徵x我們寫死,不用讀取青蛙B的矩陣;y也不用讀取青蛙A,也寫死。
然後定義w是一個跟x同型矩陣,然後定義b是一個0張量。
然後利用前面的知識使用backward求梯度,然後得到w.grad和b.grad。
w.grad和b.grad和w,b是同型張量,現在我們用w.grad和b.grad去修正w和b,修正時我們使用learning_rate學習率,確保一次只修改一點點。
然後反覆迭代多次,就得到了我們的關係(w和b)。
程式碼如下:

# 輸入特徵和目標值
x = torch.tensor([1.0, 2.0])
y = torch.tensor([115.0, 21.0]) 

# 權重初始化(包括偏差項)
w = torch.tensor([1.0, 2.0], requires_grad=True)
b = torch.tensor(0.0, requires_grad=True)

# 學習率
learning_rate = 0.01

# 迭代多次進行最佳化
for epoch in range(100):
    # 預測
    y_hat = w * x + b
    
    # 損失函式
    loss = (y_hat - y).pow(2).mean()
    
    # 反向傳播
    loss.backward()
    
    # 更新權重和偏差
    with torch.no_grad():
        w -= learning_rate * w.grad
        b -= learning_rate * b.grad
    
    # 清零梯度
    w.grad.zero_()
    b.grad.zero_()

    print(f'Epoch {epoch + 1}, Loss: {loss.item()}')

# 最終模型引數
print("Final weights:", w)
print("Final bias:", b)

執行如下圖:
image

如圖,我迴圈了100次,但loss的值還是比較大,loss的含義是,越接近0,這個w和b的值就越精確。
當然,如果青蛙A和B實在是不像,那可能迴圈了1000次,loss還是會很大。
這裡我們迴圈100次後w=[51.8260,-9.4314] b=45.1103
現在我們使用y=wx+b帶入x、w、b得到y_pred=51.8260 * 1 +45.1103= 96.9363。我們的y的第一項是115.0。
可以看到x透過wx+b得到的預測值,已經變的很接近y的真實值了。

現在修改執行2000次,執行如下圖:
image

y=wx+b帶入x、w、b得到y_pred=62.4444 * 1 +52.5554= 114.9998。
而我們的y的第一項是115.0。
可以看到,預測值已經非常接近真實值了。

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}')

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


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



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

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

相關文章