神经网络基础篇:Python 中的广播(Broadcasting in Python)
Python 中的廣播
這是一個(gè)不同食物(每100g)中不同營養(yǎng)成分的卡路里含量表格,表格為3行4列,列表示不同的食物種類,從左至右依次為蘋果,牛肉,雞蛋,土豆。行表示不同的營養(yǎng)成分,從上到下依次為碳水化合物,蛋白質(zhì),脂肪。
那么,現(xiàn)在想要計(jì)算不同食物中不同營養(yǎng)成分中的卡路里百分比。
現(xiàn)在計(jì)算蘋果中的碳水化合物卡路里百分比含量,首先計(jì)算蘋果(100g)中三種營養(yǎng)成分卡路里總和56+1.2+1.8
= 59,然后用56/59 = 94.9%算出結(jié)果。
可以看出蘋果中的卡路里大部分來自于碳水化合物,而牛肉則不同。
對(duì)于其他食物,計(jì)算方法類似。首先,按列求和,計(jì)算每種食物中(100g)三種營養(yǎng)成分總和,然后分別用不用營養(yǎng)成分的卡路里數(shù)量除以總和,計(jì)算百分比。
那么,能否不使用for循環(huán)完成這樣的一個(gè)計(jì)算過程呢?
假設(shè)上圖的表格是一個(gè)4行3列的矩陣\(A\),記為 \(A_{3\times 4}\),接下來要使用Python的numpy庫完成這樣的計(jì)算。打算使用兩行代碼完成,第一行代碼對(duì)每一列進(jìn)行求和,第二行代碼分別計(jì)算每種食物每種營養(yǎng)成分的百分比。
在jupyter notebook中輸入如下代碼,按shift+Enter運(yùn)行,輸出如下。
下面使用如下代碼計(jì)算每列的和,可以看到輸出是每種食物(100g)的卡路里總和。
其中sum的參數(shù)axis=0表示求和運(yùn)算按列執(zhí)行,之后會(huì)詳細(xì)解釋。
接下來計(jì)算百分比,這條指令將 \(3\times 4\)的矩陣\(A\)除以一個(gè)\(1 \times 4\)的矩陣,得到了一個(gè) \(3 \times 4\)的結(jié)果矩陣,這個(gè)結(jié)果矩陣就是要求的百分比含量。
下面再來解釋一下A.sum(axis = 0)中的參數(shù)axis。axis用來指明將要進(jìn)行的運(yùn)算是沿著哪個(gè)軸執(zhí)行,在numpy中,0軸是垂直的,也就是列,而1軸是水平的,也就是行。
而第二個(gè)A/cal.reshape(1,4)指令則調(diào)用了numpy中的廣播機(jī)制。這里使用 \(3 \times 4\)的矩陣\(A\)除以 \(1 \times 4\)的矩陣\(cal\)。技術(shù)上來講,其實(shí)并不需要再將矩陣\(cal\) reshape(重塑)成 \(1 \times 4\),因?yàn)榫仃?span id="vt6mr5x" class="math inline">\(cal\)本身已經(jīng)是 \(1 \times 4\)了。但是當(dāng)寫代碼時(shí)不確定矩陣維度的時(shí)候,通常會(huì)對(duì)矩陣進(jìn)行重塑來確保得到想要的列向量或行向量。重塑操作reshape是一個(gè)常量時(shí)間的操作,時(shí)間復(fù)雜度是\(O(1)\),它的調(diào)用代價(jià)極低。
那么一個(gè) \(3 \times 4\) 的矩陣是怎么和 \(1 \times 4\)的矩陣做除法的呢?讓來看一些更多的廣播的例子。
在numpy中,當(dāng)一個(gè) \(4 \times 1\)的列向量與一個(gè)常數(shù)做加法時(shí),實(shí)際上會(huì)將常數(shù)擴(kuò)展為一個(gè) \(4 \times 1\)的列向量,然后兩者做逐元素加法。結(jié)果就是右邊的這個(gè)向量。這種廣播機(jī)制對(duì)于行向量和列向量均可以使用。
再看下一個(gè)例子。
用一個(gè) \(2 \times 3\)的矩陣和一個(gè) \(1 \times 3\) 的矩陣相加,其泛化形式是 \(m \times n\) 的矩陣和 \(1 \times n\)的矩陣相加。在執(zhí)行加法操作時(shí),其實(shí)是將 \(1 \times n\) 的矩陣復(fù)制成為 \(m \times n\) 的矩陣,然后兩者做逐元素加法得到結(jié)果。針對(duì)這個(gè)具體例子,相當(dāng)于在矩陣的第一列加100,第二列加200,第三列加300。這就是在前面的計(jì)算卡路里百分比的廣播機(jī)制,只不過這里是除法操作(廣播機(jī)制與執(zhí)行的運(yùn)算種類無關(guān))。
下面是最后一個(gè)例子
這里相當(dāng)于是一個(gè) \(m \times n\) 的矩陣加上一個(gè) \(m \times 1\) 的矩陣。在進(jìn)行運(yùn)算時(shí),會(huì)先將 \(m \times 1\) 矩陣水平復(fù)制 \(n\) 次,變成一個(gè) \(m \times n\) 的矩陣,然后再執(zhí)行逐元素加法。
廣播機(jī)制的一般原則如下:
這里先說一下本人對(duì)numpy廣播機(jī)制的理解。
首先是numpy廣播機(jī)制
如果兩個(gè)數(shù)組的后緣維度的軸長度相符或其中一方的軸長度為1,則認(rèn)為它們是廣播兼容的。廣播會(huì)在缺失維度和軸長度為1的維度上進(jìn)行。
后緣維度的軸長度:A.shape[-1] 即矩陣維度元組中的最后一個(gè)位置的值
對(duì)于博客中卡路里計(jì)算的例子,矩陣 \(A_{3,4}\) 后緣維度的軸長度是4,而矩陣 \(cal_{1,4}\) 的后緣維度也是4,則他們滿足后緣維度軸長度相符,可以進(jìn)行廣播。廣播會(huì)在軸長度為1的維度進(jìn)行,軸長度為1的維度對(duì)應(yīng)axis=0,即垂直方向,矩陣 \(\text{cal}_{1,4}\) 沿axis=0(垂直方向)復(fù)制成為 \(\text{cal_temp}_{3,4}\) ,之后兩者進(jìn)行逐元素除法運(yùn)算。
現(xiàn)在解釋上圖中的例子
矩陣 \(A_{m,n}\) 和矩陣 \(B_{1,n}\) 進(jìn)行四則運(yùn)算,后緣維度軸長度相符,可以廣播,廣播沿著軸長度為1的軸進(jìn)行,即 \(B_{1,n}\) 廣播成為 \({B_{m,n}}'\) ,之后做逐元素四則運(yùn)算。
矩陣 \(A_{m,n}\) 和矩陣 \(B_{m,1}\) 進(jìn)行四則運(yùn)算,后緣維度軸長度不相符,但其中一方軸長度為1,可以廣播,廣播沿著軸長度為1的軸進(jìn)行,即 \(B_{m,1}\) 廣播成為 \({B_{m,n}}'\) ,之后做逐元素四則運(yùn)算。
矩陣 \(A_{m,1}\) 和常數(shù)$ R$ 進(jìn)行四則運(yùn)算,后緣維度軸長度不相符,但其中一方軸長度為1,可以廣播,廣播沿著缺失維度和軸長度為1的軸進(jìn)行,缺失維度就是axis=0,軸長度為1的軸是axis=1,即\(R\)廣播成為 \({B_{m,1}}'\) ,之后做逐元素四則運(yùn)算。
最后,對(duì)于Matlab/Octave 有類似功能的函數(shù)bsxfun。
總結(jié)一下broadcasting,可以看看下面的圖:
總結(jié)
以上是生活随笔為你收集整理的神经网络基础篇:Python 中的广播(Broadcasting in Python)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Instagram 早期技术架构
- 下一篇: 【scipy 基础】--插值