一、Python的矩陣傳播機(jī)制(Broadcasting)
我們知道在深度學(xué)習(xí)中經(jīng)常要操作各種矩陣(matrix)。
回想一下,我們?cè)诓僮鲾?shù)組(list)的時(shí)候,經(jīng)常習(xí)慣于用**for循環(huán)(for-loop)**來(lái)對(duì)數(shù)組的每一個(gè)元素進(jìn)行操作。例如:
my_list = [1,2,3,4]
new_list = []
for each in my_list:
new_list.append(each*2)
print(new_list) # 輸出 [2,3,4,5]
如果是矩陣呢:
my_matrix = [[1,2,3,4],
[5,6,7,8]]
new_matrix = [[],[]]
for i in range(2):
for j in range(4):
new_matrix[i].append(my_matrix[i][j]*2)
print(new_matrix)# 輸出 [[2, 4, 6, 8], [10, 12, 14, 16]]
實(shí)際上,上面的做法是十分的低效的!數(shù)據(jù)量小的話還不明顯,如果數(shù)據(jù)量大了,尤其是深度學(xué)習(xí)中我們處理的矩陣往往巨大,那用for循環(huán)去跑一個(gè)矩陣,可能要你幾個(gè)小時(shí)甚至幾天。
Python考慮到了這一點(diǎn),這也是本文主要想介紹的**“Python的broadcasting”即傳播機(jī)制**。
先說(shuō)一句,python中定義矩陣、處理矩陣,我們一般都用numpy這個(gè)庫(kù)。
二、下面展示什么是python的傳播機(jī)制
import numpy as np# 先定義一個(gè)3×3矩陣 A:
A = np.array(
[[1,2,3],
[4,5,6],
[7,8,9]])
print(“A:
”,A)
print(“
A*2:
”,A*2) # 直接用A乘以2print(“
A+10:
”,A+10) # 直接用A加上10
運(yùn)行結(jié)果:
A:
[[1 2 3]
[4 5 6]
[7 8 9]]
A*2:
[[ 2 4 6]
[ 8 10 12]
[14 16 18]]
A+10:
[[11 12 13]
[14 15 16]
[17 18 19]]
接著,再看看矩陣×(+)矩陣:
#定義一個(gè)3×1矩陣(此時(shí)也可叫向量了)
B = np.array([[10],
[100],
[1000]])
print(“
B:
”,B)
print(“
A+B:
”,A+B)
print(“
A*B:
”,A*B)
運(yùn)行結(jié)果:
B:
[[ 10]
[ 100]
[1000]]
A+B:
[[ 11 12 13]
[ 104 105 106]
[1007 1008 1009]]
A*B:
[[ 10 20 30]
[ 400 500 600]
[7000 8000 9000]]
可見(jiàn),雖然A和B的形狀不一樣,一個(gè)是3×3,一個(gè)是3×1,但是我們?cè)趐ython中可以直接相加、相乘,相減相除也可以。
也許看到這,大家都對(duì)broadcasting有感覺(jué)了。
用一個(gè)圖來(lái)示意一下:
所謂“傳播”,就是把一個(gè)數(shù)或者一個(gè)向量進(jìn)行“復(fù)制”,從而作用到矩陣的每一個(gè)元素上。
有了這種機(jī)制,那進(jìn)行向量和矩陣的運(yùn)算,就太方便了!理解了傳播機(jī)制,就可以隨心所欲地對(duì)矩陣進(jìn)行各種便捷的操作了。
利用numpy的內(nèi)置函數(shù)對(duì)矩陣進(jìn)行操作:
numpy內(nèi)置了很多的數(shù)學(xué)函數(shù),例如np.log(),np.abs(),np.maximum()等等上百種。直接把矩陣丟進(jìn)去,就可以算出新矩陣!示例:
print(np.log(A))
輸出把A矩陣每一個(gè)元素求log后得到的新矩陣:
array([[0. , 0.69314718, 1.09861229],
[1.38629436, 1.60943791, 1.79175947],
[1.94591015, 2.07944154, 2.19722458]])
再比如深度學(xué)習(xí)中常用的ReLU激活函數(shù),就是y=max(0,x),
也可以對(duì)矩陣直接運(yùn)算:
X = np.array([[1,-2,3,-4], [-9,4,5,6]])Y = np.maximum(0,X)print(Y)
得到:
[[1 0 3 0] [0 4 5 6]]
更多的numpy數(shù)學(xué)函數(shù),可以參見(jiàn)文檔:https://docs.scipy.org/doc/numpy-1.13.0/reference/routines.math.html
三、定義自己的函數(shù)來(lái)處理矩陣
其實(shí)這才是我寫下本文的目的。。。前面扯了這么多,只是做個(gè)鋪墊(/ω\)
我昨天遇到個(gè)問(wèn)題,就是我要對(duì)ReLU函數(shù)求導(dǎo),易知,y=max(0,x)的導(dǎo)函數(shù)是:y’ = 0 if x《0y’ = 1 if x》0但是這個(gè)y’(x)numpy里面沒(méi)有定義,需要自己構(gòu)建。即,我需要將矩陣X中的小于0的元素變?yōu)?,大于0的元素變?yōu)?。搞了好久沒(méi)弄出來(lái),后來(lái)在StackOverflow上看到了解決辦法:
def relu_derivative(x):
x[x《0] = 0
x[x》0] = 1
return x
X = np.array([[1,-2,3,-4],
[-9,4,5,6]])
print(relu_derivative(X))
輸出:
[[1 0 1 0]
[0 1 1 1]]
**居然這么簡(jiǎn)潔就出來(lái)了!!!**ミ?Д?彡 (?Д?#)
這個(gè)函數(shù)relu_derivative中最難以理解的地方,就是**x[x》0]**了。于是我試了一下:
X = np.array([[1,-2,3,-4],
[-9,4,5,6]])
print(X[X》0])
print(X[X《0])
輸出:
[1 3 4 5 6]
[-2 -4 -9]
它直接把矩陣X中滿足條件的元素取了出來(lái)!原來(lái)python對(duì)矩陣還有這種操作!
震驚了我好久~
所以可以這么理解,X[X》0]相當(dāng)于一個(gè)“選擇器”,把滿足條件的元素選出來(lái),然后直接全部賦值。
用這種方法,我們便可以定義各種各樣我們需要的函數(shù),然后對(duì)矩陣整體進(jìn)行更新操作了!
四、綜上
可以看出,python以及numpy對(duì)矩陣的操作簡(jiǎn)直神乎其神,方便快捷又實(shí)惠。其實(shí)上面忘了寫一點(diǎn),那就是計(jì)算機(jī)進(jìn)行矩陣運(yùn)算的效率要遠(yuǎn)遠(yuǎn)高于用for-loop來(lái)運(yùn)算,
不信可以用跑一跑:
# vetorization vs for loop# define two arrays a, b:
a = np.random.rand(1000000)
b = np.random.rand(1000000)
# for loop version:
t1 = time.time()
c = 0
for i in range(1000000):
c += a[i]*b[i]
t2 = time.time()
print(c)
print(“for loop version:”+str(1000*(t2-t1))+“ms”)
time1 = 1000*(t2-t1)
# vectorization version:
t1 = time.time()
c = np.dot(a,b)
t2 = time.time()
print(c)
print(“vectorization version:”+str(1000*(t2-t1))+“ms”)
time2 = 1000*(t2-t1)
print(“vectorization is faster than for loop by ”+str(time1/time2)+“ times!”)
運(yùn)行結(jié)果:
249765.8415288075
for loop version:627.4442672729492ms
249765.84152880745
vectorization version:1.5032291412353516ms
vectorization is faster than for loop by 417.39762093576525 times!
可見(jiàn),用for方法和向量化方法,計(jì)算結(jié)果是一樣,但是后者比前者快了400多倍!
因此,在計(jì)算量很大的時(shí)候,我們要盡可能想辦法對(duì)數(shù)據(jù)進(jìn)行Vectorizing,即“向量化”,以便讓計(jì)算機(jī)進(jìn)行矩陣運(yùn)算。
責(zé)任編輯:haq
-
for
+關(guān)注
關(guān)注
0文章
44瀏覽量
15830 -
python
+關(guān)注
關(guān)注
56文章
4800瀏覽量
84820 -
深度學(xué)習(xí)
+關(guān)注
關(guān)注
73文章
5507瀏覽量
121298
原文標(biāo)題:消滅 for 循環(huán)!Python 的矩陣傳播機(jī)制和矩陣運(yùn)算
文章出處:【微信號(hào):LinuxHub,微信公眾號(hào):Linux愛(ài)好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論