1. 程式人生 > 其它 >[軟體工程]——PyTorch基礎

[軟體工程]——PyTorch基礎

PyTorch基礎

在學習pytorch基礎語法時,直接執行以下段時報錯。

import torch
m = torch.Tensor([[2,5,3,7], [4,2,1,9]])
v = torch.arange(1, 5)
print(m @ v) # @ 點積運算

# RuntimeError: expected scalar type Float but found Long

這是因為tensor的資料型別不匹配造成的問題。

# torch.Tensor()是Python類,是預設張量型別torch.FloatTensor()的別名,生成單精度浮點型別的張量。
x = torch.Tensor([1, 2 ,3, 4])

#torch.tensor()僅僅是Python的函式,根據原始資料型別生成相應的torch.LongTensor
x = torch.tensor([1, 2, 3, 4])

因此我們在使用時,需要注意型別統一,可以使用dtype進行設定

v = torch.arange(1, 5, dtype = torch.float)
print(m @ v)

螺旋資料分類demo

初始化一些引數

import random
import torch
from torch import nn, optim
import math
from IPython import display
from plot_lib import plot_data, plot_model, set_default

# 在cpu上執行torch 
device = torch.device("
cuda:0" if torch.cuda.is_available() else "cpu") print('device: ', device) # 初始化隨機數種子。神經網路的引數都是隨機初始化的, # 不同的初始化引數往往會導致不同的結果,當得到比較好的結果時我們通常希望這個結果是可以復現的, # 因此,在pytorch中,通過設定隨機數種子也可以達到這個目的 seed = 12345 random.seed(seed) torch.manual_seed(seed) N = 1000 # 每類樣本的數量 D = 2 # 每個樣本的特徵維度 C = 3 # 樣本的類別 H = 100 #
神經網路裡隱層單元的數量

構造樣本

X = torch.zeros(N * C, D).to(device)
Y = torch.zeros(N * C, dtype=torch.long).to(device)
for c in range(C):
    index = 0
    t = torch.linspace(0, 1, N) # 在[0,1]間均勻的取10000個數,賦給t
    # 下面的程式碼不用理解太多,總之是根據公式計算出三類樣本(可以構成螺旋形)
    # torch.randn(N) 是得到 N 個均值為0,方差為 1 的一組隨機數,注意要和 rand 區分開
    inner_var = torch.linspace( (2*math.pi/C)*c, (2*math.pi/C)*(2+c), N) + torch.randn(N) * 0.2
    
    # 每個樣本的(x,y)座標都儲存在 X 裡
    # Y 裡儲存的是樣本的類別,分別為 [0, 1, 2]
    for ix in range(N * c, N * (c + 1)):
        X[ix] = t[index] * torch.FloatTensor((math.sin(inner_var[index]), math.cos(inner_var[index])))
        Y[ix] = c
        index += 1

print("Shapes:")
print("X:", X.size())
print("Y:", Y.size())

其中,

X可以理解為特徵矩陣,共有3000個樣本,每個樣本的特徵維度是2維,因此X是一個N*C行,D列的矩陣。

Y可以理解為樣本標籤,所以是一個N*C行的一維矩陣

最後得出的樣本是這個樣子的:

構建線性模型分類

learning_rate = 1e-3
lambda_l2 = 1e-5

# nn 包用來建立線性模型
# 每一個線性模型都包含 weight 和 bias
model = nn.Sequential(
    nn.Linear(D, H), # 2*100
    nn.Linear(H, C)  # 100*3
)
model.to(device)

# nn 包含多種不同的損失函式,這裡使用的是交叉熵(cross entropy loss)損失函式
criterion = torch.nn.CrossEntropyLoss()

# 這裡使用 optim 包進行隨機梯度下降(stochastic gradient descent)優化
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate, weight_decay=lambda_l2)

# 開始訓練
for t in range(1000):
    # 把資料輸入模型,得到預測結果
    y_pred = model(X)
    # 計算損失和準確率
    loss = criterion(y_pred, Y)
    score, predicted = torch.max(y_pred, 1)
    acc = (Y == predicted).sum().float() / len(Y)
    print('[EPOCH]: %i, [LOSS]: %.6f, [ACCURACY]: %.3f' % (t, loss.item(), acc))
    display.clear_output(wait=True)

    # 反向傳播前把梯度置 0 
    optimizer.zero_grad()
    # 反向傳播優化 
    loss.backward()
    # 更新全部引數
    optimizer.step()

其中,

nn.Sequential是一個有序容器,神經網路模組將按照傳入構造器的順序依次被新增到計算圖中執行。

nn.Linear用於設定神經網路的全連線層, 在二維影象處理中,其輸入輸出一般是二維張量。

這裡直接使用了兩個線性模型,第一個是2*100(2個特徵維度到100個隱層單元),第二個是100*3(100個隱層單元到最終的3個類別)

我們打印出model來,也可以看到這樣的結構。

print(model)
'''
Sequential(
  (0): Linear(in_features=2, out_features=100, bias=True)
  (1): Linear(in_features=100, out_features=3, bias=True)
)
'''

最終,線性模型的分類效果如下,可以看到分類的結果是線性的。

其正確率只有50%左右,效果較差。

構建兩層神經網路分類

我們在原先的線性模型中進行一些改動,主要是在model中加入一個啟用函式ReLU,使其變成一個兩層的神經網路

learning_rate = 1e-3
lambda_l2 = 1e-5

# 這裡可以看到,和上面模型不同的是,在兩層之間加入了一個 ReLU 啟用函式
model = nn.Sequential(
    nn.Linear(D, H),
    nn.ReLU(),      # 加入了啟用函式ReLU
    nn.Linear(H, C)
)
model.to(device)

# 下面的程式碼和之前是完全一樣的,這裡不過多敘述
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate, weight_decay=lambda_l2) # built-in L2

# 訓練模型,和之前的程式碼是完全一樣的
for t in range(1000):
    y_pred = model(X)
    loss = criterion(y_pred, Y)
    score, predicted = torch.max(y_pred, 1)
    acc = ((Y == predicted).sum().float() / len(Y))
    print("[EPOCH]: %i, [LOSS]: %.6f, [ACCURACY]: %.3f" % (t, loss.item(), acc))
    display.clear_output(wait=True)
    
    # zero the gradients before running the backward pass.
    optimizer.zero_grad()
    # Backward pass to compute the gradient
    loss.backward()
    # Update params
    optimizer.step()

因為線性模型的表達力不夠,所以我們使用了啟用函式,用來加入非線性因素。

ReLU函式很簡單,表達形式如下:

f(x) = max(0, max)

加入ReLU函式的兩層神經網路最終的分類效果如下:

其準確率已經達到了95%左右,效果非常明顯。