白手起家学习数据科学 ——梯度下降法之“优化步长和随机梯度下降篇”(六)

选择正确的步长(Choosing the Right Step Size)

虽然针对梯度移动的基本原理是清楚的,但是移动多少是不清楚的。的确,选择一个合适的步长是一门艺术。流行的选择包括:

  • 使用固定的步长
  • 随时间逐步缩小步长
  • 在每次迭代,选择最小化目标函数的步长

最后一个听起来是最优的,但是,实际上它是最耗时的。通过尝试几种步长来选择最小化目标函数的步长,近似于最后一种方法:

step_sizes = [100, 10, 1, 0.1, 0.01, 0.001, 0.0001, 0.00001]

可能某个步长对于目标函数会引起无效的输入。我们需要创建一个”safe apply”函数,这个函数对于无效的输入返回无限(infinity):

def safe(f):
    """return a new function that's the same as f,
    except that it outputs infinity whenever f produces an error"""
    def safe_f(*args, **kwargs):
        try:
            return f(*args, **kwargs)
        except:
            return float('inf') # this means "infinity" in Python
    return safe_f

优化步长+梯度下降法(Putting It ALL Together)

一般情况下,我们有想要最小化的目标函数 target_fn,我们也有它的梯度函数gradient_fn。例如,target_fn可能表示一个模型(带参函数)的误差函数,我们想要找到最小化误差函数的参数。

我们选择一个开始值为参数theta_0,然后我们执行梯度下降法:

def minimize_batch(target_fn, gradient_fn, theta_0, tolerance=0.000001):
    """use gradient descent to find theta that minimizes target function"""

    step_sizes = [100, 10, 1, 0.1, 0.01, 0.001, 0.0001, 0.00001]

    theta = theta_0 # set theta to initial value
    target_fn = safe(target_fn) # safe version of target_fn

    while True:
        gradient = gradient_fn(theta)
        next_thetas = [step(theta, gradient, -step_size)
                        for step_size in step_sizes]
        # choose the one that minimizes the error function
        next_theta = min(next_thetas, key=target_fn)
        next_value = target_fn(next_theta)

        # stop if we're "converging"
        if abs(value - next_value) < tolerance:
            return theta
        else:
            theta, value = next_theta, next_value

我们叫它最小化批量(minimize_batch),因为对于每个梯度步骤,它作用于全部的数据集上(target_fn返回的是全部数据集的误差)。后面我们会介绍另外一种方法:在同一时间里只作用于一个数据点。

有时候,代替的我们想要最大化一个函数,我们能通过最小化的负数来实现:

def negate(f):
    """return a function that for any input x returns -f(x)"""
    return lambda *args, **kwargs: -f(*args, **kwargs)

def negate_all(f):
    """the same when f returns a list of numbers"""
    return lambda *args, **kwargs: [-y for y in f(*args, **kwargs)]

    def maximize_batch(target_fn, gradient_fn, theta_0, tolerance=0.000001):
        return minimize_batch(negate(target_fn),
                                negate_all(gradient_fn),
                                theta_0,
                                tolerance)

随机梯度下降

正如我前面所提,我们常常使用梯度下降法选择一个模型的参数来最小化误差函数,使用前面的批量方法,需要我们做预测,计算全部数据集的梯度,这个会让每个步骤非常耗时。

现在使用的误差函数都是相加的,那个意思是在整个数据集上的误差函数其实是每个数据点上预测的误差简单的相加。

这种情况,我们能使用一种叫做随机梯度下降法来计算每个数据点的梯度,循环整个数据直到到达一个停止点。

在这个循环中,我们想要在一个随机顺序中迭代整个数据:

def in_random_order(data):
    """generator that returns the elements of data in random order"""
    indexes = [i for i, _ in enumerate(data)] # create a list of indexes
    random.shuffle(indexes) # shuffle them
    for i in indexes: # return the data in that order
        yield data[i]

我们想要每个数据点移动一小步,这种方法仅有的一种可能是永远的在最小值附近循环,所以不论何时我们停止改进,我们都会减少步长直到最后放弃:

def minimize_stochastic(target_fn, gradient_fn, x, y, theta_0, alpha_0=0.01):

    data = zip(x, y)
    theta = theta_0 # initial guess
    alpha = alpha_0 # initial step size
    min_theta, min_value = None, float("inf") # the minimum so far
    iterations_with_no_improvement = 0

    # if we ever go 100 iterations with no improvement, stop
    while iterations_with_no_improvement < 100:
        value = sum( target_fn(x_i, y_i, theta) for x_i, y_i in data )

        if value < min_value:
            # if we've found a new minimum, remember it
            # and go back to the original step size
            min_theta, min_value = theta, value
            iterations_with_no_improvement = 0
            alpha = alpha_0
        else:
            # otherwise we're not improving, so try shrinking the step size
            iterations_with_no_improvement += 1
            alpha *= 0.9

        # and take a gradient step for each of the data points
        for x_i, y_i in in_random_order(data):
            gradient_i = gradient_fn(x_i, y_i, theta)
            theta = vector_subtract(theta, scalar_multiply(alpha, gradient_i))

    return min_theta

随机版本要比批量版本快很多,当然,我们也想要一个最大化的版本:

def maximize_stochastic(target_fn, gradient_fn, x, y, theta_0, alpha_0=0.01):
    return minimize_stochastic(negate(target_fn),
                                negate_all(gradient_fn),
                                x, y, theta_0, alpha_0)
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值