前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >零基础学习梯度下降算法

零基础学习梯度下降算法

作者头像
老齐
发布2020-08-28 14:41:51
3240
发布2020-08-28 14:41:51
举报
文章被收录于专栏:老齐教室老齐教室

零基础学习梯度下降算法

作者:Philipp Muens

翻译:老齐

与本文相关的图书推荐:《数据准备和特征工程》

梯度下降法是机器学习中最基本的优化技术之一。那么,什么是梯度? 下降的是什么?我们要优化的是什么?

这些可能是第一次接触梯度下降时想到的一些问题,本文就从零基础开始实现梯度下降,并在过程中回答这些问题。

优化和损失函数

许多机器学习问题需要某种形式的优化。通常,算法首先对正确答案进行初步猜测,然后慢慢地调整参数,使其在每次预测检验中的误差变小。

这个学习过程反复进行,直到算法学会了“正确地”预测到结果为止。

为了弄清楚算法在预测上的误差,我们需要定义一个损失函数的概念。损失函数将猜测值与实际值进行比较,并将两者之间的差异转化为一种度量标准,我们可以用它来量化算法的质量。重要的损失函数包括均方误差(MSE)、均方根误差(RMSE)或平方误差和(SSE)。

想象这样一种情境:将算法所造成的误差放到一个平面上,然后找到误差最少的地方,这正是梯度下降发挥作用的地方。在梯度下降的情况下,我们遍历这个表面,以便找到这样一个地方。

梯度下降

我们已经发现,在处理机器学习问题时,损失函数和优化通常是相互交织的。虽然把它们放在一起学习很有意义,但我个人认为:在探索核心思想时,更有价值的做法是保持简单和专注。因此,接下来,我们只专注于把梯度下降作为一种数学优化技术。这种技术可以应用于各种不同的领域(包括机器学习问题)。

抛物面

代码语言:javascript
复制
def paraboloid(x: float, y: float) -> float:
    return x ** 2 + y ** 2

很简单。接下来,我们应该生成一些测试数据,将其传到抛物面函数中,并绘制结果,看看是否一切都如预期的那样:

代码语言:javascript
复制
# Test data generation (only really necessary for the plotting below)
xs_start = ys_start = -10
xs_stop = ys_stop = 11
xs_step = ys_step = 1

xs: List[float] = [i for i in range(xs_start, xs_stop, xs_step)]
ys: List[float] = [i for i in range(ys_start, ys_stop, ys_step)]
zs: List[List[float]] = []

for x in xs:
    temp_res: List[float] = []
    for y in ys:
        result: float = paraboloid(x, y)
        temp_res.append(result)
    zs.append(temp_res)

print(f'xs: {xs}\n')
# xs: [-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

print(f'ys: {ys}\n')
# ys: [-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

print(f'zs: {zs[:5]} ...\n')
# zs: [[200, 181, 164, 149, 136, 125, 116, 109, 104, 101, 100, 101, 104, 109, 116, 125, 136, 149, 164, 181, 200], [181, 162, 145, 130, 117, 106, 97, 90, 85, 82, 81, 82, 85, 90, 97, 106, 117, 130, 145, 162, 181], [164, 145, 128, 113, 100, 89, 80, 73, 68, 65, 64, 65, 68, 73, 80, 89, 100, 113, 128, 145, 164], [149, 130, 113, 98, 85, 74, 65, 58, 53, 50, 49, 50, 53, 58, 65, 74, 85, 98, 113, 130, 149], [136, 117, 100, 85, 72, 61, 52, 45, 40, 37, 36, 37, 40, 45, 52, 61, 72, 85, 100, 117, 136]] ...

可以使用以下代码来绘制图形(使用Plotly库):

代码语言:javascript
复制
fig = go.Figure(go.Surface(x=xs, y=ys, z=zs, colorscale='Viridis'))
fig.show()

梯度和导数

代码语言:javascript
复制
def compute_gradient(vec: List[float]) -> List[float]:
    assert len(vec) == 2
    x: float = vec[0]
    y: float = vec[1]
    return [2 * x, 2 * y]

梯度下降

代码语言:javascript
复制
def compute_step(curr_pos: List[float], learning_rate: float) -> List[float]:
    grad: List[float] = compute_gradient(curr_pos)
    grad[0] *= -learning_rate
    grad[1] *= -learning_rate
    next_pos: List[float] = [0, 0]
    next_pos[0] = curr_pos[0] + grad[0]
    next_pos[1] = curr_pos[1] + grad[1]
    return next_pos

代码语言:javascript
复制
start_pos: List[float]

# Ensure that we don't start at a minimum (0, 0 in our case)
while True:
    start_x: float = randint(xs_start, xs_stop)
    start_y: float = randint(ys_start, ys_stop)
    if start_x != 0 and start_y != 0:
        start_pos = [start_x, start_y]
        break

print(start_pos)
# [6, -3]

最后,我们将compute_step函数封装到一个循环中,以迭代方式遍历表面,最终达到局部最小值:

代码语言:javascript
复制
epochs: int = 5000
learning_rate: float = 0.001
    
best_pos: List[float] = start_pos

for i in range(0, epochs):
    next_pos: List[float] = compute_step(best_pos, learning_rate)
    if i % 500 == 0:
        print(f'Epoch {i}: {next_pos}')
    best_pos = next_pos    

print(f'Best guess for a minimum: {best_pos}')

# Epoch 0: [5.988, -2.994]
# Epoch 500: [2.2006573940846716, -1.1003286970423358]
# Epoch 1000: [0.8087663604107433, -0.4043831802053717]
# Epoch 1500: [0.2972307400008091, -0.14861537000040456]
# Epoch 2000: [0.10923564223981955, -0.054617821119909774]
# Epoch 2500: [0.04014532795468376, -0.02007266397734188]
# Epoch 3000: [0.014753859853277982, -0.007376929926638991]
# Epoch 3500: [0.005422209548664845, -0.0027111047743324226]
# Epoch 4000: [0.0019927230353282872, -0.0009963615176641436]
# Epoch 4500: [0.0007323481432962652, -0.0003661740716481326]
# Best guess for a minimum: [0.00026968555624761565, -0.00013484277812380783]

大功告成了。我们已经成功地实现了从零基础开始的梯度下降算法!

结论

原文链接:https://philippmuens.com/gradient-descent-from-scratch/

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-08-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 老齐教室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 零基础学习梯度下降算法
    • 优化和损失函数
      • 梯度下降
        • 抛物面
      • 梯度和导数
        • 梯度下降
      • 结论
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档