官术网_书友最值得收藏!

1.3.1 NumPy操作

NumPy(Numerical Python extension)是一個(gè)第三方的Python包,用于科學(xué)計(jì)算。這個(gè)庫(kù)的前身是1995年就開(kāi)始開(kāi)發(fā)的一個(gè)用于數(shù)組運(yùn)算的庫(kù)。經(jīng)過(guò)了長(zhǎng)時(shí)間的發(fā)展,它基本上成為絕大部分Python科學(xué)計(jì)算的基礎(chǔ)包,當(dāng)然也包括所有提供Python接口的深度學(xué)習(xí)框架。

1.基本模塊

(1)array模塊

數(shù)組(Array)是NumPy中最基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu)。其最關(guān)鍵的屬性是維度和元素類(lèi)型,在NumPy中,可以非常方便地創(chuàng)建各種不同類(lèi)型的多維數(shù)組,并且執(zhí)行一些基本操作。在深度學(xué)習(xí)中,如果神經(jīng)元之間的連接關(guān)系涉及的參數(shù)是數(shù)組,便可利用array模塊進(jìn)行設(shè)定,如代碼清單1-1所示。

代碼清單1-1 array的基本操作


import numpy as np

a = [1, 2, 3, 4]         # a是python中的list類(lèi)型
b = np.array(a)          # 數(shù)組化之后b的類(lèi)型變?yōu)?array
type(b)                  # b的類(lèi)型 <type 'numpy.ndarray'>

b.shape                  # shape參數(shù)表示array的大小,這里是4
b.argmax()               # 調(diào)用arg max()函數(shù)可以求得array中的最大值的索引,這里是3
b.max()                  # 調(diào)用max()函數(shù)可以求得array中的最大值,這里是4
b.mean()                 # 調(diào)用mean()函數(shù)可以求得array中的平均值,這里是2.5

注意到在導(dǎo)入NumPy的時(shí)候,代碼中將np作為NumPy的別名。這是一種習(xí)慣性的用法,后面的章節(jié)中也默認(rèn)這么使用。在機(jī)器學(xué)習(xí)中常用到的矩陣的轉(zhuǎn)置操作可以首先通過(guò)matrix構(gòu)建矩陣,再用transpose函數(shù)來(lái)實(shí)現(xiàn)轉(zhuǎn)置,如代碼清單1-2所示。

代碼清單1-2 NumPy中實(shí)現(xiàn)矩陣轉(zhuǎn)置


import numpy as np
x=np.array(np.arange(12).reshape((3,4)))
 
'''
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
'''
t = x.transpose()
'''
[[ 0  4  8]
 [ 1  5  9]
 [ 2  6 10]
 [ 3  7 11]] 
'''

對(duì)于一維的array,array支持所有Python列表(List)支持的下標(biāo)操作方法,所以在此沒(méi)有特別列出,如代碼清單1-3所示。

代碼清單1-3 NumPy基礎(chǔ)數(shù)學(xué)運(yùn)算


import numpy as np

# 絕對(duì)值,1
a = np.abs(-1)

# sin函數(shù),1.0
b = np.sin(np.pi/2)

# tanh逆函數(shù),0.50000107157840523
c = np.arctanh(0.462118)

# e為底的指數(shù)函數(shù),20.085536923187668
d = np.exp(3)

# 2的3次方,8
f = np.power(2, 3)

# 點(diǎn)積,1*3+2*4=11
g = np.dot([1, 2], [3, 4])

# 開(kāi)方,5
h = np.sqrt(25)

# 求和,10
l = np.sum([1, 2, 3, 4])

# 平均值,5.5
m = np.mean([4, 5, 6, 7])

# 標(biāo)準(zhǔn)差,0.96824583655185426
p = np.std([1, 2, 3, 2, 1, 3, 2, 0])

(2)random模塊

NumPy中的隨機(jī)模塊包含了與隨機(jī)數(shù)產(chǎn)生和統(tǒng)計(jì)分布相關(guān)的基本函數(shù)。Python本身也有隨機(jī)模塊random,不過(guò)NumPy的random功能更豐富,隨機(jī)模塊一般會(huì)用于深度學(xué)習(xí)中一些隨機(jī)數(shù)的生成、seed的生成以及初始值的設(shè)定,具體的用法請(qǐng)看代碼清單1-4。

代碼清單1-4 random模塊相關(guān)操作


import numpy as np

# 設(shè)置隨機(jī)數(shù)種子
np.random.seed(42)

# 產(chǎn)生一個(gè)1x3,[0,1)之間的浮點(diǎn)型隨機(jī)數(shù)
# array([[ 0.37454012,  0.95071431,  0.73199394]])
# 后面的例子就不在注釋中給出具體結(jié)果了
np.random.rand(1, 3)

# 產(chǎn)生一個(gè)[0,1]之間的浮點(diǎn)型隨機(jī)數(shù)
np.random.random()

# 從a中有放回地隨機(jī)采樣7個(gè)
a = np.array([1, 2, 3, 4, 5, 6, 7])
np.random.choice(a, 7)

# 從a中無(wú)放回地隨機(jī)采樣7個(gè)
np.random.choice(a, 7, replace=False)

# 對(duì)a進(jìn)行亂序并返回一個(gè)新的array
b = np.random.permutation(a)
   
# 生成一個(gè)長(zhǎng)度為9的隨機(jī)bytes序列并作為str返回
# '\x96\x9d\xd1?\xe6\x18\xbb\x9a\xec'
np.random.bytes(9)

隨機(jī)模塊可以很方便地做一些快速模擬去驗(yàn)證結(jié)論,在神經(jīng)網(wǎng)絡(luò)中也能夠做一些快速的網(wǎng)絡(luò)構(gòu)造。如考慮一個(gè)非常違反直覺(jué)的概率題:一個(gè)選手去參加一個(gè)TV秀,有三扇門(mén),其中一扇門(mén)后有獎(jiǎng)品,這扇門(mén)只有主持人知道。選手先隨機(jī)選一扇門(mén),但并不打開(kāi),主持人看到后,會(huì)打開(kāi)其余兩扇門(mén)中沒(méi)有獎(jiǎng)品的一扇門(mén)。然后主持人問(wèn)選手:是否要改變一開(kāi)始的選擇?

這個(gè)問(wèn)題的答案是應(yīng)該改變一開(kāi)始的選擇。在第一次選擇的時(shí)候,選錯(cuò)的概率是2/3,選對(duì)的概率是1/3。第一次選擇之后,主持人相當(dāng)于幫忙剔除了一個(gè)錯(cuò)誤答案,所以如果一開(kāi)始選的是錯(cuò)的,這時(shí)候換掉就對(duì)了;而如果一開(kāi)始就選對(duì)了,則這時(shí)候換掉就錯(cuò)了。根據(jù)以上分析,一開(kāi)始選錯(cuò)的概率就是換掉之后選對(duì)的概率(2/3),這個(gè)概率大于一開(kāi)始就選對(duì)的概率(1/3),所以應(yīng)該換。雖然道理上是這樣的,但是通過(guò)推理仍不明白怎么辦?沒(méi)關(guān)系,用隨機(jī)模擬就可以輕松得到答案。

這一部分請(qǐng)讀者作為練習(xí)自行完成。

2.廣播機(jī)制

對(duì)于array,默認(rèn)執(zhí)行對(duì)位運(yùn)算。涉及多個(gè)array的對(duì)位運(yùn)算需要array的維度一致,如果一個(gè)array的維度與另一個(gè)array的維度不一致,則在沒(méi)有對(duì)齊的維度上分別執(zhí)行對(duì)位運(yùn)算,這種機(jī)制稱(chēng)為廣播(Broadcasting),具體通過(guò)代碼清單1-5理解。

代碼清單1-5 廣播機(jī)制的理解


import numpy as np

a = np.array([
    [1, 2, 3],
    [4, 5, 6]
])

b = np.array([
    [1, 2, 3],
    [1, 2, 3]
])

'''
維度一樣的array,對(duì)位計(jì)算
array([[2, 4, 6],
       [5, 7, 9]])
'''
a + b

c = np.array([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
    [10, 11, 12]
])
d = np.array([2, 2, 2])

'''
廣播機(jī)制讓計(jì)算的表達(dá)式保持簡(jiǎn)潔
d和c的每一行分別進(jìn)行運(yùn)算
array([[ 3,  4,  5],
       [ 6,  7,  8],
       [ 9, 10, 11],
       [12, 13, 14]])
'''
c + d

3.向量化

讀者在1.2.1節(jié)已經(jīng)初步了解到,向量化在深度學(xué)習(xí)中的應(yīng)用十分廣泛,它是提升計(jì)算效率的主要手段之一,對(duì)于在機(jī)器學(xué)習(xí)中縮短每次訓(xùn)練的時(shí)間具有重要意義,當(dāng)可用工作時(shí)間不變的情況下,更短的單次訓(xùn)練時(shí)間可以讓程序員有更多的測(cè)試機(jī)會(huì),進(jìn)而更快、更好地調(diào)整神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu)和參數(shù)。代碼清單1-6~1-8通過(guò)一個(gè)矩陣相乘的例子展示了向量化對(duì)于代碼計(jì)算速度的提升效果。

在代碼清單1-6中首先導(dǎo)入了numpy和time庫(kù),它們分別被用于數(shù)學(xué)計(jì)算和統(tǒng)計(jì)運(yùn)行時(shí)間。然后準(zhǔn)備數(shù)據(jù),這里初始化兩個(gè)1000000維的隨機(jī)向量v1和v2,v作為計(jì)算結(jié)果初始化為零。

代碼清單1-6 導(dǎo)入庫(kù)和數(shù)據(jù)初始化


import numpy as np
import time
#初始化兩個(gè)1000000維的隨機(jī)向量v1,v2用于矩陣相乘計(jì)算
v1 = np.random.rand(1000000)      
v2 = np.random.rand(1000000)
v = 0

在代碼清單1-7中,設(shè)置變量tic和toc分別為計(jì)算開(kāi)始和結(jié)束時(shí)間。在非向量化版本中,兩個(gè)向量相乘的計(jì)算過(guò)程使用for循環(huán)實(shí)現(xiàn)。

代碼清單1-7 矩陣相乘(非向量化版本)


#矩陣相乘-非向量化版本
tic = time.time()
for i in range(1000000):
    v += v1[i] * v2[i]
toc = time.time()
print("非向量化-計(jì)算時(shí)間:" + str((toc - tic)*1000)+"ms"+"\n")

在代碼清單1-8中,同樣使用變量tic和toc記錄計(jì)算開(kāi)始和結(jié)束時(shí)間。向量化版本使用NumPy庫(kù)的numpy.dot()計(jì)算矩陣相乘。

代碼清單1-8 矩陣相乘(向量化版本)


#矩陣相乘-向量化版本
tic = time.time()
v = np.dot(v1, v2)
toc = time.time()
print("向量化-計(jì)算時(shí)間:" + str((toc - tic)*1000)+"ms")

為了保證計(jì)算結(jié)果相同,我們輸出了二者的計(jì)算結(jié)果,確保計(jì)算無(wú)誤。最后的輸出結(jié)果為“非向量化-計(jì)算時(shí)間為578.0208ms,向量化-計(jì)算時(shí)間為1.1038ms”。可以觀(guān)察到效率提升效果十分顯著。非向量化版本計(jì)算時(shí)間約為向量化版本計(jì)算時(shí)間的500倍。可見(jiàn)向量化對(duì)于計(jì)算速度的提升非常顯著,尤其在長(zhǎng)時(shí)間的深度學(xué)習(xí)訓(xùn)練中,向量化可以幫助開(kāi)發(fā)者節(jié)省更多時(shí)間。

主站蜘蛛池模板: 彩票| 常宁市| 常宁市| 商丘市| 车险| 长岛县| 色达县| 长垣县| 延安市| 阿尔山市| 桐柏县| 诸暨市| 林州市| 汝阳县| 德州市| 湖北省| 富民县| 徐闻县| 龙海市| 昌图县| 台江县| 东方市| 长治县| 大姚县| 临汾市| 灵武市| 丹棱县| 定襄县| 灵台县| 内黄县| 巴青县| 安平县| 武冈市| 呈贡县| 太仆寺旗| 浦县| 大化| 和政县| 东乌珠穆沁旗| 承德市| 万载县|