筆記
1 張量索引操作
import torch
?
# 下標從左到右從0開始(0->第一個值), 從右到左從-1開始
# data[行下標, 列下標]
# data[0軸下標, 1軸下標, 2軸下標]
?
def dm01():# 創建張量torch.manual_seed(0)data = torch.randint(low=0, high=10, size=(4, 5))print('data->', data)# 根據下標值獲取對應位置的元素# 行數據 第一行print('data[0] ->', data[0])# 列數據 第一列print('data[:, 0]->', data[:, 0])# 根據下標列表取值# 第二行第三列的值和第四行第五列值print('data[[1, 3], [2, 4]]->', data[[1, 3], [2, 4]])# [[1], [3]: 第二行第三列 第二行第五列值 ? 第四行第三列 第四行第五列值print('data[[[1], [3]], [2, 4]]->', data[[[1], [3]], [2, 4]])# 根據布爾值取值# 第二列大于6的所有行數據print(data[:, 1] > 6)print('data[data[:, 1] > 6]->', data[data[:, 1] > 6])# 第三行大于6的所有列數據print('data[:, data[2]>6]->', data[:, data[2] > 6])# 根據范圍取值 切片 [起始下標:結束下標:步長]# 第一行第三行以及第二列第四列張量print('data[::2, 1::2]->', data[::2, 1::2])
?# 創建三維張量data2 = torch.randint(0, 10, (3, 4, 5))print("data2->", data2)# 0軸第一個值print(data2[0, :, :])# 1軸第一個值print(data2[:, 0, :])# 2軸第一個值print(data2[:, :, 0])
?
?
if __name__ == '__main__':dm01()
2 張量形狀操作
2.1 reshape
import torch
?
?
# reshape(shape=(行,列)): 修改連續或非連續張量的形狀, 不改數據
# -1: 表示自動計算行或列 ? 例如: (5, 6) -> (-1, 3) -1*3=5*6 -1=10 (10, 3)
def dm01():torch.manual_seed(0)t1 = torch.randint(0, 10, (5, 6))print('t1->', t1)print('t1的形狀->', t1.shape)# 形狀修改為 (2, 15)t2 = t1.reshape(shape=(2, 15))t3 = t1.reshape(shape=(2, -1))print('t2->', t2)print('t2的形狀->', t2.shape)print('t3->', t3)print('t3的形狀->', t3.shape)
?
?
?
if __name__ == '__main__':dm01()
?
2.2 squeeze和unsqueeze
# squeeze(dim=): 刪除值為1的維度, dim->指定維度, 維度值不為1不生效 不設置dim,刪除所有值為1的維度
# 例如: (3,1,2,1) -> squeeze()->(3,2) squeeze(dim=1)->(3,2,1)
# unqueeze(dim=): 在指定維度上增加值為1的維度 dim=-1:最后維度
def dm02():torch.manual_seed(0)# 四維t1 = torch.randint(0, 10, (3, 1, 2, 1))print('t1->', t1)print('t1的形狀->', t1.shape)# squeeze: 降維t2 = torch.squeeze(t1)print('t2->', t2)print('t2的形狀->', t2.shape)# dim: 指定維度t3 = torch.squeeze(t1, dim=1)print('t3->', t3)print('t3的形狀->', t3.shape)# unsqueeze: 升維# (3, 2)->(1, 3, 2)# t4 = t2.unsqueeze(dim=0)# 最后維度 (3, 2)->(3, 2, 1)t4 = t2.unsqueeze(dim=-1)print('t4->', t4)print('t4的形狀->', t4.shape)
?
?
if __name__ == '__main__':dm02()
2.3 transpose和permute
# 調換維度
# torch.permute(input=,dims=): 改變張量任意維度順序
# input: 張量對象
# dims: 改變后的維度順序, 傳入軸下標值 (1,2,3)->(3,1,2)
# torch.transpose(input=,dim0=,dim1=): 改變張量兩個維度順序
# dim0: 軸下標值, 第一個維度
# dim1: 軸下標值, 第二個維度
# (1,2,3)->(2,1,3) 一次只能交換兩個維度
def dm03():torch.manual_seed(0)t1 = torch.randint(low=0, high=10, size=(3, 4, 5))print('t1->', t1)print('t1形狀->', t1.shape)# 交換0維和1維數據# t2 = t1.transpose(dim0=1, dim1=0)t2 = t1.permute(dims=(1, 0, 2))print('t2->', t2)print('t2形狀->', t2.shape)# t1形狀修改為 (5, 3, 4)t3 = t1.permute(dims=(2, 0, 1))print('t3->', t3)print('t3形狀->', t3.shape)
?
?
if __name__ == '__main__':dm03()
2.4 view和contiguous
# tensor.view(shape=): 修改連續張量的形狀, 操作等同于reshape()
# tensor.is_contiugous(): 判斷張量是否連續, 返回True/False 張量經過transpose/permute處理變成不連續
# tensor.contiugous(): 將張量轉為連續張量
def dm04():torch.manual_seed(0)t1 = torch.randint(low=0, high=10, size=(3, 4))print('t1->', t1)print('t1形狀->', t1.shape)print('t1是否連續->', t1.is_contiguous())# 修改張量形狀t2 = t1.view((4, 3))print('t2->', t2)print('t2形狀->', t2.shape)print('t2是否連續->', t2.is_contiguous())# 張量經過transpose操作t3 = t1.transpose(dim0=1, dim1=0)print('t3->', t3)print('t3形狀->', t3.shape)print('t3是否連續->', t3.is_contiguous())# 修改張量形狀# view# contiugous(): 轉換成連續張量t4 = t3.contiguous().view((3, 4))print('t4->', t4)t5 = t3.reshape(shape=(3, 4))print('t5->', t5)print('t5是否連續->', t5.is_contiguous())
?
?
if __name__ == '__main__':dm04()
3 張量拼接操作
3.1 cat/concat
import torch
?
?
# torch.cat()/concat(tensors=, dim=): 在指定維度上進行拼接, 其他維度值必須相同, 不改變新張量的維度, 指定維度值相加
# tensors: 多個張量列表
# dim: 拼接維度
def dm01():torch.manual_seed(0)t1 = torch.randint(low=0, high=10, size=(2, 3))t2 = torch.randint(low=0, high=10, size=(2, 3))t3 = torch.cat(tensors=[t1, t2], dim=0)print('t3->', t3)print('t3形狀->', t3.shape)t4 = torch.concat(tensors=[t1, t2], dim=1)print('t4->', t4)print('t4形狀->', t4.shape)?
if __name__ == '__main__':# dm01()
3.2 stack
# torch.stack(tensors=, dim=): 根據指定維度進行堆疊, 在指定維度上新增一個維度(維度值張量個數), 新張量維度發生改變
# tensors: 多個張量列表
# dim: 拼接維度
def dm02():torch.manual_seed(0)t1 = torch.randint(low=0, high=10, size=(2, 3))t2 = torch.randint(low=0, high=10, size=(2, 3))t3 = torch.stack(tensors=[t1, t2], dim=0)# t3 = torch.stack(tensors=[t1, t2], dim=1)print('t3->', t3)print('t3形狀->', t3.shape)
?
?
if __name__ == '__main__':dm02()
4 自動微分模塊
4.1 梯度計算
"""
梯度: 求導,求微分 上山下山最快的方向
梯度下降法: W1=W0-lr*梯度 ? lr是可調整已知參數 W0:初始模型的權重,已知 計算出W0的梯度后更新到W1權重
pytorch中如何自動計算梯度 自動微分模塊
注意點: ①loss標量和w向量進行微分 ②梯度默認累加,計算當前的梯度, 梯度值是上次和當前次求和 ③梯度存儲.grad屬性中
"""
import torch
?
?
def dm01():# 創建標量張量 w權重# requires_grad: 是否自動微分,默認False# dtype: 自動微分的張量元素類型必須是浮點類型# w = torch.tensor(data=10, requires_grad=True, dtype=torch.float32)# 創建向量張量 w權重w = torch.tensor(data=[10, 20], requires_grad=True, dtype=torch.float32)# 定義損失函數, 計算損失值loss = 2 * w ** 2print('loss->', loss)print('loss.sum()->', loss.sum())# 計算梯度 反向傳播 loss必須是標量張量,否則無法計算梯度loss.sum().backward()# 獲取w權重的梯度值print('w.grad->', w.grad)w.data = w.data - 0.01 * w.gradprint('w->', w)
?
?
if __name__ == '__main__':dm01()
4.2 梯度下降法求最優解
"""
① 創建自動微分w權重張量
② 自定義損失函數 loss=w**2+20 后續無需自定義,導入不同問題損失函數模塊
③ 前向傳播 -> 先根據上一版模型計算預測y值, 根據損失函數計算出損失值
④ 反向傳播 -> 計算梯度
⑤ 梯度更新 -> 梯度下降法更新w權重
"""
import torch
?
?
def dm01():# ① 創建自動微分w權重張量w = torch.tensor(data=10, requires_grad=True, dtype=torch.float32)print('w->', w)# ② 自定義損失函數 后續無需自定義, 導入不同問題損失函數模塊loss = w ** 2 + 20print('loss->', loss)# 0.01 -> 學習率print('開始 權重x初始值:%.6f (0.01 * w.grad):無 loss:%.6f' % (w, loss))for i in range(1, 1001):# ③ 前向傳播 -> 先根據上一版模型計算預測y值, 根據損失函數計算出損失值loss = w ** 2 + 20# 梯度清零 -> 梯度累加, 沒有梯度默認Noneif w.grad is not None:w.grad.zero_()# ④ 反向傳播 -> 計算梯度loss.sum().backward()# ⑤ 梯度更新 -> 梯度下降法更新w權重# W = W - lr * W.grad# w.data -> 更新w張量對象的數據, 不能直接使用w(將結果重新保存到一個新的變量中)w.data = w.data - 0.01 * w.gradprint('w.grad->', w.grad)print('次數:%d 權重w: %.6f, (0.01 * w.grad):%.6f loss:%.6f' % (i, w, 0.01 * w.grad, loss))
?print('w->', w, w.grad, 'loss最小值', loss)
?
?
if __name__ == '__main__':dm01()
4.3 梯度計算注意點
# 自動微分的張量不能轉換成numpy數組, 可以借助detach()方法生成新的不自動微分張量
import torch
?
?
def dm01():x1 = torch.tensor(data=10, requires_grad=True, dtype=torch.float32)print('x1->', x1)# 判斷張量是否自動微分 返回True/Falseprint(x1.requires_grad)# 調用detach()方法對x1進行剝離, 得到新的張量,不能自動微分,數據和原張量共享x2 = x1.detach()print(x2.requires_grad)print(x1.data)print(x2.data)print(id(x1.data))print(id(x2.data))# 自動微分張量轉換成numpy數組n1 = x2.numpy()print('n1->', n1)
?
?
if __name__ == '__main__':dm01()
4.4 自動微分模塊應用
import torch
import torch.nn as nn ?# 損失函數,優化器函數,模型函數
?
?
def dm01():# todo:1-定義樣本的x和yx = torch.ones(size=(2, 5))y = torch.zeros(size=(2, 3))print('x->', x)print('y->', y)# todo:2-初始模型權重 w b 自動微分張量w = torch.randn(size=(5, 3), requires_grad=True)b = torch.randn(size=(3,), requires_grad=True)print('w->', w)print('b->', b)# todo:3-初始模型,計算預測y值y_pred = torch.matmul(x, w) + bprint('y_pred->', y_pred)# todo:4-根據MSE損失函數計算損失值# 創建MSE對象, 類創建對象criterion = nn.MSELoss()loss = criterion(y_pred, y)print('loss->', loss)# todo:5-反向傳播,計算w和b梯度loss.sum().backward()print('w.grad->', w.grad)print('b.grad->', b.grad)
?
?
if __name__ == '__main__':dm01()