當前位置:股票大全官網 - 資訊咨詢 - 人工智能基礎——算法工程師為什麽要懂線性代數?

人工智能基礎——算法工程師為什麽要懂線性代數?

什麽是線性代數?

在大學數學中,線性代數是最抽象的課程,從初等數學到線性代數的思維跨度遠大於微積分和概率統計。很多人都停留在了知其然不知其所以然的階段。幾年後,他們發現線性代數的應用無處不在,卻不能很好的理解和掌握。的確,大多數人都能輕松理解初等數學的概念。函數、方程、數列都是那麽的自然,但壹旦進入線性代數的世界,就仿佛置身於另壹個陌生的世界,迷失在各種奇怪的符號和運算中。

剛接觸線性代數的時候,我只是單純的覺得這是壹門飛行學科,腦海中浮現出壹個問題:

如果看到這個問題,妳的反應是“不用說,數學當然是客觀自然規律”。我壹點也不驚訝。我自己也曾經這麽認為。從中學的初等數學和初等物理開始,很少有人懷疑壹門數學學科是不是自然規律。我學微積分和概率統計的時候從來沒有懷疑過。只有線性代數讓我產生了懷疑,因為它的符號和運算規則太抽象太奇怪,不符合生活經驗。所以,我真的要感謝線性代數,它引發了我對壹門數學學科本質的思考。其實不僅僅是學生,很多數學老師都不知道線性代數是什麽,是用來做什麽的,不僅國內不知道,國外也不知道。中國的孟雁寫了《理解矩陣》,國外的謝爾登·埃克斯勒教授寫了《線性代數應該學習的方法》,但他們都沒有從根本上解釋線性代數的來龍去脈。對我自己來說,大學的時候沒有學過線性代數,後來從編程的角度理解了。很多人說數學好對編程有幫助,而我恰好相反。理解程序有助於我理解數學。

本文的目標讀者是程序員,所以我將帶妳在線性代數的世界裏進行壹次程序員的深度冒險!既然我們是程序員,在進入線性代數領域之前,不妨先考察壹下程序世界,請大家思考這樣壹個問題:

為什麽問這麽傻的問題?因為它的答案是顯而易見的,大家對日常使用的編程語言的理解壹定比抽象的線性代數要好。顯然,編程語言雖然包含內部邏輯,但本質上都是人為設計的。所有編程語言的相似之處在於建立了壹套模型,定義了壹套語法,每壹套語法都映射到壹個特定的語義上。程序員和語言實現者遵守語言契約:程序員保證代碼符合語言的語法,編譯器/解釋器保證代碼執行的結果符合語法對應的語義。比如C++規定對象A要用新的A()語法在堆上構造。這樣寫C++的話,壹定要保證相應的執行效果,在堆上分配內存,調用A的構造函數,否則編譯器就違反了語言契約。

從應用的角度來看,可以把線性代數看作壹門編程語言嗎?答案是肯定的,我們可以用語言契約作為標準來嘗試。假設妳有壹個圖像,妳想把它旋轉60度,沿著X軸拉伸兩次。線性代數告訴妳,“好!妳按照我的語法構造壹個矩陣,然後按照矩陣乘法規則把妳的圖像相乘,我保證結果就是妳想要的。”其實線性代數和SQL之類的DSL很像。我們來做壹些類比:

因此,從應用的角度來看,線性代數是壹種人工設計的特定領域語言(DSL),它建立壹套模型,通過符號系統完成語法和語義的映射。其實向量、矩陣、運算規則的語法和語義都是人為設計的,這和壹門語言中的各種概念是壹樣的。是壹種創造,但前提是必須滿足語言契約。

為什麽會有線性代數?

有些人可能不願意將線性代數視為DSL。我給妳壹個矩陣,妳把我的圖旋轉60度,沿著X軸拉伸兩次。我總是沒有安全感。我都不知道妳在底層是怎麽做到的!其實就像有些程序員對高級語言不實用,以為底層就是程序的本質,總想知道把這句話編譯成匯編是什麽感覺。為該操作分配了多少內存?有人在Shell裏直接輸入壹個wget命令就可以得到壹個網頁,而他要花上幾十分鐘用C語言寫壹堆代碼才能實用。其實所謂的底和頂只是壹個習慣性的說法,並不是誰比誰更本質。程序的編譯和解釋本質上是不同模型之間的語義映射。通常情況下,高級語言映射到低級語言,但是方向完全可以反過來。Fabricbellard用JavaScript寫了壹個虛擬機,在JavaScript虛擬機上運行Linux,就是把機器模型映射到JavaScript模型。

新模型的建立必須依賴現有模型,但這是建模的手段而不是目的。任何新模型的目的都是為了更簡單地分析和解決某壹類問題。線性代數在建立的時候,它的概念和運算規則依賴於初等數學的知識,但是壹旦建立了這種抽象模型,我們就要習慣於直接使用高層次的抽象模型來分析和解決問題。說到線性代數,它比初等數學更容易分析和解決問題。讓我們通過壹個例子來感受它的好處:

初等數學中最著名的計算三角形面積的公式是面積= 1/2 *底*高。當三角形有壹條邊正好在坐標軸上時,我們可以很容易地計算出它的面積。但是,如果我們旋轉同壹個三角形的坐標軸,使得它的邊不在坐標軸上呢?我們還能得到它的底部和高度嗎?答案當然是肯定的,但顯然是復雜的,要在很多情況下討論。

相反,如果我們用線性代數的知識來解決這個問題,就非常容易了。線性代數中,兩個向量A和B的叉積是壹個方向垂直於A和B的向量,其大小等於A和B組成的平行四邊形的面積:

我們可以把三角形的邊看成向量,所以三角形的面積等於兩個邊向量的叉積向量的長度除以二:

註意:length表示方向量的長度,cross_product表示兩個向量的叉積。

初等數學中這麽壹個小難題,線性代數就能瞬間解決!可能有人會說,妳直接基於叉積做很容易,但是叉積本身不是挺復雜的嗎?妳為什麽不試試呢?是的,模型的作用就是把壹些復雜性隱藏到模型中,讓模型的使用者更容易解決問題。曾經有人質疑C++太復雜,C++之父比雅尼·斯特勞斯特魯普回答說:

在特定環境下,問題的復雜程度是由其性質決定的。C++將部分復雜性引入語言和標準庫,以使應用程序更簡單。當然,C++並不是在所有情況下都能讓問題變得簡單,但原則上,C++的復雜性是有意義的。除了C++,Java、SQL、CSS等語言和框架都比較好。想象壹下,不使用數據庫,自己做數據存儲和管理是多麽復雜!這樣我們就不難理解為什麽線性代數會把這麽奇怪的運算定義為叉積,這和C++把很多常用的算法和容器並入STL是壹樣的。同樣,您甚至可以在線性代數中定義自己想要的操作,以便重用。所以,數學壹點也不死板,它像程序壹樣活潑,了解它的脈絡妳就能駕馭自如。說到這裏,我們就順便回答壹個很常見的疑問:

其實線性代數和程序復用壹樣,定義了點積、叉積、矩陣運算,是因為它們應用廣泛,有很大的復用價值,可以作為我們分析和解決問題的基礎。比如很多問題都涉及到壹個向量到另壹個向量的投影或者兩個向量之間的夾角,所以我們會考慮定義點積的運算:

點產品的概念屬於設計,有創意的空間。設計壹旦確定,具體的公式就不能隨意發揮,壹定要有邏輯性,保證其映射到初等數學模型的正確性。這就好比壹門高級語言可以定義很多概念,比如高級函數、閉包等。,但它必須確保映射到底層實現時產生的效果符合其定義的規範。

線性代數有什麽好?

如上所述,線性代數是壹種高級抽象模型,我們可以通過學習壹門編程語言來學習它的語法和語義,但這種理解不僅僅是針對線性代數,而是針對每壹門數學學科,可能有人會有疑問。

這就把我們帶到了線性代數的核心:向量模型。我們在初等數學中學習的坐標系屬於笛卡爾提出的解析模型。這個模型很有用,但是也有很大的缺點。坐標系是壹個人工的虛擬參考系,但是我們要解決的問題,比如求面積,畫旋轉,拉伸,都與坐標系無關。建立虛擬坐標系往往無助於問題的解決,就像剛才三角形面積的例子。

矢量模型克服了解析模型的缺點。如果分析模型代表“絕對”世界觀,那麽矢量模型代表“相對”世界觀。我建議把向量模型和解析模型看成是兩個對立的模型。

矢量模型中定義了矢量和標量的概念。向量有大小和方向,滿足線性組合定律。標量是只有大小沒有方向的量(註:標量的另壹個更深層次的定義是在旋轉變換下不變的量)。矢量模型的壹個優點就是獨立於坐標系,也就是相對性。在定義向量和運算規則時,它從壹開始就拋棄了坐標系的約束。不管妳的坐標軸怎麽轉,我都能適應。向量的線性組合、內積、叉積、線性變換等運算都是獨立於坐標系的。註意,所謂坐標系獨立,並不是說沒有坐標系,而是有。剛才三角形例子的頂點都是用坐標表示的,但是不同的坐標系在解題的時候是不會影響的。打個比喻,Java號稱平臺無關,不是說Java是空中樓閣,而是妳用Java編程的時候底層是Linux還是Windows往往對妳沒有影響。

向量模型有什麽好處?除了剛才的三角形面積問題是壹個例子之外,我再舉壹個幾何學的例子:

如果要從解析幾何的角度解決這個問題,幾乎太復雜,無從下手,除非是平面恰好通過坐標軸的特例,但如果從矢量模型考慮,就很簡單:根據平面方程,平面的法向量為v=(a,b,c),設它從平面上的任意壹點(x,y,z)到(x0,y0,z0)。然後用點積dot_product(w,v)計算w到v的投影向量p,其大小為(x0,y0,z0)到平面a*x+b*y+c*z+d = 0的垂直距離。這裏用到向量模型的基本概念:法向量、投影向量、點積,整個解題過程簡潔生動。

給大家留壹個類似的練習(熟悉機器學習的朋友可能會發現這就是線性代數在線性分類中的應用):

離開向量,我們來邀請線性代數的另壹個主角:矩陣。

線性代數定義了矩陣與向量、矩陣與矩陣的乘法。操作規則很復雜,不清楚該怎麽做。很多初學者理解不好。可以說矩陣是學好線性代數的障礙。遇到復雜的事情,往往需要先避免陷入細節,先從整體上把握。其實從程序的角度來說,再奇怪的形式,也無非是壹種語法,語法必須對應語義,所以理解矩陣的關鍵是理解它的語義。壹個矩陣的語義不止壹個,在不同的環境下有不同的語義,在同壹環境下可以有不同的解釋。最常見的有:1)表示線性變換;2)表示壹組列向量或行向量;3)表示壹組子矩陣。

矩陣整體對應線性變換語義:矩陣A乘以壹個向量V得到W,矩陣A表示從V到W的線性變換,比如妳想把向量v0逆時針旋轉60度得到V’,妳只需要把v0乘以旋轉矩陣。

除了旋轉變換,拉伸變換也是壹種常見的變換。比如我們可以通過壹個拉伸矩陣將向量沿X軸拉伸兩次(請自己嘗試給出拉伸矩陣的形式)。更重要的是,矩陣乘法有壹個很好的性質:它滿足組合率,這意味著線性變換可以疊加。比如我們可以將“逆時針旋轉60度”的矩陣m和“沿X軸拉伸2倍”的矩陣n相乘,得到壹個新的表示“逆時針旋轉60度,沿X軸拉伸2倍”的矩陣T。這不是很像在我們的Shell中通過管道堆疊多個命令嗎?

以上重點介紹了矢量模型的坐標系獨立性。此外,向量模型的另壹個優點是可以描述線性關系。讓我們看壹個熟悉的斐波那契數列的例子:

首先我們構造兩個向量,v1=(f(n+1),f(n))和v2=(f(n+2),f(n+1))。根據斐波那契數列的性質,我們可以得到從v1到v2。

並進壹步得到:

這樣就把線性遞歸問題轉化為n次冪矩陣的經典問題,可以在O(log n)時間復雜度內求解。除了線性遞歸序列,初等數學中眾所周知的n元線性方程組問題也可以轉化為矩陣和向量乘法來更容易地解決。這個例子的目的是為了說明所有滿足線性關系的系統都是向量模型發揮作用的地方,我們往往可以將其轉化為線性代數來得到簡潔高效的解。

摘要

本文提出壹個觀點:從應用的角度來看,可以把線性代數看作是壹種特定領域的編程語言。線性代數在初等數學的基礎上建立向量模型,定義壹套符合編程語言的語法和語義的語言契約。矢量模型獨立於坐標系,是線性的。它是整個線性代數的核心,是解決線性空間問題的最佳模型。向量的概念、性質、關系和變換是掌握和應用線性代數的關鍵。