第1章 Pytorch介紹與基礎(chǔ)知識(shí)
大家好,本章是主要介紹一下深度學(xué)習(xí)框架Pytorch的的歷史與發(fā)展,主要模塊構(gòu)成與基礎(chǔ)操作代碼演示。重點(diǎn)介紹Pytorch的各個(gè)組件、編程方式、環(huán)境搭建、基礎(chǔ)操作代碼演示。本章對(duì)有Pytorch開(kāi)發(fā)經(jīng)驗(yàn)的讀者來(lái)說(shuō)可以直接跳過(guò);對(duì)初次接觸Pytorch的讀者來(lái)說(shuō),通過(guò)本章學(xué)習(xí)認(rèn)識(shí)Pytorch框架,搭建好Pytorch的開(kāi)發(fā)環(huán)境,通過(guò)一系列的基礎(chǔ)代碼練習(xí)與演示建立起對(duì)深度學(xué)習(xí)與Pytorch框架的感性認(rèn)知。
本書(shū)內(nèi)容以Python完成全部代碼構(gòu)建與程序演示。本章的主要目標(biāo)是幫助初次接觸Python與Pytorch的讀者搭建好開(kāi)發(fā)環(huán)境,認(rèn)識(shí)與理解Pytorch框架中常見(jiàn)的基礎(chǔ)操作函數(shù)、學(xué)會(huì)使用它們完成一些基礎(chǔ)的數(shù)據(jù)處理與流程處理,為后續(xù)內(nèi)容學(xué)習(xí)打下良好基礎(chǔ)。
好了,下面就讓我們來(lái)一起開(kāi)啟這段Pytorch框架的深度學(xué)習(xí)破冰之旅。
1.1 Pytorch介紹
Pytorch是開(kāi)放源代碼的機(jī)器學(xué)習(xí)框架,目的是加速?gòu)难芯吭偷疆a(chǎn)品開(kāi)發(fā)的過(guò)程。其 SDK主要基于Python語(yǔ)言,而Python語(yǔ)言作為流行的人工智能開(kāi)發(fā)語(yǔ)言一直很受研究者與開(kāi)發(fā)者的歡迎。其模型訓(xùn)練支持CPU與GPU、支持分布式訓(xùn)練、云部署、針對(duì)深度學(xué)習(xí)特定領(lǐng)域有不同的豐富的擴(kuò)展庫(kù)。
1.1.1 Pytorch歷史
Pytorch在2016年由facebook發(fā)布的開(kāi)源機(jī)器學(xué)習(xí)(深度學(xué)習(xí))框架,Pytorch最初的來(lái)源歷史可以追溯到另外兩個(gè)機(jī)器學(xué)習(xí)框架,第一個(gè)是torch框架,第二個(gè)是Chainer,實(shí)現(xiàn)了Eager模式與自動(dòng)微分,Pytoch集成了這兩個(gè)框架的優(yōu)點(diǎn), 把Python語(yǔ)言作為框架的首選編程語(yǔ)言,所以它的名字是在torch的前面加上Py之后的Pytorch。由于Pytorch吸取了之前一些深度學(xué)習(xí)框架優(yōu)點(diǎn),開(kāi)發(fā)難度大大降低、很容易構(gòu)建各種深度學(xué)習(xí)模型并實(shí)現(xiàn)分布式的訓(xùn)練,因此一發(fā)布就引發(fā)學(xué)術(shù)界的追捧熱潮,成為深度學(xué)習(xí)研究者與愛(ài)好者的首選開(kāi)發(fā)工具。在pytorch發(fā)布之后兩年的2018年facebook又把caffe2項(xiàng)目整合到pytorch框架中,這樣pytorch就進(jìn)一步整合原來(lái)caffe開(kāi)發(fā)者生態(tài)社區(qū),因?yàn)槠溟_(kāi)發(fā)效率高、特別容易構(gòu)建各種復(fù)雜的深度學(xué)習(xí)模型網(wǎng)絡(luò),因此很快得到大量人工智能開(kāi)發(fā)者的認(rèn)可與追捧,也成為工業(yè)界最受歡迎的深度學(xué)習(xí)框架之一。
Pytorch發(fā)展至今,其版本跟功能幾經(jīng)迭代,針對(duì)不同的場(chǎng)景任務(wù)分裂出不同的分支擴(kuò)展庫(kù),比如針對(duì)自然語(yǔ)言處理(NLP)的torchtext、針對(duì)計(jì)算機(jī)視覺(jué)的torchvision、針對(duì)語(yǔ)音處理的torchaudio,這些庫(kù)支持快速模型訓(xùn)練與演示應(yīng)用,可以幫助開(kāi)發(fā)者快速搭建原型演示。此外在移動(dòng)端支持、模型部署的壓縮、量化、服務(wù)器端云化部署、推理端SDK支持等方面Pytorch也在不斷的演化改進(jìn)。
在操作系統(tǒng)與SDK支持方面,Pytorch從最初的單純支持Python語(yǔ)言到如今支持Python/C++/Java主流編程語(yǔ)言,目前已經(jīng)支持Linux、Windows、MacOS等主流的操作系統(tǒng)、同時(shí)全面支持Android與iOS移動(dòng)端部署。
在版本發(fā)布管理方面,Pytorch分為三種不同的版本分別是穩(wěn)定版本(Stable Release)、Beta版本、原型版本(Prototype)。其中穩(wěn)定版本長(zhǎng)期支持維護(hù)沒(méi)有明顯的性能問(wèn)題與缺陷,理論上支持向后兼容的版本;Beta版本是基于用戶(hù)反饋的改動(dòng)版本,可能有API/SDK函數(shù)改動(dòng),性能有進(jìn)一步需要提升的空間;原型版本是新功能還不可以,需要開(kāi)發(fā)不能通過(guò)pip方式直接安裝。
1.1.2 Pytorch的模塊與功能
Pytorch當(dāng)前支持絕大數(shù)的深度學(xué)習(xí)常見(jiàn)的算子操作,基于相關(guān)的功能模塊可以快速整合數(shù)據(jù)、構(gòu)建與設(shè)計(jì)模型、實(shí)現(xiàn)模型訓(xùn)練、導(dǎo)出與部署等操作。這些功能的相關(guān)模塊主要有如下:
torch.nn包,里面主要包含構(gòu)建卷積神經(jīng)網(wǎng)絡(luò)的各種算子操作,主要包括卷積操作(Conv2d、Conv1d、Conv3d)激活函數(shù)、序貫?zāi)P?Sequential)、功能函數(shù)(functional)、損失功能、支持自定義的模型類(lèi)(Module)等。通過(guò)它們就可以實(shí)現(xiàn)大多數(shù)的模型結(jié)構(gòu)搭建與生成。
torch.utils包,里面主要包括訓(xùn)練模型的輸入數(shù)據(jù)處理類(lèi)、pytorch自帶的模型庫(kù)、模型訓(xùn)練時(shí)候可視化支持組件、檢查點(diǎn)與性能相關(guān)的組件功能。重要的類(lèi)有數(shù)據(jù)集類(lèi)(Dataset), 數(shù)據(jù)加載類(lèi)(DataLoader)、自定義編程的可視化支持組件tensorboard相關(guān)類(lèi)、
torch開(kāi)頭的一些包與功能,主要包括支持模型導(dǎo)出功能的torch.onnx模塊、優(yōu)化器torch.optim模塊、支持GPU訓(xùn)練torch.cuda模塊,這些都是會(huì)經(jīng)常用的。
此外本書(shū)當(dāng)中還會(huì)重點(diǎn)關(guān)注的torchvison庫(kù)中的一些常見(jiàn)模型庫(kù)與功能函數(shù),主要包括對(duì)象檢測(cè)模塊與模型庫(kù)、圖象數(shù)據(jù)增強(qiáng)與預(yù)處理模塊等。
以上并不是pytorch框架中全部模塊與功能說(shuō)明,作者這里只列出了跟本書(shū)內(nèi)容關(guān)聯(lián)密切必須掌握的一些模塊功能,希望讀者可以更好的針對(duì)性學(xué)習(xí),掌握這些知識(shí)。
1.1.3 Pytorch框架現(xiàn)狀與趨勢(shì)
Pytorch是深度學(xué)習(xí)框架的后起之秀,它參考了市場(chǎng)上早期框架包括torch、caffe、tensorflow的經(jīng)驗(yàn)教訓(xùn),從一開(kāi)始設(shè)計(jì)就特別注重開(kāi)發(fā)者體驗(yàn)與生產(chǎn)效率提升,一經(jīng)發(fā)布就引發(fā)追捧熱潮,可以說(shuō)“出道即巔峰”。Pytorch雖然來(lái)自臉書(shū)實(shí)驗(yàn)室,但是它也吸引外部公司包括特斯拉、優(yōu)步、亞馬遜、微軟、阿里等積極支持,其平緩的學(xué)習(xí)曲線,簡(jiǎn)潔方便的函數(shù)與模型構(gòu)建在短時(shí)間內(nèi)吸引了大量學(xué)術(shù)研究者與工業(yè)界開(kāi)發(fā)者的追捧。
當(dāng)前無(wú)論是在學(xué)術(shù)界還是工業(yè)界Pytorch已經(jīng)是主流深度學(xué)習(xí)框架之一,而且大有后來(lái)居上之勢(shì),因此隨著人工智能賦能各行各業(yè),Pytorch框架必然會(huì)更加得到開(kāi)發(fā)者的青睞,成為人工智能(AI)開(kāi)發(fā)者必備技能之一。同時(shí)Pytorch也會(huì)在部署跟推理方面會(huì)更加完善與方便,加強(qiáng)支持移動(dòng)端,嵌入式端等應(yīng)用場(chǎng)景,相信掌握Pytorch框架的開(kāi)發(fā)技術(shù)人才也會(huì)得到豐厚回報(bào)。
1.2 環(huán)境搭建
Pytorch的開(kāi)發(fā)環(huán)境搭建十分的簡(jiǎn)潔,它的依賴(lài)只有Python語(yǔ)言SDK,只要有了Python語(yǔ)言包支持,無(wú)論是在windows平臺(tái)、ubuntu平臺(tái)還是Mac平臺(tái)都靠一條命令行就可以完成安裝。首先是安裝Python語(yǔ)言包支持,當(dāng)前Pytorch支持的Python語(yǔ)言版本與系統(tǒng)對(duì)應(yīng)列表如下:
表-1(參考Pytorch官網(wǎng)與Github)
當(dāng)前最新穩(wěn)定版本是Pytorch 1.9.0、長(zhǎng)期支持版本是Pytorch1.8.2(LTS),此外Python語(yǔ)言支持版本3.6表示支持3.6.x版本,其中x表示3.6版本下的各個(gè)小版本,依此類(lèi)推3.7、3.8同樣如此。本書(shū)代碼演示以Python3.6.5版本作為Python支持語(yǔ)言包。它在Windows系統(tǒng)下的安裝過(guò)程非常簡(jiǎn)單,只需如下幾步:
1. 下載Python3.6.5安裝包,地址為:
https://www.python.org/ftp/python/3.6.5/python-3.6.5-amd64.exe
2. 下載之后,雙擊exe文件安裝,顯示的界面如下:
圖1-1(Python3.6.5安裝界面)
注意:圖1-1中的矩形框,必須手動(dòng)選擇上“add Python3.6 to PATH”之后再點(diǎn)擊【Install Now】默認(rèn)安裝完成即可。
3. 安裝好Python語(yǔ)言包支持以后可以通過(guò)命令行來(lái)驗(yàn)證測(cè)試安裝是否成功,首先通過(guò)cmd打開(kāi)Window命令行窗口,然后輸入Python,顯示如下:
圖1-2(驗(yàn)證Python命令行模式)
如果顯示圖1-2所示的信息表示已經(jīng)安裝成功Python語(yǔ)言包支持;如果輸入Python之后顯示信息為“'python' 不是內(nèi)部或外部命令,也不是可運(yùn)行的程序”則說(shuō)明第二步中沒(méi)有勾選上“add Python3.6 to PATH”,此時(shí)請(qǐng)手動(dòng)把python.exe所在路徑添加到Windows系統(tǒng)的環(huán)境變量中去之后再次執(zhí)行即可。
4. 安裝好Python語(yǔ)言包支持之后,只要運(yùn)行下面的命令行即可完成Pytorch框架的安裝,GPU支持版本的命令行如下(需要GPU顯卡支持):
pip install torch==1.9.0+cu102 torchvision==0.10.0+cu102 torchaudio===0.9.0 -f
https://download.pytorch.org/whl/torch_stable.html
CPU支持版本的命令行如下(沒(méi)有GPU顯示支持):
pip install torch torchvision torchaudio
5. 在執(zhí)行第三步的基礎(chǔ)上,在命令行中輸入下面兩行代碼,執(zhí)行結(jié)果如下:
>>> import torch
>>> torch._ _version_ _
'1.9.0+cu102'
其中第一行表示導(dǎo)入pytorch的包支持,第二行表示版本查詢(xún),第三行是執(zhí)行結(jié)果(GPU版本)。
現(xiàn)在很多開(kāi)發(fā)者喜歡使用Ubuntu開(kāi)發(fā)系統(tǒng),在Ubuntu系統(tǒng)下如下正確安裝與配置Pytorch,第一步同樣是安裝python語(yǔ)言依賴(lài)包Python3.6,主要是執(zhí)行一系列的安裝命令行,具體步驟如下:
1. 導(dǎo)入第三方軟件倉(cāng)庫(kù)
sudo add-apt-repository ppa:jonathonf/python-3.6
2. 更新與安裝python3.6
sudo apt-get update
sudo apt-get install python3.6
3. 刪除默認(rèn)python版本設(shè)置
zhigang@ubuntu:/usr/bin$ sudo rm python
4. 把安裝好的3.6設(shè)置為默認(rèn)版本
zhigang@ubuntu:/usr/bin$ sudo ln -s python3.6 /usr/bin/python
5. 檢查與驗(yàn)證
zhigang@ubuntu:~$ python -V
Python 3.6.5
成功完成上述五個(gè)步驟的命令行執(zhí)行就完成了Python語(yǔ)言包依賴(lài)安裝,然后安裝Pytorch框架,CPU版本執(zhí)行命令行如下:
pip3 install torch==1.9.0+cpu torchvision==0.10.0+cpu torchaudio==0.9.0 -f https://download.pytorch.org/whl/torch_stable.html
GPU版本執(zhí)行命令行如下:
pip3 install torch torchvision torchaudio
然后執(zhí)行與Windows下相同的命令行完成pytorch安裝校驗(yàn)測(cè)試。這樣我們就完成了Pytorch的環(huán)境搭建,這里有個(gè)很特別的地方需要注意,就是Pytorch的GPU版本需要CUDA驅(qū)動(dòng)支持與CUDA庫(kù)的安裝配置支持。關(guān)于這塊的安裝強(qiáng)烈建議參照英偉達(dá)官方網(wǎng)站的安裝指導(dǎo)與開(kāi)發(fā)者手冊(cè)。
1.3 Pytorch基礎(chǔ)術(shù)語(yǔ)與概念
很多人開(kāi)始學(xué)習(xí)深度學(xué)習(xí)框架面臨的第一個(gè)問(wèn)題就是專(zhuān)業(yè)術(shù)語(yǔ)理解跟基本的編程概念與傳統(tǒng)面向?qū)ο缶幊滩灰粯?,這個(gè)是初學(xué)者面臨的第一個(gè)學(xué)習(xí)障礙。在主流的面向?qū)ο缶幊陶Z(yǔ)言中,結(jié)構(gòu)化代碼最常見(jiàn)的關(guān)鍵字是if、else、while、for等關(guān)鍵字,而在深度學(xué)習(xí)框架中編程模式主要是基于計(jì)算圖、張量數(shù)據(jù)、自動(dòng)微分、優(yōu)化器等組件構(gòu)成。面向?qū)ο缶幊踢\(yùn)行的結(jié)果是交互式可視化的,而深度學(xué)習(xí)通過(guò)訓(xùn)練模型生成模型文件,然后再使用模型預(yù)測(cè),本質(zhì)數(shù)據(jù)流圖的方式工作。所以學(xué)習(xí)深度學(xué)習(xí)首先必須厘清深度學(xué)習(xí)編程中計(jì)算圖、張量數(shù)據(jù)、自動(dòng)微分、優(yōu)化器這些基本術(shù)語(yǔ)概念,下面分別解釋如下:
張量
張量是深度學(xué)習(xí)編程框架中需要理解最重要的一個(gè)概念,張量的本質(zhì)是數(shù)據(jù),在深度學(xué)習(xí)框架中一切的數(shù)據(jù)都可以看成張量。深度學(xué)習(xí)中的計(jì)算圖是以張量數(shù)據(jù)為輸入,通過(guò)算子運(yùn)算,實(shí)現(xiàn)對(duì)整個(gè)計(jì)算圖參數(shù)的評(píng)估優(yōu)化。但是到底什么是張量?可以看下面這張圖:
圖1-3(張量表示)
上圖1-3中標(biāo)量、向量、數(shù)組、3D、4D、5D數(shù)據(jù)矩陣在深度學(xué)習(xí)框架中都被稱(chēng)為張量??梢?jiàn)在深度學(xué)習(xí)框架中所有的數(shù)據(jù)都是張量形式存在,張量是深度學(xué)習(xí)數(shù)據(jù)組織與存在一種數(shù)據(jù)類(lèi)型。
算子/操作數(shù)
深度學(xué)習(xí)主要是針對(duì)張量的數(shù)據(jù)操作、這些數(shù)據(jù)操作從簡(jiǎn)單到復(fù)雜、多數(shù)都是以矩陣計(jì)算的形式存在,最常見(jiàn)的矩陣操作就是加減乘除、此外卷積、池化、激活、也是模型構(gòu)建中非常有用的算子/操作數(shù)。Pytorch支持自定義算子操作,可以通過(guò)自定義算子實(shí)現(xiàn)復(fù)雜的網(wǎng)絡(luò)結(jié)構(gòu),構(gòu)建一些特殊的網(wǎng)絡(luò)模型。張量跟算子/操作數(shù)一起構(gòu)成了計(jì)算圖,它們是也是計(jì)算圖的基本組成要素。
計(jì)算圖
深度學(xué)習(xí)是基于計(jì)算圖完成模型構(gòu)建,實(shí)現(xiàn)數(shù)據(jù)在各個(gè)計(jì)算圖節(jié)點(diǎn)之間流動(dòng),最終輸出,因此計(jì)算圖又被稱(chēng)為數(shù)據(jù)流圖。根據(jù)構(gòu)建計(jì)算圖的方式不同還可以分為靜態(tài)圖與動(dòng)態(tài)圖,Pytorch默認(rèn)是基于動(dòng)態(tài)圖的方式構(gòu)建計(jì)算圖,動(dòng)態(tài)圖采用類(lèi)似python語(yǔ)法,可以隨時(shí)運(yùn)行,靈活修改調(diào)整;而靜態(tài)圖則是效率優(yōu)先,但是在圖構(gòu)建完成之前無(wú)法直接運(yùn)行??梢钥闯鰟?dòng)態(tài)圖更加趨向于開(kāi)發(fā)者平時(shí)接觸的面向?qū)ο蟮木幊谭绞?,也更容易被開(kāi)發(fā)者理解與接受。下圖是一個(gè)簡(jiǎn)單的計(jì)算圖示例:
圖1-4(計(jì)算圖示意)
圖1-4中最底層三個(gè)節(jié)點(diǎn)表示計(jì)算圖的輸入張量數(shù)據(jù)節(jié)點(diǎn)(a、b、c)、剩下節(jié)點(diǎn)表示操作、帶箭頭的線段表示數(shù)據(jù)的流向。
自動(dòng)微分
使用Pytorch構(gòu)建神經(jīng)網(wǎng)絡(luò)(計(jì)算圖)模型之后,一般都是通過(guò)反向傳播進(jìn)行訓(xùn)練,使用反向傳播算法對(duì)神經(jīng)網(wǎng)絡(luò)中每個(gè)參數(shù)根據(jù)損失函數(shù)功能根據(jù)梯度進(jìn)行參數(shù)值的調(diào)整。為了計(jì)算這些梯度完成參數(shù)調(diào)整,深度學(xué)習(xí)框架中都會(huì)自帶一個(gè)叫做自動(dòng)微分的內(nèi)置模塊,來(lái)自動(dòng)計(jì)算神經(jīng)網(wǎng)絡(luò)模型訓(xùn)練時(shí)候的各個(gè)參數(shù)梯度值并完成參數(shù)值更新,這種技術(shù)就是深度學(xué)習(xí)框架中的自動(dòng)微分。
1.4 Pytorch基礎(chǔ)操作
前面我們已經(jīng)安裝并驗(yàn)證好了Pytorch框架,解釋了深度學(xué)習(xí)框架中一些常見(jiàn)術(shù)語(yǔ)與基本概念。本節(jié)重點(diǎn)介紹Pytorch中一些基本的數(shù)據(jù)定義與類(lèi)型轉(zhuǎn)換、算子操作、通過(guò)它們幫助讀者進(jìn)一步了解Pytorch開(kāi)發(fā)基礎(chǔ)知識(shí),為后續(xù)章節(jié)學(xué)習(xí)打下良好基礎(chǔ)。在正式開(kāi)始這些基礎(chǔ)操作之前,我們首先需要有一個(gè)合適的集成開(kāi)發(fā)環(huán)境(IDE),本書(shū)的源代碼是基于Python實(shí)現(xiàn),演示的集成開(kāi)發(fā)環(huán)境(IDE)是PyCharm。
1.4.1 PyCharm的安裝與配置
首先是從Pycharm官方網(wǎng)站上下載Pycharm,版本有專(zhuān)業(yè)版與社區(qū)版之分,社區(qū)版免費(fèi)使用而專(zhuān)業(yè)版則需要付費(fèi)使用。Pycharm官方網(wǎng)站如下:
https://www.jetbrains.com/pycharm/
點(diǎn)擊就可以下載專(zhuān)業(yè)版試用或者社區(qū)免費(fèi)版,默認(rèn)安裝之后就可以通過(guò)桌面圖標(biāo)雙擊打開(kāi)如下:
圖1-5(Pycharm導(dǎo)航頁(yè)面)
點(diǎn)擊【New Project】,輸入項(xiàng)目名稱(chēng),顯示如下:
圖1-6(創(chuàng)建新項(xiàng)目)
點(diǎn)擊【Create】按鈕完成項(xiàng)目創(chuàng)建,選擇文件(File)->設(shè)置(Setting)選項(xiàng):
圖1-7(設(shè)置選項(xiàng))
圖1-8(設(shè)置系統(tǒng)Python解釋器)
完成之后,在項(xiàng)目中創(chuàng)建一個(gè)空的python文件命名為main.py,然后直接輸入下面兩行測(cè)試代碼:
import torch
print(torch.__version__)
執(zhí)行測(cè)試(作者筆記本):
1.9.0+cu102
這樣我們就完成了PyCharm IDE開(kāi)發(fā)環(huán)境配置與項(xiàng)目創(chuàng)建。
1.4.2 張量定義與聲明
張量在Pytorch深度學(xué)習(xí)框架中表示的數(shù)據(jù),有幾種不同的方式來(lái)創(chuàng)建與聲明張量數(shù)據(jù),一種是通過(guò)常量數(shù)值來(lái)直接聲明為tensor數(shù)據(jù),代碼如下:
a = torch.tensor([[2., 3.], [4., 5.]])
print(a, a.dtype)
運(yùn)行結(jié)果
tensor([[2., 3.],
[4., 5.]]) torch.float32
其中torch.Tensor是torch.FloatTensor的別名,所以默認(rèn)的數(shù)據(jù)類(lèi)型是flaot32,這點(diǎn)從a.dtype的打印結(jié)果上也得了印證。此外torch.Tensor函數(shù)還支持從Numpy數(shù)組直接轉(zhuǎn)換為張量數(shù)據(jù),這種定義聲明張量數(shù)據(jù)的代碼如下:
b = torch.tensor(np.array([[1,2],[3,4],[5,6],[7, 8]]))
print(b)
運(yùn)行結(jié)果:
tensor([[1, 2],
[3, 4],
[5, 6],
[7, 8]], dtype=torch.int32)
根據(jù)數(shù)據(jù)類(lèi)型的自動(dòng)識(shí)別,轉(zhuǎn)換為torch.int32的數(shù)據(jù)類(lèi)型。除了直接聲明常量數(shù)組的方式,Pytorch框架還支持類(lèi)似Matlab方式的數(shù)組初始化方式,可以定義數(shù)組的維度,然后初始化為零,相關(guān)的演示代碼如下:
c = torch.zeros([2, 4], dtype=torch.float32)
print(c)
運(yùn)行結(jié)果:
tensor([[0., 0., 0., 0.],
[0., 0., 0., 0.]])
初始化了一個(gè)兩行四列值全部為零的數(shù)組。torch.zeros表示初始化全部為零,torch.ones表示初始化全部為1,torch.ones的代碼演示如下:
d = torch.ones([2, 4], dtype=torch.float32)
print(d)
運(yùn)行結(jié)果:
tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.]])
上面都是創(chuàng)建常量數(shù)組的方式。在實(shí)際的開(kāi)發(fā)中,經(jīng)常需要隨機(jī)初始化一些張量變量,創(chuàng)建張量并隨機(jī)初始化的方式主要通過(guò)torch.rand函數(shù)實(shí)現(xiàn)。用該函數(shù)創(chuàng)建張量的代碼演示如下:
v1 = torch.rand((2, 3))
print("v1 = ", v1)
torch.initial_seed()
v2 = torch.rand((2, 3))
print("v2 = ", v2)
v3 = torch.randint(0, 255, (4, 4))
print("v3 = ", v3)
運(yùn)行結(jié)果:
v1 = tensor([[0.5257, 0.4236, 0.0409],
[0.3271, 0.6173, 0.8080]])
v2 = tensor([[0.9671, 0.6011, 0.3136],
[0.7428, 0.9261, 0.6602]])
v3 = tensor([[181, 170, 49, 82],
[209, 25, 0, 210],
[ 65, 220, 93, 11],
[133, 102, 64, 230]])
其中v1是直接輸出、v2首先隨機(jī)初始化種子之后再輸出、v3是函數(shù)torch.randint創(chuàng)建的隨機(jī)數(shù)組,它的前面兩個(gè)值0跟255表示整數(shù)的取值范圍為0~255之間,最后一個(gè)(4,4)表示創(chuàng)建4x4大小的數(shù)組。
1.4.3 張量操作
通過(guò)前面一小節(jié),我們已經(jīng)學(xué)會(huì)了在Pytorch中如何創(chuàng)建張量,本節(jié)將介紹張量常見(jiàn)的算子操作,通過(guò)這些操作進(jìn)一步加深對(duì)Pytorch的理解。
計(jì)算圖操作
還記得圖1-4的計(jì)算圖嗎?這里我們就通過(guò)代碼構(gòu)建這樣一個(gè)計(jì)算圖,完成一系列基于張量的算子操作,演示代碼如下:
a = torch.tensor([[2., 3.], [4., 5.]])
b = torch.tensor([[10, 20], [30, 40]])
c = torch.tensor([[0.1], [0.2]])
x = a + b
y = torch.matmul(x, c)
print("y: ", y)
運(yùn)行結(jié)果如下:
y: tensor([[ 5.8000],
[12.4000]])
上面得代碼中x是a加b的結(jié)果,y是a加b之和與c的矩陣乘法的最終輸出結(jié)果。
數(shù)據(jù)類(lèi)型轉(zhuǎn)換
在實(shí)際的開(kāi)發(fā)過(guò)程中,我們經(jīng)常需要在不同類(lèi)型的數(shù)據(jù)張量中切換,因此數(shù)據(jù)類(lèi)型轉(zhuǎn)換函數(shù)也是必修的,代碼演示如下:
m = torch.tensor([1.,2.,3.,4.,5.,6], dtype=torch.float32)
print(m, m.dtype)
print(m.int())
print(m.long())
print(m.double())
運(yùn)行結(jié)果如下:
tensor([1., 2., 3., 4., 5., 6.]) torch.float32
tensor([1, 2, 3, 4, 5, 6], dtype=torch.int32)
tensor([1, 2, 3, 4, 5, 6])
tensor([1., 2., 3., 4., 5., 6.], dtype=torch.float64)
可見(jiàn),在PyTorch中實(shí)現(xiàn)數(shù)據(jù)類(lèi)型轉(zhuǎn)換非常的便捷, m.int()表示轉(zhuǎn)換偉32位整型、m.double()表示轉(zhuǎn)換位64位浮點(diǎn)數(shù)類(lèi)型、m.long()表示64位整型。
維度轉(zhuǎn)換
在Pytorch開(kāi)發(fā)中另外一個(gè)常見(jiàn)的基礎(chǔ)操作就是圖象維度轉(zhuǎn)換與升降維度操作,Pytorch中實(shí)現(xiàn)對(duì)張量數(shù)據(jù)的維度轉(zhuǎn)換與升降的代碼演示如下:
a = torch.arange(12.)
a = torch.reshape(a, (3, 4))
print("a: ", a)
a = torch.reshape(a, (-1, 6))
print("a: ", a)
a = torch.reshape(a, (-1, ))
print("a: ", a)
a = torch.reshape(a, (1, 1, 3, 4))
print("a: ", a)
運(yùn)行結(jié)果如下:
a: tensor([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.]])
a: tensor([[ 0., 1., 2., 3., 4., 5.],
[ 6., 7., 8., 9., 10., 11.]])
a: tensor([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11.])
a: tensor([[[[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.]]]])
其中a是聲明的張量數(shù)據(jù),torch.reshape(a, (3, 4))意思轉(zhuǎn)換為3行4列的二維數(shù)組、torch.reshape(a, (-1, 6))表示轉(zhuǎn)為每行6列的二維數(shù)組,其中-1表示從列數(shù)推理得到行數(shù)、torch.reshape(a, (-1, ))表示直接轉(zhuǎn)換為一行、torch.reshape(a, (1, 1, 3, 4))表示轉(zhuǎn)為1x1x3x4的四維張量。除了torch.reshape函數(shù)之外,還有另外一個(gè)基于tensor的維度轉(zhuǎn)換方法tensor.view(), 它的用法代碼演示如下:
x = torch.randn(4, 4)
print(x.size())
x = x.view(-1, 8)
print(x.size())
x = x.view(1, 1, 4, 4)
print(x.size())
運(yùn)行結(jié)果如下:
torch.Size([4, 4])
torch.Size([2, 8])
torch.Size([1, 1, 4, 4])
其中torch.randn(4, 4)是創(chuàng)建一個(gè)4x4的隨機(jī)張量;x.view(-1, 8)表示轉(zhuǎn)換為每行八列的,-1表示自動(dòng)計(jì)算行數(shù);x.view(1, 1, 4, 4)表示轉(zhuǎn)換為1x1x4x4的四維張量。其中torch.size表示輸出數(shù)組維度大小。
其它屬性操作
通道交換與尋找最大值是Pytorch中處理張量數(shù)據(jù)常用操作之一,這兩個(gè)相關(guān)函數(shù)名稱(chēng)分別是torch.transpose與torch.argmax,支持張量直接操作。代碼演示如下:
x = torch.randn(5, 5, 3)
print(x.size())
x = x.transpose(2, 0)
print(x.size())
x = torch.tensor([2., 3., 4.,12., 3., 5., 8., 1.])
print(torch.argmax(x))
x = x.view(-1, 4)
print(x.argmax(1))
運(yùn)行結(jié)果如下:
torch.Size([5, 5, 3])
torch.Size([3, 5, 5])
tensor(3)
tensor([3, 2])
運(yùn)行結(jié)果的第一行對(duì)應(yīng)是聲明的張量x的維度信息、第二行是調(diào)用transpose方法完成通道交換之后x輸出的維度信息;第三行是針對(duì)x調(diào)用argmax得到最大值對(duì)應(yīng)索引(12對(duì)應(yīng)索引值為3)、第四行是進(jìn)行維度變換之后針對(duì)二維數(shù)據(jù)(2x4)的第二個(gè)維度調(diào)用argmax得到的輸出,分別是12與8對(duì)應(yīng)的索引值[3,2]。
CPU與GPU運(yùn)算支持
Pytorch支持CPU與GPU計(jì)算,默認(rèn)創(chuàng)建的tensor是CPU版本的,要想使用GPU版本,首先需要檢測(cè)GPU支持,然后轉(zhuǎn)換為GPU數(shù)據(jù),或者直接創(chuàng)建為GPU版本數(shù)據(jù),代碼演示如下:
gpu = torch.cuda.is_available()
for i in range(torch.cuda.device_count()):
print(torch.cuda.get_device_name(i))
if gpu:
print(x.cuda())
y = torch.tensor([1, 2, 3, 4], device="cuda:0")
print("y: ", y)
以上代碼查詢(xún)CUDA支持,如果支持打印GPU名稱(chēng)并把變量x變成GPU支持?jǐn)?shù)據(jù),并打印輸出。運(yùn)行結(jié)果如下:
GeForce GTX 1050 Ti
tensor([[ 2., 3., 4., 12.],
[ 3., 5., 8., 1.]], device='cuda:0')
y: tensor([1, 2, 3, 4], device='cuda:0')
這里x默認(rèn)是CPU類(lèi)型數(shù)據(jù),y是直接創(chuàng)建的GPU類(lèi)型數(shù)據(jù)。
以上都是一些最基礎(chǔ)跟使用頻率較高的Pytorch基礎(chǔ)操作,了解并掌握這些函數(shù)有助于進(jìn)一步學(xué)習(xí)本書(shū)后續(xù)章節(jié)知識(shí),更多關(guān)于Pytorch基礎(chǔ)操作的函數(shù)知識(shí)與參數(shù)說(shuō)明,讀者可以直接參見(jiàn)官方的開(kāi)發(fā)文檔。
1.5 線性回歸預(yù)測(cè)
上一小節(jié)介紹了Pytorch框架各種基礎(chǔ)操作,本節(jié)我們學(xué)習(xí)一個(gè)堪稱(chēng)是深度學(xué)習(xí)版本的Hello World程序,幫助讀者理解模型訓(xùn)練與參數(shù)優(yōu)化等基本概念,開(kāi)始我們學(xué)習(xí)Pytorch框架編程的愉快旅程。
1.5.1 線性回歸過(guò)程
很坦誠(chéng)的說(shuō),有很多資料把線性回歸表述的很復(fù)雜、一堆公式推導(dǎo)讓初學(xué)者望而生畏,無(wú)法準(zhǔn)確快速理解線性回歸,這里作者將通過(guò)一個(gè)碼農(nóng)的獨(dú)特視角來(lái)解釋線性回歸概念。線性回歸的本質(zhì)就是根據(jù)給出二維數(shù)據(jù)集來(lái)擬合生成一條直線,簡(jiǎn)單的圖示如下:
圖1-9(線性回歸與非線性回歸)
圖1-9左側(cè)是圖中得圓點(diǎn)表示xy二維坐標(biāo)點(diǎn)數(shù)據(jù)集,直線是根據(jù)線性回歸算法生成的。右側(cè)則是一個(gè)根據(jù)坐標(biāo)點(diǎn)數(shù)據(jù)集生成一個(gè)非線性回歸的例子。現(xiàn)在我們已經(jīng)可以很直觀的了解什么線性回歸了,腦子里面可能會(huì)有個(gè)大大的疑問(wèn)(?),線性回歸是怎么找到這條直線的?答案就是通過(guò)Pytorch構(gòu)建一個(gè)簡(jiǎn)單的計(jì)算圖來(lái)不斷學(xué)習(xí),最終得到一個(gè)足夠逼近真實(shí)直線參數(shù)方程,這個(gè)過(guò)程也可以被稱(chēng)為線性回歸的學(xué)習(xí)/訓(xùn)練過(guò)程。最終根據(jù)得到的參數(shù)就可以繪制回歸直線。那這個(gè)計(jì)算圖到底是怎么樣的?答案就是很簡(jiǎn)單的數(shù)學(xué)知識(shí),最常見(jiàn)的直線方程如下:
y=kx+b
(公式1-1)
假設(shè)我們有二維的坐標(biāo)點(diǎn)數(shù)據(jù)集:
x: 1,2,0.5,2.5,2.6,3.1
y: 3.7,4.6,1.65,5.68,5.98,6.95
我們通過(guò)隨機(jī)賦值初始k、b兩個(gè)參數(shù),根據(jù)公式1-1,x會(huì)生成一個(gè)對(duì)應(yīng)輸出,它跟真實(shí)值y之間的差值我們稱(chēng)為損失,最常見(jiàn)的為均值平方損失(MSE),表示如下:
MSE=1/n ∑?〖(y-y ?)〗^2
(公式1-2)
然后我們可以通過(guò)下面的公式來(lái)更新k、b兩個(gè)參數(shù):
更新參數(shù)(k",b")=參數(shù)(k,b)-學(xué)習(xí)率*對(duì)應(yīng)參數(shù)梯度
(公式1-3)
其中學(xué)習(xí)率通常用表示,對(duì)應(yīng)的每個(gè)參數(shù)梯度則根據(jù)深度學(xué)習(xí)框架的自動(dòng)微分機(jī)制得到的,這樣就實(shí)現(xiàn)了線性回歸模型模型的構(gòu)建與訓(xùn)練過(guò)程,最終根據(jù)輸入的迭代次數(shù)運(yùn)行輸出就獲取了回歸直線的兩個(gè)參數(shù)。完成了線性回歸的求解。
1.5.2 線性回歸代碼演示
通過(guò)前面一小節(jié)的學(xué)習(xí)讀者應(yīng)該了什么是線性回歸、線性回歸是如何工作的,現(xiàn)在我們已經(jīng)迫不及待的想在Pytorch中通過(guò)代碼來(lái)驗(yàn)證我們上面的理論解釋了。Pytorch提供了豐富的函數(shù)組件可以幫助我們快速搭建線性回歸模型并完成訓(xùn)練預(yù)測(cè)。
第一步:構(gòu)建數(shù)據(jù)集
x = np.array([1,2,0.5,2.5,2.6,3.1], dtype=np.float32).reshape((-1, 1))
y = np.array([3.7,4.6,1.65,5.68,5.98,6.95], dtype=np.float32).reshape(-1, 1)
第二步:根據(jù)公式1-1構(gòu)建線性回歸模型
class LinearRegressionModel(torch.nn.Module):
def __init__(self, input_dim, output_dim):
super(LinearRegressionModel, self).__init__()
self.linear = torch.nn.Linear(input_dim, output_dim)
def forward(self, x):
out = self.linear(x)
return out
LinearRegressionModel是一個(gè)自定義的類(lèi),繼承了torch.nn.Module,其中torch.nn.Linear就表示構(gòu)建了公式1-1的線性模型,重載方法forward,表示根據(jù)模型計(jì)算返回預(yù)測(cè)結(jié)果。
第三步:創(chuàng)建損失功能與優(yōu)化器
input_dim = 1
output_dim = 1
model = LinearRegressionModel(input_dim, output_dim)
criterion = torch.nn.MSELoss()
learning_rate = 0.01
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
其中MSELoss跟公式1-2表述一致、優(yōu)化器optimizer完成自動(dòng)梯度求解并根據(jù)公式1-3的方式來(lái)更新每個(gè)參數(shù)。
第四步:開(kāi)始迭代訓(xùn)練過(guò)程
for epoch in range(100):
epoch += 1
# Convert numpy array to torch Variable
inputs = torch.from_numpy(x).requires_grad_()
labels = torch.from_numpy(y)
# Clear gradients w.r.t. parameters
optimizer.zero_grad()
# Forward to get output
outputs = model(inputs)
# Calculate Loss
loss = criterion(outputs, labels)
# Getting gradients w.r.t. parameters
loss.backward()
# Updating parameters
optimizer.step()
print('epoch {}, loss {}'.format(epoch, loss.item()))
這部分的代碼注釋都很清楚了,這里就不再贅述。
第五步:根據(jù)訓(xùn)練得到的參數(shù),使用模型預(yù)測(cè)得到回歸直線并顯示,代碼如下:
predicted = model(torch.from_numpy(x).requires_grad_()).data.numpy()
# Plot true data
plt.plot(x, y, 'go', label='True data', alpha=0.5)
# Plot predictions
plt.plot(x, predicted_y, '--', label='Predictions', alpha=0.5)
# Legend and plot
plt.legend(loc='best')
plt.show()
運(yùn)行結(jié)果如下:
圖1-10中點(diǎn)表示訓(xùn)練數(shù)據(jù),直線表示線性回歸預(yù)測(cè)。
總結(jié)線性回歸這個(gè)入門(mén)級(jí)別例子演示,我們從中可以學(xué)習(xí)到一些基本組件函數(shù),它們就是模型創(chuàng)建、損失函數(shù)、學(xué)習(xí)率、優(yōu)化器,它們都是Pytroch開(kāi)發(fā)中必須掌握的基本組件函數(shù)與方法,學(xué)會(huì)使用它們可以事半功倍,減少代碼量,提升開(kāi)發(fā)效率。
1.6 小結(jié)
本章是Pytorch框架與基礎(chǔ)知識(shí)的介紹,通過(guò)本章學(xué)習(xí)了解Pytorch框架的歷史與發(fā)展、理解深度學(xué)習(xí)框架常見(jiàn)的術(shù)語(yǔ)與詞匯含義;安裝Python SDK、掌握Pytorch安裝命令行、Pycharm IDE安裝與配置。學(xué)會(huì)使用Pytorch創(chuàng)建基本的張量、能夠完成常見(jiàn)的張量數(shù)據(jù)操作、最后通過(guò)一個(gè)具有代表性的線性回歸的例子,幫助大家真正打開(kāi)Pytroch框架開(kāi)發(fā)的大門(mén)。
本章的目標(biāo)是幫助初學(xué)者厘清深度學(xué)習(xí)框架基本概念、基礎(chǔ)組件與基礎(chǔ)數(shù)據(jù)操作、同時(shí)通過(guò)案例激發(fā)起大家進(jìn)一步學(xué)習(xí)的興趣。