[軟體工程]——PyTorch基礎
阿新 • • 發佈:2021-10-04
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%左右,效果非常明顯。