backward理解
backward:自動求梯度。計算小批量隨機梯度。
當模型和損失函數形式較為簡單時,上面的誤差最小化問題的解可以直接用公式表達出來。這類解 叫作解析解(analytical solution)。本節使用的線性回歸和平方誤差剛好屬于這個范疇。然而,大多數 深度學習模型并沒有解析解,只能通過優化算法有限次迭代模型參數來盡可能降低損失函數的值。這類解叫作數值解(numerical solution)。
在求數值解的優化算法中,小批量隨機梯度下降(mini-batch stochastic gradient descent)在深度學習中被廣泛使用。它的算法很簡單:1.先選取一組模型參數的初始值,如隨機選取;2.接下來對參數進行多次迭代,使每次迭代都可能降低損失函數的值。
在每次迭代中,先隨機均勻采樣一個由固定數目訓練數據樣本所組成的小批量(mini-batch)B,然后求小批量中數據樣本的平均損失有關模型參數的導 數(梯度),最后用此結果與預先設定的一個正數的乘積作為模型參數在本次迭代的減小量。
?在上式中,|B| 代表每個小批量中的樣本個數(批量大小,batch size),η 稱作學習率(learning rate)并取正數。需要強調的是,這里的批量大小和學習率的值是人為設定的,并不是通過模型訓練學 出的,因此叫作超參數(hyperparameter)。我們通常所說的“調參”指的正是調節超參數,例如通過反復試錯來找到超參數合適的值。在少數情況下,超參數也可以通過模型訓練學出。
梯度累積
所謂梯度累積,其實很簡單,我們梯度下降所用的梯度,實際上是多個樣本算出來的梯度的平均值,以 batch_size=128 為例,你可以一次性算出 128 個樣本的梯度然后平均,我也可以每次算 16 個樣本的平均梯度,然后緩存累加起來,算夠了 8 次之后,然后把總梯度除以 8,然后才執行參數更新。當然,必須累積到了 8 次之后,用 8 次的平均梯度才去更新參數,不能每算 16 個就去更新一次,不然就是 batch_size=16 了。
定義優化函數
以下的?sgd?函數實現了上一節中介紹的小批量隨機梯度下降算法。它通過不斷迭代模型參數來優化 損失函數。這里自動求梯度模塊計算得來的梯度是一個批量樣本的梯度和。我們將它除以批量大小來得到平均值。
def sgd(params, lr, batch_size):'''小批量隨機梯度下降params: 權重lr: 學習率batch_size: 批大小'''for param in params:param.data -= lr * param.grad / batch_size在訓練中,我們將多次迭代模型參數。在每次迭代中,我們根據當前讀取的小批量數據樣本(特征 X 和標簽 y ),通過調用反向函數 backward 計算小批量隨機梯度,并調用優化算法 sgd 迭代模型參數。由于我們之前設批量大小 batch_size 為10,每個小批量的損失 l 的形狀為(10, 1)。回憶一下自動 求梯度一節。由于變量?l?并不是一個標量,所以我們可以調用?.sum()?將其求和得到一個標量,再運行 l.backward() 得到該變量有關模型參數的梯度。注意在每次更新完參數后不要忘了將參數的梯度清零。(如果不清零,PyTorch默認會對梯度進行累加)
對于這種我們自己定義的變量,我們稱之為葉子節點(leaf nodes),而基于葉子節點得到的中間或最終變量則可稱之為結果節點
x = torch.tensor(1.0, requires_grad=True) y = torch.tensor(2.0, requires_grad=True) z = x**2+y z.backward() print(z, x.grad, y.grad)>>> tensor(3., grad_fn=<AddBackward0>) tensor(2.) tensor(1.)z對x求導為:2,z對y求導為:1
可以z是一個標量,當調用它的backward方法后會根據鏈式法則自動計算出葉子節點的梯度值。
求一個矩陣對另一矩陣的導數束手無策。
對矩陣求和不就是等價于z點乘一個一樣維度的全為1的矩陣嗎?即??,而這個I也就是我們需要傳入的grad_tensors參數。(點乘只是相對于一維向量而言的,對于矩陣或更高為的張量,可以看做是對每一個維度做點乘)
【點乘:對兩個向量執行點乘運算,就是對這兩個向量對應位一一相乘之后求和的操作】
?如:
x = torch.tensor([2., 1.], requires_grad=True) y = torch.tensor([[1., 2.], [3., 4.]], requires_grad=True)z = torch.mm(x.view(1, 2), y) print(f"z:{z}") z.backward(torch.Tensor([[1., 0]]), retain_graph=True) print(f"x.grad: {x.grad}") print(f"y.grad: {y.grad}")>>> z:tensor([[5., 8.]], grad_fn=<MmBackward>) x.grad: tensor([[1., 3.]]) y.grad: tensor([[2., 0.],[1., 0.]])結果解釋如下:
查看梯度以及參數更新的問題?
import torch import torch.nn as nn import numpy as np import torch.optim as optim from torchsummary import summary import os from torch.utils.data.dataset import Dataset from torch.utils.data import DataLoader from tqdm import tqdm# 設置一下數據集 數據集的構成是隨機兩個整數,形成一個加法的效果 input1 + input2 = label class TrainDataset(Dataset):def __init__(self):super(TrainDataset, self).__init__()self.data = []for i in range(1,1000):for j in range(1,1000):self.data.append([i,j])def __getitem__(self, index):input_data = self.data[index]label = input_data[0] + input_data[1]return torch.Tensor(input_data),torch.Tensor([label])def __len__(self):return len(self.data)class TestNet(nn.Module):def __init__(self):super(TestNet, self).__init__()self.net1 = nn.Linear(2,1)def forward(self, x):x = self.net1(x)return xdef train():traindataset = TrainDataset()traindataloader = DataLoader(dataset = traindataset,batch_size=1,shuffle=False)testnet = TestNet().cuda()myloss = nn.MSELoss().cuda()optimizer = optim.SGD(testnet.parameters(), lr=0.001 )for epoch in range(100):for data,label in traindataloader :print("\n=====迭代開始=====")data = data.cuda()label = label.cuda()output = testnet(data)print("輸入數據:",data)print("輸出數據:",output)print("標簽:",label)loss = myloss(output,label)optimizer.zero_grad()for name, parms in testnet.named_parameters(): print('-->name:', name)print('-->para:', parms)print('-->grad_requirs:',parms.requires_grad)print('-->grad_value:',parms.grad)print("===")loss.backward()optimizer.step()print("=============更新之后===========")for name, parms in testnet.named_parameters(): print('-->name:', name)print('-->para:', parms)print('-->grad_requirs:',parms.requires_grad)print('-->grad_value:',parms.grad)print("===")print(optimizer)input("=====迭代結束=====")if __name__ == '__main__':os.environ["CUDA_VISIBLE_DEVICES"] = "{}".format(3)train()?
?
?
?
參考自:動手學深度學習(Pytorch)第2章深度學習基礎-上 - 知乎
Pytorch autograd,backward詳解 - 知乎
Pytorch 模型 查看網絡參數的梯度以及參數更新是否正確,優化器學習率設置固定的學習率,分層設置學習率_呆呆象呆呆的博客-CSDN博客
總結
以上是生活随笔為你收集整理的backward理解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: sql常见语句记录
- 下一篇: c python 内存冲突_Python