Lesson 5.基本优化思想与最小二乘法
??在正式開始進行神經網絡建模之前,我們還需要掌握一些基本數學工具,在PyTorch中,最核心的基礎數學工具就是梯度計算工具,也就是PyTorch的AutoGrad(自動微分)模塊。雖然對于任何一個通用的深度學習框架,都會提供許多自動優化的算法和現成的loss function,PyTorch也不例外,但如果希望能夠更深入的理解神經網絡、希望對深度學習的建模不僅僅停留在調包和調參的層次,那我們就必須深入一些數學領域、掌握一些數學工具,從底層提升自己的數學能力,以期能夠在日后的使用深度學習算法的過程中能夠更加靈活的解決問題、取得更好的建模效果。而AutoGrad模塊,就是PyTorch提供的最核心的數學工具模塊,我們可以利用其編寫一系列的最優化方法,當然,要使用好微分工具,就首先需要了解廣泛應用于機器學習建模的優化思想。
??所謂優化思想,指的是利用數學工具求解復雜問題的基本思想,同時也是近現代機器學習算法在實際建模過程中經常使用基礎理論在實際建模過程中,我們往往會先給出待解決問題的數值評估指標,并在此基礎之上構建方程、采用數學工具、不斷優化評估指標結果,以期達到可以達到的最優結果。本節,我們將先從簡單線性回歸入手,探討如何將機器學習建模問題轉化為最優化問題,然后考慮使用數學方法對其進行求解。
一、簡單線性回歸的機器學習建模思路
??在《Lesson 4.張量的線性代數運算》結尾,我們曾簡單提及線性方程建模問題,彼時,我們將線性回歸問題轉化成,求解以線性方程系數為核心目標的線性方程組求解問題,并且將方程組轉化為矩陣表示形式,最終使用逆矩陣的方法解出線性方程系數。線性回歸是較為基礎且通用的模型,但使用矩陣方法求解卻不是一般方法。
??接下來,我們將更進一步,將簡單線性回歸的求解參數問題轉化為最優化問題求解問題,這也是機器學習建模過程中的最通用的思想。
1.回顧簡單線性回歸建模問題
import matplotlib as mpl import matplotlib.pyplot as pltA = torch.arange(1, 5).reshape(2, 2).float() A #tensor([[1., 2.], # [3., 4.]])# 繪制點圖查看兩個點的位置 plt.plot(A[:,0], A[:, 1], 'o')結果:
如果更進一步,我們希望在二維空間中找到一條直線,來擬合這兩個點,也就是所謂的構建一個線性回歸模型,我們可以設置線性回歸方程如下:
2.轉化為優化問題
??上述問題除了可以使用矩陣方法求解以外,還可以將其轉化為最優化問題,然后通過求解最優化問題的方法對其進行求解。總的來說,最優化問題的轉化分為兩步,其一是確定優化數值指標,其二則是確定優化目標函數。在大多數問題中,這二者是相輔相成的,確定了優化的數值指標,也就確定了優化的目標函數。
??如果我們希望通過一條直線擬合二維平面空間上分布的點,最核心的目標,毫無疑問,就是希望方程的預測值和真實值相差較小。假設真實的y值用y表示,預測值用?表示,帶入a、b參數,則有數值表示如下:
而這兩個預測值和真實值相差:
? ? ? ?我們希望?和y盡可能接近,因此我們可以考慮計算上述誤差總和,但為了避免正負相消(一部分為正、另一部分為負),在衡量上述兩個點的誤差總和時,我們使用平方和來進行衡量,而不是簡單的求和:
??上式也就是兩個點的預測值和真實值的差值的平方和,也就是所謂的,誤差平方和——SSE(Sum of the Squared Errors)。
當然,此處我們只帶入了(1, 2)和(3, 4)兩個點來計算SSE,也就是帶入了兩條數據來訓練y = ax + b這個模型。
不難發現,很多時候,機器學習的思想都是相對比較樸素的,很多看似復雜的概念,出發點都是一個非常“簡單”的想法,在學習機器學習的過程中,掌握其底層的樸素思想,能夠幫助大家在很多場景下活學活用。
??至此,我們已經將原問題轉化為了一個最優化問題,接下來我們的問題就是,當a、b取何值時,SSE取值最小?值得注意的是,SSE方程就是我們優化的目標方程(求最小值),因此上述方程也被稱為目標函數,同時,SSE代表著真實值和預測值之間的差值(誤差平方和),因此也被稱為損失函數(預測值距真實值的損失)。
換而言之,就是當SSE取值最小時,a、b的取值,就是最終線性回歸方程的系數取值。
值得注意的是,目標函數和損失函數并不完全等價,但大多數目標函數都由損失函數構成。
3.最優化問題的求解方法
??在機器學習領域,大多數優化問題都是圍繞目標函數(或者損失函數)進行求解。在上述問題中,我們需要圍繞SSE求最小值。SSE是一個關于a和b的二元函數,要求其最小值,需要借助數學工具,也就是所謂的最優化方法。選擇優化方法并執行相應計算,可以說是整個建模過程中最核心也是相對較難的部分,很多時候這個過程會直接決定模型的性能。
- 圖形展示目標函數
??為了更好的討論目標函數(SSE)求最小值的過程,對于上述二元函數來說,我們可以將其展示在三維空間內。此處我們可以使用Python中matplotlib包和Axes3D函數進行三維圖像繪制
from matplotlib import pyplot as plt from mpl_toolkits.mplot3d import Axes3Dx = np.arange(-1,3,0.05) y = np.arange(-1,3,0.05) a, b = np.meshgrid(x, y) SSE = (2 - a - b) ** 2 + (4 - 3 * a - b) ** 2ax = plt.axes(projection='3d')ax.plot_surface(a, b, SSE, cmap='rainbow') ax.contour(a, b, SSE, zdir='z', offset=0, cmap="rainbow") #生成z方向投影,投到x-y平面 plt.show()結果:?
- 函數的凹凸性
??初步探索函數圖像,不難看出,目標函數是個整體看起來“向下凸”的函數,函數的凹凸性是函數的重要性質,首先我們給出凸函數的一般定義,對于任意一個函數,如果函數f(x)上存在任意兩個點,𝑥1,𝑥2x1,x2,且
我們就判定,這個函數是凸函數。
典型的,例如𝑦=x^2,我們可以繪制函數圖像如下:?
x = np.arange(-10,10,0.1) y = x ** 2 plt.plot(x, y, '-') plt.show()結果:
不難看出,函數上任意兩個點的y取值的均值都不小于這兩個點均值的y的值。
# x1 = 1, x2 = 3 (1 ** 2 + 3 ** 2)/2 #5.0# x1 = 1, x2 = 3 ((1+3)/2) ** 2 #4.0而對于一個凸函數來說,全域最小值明顯存在,基于凸函數的數學定義,我們可以進一步給出求解上述SSE凸函數最小值的一般方法,也就是著名的最小二乘法
- 凸函數的最小值
??通過𝑦=𝑥^2函數不難看出,最小值x = 0唯一存在,并且最小值點對應的函數切線與x軸平行,也就是在最小值點,函數的導數為0。這其實也凸函數求解最小值的一般方法:
a).對于一元函數,如果存在導數為0的點,則該點就是最小值點;
b).對于多元函數,如果存在某一點,使得函數的各個自變量的偏導數都為0,則該點就是最小值點。
因此,對于凸函數的最小值求解,最基本的出發點就是尋找導數為0的點。而最小二乘法也是基于偏導函數取值為0聯立的方程組進行的求解。
從更嚴格的意義上來說,凸函數的最小值點其實是根據邊界點和駐點(導數為0的點)決定,如果沒有邊界點且沒有駐點,則函數沒有最小值(例如y=x),如果存在邊界點,但沒有駐點,則邊界點的一側就是最小值點,如果存在駐點(且左右兩邊單調性相反),則駐點就是最小值點,例如,對于𝑦=𝑥^2而言,𝑦′=2𝑥,2x = 0時x取值為0,也就是0點就是最小值點。
值得注意的是,駐點也可以說是臨界點,但不是拐點,拐點特指左右兩邊函數凹凸性發生變化的點,切勿和駐點混淆。
??函數的凹凸性是函數的重要性質,而在使用優化方法圍繞目標函數進行求解時,函數本身性質是決定使用哪種優化方法的重要因素,例如函數是否可導、是否連續、函數凹凸性等等。而要判斷函數的各種屬性,其實都需要經過非常嚴格的數學證明,也就是說,一般的采用數學優化方法求解的過程,都是先確定函數形式、然后探索函數性質、之后尋找優化方法、最終執行優化算法求解。
??當然,機器學習建模中的目標函數,大多數時候都是可導的函數,而凹凸性則是影響使用哪種最優化方法的最核心因素。正因如此,凸函數的最優化問題是優化方法的一類重要應用,甚至圍繞凸函數,還衍生出了凸優化相關的一大類優化問題分支學課,在機器學習中,我們經常聽說的最小二乘法就是求解凸優化問題的重要工具。當然,很多本身不是針對凸函數設計的最優化方法,但鑒于凸函數在求最小值時的優異特性,我們也會在凸優化過程中應用的、例如梯度下降、擬牛頓法等等等等,都是本次課程中重點學習的內容。
- SSE最小值
而對于SSE來說,此處雖然不做證明,但對于簡單線性回歸的損失函數,SSE是凸函數,因此,對于𝑆𝑆𝐸(𝑎,𝑏)=(2?𝑎?𝑏)^2+(4?3𝑎?𝑏)^2而言,最小值點就是a、b兩個參數求偏導等于0的點
?其中:
此外,還可通過(1)式解出一個參數然后帶入(2)式進行求解
利用偏導等于0得出的方程組求解線性回歸方程參數,就是最小二乘法求解過程。此處我們求得a=1,b=1時,SSE(a,b)取得最小值,也就是(1,1)是目標函數的最小值點。
4.機器學習建模一般流程
??至此,我們就完成了一個基本的簡單線性回歸建模過程。當然,對于線性回歸來說,有很多種建模方式,哪怕是主流的統計學和機器學習,在利用線性回歸進行建模時都有不一樣的流程(后續介紹機器學習基礎時還會詳細介紹)。此處我們是通過一個簡單的例子,來介紹機器學習、包括深度學習的利用優化方法建模的一般思想,我們可以將其總結如下:
- Step 1:提出基本模型
- 如本節中,我們試圖利用一條直線(y=ax+b)去擬合二維平面空間中的點,這里我們所使用的這條直線,就是我們提出的基本模型。而在后續的深度學習的學習過程中,我們還將看到更為強大、同時也更加通用的神經網絡模型。當然,不同的模型能夠適用不同的場景,在提出模型時,我們往往會預設一些影響模型結構或者實際判別性能的參數,如簡單線性回歸中的a和b;
- Step 2:確定損失函數和目標函數
- 接下來,圍繞建模的目標,我們需要合理設置損失函數,并在此基礎之上設置目標函數,當然,在很多情況下,這二者是相同的。例如,在上述簡單線性回歸中,我們的建模目標就是希望y=ax+b這條直線能夠盡可能的擬合(1,2)、(3,4)這兩個點,或者說盡可能“穿過”這兩個點,因此我們設置了SSE作為損失函數,也就是預測值和真實值的差值平方和。當然,在計算過程中不難發現,SSE是一個包含了a和b這兩個變量的方程,因此SSE本身也是一個函數(a和b的二元函數),并且在線性回歸中,SSE既是損失函數(用于衡量真實值和預測值差值的函數),同時也是我們的目標函數(接下來需要優化、或者說要求最小值的函數)。這里尤其需要注意的是,損失函數不是模型,而是模型參數所組成的一個函數。
- Step 3:根據目標函數特性,選擇優化方法,求解目標函數
- 之前提到,目標函數既承載了我們優化的目標(讓預測值和真實值盡可能接近),同時也是包含了模型參數的函數,因此完成建模需要確定參數、優化結果需要預測值盡可能接近真實值這兩方面需求就統一到了求解目標函數最小值的過程中了,也就是說,當我們圍繞目標函數求解最小值時,也就完成了模型參數的求解。當然,這個過程本質上就是一個數學的最優化過程,求解目標函數最小值本質上也就是一個最優化問題,而要解決這個問題,我們就需要靈活適用一些最優化方法。當然,在具體的最優化方法的選擇上,函數本身的性質是重要影響因素,也就是說,不同類型、不同性質的函數會影響優化方法的選擇。在簡單線性回歸中,由于目標函數是凸函數,我們根據凸函數性質,判斷偏導函數取值為0的點就是最小值點,進而完成a、b的計算(也就是最小二乘法),其實就是通過函數本身的性質進行最優化方法的選取。
二、第一個優化算法:最小二乘法
??前面提到,利用優化方法求解目標函數其實是機器學習建模過程中最為核心的環節,因此,我們有必要將圍繞上述簡單線性回歸問題,進一步討論最小二乘法背后的數學邏輯和優化思想,同時簡單探討數據的矩陣表示方法和基本矩陣運算。雖然最小二乘法并不是主流的深度學習損失函數的優化算法,但從最小二乘法入手了解優化算法背后的數學邏輯,卻是非常有必要,同時,線性方程也是構建神經網絡模型的基礎,因此,我們有必要深入探討線性模型建模細節以及最基本的優化算法:最小二乘法。
1.最小二乘法的代數表示方法
??從更加嚴格的數學角度出發,最小二乘法有兩種表示形式,分別是代數法表示和矩陣表示。我們先看最小二乘法的代數表示方法。
首先,假設多元線性方程有如下形式
?令𝑤=(𝑤1,𝑤2,...𝑤𝑑),𝑥=(𝑥1,𝑥2,...𝑥𝑑),則上式可寫為
在機器學習領域,我們將線性回歸自變量系數命名為w,其實是weight的簡寫,意為自變量的權重。
多元線性回歸的最小二乘法的代數法表示較為復雜,此處先考慮簡單線性回歸的最小二乘法表示形式。在簡單線性回歸中,w只包含一個分量,x也只包含一個分量,我們令此時的𝑥𝑖就是對應的自變量的取值,此時求解過程如下
優化目標可寫為
通過偏導為0求得最終結果的最小二乘法求解過程為:
?進而可得
其中,(𝑥𝑖,𝑦𝑖)代表二維空間中的點。針對二維空間內的(1,2)和(3,4)兩個點,我們可以使用torch中運算函數手動計算w和b,本部分留作練習,用于同學們課后復習對此前學習的張量基本運算相關知識。
2.最小二乘法的矩陣表示形式
??從《Lesson 4》的矩陣部分內容不難理解,對于線性方程組來說,矩陣表示是一種更加簡潔的表示方式,并且對于支持數組運算的torch來說,線性方程組的矩陣表示也更貼近代碼的實際書寫形式。首先先回顧《Lesson 4》中提到的將上述方程轉化為矩陣的過程。線性方程如下
?在轉化為矩陣表示的過程中,我們令
則原方程組可表示為?
?更為一般的情況下,多元線性回歸方程為
?令
- 𝑤? :方程系數所組成的向量,并且我們將自變量系數和截距放到了一個向量中,此處𝑤??就相當于前例中的a、b組成的向量(a,b);
- 𝑥? :方程自變量和1共同組成的向量;
因此,方程可表示為
另外,我們將所有自變量的值放在一個矩陣中,并且和此前A矩陣類似,為了捕捉截距,添加一列全為1的列在矩陣的末尾,設總共有m組取值,則
對應到前例中的A矩陣,A矩陣就是擁有一個自變量、兩個取值的X矩陣。令y為因變量的取值,則有
此時,SSE可表示為:
根據最小二乘法的求解過程,令𝐸(𝑤??)對𝑤? 求導方程取值為0,有
進一步可得?
要使得此式有解,等價于𝑋^𝑇𝑋(也被稱為矩陣的交叉乘積crossprod存在逆矩陣,若存在,則可解出?
3.最小二乘法的簡單實現
回到最初的例子,不難發現,有如下對應關系:
手動實現代碼驗證最小二乘法?
X = A X #tensor([[1., 1.], # [3., 1.]])y = B y #tensor([[2.], # [4.]])X.t() #tensor([[1., 3.], # [1., 1.]])w = torch.mm(torch.mm(torch.inverse(torch.mm(X.t(),X)),X.t()),y) w #tensor([[1.0000], # [1.0000]])和此前結果保持一致。當然,最小二乘法作為最優化問題的求解方法,我們可以這么理解w最終取值:當w取值為(1,1)時,自變量為w的SSE函數取得全域最小值。
當然,我們也可以直接調用最小二乘法函數torch.lstsq(B, A)進行求解
torch.lstsq(y, X) #先輸入y再輸入x #torch.return_types.lstsq( #solution=tensor([[1.0000], # [1.0000]]), #QR=tensor([[-3.1623, -1.2649], # [ 0.7208, -0.6325]]))對于lstsq函數來說,第一個參數是因變量張量,第二個參數是自變量張量,并且同時返回結果還包括QR矩陣分解的結果,QR分解也是一種矩陣分解方法,后續在涉及到QR分解內容時會詳細進行講解。
另外,在最小二乘法數學推導過程,涉及到矩陣范數的運算,在PyTorch中,我們使用linalg.norm函數求向量或矩陣的范數
注意,老版本教材會推薦使用norm函數進行求解,但實際上新版pytorch已經開始推薦使用linalg.norm替換norm進行范數運算,因此更推薦使用linalg.norm函數
t = torch.tensor([-1, 2.]) t #tensor([-1., 2.])# 默認情況,求解L2范數,個元素的平方和開平方 torch.linalg.norm(t) #tensor(2.2361)torch.sqrt(torch.tensor(5.)) #tensor(2.2361)# 輸入參數,求解L1范數,個元素的絕對值之和 torch.linalg.norm(t, 1) tensor(3.)#4.反向驗證導數為零
??當然,我們也可以反向驗證,看下損失函數SSE在a=1,b=1時偏導數是否都為0。此時就需要借助PyTorch中的autograd模塊來進行偏導計算。嚴格意義上來講,autograd模塊是PyTorch中的自動微分模塊,我們可以通過autograd模塊中的函數進行微分運算,在神經網絡模型中,通過自動微分運算求解梯度是模型優化的核心。關于微分計算梯度進而執行優化的相關方法我們會在后續逐步介紹,此處我們僅適用autograd模塊來進行簡單的微分計算嘗試,也就是對SSE進行偏導計算,判斷a、b同時取值為1時偏導是否為0。
??對于目前我們所適用的PyTorch 1.7.1版本來說,我們可以直接在張量Tensor中進行微分運算。目前市面上流通的PyTorch教材有些會介紹Variable類,在進行微分運算時需提前將Tensor類轉化為Variable類,但其實在PyTorch 0.4版本以后Tensor就已經不僅僅是一個純計算的載體,而是可以支持微分運算,Variable的概念被逐漸弱化,可微分性也變成了Tensor的一個基本屬性,我們只需要在創建Tensor時,通過設置requires_grad屬性為True、規定張量可微分即可。
a = torch.tensor(1.,requires_grad = True) a #tensor(1., requires_grad=True) '''此時a就是一個可微分的張量,requires_grad是a的一個屬性,可以查看可以修改。'''# 查看可微分性 a.requires_grad #True# 修改可微分性 a.requires_grad = False a.requires_grad #Falsea.requires_grad = Trueb = torch.tensor(1.,requires_grad = True) b #tensor(1., requires_grad=True)然后創建損失函數
sse = torch.pow((2 - a - b), 2) + torch.pow((4 - 3 * a - b), 2) '''使用torch.autograd.grad進行偏導運算,并輸出a=1、b=1時偏導數的值'''torch.autograd.grad(sse,[a, b]) #(tensor(-0.), tensor(-0.))至此,也可驗證(1,1)是損失函數的最小值點。
- torch.autograd.grad函數
torch.autograd.grad是通用微分函數,當只輸入一個自變量時計算結果就是導數,輸入多個自變量時則會計算偏導數。
總結
以上是生活随笔為你收集整理的Lesson 5.基本优化思想与最小二乘法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Lesson 4.张量的线性代数运算
- 下一篇: Lesson 6.动态计算图与梯度下降入