天天看點

LR_GD_MSE (公式補充)

對上篇線性模型中涉及的 梯度計算 代碼進行數學原理推導

上篇是先撸了一把梯度下降的代碼, 用來優先 LR 中的 MSE. 核心代碼是在求解梯度這一步.

# y = wx + b
def step_gradient(b_current, w_current, points, lr):
    # 計算誤差函數在所有點的導數, 并更新 w, b 
    b_gradient = 0
    w_gradinet = 0
    n = len(points) # 樣本數
    for i in range(n):
        # x, y 都是一個數值
        x = points[i, 0]
        y = points[i, 1]
        
        b_gradient += (n/2) * ((w_current * x + b) - y)
        w_gradinet += (n/2) * x * ((w_current * x + b) - y)
        
    # 根據梯度下降法, 更新 w, b
    new_w = w_current - (lr * b_gradient)
    new_b = b_current - (lr * b_gradient)
    
    return [new_w, new_b]      

比較困惑可能是在這兩行.

b_gradient += (n/2) * ((w_current * x + b) - y)
w_gradinet += (n/2) * x * ((w_current * x + b) - y)      

本來想着, 算了, 這是最基本的, 但還是給做推導了一下GD, 想着即便是寫 hello, world, 也是很有意義的.

推過過程

LR_GD_MSE (公式補充)
LR_GD_MSE (公式補充)

我是用Pad來寫的, 貼的圖, 湊合着用吧, 能表達清楚大緻意思就行, 原理其實就是, 求導數, 求梯度而已, 也沒啥新的東西, 都是老古董了, 幾百年都沒有變過的.

這樣再來看這兩行代碼, 不就立刻秒懂了嗎.

b_gradient += (n/2) * ((w_current * x + b) - y)
w_gradinet += (n/2) * x * ((w_current * x + b) - y)      

ML 有意思的一點在于, 它跟普通的寫代碼不一樣, 更多的時候, 像是把數學公式, 翻譯為代碼的過程, 這跟代碼邏輯沒有太大關系, 跟數學的基本功有關系. 數學這塊涉及的其實不難, 大部分都在求解多元函數的偏導數, 導數, 條件極值涉及拉格朗日, 函數優化用泰勒展開等, 都是一些高數的基本概念而已, 幾百年來, 都沒有變過, 是死的, 相對于, 寫代碼的業務邏輯, 還是會相對有趣一點, 是以,我也是作為愛好,偶爾寫寫.

最為享受的一點是, 基于數學模型的完整推導下, 用程式設計語言, 來将這個過程或者, 推導出來的結論, 進行代碼化, 然後進行封裝為一個 api, 這樣就完成了閉環, 還是很有趣的一件事情.

其實是關于導包, 當然我現在是在開始學習用架構, 導包, 不同在于, 我是自信的, 都是基于, 對數學原理的了解來導包, 很自信, 萬一, 導包不好使, 就基于數學公式, 自己慢慢撸代碼, 也是能實作的. 反之, 如果不懂數學原理來調包, 那ML則會是變成多麼無聊的事情呢.

小結

  • ML 就3部分: 數學模型 + 損失函數(目标) + 優化求解參數 (code)
  • 梯度是偏導數組成的向量, 向量有大小, 有方向, 衡量大小用模; 導數的本質是衡量 "變化率"
  • 梯度是多元函數, 最大方向導數 的方向, 加個 "-" 反方向, 則是函數增長最小的方向, 即極值點的位置
  • 梯度下降法, 即沿着梯度反方向求極值點時的模型參數, 類似的還有梯度上升法, 在求解SVM會用到.

繼續閱讀