梯度下降Gradient descent

来源:互联网 发布:突袭2 mac版本 编辑:程序博客网 时间:2024/05/17 04:17

来源:http://cs231n.github.io/optimization-1/

 

对于一个分类问题,可以概括为以下三部分: score function + lossfunction + optimization. 以图像分类为例,我们选择线性分类器,那么scorefunction可以写成如下形式:

 同时Multiclass SupportVector Machine loss可以写成如下形式:


Loss function是W的函数,因此问题转化为最小化loss function的optimization问题。式中N是训练集中所有的样本数。也就是说,在计算loss function时候把所有的训练样本都用了个遍,后面可以看到,计算梯度的时候也用到了所有样本。

 

Strategy #1: A first very bad idea solution: Randomsearch

假设不知道W有什么规律,也不知道该怎么找,最笨的办法就是每次都随机一组数,如果loss function比之前小了就更新下weightvectorW,代码如下:

# assume X_train is the data where each column is an example (e.g. 3073 x 50,000)# assume Y_train are the labels (e.g. 1D array of 50,000)# assume the function L evaluates the loss functionbestloss = float("inf") # Python assigns the highest possible float valuefor num in xrange(1000):  W = np.random.randn(10, 3073) * 0.0001 # generate random parameters  loss = L(X_train, Y_train, W) # get the loss over the entire training set  if loss < bestloss: # keep track of the best solution    bestloss = loss    bestW = W  print 'in attempt %d the loss was %f, best %f' % (num, loss, bestloss)# prints:# in attempt 0 the loss was 9.401632, best 9.401632# in attempt 1 the loss was 8.959668, best 8.959668# in attempt 2 the loss was 9.044034, best 8.959668# in attempt 3 the loss was 9.278948, best 8.959668# in attempt 4 the loss was 8.857370, best 8.857370# in attempt 5 the loss was 8.943151, best 8.857370# in attempt 6 the loss was 8.605604, best 8.605604# ... (trunctated: continues for 1000 lines)

显然这种办法是傻办法,而且很难找到最优解,是不可行的。   

Strategy #2: Random Local Search

       第二种策略是首先初始化个W, 然后让他一步一步往前走,定义步伐为, 那么下一步他的位置就是 而且只有在loss function变小的时候才往下走,否则不走:

W = np.random.randn(10, 3073) * 0.001 # generate random starting Wbestloss = float("inf")for i in xrange(1000):  step_size = 0.0001  Wtry = W + np.random.randn(10, 3073) * step_size  loss = L(Xtr_cols, Ytr, Wtry)  if loss < bestloss:    W = Wtry    bestloss = loss  print 'iter %d loss is %f' % (i, bestloss)

这种方法虽然比上一种好一点,但是计算成本太大,没有一个明确的方向,所以也不好。

 

Strategy #3: Following the Gradient

       终于引出了梯度下降法,梯度的定义如下:

如果是一维情况就是求个微分,如果是高维情况就是求个偏微分。这里说的梯度就是高维向量中每一维的一个偏微分。

接下来介绍两种求梯度的方法。

 

numerical gradient:比较慢,是近似值,并且比较容易

analytic gradient:比较快,是精确值,但是容易犯错,需要微积分的知识。

 

Case1 Computing the gradient numerically with finitedifferences

def eval_numerical_gradient(f, x):  """   a naive implementation of numerical gradient of f at x   - f should be a function that takes a single argument  - x is the point (numpy array) to evaluate the gradient at  """   fx = f(x) # evaluate function value at original point  grad = np.zeros(x.shape)  h = 0.00001  # iterate over all indexes in x  it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])  while not it.finished:    # evaluate function at x+h    ix = it.multi_index    old_value = x[ix]    x[ix] = old_value + h # increment by h    fxh = f(x) # evalute f(x + h)    x[ix] = old_value # restore to previous value (very important!)    # compute the partial derivative    grad[ix] = (fxh - fx) / h # the slope    it.iternext() # step to next dimension  return grad
# to use the generic code above we want a function that takes a single argument# (the weights in our case) so we close over X_train and Y_traindef CIFAR10_loss_fun(W):  return L(X_train, Y_train, W)W = np.random.rand(10, 3073) * 0.001 # random weight vectordf = eval_numerical_gradient(CIFAR10_loss_fun, W) # get the gradient
loss_original = CIFAR10_loss_fun(W) # the original lossprint 'original loss: %f' % (loss_original, )# lets see the effect of multiple step sizesfor step_size_log in [-10, -9, -8, -7, -6, -5,-4,-3,-2,-1]:  step_size = 10 ** step_size_log  W_new = W - step_size * df # new position in the weight space  loss_new = CIFAR10_loss_fun(W_new)  print 'for step size %f new loss: %f' % (step_size, loss_new)# prints:# original loss: 2.200718# for step size 1.000000e-10 new loss: 2.200652# for step size 1.000000e-09 new loss: 2.200057# for step size 1.000000e-08 new loss: 2.194116# for step size 1.000000e-07 new loss: 2.135493# for step size 1.000000e-06 new loss: 1.647802# for step size 1.000000e-05 new loss: 2.844355# for step size 1.000000e-04 new loss: 25.558142

上述代码使用 公式进行计算,实际情况使用centered difference formula会更好 ,原因[wiki]

       上述算法虽然可行但是效率太低,当特征维数太高时不能使用。


Case2 Computing the gradient analytically withCalculus

第一中方法虽然简单但是不是精确值,是近似值,实际可以通过直接推导的方式计算,但是也更容易出错,因此经常使用第二中方法计算然后再去用第一种方法验证下对不对,这种方法叫:gradient check。

 

———————————————————————————————————————

 

上述分析就是梯度下降法的思考过程,梯度下降法是目前最常用且成熟的方法,在优化神经网络loss function问题上。

但是当数据量较大时不适合用这种方法,因为将全部训练样本都用上只为了训练一个参数是非常耗时的,比如有1.2million个数据,使用上述方法是非常耗时的。

 

Mini-batch gradientdescent(MGD or BGD)是比较常用的方法,即只使用一部分训练样本做训练。假设一个极端的例子,如果1.2million样本中只有1000个样本是不一样的,剩下的全是这1000个样本的简单复制,那么即使使用全部样本训练最终也会和1000个样本的效果一样,因此下面的方法将会更快。当然实际情况可能不是完全复制,结果也只是真是结果的一个近似值,但是在牺牲一点精度的情况下可以大大提高效率。

MGD更极端一点的例子是只有一个图像,剩下的全是复制品,那么每次训练只用一个样本计算lossfunction,这种情况叫Stochastic Gradient Descent (SGD,有时候也叫on-line gradient descent,比较形象)。SGD这种情况实际使用并不多见,因为一次计算100个样本比计算1个样本100次要更有效率。有时人们说的SGD也是指的MGD。

MGD实际操作过程中一般选择样本个数时都选2的整次幂,因为在向量化的计算过程中速度可以更快。




注:上述文章从写完的word文档中直接copy,公式编辑器写的东西复制不过来,文章格式也有很多错乱,为了不浪费第二遍时间都不做整理。

0 0
原创粉丝点击