全文共9175字,預計學習時長18分鐘html
本文做者是Facebook的機器學習/人工智能首席開發佈道師,爲其麾下的PyTorch團隊助力,曾經是一名軟件工程師。前端
值得注意的是,在以前,做者從未使用過PyTorch。他將用本身的親身經歷告訴你:PyTorch並不難學。python
PyTorch內容集錦git
PyTorch及其工做原理:github
• PyTorch是Facebook開發的深度學習框架,用於快速靈活實驗。這是一個基於Python的計算軟件包,含有 C++後端API。算法
• PyTorch的Python前端有三個不一樣部分:數據庫
Torch編程
這是一個包含多維張量與數學運算的數據結構包。後端
Torch.nn數組
用於建立並訓練神經網絡。區域塊的導入數據以張量形式傳遞。
例如:爲處理圖像而訓練卷積神經網絡時,可以使用nn.conv2D模塊(這一想法來自筆者同事塞斯)。
Torch.optim
該優化算法可訓練神經網絡。
例如:適用於初學者的SGD或適合進階者的Adam等算法,均可訓練神經網絡(這個好例子也源自塞斯)。
Tensors(張量)
PyTorch的Tensors 與Numpy數組相似。不一樣之處在於,Tensors數據能夠是單個數字,或一維矩陣(向量),或囊括各類數據的多維結構。
算梯度即求導(沒錯,機器學習即微積分)。求出張量的梯度,即可最大程度地規避錯誤。
梯度降低這一算法能有效實現錯誤最小化。錯誤由數據決定,而數據的分類也有適當與不適當之別。
經過梯度下降不當分類項目數。
張量最重要的特色即自動跟蹤梯度。每一個張量中的數據表明神經網路的鏈接層。這其中,有三點值得一提:
• 階 (rank): 肯定張量的維數。例如,向量爲一階。
• 形狀 (shape): 行數和列數,表現形式爲tensor. Size ([x]).
• 數據類型 (type): 給張量元素所指定的數據類型。
PyTorch的神經網絡訓練循環以下:肯定目標函數、迭代輸入其餘數據、將數據運用於神經網絡、執行梯度操做減小偏差,將異常參數運用於神經網絡。
在神經網絡中重複迭代整個訓練數據集便可。
C++ 後端
C++「後端」有五個不一樣部分。
• Autograd: 自動求導,即張量上的記錄操做,進而生成自動求導圖,基本上依據梯度張量求導。
• ATen: 張量及數學運算庫。
• TorchScript: 鏈接TorchScript的JIT編譯器與解釋器的界面(JIT爲「即時」)
• C++前端: 訓練與評價機器學習模型的高級構造。
• C++ 擴展: 經過自定義C++與CUDA的例程擴展,擴展Python的API.
CUDA (計算機統一設備架構) 是由Nvidia推出的並行計算架構及應用程序界面 (API) 模型。
上述內容皆援引自維基百科,總的來講,CUDA經常使用於GPU上的各項操做。
GPU即圖像處理器。可將其視爲具備強大運算力的電腦。
「說好的概覽呢?這些知識點簡直讓人摸不着頭腦。」雖然上述內容的確晦澀難懂,但它們相當重要。
若想對相關知識有深刻全面的瞭解,請參閱優達課程(https://classroom.udacity.com/courses/ud188)並閱讀PyTorch docs(https://pytorch.org/docs/stable/index.html)這份資料,必能讓你獲益匪淺。
那份資料並不着眼於PyTorch的方方面面,而是幫助讀者開始給GitPyTorch開源數據庫貢獻代碼(https://github.com/pytorch/pytorch)。
在這份repo中,你可根據上述信息,自行推斷大量所含文件夾的內容。
搭建開發環境
貢獻任何代碼以前,務必閱讀CONTRIBUTING.md這份文檔(https://github.com/pytorch/pytorch/blob/master/CONTRIBUTING.md),切勿有所遺漏。這是筆者從血淚中總結出的教訓。
若條件容許,不管是處理Python仍是C++問題,最好都藉助GPU。
還可採用其餘途徑(如AWS DLAMI或Nvidia Docker),這會顯著提高運行速度。
做爲初學者,筆者犯下的第一個錯誤就是在本地電腦上開工。因爲本地電腦性能不夠強大,各類使人困惑頭疼的段錯誤也就層出不窮。
最終,筆者用SSH、MOSH、TMUX等登錄GPU服務器,效果極佳。若是想就此作好準備,可參閱如下博文:
• HPC上的GPU運算簡介:安裝GPU與SSH
https://sydney-informatics-hub.github.io/training.artemis.gpu/setup.html
• PyTorch必備——GPU
https://discuss.pytorch.org/t/solved-make-sure-that-pytorch-using-gpu-to-compute/4870
• GPU內存須知
https://discuss.pytorch.org/t/reserving-gpu-memory/25297
• 安裝PyTorch與Tensorflow—— 採用支持CUDA的GPU
https://medium.com/datadriveninvestor/installing-pytorch-and-tensorflow-with-cuda-enabled-gpu-f747e6924779
接下來,搭建PyTorch開發環境。想用SSH登錄GPU,須作好如下內務處理操做:
• 鏈接GitHub帳號,確保在GPU建立SSH密鑰,並將其添加至GitHub帳號。
• 你的設備極可能會用到Python。須確保用的是Python 3。你極可能已經安裝了 pip。如若否則,務必所有安裝。
• 安裝Miniconda. 這和pip極爲相似。官方網站並無很好的終端安裝指南,在此列出筆者的操做方式:
$ with-proxy wget 「https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh"$ chmod +x Miniconda-latest-Linux-x86_64.sh$ bash Miniconda3-latest-MacOSX-x86_64.sh
• 重啓終端,輸入conda,確保操做無誤。
• 運行conda config — set auto_activate_base false, 以防止Conda自動激活,否則會干擾機器的運做。
• 運行 conda activate,激活Conda。每次開發前,務必保證conda處於激活態,注意終端的(base)語句便可。
• 安裝 ccache。若是無效,在啓用conda的狀況下執行 conda install ccachewhen conda。若依然無效,請嘗試wget。"https://www.samba.org/ftp/ccache/ccache-3.3.3.tar.gz".
• 輸入ccache 確保一切奏效,輸入conda list確保其出如今安裝列表。
• 安裝一個faster linker。除非萬不得已,否則請勿輸入 ln -s /path/to/downloaded/ld.lld /usr/local/bin/ld 指令。筆者曾遇到這種狀況,因爲它們做用不大,最終還得將相關文檔所有刪除。
• 運行 pip install ghstack 或 conda install ghstack.
• 運行 pip install ninja 或 conda install ninja.
• 經過pip install flake8 flake8-mypy flake8-bugbear flake8-comprehensions flake8-executable flake8-pyi mccabe pycodestyle pyflakes安裝 Flake8,它會爲你糾錯。若想給文檔糾錯 (lint),輸入 flake8 <FILENAME> 便可。
• 安裝一個IDE,經過SSH登錄GPU。筆者在Atom. 上查找remote-ssh ,便可獲得相關操做說明。
• 最後,安裝PyTorch:
$ git clone https://github.com/pytorch/pytorch$ cd pytorch$ git pull --rebase$ git submodule sync — recursive$ git submodule update — init — recursive$ python setup.py develop
python setup.py develop 就是用來編寫PyTorch代碼的工具。一開始會花些工夫,但一旦寫過一次,之後就能使用很多加速方法。
編輯C++時須要構建PyTorch,但編輯Python時則否則。
想把這一系列步驟辦好,就得鬥志昂揚,心懷熱忱。不過一旦完成這不易的任務,你就能夠長舒一口氣,好好犒賞下本身。
若是碰壁,不要恐慌,筆者也有過相似的經歷。參照後文的《常見錯誤》,或在評論區留言,筆者必竭力相助。搭建好開發環境會花一番工夫,祝各位馬到成功。
代碼時間到!
開發環境搭建完畢,能夠開始寫代碼了!
若是你以前從未貢獻過開源代碼,務必略讀《行爲準則》(https://github.com/pytorch/pytorch/blob/5bc7c1f83dd3ea740ba1d2af286c464862b90743/docs/source/community/governance.rst)。不少代碼庫都有這樣的文檔,簡言之,作好人,行好事。
關注GitHub的問題 (issues) 選項卡。其中囊括不少社區成員提出的問題。點擊訓練營 (bootcamp) 標籤,查看初學者級別的問題,選擇本身能力範圍內的任務,加以攻堅。
筆者建議,開始動手前,先閱讀相關資料,洞悉箇中玄機。還可更新過濾器 (filter) 查看訓練營的歷史紀錄,研究已解決的問題。
若是你胸懷大志,大可點擊 pull requests 標籤。不是全部的PR都有相關的問題可供參考,有時研究問題自己更容易瞭解狀況。
剛研究這些問題時,「冒牌貨綜合徵」如烏雲般籠罩在本身心頭。「我又不是科班出身,怎麼作得了這個?」打住!相信本身,你能行!
解決問題無須全知全能,找到方向,難題便迎刃而解。
若是你找到一個願意動手解決的問題,要勇於留言併發問,哪怕是這樣的一句話,「我想接下這個任務,請問你能就如何着手給我一些建議嗎?」都大有裨益。
這些問題板塊下的評論者都很樂於助人,由於若是有人對這些問題感興趣,他們本身也會很高興。對此筆者有切身體會,在他們的引導下,筆者解決了一系列問題,本身的PyTorch技術也日臻完善。
接下來是案例分析,闡述筆者如何在一頭霧水的狀況下解決問題。
第17893號問題:確保Grad_outputs的輸出值形狀與torch.autograd.grad()一致
幸運的是,據筆者切身經驗來講,PyTorch庫的做者每每細緻縝密,言之有物。
就此例:https://github.com/pytorch/pytorch/issues/17893而言,結合前文的知識,不難發現,因爲該問題涉及「接受輸入」,因此這一定與Python前端有關。
乍一看這個問題角度很刁鑽,雖然本質上與Python相關,但題目中的autograd,卻有將人引向C++之嫌。
筆者建立一個新分支並將其導至最高級的torch文件夾(本例中,所涉及的函數正是torch)。
有趣的是,在最先創立的文件夾中,正好有一個名爲autograd ,真可謂無巧不成書。
打開 autograd 文件夾,在 grad( 語句中調用git grep ,以肯定函數定義。能夠肯定,其中一個就在 __init__.py 文件中。
更巧的是,在 grad 函數,中 正好有以 *gasp*爲名的變量,也就是說只須要作一個簡單的condition,一切便迎刃而解。
如題所示, outputs 與 grad_outputs 須形狀一致。經過NumPy,有一個簡單的法子能夠作到這點。
import numpy as np...if np.shape(outputs) != np.shape(grad_outputs):
raise RuntimeError("grad_outputs and outputs do not have the same shape")
做爲一名優秀的軟件工程師,筆者很清楚只有先測試代碼,才能保證本身的PR滴水不漏。不過首先,得確認程序的兼容性沒有問題。
據CONTRIBUTING.md 文件所示, 先得運行 python test/run_test.py。
運行結果並不盡如人意,那麼到底是哪裏出了紕漏?原來PyTorch在調用NumPy並不直接照搬,而是會作出相應調整。只能這樣說,PyTorch能夠無損調用NumPy中的函數。在這篇文章(https://github.com/wkentaro/pytorch-for-numpy-users)中,筆者獲悉如何實現兩種程序的代碼轉化。
此外,這篇文章中還提到,只能在一個(而非多個)張量中讀取形狀需求,所以筆者調用shape() 語句時也出了差錯。所以,__init__.py 中 grad() 函數代碼也須修改,詳情以下:
再次測試程序,此次終於成功,接下來是報錯測試。
打開test 文件夾,裏面是帶有test_grad 函數的 test_autograd.py 文件,一切都是那麼的簡潔明瞭!
在敲定測試方案前,筆者先加入一些打印語句。謹記,打印語句是Python編程師的鼎力助手。
打印隨機變量有助於深刻了解張量,並從程序上將其與梯度張量相比較。
此外,讀取其餘測試,瞭解項目中相關對象的建立與測試,也能使人獲益匪淺。最終,測試以下:
grad_out = torch.ones(2)try:
torch.autograd.grad(
outputs=[grad_sum], grad_outputs=[grad_out],
inputs=[x], create_graph=True)
self.assertFail()
except RuntimeError as error:
self.assertEqual(str(error), "grad_outputs and outputs do not have the same shape")
運行上述測試,萬無一失。接下來,用Flake8糾錯,在GitHub上提交修改結果,建立PR,添加問題標籤,確認與原問題標籤一致,提交,搞定收工!
很快,筆者就收到了評論,這些意見邏輯清晰、很有洞見,所以也極易落實。
第一樁PR圓滿完成!幸虧只用Python就可解決,畢竟,又有誰敢去編輯臭名昭著的C++呢?不過明知山有虎,偏向虎山行,有請下一個問題!
第22963號問題: 經過Torch.flatten(),輸入零維張量,得出零維張量(非一維)
起初,筆者並未意識到該問題涉及C++API, 但仔細一看(再次給出題者點個贊),一切不言而喻。
切勿一見討論而萌生退意,圍繞這些問題的討論每每蘊含不少信息。在接手問題以前,要確保本身有解決的方法。
該問題涉及兩方面,一是「返回值」,二是「輸入值」。輸入值與「前端」相關,即Python;而「輸出值」與「後端」相關,即C++。
建立新分支,大膽一試。大部分編程都是這麼一回事——懷揣但願,放手一試。
首先,探尋 flatten() 函數的奧祕。而這即是打印語句的用武之地。
導航回 test 文件夾, 在flatten( 上調用git grep 。通過一番查詢,筆者剛好在test_torch.py文件找到test_flatten 函數。
打開文件,研究其斷言,明白本身所找何物後,輸入以下打印語句:
# Test that flatten returns 1-dim tensor when given a 0-dim tensor
zero_dim_tensor = torch.tensor(123)
one_dim_tensor = torch.tensor([123])
cool_dim_tensor = torch.tensor([1,2,3])
flat0 = zero_dim_tensor.flatten()
flat1 = one_dim_tensor.flatten()
flat2 = cool_dim_tensor.flatten()print("--zero dim tensor--")
print(zero_dim_tensor)
print(zero_dim_tensor.shape)
print(flat0)
print(flat0.shape)
print("--one dim tensor--")
print(one_dim_tensor)
print(one_dim_tensor.shape)
print(flat1)
print(flat1.shape)
print("--cool dim tensor--")
print(cool_dim_tensor)
print(cool_dim_tensor.shape)
print(flat2)
print(flat2.shape)
輸出值以下:
--zero dim tensor--
tensor(123)
torch.Size([])
tensor(123)
torch.Size([])
--one dim tensor--
tensor([123])
torch.Size([1])
tensor([123])
torch.Size([1])
—cool dim tensor--
tensor([1, 2, 3])
torch.Size([3])
tensor([1, 2, 3])
torch.Size([3])
結果與問題相吻合。展開後,零維張量與一維張量是等值的。
根據這些打印語句可得,這個等值性是由其形狀(shape)爲torch.Size([1])決定的。一經展開,零維向量等於一維向量。
接下來在代碼中驗證這一觀點。筆者在GitHub庫中搜索「flatten」的實例。在Python中,的確有Flatten模塊這一說法。
由此,筆者第一次意識到本身得處理C++編程,通常來講人們不肯從事模塊編輯,而這其中另有玄機。
有這麼一種模塊框架,名爲 caffe2。你大可谷歌百度,簡言之,它是PyTorch的一部分,而且人們每每不同意使用這一框架。對筆者來講,編輯Caffe2不是個好主意。
無奈地盯着tensor_flatten.cpp文件,筆者彷佛只能止步於此。這但是讓人頭疼的C++,就算費上九牛二虎之力,恐怕到頭來本身仍束手無策。
鼓起勇氣求助以前,筆者對着屏幕足足懊喪了一個小時,「冒牌者綜合徵」如陰雲般在腦海中揮之不去。
乾坐着泄氣可不是理想的應對之策。若是不是坐在辦公室,筆者恐怕早就發帖詢問該從哪裏下手了。所幸的是,辦公桌几步以外,即是好心的工程師同伴。謝天謝地,在他們的點撥下,陰雲散去,柳暗花明。
解決這一難題的關鍵在於aten. 由於 ATen 即張量運算庫,而flatten 與運算息息相關。
明白這個道理須要花一番工夫。若是你因無處解惑而束手無策,可參閱PyTorch技術文檔(https://pytorch.org/docs/stable/torch.html?highlight=flatten#torch.flatten)。
這代表,想解決這個問題,須找到帶有各類參數(如input, start_dum, end_dim)的flatten 函數,返回一個Tensor 。根據這個說法,很明顯以前筆者的嘗試有如南轅北轍。
筆者決定在頂層調用 git grep,實現Tensor flatten( 。因而瓜熟蒂落地獲得atn, TensorShape.cpp。這代碼看上去沒問題,準沒錯。
爲了完全理解該代碼,筆者審閱了數遍,並確保單步執行的函數符合邏輯。
這代碼看起來如何?簡潔易懂!這樣每當輸入一維張量時,它就會模仿flatten 函數,而非返回輸入值:
if (self.dim() == 0) {
shape.reserve(1);
shape.push_back(1);
return self.reshape(shape);
}
更新測試,代入合適的結果,而後一切水到渠成。接下來就是糾錯,作PR,獲取建議反饋,貢獻PyTorch代碼大功告成!
點滴感悟
筆者貢獻開源代碼已有些時日,如下幾點經驗教訓值得牢記:
1. 敢於探索 不要對代碼心生畏懼。這些代碼都是聰明人寫出來的(對於大項目來講更是如此),其中蘊含許多玄機可供探索。敢於揭開那些代碼的神祕面紗,哪怕不許備爲其添磚加瓦,僅僅是瞭解其工做原理,也能使本身獲益匪淺。
2. 勤於發問 沒必要害羞瑟縮,GitHub開源社區倡導共享精神,主張領導力培養。別人會由於你的發問與參與心潮澎湃,進而伸出援助之手。
3. 樂於學習 你並非團隊中的冒牌者,只要本身樂於學習勇於拼搏,哪怕不是科班出身,不能作到凡事心照不宣,你依然能夠爲團隊發展添磚加瓦。
4. 善於鑽研 多讀資料。查閱README,技術文檔,參與論壇,這些都能讓人受益頗多。
5. 勇於嘗試 哪怕本身不是穩操勝券,想不出萬全之策,也不要躊躇不前,要勇於嘗試。
望諸位的編程之路一路順風!
常見錯誤一覽
Import not found, or import not connecting
1. 確認是否鍵入輸入值。
2. 確認conda 是否激活。
3. 重啓PyTorch。
NumPy functions don’t work
1. 先確認可否在不影響效果的狀況下,用 PyTorch 替換Numpy。
2. 如若否則,在GitHub上建立問題,徵求PyTorch可兼容的函數來達到預期效果。亦可本身寫出函數。
Not all the tests on my PR are passing
1. 彆氣餒,深呼吸,相信本身。
2. 有時,這不是你的錯。檢查日誌文件,留意是否有來自本機的新消息,若收到新消息,從新訪問代碼。
3. 你並未合併本身的PR,但團隊其餘成員合併了各自的PR。不過你有個好團隊,夥伴們會告知你併爲你分憂。
推薦閱讀專題
留言 點贊 關注
咱們一塊兒分享AI學習與發展的乾貨
歡迎關注全平臺AI垂類自媒體 「讀芯術」
(添加小編微信:dxsxbb,加入讀者圈,一塊兒討論最新鮮的人工智能科技哦~)