深度学习修炼(一)——从机器学习转向深度学习
文章目錄
- 1 轉變
- 1.1 前言
- 1.2 基本元素
- 1.2.1 張量
- 1.2.2 創建張量
- 1.2.3 操縱張量
- 1.2.3.1 張量乘法
- 1.2.3.2 哈達瑪積
- 1.2.3.3 降維
- 1.2.3.4 轉置
- 1.2.3.5 范數
- 1.2.3.6 拼接張量
- 1.2.4 張量屬性
- 1.2.5 張量和Numpy
- 1.2.5.1 張量變Numpy
- 1.2.5.2 Numpy變張量
- 1.3 后話
1 轉變
1.1 前言
在之前的機器學習中,我們都是講解完知識,然后使用sklearn提供的API,然后瘋狂傳參調參。但是實際上底層的邏輯,比如它們為什么能這樣,為什么有這樣的效果,我們是不知道的。
在深度學習中就不一樣了,我們必須掌握好數學這個畫筆,用它規劃出我們想要的神經網絡。而對于顏料來說,各種深度學習框架已經提供了我們所需的各種顏料。我們要做的,就是利用不同的顏料,在空白的紙上,一筆一劃畫出我們所需的網絡。
深度學習改變了傳統互聯網業務。第一次聽到這個名詞時可能大家都會對這方面的知識感到一頭霧水,到底什么是深度學習?實際上,深度學習已經應用到生活中的點點滴滴了,比如我們熟知的自動無人駕駛,小愛同學音箱和其他的一些人工智能產品。在這個筆記中,你可以無需任何視頻直接從頭看到尾,也可以搭配任何一個深度學習的課程視頻進行觀看,當然,除了里面的代碼部分,其他的對于所有的深度學習框架是通用的,代碼部分主要用的是pytorch框架來書寫的。
1.2 基本元素
在深度學習中,實際上最基本的元素就是張量。所以如何利用pytorch來創建一個張量成為我們第一個問題。在后面的學習中,我會告訴你為何張量很重要。
1.2.1 張量
在機器學習中,我們談論過了線性代數的部分知識,當時我們講到,0維叫標量,1維叫向量,2維叫矩陣,2維以上叫多維矩陣。
而實際上,在torch中其賦予了這些維度一個統一的名詞,即張量。如果你學過Numpy,張量實際上就相當于Numpy中的adarray。由此我們不禁疑問,為何torch還要搞自己的這套方法呢?直接用Numpy的不好嗎?
在大部分的學習框架中實際上都有屬于自己的方法來創建張量,這是因為深度學習一般用來處理大量的數據,而僅僅用電腦的CPU硬件已經不能滿足我們深度學習的算力了,為此,我們需要使用GPU來加速我們的算法,而Numpy是不支持GPU加速的,而深度學習框架的張量可以。
換而言之,在深度學習框架中的張量一般都可以很好地支持GPU加速運算,而Numpy僅僅支持CPU計算。
1.2.2 創建張量
在Pytorch中,張量的英文繼承于TensorFlow深度學習框架中的張量Tensor。如果我們要利用最簡單的方法來創建一個tensor,可以用列表來創建,如下:
import torchtensor = torch.FloatTensor([[1, 2, 3], [4, 5, 6]]) print(f"張量為:{tensor}")out:
張量為:tensor([[1., 2., 3.],
[4., 5., 6.]])
實際上,torch提供了創建不同數據類型張量的方法,上述的是創建一個浮點數張量,所以無獨有偶,我們可以嘗試把Float改成Int,其可以為我們創建一個Int類型的常量。
torch.IntTensor([[1,2,3],[4,5,6]])當然類似于Numpy,在Numpy中有ones,zeros等方法創建全1和全0向量,在torch也可以這么做。
torch.IntTensor(2,4).zero_() torch.zeros((2,3,4)) torch.ones((2,3,4))利用python的索引和切片,我們可以獲取和修改一個張量中的任意一個元素。
A = torch.IntTensor([[1,2,3],[4,5,6]]) print(A[1][2])前面我們不是說過可以利用GPU來加速張量嗎?詳情可以見下表:
| 32-bit floating point | torch.FloatTensor | torch.cuda.FloatTensor |
| 64-bit floating point | torch.DoubleTensor | torch.cuda.DoubleTensor |
| 16-bit floating point | N/A | torch.cuda.HalfTensor |
| 8-bit integer (unsigned) | torch.ByteTensor | torch.cuda.ByteTensor |
| 8-bit integer (signed) | torch.CharTensor | torch.cuda.CharTensor |
| 16-bit integer (signed) | torch.ShortTensor | torch.cuda.ShortTensor |
| 32-bit integer (signed) | torch.IntTensor | torch.cuda.IntTensor |
| 64-bit integer (signed) | torch.LongTensor | torch.cuda.LongTensor |
上面這表格里面包含的玩意就別背了,我都背不下來,沒事多用用,忘記查就行,上面的方法還挺有規律的不是?
我們可能在平時學習python時不怎么關注內存,但是在深度學習中內存也是十分重要的。為此,torch提供了節省內存的方法。如你想對A張量的元素全部做絕對值操作,那么abs方法可以在原有的張量基礎上在創建一個張量用于存放新的計算后的張量。而使用abs_方法則是在原有的張量上直接操作,把原有的張量做絕對值操作后直接覆蓋。
就地操作可以節省一些內存,但由于會立即丟失歷史記錄,因此在計算導數時可能會出現問題。因此,不鼓勵使用它們。
1.2.3 操縱張量
張量有了,我們就得會各種各樣的操作,其中不乏就是加減乘除。為了下面的學習,我們當然需要先會一些操作了。
1.2.3.1 張量乘法
張量乘法就是我們在機器學習中談到的矩陣——矩陣乘法。在pytorch中,我們使用mm(matrix multiplication)或matmul方法來做這么一件事情。
import torchA = torch.arange(12).reshape(3, 4) B = torch.arange(12).reshape(4, 3)print(f"兩矩陣乘積為:{torch.mm(A, B)}") print(f"兩矩陣乘積為:{torch.matmul(A, B)}")out:
兩矩陣乘積為:tensor([[ 42, 48, 54],
[114, 136, 158],
[186, 224, 262]])
兩矩陣乘積為:tensor([[ 42, 48, 54],
[114, 136, 158],
[186, 224, 262]])
如果是兩個一維張量即向量相乘時,我們還可以使用dot方法。
import torchA = torch.arange(12) B = torch.arange(12) print(f"兩向量點積為:{torch.dot(A, B)}")out:
兩向量點積為:506
1.2.3.2 哈達瑪積
如果你并不想做矩陣乘法,而是想要讓兩個矩陣對應元素相乘,那么使用運算符*即可達到這種效果。
import torchA = torch.arange(12) B = torch.arange(12) print(A) print(B)print(f"哈達瑪積為:{A*B}")tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
哈達瑪積為:tensor([ 0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121])
1.2.3.3 降維
emm,實際上我覺得可以稍微偷懶,先把數據用sklearn中的PCA降維先降維掉,或者用特征選取先整好。當然深度學習它們不允許我這么干,它們通常都是把矩陣中的某些數據往軸上合并。如求和、求平均啥的。
python的內置函數sum()允許我們對張量內的元素求和。當前我們可以發現,通過求和,本來是一維張量,變成了0維的張量。
import torchx = torch.arange(4, dtype=torch.float32) print(f"x:{x}") print(f"x_sum:{x.sum()}")out:
x:tensor([0., 1., 2., 3.])
x_sum:6.0
明顯地,這實際上就是一種降維的方法,調用求和函數會沿所有的軸降低張量的維度,使它變為一個標量;一維可以變0維,那么說明二維也能變一維,我們可以指定沿著哪個軸來通過求和降低維度。
import torchA = torch.arange(12).reshape(3, 4) A_sum_axis0 = A.sum(axis=0) print(f"A_sum_axis0:{A_sum_axis0}") print(f"A_sum_axis0_shape:{A_sum_axis0.shape}")out:
A_sum_axis0:tensor([12, 15, 18, 21])
A_sum_axis0_shape:torch.Size([4])
對比矩陣A,我們可以發現如果沿著0軸(行)求和,那么實際上就是把該列所有的元素全部相加,加到該列的第0個元素上去。
同樣的,如果指定axis = 1,那么將沿著列求和,那么實際上就是把每行的所有元素相加,加到該行的第0個元素上去。
A = torch.arange(12).reshape(3, 4) A_sum_axis1 = A.sum(axis=1) print(f"A_sum_axis1:{A_sum_axis1}") print(f"A_sum_axis1_shape:{A_sum_axis1.shape}")out:
A_sum_axis1:tensor([ 6, 22, 38])
A_sum_axis1_shape:torch.Size([3])
axis = 0按照行,可以理解為把“行”給抹去只剩1行,也就是上下壓扁。
axis = 1按照列,可以理解為把“列”給抹去只剩1列,也就是左右壓扁。
當然,如果你又對行又對列求和,那么實際上就是對矩陣的所有元素求和。
import torchA = torch.arange(12).reshape(3, 4) print(A.sum(axis=[0, 1])) # 相當于 A.sum()out:
tensor(66)
也許有人說不喜歡通過求和加到某條軸上這種方式去降維,那你可以選擇通過求平均值然后把平均值寫在某條軸上來降維。求平均值有兩種方法,一種是調用python內置函數mean(),另外一種就是用sum()/numel,這實際上也是一種求平均值的方法,但是,我相信你不會那么蠢選擇后者是吧。
1.2.3.4 轉置
用張量自帶的T方法即可完成轉置。
import torchA = torch.arange(12).reshape(3,4) print(A) print(A.T)out:
tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
tensor([[ 0, 4, 8],
[ 1, 5, 9],
[ 2, 6, 10],
[ 3, 7, 11]])
1.2.3.5 范數
如果要計算一個向量的L2L_2L2?范數,可以使用norm來計算。
import torchu = torch.tensor([3.0, -4.0]) print(torch.norm(u))out:
tensor(5.)
如果是L1L_1L1?范數,他表示為向量元素的絕對值之和。這么說,我們求L1L_1L1?范數可以這么求:先求每個元素的絕對值,然后再求和。
import torchu = torch.tensor([3.0, -4.0]) print(torch.abs(u).sum())out:
tensor(7.)
1.2.3.6 拼接張量
如果想要拼接n個張量,可以使用torch.cat方法。其中dim = 0,則n個張量按豎軸拼接;若dim = 1,則按橫軸拼接。
import torchtensor = torch.arange(4).reshape(2, 2) t1 = torch.cat([tensor, tensor, tensor], dim=0) print(t1)out:
tensor([[0, 1],
[2, 3],
[0, 1],
[2, 3],
[0, 1],
[2, 3]])
1.2.4 張量屬性
我們用shape查看張量形狀,用dtype查看張量數據類型,用device查看張量存儲設備。
import torchtensor = torch.rand(3, 4)print(f"shape of tensor:{tensor.shape}") print(f"shape of tensor:{tensor.dtype}") print(f"Device tensor is stored on:{tensor.device}")out:
shape of tensor:torch.Size([3, 4])
shape of tensor:torch.float32
Device tensor is stored on:cpu
如果你的張量中只有一個元素,即單元素張量,那么使用tensor.item()方法可以使其從tensor類型變為int、float等類型。具體是什么類型看張量中的單元素而定。
import torchA = torch.arange(12).reshape(3,4) agg = A.sum() agg_item = agg.item() print(agg_item,type(agg_item))out:
66 <class ‘int’>
1.2.5 張量和Numpy
1.2.5.1 張量變Numpy
如果想要使一個Tensor變為adarray,則調用tensor自身的numpy方法即可。
import torcht = torch.ones(5) print(t) n = t.numpy() print(n)out:
tensor([1., 1., 1., 1., 1.])
[1. 1. 1. 1. 1.]
1.2.5.2 Numpy變張量
如果想要使一個adarray變為Tensor,則調用torch的from_numpy方法即可。
import torch import numpy as npn = np.ones(5) t = torch.from_numpy(n) print(t)out:
tensor([1., 1., 1., 1., 1.], dtype=torch.float64)
1.3 后話
從機器學習到深度學習思路要學會轉變了,我們不再是那個調包俠了,我們也能利用學到的知識從0搭建一個網絡了。這是非常重要的一個點,在后面的學習中你會慢慢適應的。這一講就到這里吧。
總結
以上是生活随笔為你收集整理的深度学习修炼(一)——从机器学习转向深度学习的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在Centos中yum安装和卸载软件的使
- 下一篇: iCartoonFace:爱奇艺的动漫人