計(jì)算全解析:從L1、L2到矩陣范數(shù)與應(yīng)用實(shí)戰(zhàn))
1. 項(xiàng)目概述為什么我們需要深入理解np.linalg.norm()在數(shù)據(jù)處理、機(jī)器學(xué)習(xí)乃至日常的科學(xué)計(jì)算中我們經(jīng)常需要衡量一個向量或矩陣的“大小”或“長度”。比如在計(jì)算兩個向量的歐氏距離時我們實(shí)際上是在計(jì)算它們差值的“長度”在機(jī)器學(xué)習(xí)中正則化項(xiàng)如L1、L2正則的本質(zhì)就是對模型參數(shù)向量施加某種“大小”的懲罰以防止過擬合。這個衡量“大小”的數(shù)學(xué)工具就是范數(shù)Norm。而np.linalg.norm()正是 NumPy 這個 Python 科學(xué)計(jì)算基石庫中用于計(jì)算各種范數(shù)的核心函數(shù)。它絕不僅僅是一個簡單的“求長度”的函數(shù)。新手可能會用它來計(jì)算向量的模長但老手會用它來評估矩陣的條件數(shù)、計(jì)算兩個樣本的相似度、或者作為優(yōu)化目標(biāo)的一部分。網(wǎng)絡(luò)上關(guān)于它的討論很多從基礎(chǔ)的“怎么用”到進(jìn)階的“為什么我的結(jié)果和預(yù)期不符”再到版本兼容性問題比如熱搜中提到的 numpy 2.x 與 1.x 的兼容性沖突都說明了其基礎(chǔ)性和易錯性。因此僅僅知道np.linalg.norm(x)能算個模長是遠(yuǎn)遠(yuǎn)不夠的。我們需要系統(tǒng)地掌握它的參數(shù)體系、理解不同范數(shù)在幾何和數(shù)學(xué)上的意義、熟知其在多維數(shù)組矩陣上的行為差異并規(guī)避那些常見的“坑”。這篇文章我將結(jié)合自己多年的使用經(jīng)驗(yàn)帶你從內(nèi)部實(shí)現(xiàn)和實(shí)際應(yīng)用兩個角度徹底吃透這個函數(shù)讓你不僅能正確使用它更能理解何時、為何要使用某種特定的范數(shù)。2. 核心概念解析范數(shù)究竟是什么在深入函數(shù)用法之前我們必須先夯實(shí)概念。范數(shù)是一個為向量空間中的向量賦予“長度”的函數(shù)它需要滿足非負(fù)性、齊次性和三角不等式三條公理。對于程序員來說可以直觀地將其理解為一種“度量”。2.1 向量范數(shù)從L1到L∞最常見的向量范數(shù)定義在實(shí)數(shù)域 R^n 上。給定一個向量x [x1, x2, ..., xn]L1范數(shù)曼哈頓距離各分量絕對值的和。||x||1 |x1| |x2| ... |xn|。它在統(tǒng)計(jì)學(xué)和機(jī)器學(xué)習(xí)中對應(yīng)Lasso回歸的正則項(xiàng)具有特征選擇的能力因?yàn)樗牡雀呔€是“菱形”更容易與損失函數(shù)等高線在坐標(biāo)軸上相交使得部分系數(shù)為0。L2范數(shù)歐幾里得距離各分量平方和的平方根。||x||2 sqrt(x1^2 x2^2 ... xn^2)。這是我們最熟悉的“幾何長度”。它對應(yīng)**嶺回歸Ridge Regression**的正則項(xiàng)其等高線是“圓形”傾向于讓所有系數(shù)均勻地縮小。L∞范數(shù)切比雪夫距離所有分量絕對值的最大值。||x||∞ max(|x1|, |x2|, ..., |xn|)。它衡量的是向量分量中的最大偏差在控制最大誤差的場景下很有用例如在游戲AI中衡量單位到達(dá)目標(biāo)所需的最大單步距離。注意np.linalg.norm()的ord參數(shù)就是用來指定這些范數(shù)類型的。對于向量ord1對應(yīng)L1ord2對應(yīng)L2ordnp.inf對應(yīng)L∞。2.2 矩陣范數(shù)不僅僅是向量的推廣當(dāng)輸入x是一個二維數(shù)組矩陣時np.linalg.norm()的行為就變得豐富起來。矩陣范數(shù)可以看作是向量范數(shù)的一種誘導(dǎo)它衡量的是矩陣作為線性變換的“放大”能力。Frobenius范數(shù)F范數(shù)將矩陣展平為向量后求其L2范數(shù)。||A||_F sqrt(ΣΣ |a_ij|^2)。這是最常用的矩陣范數(shù)在np.linalg.norm()中通過ordfro指定。它本質(zhì)上衡量了矩陣所有元素的“能量”。核范數(shù)Nuclear Norm矩陣奇異值之和。它常用于矩陣補(bǔ)全如推薦系統(tǒng)和低秩矩陣恢復(fù)問題是矩陣秩的凸松弛。在np.linalg.norm()中通過ordnuc指定。誘導(dǎo)范數(shù)Induced Norm例如ord1列和范數(shù)、ord2譜范數(shù)即最大奇異值、ordnp.inf行和范數(shù)。這些范數(shù)有明確的幾何意義||A||_2表示矩陣A能將一個單位球在L2范數(shù)下映射成的橢球的最長軸長度。理解這些區(qū)別至關(guān)重要。例如計(jì)算兩個矩陣的差異時如果你關(guān)心的是所有元素整體的誤差用F范數(shù)如果你關(guān)心的是矩陣作為變換算子時的最大放大倍數(shù)用譜范數(shù)ord2。3.np.linalg.norm()參數(shù)全解與實(shí)戰(zhàn)演示函數(shù)簽名通常為np.linalg.norm(x, ordNone, axisNone, keepdimsFalse)。我們來逐一拆解并配上代碼示例。3.1 核心參數(shù)ord范數(shù)類型的選擇器ord參數(shù)是函數(shù)的靈魂它決定了計(jì)算何種范數(shù)。其取值與輸入x的維度緊密相關(guān)。1. 向量范數(shù) (x為一維數(shù)組)import numpy as np vec np.array([1, -2, 3]) # L1范數(shù)|1| |-2| |3| 6 print(np.linalg.norm(vec, ord1)) # 輸出6.0 # L2范數(shù)sqrt(1^2 (-2)^2 3^2) sqrt(14) ≈ 3.74165738677 print(np.linalg.norm(vec, ord2)) # 默認(rèn)值 ordNone 時也返回L2范數(shù) print(np.linalg.norm(vec)) # 輸出3.7416573867739413 # L∞范數(shù)max(|1|, |-2|, |3|) 3 print(np.linalg.norm(vec, ordnp.inf)) # 輸出3.0 # 其他整數(shù)p計(jì)算Lp范數(shù)例如 p3 print(np.linalg.norm(vec, ord3)) # (|1|^3 |-2|^3 |3|^3)^(1/3) ≈ 2.884499140612. 矩陣范數(shù) (x為二維數(shù)組)mat np.array([[1, 2], [3, 4]]) # Frobenius范數(shù)sqrt(1^22^23^24^2) sqrt(30) ≈ 5.477 print(np.linalg.norm(mat, ordfro)) # 輸出5.477225575051661 # 核范數(shù)奇異值之和mat的奇異值約為 [5.4649857, 0.36596619]和約為 5.83095189 print(np.linalg.norm(mat, ordnuc)) # 輸出5.830951894845301 # 誘導(dǎo)范數(shù) # ord1: 列和范數(shù)各列絕對值之和的最大值 max(|1||3|, |2||4|) max(4,6) 6 print(np.linalg.norm(mat, ord1)) # 輸出6.0 # ord2: 譜范數(shù)最大奇異值約為 5.4649857 print(np.linalg.norm(mat, ord2)) # 輸出5.464985704219043 # ordnp.inf: 行和范數(shù)各行絕對值之和的最大值 max(|1||2|, |3||4|) max(3,7) 7 print(np.linalg.norm(mat, ordnp.inf)) # 輸出7.0實(shí)操心得對于矩陣ord2譜范數(shù)的計(jì)算開銷是最大的因?yàn)樗枰?jì)算奇異值分解SVD。如果你的矩陣很大且只需要一個近似的“大小”度量F范數(shù)通常是更快、更穩(wěn)定的選擇。3.2 軸向計(jì)算axis與保持維度keepdims這是np.linalg.norm()功能強(qiáng)大的另一個體現(xiàn)它允許你沿著數(shù)組的特定軸計(jì)算范數(shù)這對于批處理操作特別有用。# 創(chuàng)建一個 3x4 的矩陣 X np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) # 1. 默認(rèn)axisNone將整個數(shù)組展平計(jì)算一個總的范數(shù) print(np.linalg.norm(X)) # 計(jì)算所有元素的L2范數(shù) # 2. axis0沿著第0軸行方向壓縮對每一列計(jì)算范數(shù)結(jié)果形狀為 (4,) # 即計(jì)算 [sqrt(1^25^29^2), sqrt(2^26^210^2), ...] col_norms np.linalg.norm(X, axis0) print(col_norms) # 輸出[10.34408043 11.83215957 13.37908816 14.96662955] print(col_norms.shape) # (4,) # 3. axis1沿著第1軸列方向壓縮對每一行計(jì)算范數(shù)結(jié)果形狀為 (3,) # 即計(jì)算 [sqrt(1^22^23^24^2), sqrt(5^26^27^28^2), ...] row_norms np.linalg.norm(X, axis1) print(row_norms) # 輸出[ 5.47722558 13.19090596 22.44994432] print(row_norms.shape) # (3,) # 4. keepdimsTrue保持原始維度這在后續(xù)的廣播運(yùn)算中非常關(guān)鍵 row_norms_keep np.linalg.norm(X, axis1, keepdimsTrue) print(row_norms_keep) # 輸出 # [[ 5.47722558] # [13.19090596] # [22.44994432]] print(row_norms_keep.shape) # (3, 1) # 應(yīng)用對X的每一行進(jìn)行L2歸一化使每行向量的L2范數(shù)為1 # 如果沒有 keepdims row_norms 形狀是(3,)無法直接與X(3,4)做除法需要廣播維度對齊 # 有了 keepdimsTrue row_norms_keep 形狀是(3,1)可以完美廣播到每一行的4個元素上 X_normalized X / row_norms_keep print(X_normalized) # 驗(yàn)證每一行的范數(shù)是否為1 print(np.linalg.norm(X_normalized, axis1)) # 輸出[1. 1. 1.]axis參數(shù)對于高維數(shù)組如批量圖像數(shù)據(jù)同樣有效# 假設(shè)有一批batch10張 32x32 的RGB圖像數(shù)據(jù)形狀為 (10, 32, 32, 3) # 我們想計(jì)算每張圖像所有像素的L2范數(shù)即整張圖的“能量” batch_data np.random.randn(10, 32, 32, 3) # 指定 axis(1,2,3)即在高度、寬度、通道這三個維度上計(jì)算范數(shù)壓縮掉它們 image_norms np.linalg.norm(batch_data, axis(1, 2, 3)) print(image_norms.shape) # 輸出(10,)得到了10個標(biāo)量每個代表一張圖的范數(shù)注意事項(xiàng)axis可以是一個整數(shù)元組用于指定多個要壓縮的軸。keepdims是一個容易被忽略但極其有用的參數(shù)特別是在涉及后續(xù)矩陣運(yùn)算時它能避免很多維度不匹配的錯誤。養(yǎng)成使用keepdimsTrue的習(xí)慣能讓你的代碼更健壯。3.3 默認(rèn)行為與常見陷阱默認(rèn)ordNone對于向量返回L2范數(shù)對于矩陣返回Frobenius范數(shù)。這是一個“安全”但需要你心里有數(shù)的默認(rèn)值。如果你在處理矩陣但心里想的是譜范數(shù)用默認(rèn)值就會得到錯誤的結(jié)果。默認(rèn)axisNone計(jì)算整個數(shù)組的范數(shù)。默認(rèn)keepdimsFalse壓縮計(jì)算范數(shù)的維度。如上所述這常常是后續(xù)運(yùn)算出錯的根源。陷阱示例版本兼容性與數(shù)據(jù)類型熱搜詞中提到了AttributeError: module numpy has no attribute arange和版本沖突問題。雖然這不直接是norm的問題但 NumPy 版本升級如從 1.x 到 2.x可能帶來細(xì)微的變化。np.linalg.norm()本身是穩(wěn)定的但需注意確保你的 NumPy 是正確安裝的版本避免因環(huán)境混亂導(dǎo)致的linalg子模塊缺失。對于整數(shù)數(shù)組計(jì)算范數(shù)時會自動轉(zhuǎn)換為浮點(diǎn)數(shù)float64以避免溢出。但如果你手動指定了dtype或使用了自定義數(shù)據(jù)類型需要留意精度問題。# 整數(shù)數(shù)組計(jì)算范數(shù) int_arr np.array([1, 2, 3], dtypenp.int32) norm_result np.linalg.norm(int_arr) print(norm_result, norm_result.dtype) # 3.7416573867739413 float64 # 函數(shù)內(nèi)部已處理了類型提升4. 高級應(yīng)用與性能優(yōu)化掌握了基礎(chǔ)用法我們來看看如何在實(shí)際項(xiàng)目中高級、高效地使用它。4.1 計(jì)算歐氏距離與余弦相似度這是機(jī)器學(xué)習(xí)中最常見的應(yīng)用之一。批量計(jì)算歐氏距離 計(jì)算一個查詢向量q與一組向量V每行一個向量之間的歐氏距離。最直接的方法是使用廣播和np.linalg.norm(..., axis1)。def batch_euclidean_distance(q, V): 計(jì)算向量q與向量集V中每個向量的歐氏距離。 參數(shù) q: 形狀為 (d,) 的查詢向量 V: 形狀為 (n, d) 的向量集 返回 distances: 形狀為 (n,) 的距離數(shù)組 # 利用廣播計(jì)算差值。V - q 會將q廣播到V的每一行 differences V - q # 沿 axis1 計(jì)算每一行差值的L2范數(shù) distances np.linalg.norm(differences, axis1) return distances # 示例 V np.random.randn(100, 50) # 100個50維向量 q np.random.randn(50) dists batch_euclidean_distance(q, V) print(dists.shape) # (100,)計(jì)算余弦相似度 余弦相似度 向量點(diǎn)積 / (向量A的L2范數(shù) * 向量B的L2范數(shù))。np.linalg.norm在這里用于計(jì)算分母。def cosine_similarity(A, B): 計(jì)算兩個向量或兩批向量間的余弦相似度。 參數(shù) A, B: 形狀相同的數(shù)組。如果是一維則為單向量二維則為批處理。 返回 相似度標(biāo)量或數(shù)組。 # 點(diǎn)積。對于一維向量是標(biāo)量對于二維矩陣是逐行點(diǎn)積需指定axis。 dot_product np.dot(A, B) if A.ndim 1 else np.sum(A * B, axis1) # 計(jì)算L2范數(shù) norm_A np.linalg.norm(A, axisA.ndim-1) # 對于一維axisNone二維axis1 norm_B np.linalg.norm(B, axisB.ndim-1) # 避免除零錯誤 similarity dot_product / (norm_A * norm_B 1e-8) return similarity vec1 np.array([1, 2, 3]) vec2 np.array([4, 5, 6]) print(cosine_similarity(vec1, vec2)) # 約 0.97463184.2 正則化與歸一化L2正則化權(quán)重衰減的實(shí)現(xiàn) 在訓(xùn)練神經(jīng)網(wǎng)絡(luò)時L2正則化項(xiàng)是所有權(quán)重參數(shù)的L2范數(shù)平方和的一半乘以系數(shù) lambda。def l2_regularization_loss(model_weights, lambda_reg): 計(jì)算模型權(quán)重的L2正則化損失。 model_weights: 一個包含所有權(quán)重矩陣/向量的列表或字典。 l2_norm_squared 0.0 for param in model_weights.values(): # 計(jì)算每個參數(shù)矩陣的Frobenius范數(shù)的平方等價于所有元素的平方和 l2_norm_squared np.linalg.norm(param, ordfro) ** 2 reg_loss 0.5 * lambda_reg * l2_norm_squared return reg_loss數(shù)據(jù)標(biāo)準(zhǔn)化Standardization與歸一化NormalizationZ-score標(biāo)準(zhǔn)化使數(shù)據(jù)均值為0標(biāo)準(zhǔn)差為1。這個過程不直接使用范數(shù)但思想相關(guān)。L2歸一化向量單位化使向量的L2范數(shù)變?yōu)?。這正是我們前面keepdims示例所做的。這在文本處理TF-IDF向量、特征工程中非常常見可以消除向量長度對相似度計(jì)算的影響。4.3 性能考量與替代方案對于超大規(guī)模數(shù)據(jù)或?qū)π阅苡袠O致要求的場景直接使用np.linalg.norm可能不是最快的。僅需平方和時如果你后續(xù)只需要范數(shù)的平方例如計(jì)算L2損失直接使用np.sum(x**2)或np.dot(x, x)會更快因?yàn)樗苊饬碎_方運(yùn)算。x np.random.randn(1000) # 方法1求L2范數(shù)再平方 norm_sq_1 np.linalg.norm(x) ** 2 # 方法2直接計(jì)算點(diǎn)積更快 norm_sq_2 np.dot(x, x) # 方法3使用元素運(yùn)算對于大數(shù)組可能稍慢于dot norm_sq_3 np.sum(x**2)SciPy的scipy.linalg.norm對于某些特殊的矩陣范數(shù)SciPy的實(shí)現(xiàn)可能更優(yōu)化或提供更多選項(xiàng)。但絕大多數(shù)情況下NumPy的實(shí)現(xiàn)已經(jīng)足夠高效。自定義Cython/NumPy C-API僅在性能瓶頸被明確識別且上述方法都無法滿足時考慮。99%的場景用不到。5. 常見問題排查與深度避坑指南即使理解了原理在實(shí)際編碼中還是會遇到各種問題。下面是我踩過的一些坑和解決方案。5.1 維度錯誤與axis誤解問題ValueError: Invalid axis parameter (2) for array of dimension 2mat np.random.randn(5, 10) # 錯誤試圖在一個2維矩陣上指定 axis2 # wrong_norm np.linalg.norm(mat, axis2)原因與解決axis參數(shù)的值必須小于數(shù)組的維數(shù)ndim。對于2維矩陣axis只能是0或1或None或(0,1)元組。高維數(shù)組時要清楚每個軸的意義。畫個草圖或打印array.shape來確認(rèn)維度。5.2 復(fù)數(shù)數(shù)組的范數(shù)計(jì)算np.linalg.norm()完美支持復(fù)數(shù)。對于復(fù)數(shù)向量z其L2范數(shù)定義為sqrt(real(z)^2 imag(z)^2)這等價于sqrt(np.vdot(z, z))其中vdot會計(jì)算共軛點(diǎn)積。函數(shù)內(nèi)部已經(jīng)處理好了這一切。z np.array([12j, 3-4j]) norm_z np.linalg.norm(z) print(norm_z) # 計(jì)算 sqrt(|12j|^2 |3-4j|^2) sqrt(5 25) sqrt(30) ≈ 5.477 print(np.sqrt(np.vdot(z, z))) # 相同結(jié)果5.3 數(shù)值穩(wěn)定性問題當(dāng)向量的值非常大或非常小時直接計(jì)算平方和可能溢出或下溢。雖然np.linalg.norm()內(nèi)部有一些穩(wěn)定性處理例如使用標(biāo)量縮放但在極端情況下仍需注意。 一種更穩(wěn)定的手動計(jì)算L2范數(shù)的方法是def stable_norm(x): max_val np.max(np.abs(x)) if max_val 0: return 0.0 # 先縮放避免大數(shù)平方溢出 scaled_x x / max_val return max_val * np.linalg.norm(scaled_x)對于大多數(shù)應(yīng)用直接使用np.linalg.norm()即可無需擔(dān)心。5.4 與torch.norm和tf.norm的異同如果你也使用 PyTorch 或 TensorFlow了解它們的對應(yīng)函數(shù)有助于代碼遷移。特性np.linalg.normtorch.normtf.norm(TensorFlow)核心函數(shù)np.linalg.norm(x, ord, axis)torch.norm(x, p, dim)tf.norm(tensor, ord, axis)默認(rèn)范數(shù)向量L2矩陣Frop2(L2)ordeuclidean(L2)軸參數(shù)axisdimaxis保持維度keepdimskeepdimkeepdims矩陣核范數(shù)ordnucpnucordnuclear復(fù)數(shù)支持是是是遷移注意PyTorch 的dim參數(shù)和 NumPy 的axis語義相同。TensorFlow 的tf.norm在早期版本中可能對某些ord參數(shù)支持不全使用時需查證對應(yīng)版本文檔。5.5 理解“范數(shù)”與“標(biāo)準(zhǔn)化層”的區(qū)別熱搜詞中出現(xiàn)了 “batch norm 和layer norm”這里要特別區(qū)分一下。np.linalg.norm()計(jì)算的是一個數(shù)學(xué)上的范數(shù)是一個將向量/矩陣映射到非負(fù)實(shí)數(shù)的函數(shù)用于衡量“大小”。BatchNorm/LayerNorm是深度學(xué)習(xí)中的標(biāo)準(zhǔn)化技術(shù)。它們雖然名字里有“norm”但做的是“規(guī)范化”操作減去均值除以標(biāo)準(zhǔn)差或類似統(tǒng)計(jì)量目的是穩(wěn)定網(wǎng)絡(luò)訓(xùn)練、加速收斂。它們不計(jì)算我們這里討論的數(shù)學(xué)范數(shù)。簡單說np.linalg.norm(x)輸出一個標(biāo)量代表x的大小而torch.nn.LayerNorm(x)輸出一個與x同形的張量每個位置被規(guī)范化了。6. 綜合案例實(shí)現(xiàn)一個簡單的KNN分類器讓我們用一個完整的例子串聯(lián)np.linalg.norm()在距離計(jì)算和向量歸一化中的應(yīng)用。import numpy as np from collections import Counter class SimpleKNN: def __init__(self, k3, normalizeFalse): self.k k self.normalize normalize # 是否對特征進(jìn)行L2歸一化 self.X_train None self.y_train None def fit(self, X, y): 存儲訓(xùn)練數(shù)據(jù)可選進(jìn)行歸一化。 if self.normalize: # 對每個樣本行進(jìn)行L2歸一化 norms np.linalg.norm(X, axis1, keepdimsTrue) self.X_train X / (norms 1e-8) # 防止除零 else: self.X_train X self.y_train y def predict(self, X): 預(yù)測新樣本的類別。 if self.X_train is None: raise ValueError(Model must be fitted before prediction.) if self.normalize: norms np.linalg.norm(X, axis1, keepdimsTrue) X X / (norms 1e-8) predictions [] for x in X: # 對于每個待預(yù)測樣本 # 1. 計(jì)算與所有訓(xùn)練樣本的歐氏距離 distances np.linalg.norm(self.X_train - x, axis1) # 2. 獲取最近的k個鄰居的索引 k_indices np.argpartition(distances, self.k)[:self.k] # 3. 獲取這k個鄰居的標(biāo)簽 k_nearest_labels self.y_train[k_indices] # 4. 投票決定預(yù)測類別 most_common Counter(k_nearest_labels).most_common(1) predictions.append(most_common[0][0]) return np.array(predictions) # 示例使用 if __name__ __main__: # 構(gòu)造簡單數(shù)據(jù) X_train np.array([[1, 2], [2, 3], [3, 1], [5, 4], [6, 5], [7, 7]]) y_train np.array([0, 0, 0, 1, 1, 1]) # 兩類 X_test np.array([[2.5, 2], [6, 6]]) # 不歸一化 knn_raw SimpleKNN(k2) knn_raw.fit(X_train, y_train) pred_raw knn_raw.predict(X_test) print(Predictions without normalization:, pred_raw) # 可能為 [0, 1] # 使用L2歸一化 (當(dāng)特征尺度差異大時歸一化很重要) knn_norm SimpleKNN(k2, normalizeTrue) knn_norm.fit(X_train, y_train) pred_norm knn_norm.predict(X_test) print(Predictions with L2 normalization:, pred_norm)在這個案例中np.linalg.norm被用于兩個關(guān)鍵步驟fit階段如果開啟歸一化則對每個訓(xùn)練樣本計(jì)算L2范數(shù)并除以其值使所有樣本向量長度為1。predict階段計(jì)算測試樣本與所有訓(xùn)練樣本的歐氏距離差向量的L2范數(shù)。通過這個例子你可以看到范數(shù)計(jì)算是如何嵌入到一個實(shí)際的機(jī)器學(xué)習(xí)算法核心邏輯中的。理解并熟練運(yùn)用np.linalg.norm()能讓你更自如地實(shí)現(xiàn)和調(diào)試各種涉及距離、相似度和正則化的算法。