《深度學習與Pytorch入門實戰》2019


《深度學習與Pytorch入門實戰》2019

其他

https://www.cnblogs.com/taosiyu/category/1538754.html

1-深度學習框架簡介

  • pytorch動態圖:

一步一步給定數據計算,隨時查看每一步數據,較符合人的思維邏輯。

TensorFlow靜態圖:

先define定義階段,再run,函數給出xy的值及輸出。

2-

3-開發環境安裝

右鍵,管理員身份運行

4、5-簡單回歸問題

  • 梯度下降算法

loss=x^2*sinx

新的x: x'=x-learning rate*y'(x)

因為有誤差,在理論的最優解(x=5)附近有一定程度的抖動

learning rate設成0.05以后,步長變大,波動程度較大,效果不好

learning rate一般設定為0.001,簡單的可以設成0.01等等

y=w*x+b+∈

噪聲 ∈~N(0.01,1)

min loss=∑_i〖(w*x_i+b-y_i)〗^2

w'*x+b'→y

6-回歸問題實戰

points是一系列x、y的數據點。如下圖紅點

  • 求loss:

python range()函數可創建一個整數列表:
range(start, stop[, step])
start:計數從 start 開始。默認從 0 開始。
stop:計數到 stop 結束,但不包括 stop。
step:步長,默認為1。

  • 求梯度信息w、b:

11、12行的m應改為w

除以N是為了累加后的求average。

  • 迭代優化:

7-8-分類問題引入

  • ReLU:線性整流函數,又稱修正線性單元,是一種非線性函數。

最大值0.8所在的索引為1

label為1的概率為0.8

argmax也就是label

9-13-手寫數字識別初體驗

14-15-張量數據類型

  • 沒有內建String支持,必須使用編碼的方式:

1.one-hot code:如[0100000]

無法體現單詞間的相關性,如like dislike

2.embedding:如Word2vec、glove

ByteTensor,判斷兩Tensor元素是否相等,返回0或1

部署在CPU GPU上是不一樣的

x.cuda會返回一個GPU上的引用

  • 三種Tensor類型的判斷方法

隨機初始化一個兩行三列的二維的Tensor,randn隨機正態分布的數中選取

第一種打印出具體數據類型;第三種判斷是否是某種類型,是返回true

  • 標量 Dimension=0

1.3是0維,但[1.3]是1維長度為1的Tensor

獲取標量的shape

len(a.dim)也會返回0

  • Dim=1的張量/向量

.tensor接受的是數據的內容,后接現有的數據

.FloatTensor接受的是數據的shape,也可接受現有的數據但容易混淆故不推薦。第7行給定向量的長度為1,8行隨機初始化一個數值。

13行從numpy引入,規定長度為2。生成[1.,1.](16行)

18行使用form_numpy方法從data里引入,顯示數據一樣,但類型變成FloatTensor

應用:Bias偏置;Linear Input神經網絡線性層的輸入

  • Dim=2的張量

獲取shape(size):

區分:

dim:2
size/shape:[2,2]
tensor:[1 2]
        [3 4]

a.size不給參數返回第9行

應用:帶有batch的Linear Input

  • Dim=3的張量

.rand [0,1)隨機的均勻分布中的數據來初始化

第一個維度是1,所以第5行在一個總的括號[]內;第二個維度是2,所以第二個[]內兩個元素;…

應用:帶有batch的RNN Input

  • Dim=4

可用於表示圖片

圖中第一個維度2,表示照片數b為2;第二個維度3,灰度圖的通道數channel為1,彩色圖通道數為3;第三四個維度18是MNIST數據集的長h和寬w。

munel指tensor占用內存的數量

16-17-創建tensor

  • 從numpy引入

通過numoy創建一個dim=1,長度為2的向量

從numpy導入的float其實是double類型

  • 通過list方法導入

  • 生成未初始化的數據

·torch.enpyt()

·torch.FloatTensor(d1,d2,d3)
NOT torch.FloatTensor([1,2])=torch.tensor([1,2])

·torch.IntTensor(d1,d2,d3)

未初始化的tensor一定要跟寫入數據的后續步驟

第二行的0是隨機出來的巧合

pytorch里.tensor默認類型是FloatTensor,torch.set_default_tensor_type()可修改默認類型(第四行)

增強學習里一般使用double,其他一般使用float

  • 隨機初始化

重疊部分為[3.3])

rand隨機產生0-1之間的數值,不包括1。也就是[0,1)均勻分布

rand_like()接受的參數不再是shape,而是tensor

randint(min,max,[維度,…])采樣[min,max)間的整數值

均勻采樣0-10的tensor要用x=10*torch.rand(d1,d2)

randn,初始化時的隨機數服從正態分布,最常見的是N(0,1)

torch.normal(means, std, out=None)返回一個張量,包含從給定參數means為均值,std為標准差的離散正態分布中抽取隨機數。out為可選的輸出張量。

torch.full([],?)依size生成值均為?的元素的張量。size:張量的形狀,如[3,3]、[10]。圖中為生成10個0:[0,0,0,…,0]

torch.arange(start,end,step)start:數列起始值,end:數列“結束值”(取不到),step:數列公差,默認為1。圖中為[1,0.9,0.8,……,0.1]

例94生成Dim=0的標量,95生成Dim=1,長度為1的張量

例98方法不建議

torch.linspace(start, end, steps=?)線性等分向量。start:開始值,end:結束值(能取到),steps:在start和end間生成的樣本數,默認是100。

torch.logspace(start, end, steps=100)返回一個1維張量,包含在區間10(start)和10(end)(能取到)上以對數刻度均勻間隔的 steps個點。

torch.ones(size)返回一個全為1的張量,形狀由可變參數sizes定義

torch.zeros(size)返回一個全為標量0的張量,形狀由可變參數sizes定義

torch.eye(n, m)返回一個2維張量,對角線為1,其它位置為0。n-行數;m-列數,默認為n

torch.randperm(n)返回一個從0到n-1的隨機整數排列

用同一個索引來做shuffle,比如a為人名+數學成績,b為人名+語文成績,索引要對應起來。

4-7是為了演示得到了不同的idx,第9、14行的idx必須保持一致

18-19-索引與切片

a[0],取第=張圖片,包含3個通道,長寬各為28。

a[0,0,2,4],第0張圖片,第0個通道,第2行第4列的像素點

start:end:step

:2可理解為→2,從最開始(第0張)的圖片到第二張圖片(不包含第二張)。不寫數字默認取全部。

例143中,1:表示從第一個通道開始取到最末尾,也就是G、B兩通道

例144中,反向索引,-1:也就是最后一個元素開始取,也就是B通道

0:28:2隔行采樣,對序號0至序號28(取不到)進行間隔采樣,每隔2采一次,也就是采序號為0,2,4,6,...,26的元素,共14個

0:28:等同於0:28:1

第4行:a.index_select(0,torch.tensor([0,2])).shape

第5行:[2,3,28,28]

index_select(dim,index)dim:表示從第幾維挑選數據;index:表示從第一個參數維度中的哪個位置挑選數據,類型為torch.Tensor類的實例

第7行:a.index_select(1,torch.tensor([1,2])).shape

第8行:[4,2,28,28]

...表示任意多的維度

.gt() #greater than(大於)
.ge() #greater and equal(大於等於)
.eq() #equal(等於)
.le() #less and equal(小於等於)
.lt() #less than(小於)

第6行,大於等於0.5的數置為1,否則置為0

torch.masked_select(input, mask)。input輸入張量,mask掩碼張量。mask須跟input有相同數量的元素數目,但形狀或維度不需要相同。

In[39]: src = torch.tensor([[4,3,5],[6,7,8]])		# 先打平成1維的,共6列
In[40]: src
Out[40]: 
tensor([[4, 3, 5],
        [6, 7, 8]])
In[41]: torch.take(src, torch.tensor([0, 2, 5]))	# 取打平后編碼,位置為0 2 5
Out[41]: tensor([4, 5, 8])

torch.take(src, torch.tensor([index]))打平后,按照index來取對應位置的元素

20-23-維度變換

tensor的維度變化改變的是數據的理解方式

.view()/.reshape():返回的數據和傳入的tensor一樣的條件下,轉變shape

第4行:(4,12828)將通道、長寬合並,忽略了通道信息、上下左右的空間信息。適合全連接層。

保證tensor的size不變即可/numel()一致/元素個數不變。

view操作必須滿足物理意義,否則會導致數據的被污染與破壞

第16行:合並batch、channel、行,放在一起為N,[N,28],每個N,剛好有28個像素點,只關心一行數據

第19行:4張疊起來了

損失維度信息,如果不額外存儲維度順序的話,恢復時會出現問題。如22-24行的邏輯混亂。

view的新的size(783)與原來(784)不一致會報錯

squeeze/unsqueeze:減少/增加維度

unsqueeze(index) 拉伸(增加一個維度/一個組,而非一個數據,還是4張圖片,可以理解為增加了一個組,組里有原來的四張圖片)

參數的范圍是 [-a.dim()-1, a.dim()+1) 如圖中例子中范圍是[-5,5)

-5→0,…,-1→4 這樣的話,0表示在前面插入,-1表示在后面插入,正負會有些混亂,所以推薦用正數。

[ 4 1 28 28 ]
1 2 3 4
-5 -4 -3 -2 -1

0與正數,就是在第X個維度前面插入,負數在某個維度后面插入


In[24]: a = torch.tensor([1.2,2.3])  # 維度為[2]

In[27]: a.shape
Out[27]: torch.Size([2])

In[25]: a.unsqueeze(-1)  # -1,后面增加維度,維度變成[2,1]  2行1列
Out[25]: 
tensor([[1.2000],
        [2.3000]])

In[26]: a.unsqueeze(0)
Out[26]: tensor([[1.2000, 2.3000]]) # 0,前面增加維度,維度變成[1,2]  1行2列

  • 實例

給一個bias(偏置),bias相當於給每個channel上的所有像素增加一個偏置

為了做到 f+b 我們需要改變b的維度

squeeze(index)當index對應的dim為1,才產生作用。例64中第1個維度32≠1,不能擠壓。

不寫參數,會擠壓所有維度為1的。例61將所有維度為1的進行擠壓,理解:一張圖片,有32個channel,每個channel有一個點(值)

expand/repeat:維度擴展

Expand:broadcasting(推薦),只是改變了理解方式,並沒有增加數據。只在需要的時候復制數據,不會主動復制。速度快節約內存。

Reapeat:memory copied,會實實在在的增加數據

以上面提到的實例為例, b[1,32,1,1]與f[4,32,14,14],目標是將b的維度變成與f相同的維度(1→4,1→14,1→14)。

  • 擴展(expand)張量不會分配新的內存,只是在存在的張量上創建一個新的視圖(view)

In[44]: a = torch.rand(4,32,14,14)
In[45]: b.shape
Out[45]: torch.Size([1, 32, 1, 1])  # 只有1→N才是可行的, 3→N需要另起規則
In[46]: b.expand(4,32,14,14).shape
Out[46]: torch.Size([4, 32, 14, 14])
In[47]: b.expand(-1,32,-1,-1).shape	# -1表示這個維度不變
Out[47]: torch.Size([1, 32, 1, 1])
In[48]: b.expand(-1,32,-1,-4).shape	# -4這里是一個bug,沒有意義,最新版已經修復了
Out[48]: torch.Size([1, 32, 1, -4])

  • repeat:

主動復制原來的。

參數表示的是要拷貝的次數/是原來維度的倍數

沿着特定的維度重復這個張量,和expand()不同的是,這個函數拷貝張量的數據。

t/transpose/permute:轉置,單次/多次交換

  • .t


a = torch.randn(3,4)

a.t().shape
Out[58]: torch.Size([4, 3])

In[60]: a
Out[60]: 
tensor([[ 0.5629, -0.5085, -0.3371,  1.2387],
        [ 0.2142, -1.7846,  0.2297,  1.7797],
        [-0.3197,  0.6116,  0.3791,  0.9218]])

In[61]: a.t()
Out[61]: 
tensor([[ 0.5629,  0.2142, -0.3197],
        [-0.5085, -1.7846,  0.6116],
        [-0.3371,  0.2297,  0.3791],
        [ 1.2387,  1.7797,  0.9218]])

b.t()
RuntimeError: t() expects a tensor with <= 2 dimensions, but self is 4D

.t 只針對2維矩陣

  • transpose

在結合view使用的時候,view會導致維度順序關系變模糊,所以需要人為跟蹤。

錯誤的順序,會導致數據污染

一次只能兩兩交換


In[8]: a = torch.randn(4,3,32,32)

In[9]: a.shape
Out[9]: torch.Size([4, 3, 32, 32])

In[10]: a1 = a.transpose(1,3).contiguous().view(4,3*32*32).view(4,3,32,32)
# 由於交換了1、3維度,就會變得不連續,所以需要用contiguous,來把數據變得連續。
# [b c h w]交換1、3維度的數據變成[b w h c],再把后面的三個連在一起,展開后變為[b c w h],導致和原來的順序不同,造成數據污染

In[11]: a1.shape
Out[11]: torch.Size([4, 3, 32, 32])

In[12]: a2 = a.transpose(1,3).contiguous().view(4,3*32*32).view(4,32,32,3).transpose(1,3)
# [b c h w] -> [b w h c] -> [b w h c] -> [b c h w] 和原來順序相同。

In[13]: a2.shape
Out[13]: torch.Size([4, 3, 32, 32])

# 驗證向量一致性
In[14]: torch.all(torch.eq(a,a1)) # 使用.eq函數比較數據是否一致,.all函數保證每一處數據都一致
Out[14]: tensor(0, dtype=torch.uint8)

In[15]: torch.all(torch.eq(a,a2))
Out[15]: tensor(1, dtype=torch.uint8)

tensor.all()功能: 如果張量tensor中所有元素都是True, 才返回True; 否則返回False

torch.all() 判斷每個位置是否存在為0的元素


In[21]: torch.all(torch.ByteTensor([1,1,1,1]))
Out[21]: tensor(1, dtype=torch.uint8)

In[22]: torch.all(torch.ByteTensor([1,1,1,0]))
Out[22]: tensor(0, dtype=torch.uint8)

tensor.any()功能: 如果張量tensor中存在一個元素為True, 那么返回True; 只有所有元素都是False時才返回False

  • permute

permute會打亂內存順序,也需要contiguous


In[18]: a = torch.rand(4,3,28,28)

In[19]: a.transpose(1,3).shape
# [b c h w] → [b w h c], h與w的順序發生了變換,導致圖像發生了變化
Out[19]: torch.Size([4, 28, 28, 3]) 

In[20]: b = torch.rand(4,3,28,32)

In[21]: b.transpose(1,3).shape
Out[21]: torch.Size([4, 32, 28, 3])

In[22]: b.transpose(1,3).transpose(1,2).shape
Out[22]: torch.Size([4, 28, 32, 3])
# [b,h,w,c]是numpy存儲圖片的格式,需要這一步才能導出numpy

In[23]: b.permute(0,2,3,1).shape
Out[23]: torch.Size([4, 28, 32, 3])

24-26-broadcast

  • 自動擴展:

維度擴展,自動調用expand

without copying data ,不需要拷貝數據。

  • 實施

從最小的維度開始匹配,前面沒有維度的話,在前面插入一個維度;然后將size 1擴展成相同size的維度

例子:對於 feature maps : [4, 32, 14, 14],想給它添加一個偏置Bias

Bias:[32] –> [32, 1 , 1] (手動插入兩個維度以滿足broadcast的條件) => [1, 32, 1, 1] => [4, 32, 14, 14]

目標:當Bias和feature maps的size一樣時,才能執行疊加操作

  • Broadcast的原因

broadcast = unsqueze(插入新維度) + expand(將1dim變成相同維度)

  • 實例

有這樣的數據 [class, students, scores],具體是4個班,每個班32人,每人8門課程[4, 32, 8] 。

考試不理想,對於這組數據我們需要為每一位同學的成績加5分

要求: [4, 32, 8] + [4, 32, 8]

實際上:[4, 32, 8] + [5.0]

操作上:[1] =>(unsqueeze) [1, 1, 1] =>(expand_as) [4, 32, 8],這樣需要寫3個接口。所以需要broadcast

內存:

[4, 32, 8] => 1024

[5.0] => 1 如果是手動復制的話,內存消耗將變為原來的1024倍

  • 使用條件

A [ 大維度 —> 小維度 ]

從最后一位(最小維度)開始匹配,如果維度上的size是0,1或相同,則滿足條件,看下一個維度,直到都滿足條件為止。

如果當前維度是1,擴張到相同維度

如果沒有維度,插入一個維度並擴張到相同維度

當最小維度不匹配的時候沒法使用broadcastiong,如共有8門課程,但只給了4門課程的變化,這樣就會產生歧義。

小維度指定,大維度隨意

小維度指定:假如英語考難了,只加英語成績 [0 0 5 0 0 0 0 0]

  • 具體案例分析

size一樣,不需要擴展,只擴張到相同維度即可

先增加維度,再擴張

B只給了兩張照片的參數,不符合要求

  • 使用

A [4, 3, 32, 32] b,c,h,w

+[32, 32] 疊加一個相同的feature map,做一些平移變換。相當於一個base(基底),

+[3, 1, 1] 針對 RGB 進行不同的補充,如R 0.5 、G 0 、B 0.3

+[1, 1, 1, 1] 對於所有的都加一個數值,抬高一下,如加0.5.

27-28-合並與分割

numpy中使用concat,在pytorch中使用更加簡寫的cat

完成一個拼接

兩個向量維度相同,想要拼接的維度上的值可以不同,但是其它維度上的值必須相同。

例子:將兩班級的成績合並起來

a[class 1-4, students, scores]

b[class 5-9, students, scores]


In[4]: a = torch.rand(4,32,8)

In[5]: b = torch.rand(5,32,8)

In[6]: torch.cat([a,b],dim=0).shape
# 將a,b在第0個維度進行合並
Out[6]: torch.Size([9, 32, 8])
# 結果就是9個班級的成績

行拼接:[4, 4] 與 [5, 4] 以 dim=0(行)進行拼接 —> [9, 4] 9個班的成績合起來

列拼接:[4, 5] 與 [4, 3] 以 dim=1(列)進行拼接 —> [4, 8] 每個班合成8項成績

例2:


In[7]: a1 = torch.rand(4,3,32,32)

In[8]: a2 = torch.rand(5,3,32,32)

In[9]: torch.cat([a1,a2],dim=0).shape		# 合並第1維 理解上相當於合並batch
Out[9]: torch.Size([9, 3, 32, 32])

In[11]: a2 = torch.rand(4,1,32,32)

In[12]: torch.cat([a1,a2],dim=1).shape		# 合並第2維 理解上相當每張圖片有rgbα四個通道
Out[12]: torch.Size([4, 4, 32, 32])

In[13]: a1 = torch.rand(4,3,16,32)

In[14]: a2 = torch.rand(4,3,16,32)

In[15]: torch.cat([a1,a2],dim=3).shape		# 合並第3維 理解上相當於合並照片的上下兩半
Out[15]: torch.Size([4, 3, 16, 64])

In[17]: a1 = torch.rand(4,3,32,32)

In[18]: torch.cat([a1,a2],dim=0).shape
RuntimeError: invalid argument 0: Sizes of tensors must match except in dimension 0.

  • stack

創造一個新的維度(代表了新的組別)

要求兩個tensor的size完全相同


In[19]: a1 = torch.rand(4,3,16,32)
In[20]: a2 = torch.rand(4,3,16,32) 

In[21]: torch.cat([a1,a2],dim=2).shape		# 合並照片的上下部分
Out[21]: torch.Size([4, 3, 32, 32])

In[22]: torch.stack([a1,a2],dim=2).shape	# 添加了一個維度 一個值代表上半部分,一個值代表下半部分。 這顯然是沒有cat合適的。
Out[22]: torch.Size([4, 3, 2, 16, 32])

In[23]: a = torch.rand(32,8)
In[24]: b = torch.rand(32,8)

In[25]: torch.stack([a,b],dim=0).shape		# 將兩個班級的學生成績合並,添加一個新的維度,這個維度的每個值代表一個班級。顯然是比cat合適的。
Out[25]: torch.Size([2, 32, 8])

In[26]: a.shape
Out[26]: torch.Size([32, 8])

In[27]: b = torch.rand([30,8])

In[28]: torch.stack([a,b],dim=0)
RuntimeError: invalid argument 0: Sizes of tensors must match except in dimension 0

  • split

按長度進行拆分:單元長度/數量

長度相同給一個固定值,長度不同給一個列表


In[48]: a = torch.rand(32,8)
In[49]: b = torch.rand(32,8)
In[50]: c = torch.rand(32,8)
In[51]: d = torch.rand(32,8)
In[52]: e = torch.rand(32,8)
In[53]: f = torch.rand(32,8)

In[54]: s = torch.stack([a,b,c,d,e,f],dim=0)
In[55]: s.shape
Out[55]: torch.Size([6, 32, 8])  

In[57]: aa,bb = s.split(3,dim=0)	# 按數量切分,可以使用一個常數
In[58]: aa.shape, bb.shape
Out[58]: (torch.Size([3, 32, 8]), torch.Size([3, 32, 8]))

In[59]: cc,dd,ee = s.split([3,2,1],dim=0)	# 按單位長度切分,可以使用一個列表
In[60]: cc.shape, dd.shape, ee.shape
Out[60]: (torch.Size([3, 32, 8]), torch.Size([2, 32, 8]), torch.Size([1, 32, 8]))

In[61]: ff,gg = s.split(6,dim=0)	# 只能拆成一個,返回一個tensor,不能用兩個tensor接收
ValueError: not enough values to unpack (expected 2, got 1)

  • chunk

按數量進行拆分

chunk中的參數是要切成幾份;split的常數是每份有幾個


In[63]: s.shape
Out[63]: torch.Size([6, 32, 8])

In[64]: aa,bb = s.chunk(2,dim=0)
In[65]: aa.shape, bb.shape
Out[65]: (torch.Size([3, 32, 8]), torch.Size([3, 32, 8]))

In[66]: cc,dd = s.split(3,dim=0)
In[67]: cc.shape,dd.shape
Out[67]: (torch.Size([3, 32, 8]), torch.Size([3, 32, 8]))

29-30-數學運算

  • 基礎運算

可以使用 + - * / (推薦),也可以使用 torch.add, mul, sub, div

b:使用broadcast [4] → [3,4]

//二斜線表示整除

  • matmul

matmul 表示 matrix mul,矩陣乘法

*表示的是element-wise,按元素一個一個操作, 是兩個同樣維度的向量/矩陣每一個元素分別相乘

torch.mm(a,b) 只能計算2D 不推薦

torch.matmul(a,b) 可以計算更高維度,落腳點依舊在行與列。 推薦

@是matmul的重載形式

實例:神經網絡中線性層的相加

線性層的計算 : x @ w.t() + b

x是4張照片且已經打平了 (4, 784)

我們希望 (4, 784) —> (4, 512)

這樣的話w因該是 (784, 512)

但由於pytorch默認 第一個維度是 channel-out(目標),第二個維度是 channel-in (輸入),所以需要用一個轉置

.t() 只適合2D,高維用transpose

  • 2維以上的matmul

對於2維以上的matrix multiply , torch.mm(a,b)就不行了。

運算規則:只取最后的兩維做矩陣乘法

對於 [b, c, h, w] 來說,b,c 是不變的,圖片的大小在改變;並且也並行的計算出了b,c。也就是支持多個矩陣並行相乘。

對於不同的size(例33),如果符合broadcast,先執行broadcast,在進行矩陣相乘。

  • power

pow(a, n):a的n次方

** 也表示次方(可以是2,0.5,0.25,3),推薦

sqrt() 表示 square root 平方根

rsqrt() 表示平方根的倒數

  • exp log

exp(n) 表示:e的n次方

log(a) 表示:ln(a)

log2() 、 log10()


In[22]: torch.log2(a)
Out[22]: 
tensor([[1.4427, 1.4427],
        [1.4427, 1.4427]])

In[23]: torch.log10(a)
Out[23]: 
tensor([[0.4343, 0.4343],
        [0.4343, 0.4343]])

  • approximation

不太常用

floor、ceil 向下取整、向上取整

round 4舍5入

trunc、frac 裁剪

  • clamp

gradient clipping 梯度裁剪

(min) 限定最小值,小於min的都變為min

(min, max) 大於這個區間的都變為max,小於的都變為min

梯度爆炸:一般來說,當梯度達到100左右的時候,就已經很大了,正常在10左右,通過打印梯度的模來查看 w.grad.norm(2)

對於w的限制叫做weight clipping,對於weight gradient clipping稱為 gradient clipping。

31-32-屬性統計

  • norm

norm指的是范數,並不是normalize。normalize是歸一化,例如 batch_norm。

向量的范數,就是表示這個原有集合的大小。

矩陣的范數,就是表示這個變化過程的大小的一個度量。

總結起來一句話,范數(norm),是具有“長度”概念的函數。

norm(1, 一范數,所有元素的絕對值之和

norm(2, 二范數,所有元素的平方和並開根號

不加dim參數,默認所有維度

從shape出發,加入dim后,這個dim就會消失(做Norm)


In[3]: a = torch.full([8],1)
In[4]: b = a.view(2,4)
In[5]: c = a.view(2,2,2)

In[6]: b
Out[6]: 
tensor([[1., 1., 1., 1.],
        [1., 1., 1., 1.]])

In[7]: c
Out[7]: 
tensor([[[1., 1.],
         [1., 1.]],

        [[1., 1.],
         [1., 1.]]])

In[8]: a.norm(1), b.norm(1), c.norm(1)
Out[8]: (tensor(8.), tensor(8.), tensor(8.)) # 一范數是所有元素絕對值的求和,八個1所以一范數是8

In[9]: a.norm(2), b.norm(2), c.norm(2)
Out[9]: (tensor(2.8284), tensor(2.8284), tensor(2.8284))

In[10]: b.norm(1,dim=1)    # 一范數,[1., 1., 1., 1.]→4.,[1., 1., 1., 1.]→4.
Out[10]: tensor([4., 4.])	# 就shape來講 [2,4] norm之后 --> [2]

In[16]: b.norm(1,dim=0)
Out[16]: tensor([2., 2., 2., 2.])	# shape [2,4]  ---> [4]

In[11]: b.norm(2,dim=1)
Out[11]: tensor([2., 2.])

In[12]: c.norm(1,dim=0)	   # [2,2,2],在0維度做求1范數,那么這個維度就將消掉,得到shape為[2,2]
Out[12]: 
tensor([[2., 2.],
        [2., 2.]])

In[14]: c.norm(2,dim=0)		
Out[14]: 
tensor([[1.4142, 1.4142],
        [1.4142, 1.4142]])

  • mean,sum,min,max,prod

max() 求最大的值

min() 求最小的值

mean() 求平均值 mean = sum / size

prod() 累乘

sum() 求和

argmax() 返回最大值元素的索引

argmin() 返回最大值元素的索引

argmax(dim=l) 求l維中,最大元素的位置,這樣的話這一維將消失。

以上這些,如果不加參數,會先打平,在計算,所以對於 argmax 和 argmin來說得到的是打平后的索引。

例158,dim=1,獲取4張照片預測值最大的位置,這個位置決定了它是數字幾

  • keepdim

使用max(dim=) 函數配上dim參數,可以很好的返回最大值與該值的位置

argmax 其實是 max 的一部分(位置)

keepdim=True 設置這個參數后,維度得以保留,與原來的維度是一樣的。

  • top-k / k-th

    • topk

由於max只能找出一個最大,如果想找最大的幾個就做不到了。

topk(k, 比max提供更多的信息,適用於特定的場合。

topk(k, 指的是返回概率最大的的 k 組數據以及位置

largest=False 求概率最小的 k 組

例如:對於一張照片,他的概率是[0.2, 0.3, 0.1, 0.2, 0.1, 0.1],使用topk(3) 會得到概率最大的三個數[0.3, 0.2, 0.2] 以及位置[1, 0, 3]


In[33]: a
Out[33]: 
tensor([[ 0.0234,  0.6830, -0.1518,  0.4595, -1.5634,  0.5534,  0.9934, -1.1536,
          0.3124, -1.4103],
        [ 0.6339,  1.5724,  0.2552,  1.0917, -1.4003,  0.5165,  0.8891, -2.0315,
          0.4666,  1.4355],
        [ 1.6149,  0.2364,  0.3789, -0.3974, -0.1433,  0.9235,  0.6730,  0.3575,
          2.0742,  0.8954],
        [-0.1019,  1.6405, -1.3493,  0.5554, -0.0533,  0.0450,  0.2018, -0.1688,
         -1.2579, -0.7906]])
In[34]: 
In[34]: a.topk(3,dim=1)
Out[34]: 
torch.return_types.topk(
values=tensor([[0.9934, 0.6830, 0.5534],	# 返回概率最大的前3個
        [1.5724, 1.4355, 1.0917],
        [2.0742, 1.6149, 0.9235],
        [1.6405, 0.5554, 0.2018]]),
    	# shape的話 從[4, 10]   --->  [4,3]
indices=tensor([[6, 1, 5],	# 最可能是6,1次之,5次之
        [1, 9, 3],
        [8, 0, 5],
        [1, 3, 6]]))

In[35]: a.topk(3,dim=1,largest=False)
Out[35]: 
torch.return_types.topk(
values=tensor([[-1.5634, -1.4103, -1.1536],
        [-2.0315, -1.4003,  0.2552],
        [-0.3974, -0.1433,  0.2364],
        [-1.3493, -1.2579, -0.7906]]),
indices=tensor([[4, 9, 7],	# 最不可能是4,9次之,7次之
        [7, 4, 2],

  • kthvalue

kthvalue(i, dim=j) 求 j 維上,第 i 小的元素以及位置。dim默認為1。

keepdim=True 會保持維度


In[36]: a.kthvalue(8,dim=1)	# 求1維,第8小
Out[36]: 
torch.return_types.kthvalue(
values=tensor([0.5534, 1.0917, 0.9235, 0.2018]),
indices=tensor([5, 3, 5, 6]))

In[37]: a.kthvalue(3)
Out[37]: 
torch.return_types.kthvalue(
values=tensor([-1.1536,  0.2552,  0.2364, -0.7906]),
indices=tensor([7, 2, 1, 9]))

In[38]: a.kthvalue(3,dim=1)
Out[38]: 
torch.return_types.kthvalue(
values=tensor([-1.1536,  0.2552,  0.2364, -0.7906]),
indices=tensor([7, 2, 1, 9]))

  • compare

, >=, <, <=, !=, ==

進行比較后,返回的是一個 bytetensor,不再是floattensor,由於pytorch中所有的類型都是數值,沒有True or False ,為了表達使用整型的1或0

torch.eq(a,b) 判斷每一個元素是否相等,返回 bytetensor

torch.equal(a,b) 返回True或False

numpy與pytorch比較操作的方法,還是推薦 符號 > < ..

Numpy PyTorch
np.less x.lt
np.less_equal x.le
np.less_equal x.le
np.less_equal x.le
np.equal x.eq
np.not_equal x.ne

33-高階操作

  • where

torch.where(condition, x, y) → Tensor

針對於x而言,如果其中的每個元素都滿足condition,就返回x的值;如果不滿足condition,就將y對應位置的元素或者y的值替換x的值,最后返回結果。

  • gather

torch.gather(input, dim, index, out=None) → Tensor

沿給定軸 dim ,將輸入索引張量 index 指定位置的值進行聚合.

input (Tensor) – 源張量

dim (int) – 索引的軸

index (LongTensor) – 聚合元素的下標(index需要是torch.longTensor類型)

out (Tensor, optional) – 目標張量

對一個 3 維張量,輸出可以定義為:


out[i][j][k] = input[index[i][j][k]][j][k]  # if dim == 0
out[i][j][k] = input[i][index[i][j][k]][k]  # if dim == 1
out[i][j][k] = input[i][j][index[i][j][k]]  # if dim == 2


a = torch.Tensor([[1,2],
                 [3,4]])

b = torch.gather(a,1,torch.LongTensor([[0,0],[1,0]]))
#1. 取各個元素行號:[(0,y)(0,y)][(1,y)(1,y)]
#2. 取各個元素值做y:[(0,0)(0,0)][(1,1)(1,0)]
#3. 根據得到的索引在輸入中取值
#[1,1],[4,3]

c = torch.gather(a,0,torch.LongTensor([[0,0],[1,0]]))
#1. 取各個元素列號:[(x,0)(x,1)][(x,0)(x,1)]
#2. 取各個元素值做x:[(0,0)(0,1)][(1,0)(0,1)]
#3. 根據得到的索引在輸入中取值
#[1,2],[3,2]

(0,7)(0,4)(0,9)
(1,7)(1,4)(1,9)
(2,8)(2,1)(2,3)
(3,8)(3,6)(3,9)

34-35-什么是梯度

尋找全局極小值時的影響因素:

初始化

learning rate(小一點)

動量(慣性,沖出局部極小)

36-常見函數的梯度

導數:給定一個方向;梯度:所有方向的綜合。對於一維函數只有一個方向,所以兩者基本是一個東西。

y=xw+b x作為神經網絡的輸入。wb為神經網絡的參數,是要優化的目標

y=x w2+b2

y=x ew+eb

[y-(xw+b)]^2 可理解為線性感知器的輸出與真實的label(y)間的均方差

y log(x w+b)

37-40-激活函數與Loss的梯度

激活函數:

輸入小於某個值時沒有輸出,大於某個值時給出一個固定的響應(青蛙實驗)

  • Sigmoid函數

常被用作神經網絡的激活函數,將變量映射到0-1之間。

求導:

torch.sigmoid

  • Tanh

  • Rectified Linear Unit 整形的線性單元 ReLU

極大減少了梯度離散與梯度爆炸的情況

  • typical loss

mean squared Error 均方誤差MSE

y減去y的預測值的平方和

cross entropy loss 可用於二分類也可用於多分類,通常與softmax激活函數搭配使用

  • MSE

torch.norm(y-pred,2).pow(2)

梯度求解:

使用pytorch自動求導:

mse_loss(input,label)

input:預測值;label:目標值。維度為 [N1,N2,...,Nk,D] 的多維Tensor,其中最后一維D是類別數目。數據類型為float32或float64。

例21出錯因為w沒有標注需要求導信息

requests_grad:是否求導.默認為False,可以新建W時就加上requests_grad=true,或者后面使用requests_grad_()。

23還出錯因為pytorch是動態圖,做一步計算一步,圖還沒有更新。所以要用24把圖重新計算,更新一遍

.backward() 從后往前傳播

  • gradient API

  • softmax

變成取值0-1,概率和為1.大的會較大,小的會壓縮(大小差距變大)

求導:

i=j

i≠j

所以ij相等時候是正的,不等為負

F.softmax

例39 p[1],δP1/δai 所以i=1時的0.2274是正的; 例40 p[2]所以0.2425是正的 其他梯度是負的

41-42-感知器的梯度推導

  • 單層感知器

最終的loss對某層結點的求導公式:

輸出只有一個,所以只有O0,沒有O1O2……

跟神經元輸出結點O及與其對應的j號結點的輸入xj有關

  • 多輸出感知器

43-鏈式法則

針對神經網絡的具體實例:

輸入,經過一個隱藏層(橙色),再經過一個輸出層(綠色),最后計算一個最終的loss。字母上標表示層數,下標表示編號

44-45-反向傳播算法

  • 多層感知器

46-優化問題實戰

2D函數優化實例:

四個解都是全局最小解(因為一樣大小)

numpy.meshgrid()——生成網格點坐標矩陣

使用隨機梯度下降方法求解:

找到的是(3,2)這個局部極小值

初始化值改為4:

找到了另外的局部極小值

47-Logistic Regression邏輯回歸

二分類問題:

大於0.5判斷為1,小於0.5判斷為0

多分類問題:

大的變的更大,小的聚集:

2,1→0.7,0.2 原來大兩倍,現在大3.5倍

48-49-交叉熵

  • entropy

不確定性 驚喜度

  • cross entropy

OKL:KL Divergence散度,衡量兩個分布的距離的關系

兩個分布越相似DKL越接近於0

P=Q時,DKL=0,H(p,q)=H(p)

對於01encoding,H(p)=0

二分類:

具體實例:

P為真實的分布,第一張圖是狗。Q是Pθ,是模型的分布

理想情況:

對於分類問題為什么不使用MSE

用sigmoid搭配MSE很容易出現sigmoid飽和的現象,會出現梯度離散;

cross entropy梯度概率信息更大,收斂得更快

但由於MSE梯度求導更簡單,所以有時候可以一試

小結:

50-多分類問題實戰

十層 代表十分類

網絡tensor定義和forward過程:

新建三個線性層

第一層,輸入784,可以想象成28×28,也就是784降維成200的過程。w1b1都需要梯度信息

第二層,隱藏層,沒有降維過程,不代表沒有作用/功能,比如特征提取

第三層,因為十分類所以最后輸出結點應為10個

經過relu后得到logits,沒有經過sigmoid或softmax的稱為logits

最后的F.relu也可以不用

train:

定義一個優化器

發現loss長時間得不到更新,出現梯度離散,說明梯度信息接近於0

加上hekaiming初始化的代碼

只對w初始化,因為b已經初始化為0了

發現改善

全連接層

  • nn.Linear

nn.Linear(in_features,out_features)是用於設置網絡中的全連接層的,全連接層的輸入與輸出都是二維張量,一般形狀為[batch_size, size],不同於卷積層要求輸入輸出是四維張量。

加上relu以后:

inplace=True的意思是進行原地操作,例如x=x+5,對x就是一個原地操作,不創建新的對象,直接對原始對象進行修改

step1:

step2:

step3:

nn.Relu vs F.relu

net.parameters()

激活函數與GPU加速

  • SELU

  • softplus

  • GPU加速

可以使用torch.device()選取並返回抽象出的設備(這里選擇了GPU),然后在定義的網絡模塊或者Tensor后面加上.to(device變量)就可以將它們搬到設備上了。

如有八張顯卡,則cuda后可以是0-7的編號

.cuda()方法已經不推薦了

win7任務管理器里好像看不到GPU狀態,一個比較笨的看NVIDIA GPU狀態的方法就是在cmd里一直執行:


"C:\Program Files\NVIDIA Corporation\NVSMI\nvidia-smi.exe"

MNIST測試實戰

  • argmax

Visdom可視化

  • tensorbroadX

  • visdom

step1:install

pip install visdom

pip uninstall visdom是卸載

直接用pip安裝的話在windows上面可能出現問題,先從Github上下載Visdom的源碼,進入解壓后的目錄,執行:

pip install -e . 有個點號!

即從當前目錄下的setup.py安裝了Visdom。

step2:run server damon

python -m visdom.server

除了可能看到一些warning信息之外,正常運行時是這樣的:


It's Alive!
INFO:root:Application Started
You can navigate to http://localhost:8097

訪問http://localhost:8097

  • 繪制單曲線:

第三行創建一條曲線,首先創建y和x,這里初始只有一個點,所以yx都是0

win='train loss'是標志符

  • 繪制多曲線

  • 可視化 visdom x

過擬合與欠擬合

實例1:房價隨面積的變化

例2:GPA

次方增加,網絡表達能力變強

容量:

層數越大,學習能力越強

模型表達能力/復雜度<真實數據的復雜度:underfitting欠擬合

例子:WGAN

模型表達能力/復雜度>真實數據的復雜度:overfitting過擬合

交叉驗證

數據集拆分:

test while train

檢測 如果已經overfitting了就取最好的狀態

train-val-test

作弊:用train的數據做test,會導致代碼的泛化能力變差

划分train和test數據的方式:

  • 留出法(hold-out)

也就是直接划分,如將60k的訓練集划分出10k來做驗證集。

  • K-fold cross validation

也就是K折交叉驗證。這可以將驗證集充分利用起來,比如在每個epoch重新划分這60k的數據,拿出其中的50k作為訓練數據,其中的10k作為驗證集。好處是這60k數據中每個都有可能是用來做train的,同時每個數據都有可能是做validation的,也同樣防止了用train的來做validation出現的記樣本的問題。

K-fold cross-validation划分成K份,每次取K-1份用來作為訓練數據,1份用來做驗證。

Regularization

如何防止/減輕overfitting

1.提供更多的數據(最簡單 消耗最大)

2.降低模型復雜度(減少層數、)

3.正則化

  • L2 Regularization

  • L1 Regularization

動量與學習率衰減

  • 動量momentum

梯度更新的公式:

動量為0,沒有找到全局最優解,並且出現很尖銳的更新方向

動量0.78,考慮歷史方向會更多一點

  • 學習率

Early stopping, dropout等

如何early stop

  • DROPOUT

每段關系有一定概率斷掉

加了dropout以后:

曲線更平滑

p=1時候說明所有線都有可能斷掉,TensorFlow里相反

behavior between train and test:

  • stochastic gradient descent隨機梯度下降

最大的原因是硬件問題,大容量的價格高,不可能把所有數據都加載進來計算

什么是卷積

圖片的表示(MNIST為例,黑白圖)

每個數據表示了這個點的灰度值,0-255.使用時可以除以255變成0-1,這就變成了一個浮點型的數組

對於彩色圖,如果忽略阿爾法通道的話就是RGB,使用三張表。每個數值也是0-255(0-1)

全連接網絡/pytorch里也叫線性層:

全值共享weight sharing

為什么成為卷積?

卷積神經網絡

  • nn.Conv2d

  • inner weight & bias

  • F.conv2d

池化層與采樣

下采樣:

max pooling:

avg pooling:

reduce size:

上采樣:

  • F.interpolate

  • RELU

Batch Norm

  • feature scaling

經典卷積網絡 LeNet5,AlexNet, VGG, GoogLeNet

  • LeNet-5

99.2%acc

5/6 layers

  • AlexNet

  • VGG

  • GoogLeNet

ResNet與DenseNet

直覺:更深層次的網絡結構會帶來更好的效果

實際上:層數增加以后,每層誤差的積累,造成梯度離散或爆炸

人為設置一種機制,使得例如30層的效果再差也不會退化成20層的效果

殘差:H(x)-x

  • DenseNet

flat:

ResNet:

DenseNet:任何一層都有機會跟前面的所有層有接觸

nn.Module模塊

所有網絡層類的一個輔類

nn.Module可嵌套

功能:

1.nn.Module里提供了大量的神經網絡的計算模塊

2.container: self.net nn.Sequential

3.parameters

4.modules

直接子節點稱為children,所有產生的結點稱為modules

5.to(device)

6.save and load

7.train/test


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM