天天看点

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会用到.

继续阅读