重磅!PyTorch 1.2.0 版本來啦!快來 get 這個新技能!讓你快速熟練掌握深度學習框架!
1070
2025-04-01
三階多項式擬合正弦函數(numpy, ndarray)
張量
直接由數據得到
由NumPy array得到
由另一個張量得到
初始化隨機或常量值張量
三階多項式擬合正弦函數(numpy, ndarray)
張量
直接由數據得到
由NumPy array得到
由另一個張量得到
初始化隨機或常量值張量
張量的屬性
張量運算
標準numpy式的索引和切片
連接張量[2]
算術運算
單元素張量
就地(In-place)操作[3]
張量與Numpy 數組
張量 到 NumPy 數組
NumPy 數組 到 張量
三階多項式擬合正弦函數(pytorch,tensor)
三階多項式擬合正弦函數(numpy, ndarray)
Numpy是科學計算的框架,不是專門用于計算圖、深度學習或梯度的。但我們可以使用numpy實現網絡的正向和反向傳播。例如,用三階多項式擬合正弦函數:
# -*- coding: utf-8 -*- import numpy as np import math import time time_start = time.time() # 隨機初始化輸入和輸出數據 x = np.linspace(-math.pi, math.pi, 2000) y = np.sin(x) # 隨機初始化權重 a = np.random.randn() b = np.random.randn() c = np.random.randn() d = np.random.randn() learning_rate = 1e-6 for t in range(2000): # 前向傳播:計算預測值 y # y = a + b x + c x^2 + d x^3 y_pred = a + b * x + c * x ** 2 + d * x ** 3 # 計算損失 loss = np.square(y_pred - y).sum() if t % 100 == 99: print(f'迭代次數:{t+1},損失值:{loss}') # 反向傳播:計算損失關于a, b, c, d 的梯度 grad_y_pred = 2.0 * (y_pred - y) grad_a = grad_y_pred.sum() grad_b = (grad_y_pred * x).sum() grad_c = (grad_y_pred * x ** 2).sum() grad_d = (grad_y_pred * x ** 3).sum() # 梯度下降更新權重 a -= learning_rate * grad_a b -= learning_rate * grad_b c -= learning_rate * grad_c d -= learning_rate * grad_d time_end = time.time() print('消耗時間:', time_end - time_start, 's') print(f'結果: y = {a} + x + {c} x^2 + gs2w0wm x^3')
輸出:
... ... 迭代次數:2000,損失值:9.68922650914574 消耗時間: 0.6189007759094238 s 結果: y = -0.03123761638932383 + 0.8577752449653959 x + 0.0053890086233387485 x^2 + -0.09347752370202965 x^3
既然numpy也可以實現網絡的正向和反向傳播,那為什么還要pytorch呢?
Numpy是一個很棒的框架,但它不能利用GPU來加速計算,這使得它不適用于大計算量的深度學習。而pytorch的一種數據結構——張量(tensor)則可以在GPU或其他硬件加速器上運行。另外,pytorch的自動求導機制,能自動的幫我們把反向傳播全部計算好。
下面,我們將進入本文的主題:張量(tensor)。
張量
張量(tensor)是一種特殊的數據結構,與數組和矩陣非常相似。在pytorch中,我們使用張量對模型的輸入和輸出以及模型的參數進行編碼。張量與NumPy的數組很相似,只是它可以在GPU或其他硬件加速器上運行。
In[2]: import torch In[3]: import numpy as np
直接由數據得到
使用torch.tensor()
In[4]: data = [[1, 2],[3, 4]] In[5]: x_data = torch.tensor(data) In[6]: x_data Out[6]: tensor([[1, 2], [3, 4]])
由NumPy array得到
使用torch.from_numpy()
np_array = np.array(data) x_np = torch.from_numpy(np_array) x_np Out[9]: tensor([[1, 2], [3, 4]], dtype=torch.int32)
由另一個張量得到
除非顯式重寫,否則新的張量將保留參數張量的屬性(形狀、數據類型)。
In[10]: x_ones = torch.ones_like(x_data) In[11]: x_ones Out[11]: tensor([[1, 1], [1, 1]]) In[12]: x_rand = torch.rand_like(x_data, dtype=torch.float) # 類型重寫 In[13]: x_rand Out[13]: tensor([[0.2792, 0.9185], [0.5906, 0.8662]]) In[14]: x_rand.dtype Out[14]: torch.float32
初始化隨機或常量值張量
shape是表示張量維度的元組。在下面的函數中,它決定了輸出張量的維數。
In[15]: shape = (2,3,) ...: rand_tensor = torch.rand(shape) ...: ones_tensor = torch.ones(shape) ...: zeros_tensor = torch.zeros(shape) In[16]: rand_tensor Out[16]: tensor([[0.3380, 0.0584, 0.5423], [0.6003, 0.6216, 0.9982]]) In[17]: ones_tensor Out[17]: tensor([[1., 1., 1.], [1., 1., 1.]]) In[18]: zeros_tensor Out[18]: tensor([[0., 0., 0.], [0., 0., 0.]])
張量的屬性
張量屬性描述它們的形狀(shape)、數據類型(dtype)和存儲它們的設備(device)。
In[19]: tensor = torch.rand(3,4) In[20]: tensor.shape Out[20]: torch.Size([3, 4]) In[21]: tensor.dtype Out[21]: torch.float32 In[22]: tensor.device Out[22]: device(type='cpu')
張量運算
pytorch對張量有超過100種運算操作(傳送門)。每個操作都可以在GPU上運算(速度通常高于CPU)。
默認情況下,創建張量都是在CPU上運算。我們需要使用.to顯式地將張量移動到GPU中(在GPU可用的前提下)。但請記住,跨設備復制大量張量需要耗費許多時間和內存!
In[23]: tensor Out[23]: tensor([[0.0061, 0.1010, 0.5185, 0.8282], [0.7172, 0.8436, 0.0652, 0.0033], [0.2006, 0.7263, 0.8957, 0.8063]]) In[25]: # 如果GPU可用,將張量移動到GPU ...: if torch.cuda.is_available(): ...: tensor = tensor.to('cuda') In[26]: tensor Out[26]: tensor([[0.0061, 0.1010, 0.5185, 0.8282], [0.7172, 0.8436, 0.0652, 0.0033], [0.2006, 0.7263, 0.8957, 0.8063]], device='cuda:0')
下面列舉一些簡單的操作。如果你熟悉NumPy API,您會發現Tensor API很容易使用。
標準numpy式的索引和切片
In[33]: tensor = torch.rand(4, 4) In[34]: tensor Out[34]: tensor([[0.1227, 0.2580, 0.4331, 0.9736], [0.3351, 0.5426, 0.5793, 0.1816], [0.7569, 0.6747, 0.0966, 0.9883], [0.1359, 0.1780, 0.0796, 0.9142]]) In[35]: tensor[0] # 第一行 Out[35]: tensor([0.1227, 0.2580, 0.4331, 0.9736]) In[36]: tensor[:, 0] #第一列 Out[36]: tensor([0.1227, 0.3351, 0.7569, 0.1359]) In[37]: tensor[..., -1] # 最后一列 Out[37]: tensor([0.9736, 0.1816, 0.9883, 0.9142])
連接張量[2]
連接張量有兩種方法:torch.cat()或torch.stack()
In[39]: tensor = torch.ones(2, 3) In[40]: tensor Out[40]: tensor([[1., 1., 1.], [1., 1., 1.]])
首先看一下torch.cat():
dim=1時,形狀變為[2, 6]
In[41]: t1 = torch.cat([tensor, tensor, tensor], dim=1) In[42]: t1 Out[42]: tensor([[1., 1., 1., 1., 1., 1., 1., 1., 1.], [1., 1., 1., 1., 1., 1., 1., 1., 1.]])
dim=0時,形狀變為[6, 2]
In[43]: t0 = torch.cat([tensor, tensor, tensor], dim=0) In[44]: t0 Out[44]: tensor([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.], [1., 1., 1.], [1., 1., 1.], [1., 1., 1.]])
與torch.cat()不同,torch.stack()是沿著一個新維度對輸入張量序列進行連接。 序列中所有的張量都應該為相同形狀。
淺顯說法:就是把多個2維的張量湊成一個3維的張量;多個3維的湊成一個4維的張量……以此類推,也就是在增加新的維度進行堆疊。
例子:
準備2個[3,3]的張量數據。
In[45]: T1 = torch.tensor([[1, 2, 3], ...: [4, 5, 6], ...: [7, 8, 9]]) ...: T2 = torch.tensor([[10, 20, 30], ...: [40, 50, 60], ...: [70, 80, 90]])
dim=0時,形狀變為[2, 3, 3]
In[48]: stack_0=torch.stack((T1,T2),dim=0) In[49]: stack_0 Out[49]: tensor([[[ 1, 2, 3], [ 4, 5, 6], [ 7, 8, 9]], [[10, 20, 30], [40, 50, 60], [70, 80, 90]]]) In[50]: stack_0.shape Out[50]: torch.Size([2, 3, 3])
dim=1時,形狀變為[3, 2, 3]
In[51]: stack_1=torch.stack((T1,T2),dim=1) In[52]: stack_1 Out[52]: tensor([[[ 1, 2, 3], [10, 20, 30]], [[ 4, 5, 6], [40, 50, 60]], [[ 7, 8, 9], [70, 80, 90]]]) In[53]: stack_1.shape Out[53]: torch.Size([3, 2, 3])
dim=2時,形狀變為[3, 3, 2]
In[54]: stack_2=torch.stack((T1,T2),dim=2) In[55]: stack_2 Out[55]: tensor([[[ 1, 10], [ 2, 20], [ 3, 30]], [[ 4, 40], [ 5, 50], [ 6, 60]], [[ 7, 70], [ 8, 80], [ 9, 90]]]) In[56]: stack_2.shape Out[56]: torch.Size([3, 3, 2])
算術運算
下面是計算兩個張量之間的矩陣乘法的方法。y1、y2、y3將具有相同的值
In[62]: tensor=torch.ones(3,3) In[63]: y1 = tensor @ tensor.t() #.t():矩陣轉置 In[64]: y2 = tensor.matmul(tensor.t()) In[65]: y3 = torch.rand_like(tensor) In[66]: torch.matmul(tensor, tensor.t(), out=y3) Out[66]: tensor([[3., 3., 3.], [3., 3., 3.], [3., 3., 3.]]) In[67]: y1 Out[67]: tensor([[3., 3., 3.], [3., 3., 3.], [3., 3., 3.]]) In[68]: y2 Out[68]: tensor([[3., 3., 3.], [3., 3., 3.], [3., 3., 3.]]) In[69]: y3 Out[69]: tensor([[3., 3., 3.], [3., 3., 3.], [3., 3., 3.]])
下面將計算逐元素的乘積。z1、z2、z3將具有相同的值
In[70]: z1 = tensor * tensor In[71]: z2 = tensor.mul(tensor) In[72]: z3 = torch.rand_like(tensor) In[73]: torch.mul(tensor, tensor, out=z3); In[74]: z1 Out[74]: tensor([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]]) In[75]: z2 Out[75]: tensor([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]]) In[77]: z3 Out[77]: tensor([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]])
單元素張量
如果有一個單元素張量,例如將張量的所有值加起來得到一個值,那么可以使用item()將其轉換為Python數值:
In[82]: agg = tensor.sum() In[83]: agg Out[83]: tensor(9.) In[84]: agg_item = agg.item() In[85]: agg_item Out[85]: 9.0 In[86]: type(agg_item) Out[86]: float In[87]: type(agg) Out[87]: torch.Tensor
就地(In-place)操作[3]
就地操作是直接更改給定張量的內容而不會為變量分配新的內存進行復制。
將結果存儲到操作數中的操作稱為就地調用。它們由一個后綴表示。例如:x.copy_(y), x.t_()。這種操作將更改x。
In[88]: tensor Out[88]: tensor([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]]) In[89]: tensor.add_(5) Out[89]: tensor([[6., 6., 6.], [6., 6., 6.], [6., 6., 6.]]) In[90]: tensor Out[90]: tensor([[6., 6., 6.], [6., 6., 6.], [6., 6., 6.]])
注意:
就地操作可以節省一些內存,但在計算導數時可能會出現問題,因為會立即丟失歷史記錄。因此,不鼓勵使用它們。
張量與Numpy 數組
在CPU的tensor和NumPy的array會共享其底層內存,即更改其中一個的同時另一個也會被更改。
張量 到 NumPy 數組
In[91]: t = torch.ones(5) In[92]: n = t.numpy() In[93]: t Out[93]: tensor([1., 1., 1., 1., 1.]) In[94]: n Out[94]: array([1., 1., 1., 1., 1.], dtype=float32)
張量的改變將導致對應NumPy數組的改變。
In[95]: t.add_(1) Out[95]: tensor([2., 2., 2., 2., 2.]) In[96]: t Out[96]: tensor([2., 2., 2., 2., 2.]) In[97]: n Out[97]: array([2., 2., 2., 2., 2.], dtype=float32)
NumPy 數組 到 張量
In[99]: n = np.ones(5) In[99]: t = torch.from_numpy(n) In[100]: np.add(n, 1, out=n) Out[100]: array([2., 2., 2., 2., 2.]) In[101]: t Out[101]: tensor([2., 2., 2., 2., 2.], dtype=torch.float64) In[102]: n Out[102]: array([2., 2., 2., 2., 2.])
三階多項式擬合正弦函數(pytorch,tensor)
下面我們基于PyTorch的張量,將三階多項式擬合正弦函數。
# -*- coding: utf-8 -*- import torch import math import time time_start = time.time() dtype = torch.float device = torch.device("cpu") #device = torch.device("cuda:0") # 取消這一行注釋以在GPU上運行 # 隨機初始化輸入和輸出數據 x = torch.linspace(-math.pi, math.pi, 2000, device=device, dtype=dtype) y = torch.sin(x) # 隨機初始化權重 a = torch.randn((), device=device, dtype=dtype) b = torch.randn((), device=device, dtype=dtype) c = torch.randn((), device=device, dtype=dtype) d = torch.randn((), device=device, dtype=dtype) learning_rate = 1e-6 for t in range(2000): # 前向傳播:計算預測值 y y_pred = a + b * x + c * x ** 2 + d * x ** 3 # 計算損失 loss = (y_pred - y).pow(2).sum().item() if t % 100 == 99: print(f'迭代次數:{t + 1},損失值:{loss}') # 反向傳播:計算損失關于a, b, c, d 的梯度 grad_y_pred = 2.0 * (y_pred - y) grad_a = grad_y_pred.sum() grad_b = (grad_y_pred * x).sum() grad_c = (grad_y_pred * x ** 2).sum() grad_d = (grad_y_pred * x ** 3).sum() # 梯度下降更新權重 a -= learning_rate * grad_a b -= learning_rate * grad_b c -= learning_rate * grad_c d -= learning_rate * grad_d time_end = time.time() print('消耗時間:', time_end - time_start, 's') print(f'Result: y = {a.item()} + {b.item()} x + {c.item()} x^2 + {d.item()} x^3')
使用CPU,輸出:
... ... 迭代次數:2000,損失值:14.256892204284668 消耗時間: 0.8661777973175049 s Result: y = 0.05625741183757782 + 0.8070318698883057 x + -0.00970533862709999 x^2 + -0.08625971525907516 x^3
使用GPU,輸出:
... ... 迭代次數:2000,損失值:9.254937171936035 消耗時間: 8.750219345092773 s Result: y = -0.000127201754366979 + 0.8364022374153137 x + 2.19428966374835e-05 x^2 + -0.0904374048113823 x^3
???說好的GPU加速呢?
用電鋸切菜能快么,電鋸是用來砍樹的。同樣道理,GPU在大規模網絡才有明顯的加速。
GPU比CPU慢的原因大致為[4]:
數據傳輸會有很大的開銷,而GPU處理數據傳輸要比CPU慢,而GPU的專長矩陣計算在小規模神經網絡中無法明顯體現出來。
下面以單純的矩陣乘法做對比:
import torch import time a = torch.ones(10000, 1000) b = torch.ones(1000, 10000) t0 = time.time() c = torch.matmul(a, b) t1 = time.time() print('CPU:', t1 - t0, 's') device = torch.device('cuda') a = a.to(device) b = b.to(device) t0 = time.time() c = torch.matmul(a, b) t1 = time.time() print('GPU:', t1 - t0, 's')
輸出:
CPU: 2.434323310852051 s GPU: 0.5386180877685547 s
這不,快了。
參考:
[1] https://pytorch.org/tutorials/beginner/basics/tensorqs_tutorial.html
[2] https://blog.csdn.net/xinjieyuan/article/details/105205326
[3]https://zhuanlan.zhihu.com/p/344455805
[4]https://blog.csdn.net/qq_43673118/article/details/90305340
Numpy pytorch
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。