CS231N学习笔记4 Optimization: Stochastic Gradient Descent

Optimization is the process of finding the set of parameters WW that minimize the loss function.

 

Visualizing the loss function

从上一个chapter,得到loss function如下:

 

换一种写法:

 

其中wj是类j的权重向量.可以发现,L其实是wj的一个线性函数的和.

假设现在每张图xi只有一个维度,给三个图,他们的ground truth分别是class1,2,3.

那么,0,1,2(x0,x1,x2)loss分别如下:

 

下图是以w0为例的loss的可视化.左边是L0,L1,L2,右边则是L.

其中横轴为w0.


可以发现,sum of loss是一个碗装的凸函数,我们可以优化该函数得到最优解.

上图中x是一维的,如果变成多维状态,sum of loss将不再是一个凸函数.

注意到loss function是不可微分的,由于max函数,导致函数中存在一定的不可导点.

 

 

Optimization

Strategy #1: A first very bad idea solution: Random search

就是随机选择weights,然后看哪个loss.

Our strategy will be to start with random weights and iteratively refine them over time to get lower loss.

有一种方式是把这个过程看作是盲人登山,山上每一个点都是一个loss(山的海拔).

 

Strategy #2: Random Local Search

随机选择一个方向,随机走一个step_size,如果loss下降,则继续往下走.

Ps: np.random.randn(10, 3073) * 0.001

原型numpy.random.randn(d0, d1, ..., dn)

其中d0, d1, ..., dn : int, optional.The dimensions of the returned array, should be all positive. 

 

Strategy #3: Following the Gradient

不需要随机选择方向,而是可以用数学方式计算出最速下降的方向.

The gradient is just a vector of slopes (more commonly referred to as derivatives) for each dimension in the input space.

 

 

Computing the gradient

两种方式:缓慢,近似但非常简单的数值梯度;快速但是易错,需要微积分的解析梯度.

 

Computing the gradient numerically with finite differences

这部分代码使用迭代器:

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

  np.nditer原来是numpy array自带的迭代器

  #flags=['multi_index']表示对a进行多重索引.

  #op_flags=['readwrite']表示不仅可以对a进行read(读取),还可以write(写入).

即相当于在创建这个迭代器的时候,我们就规定好了有哪些权限。

  it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])

  while not it.finished:

# evaluate function at x+h

#it.multi_index表示元素的索引

    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

这里h虽然在数学意义上趋向于0,但是这里用一个极小值1e-5代替就可以了.

新的weight向着df的反方向走(df就是grad).

 W_new = W - step_size * df

Step_size就是learning rate,取值过大可能progress很大但是会有risky.取值过小progress过小.

用这种方式,对于有10*3072个参数的网络而言,我们每走一步,要计算30721loss,这对于现代神经网络所拥有的庞大参数量而言,非常worse.

 

Computing the gradient analytically with Calculus

analytic gradient是易错的,因此常常需要用的numerical gradient和它进行check.

SVMloss function如下:

 

现在我们要求Loss对于w的微分,对于每一张图,classw,对于每一行w,如果是ground truth那一行,就是:

 

Ps:这里1指的是,括号里面的判别式取true则为1,否则取0.

如果不是,则是:

 

 

Gradient Descent

优化的核心:

# Vanilla Gradient Descent

while True:

  weights_grad = evaluate_gradient(loss_fun, data, weights)

  weights += - step_size * weights_grad # perform parameter update

由于计算所有的gradient会非常的wasteful,所以我们选择一个小batch做这一工作(也会更加容易收敛).

# Vanilla Minibatch Gradient Descent

while True:

  data_batch = sample_training_data(data, 256# sample 256 examples

  weights_grad = evaluate_gradient(loss_fun, data_batch, weights)

  weights += - step_size * weights_grad # perform parameter update

最极端的是batch_size=1的情况,被称为随机梯度下降(on-line gradient descent). batch_size的大小一般不用cross-validation来确定.

 

 

Unknown word

march along 行进

piecewise-linear 分段线性

bumpy  颠簸的

Interchangeably 互换的

To reiterate, 重申

Perturbations 扰动 

steepest descend 最速下降

at least in the limit as the step size goes towards zero 至少在步长接近零的范围内

instantaneous rate  顺势速率

error-prone 易错的

Calculus 微积分

generic function 通用函数

headache-inducing 令人头疼的

overshoot  超调

Derive 得到

vanilla  香草

Stochastic 随机的

 

你可能感兴趣的:(CS231n学习笔记)