從近視宅男買早餐到彭羅斯逆矩陣(1):矩陣乘法|N文粗通線性代數

「N文粗通線性代數」開篇辭:

本來想模仿網紅爆款文,寫篇《一文讀懂線性代數》。但實際一寫,發現很難。別說讓讀者讀懂,光是把一些概念粗淺地寫明白,也起碼要寫兩篇,於是把標題改成《兩文粗通線性代數》。寫着寫着,發現兩篇也不夠,最後只好改成《N文粗通線性代數》。

學習數學,從來都是一分耕耘,一分收穫,來不得半點自欺與浮躁,任何投機取巧都註定枉然。但刻苦用功不等於死記硬背、機械刷題。事實上,書本上抽象的數學原理,很多都是從自然現象與實際生活中歸納總結出來的。只要善於聯繫數學原理與實際生活,你會發現掌握線性代數並不難。

——吳進遠

撰文 | 吳進遠

在全世界的大學裡,“線性代數”這個名字給人的印象是學起來很難,很容易掛科,而且對找工作沒什麼用。其實這門課的應用並不窄。有個笑話說,有位教授開了線性代數課,選修者寥寥。於是下個學期他把課名改爲“人工智能工程基礎”,結果選修者趨之若鶩。至於學起來難不難,要看能不能找到合適的學習方法,方法對了就不難了。

書歸正傳,話說某近視宅男,某日下樓到早點鋪買早餐。眼鏡忘在家裡,看不清黑板上寫的價目。宅男心算能力超強,碰巧服務員小妹口算能力也超強,而且唱收唱付聲音清亮。

於是,宅男就一邊排隊,一邊聽着前邊顧客買早點的品種數量和服務員小妹報的總價,據此計算各種早點的單價。

(1)先乘再累加

爲了簡化問題,我們假定早點鋪只賣三種早點:

1)油餅,單價3元;

2)茶葉蛋,單價4元;

3)豆腐腦,單價7元。

當然這幾個單價對宅男來說是未知的。

第一個顧客買了一個油餅、一個茶葉蛋、一碗豆腐腦,服務員小妹報價14元;

第二個顧客買了兩個油餅、四個茶葉蛋、四碗豆腐腦,服務員小妹報價50元;

第三個顧客買了三個油餅、五個茶葉蛋、八碗豆腐腦,服務員小妹報價85元;

第四個顧客買了三個油餅、一個茶葉蛋、一碗豆腐腦,服務員小妹報價20元。

這幾筆交易可以列成下面一個表:

服務員小妹是怎樣算出總價的呢?很簡單,把顧客購買每種食品的數量乘以它們各自的單價,再把各個乘積加和起來,就得到了總價。這個計算方法,可以用下圖表示:

(2)矩陣與向量相乘

上面這個算法,可以用一個更簡潔的矩陣乘法公式寫出來:

有的時候,只有一個下標的矩陣可以稱爲向量。或者說,向量有時可以看成是一種特殊的矩陣。因此,上面這個公式顯示了矩陣乘法的一種特殊情況,即一個矩陣與一個向量相乘,得到另一個向量。不過注意,這兩個向量的意義不一定一樣,它們的維度也不一定一樣。

向量與矩陣之間的乘法是按照下面的公式進行的

在上面的計算中,我們把左邊矩陣中一行裡j=1到3的元素,與右邊矩陣(或向量)一列中j=1到3的元素一對對相乘然後累加,就得到新向量的一個元素。大家是不是覺得這話聽着像繞口令?現在我告訴你我是怎麼記住這個算法的。

我們可以把矩陣乘法中左邊的矩陣想象成一串串橫掛的羊肉串,把右邊的矩陣(或向量)看成是豎着插的糖葫蘆。二者相乘的時候,把糖葫蘆舉高,再橫過來。

然後把糖葫蘆與第一串羊肉串懟到一起,把一個個糖葫蘆球與對應的一片片羊肉一對一對地擼下來,打爛攪勻(即一對對地做乘法),再把一對對混合物捏在一起(即累加)。這樣就形成了新串燒(新向量)的第一個球。

用同樣的糖葫蘆與第二羊肉串做相同操作,就得到新串燒的第二球。對左邊矩陣的所有行重複這個運算,最終就得到了一個新的向量。總之,只要始終把左邊的矩陣看成橫掛的串燒,右邊的看成豎插的,就不會記混。

(3)矩陣與矩陣相乘

我們可以把上面買早餐的問題再擴展一下,比如這個餐廳的老闆鼓勵同學早起,規定早上七點以前有早起優惠,這樣就有了兩組不同的單價。而同樣的顧客購買同樣品種數量的食品,早起或睡懶覺就會有不同的總價。這種情況下,我們就有了一個公式:一個4行3列矩陣,乘以一個3行2列矩陣,得到一個4行2列矩陣。

在這個公式中,我們特意把食品的品種下標寫成油、蛋、豆,而價格的下標寫成平(常)、早(起)。這樣寫的目的,是強調不同的下標表示的意義可能是不同的。儘管我們平時都用1,2,3,4等下標,但不同下標即便使用相同的數字,它們代表的意義也可能相差十萬八千里,千萬不可以傻傻分不清。

上面公式中保留的1,2,3,4代表了不同的顧客,如果不嫌煩瑣,我們也完全可以把這些顧客用他們的自然姓名標註,比如張三、李四、陳老大、王二麻子等等。不過,代數代數,妙就妙在這個“代”字上。數學中一個非常重要的技巧,就是把一些繁雜的事物,以及對這些繁雜事物的處理方法,打包起來,用一個比較簡單的符號代替。通過這樣一種層層迭代,人們就可以認識與處理遠遠超過人腦處理能力的複雜事物。比如前面談到的矩陣乘法,就可以用一個很簡單的公式寫出來:

更進一步,我們甚至可以把這個運算直接寫成 y = Ax 。

(4)愛因斯坦求和約定

大家都知道愛因斯坦,他腦子比咱們大家都好使,上面這個公式對他應該是小菜一碟。可是架不住他天天做這樣的推導運算,整天“西格瑪”“西格瑪”地寫,也夠煩的,於是他老人家就提出了一個著名的愛因斯坦求和約定。這個約定最主要的一件事,就是遇到類似的矩陣乘法可以不寫“西格瑪”。兩個數懟到一起,如果有相同的下標或上標,就表示對這個下標(或上標)的所有成員一對對相乘然後求和。於是上面那個公式就簡化爲:

這個約定看似只做了很少的簡化,但可以想象一下,如果討論的問題涉及很多個矩陣連續相乘,我們就需要寫上很多層連加號。這種情況下,使用愛因斯坦求和約定帶來的好處就非常明顯了。

愛因斯坦求和約定還涉及一些細節,比如下標與上標的使用規範。又比如用拉丁字母做上下標代表三維空間中1,2,3這三個維度,而用希臘字母做上下標時表示時間加空間,即0,1,2,3這四個維度。這些大家讀到具體的文獻時就會接觸到。

(5)硬件相乘累加運算單元

這種兩組數一對一對地相乘再累加的運算,在數學的很多領域都有非常廣泛的應用。除了矩陣乘法,我們學過加權平均,兩個矢量的內積(點積)都是這樣的形式。由於這種運算使用得太頻繁了,在現代的微處理器、數字信號處理器以及現場可編程門陣列(FPGA)等邏輯芯片中,人們經常會把相乘累加運算單元直接設計進去。

上圖就是一個典型的相乘累加運算單元。輸入的數據從ai和xi這兩個端口送進去,每個時鐘週期放一對數。這一對數相乘之後,其乘積送到累加器。每次得到的新的乘積都與留存在寄存器中的部分和y相加。等到ai與xi這兩個向量中所有的成員都刷過一遍之後,寄存器y就累加出了這兩個向量的內積。

(6)矩陣乘法與圖片旋轉

大家可能會問,這種矩陣或者向量的乘法運算,除了買早餐算賬,還有什麼用呢?我們現在討論一個和吃沒有關係的例子。

外出旅遊,拍了一張很好看的風景照,可惜手機沒有端平,地平線拍歪了。這樣一張照片,怎麼才能把地平線調平呢?

照片是由縱橫排列的像素構成的,要想把地平線調平,只要把所有像素圍繞一個原點旋轉一定角度就可以了。具體講,是把橫座標爲x1,縱座標爲x2的像素,按照下面這個公式,移動到橫座標y1,縱座標y2的位置。或者說,我們要對照片每個像素的座標做線性變換。(注意我們這裡分別用x和y代表轉動前後的座標,而用下標1、2代表橫座標與縱座標。這是爲了和我們前面的用法統一形式。)

把所有像素的座標都按照這個公式算出來,再把各個像素移動到新的位置,我們就可以看到整個照片旋轉了一個角度。當然實際操作時,新圖片中可能會有一些像素被漏掉,這就需要根據周圍像素顯示的色彩亮度數據來做插值,把這些漏掉的像素填上。

(7)美顏磨皮

如今照相,美顏已成爲標配功能。所謂美顏,其實就是對照片中的像素做一系列的修改。這些像素修改,很多時候要用到矩陣乘法。磨皮是美顏中的一個重要功能。比如下面這位笑臉帥哥,不滿意自己皮膚,尤其是眼睛下方皮膚的鬆弛感,就給自己的照片做了磨皮。

原始照片有很多瑕疵,皮膚上各種斑點非常多。經過磨皮,這些缺陷被抹掉了。

磨皮有非常多的算法,上網搜一搜甚至能找到不少學術會議論文。磨皮算法中最簡單的一種,是把一個小範圍內的像素做加權平均,然後生成一個新的像素。用公式寫出來是這樣的:

這個算法可以寫成矩陣乘法的形式:

這裡請讀者注意,公式中所有權重因子的和等於1。新生成圖片的每個像素都是原始圖片對應點附近九個像素的加權平均。這九個像素對新像素的貢獻是不同的,其中中心像素的貢獻爲0.2,比周邊像素的貢獻(0.1)要高。經過這個運算,原始圖片中相鄰像素亮度(或顏色)突然跳變的情形就被平均掉了,圖片看起來就顯得更加平滑。

對於大多數彩色數字圖片,每個像素包括紅綠藍三種顏色,q1到q9是這九個像素中某一種顏色的亮度值,上面的運算要對所有三種顏色重複進行。這些亮度值通常是整數,範圍是0到255,用8個比特來表述。

在處理器硬件中,整數運算通常要比浮點運算快,功耗也更低。此外,乘法的功耗要比普通的加減法高。只是我們平時編程的時候,運算操作會交給編譯器調用的事先寫好的二進制代碼,我們完全感覺不到底層處理過程,但所有這些運算消耗的電能是實打實的。要想節約能耗,我們就應該儘量減少浮點運算,減少乘法,於是上面這個矩陣乘法可以寫成:

這個公式中,由於大部分權重爲1,所以不需要做乘法,直接把整數亮度值累加起來就可以了。中間權重爲2,相當於把對應的整數q5加兩次,也相當於把q5所有的二進制比特向左移動一位。

最後累加出來的結果,我們把它乘以0.1,而不是除以10。這是因爲除法是四則運算中最麻煩的——不僅僅是筆算時麻煩,在計算機中也同樣如此。

有時候,我們會把節約功耗的想法在算法設計的過程中就體現出來,比如像下面這個公式裡的情形。

這個公式中,整數亮度值與權重值的乘法,完全可以通過移位來實現,乘以2或4分別相當於向左移動1位或2位。最後累加結果需要除以16,可以用向右移動4位實現。

對大多數碼農來說,這類節約資源與功耗的技巧可有可無,因爲現代處理器都比較快,像磨皮這種偶爾用一次的子程序,上述技巧帶來的好處不很明顯。不過,如果是FPGA等資源有限的硬件環境,計算量又非常大的情況下,這種設計與實現算法的技巧就會有用武之地了。

各位讀者可能會問,宅男算出食品單價了沒有?別急,我和您說過一篇文章寫不完,欲知後事如何,且聽下回分解。

特 別 提 示

1. 進入『返樸』微信公衆號底部菜單“精品專欄“,可查閱不同主題系列科普文章。

2. 『返樸』提供按月檢索文章功能。關注公衆號,回覆四位數組成的年份+月份,如“1903”,可獲取2019年3月的文章索引,以此類推。

版權說明:歡迎個人轉發,任何形式的媒體或機構未經授權,不得轉載和摘編。轉載授權請在「返樸」微信公衆號內聯繫後臺。