Pytorch Tutorial 使用torch.autograd進行自動微分

Pytorch Tutorial 使用torch.autograd進行自動微分

本文翻譯自 PyTorch 官網教程。

原文:https://pytorch.org/tutorials/beginner/basics/autogradqs_tutorial.html#optional-reading-tensor-gradients-and-jacobian-products

在訓練神經網絡時,最常使用到的算法就是反向傳播(back propagation)。在該算法中,參數(模型權重)會根據損失函數相對于給定參數的**梯度(gradient)**進行更新。

為了計算這些梯度,PyTorch 中有一個內置的微分引擎,叫做 torch.autograd 。它可以自動地計算任意計算圖的梯度。

考慮下面一個最簡單的單層神經網絡,其輸入為 x,權重參數為 wb ,還有一個損失函數(此處采用二進制交叉熵)。在 PyTorch 中可以按照以下方式來定義上述神經網絡:

import torchx = torch.ones(5)  # input tensor
y = torch.zeros(3)  # expected output
w = torch.randn(5, 3, requires_grad=True)
b = torch.randn(3, requires_grad=True)
z = torch.matmul(x, w)+b
loss = torch.nn.functional.binary_cross_entropy_with_logits(z, y)

張量、函數和計算圖

上述代碼定義了這樣一個計算圖(computational graph)

在這里插入圖片描述

在該網絡中,wb 是需要優化更新的權重參數。因此,我們需要能夠計算損失函數關于這兩個變量的梯度。為此,我們設置這兩個變量的 requires_grad 屬性為 True

我們也可以在創建張量之后,再使用 x.requires_grad_(True) 方法來設置 requires_grad 的值。

我們將某個函數作用于張量來構建計算圖,該函數實際上是 Function 類的一個對象。這個對象知道在前向傳播時怎樣計算該函數,也知道在反向傳播時怎樣計算它的微分。反向傳播函數的是依據張量的 grad_fn 屬性。更多信息請參考 Function 的[文檔][https://pytorch.org/docs/stable/autograd.html#function]。

print('Gradient function for z =', z.grad_fn)
print('Gradient function for loss =', loss.grad_fn)

輸出:

Gradient function for z = <AddBackward0 object at 0x7f06c1316a90>
Gradient function for loss = <BinaryCrossEntropyWithLogitsBackward0 object at 0x7f06c1316a90>

計算梯度

為了優化更新網絡中的權重參數,我們需要計算損失函數關于權重參數的導數,即我們需要在給定 xy 值的情況下的 ?losss?w\frac{\partial losss}{\partial w}?w?losss??losss?b\frac{\partial losss}{\partial b}?b?losss?。 為了計算這些導數,我們調用 loss.backward() 函數,然后再來查看 w.gradb.grad 的值。

loss.backward()
print(w.grad)
print(b.grad)

輸出:

tensor([[0.2225, 0.2403, 0.3150],[0.2225, 0.2403, 0.3150],[0.2225, 0.2403, 0.3150],[0.2225, 0.2403, 0.3150],[0.2225, 0.2403, 0.3150]])
tensor([0.2225, 0.2403, 0.3150])
  • 我們只能得到 requires_grad 設置為 True 且為計算圖中葉子結點grad 屬性,計算圖中的所有其他結點的梯度是無法得到的。
  • 通過 backward(),我們只能對某張計算圖進行一次求梯度的運算,因為為了提升性能,通常計算圖在進行一次求梯度的計算后就會被釋放。如果我們需要多次對同一張計算圖調用 backward() ,我們需要在調用 backward 的時候傳入 retain_grap=True

禁用梯度跟蹤

默認情況下,所有的 requires_grad=True 的張量都會追蹤它們的計算歷史,并支持梯度計算。然而,有些情況下我們并不需要做這些。比如說,我們已經訓練好了一個模型然后想將它應用于某些輸入數據,即我們只想要對網絡進行前向計算(就是推理時)。我們可以將我們的計算代碼放到一個上下文管理器 torch.no_grad() 中來停止梯度追蹤:

z = torch.matmul(x, w)+b
print(z.requires_grad)with torch.no_grad():z = torch.matmul(x, w)+b
print(z.requires_grad)

輸出:

True
False

另一種方式也可以實現相同的效果:調用張量的 detach() 方法:

z = torch.matmul(x, w)+b
z_det = z.detach()
print(z_det.requires_grad)

輸出:

False

這里是我們可能會想要禁用梯度追蹤的一些原因:

  • 將我們網絡中的某些參數凍結,這時我們要微調一個預訓練過的網絡時很常見的場景。
  • 在我們只需要進行前向傳播時加速運算,因為不進行梯度追蹤的計算肯定會更高效。

更多關于計算圖的知識

從概念上講,autograd 在由 Function 對象組成的有向無環圖 (DAG) 中記錄數據(張量)和所有執行的操作(以及生成的新張量)。 在這個 DAG 中,葉子節點是輸入張量,根節點是輸出張量。 通過從根節點到葉子節點跟蹤此圖,可以使用鏈式法則自動計算梯度。

在前向傳播中,autograd 同時完成這兩件事情:

  • 運行指定的操作來計算結果向量
  • 將各操作的梯度函數保存在 DAG 中

當在 DAG 根上調用 .backward() 時,反向傳遞開始, 然后自動求導:

  • 根據各個 .grad_fn 計算梯度
  • 將它們累加到對應的張量的 .grad 屬性中
  • 使用鏈式求導法則,一直傳播到葉子張量

在 PyTorch 中 DAG 是動態的

需要注意的重要一點是,在每次 .backward() 調用之后,DAG 是從頭開始重新創建的。autograd 開始構建一張新圖。這也是為什么在 PyTorch 中支持控制流語句; 我們可以根據需要在每次迭代時更改形狀、大小和操作。

選讀:張量梯度和雅克比乘積

在許多情況下,我們得到的損失都是一個標量,然后我們去計算它關于各個權重參數的梯度。然而,在某些情況下我們會輸出一個任意維度的張量,PyTorch 允許我們計算所謂的雅克比乘積,而非真實的梯度。

對于一個向量 y?=f(x?)\vec{y}=f(\vec{x})y?=f(x),其中 x?=<x1,…,xn>\vec{x}=<x_1,\dots,x_n>x=<x1?,,xn?>y?=<y1,…,yn>\vec{y}=<y_1,\dots,y_n>y?=<y1?,,yn?>,則 y?\vec{y}y? 關于 x?\vec{x}x 的梯度可以由雅克比矩陣給出:

在這里插入圖片描述

PyTorch 允許我們計算給定輸入向量 v=(v1,…,vn)v=(v_1,\dots,v_n)v=(v1?,,vn?) 的雅克比乘積 vTv^TvT 而非雅克比矩陣本身。只需在調用 backward 的時候將 vvv 作為參數傳入。vvv 的尺寸需要與我們想要計算雅克比乘積的原始張量相同:

inp = torch.eye(5, requires_grad=True)
out = (inp+1).pow(2)
out.backward(torch.ones_like(inp), retain_graph=True)
print("First call\n", inp.grad)
out.backward(torch.ones_like(inp), retain_graph=True)
print("\nSecond call\n", inp.grad)
inp.grad.zero_()
out.backward(torch.ones_like(inp), retain_graph=True)
print("\nCall after zeroing gradients\n", inp.grad)

輸出:

First calltensor([[4., 2., 2., 2., 2.],[2., 4., 2., 2., 2.],[2., 2., 4., 2., 2.],[2., 2., 2., 4., 2.],[2., 2., 2., 2., 4.]])Second calltensor([[8., 4., 4., 4., 4.],[4., 8., 4., 4., 4.],[4., 4., 8., 4., 4.],[4., 4., 4., 8., 4.],[4., 4., 4., 4., 8.]])Call after zeroing gradientstensor([[4., 2., 2., 2., 2.],[2., 4., 2., 2., 2.],[2., 2., 4., 2., 2.],[2., 2., 2., 4., 2.],[2., 2., 2., 2., 4.]])

注意當我們使用相同的參數第二次調用 backward 時,梯度的值會不同。這是因為在調用 backward 進行反向傳播時,PyTorch 會累加梯度,即計算梯度得到的值會被加到計算圖中所有葉子結點的 .grad 屬性上。因此一般區情況下,為了計算的梯度正確,我們需要再每一步計算梯度前先將已有梯度清零(zero_grad())。在實際的訓練中,優化器會幫助我們做這一步。

譯者注:有時也可以通過這一累加特性變相增大 batch_size。

之前我們調用無參數的 backward() 函數。 這本質上等同于調用 backward(torch.tensor(1.0)),這在標量值函數的情況下計算梯度時很有用,例如神經網絡訓練期間的損失。

擴展閱讀

  • Autograd Mechanics

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/532537.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/532537.shtml
英文地址,請注明出處:http://en.pswp.cn/news/532537.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

TVM:編譯深度學習模型快速上手教程

TVM&#xff1a;編譯深度學習模型快速上手教程 本文將展示如何使用 Relay python 前端構建一個神經網絡&#xff0c;并使用 TVM 為 Nvidia GPU 生成一個運行時庫。 注意我們需要再構建 TVM 時啟用了 cuda 和 llvm。 TVM支持的硬件后端總覽 在本教程中&#xff0c;我們使用 cu…

TVM:設計與架構

TVM&#xff1a;設計與架構 本文檔適用于想要了解 TVM 架構和/或積極開發項目的開發人員。頁面組織如下&#xff1a; 示例編譯流程概述了 TVM 將模型的高層描述轉換為可部署模塊所采取的步驟。要開始使用&#xff0c;請先閱讀本節。 邏輯架構組件部分描述了邏輯組件。后面的部…

遞歸+回溯

遞歸-回溯 本文參考自代碼隨想錄視頻&#xff1a; https://www.bilibili.com/video/BV1cy4y167mM https://www.bilibili.com/video/BV1ti4y1L7cv 遞歸回溯理論基礎 只要有遞歸&#xff0c;就會有回溯&#xff0c;遞歸函數的下面的部分通常就是回溯的邏輯。 回溯是純暴力的搜索…

Nvidia CUDA初級教程1 CPU體系架構綜述

Nvidia CUDA初級教程1 CPU體系架構綜述 視頻&#xff1a;https://www.bilibili.com/video/BV1kx411m7Fk?p2 講師&#xff1a;周斌 本節內容&#xff1a;了解現代CPU的架構和性能優化&#xff1a; 流水線 Pipelining分支預測 Branch Prediction超標量 Superscalar亂序執行 Out…

Nvidia CUDA初級教程2 并行程序設計概述

Nvidia CUDA初級教程2 并行程序設計概述 視頻&#xff1a;https://www.bilibili.com/video/BV1kx411m7Fk?p3 講師&#xff1a;周斌 本節內容&#xff1a; 為什么需要&#xff1f;怎么做&#xff1f;一些技術和概念 串并行計算模式 串行計算模式 常規軟件時串行的 設計運行…

Nvidia CUDA初級教程4 GPU體系架構概述

Nvidia CUDA初級教程4 GPU體系架構概述 視頻&#xff1a;https://www.bilibili.com/video/BV1kx411m7Fk?p5 講師&#xff1a;周斌 本節內容&#xff1a; 為什么需要GPU三種方法提升GPU的處理速度實際GPU的設計舉例&#xff1a; NVDIA GTX 480: FermiNVDIA GTX 680: Kepler GP…

Nvidia CUDA初級教程5 CUDA/GPU編程模型

Nvidia CUDA初級教程5 CUDA/GPU編程模型 視頻&#xff1a;https://www.bilibili.com/video/BV1kx411m7Fk?p6 講師&#xff1a;周斌 本節內容&#xff1a; CPU和GPU互動模式GPU線程組織模型&#xff08;需要不停強化&#xff09;GPU存儲模型基本的編程問題 CPU與GPU交互 各自…

Nvidia CUDA初級教程6 CUDA編程一

Nvidia CUDA初級教程6 CUDA編程一 視頻&#xff1a;https://www.bilibili.com/video/BV1kx411m7Fk?p7 講師&#xff1a;周斌 GPU架構概覽 GPU特別使用于&#xff1a; 密集計算&#xff0c;高度可并行計算圖形學 晶體管主要被用于&#xff1a; 執行計算而不是 緩存數據控制指令…

由前中后遍歷序列構建二叉樹

由前/中/后遍歷序列構建二叉樹 基礎 首先&#xff0c;我們需要知道前中后序三種深度優先遍歷二叉樹的方式的具體順序&#xff1a; 前序&#xff1a;中左右中序&#xff1a;左中右后序&#xff1a;左右中 另外&#xff0c;要知道只有中序前/后序可以唯一確定一棵二叉樹&…

手寫nms

手寫nms 計算寬高的時候加1是為什么&#xff1f; 本文總結自互聯網的多種nms實現&#xff0c;供參考&#xff0c;非博主原創&#xff0c;各原文鏈接如下&#xff0c;也建議大家動手寫一寫。 Ref&#xff1a; 淺談NMS的多種實現 目標窗口檢測算法-NMS非極大值抑制 一、fas…

目標檢測綜述

目標檢測綜述 轉自&#xff1a;https://zhuanlan.zhihu.com/p/383616728 論文參考&#xff1a;[Object Detection in 20 Years: A Survey][https://arxiv.org/abs/1905.05055] 引言 目標檢測領域發展至今已有二十余載&#xff0c;從早期的傳統方法到如今的深度學習方法&#x…

Nvidia CUDA初級教程7 CUDA編程二

Nvidia CUDA初級教程7 CUDA編程二 視頻&#xff1a;https://www.bilibili.com/video/BV1kx411m7Fk?p8 講師&#xff1a;周斌 本節內容&#xff1a; 內置類型和函數 Built-ins and functions線程同步 Synchronizing線程調度 Scheduling threads存儲模型 Memory model重訪 Matr…

詳解優酷視頻質量評價體系

萬字長文 | 詳解優酷視頻質量評價體系 分享嘉賓&#xff5c;李靜博士&#xff0c;阿里巴巴文娛集團資深算法專家&#xff0c;阿里巴巴大文娛摩酷實驗室視頻體驗與質量團隊負責人 整理出品&#xff5c;AICUG人工智能社區 本文地址&#xff1a;https://www.6aiq.com/article/1617…

視頻質量評價:挑戰與機遇

視頻質量評價&#xff1a;挑戰與機遇 轉自&#xff1a;https://zhuanlan.zhihu.com/p/384603663 本文整理自鵬城實驗室助理研究員王海強在LiveVideoStack線上分享上的演講。他通過自身的實踐經驗&#xff0c;詳細講解了視頻質量評價的挑戰與機遇。 文 / 王海強 整理 / LiveVi…

關于二分法的邊界問題及兩種寫法

關于二分法的邊界問題及兩種寫法 二分查找法大家很熟悉了&#xff0c;對于一個有序序列&#xff0c;我們可以通過二分查找法在 O(logN)O(logN)O(logN) 的時間內找到想要的元素。但是&#xff0c;在代碼實現的過程中&#xff0c;如果沒有仔細理解清楚&#xff0c;二分法的邊界條…

LeetCode上的各種股票最大收益

LeetCode上的各種股票最大收益 對于力扣平臺上的股票類型的題目&#xff1a; 121 買賣股票的最佳時機 122 買賣股票的最佳時機 II 123 買賣股票的最佳時機 III 124 買賣股票的最佳時機 IV 309 最佳買賣股票時機含冷凍期 714 買賣股票的最佳時機含手續費 劍指 Offer 63. …

建設專業化運維服務團隊必要性

信息系統的生命周期涵蓋&#xff1a;設計、開發、測試、部署上線、運行維護。其中&#xff0c;運行維護階段是信息系統生命周期中的關鍵環節&#xff0c;其執行效果直接影響系統是否能達到預期的運行目標。為了實現這個目標&#xff0c;我們必須建立一個以業務服務為導向的專業…

docker初探

docker初探 本文旨在介紹 docker 基本的安裝、常用命令和常見概念的辨析&#xff0c;方便新手入門和筆者日后查閱&#xff0c;大部分內容整理自互聯網&#xff0c;原出處在文中注明。 文章目錄docker初探docker安裝&#xff08;mac&#xff09;版本、信息相關命令version/info…

ubuntu安裝zsh、oh-my-zsh及常用配置

ubuntu安裝zsh、oh-my-zsh及常用配置 目前&#xff0c;ubuntu默認的shell是bash&#xff0c;但還有一種shell&#xff0c;叫做zsh它比bash更加強大&#xff0c;功能也更加完善&#xff0c;zsh雖說功能強大&#xff0c;但是配置比較復雜導致流行度不是很高 但是好東西終究是好…

Segmentaion標簽的三種表示:poly、mask、rle

Segmentaion標簽的三種表示&#xff1a;poly、mask、rle 不同于圖像分類這樣比較簡單直接的計算機視覺任務&#xff0c;圖像分割任務&#xff08;又分為語義分割、實例分割、全景分割&#xff09;的標簽形式稍為復雜。在分割任務中&#xff0c;我們需要在像素級上表達的是一張…