推薦一個快速定位深度學習代碼bug的煉丹神器!

2021-03-06 夕小瑤的賣萌屋

文 | McGL

源 | 知乎

寫深度學習網絡代碼,最大的挑戰之一,尤其對新手來說,就是把所有的張量維度正確對齊。如果以前就有TensorSensor這個工具,相信我的頭髮一定比現在更濃密茂盛!

TensorSensor,碼痴教授 Terence Parr 出品,他也是著名 parser 工具 ANTLR 的作者。

在包含多個張量和張量運算的複雜表達式中,張量的維數很容易忘了。即使只是將數據輸入到預定義的 TensorFlow 網絡層,維度也要弄對。當你要求進行錯誤的計算時,通常會得到一些沒啥用的異常消息。為了幫助自己和其他程式設計師調試張量代碼,Terence Parr 寫了一個名叫 TensorSensor 的庫(pip install tensor-sensor 直接安裝) 。TensorSensor 通過增加消息和可視化 Python 代碼來展示張量變量的形狀,讓異常更清晰(見下圖)。它可以兼容 TensorFlow、PyTorch 和 Numpy以及 Keras 和 fastai 等高級庫。

在張量代碼中定位問題令人抓狂!

即使是專家,執行張量操作的 Python 代碼行中發生異常,也很難快速定位原因。調試過程通常是在有問題的行前面添加一個 print 語句,以打出每個張量的形狀。這需要編輯代碼添加調試語句並重新運行訓練過程。或者,我們可以使用交互式調試器手動單擊或鍵入命令來請求所有張量形狀。(這在像 PyCharm 這樣的 IDE 中不太實用,因為在調試模式很慢。)下面將詳細對比展示看了讓人貧血的預設異常消息和 TensorSensor 提出的方法,而不用調試器或 print 大法。

調試一個簡單的線性層

讓我們來看一個簡單的張量計算,來說明預設異常消息提供的信息不太理想。下面是一個包含張量維度錯誤的硬編碼單(線性)網絡層的簡單 NumPy 實現。

import numpy as np

n = 200                          # number of instances
d = 764                          # number of instance features
n_neurons = 100                  # how many neurons in this layer?

W = np.random.rand(d,n_neurons)  # Ooops! Should be (n_neurons,d)
b = np.random.rand(n_neurons,1)
X = np.random.rand(n,d)          # fake input matrix with n rows of d-dimensions

Y = W @ X.T + b                  # pass all X instances through layer

10 Y = W @ X.T + b

ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (n?,k),(k,m?)->(n?,m?) (size 764 is different from 100)

執行該代碼會觸發一個異常,其重要元素如下:

...
---> 10 Y = W @ X.T + b
ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (n?,k),(k,m?)->(n?,m?) (size 764 is different from 100)

異常顯示了出錯的行以及是哪個操作(matmul: 矩陣乘法),但是如果給出完整的張量維數會更有用。此外,這個異常也無法區分在 Python 的一行中的多個矩陣乘法。

接下來,讓我們看看 TensorSensor 如何使調試語句更加容易的。如果我們使用 Python with 和tsensor 的 clarify()包裝語句,我們將得到一個可視化和增強的錯誤消息。

import tsensor
with tsensor.clarify():
    Y = W @ X.T + b

...
ValueError: matmul: Input operand ...
Cause: @ on tensor operand W w/shape (764, 100) and operand X.T w/shape (764, 200)

從可視化中可以清楚地看到,W 的維度應該翻轉為 n _ neurons x d; W 的列必須與 X.T 的行匹配。您還可以檢查一個完整的帶有和不帶闡明()的並排圖像,以查看它在筆記本中的樣子。下面是帶有和沒有 clarify() 的例子在notebook 中的比較。

clarify() 功能在沒有異常時不會增加正在執行的程序任何開銷。有異常時, clarify():

給出出錯操作所涉及的張量大小的可視化表示; 只突出顯示異常涉及的操作對象和運算符,而其他 Python 元素則不突出顯示。

TensorSensor 還區分了 PyTorch 和 TensorFlow 引發的與張量相關的異常。下面是等效的代碼片段和增強的異常錯誤消息(Cause: @ on tensor ...)以及 TensorSensor 的可視化:

PyTorch 消息沒有標識是哪個操作觸發了異常,但 TensorFlow 的消息指出了是矩陣乘法。兩者都顯示操作對象維度。

調試複雜的張量表達式

預設消息缺乏具體細節,在包含大量操作符的更複雜的語句中,識別出有問題的子表達式很難。例如,下面是從一個門控循環單元(GRU)實現的內部提取的一個語句:

h_ = torch.tanh(Whh_ @ (r*h) + Uxh_ @ X.T + bh_)

這是什麼計算或者變量代表什麼不重要,它們只是張量變量。有兩個矩陣乘法,兩個向量加法,還有一個向量逐元素修改(r*h)。如果沒有增強的錯誤消息或可視化,我們就無法知道是哪個操作符或操作對象導致了異常。為了演示 TensorSensor 在這種情況下是如何分清異常的,我們需要給語句中使用的變量(為 h _ 賦值)一些偽定義,以得到可執行代碼:

nhidden = 256
Whh_ = torch.eye(nhidden, nhidden)  # Identity matrix
Uxh_ = torch.randn(d, nhidden)
bh_  = torch.zeros(nhidden, 1)
h = torch.randn(nhidden, 1)         # fake previous hidden state h
r = torch.randn(nhidden, 1)         # fake this computation
X = torch.rand(n,d)                 # fake input

with tsensor.clarify():
    h_ = torch.tanh(Whh_ @ (r*h) + Uxh_ @ X.T + bh_)

同樣,你可以忽略代碼執行的實際計算,將重點放在張量變量的形狀上。

對於我們大多數人來說,僅僅通過張量維數和張量代碼是不可能識別問題的。當然,默認的異常消息是有幫助的,但是我們中的大多數人仍然難以定位問題。以下是默認異常消息的關鍵部分(注意對 C++ 代碼的不太有用的引用) :

---> 10     h_ = torch.tanh(Whh_ @ (r*h) + Uxh_ @ X.T + bh_)
RuntimeError: size mismatch, m1: [764 x 256], m2: [764 x 200] at /tmp/pip-req-build-as628lz5/aten/src/TH/generic/THTensorMath.cpp:41

我們需要知道的是哪個操作符和操作對象出錯了,然後我們可以通過維數來確定問題。以下是 TensorSensor 的可視化和增強的異常消息:

---> 10 h_ = torch.tanh(Whh_ @ (r*h) + Uxh_ @ X.T + bh_)
RuntimeError: size mismatch, m1: [764 x 256], m2: [764 x 200] at /tmp/pip-req-build-as628lz5/aten/src/TH/generic/THTensorMath.cpp:41
Cause: @ on tensor operand Uxh_ w/shape [764, 256] and operand X.T w/shape [764, 200]

人眼可以迅速鎖定在指示的算子和矩陣相乘的維度上。哎呀, Uxh 的列必須與 X.T的行匹配,Uxh_的維度翻轉了,應該為:

Uxh_ = torch.randn(nhidden, d)

現在,我們只在 with 代碼塊中使用我們自己直接指定的張量計算。那麼在張量庫的內置預建網絡層中觸發的異常又會如何呢?

理清預建層中觸發的異常

TensorSensor 可視化進入你選擇的張量庫前的最後一段代碼。例如,讓我們使用標準的 PyTorch nn.Linear 線性層,但輸入一個 X 矩陣維度是 n x n,而不是正確的 n x d:

L = torch.nn.Linear(d, n_neurons)
X = torch.rand(n,n) # oops! Should be n x d
with tsensor.clarify():
    Y = L(X)

增強的異常信息

RuntimeError: size mismatch, m1: [200 x 200], m2: [764 x 100] at /tmp/pip-req-build-as628lz5/aten/src/TH/generic/THTensorMath.cpp:41
Cause: L(X) tensor arg X w/shape [200, 200]

TensorSensor 將張量庫的調用視為操作符,無論是對網絡層還是對 torch.dot(a,b) 之類的簡單操作的調用。在庫函數中觸發的異常會產生消息,消息標示了函數和任何張量參數的維數。

後臺回復關鍵詞【入群

加入賣萌屋NLP/IR/Rec與求職討論群

後臺回復關鍵詞【頂會

獲取ACL、CIKM等各大頂會論文集!

 

[1] https://explained.ai/tensor-sensor/index.html

相關焦點

  • 深度學習·煉丹入門
    深度學習的模型訓練就是煉丹。把精選原始數據,按照神經網絡的規定法則通過計算框架提煉,從而得到一個遠小於數據數倍的模型。一個好的模型不僅能抓取數據中的模式,更是能提取更加一般化規則從而可以用來預測新的數據。雖然有人會指出機器學習的模型訓練也是一個類似的過程,但深度學習丹師對此是不屑的,他們認為訓練「淺」模型的人最多算是老中醫。
  • PyCharm+Docker:打造最舒適的深度學習煉丹爐
    一般煉丹都在伺服器上,很少有人在本機跑代碼的。之前自己搗鼓怎麼用本地的編輯器配上遠程伺服器的環境來營造一個最舒乎的姿勢。開始之前你可以對比以下條件來確定自己是否真的需要這樣做: 使用 PyCharm 作為主力 IDE 寫 Python而不是其他(我非常推薦大家用) 深度學習煉丹師(當然你可以不是,但如果是,你會更舒服) 伺服器在遠程或者區域網
  • 小說常常說的神器煉丹「九鼎」,到底是什麼神器
    我們是不是經常看見玄幻小說,都市小說經常說到有關於鼎的神器或者仙器。那到底在我們中國歷史上說的九鼎到底是什麼呢?小說經常說有關與鼎的神器都非常厲害。最為常見的就是煉丹,因為小說只要有煉丹師這個職業,就會使用鼎,而越好的鼎,提升自己煉丹技術越高。所有小說作者常常給越厲害的鼎取越酷的名字,也有一些會查閱資料看歷史上有沒有"名鼎"。而最為出名的應該是「九鼎」了吧。
  • 深度學習 | Keras 簡介
    戳左上藍字「阿力阿哩哩的煉丹日常」關注作者哦~這章開始,筆者開始帶領大家一起學習深度學習的原理和實踐。
  • 夢幻西遊出過多少個重大bug,佛手事件,煉丹爐事件只是九牛一毛
    夢幻西遊出過多少個重大bug,佛手事件,煉丹爐事件只是九牛一毛 夢幻西遊出過多少個重大bug,佛手事件,煉丹爐事件只是九牛一毛!
  • 入門深度學習與機器學習的經驗和學習路徑
    ,也算個初級煉丹選手了,就想分享一些關於如何入門機器學習與深度學習的經驗和學習路徑。機器學習在學習完上面的兩個視頻之後,你就已經具備了很好的python編程基礎了。下面可以正式進入的到機器學習的學習環節中來。去看李航老師的《統計學習方法》並且配合代碼一起使用(代碼在github上應該非常容易找到)上面的過程應該會比較困難,因為有大量的數學推導,在弄懂這些數學推導後,結合代碼和具體例子一起,收穫會更多。
  • 效率工具 | 一款基於深度學習的代碼自動補全神器
    代碼補全在開發過程中起著至關重要的作用,而隨著深度學習的熱潮,有開發者開始考慮把深度學習引入開發工具中,之前我介紹了一款基於人工智慧的補全工具Kite
  • 北京大學高等深度學習課程
    北京大學課程信息課程內容:深度學習是近年來人工智慧取得突破的核心技術,在多個重要領域獲得重要應用。本課程在「深度學習:算法與應用」課程的基礎上,將更加深入的介紹深度學習中的高級專題內容,包括高級深度學習中的數學基礎、理論、算法、幾個相關人工智慧領域的具體應用,讓學生能夠在實際中有能力完成人工智慧任務的實現, 涉獵深度學習的前沿話題。
  • 神器!深度學習高層API最強官方課程!極速上手!
    很多小夥伴在後臺給我留言,深度學習對零基礎技術小白太不友好了~確實,晦澀的理論、冗長的代碼、複雜的調試、魚龍混雜的資料...搞懵了不少同學~有辦法嗎?減少代碼量,學習成本減半!使用高層API後,在同一個深度學習任務中,原始的訓練代碼需要57多行代碼才能完成,使用高層API後,僅用18行代碼即可實現相同的功能。
  • NIPS2018深度學習(24)|亮點: 可複製特徵選擇;隨意InfoGAN;快速融合(論文及代碼)
    但是,大多數深度學習方法由於內在的複雜性,在很大程度上被視為可解釋性較差的黑箱工具。儘管最近已經有學者嘗試得到深度神經網絡(DNN)的可解釋性,但是現有方法容易受到噪聲影響並且缺乏魯棒性。因此,科學家們對發現的可重複性持謹慎態度,這通常與底層統計模型的可解釋性有關。
  • 《食之契約》羅宋湯神器定位是什麼 羅宋湯神器定位介紹
    導 讀 《食之契約》中饗靈羅宋湯的定位是什麼呢?很多小夥伴還不是很了解。
  • 曠視天元深度學習框架全球首發!3個實習生寫下一行代碼,27項全球AI...
    6年前3名實習生從第一行代碼寫起,艱難創業中在全球AI競賽斬獲27項冠軍,今日天元開源,敢與TensorFlow等全球主流深度學習框架爭雄。這個絕密武器又解決了開發者哪些痛點?「新智元急聘主筆、高級主任編輯,添加HR微信(Dr-wly)或掃描文末二維碼了解詳情。」
  • 35 萬行代碼,曠視重磅開源天元深度學習框架 ,四大特性實現簡單開發
    本次發布為Alpha版本,基於ApacheLicense2.0,向外界共開源約35萬行代碼,包括C++、CUDA和Python代碼,在GitHub上進行發布。  發布會上,曠視研究院高級技術總監田忠博詳細介紹了這款剛剛正式對外開源的深度學習框架。
  • NIPS2018深度學習(18)|亮點: 貝葉斯深度學習;圖卷積(論文及代碼)
    Polytechnique Fédérale de Lausanne,RIKEN Center for AI Projecthttps://papers.nips.cc/paper/7862-slang-fast-structured-covariance-approximations-for-bayesian-deep-learning-with-natural-gradient.pdf在深度學習模型中
  • 《深度學習》聖經花書的數學推導、原理與Python代碼實現
    同時,它還介紹了工業界中實踐者用到的深度學習技術,包括深度前饋網絡、正則化、優化算法、卷積網絡、序列建模和實踐方法等,並且調研了諸如自然語言處理、語音識別、計算機視覺、在線推薦系統、生物信息學以及視頻遊戲方面的應用。
  • 【乾貨薈萃】機器學習&深度學習知識資料大全集(二)(論文/教程/代碼/書籍/數據/課程等)
    【導讀】轉載來自ty4z2008(GItHub)整理的機器學習&深度學習知識資料大全薈萃,包含各種論文、代碼、視頻、書籍、文章、數據等等。是學習機器學習和深度學習的必備品!  介紹:三星開源的快速深度學習應用程式開發分布式平臺.
  • Go 快速入門篇(三):單元測試、問題定位及代碼調試
    GoLand 單元測試失敗列印的錯誤信息非常簡潔,卻已經足夠讓開發者快速定位到問題代碼所在的文件和行數,從而在最短的時間內確認是單元測試的問題還是程序的問題。二、問題定位與代碼調試列印變量當然,對於一些簡單的測試,還可以通過列印變量的方式來定位問題,通常我們在 PHP 中就是這麼做的,比如通過 var_dump、printf、echo 之類的語句或函數列印返回的結果,在 Laravel 框架中還可以通過 dd 或 dump 方法進行簡單高效的變量列印調試,在 Go 語言中,對應的列印函數是前面介紹過的 Printf 或 Println 方法
  • 深度學習高層API官方中文課程|極速上手
    但是,對零基礎的技術小白而言,深度學習並不是一個友好的領域。晦澀的理論、冗長的代碼、複雜的調試、魚龍混雜的資料.都讓同學們望洋興嘆!對非人工智慧背景的同學及跨領域的企業應用型選手亦是如此!使用高層 API 後,在同一個深度學習任務中,原始的訓練代碼需要57多行代碼才能完成,使用高層 API 後,僅用18行代碼即可實現相同的功能。
  • 論文代碼Chrome神器:去谷歌學術搜到文章,代碼連結就能自動展示
    論文代碼Chrome神器:去谷歌學術搜到文章,代碼連結就能自動展示 2020-10-11 18:05 來源:澎湃新聞·澎湃號·湃客
  • 【新書推薦】TensorFlow深度學習及實踐
    深度學習的入門門檻甚至比傳統機器學習算法還要低。本書以TensorFlow作為使用工具,從簡單的加法運算操作開始,介紹TensorFlow環境的搭建、基本使用方法,然後實現一個最簡單的只有兩個參數的模型,接著實現圖像識別、語音識別、自然語言處理等一些高級應用。書中還用4章內容介紹深度神經網絡的原理和應用。