2.1 PyTorch介紹
- Pytorch是一個(gè)深度學(xué)習(xí)框架(類似于TensorFlow),由Facebook的人工智能研究小組開發(fā)。與Keras一樣,它也抽象出了深層網(wǎng)絡(luò)編程的許多混亂部分。
- 就高級(jí)和低級(jí)代碼風(fēng)格而言,Pytorch介于Keras和TensorFlow之間。比起Keras具有更大的靈活性和控制能力,但同時(shí)又不必進(jìn)行任何復(fù)雜的聲明式編程(declarative programming)。
- 考慮方面
- 定義模型的類與函數(shù)
- 繼承來自Torch庫(kù)的torch.nn.Module的類
- 張量和計(jì)算圖模型與標(biāo)準(zhǔn)數(shù)組的比較
- 只需要知道每個(gè)層的輸入和輸出大小
- 訓(xùn)練模型
2.2 環(huán)境配置
2.2.1 Anaconda
- Anaconda是Python的一個(gè)開源發(fā)行版本,主要面向科學(xué)計(jì)算。
- Anaconda預(yù)裝了很多我們用的到或用不到的第三方庫(kù)的Python
- 而且相比于大家熟悉的pip install命令,Anaconda中增加了conda install命令。
- 操作
- 根據(jù)操作系統(tǒng)下載并安裝Anaconda
- Anaconda安裝成功之后,建議修改其包管理鏡像為國(guó)內(nèi)源
- 比如,https://pypi.tuna.tsinghua.edu.cn/simple
2.2.2 Jupyter
- 打開notebook
- 在瀏覽器打開 http://localhost:8888 (通常會(huì)自動(dòng)打開)位于當(dāng)前目錄的jupyter 服務(wù)
-
使用notebook,可以直接在代碼旁寫出敘述性文檔,而不是另外編寫單獨(dú)的文檔。
2.2.3 PyTorch
- 課程需要用到PyTorch框架
- pip install torch==1.5.0
- 直接去PyTorch官網(wǎng)找到自己的軟硬件對(duì)應(yīng)的安裝命令即可。
2.3 數(shù)據(jù)操作
- 在深度學(xué)習(xí)中,通常會(huì)頻繁地對(duì)數(shù)據(jù)進(jìn)行操作。
- 在PyTorch中,torch.Tensor是存儲(chǔ)和變換數(shù)據(jù)的主要工具。
- 如果之前用過NumPy,會(huì)發(fā)現(xiàn)Tensor和NumPy的多維數(shù)組非常類似。
- 然而,Tensor提供GPU計(jì)算和自動(dòng)求梯度等更多功能,這些使Tensor更加適合深度學(xué)習(xí)。
- "tensor"這個(gè)單詞一般可譯作“張量”,張量可以看作是一個(gè)多維數(shù)組。
- 標(biāo)量可以看作是0維張量,向量可以看作1維張量,矩陣可以看作是二維張量。
-
下列這些創(chuàng)建方法都可以在創(chuàng)建的時(shí)候指定數(shù)據(jù)類型dtype和存放device(cpu/gpu)
- 索引
- 還可以使用類似NumPy的索引操作來訪問Tensor的一部分。
- 需要注意的是:索引出來的結(jié)果與原數(shù)據(jù)共享內(nèi)存,也即修改一個(gè),另一個(gè)會(huì)跟著修改。
- 改變形狀
- 用view()來改變Tensor的形狀:
- 注意view()返回的新Tensor與源Tensor雖然可能有不同的size,但是是共享data的,也即更改其中的一個(gè),另外一個(gè)也會(huì)跟著改變。
- view僅僅是改變了對(duì)這個(gè)張量的觀察角度,內(nèi)部數(shù)據(jù)并未改變
- 注意view()返回的新Tensor與源Tensor雖然可能有不同的size,但是是共享data的,也即更改其中的一個(gè),另外一個(gè)也會(huì)跟著改變。
- 所以如果想返回一個(gè)真正新的副本(即不共享data內(nèi)存)該怎么辦呢?
- Pytorch還提供了一個(gè)reshape()可以改變形狀,但是此函數(shù)并不能保證返回的是其拷貝,所以不推薦使用。
- 推薦先用clone創(chuàng)造一個(gè)副本然后再使用view。
- 使用clone還有一個(gè)好處是會(huì)被記錄在計(jì)算圖中,即梯度回傳到副本時(shí)也會(huì)傳到源Tensor。
- 另外一個(gè)常用的函數(shù)就是item(), 它可以將一個(gè)標(biāo)量Tensor轉(zhuǎn)換成一個(gè)Python number
- 用view()來改變Tensor的形狀:
- 線性代數(shù)
-
PyTorch還支持一些線性函數(shù)
- PyTorch中的Tensor支持超過一百種操作,包括轉(zhuǎn)置、索引、切片、數(shù)學(xué)運(yùn)算、線性代數(shù)、隨機(jī)數(shù)等等。
-
- 廣播機(jī)制
- 前面看到如何對(duì)兩個(gè)形狀相同的Tensor做按元素運(yùn)算。
- 當(dāng)對(duì)兩個(gè)形狀不同的Tensor按元素運(yùn)算時(shí),可能會(huì)觸發(fā)廣播(broadcasting)機(jī)制:先適當(dāng)復(fù)制元素使這兩個(gè)Tensor形狀相同后再按元素運(yùn)算。
- 運(yùn)算的內(nèi)存開銷
- 索引操作是不會(huì)開辟新內(nèi)存的,而像y = x + y這樣的運(yùn)算是會(huì)新開內(nèi)存的,然后將y指向新內(nèi)存。
- 如果想指定結(jié)果到原來的y的內(nèi)存,可以使用前面介紹的索引來進(jìn)行替換操作。
- 還可以使用運(yùn)算符全名函數(shù)中的out參數(shù)或者自加運(yùn)算符+=(也即add_())達(dá)到上述效果。
- 注:雖然view返回的Tensor與源Tensor是共享data的,但是依然是一個(gè)新的Tensor(因?yàn)門ensor除了包含data外還有一些其他屬性),二者id(內(nèi)存地址)并不一致。
- 索引操作是不會(huì)開辟新內(nèi)存的,而像y = x + y這樣的運(yùn)算是會(huì)新開內(nèi)存的,然后將y指向新內(nèi)存。
- Tensor和NumPy相互轉(zhuǎn)換
- 用numpy()和from_numpy()將Tensor和NumPy中的數(shù)組相互轉(zhuǎn)換。
- 但是需要注意的一點(diǎn)是: 這兩個(gè)函數(shù)所產(chǎn)生的的Tensor和NumPy中的數(shù)組共享相同的內(nèi)存
- 所有在CPU上的Tensor(除了CharTensor)都支持與NumPy數(shù)組相互轉(zhuǎn)換。
- 還有一個(gè)常用的將NumPy中的array轉(zhuǎn)換成Tensor的方法就是torch.tensor()。
- 需要注意的是,此方法總是會(huì)進(jìn)行數(shù)據(jù)拷貝(就會(huì)消耗更多的時(shí)間和空間),所以返回的Tensor和原來的數(shù)據(jù)不再共享內(nèi)存。
- 用numpy()和from_numpy()將Tensor和NumPy中的數(shù)組相互轉(zhuǎn)換。
- Tensor on GPU
- 用方法to()可以將Tensor在CPU和GPU(需要硬件支持)之間相互移動(dòng)。
2.4 梯度下降
- 梯度下降是機(jī)器學(xué)習(xí)中常見優(yōu)化算法之一,梯度下降法有以下幾個(gè)作用:
- 在求解機(jī)器學(xué)習(xí)算法的模型參數(shù),即無約束優(yōu)化問題時(shí),主要有梯度下降法(Gradient Descent)和最小二乘法。
- 在求解損失函數(shù)的最小值時(shí),可以通過梯度下降法來一步步的迭代求解,得到最小化的損失函數(shù)和模型參數(shù)值。
- 如果我們需要求解損失函數(shù)的最大值,可通過梯度上升法來迭代。
-
梯度下降法主要有隨機(jī)梯度下降法和批量梯度下降法。
2.4.1 梯度下降核心思想
- 初始化參數(shù),隨機(jī)選取取值范圍內(nèi)的任意數(shù);
- 迭代操作:
-
計(jì)算當(dāng)前梯度;
-
修改新的變量;
- 計(jì)算朝最陡的下坡方向走一步;
- 判斷是否需要終止,如否,返回a
-
- 得到全局最優(yōu)解或者接近全局最優(yōu)解
2.4.2 隨機(jī)梯度和批量梯度
-
小批量梯度下降
2.4.3 自動(dòng)求梯度概念
- Tensor是這個(gè)包的核心類,如果將其屬性.requires_grad設(shè)置為True,它將開始追蹤(track)在其上的所有操作。
- 完成計(jì)算后,可以調(diào)用.backward()來完成所有梯度計(jì)算。
- 此Tensor的梯度將累積到.grad屬性中。
- 注意在y.backward()時(shí),如果y是標(biāo)量,則不需要為backward()傳入任何參數(shù);否則,需要傳入一個(gè)與y同形的Tensor。
- 如果不想要被繼續(xù)追蹤,可以調(diào)用.detach()將其從追蹤記錄中分離出來,這樣就可以防止將來的計(jì)算被追蹤,這樣梯度就傳不過去了。
- 還可以用with torch.no_grad()將不想被追蹤的操作代碼塊包裹起來
- Function是另外一個(gè)很重要的類。
- Tensor和Function互相結(jié)合就可以構(gòu)建一個(gè)記錄有整個(gè)計(jì)算過程的有向無環(huán)圖(DAG)。
- 每個(gè)Tensor都有一個(gè).grad_fn屬性,該屬性即創(chuàng)建該Tensor的Function, 就是說該Tensor是不是通過某些運(yùn)算得到的,若是,則grad_fn返回一個(gè)與這些運(yùn)算相關(guān)的對(duì)象,否則是None。
2.4.4 梯度
-
數(shù)學(xué)上,如果有一個(gè)函數(shù)值和自變量都為向量的函數(shù) 那么 關(guān)于 的梯度就是一個(gè)雅可比矩陣(Jacobian matrix):
- 而torch.autograd這個(gè)包就是用來計(jì)算一些雅克比矩陣的乘積的。
-
例如,如果 v 是一個(gè)標(biāo)量函數(shù)的梯度:
-