1 什么是pytorch?
PyTorch是一個基于Numpy的科學計算包,它主要有兩個特點:第一,是GPU加速的張量計算;第二,是構(gòu)建和訓練神經(jīng)網(wǎng)絡的強大支持。PyTorch是Facebook人工智能研究團隊開源的一個機器學習框架,它支持動態(tài)計算圖,這意味著可以按照想要的方式定義、修改和執(zhí)行計算圖,而不是預先定義靜態(tài)計算圖。這樣,PyTorch可以靈活地支持不同形式的計算圖,并且非常適合用于研究和實驗。同時,PyTorch也具有很好的可視化工具,方便用戶對模型進行調(diào)試和優(yōu)化。
2 張量
概念:幾何代數(shù)中定義的張量是基于向量和矩陣的推廣,比如我們可以將標量視為零階張量,矢量可以視為一階張量,矩陣就是二階張量

2.1張量創(chuàng)建
import torch
# 創(chuàng)建一個2x3的張量
x = torch.tensor([[1, 2, 3], [4, 5, 6]])
# 打印張量的形狀和數(shù)據(jù)類型
print(x.shape) # 輸出: torch.Size([2, 3])
print(x.dtype) # 輸出: torch.int64
# 創(chuàng)建一個隨機初始化的3x3浮點數(shù)張量
y = torch.rand(3, 3)
print(y)
# 創(chuàng)建一個隨機初始化的3x3浮點數(shù)張量,符合正態(tài)分布
y = torch.randn(3, 3)
print(y)
# 創(chuàng)建一個全0的5x5張量
z = torch.zeros(5, 5)
print(z)
# 創(chuàng)建一個全1的4x4張量
w = torch.ones(4, 4)
print(w)
# 創(chuàng)建一個等差數(shù)列的張量
a = torch.linspace(0, 1, 5)
print(a)
# 創(chuàng)建一個隨機整數(shù)的張量
b = torch.randint(low=0, high=10, size=(3, 3))
print(b)
x = x.new_ones(4, 3, dtype=torch.double)
# 創(chuàng)建一個新的全1矩陣tensor,返回的tensor默認具有相同的torch.dtype和torch.device
# 也可以像之前的寫法 x = torch.ones(4, 3, dtype=torch.double)
print(x)
x = torch.randn_like(x, dtype=torch.float)
# 重置數(shù)據(jù)類型
print(x)
# 結(jié)果會有一樣的size
# 獲取它的維度信息
print(x.size())
print(x.shape)
2.2 張量的操作
import torch
# 創(chuàng)建兩個張量
a = torch.tensor([[1, 2, 3], [4, 5, 6]])
b = torch.tensor([[2, 3, 4], [5, 6, 7]])
# 加法方式1
c = a + b
print(c)
# 方式2
print(torch.add(a, b))
# 方式3 in-place,原值修改
a.add_(b)
print(a)
# 減法
d = b - a
print(d)
# 乘法
e = a * b
print(e)
# 除法
f = b / a
print(f)
# 矩陣乘法
g = torch.matmul(a, b.T)
print(g)
# 求和
h = a.sum()
print(h)
# 求平均值
i = b.mean()
print(i)
# 求最大值
j = a.max()
print(j)
# 求最小值
k = b.min()
print(k)
# 如果x中只有一個元素,可以把x的數(shù)值取出來
print(type(x.item()))
# 怎么改變張量的形狀
a = b.view(16)
c = a.view(-1, 8) # -1是指這一維的維數(shù)由其他維度決定
print(a.size(), b.size(), c.size())
# Torch Tensors和Numpy array 共享底層的內(nèi)存空間,當改變其中的一個值,另外一個值也隨之被改變
a = torch.ones(5);# 5個1
print (a)
b = a.numpy(); #將tensor 轉(zhuǎn) numpy array
print (b)
a.add_(1); #改變a的值
print (a);
print (b);
a = np.ones(5);
print (a)
b = torch.from_numpy(a); # 將numpy array 轉(zhuǎn)tensor
print (b);
b.add_(1);
print (b);
print (a);
另外張量的計算時候需要注意在哪個設備上,若不同設備是不能參與計算的。
#判斷服務器上已經(jīng)安裝了cuda和GPU
if torch.cuda.is_available():
#將設備指定為GPU
device = torch.device("cuda");
#直接在GPU創(chuàng)建張量y,在CPU上創(chuàng)建張量X
x = torch.randn(1);
y = torch.ones_like(x,device=device);
#將X轉(zhuǎn)移到GPU上
x = x.to(device);
z = x.add(y); #此時和的結(jié)果z在GPU上
print (z);
print(z.to("cpu"),torch.double);
2.3 張量的實際意義
在電商中,通常需要對用戶-品牌-時間-購買行為等多維數(shù)據(jù)進行建模和分析。這些數(shù)據(jù)可以被理解為張量的不同維度,每個維度都代表著不同的特征或?qū)傩浴@?,假設我們需要對用戶-品牌-時間-購買行為進行建模,我們可以構(gòu)建一個四維張量來存儲這些數(shù)據(jù)。其中,第一維表示用戶,第二維表示品牌,第三維表示時間,第四維表示購買行為。張量中的每個元素則代表著對應維度上的具體數(shù)值,例如張量中[i, j, k, l]元素代表著第i個用戶在第j個品牌上在第k個時間點的購買行為。
通過這種方式,我們可以在PyTorch中輕松地對這些張量進行各種數(shù)學操作和函數(shù),例如對購買行為進行求和、求平均值、求最大值、求最小值等,或者對用戶-品牌-時間進行矩陣運算,以便提取特征和進行預測。通過PyTorch中的張量,我們可以將復雜的電商數(shù)據(jù)轉(zhuǎn)化為多維數(shù)組,從而更好地進行建模和分析,幫助電商企業(yè)實現(xiàn)數(shù)據(jù)驅(qū)動決策和智能化運營。
import torch
# 創(chuàng)建一個四維張量表示用戶-品牌-時間-購買行為
tensor = torch.randn(10, 5, 20, 2)
# 求購買行為的總和
buy_sum = tensor[:, :, :, 1].sum()
print("購買行為總和:", buy_sum)
# 求用戶-品牌的交叉統(tǒng)計
user_brand_count = tensor.sum(dim=2)
print("用戶-品牌交叉統(tǒng)計:\n", user_brand_count)
# 對時間進行降維,求平均值
time_mean = tensor.mean(dim=2)
print("時間降維后的平均值:\n", time_mean)
# 對用戶-品牌進行矩陣運算
user_brand_tensor = tensor[:, :, 0, :]
user_tensor = user_brand_tensor.sum(dim=1)
brand_tensor = user_brand_tensor.sum(dim=0)
user_brand_matrix = torch.matmul(user_tensor.T, brand_tensor)
print("用戶-品牌矩陣:\n", user_brand_matrix)
上述代碼中,我們首先創(chuàng)建了一個四維張量tensor,表示用戶-品牌-時間-購買行為。然后,我們對這個張量進行了各種數(shù)學操作和函數(shù)。具體來說,我們使用sum()函數(shù)對購買行為進行求和,使用sum(dim=2)函數(shù)對用戶-品牌進行交叉統(tǒng)計,使用mean(dim=2)函數(shù)對時間進行降維,使用matmul()函數(shù)對用戶-品牌進行矩陣運算,以獲得用戶-品牌之間的相關性。這些操作可以幫助我們更好地理解和分析電商數(shù)據(jù)。
import torch
# 創(chuàng)建一個2x3的張量
x = torch.tensor([[1, 2, 3], [4, 5, 6]])
# 創(chuàng)建一個1x3的張量
y = torch.tensor([10, 20, 30])
# 對x和y進行加法
z = x + y
print(z)
#輸出如下
tensor([[1, 2, 3],
[4, 5, 6]])
tensor([10, 20, 30])
tensor([[11, 22, 33],
[14, 25, 36]])
在這個示例中,我們創(chuàng)建了一個2x3的張量x和一個1x3的張量y。兩個張量在第一維上的形狀不一致,但由于PyTorch支持廣播機制,系統(tǒng)會自動地將y進行擴展,使得它的形狀變?yōu)?x3,然后再和x進行加法運算。最終的結(jié)果是一個2x3的張量z,其中每個元素都是對應位置上x和y元素的和。在實際應用中,廣播機制可以大大簡化計算過程,避免了對數(shù)據(jù)進行顯式的擴展和復制。例如,在深度學習中,廣播機制可以使得模型對不同形狀的輸入數(shù)據(jù)進行處理,從而提高模型的通用性和適用性。同時,廣播機制還可以使得模型的參數(shù)共享,從而減少模型的參數(shù)量,提高模型的訓練效率。
3 自動求導和梯度
PyTorch中的自動求導機制是通過autograd模塊實現(xiàn)的,該模塊可以自動地對張量進行求導,同時還支持高階求導和自定義求導函數(shù)。在PyTorch中,每個張量都有一個requires_grad屬性,當設置為True時,表示需要對該張量進行求導。
下面是一個簡單的示例,說明如何使用PyTorch中的自動求導機制
import torch
# 創(chuàng)建一個張量,并設置requires_grad=True
x = torch.tensor([2.0], requires_grad=True)
# 定義一個函數(shù)y=x^2+2x+1
y = x ** 2 + 2 * x + 1
# 對y進行求導
y.backward()
# 打印x的梯度
print(x.grad)
在這個示例中,我們創(chuàng)建了一個張量x,并將requires_grad屬性設置為True,表示需要對它進行求導。然后,我們定義一個函數(shù)y=x^2+2x+1,并對它進行求導,即調(diào)用backward()函數(shù)。最后,我們打印x的梯度,即可得到y(tǒng)對x的導數(shù),即4。這里的梯度,需要重點總結(jié)一下,梯度是指函數(shù)在某一點處的變化率,它是一個向量,包含了函數(shù)在每個自變量維度上的偏導數(shù)。
我們可以看一個稍微更復雜的函數(shù),z= y^2 - x^2,那么z在自變量x上的倒數(shù)是-2x,在y自變量上的倒數(shù)是-2y。

import torch
# 創(chuàng)建一個張量,并設置requires_grad=True
x = torch.tensor([2.0], requires_grad=True)
y = torch.tensor([3.0], requires_grad=True)
# 定義一個函數(shù)z=y^2 - x^2
z = y ** 2 - x ** 2;
# 對y進行求導
z.backward()
# 打印x的梯度
print (z)
print(y.grad)
print(x.grad)
print ('x.requires_grad=',x.requires_grad,'y.requires_grad=',y.requires_grad,'z.requires_grad=',z.requires_grad)
# 輸出
tensor([5.], grad_fn=<SubBackward0>)
tensor([6.])
tensor([-4.])
x.requires_grad= True y.requires_grad= True z.requires_grad= True
關于自動求導的”自動“怎么理解?z并沒有指定requires_grad = true, 但是由于x和y被設置了,z也被自動的設置為了requires_grad = true。
4 線性回歸模型
這段代碼定義了一個簡單的線性模型(LinearModel),并使用均方差損失函數(shù)(mean_squared_error)和梯度下降法(train)進行訓練。訓練數(shù)據(jù)是輸入x_train和輸出y_train。在訓練過程中,首先通過正向傳播(model.forward)計算模型的預測輸出(y_pred),然后計算損失(loss),接著通過反向傳播(計算梯度dW和db)更新模型的權(quán)重和偏置(model.W和model.b)。訓練過程會迭代num_epochs次,每10次輸出當前的損失值。最終訓練得到的模型可以用于預測新的輸入數(shù)據(jù)。
import torch
import numpy as np
# 模型定義
class LinearModel:
def __init__(self, input_size, output_size):
self.W = np.random.randn(input_size, output_size) # 隨機初始化權(quán)重
self.b = np.zeros((output_size, 1)) # 初始化偏置
def forward(self, x):
return np.dot(x, self.W) + self.b
# 損失函數(shù)
def mean_squared_error(y_true, y_pred):
return np.mean((y_true - y_pred) ** 2)
# 訓練過程
def train(model, x_train, y_train, learning_rate, num_epochs):
for epoch in range(num_epochs):
# 正向傳播
y_pred = model.forward(x_train)
# 計算損失
loss = mean_squared_error(y_train, y_pred)
# 反向傳播(梯度下降法更新參數(shù))
dW = np.dot(x_train.T, (y_pred - y_train)) / x_train.shape[0] # 權(quán)重梯度
db = np.mean(y_pred - y_train, axis=0, keepdims=True).T # 偏置梯度
model.W -= learning_rate * dW
model.b -= learning_rate * db
if epoch % 10 == 0:
print(f"Epoch {epoch}, Loss: {loss}")
if __name__ == '__main__':
x_train = np.array([[1, 2, 3], [4, 5, 6]])
y_train = np.array([[3], [7]])
model = LinearModel(input_size=3, output_size=1)
train(model, x_train, y_train, learning_rate=0.01, num_epochs=100)
輸出:
Epoch 0, Loss: 153.96475781916735
Epoch 10, Loss: 0.5371193011886801
Epoch 20, Loss: 0.49120240483116584
Epoch 30, Loss: 0.4497690875642887
Epoch 40, Loss: 0.41183070630810104
Epoch 50, Loss: 0.3770924577692135
Epoch 60, Loss: 0.34528440820059597
Epoch 70, Loss: 0.3161593929820811
Epoch 80, Loss: 0.28949109602634426
Epoch 90, Loss: 0.2650722911885265